dwarf2diehandler.cc
1 // Copyright 2010 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> 30 31 // dwarf2diehandler.cc: Implement the dwarf2reader::DieDispatcher class. 32 // See dwarf2diehandler.h for details. 33 34 #ifdef HAVE_CONFIG_H 35 #include <config.h> // Must come first 36 #endif 37 38 #include <assert.h> 39 #include <stdint.h> 40 41 #include <string> 42 43 #include "common/dwarf/dwarf2diehandler.h" 44 #include "common/using_std_string.h" 45 46 namespace google_breakpad { 47 48 DIEDispatcher::~DIEDispatcher() { 49 while (!die_handlers_.empty()) { 50 HandlerStack& entry = die_handlers_.top(); 51 if (entry.handler_ != root_handler_) 52 delete entry.handler_; 53 die_handlers_.pop(); 54 } 55 } 56 57 bool DIEDispatcher::StartCompilationUnit(uint64_t offset, uint8_t address_size, 58 uint8_t offset_size, uint64_t cu_length, 59 uint8_t dwarf_version) { 60 return root_handler_->StartCompilationUnit(offset, address_size, 61 offset_size, cu_length, 62 dwarf_version); 63 } 64 65 bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) { 66 // The stack entry for the parent of this DIE, if there is one. 67 HandlerStack* parent = die_handlers_.empty() ? NULL : &die_handlers_.top(); 68 69 // Does this call indicate that we're done receiving the parent's 70 // attributes' values? If so, call its EndAttributes member function. 71 if (parent && parent->handler_ && !parent->reported_attributes_end_) { 72 parent->reported_attributes_end_ = true; 73 if (!parent->handler_->EndAttributes()) { 74 // Finish off this handler now. and edit *PARENT to indicate that 75 // we don't want to visit any of the children. 76 parent->handler_->Finish(); 77 if (parent->handler_ != root_handler_) 78 delete parent->handler_; 79 parent->handler_ = NULL; 80 return false; 81 } 82 } 83 84 // Find a handler for this DIE. 85 DIEHandler* handler; 86 if (parent) { 87 if (parent->handler_) 88 // Ask the parent to find a handler. 89 handler = parent->handler_->FindChildHandler(offset, tag); 90 else 91 // No parent handler means we're not interested in any of our 92 // children. 93 handler = NULL; 94 } else { 95 // This is the root DIE. For a non-root DIE, the parent's handler 96 // decides whether to visit it, but the root DIE has no parent 97 // handler, so we have a special method on the root DIE handler 98 // itself to decide. 99 if (root_handler_->StartRootDIE(offset, tag)) 100 handler = root_handler_; 101 else 102 handler = NULL; 103 } 104 105 // Push a handler stack entry for this new handler. As an 106 // optimization, we don't push NULL-handler entries on top of other 107 // NULL-handler entries; we just let the oldest such entry stand for 108 // the whole subtree. 109 if (handler || !parent || parent->handler_) { 110 HandlerStack entry; 111 entry.offset_ = offset; 112 entry.handler_ = handler; 113 entry.reported_attributes_end_ = false; 114 die_handlers_.push(entry); 115 } 116 117 return handler != NULL; 118 } 119 120 void DIEDispatcher::EndDIE(uint64_t offset) { 121 assert(!die_handlers_.empty()); 122 HandlerStack* entry = &die_handlers_.top(); 123 if (entry->handler_) { 124 // This entry had better be the handler for this DIE. 125 assert(entry->offset_ == offset); 126 // If a DIE has no children, this EndDIE call indicates that we're 127 // done receiving its attributes' values. 128 if (!entry->reported_attributes_end_) 129 entry->handler_->EndAttributes(); // Ignore return value: no children. 130 entry->handler_->Finish(); 131 if (entry->handler_ != root_handler_) 132 delete entry->handler_; 133 } else { 134 // If this DIE is within a tree we're ignoring, then don't pop the 135 // handler stack: that entry stands for the whole tree. 136 if (entry->offset_ != offset) 137 return; 138 } 139 die_handlers_.pop(); 140 } 141 142 void DIEDispatcher::ProcessAttributeUnsigned(uint64_t offset, 143 enum DwarfAttribute attr, 144 enum DwarfForm form, 145 uint64_t data) { 146 HandlerStack& current = die_handlers_.top(); 147 // This had better be an attribute of the DIE we were meant to handle. 148 assert(offset == current.offset_); 149 current.handler_->ProcessAttributeUnsigned(attr, form, data); 150 } 151 152 void DIEDispatcher::ProcessAttributeSigned(uint64_t offset, 153 enum DwarfAttribute attr, 154 enum DwarfForm form, 155 int64_t data) { 156 HandlerStack& current = die_handlers_.top(); 157 // This had better be an attribute of the DIE we were meant to handle. 158 assert(offset == current.offset_); 159 current.handler_->ProcessAttributeSigned(attr, form, data); 160 } 161 162 void DIEDispatcher::ProcessAttributeReference(uint64_t offset, 163 enum DwarfAttribute attr, 164 enum DwarfForm form, 165 uint64_t data) { 166 HandlerStack& current = die_handlers_.top(); 167 // This had better be an attribute of the DIE we were meant to handle. 168 assert(offset == current.offset_); 169 current.handler_->ProcessAttributeReference(attr, form, data); 170 } 171 172 void DIEDispatcher::ProcessAttributeBuffer(uint64_t offset, 173 enum DwarfAttribute attr, 174 enum DwarfForm form, 175 const uint8_t* data, 176 uint64_t len) { 177 HandlerStack& current = die_handlers_.top(); 178 // This had better be an attribute of the DIE we were meant to handle. 179 assert(offset == current.offset_); 180 current.handler_->ProcessAttributeBuffer(attr, form, data, len); 181 } 182 183 void DIEDispatcher::ProcessAttributeString(uint64_t offset, 184 enum DwarfAttribute attr, 185 enum DwarfForm form, 186 const string& data) { 187 HandlerStack& current = die_handlers_.top(); 188 // This had better be an attribute of the DIE we were meant to handle. 189 assert(offset == current.offset_); 190 current.handler_->ProcessAttributeString(attr, form, data); 191 } 192 193 void DIEDispatcher::ProcessAttributeSignature(uint64_t offset, 194 enum DwarfAttribute attr, 195 enum DwarfForm form, 196 uint64_t signature) { 197 HandlerStack& current = die_handlers_.top(); 198 // This had better be an attribute of the DIE we were meant to handle. 199 assert(offset == current.offset_); 200 current.handler_->ProcessAttributeSignature(attr, form, signature); 201 } 202 203 } // namespace google_breakpad