toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial