/ src / common / dwarf / dwarf2diehandler.h
dwarf2diehandler.h
  1  // -*- mode: c++ -*-
  2  
  3  // Copyright 2010 Google LLC
  4  //
  5  // Redistribution and use in source and binary forms, with or without
  6  // modification, are permitted provided that the following conditions are
  7  // met:
  8  //
  9  //     * Redistributions of source code must retain the above copyright
 10  // notice, this list of conditions and the following disclaimer.
 11  //     * Redistributions in binary form must reproduce the above
 12  // copyright notice, this list of conditions and the following disclaimer
 13  // in the documentation and/or other materials provided with the
 14  // distribution.
 15  //     * Neither the name of Google LLC nor the names of its
 16  // contributors may be used to endorse or promote products derived from
 17  // this software without specific prior written permission.
 18  //
 19  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 20  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 21  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 22  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 23  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 24  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 25  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 26  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 27  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 28  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 29  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 30  
 31  // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
 32  
 33  // dwarf2reader::CompilationUnit is a simple and direct parser for
 34  // DWARF data, but its handler interface is not convenient to use.  In
 35  // particular:
 36  //
 37  // - CompilationUnit calls Dwarf2Handler's member functions to report
 38  //   every attribute's value, regardless of what sort of DIE it is.
 39  //   As a result, the ProcessAttributeX functions end up looking like
 40  //   this:
 41  //
 42  //     switch (parent_die_tag) {
 43  //       case DW_TAG_x:
 44  //         switch (attribute_name) {
 45  //           case DW_AT_y:
 46  //             handle attribute y of DIE type x
 47  //           ...
 48  //         } break;
 49  //       ...
 50  //     } 
 51  //
 52  //   In C++ it's much nicer to use virtual function dispatch to find
 53  //   the right code for a given case than to switch on the DIE tag
 54  //   like this.
 55  //
 56  // - Processing different kinds of DIEs requires different sets of
 57  //   data: lexical block DIEs have start and end addresses, but struct
 58  //   type DIEs don't.  It would be nice to be able to have separate
 59  //   handler classes for separate kinds of DIEs, each with the members
 60  //   appropriate to its role, instead of having one handler class that
 61  //   needs to hold data for every DIE type.
 62  //
 63  // - There should be a separate instance of the appropriate handler
 64  //   class for each DIE, instead of a single object with tables
 65  //   tracking all the dies in the compilation unit.
 66  //
 67  // - It's not convenient to take some action after all a DIE's
 68  //   attributes have been seen, but before visiting any of its
 69  //   children.  The only indication you have that a DIE's attribute
 70  //   list is complete is that you get either a StartDIE or an EndDIE
 71  //   call.
 72  //
 73  // - It's not convenient to make use of the tree structure of the
 74  //   DIEs.  Skipping all the children of a given die requires
 75  //   maintaining state and returning false from StartDIE until we get
 76  //   an EndDIE call with the appropriate offset.
 77  //
 78  // This interface tries to take care of all that.  (You're shocked, I'm sure.)
 79  //
 80  // Using the classes here, you provide an initial handler for the root
 81  // DIE of the compilation unit.  Each handler receives its DIE's
 82  // attributes, and provides fresh handler objects for children of
 83  // interest, if any.  The three classes are:
 84  //
 85  // - DIEHandler: the base class for your DIE-type-specific handler
 86  //   classes.
 87  //
 88  // - RootDIEHandler: derived from DIEHandler, the base class for your
 89  //   root DIE handler class.
 90  //
 91  // - DIEDispatcher: derived from Dwarf2Handler, an instance of this
 92  //   invokes your DIE-type-specific handler objects.
 93  //
 94  // In detail:
 95  //
 96  // - Define handler classes specialized for the DIE types you're
 97  //   interested in.  These handler classes must inherit from
 98  //   DIEHandler.  Thus:
 99  //
100  //     class My_DW_TAG_X_Handler: public DIEHandler { ... };
101  //     class My_DW_TAG_Y_Handler: public DIEHandler { ... };
102  //
103  //   DIEHandler subclasses needn't correspond exactly to single DIE
104  //   types, as shown here; the point is that you can have several
105  //   different classes appropriate to different kinds of DIEs.
106  //
107  // - In particular, define a handler class for the compilation
108  //   unit's root DIE, that inherits from RootDIEHandler:
109  //
110  //     class My_DW_TAG_compile_unit_Handler: public RootDIEHandler { ... };
111  //
112  //   RootDIEHandler inherits from DIEHandler, adding a few additional
113  //   member functions for examining the compilation unit as a whole,
114  //   and other quirks of rootness.
115  //
116  // - Then, create a DIEDispatcher instance, passing it an instance of
117  //   your root DIE handler class, and use that DIEDispatcher as the
118  //   dwarf2reader::CompilationUnit's handler:
119  //
120  //     My_DW_TAG_compile_unit_Handler root_die_handler(...);
121  //     DIEDispatcher die_dispatcher(&root_die_handler);
122  //     CompilationUnit reader(sections, offset, bytereader, &die_dispatcher);
123  //
124  //   Here, 'die_dispatcher' acts as a shim between 'reader' and the
125  //   various DIE-specific handlers you have defined.
126  //
127  // - When you call reader.Start(), die_dispatcher behaves as follows,
128  //   starting with your root die handler and the compilation unit's
129  //   root DIE:
130  //
131  //   - It calls the handler's ProcessAttributeX member functions for
132  //     each of the DIE's attributes.
133  //
134  //   - It calls the handler's EndAttributes member function.  This
135  //     should return true if any of the DIE's children should be
136  //     visited, in which case:
137  //
138  //     - For each of the DIE's children, die_dispatcher calls the
139  //       DIE's handler's FindChildHandler member function.  If that
140  //       returns a pointer to a DIEHandler instance, then
141  //       die_dispatcher uses that handler to process the child, using
142  //       this procedure recursively.  Alternatively, if
143  //       FindChildHandler returns NULL, die_dispatcher ignores that
144  //       child and its descendants.
145  // 
146  //   - When die_dispatcher has finished processing all the DIE's
147  //     children, it invokes the handler's Finish() member function,
148  //     and destroys the handler.  (As a special case, it doesn't
149  //     destroy the root DIE handler.)
150  // 
151  // This allows the code for handling a particular kind of DIE to be
152  // gathered together in a single class, makes it easy to skip all the
153  // children or individual children of a particular DIE, and provides
154  // appropriate parental context for each die.
155  
156  #ifndef COMMON_DWARF_DWARF2DIEHANDLER_H__
157  #define COMMON_DWARF_DWARF2DIEHANDLER_H__
158  
159  #include <stdint.h>
160  
161  #include <stack>
162  #include <string>
163  
164  #include "common/dwarf/types.h"
165  #include "common/dwarf/dwarf2enums.h"
166  #include "common/dwarf/dwarf2reader.h"
167  #include "common/using_std_string.h"
168  
169  namespace google_breakpad {
170  
171  // A base class for handlers for specific DIE types.  The series of
172  // calls made on a DIE handler is as follows:
173  //
174  // - for each attribute of the DIE:
175  //   - ProcessAttributeX()
176  // - EndAttributes()
177  // - if that returned true, then for each child:
178  //   - FindChildHandler()
179  //   - if that returns a non-NULL pointer to a new handler:
180  //     - recurse, with the new handler and the child die
181  // - Finish()
182  // - destruction
183  class DIEHandler {
184   public:
185    DIEHandler() { }
186    virtual ~DIEHandler() { }
187  
188    // When we visit a DIE, we first use these member functions to
189    // report the DIE's attributes and their values.  These have the
190    // same restrictions as the corresponding member functions of
191    // dwarf2reader::Dwarf2Handler.
192    //
193    // Since DWARF does not specify in what order attributes must
194    // appear, avoid making decisions in these functions that would be
195    // affected by the presence of other attributes. The EndAttributes
196    // function is a more appropriate place for such work, as all the
197    // DIE's attributes have been seen at that point.
198    //
199    // The default definitions ignore the values they are passed.
200    virtual void ProcessAttributeUnsigned(enum DwarfAttribute attr,
201                                          enum DwarfForm form,
202                                          uint64_t data) { }
203    virtual void ProcessAttributeSigned(enum DwarfAttribute attr,
204                                        enum DwarfForm form,
205                                        int64_t data) { }
206    virtual void ProcessAttributeReference(enum DwarfAttribute attr,
207                                           enum DwarfForm form,
208                                           uint64_t data) { }
209    virtual void ProcessAttributeBuffer(enum DwarfAttribute attr,
210                                        enum DwarfForm form,
211                                        const uint8_t* data,
212                                        uint64_t len) { }
213    virtual void ProcessAttributeString(enum DwarfAttribute attr,
214                                        enum DwarfForm form,
215                                        const string& data) { }
216    virtual void ProcessAttributeSignature(enum DwarfAttribute attr,
217                                           enum DwarfForm form,
218                                           uint64_t signture) { }
219  
220    // Once we have reported all the DIE's attributes' values, we call
221    // this member function.  If it returns false, we skip all the DIE's
222    // children.  If it returns true, we call FindChildHandler on each
223    // child.  If that returns a handler object, we use that to visit
224    // the child; otherwise, we skip the child.
225    //
226    // This is a good place to make decisions that depend on more than
227    // one attribute. DWARF does not specify in what order attributes
228    // must appear, so only when the EndAttributes function is called
229    // does the handler have a complete picture of the DIE's attributes.
230    //
231    // The default definition elects to ignore the DIE's children.
232    // You'll need to override this if you override FindChildHandler,
233    // but at least the default behavior isn't to pass the children to
234    // FindChildHandler, which then ignores them all.
235    virtual bool EndAttributes() { return false; }
236  
237    // If EndAttributes returns true to indicate that some of the DIE's
238    // children might be of interest, then we apply this function to
239    // each of the DIE's children.  If it returns a handler object, then
240    // we use that to visit the child DIE.  If it returns NULL, we skip
241    // that child DIE (and all its descendants).
242    //
243    // OFFSET is the offset of the child; TAG indicates what kind of DIE
244    // it is.
245    //
246    // The default definition skips all children.
247    virtual DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag) {
248      return NULL;
249    }
250  
251    // When we are done processing a DIE, we call this member function.
252    // This happens after the EndAttributes call, all FindChildHandler
253    // calls (if any), and all operations on the children themselves (if
254    // any). We call Finish on every handler --- even if EndAttributes
255    // returns false.
256    virtual void Finish() { };
257  };
258  
259  // A subclass of DIEHandler, with additional kludges for handling the
260  // compilation unit's root die.
261  class RootDIEHandler : public DIEHandler {
262   public:
263    bool handle_inline;
264  
265    explicit RootDIEHandler(bool handle_inline = false)
266        : handle_inline(handle_inline) {}
267    virtual ~RootDIEHandler() {}
268  
269    // We pass the values reported via Dwarf2Handler::StartCompilationUnit
270    // to this member function, and skip the entire compilation unit if it
271    // returns false.  So the root DIE handler is actually also
272    // responsible for handling the compilation unit metadata.
273    // The default definition always visits the compilation unit.
274    virtual bool StartCompilationUnit(uint64_t offset, uint8_t address_size,
275                                      uint8_t offset_size, uint64_t cu_length,
276                                      uint8_t dwarf_version) { return true; }
277  
278    // For the root DIE handler only, we pass the offset, tag and
279    // attributes of the compilation unit's root DIE.  This is the only
280    // way the root DIE handler can find the root DIE's tag.  If this
281    // function returns true, we will visit the root DIE using the usual
282    // DIEHandler methods; otherwise, we skip the entire compilation
283    // unit.
284    //
285    // The default definition elects to visit the root DIE.
286    virtual bool StartRootDIE(uint64_t offset, enum DwarfTag tag) { return true; }
287  };
288  
289  class DIEDispatcher: public Dwarf2Handler {
290   public:
291    // Create a Dwarf2Handler which uses ROOT_HANDLER as the handler for
292    // the compilation unit's root die, as described for the DIEHandler
293    // class.
294    DIEDispatcher(RootDIEHandler* root_handler) : root_handler_(root_handler) { }
295    // Destroying a DIEDispatcher destroys all active handler objects
296    // except the root handler.
297    ~DIEDispatcher();
298    bool StartCompilationUnit(uint64_t offset, uint8_t address_size,
299                              uint8_t offset_size, uint64_t cu_length,
300                              uint8_t dwarf_version);
301    bool StartDIE(uint64_t offset, enum DwarfTag tag);
302    void ProcessAttributeUnsigned(uint64_t offset,
303                                  enum DwarfAttribute attr,
304                                  enum DwarfForm form,
305                                  uint64_t data);
306    void ProcessAttributeSigned(uint64_t offset,
307                                enum DwarfAttribute attr,
308                                enum DwarfForm form,
309                                int64_t data);
310    void ProcessAttributeReference(uint64_t offset,
311                                   enum DwarfAttribute attr,
312                                   enum DwarfForm form,
313                                   uint64_t data);
314    void ProcessAttributeBuffer(uint64_t offset,
315                                enum DwarfAttribute attr,
316                                enum DwarfForm form,
317                                const uint8_t* data,
318                                uint64_t len);
319    void ProcessAttributeString(uint64_t offset,
320                                enum DwarfAttribute attr,
321                                enum DwarfForm form,
322                                const string& data);
323    void ProcessAttributeSignature(uint64_t offset,
324                                   enum DwarfAttribute attr,
325                                   enum DwarfForm form,
326                                   uint64_t signature);
327    void EndDIE(uint64_t offset);
328  
329   private:
330  
331    // The type of a handler stack entry.  This includes some fields
332    // which don't really need to be on the stack --- they could just be
333    // single data members of DIEDispatcher --- but putting them here
334    // makes it easier to see that the code is correct.
335    struct HandlerStack {
336      // The offset of the DIE for this handler stack entry.
337      uint64_t offset_;
338  
339      // The handler object interested in this DIE's attributes and
340      // children.  If NULL, we're not interested in either.
341      DIEHandler* handler_;
342  
343      // Have we reported the end of this DIE's attributes to the handler?
344      bool reported_attributes_end_;
345    };
346  
347    // Stack of DIE attribute handlers.  At StartDIE(D), the top of the
348    // stack is the handler of D's parent, whom we may ask for a handler
349    // for D itself.  At EndDIE(D), the top of the stack is D's handler.
350    // Special cases:
351    //
352    // - Before we've seen the compilation unit's root DIE, the stack is
353    //   empty; we'll call root_handler_'s special member functions, and
354    //   perhaps push root_handler_ on the stack to look at the root's
355    //   immediate children.
356    //
357    // - When we decide to ignore a subtree, we only push an entry on
358    //   the stack for the root of the tree being ignored, rather than
359    //   pushing lots of stack entries with handler_ set to NULL.
360    std::stack<HandlerStack> die_handlers_;
361  
362    // The root handler.  We don't push it on die_handlers_ until we
363    // actually get the StartDIE call for the root.
364    RootDIEHandler* root_handler_;
365  };
366  
367  } // namespace google_breakpad
368  #endif  // COMMON_DWARF_DWARF2DIEHANDLER_H__