1// Copyright (c) 2010 Google Inc. All Rights Reserved.
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 Inc. 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#include <assert.h>
35#include <stdint.h>
36
37#include <string>
38
39#include "common/dwarf/dwarf2diehandler.h"
40#include "common/using_std_string.h"
41
42namespace google_breakpad {
43
44DIEDispatcher::~DIEDispatcher() {
45 while (!die_handlers_.empty()) {
46 HandlerStack& entry = die_handlers_.top();
47 if (entry.handler_ != root_handler_)
48 delete entry.handler_;
49 die_handlers_.pop();
50 }
51}
52
53bool DIEDispatcher::StartCompilationUnit(uint64_t offset, uint8_t address_size,
54 uint8_t offset_size, uint64_t cu_length,
55 uint8_t dwarf_version) {
56 return root_handler_->StartCompilationUnit(offset, address_size,
57 offset_size, cu_length,
58 dwarf_version);
59}
60
61bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) {
62 // The stack entry for the parent of this DIE, if there is one.
63 HandlerStack* parent = die_handlers_.empty() ? NULL : &die_handlers_.top();
64
65 // Does this call indicate that we're done receiving the parent's
66 // attributes' values? If so, call its EndAttributes member function.
67 if (parent && parent->handler_ && !parent->reported_attributes_end_) {
68 parent->reported_attributes_end_ = true;
69 if (!parent->handler_->EndAttributes()) {
70 // Finish off this handler now. and edit *PARENT to indicate that
71 // we don't want to visit any of the children.
72 parent->handler_->Finish();
73 if (parent->handler_ != root_handler_)
74 delete parent->handler_;
75 parent->handler_ = NULL;
76 return false;
77 }
78 }
79
80 // Find a handler for this DIE.
81 DIEHandler* handler;
82 if (parent) {
83 if (parent->handler_)
84 // Ask the parent to find a handler.
85 handler = parent->handler_->FindChildHandler(offset, tag);
86 else
87 // No parent handler means we're not interested in any of our
88 // children.
89 handler = NULL;
90 } else {
91 // This is the root DIE. For a non-root DIE, the parent's handler
92 // decides whether to visit it, but the root DIE has no parent
93 // handler, so we have a special method on the root DIE handler
94 // itself to decide.
95 if (root_handler_->StartRootDIE(offset, tag))
96 handler = root_handler_;
97 else
98 handler = NULL;
99 }
100
101 // Push a handler stack entry for this new handler. As an
102 // optimization, we don't push NULL-handler entries on top of other
103 // NULL-handler entries; we just let the oldest such entry stand for
104 // the whole subtree.
105 if (handler || !parent || parent->handler_) {
106 HandlerStack entry;
107 entry.offset_ = offset;
108 entry.handler_ = handler;
109 entry.reported_attributes_end_ = false;
110 die_handlers_.push(entry);
111 }
112
113 return handler != NULL;
114}
115
116void DIEDispatcher::EndDIE(uint64_t offset) {
117 assert(!die_handlers_.empty());
118 HandlerStack* entry = &die_handlers_.top();
119 if (entry->handler_) {
120 // This entry had better be the handler for this DIE.
121 assert(entry->offset_ == offset);
122 // If a DIE has no children, this EndDIE call indicates that we're
123 // done receiving its attributes' values.
124 if (!entry->reported_attributes_end_)
125 entry->handler_->EndAttributes(); // Ignore return value: no children.
126 entry->handler_->Finish();
127 if (entry->handler_ != root_handler_)
128 delete entry->handler_;
129 } else {
130 // If this DIE is within a tree we're ignoring, then don't pop the
131 // handler stack: that entry stands for the whole tree.
132 if (entry->offset_ != offset)
133 return;
134 }
135 die_handlers_.pop();
136}
137
138void DIEDispatcher::ProcessAttributeUnsigned(uint64_t offset,
139 enum DwarfAttribute attr,
140 enum DwarfForm form,
141 uint64_t data) {
142 HandlerStack& current = die_handlers_.top();
143 // This had better be an attribute of the DIE we were meant to handle.
144 assert(offset == current.offset_);
145 current.handler_->ProcessAttributeUnsigned(attr, form, data);
146}
147
148void DIEDispatcher::ProcessAttributeSigned(uint64_t offset,
149 enum DwarfAttribute attr,
150 enum DwarfForm form,
151 int64_t data) {
152 HandlerStack& current = die_handlers_.top();
153 // This had better be an attribute of the DIE we were meant to handle.
154 assert(offset == current.offset_);
155 current.handler_->ProcessAttributeSigned(attr, form, data);
156}
157
158void DIEDispatcher::ProcessAttributeReference(uint64_t offset,
159 enum DwarfAttribute attr,
160 enum DwarfForm form,
161 uint64_t data) {
162 HandlerStack& current = die_handlers_.top();
163 // This had better be an attribute of the DIE we were meant to handle.
164 assert(offset == current.offset_);
165 current.handler_->ProcessAttributeReference(attr, form, data);
166}
167
168void DIEDispatcher::ProcessAttributeBuffer(uint64_t offset,
169 enum DwarfAttribute attr,
170 enum DwarfForm form,
171 const uint8_t* data,
172 uint64_t len) {
173 HandlerStack& current = die_handlers_.top();
174 // This had better be an attribute of the DIE we were meant to handle.
175 assert(offset == current.offset_);
176 current.handler_->ProcessAttributeBuffer(attr, form, data, len);
177}
178
179void DIEDispatcher::ProcessAttributeString(uint64_t offset,
180 enum DwarfAttribute attr,
181 enum DwarfForm form,
182 const string& data) {
183 HandlerStack& current = die_handlers_.top();
184 // This had better be an attribute of the DIE we were meant to handle.
185 assert(offset == current.offset_);
186 current.handler_->ProcessAttributeString(attr, form, data);
187}
188
189void DIEDispatcher::ProcessAttributeSignature(uint64_t offset,
190 enum DwarfAttribute attr,
191 enum DwarfForm form,
192 uint64_t signature) {
193 HandlerStack& current = die_handlers_.top();
194 // This had better be an attribute of the DIE we were meant to handle.
195 assert(offset == current.offset_);
196 current.handler_->ProcessAttributeSignature(attr, form, signature);
197}
198
199} // namespace google_breakpad
200