/thirdparty/breakpad/common/dwarf/dwarf2diehandler.h
http://github.com/tomahawk-player/tomahawk · C Header · 365 lines · 93 code · 23 blank · 249 comment · 0 complexity · be050006a2e82cf2db61a9deb813a29b MD5 · raw file
- // -*- 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 "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.
- //
- // 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 std::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 std::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__