/ src / common / dwarf / dwarf2diehandler.cc
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