dwarf2diehandler.h 15.7 KB
Newer Older
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 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
// -*- 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 <stdint.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 uint8_t *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 uint8_t *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__