364 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			364 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // -*- 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.
 | |
|   //
 | |
|   // The default definition skips all children.
 | |
|   virtual DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag) {
 | |
|     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) { 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);
 | |
|   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__
 |