aboutsummaryrefslogtreecommitdiff
path: root/src/common/dwarf/dwarf2diehandler.h
blob: bd9d6c57dea6f320b828d6b66fa1921d27ca525e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
// -*- mode: c++ -*-

// Copyright 2009 Google Inc. All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// dwarf2reader::CompilationUnit is a simple and direct parser for
// DWARF data, but its handler interface is not convenient to use.  In
// particular:
//
// - CompilationUnit calls Dwarf2Handler's member functions to report
//   every attribute's value, regardless of what sort of DIE it is.
//   As a result, the ProcessAttributeX functions end up looking like
//   this:
//
//     switch (parent_die_tag) {
//       case DW_TAG_x:
//         switch (attribute_name) {
//           case DW_AT_y:
//             handle attribute y of DIE type x
//           ...
//         } break;
//       ...
//     } 
//
//   In C++ it's much nicer to use virtual function dispatch to find
//   the right code for a given case than to switch on the DIE tag
//   like this.
//
// - Processing different kinds of DIEs requires different sets of
//   data: lexical block DIEs have start and end addresses, but struct
//   type DIEs don't.  It would be nice to be able to have separate
//   handler classes for separate kinds of DIEs, each with the members
//   appropriate to its role, instead of having one handler class that
//   needs to hold data for all every DIE type.
//
// - There should be a separate instance of the appropriate handler
//   class for each DIE, instead of a single object with tables
//   tracking all the dies in the compilation unit.
//
// - It's not convenient to take some action after all a DIE's
//   attributes have been seen, but before visiting any of its
//   children.  The only indication you have that a DIE's attribute
//   list is complete is that you get either a StartDIE or an EndDIE
//   call.
//
// - It's not convenient to make use of the tree structure of the
//   DIEs.  Skipping all the children of a given die requires
//   maintaining state and returning false from StartDIE until we get
//   an EndDIE call with the appropriate offset.
//
// This interface tries to take care of all that.  (You're shocked, I'm sure.)
//
// Using the classes here, you provide an initial handler for the root
// DIE of the compilation unit.  Each handler receives its DIE's
// attributes, and provides fresh handler objects for children of
// interest, if any.  The three classes are:
//
// - DIEHandler: the base class for your DIE-type-specific handler
//   classes.
//
// - RootDIEHandler: derived from DIEHandler, the base class for your
//   root DIE handler class.
//
// - DIEDispatcher: derived from Dwarf2Handler, an instance of this
//   invokes your DIE-type-specific handler objects.
//
// In detail:
//
// - Define handler classes specialized for the DIE types you're
//   interested in.  These handler classes must inherit from
//   DIEHandler.  Thus:
//
//     class My_DW_TAG_X_Handler: public DIEHandler { ... };
//     class My_DW_TAG_Y_Handler: public DIEHandler { ... };
//
//   DIEHandler subclasses needn't correspond exactly to single DIE
//   types, as shown here; the point is that you can have several
//   different classes appropriate to different kinds of DIEs.
//
// - In particular, define a handler class for the compilation
//   unit's root DIE, that inherits from RootDIEHandler:
//
//     class My_DW_TAG_compile_unit_Handler: public RootDIEHandler { ... };
//
//   RootDIEHandler inherits from DIEHandler, adding a few additional
//   member functions for examining the compilation unit as a whole,
//   and other quirks of rootness.
//
// - Then, create a DIEDispatcher instance, passing it an instance of
//   your root DIE handler class, and use that DIEDispatcher as the
//   dwarf2reader::CompilationUnit's handler:
//
//     My_DW_TAG_compile_unit_Handler root_die_handler(...);
//     DIEDispatcher die_dispatcher(&root_die_handler);
//     CompilationUnit reader(sections, offset, bytereader, &die_dispatcher);
//
//   Here, 'die_dispatcher' acts as a shim between 'reader' and the
//   various DIE-specific handlers you have defined.
//
// - When you call reader.Start(), die_dispatcher behaves as follows,
//   starting with your root die handler and the compilation unit's
//   root DIE:
//
//   - It calls the handler's ProcessAttributeX member functions for
//     each of the DIE's attributes.
//
//   - It calls the handler's EndAttributes member function.  This
//     should return true if any of the DIE's children should be
//     visited, in which case:
//
//     - For each of the DIE's children, die_dispatcher calls the
//       DIE's handler's FindChildHandler member function.  If that
//       returns a pointer to a DIEHandler instance, then
//       die_dispatcher uses that handler to process the child, using
//       this procedure recursively.  Alternatively, if
//       FindChildHandler returns NULL, die_dispatcher ignores that
//       child and its descendants.
// 
//   - When die_dispatcher has finished processing all the DIE's
//     children, it invokes the handler's Finish() member function,
//     and destroys the handler.  (As a special case, it doesn't
//     destroy the root DIE handler.)
// 
// This allows the code for handling a particular kind of DIE to be
// gathered together in a single class, makes it easy to skip all the
// children or individual children of a particular DIE, and provides
// appropriate parental context for each die.

#ifndef COMMON_DWARF_DWARF2DIEHANDLER_H__
#define COMMON_DWARF_DWARF2DIEHANDLER_H__

#include <stack>

#include "common/dwarf/types.h"
#include "common/dwarf/dwarf2enums.h"
#include "common/dwarf/dwarf2reader.h"

namespace dwarf2reader {

// A base class for handlers for specific DIE types.  The series of
// calls made on a DIE handler is as follows:
//
// - for each attribute of the DIE:
//   - ProcessAttributeX()
// - EndAttributes()
// - if that returned true, then for each child:
//   - FindChildHandler()
//   - if that returns a non-NULL pointer to a new handler:
//     - recurse, with the new handler and the child die
// - Finish()
// - destruction
class DIEHandler {
 public:
  DIEHandler() { }
  virtual ~DIEHandler() { }

  // When we visit a DIE, we first use these member functions to
  // report the DIE's attributes and their values.  These have the
  // same restrictions as the corresponding member functions of
  // dwarf2reader::Dwarf2Handler.
  //
  // The default definitions ignore the values they are passed.
  virtual void ProcessAttributeUnsigned(enum DwarfAttribute attr,
                                        enum DwarfForm form,
                                        uint64 data) { }
  virtual void ProcessAttributeSigned(enum DwarfAttribute attr,
                                      enum DwarfForm form,
                                      int64 data) { }
  virtual void ProcessAttributeReference(enum DwarfAttribute attr,
                                         enum DwarfForm form,
                                         uint64 data) { }
  virtual void ProcessAttributeBuffer(enum DwarfAttribute attr,
                                      enum DwarfForm form,
                                      const char* data,
                                      uint64 len) { }
  virtual void ProcessAttributeString(enum DwarfAttribute attr,
                                      enum DwarfForm form,
                                      const string& data) { }

  // Once we have reported all the DIE's attributes' values, we call
  // this member function.  If it returns false, we skip all the DIE's
  // children.  If it returns true, we call FindChildHandler on each
  // child.  If that returns a handler object, we use that to visit
  // the child; otherwise, we skip the child.
  //
  // The default definition elects to ignore the DIE's children.
  // You'll need to override this if you override FindChildHandler,
  // but at least the default behavior isn't to pass the children to
  // FindChildHandler, which then ignores them all.
  virtual bool EndAttributes() { return false; }

  // If EndAttributes returns true to indicate that some of the DIE's
  // children might be of interest, then we apply this function to
  // each of the DIE's children.  If it returns a handler object, then
  // we use that to visit the child DIE.  If it returns NULL, we skip
  // that child DIE (and all its descendants).
  //
  // OFFSET is the offset of the child; TAG indicates what kind of DIE
  // it is; and ATTRS is the list of attributes the DIE will have, and
  // their forms (their values are not provided).
  //
  // The default definition skips all children.
  virtual DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag,
                                       const AttributeList &attrs) {
    return NULL;
  }

  // When we are done processing a DIE, we call this member function.
  // This happens after the EndAttributes call, all FindChildHandler
  // calls (if any), and all operations on the children themselves (if
  // any). We call Finish on every handler --- even if EndAttributes
  // returns false.
  virtual void Finish() { };
};

// A subclass of DIEHandler, with additional kludges for handling the
// compilation unit's root die.
class RootDIEHandler: public DIEHandler {
 public:
  RootDIEHandler() { }
  virtual ~RootDIEHandler() { }

  // We pass the values reported via Dwarf2Handler::StartCompilationUnit
  // to this member function, and skip the entire compilation unit if it
  // returns false.  So the root DIE handler is actually also
  // responsible for handling the compilation unit metadata.
  // The default definition always visits the compilation unit.
  virtual bool StartCompilationUnit(uint64 offset, uint8 address_size,
                                    uint8 offset_size, uint64 cu_length,
                                    uint8 dwarf_version) { return true; }

  // For the root DIE handler only, we pass the offset, tag and
  // attributes of the compilation unit's root DIE.  This is the only
  // way the root DIE handler can find the root DIE's tag.  If this
  // function returns true, we will visit the root DIE using the usual
  // DIEHandler methods; otherwise, we skip the entire compilation
  // unit.
  //
  // The default definition elects to visit the root DIE.
  virtual bool StartRootDIE(uint64 offset, enum DwarfTag tag,
                            const AttributeList& attrs) { return true; }
};

class DIEDispatcher: public Dwarf2Handler {
 public:
  // Create a Dwarf2Handler which uses ROOT_HANDLER as the handler for
  // the compilation unit's root die, as described for the DIEHandler
  // class.
  DIEDispatcher(RootDIEHandler *root_handler) : root_handler_(root_handler) { }
  // Destroying a DIEDispatcher destroys all active handler objects
  // except the root handler.
  ~DIEDispatcher();
  bool StartCompilationUnit(uint64 offset, uint8 address_size,
                            uint8 offset_size, uint64 cu_length,
                            uint8 dwarf_version);
  bool StartDIE(uint64 offset, enum DwarfTag tag,
                const AttributeList &attrs);
  void ProcessAttributeUnsigned(uint64 offset,
                                enum DwarfAttribute attr,
                                enum DwarfForm form,
                                uint64 data);
  void ProcessAttributeSigned(uint64 offset,
                              enum DwarfAttribute attr,
                              enum DwarfForm form,
                              int64 data);
  void ProcessAttributeReference(uint64 offset,
                                 enum DwarfAttribute attr,
                                 enum DwarfForm form,
                                 uint64 data);
  void ProcessAttributeBuffer(uint64 offset,
                              enum DwarfAttribute attr,
                              enum DwarfForm form,
                              const char* data,
                              uint64 len);
  void ProcessAttributeString(uint64 offset,
                              enum DwarfAttribute attr,
                              enum DwarfForm form,
                              const string &data);
  void EndDIE(uint64 offset);

 private:

  // The type of a handler stack entry.  This includes some fields
  // which don't really need to be on the stack --- they could just be
  // single data members of DIEDispatcher --- but putting them here
  // makes it easier to see that the code is correct.
  struct HandlerStack {
    // The offset of the DIE for this handler stack entry.
    uint64 offset_;

    // The handler object interested in this DIE's attributes and
    // children.  If NULL, we're not interested in either.
    DIEHandler *handler_;

    // Have we reported the end of this DIE's attributes to the handler?
    bool reported_attributes_end_;
  };

  // Stack of DIE attribute handlers.  At StartDIE(D), the top of the
  // stack is the handler of D's parent, whom we may ask for a handler
  // for D itself.  At EndDIE(D), the top of the stack is D's handler.
  // Special cases:
  //
  // - Before we've seen the compilation unit's root DIE, the stack is
  //   empty; we'll call root_handler_'s special member functions, and
  //   perhaps push root_handler_ on the stack to look at the root's
  //   immediate children.
  //
  // - When we decide to ignore a subtree, we only push an entry on
  //   the stack for the root of the tree being ignored, rather than
  //   pushing lots of stack entries with handler_ set to NULL.
  stack<HandlerStack> die_handlers_;

  // The root handler.  We don't push it on die_handlers_ until we
  // actually get the StartDIE call for the root.
  RootDIEHandler *root_handler_;
};

} // namespace dwarf2reader
#endif  // COMMON_DWARF_DWARF2DIEHANDLER_H__