|  | // -*- mode: c++ -*- | 
|  |  | 
|  | // Copyright (c) 2010 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. | 
|  |  | 
|  | // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> | 
|  |  | 
|  | // 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 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 <string> | 
|  |  | 
|  | #include "common/dwarf/types.h" | 
|  | #include "common/dwarf/dwarf2enums.h" | 
|  | #include "common/dwarf/dwarf2reader.h" | 
|  | #include "common/using_std_string.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. | 
|  | // | 
|  | // Since DWARF does not specify in what order attributes must | 
|  | // appear, avoid making decisions in these functions that would be | 
|  | // affected by the presence of other attributes. The EndAttributes | 
|  | // function is a more appropriate place for such work, as all the | 
|  | // DIE's attributes have been seen at that point. | 
|  | // | 
|  | // 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) { } | 
|  | virtual void ProcessAttributeSignature(enum DwarfAttribute attr, | 
|  | enum DwarfForm form, | 
|  | uint64 signture) { } | 
|  |  | 
|  | // 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. | 
|  | // | 
|  | // This is a good place to make decisions that depend on more than | 
|  | // one attribute. DWARF does not specify in what order attributes | 
|  | // must appear, so only when the EndAttributes function is called | 
|  | // does the handler have a complete picture of the DIE's attributes. | 
|  | // | 
|  | // 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 ProcessAttributeSignature(uint64 offset, | 
|  | enum DwarfAttribute attr, | 
|  | enum DwarfForm form, | 
|  | uint64 signature); | 
|  | 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. | 
|  | std::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__ |