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