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