OLD | NEW |
| (Empty) |
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 <stack> | |
160 | |
161 #include "common/dwarf/types.h" | |
162 #include "common/dwarf/dwarf2enums.h" | |
163 #include "common/dwarf/dwarf2reader.h" | |
164 | |
165 namespace dwarf2reader { | |
166 | |
167 // A base class for handlers for specific DIE types. The series of | |
168 // calls made on a DIE handler is as follows: | |
169 // | |
170 // - for each attribute of the DIE: | |
171 // - ProcessAttributeX() | |
172 // - EndAttributes() | |
173 // - if that returned true, then for each child: | |
174 // - FindChildHandler() | |
175 // - if that returns a non-NULL pointer to a new handler: | |
176 // - recurse, with the new handler and the child die | |
177 // - Finish() | |
178 // - destruction | |
179 class DIEHandler { | |
180 public: | |
181 DIEHandler() { } | |
182 virtual ~DIEHandler() { } | |
183 | |
184 // When we visit a DIE, we first use these member functions to | |
185 // report the DIE's attributes and their values. These have the | |
186 // same restrictions as the corresponding member functions of | |
187 // dwarf2reader::Dwarf2Handler. | |
188 // | |
189 // Since DWARF does not specify in what order attributes must | |
190 // appear, avoid making decisions in these functions that would be | |
191 // affected by the presence of other attributes. The EndAttributes | |
192 // function is a more appropriate place for such work, as all the | |
193 // DIE's attributes have been seen at that point. | |
194 // | |
195 // The default definitions ignore the values they are passed. | |
196 virtual void ProcessAttributeUnsigned(enum DwarfAttribute attr, | |
197 enum DwarfForm form, | |
198 uint64 data) { } | |
199 virtual void ProcessAttributeSigned(enum DwarfAttribute attr, | |
200 enum DwarfForm form, | |
201 int64 data) { } | |
202 virtual void ProcessAttributeReference(enum DwarfAttribute attr, | |
203 enum DwarfForm form, | |
204 uint64 data) { } | |
205 virtual void ProcessAttributeBuffer(enum DwarfAttribute attr, | |
206 enum DwarfForm form, | |
207 const char* data, | |
208 uint64 len) { } | |
209 virtual void ProcessAttributeString(enum DwarfAttribute attr, | |
210 enum DwarfForm form, | |
211 const string& data) { } | |
212 | |
213 // Once we have reported all the DIE's attributes' values, we call | |
214 // this member function. If it returns false, we skip all the DIE's | |
215 // children. If it returns true, we call FindChildHandler on each | |
216 // child. If that returns a handler object, we use that to visit | |
217 // the child; otherwise, we skip the child. | |
218 // | |
219 // This is a good place to make decisions that depend on more than | |
220 // one attribute. DWARF does not specify in what order attributes | |
221 // must appear, so only when the EndAttributes function is called | |
222 // does the handler have a complete picture of the DIE's attributes. | |
223 // | |
224 // The default definition elects to ignore the DIE's children. | |
225 // You'll need to override this if you override FindChildHandler, | |
226 // but at least the default behavior isn't to pass the children to | |
227 // FindChildHandler, which then ignores them all. | |
228 virtual bool EndAttributes() { return false; } | |
229 | |
230 // If EndAttributes returns true to indicate that some of the DIE's | |
231 // children might be of interest, then we apply this function to | |
232 // each of the DIE's children. If it returns a handler object, then | |
233 // we use that to visit the child DIE. If it returns NULL, we skip | |
234 // that child DIE (and all its descendants). | |
235 // | |
236 // OFFSET is the offset of the child; TAG indicates what kind of DIE | |
237 // it is; and ATTRS is the list of attributes the DIE will have, and | |
238 // their forms (their values are not provided). | |
239 // | |
240 // The default definition skips all children. | |
241 virtual DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag, | |
242 const AttributeList &attrs) { | |
243 return NULL; | |
244 } | |
245 | |
246 // When we are done processing a DIE, we call this member function. | |
247 // This happens after the EndAttributes call, all FindChildHandler | |
248 // calls (if any), and all operations on the children themselves (if | |
249 // any). We call Finish on every handler --- even if EndAttributes | |
250 // returns false. | |
251 virtual void Finish() { }; | |
252 }; | |
253 | |
254 // A subclass of DIEHandler, with additional kludges for handling the | |
255 // compilation unit's root die. | |
256 class RootDIEHandler: public DIEHandler { | |
257 public: | |
258 RootDIEHandler() { } | |
259 virtual ~RootDIEHandler() { } | |
260 | |
261 // We pass the values reported via Dwarf2Handler::StartCompilationUnit | |
262 // to this member function, and skip the entire compilation unit if it | |
263 // returns false. So the root DIE handler is actually also | |
264 // responsible for handling the compilation unit metadata. | |
265 // The default definition always visits the compilation unit. | |
266 virtual bool StartCompilationUnit(uint64 offset, uint8 address_size, | |
267 uint8 offset_size, uint64 cu_length, | |
268 uint8 dwarf_version) { return true; } | |
269 | |
270 // For the root DIE handler only, we pass the offset, tag and | |
271 // attributes of the compilation unit's root DIE. This is the only | |
272 // way the root DIE handler can find the root DIE's tag. If this | |
273 // function returns true, we will visit the root DIE using the usual | |
274 // DIEHandler methods; otherwise, we skip the entire compilation | |
275 // unit. | |
276 // | |
277 // The default definition elects to visit the root DIE. | |
278 virtual bool StartRootDIE(uint64 offset, enum DwarfTag tag, | |
279 const AttributeList& attrs) { return true; } | |
280 }; | |
281 | |
282 class DIEDispatcher: public Dwarf2Handler { | |
283 public: | |
284 // Create a Dwarf2Handler which uses ROOT_HANDLER as the handler for | |
285 // the compilation unit's root die, as described for the DIEHandler | |
286 // class. | |
287 DIEDispatcher(RootDIEHandler *root_handler) : root_handler_(root_handler) { } | |
288 // Destroying a DIEDispatcher destroys all active handler objects | |
289 // except the root handler. | |
290 ~DIEDispatcher(); | |
291 bool StartCompilationUnit(uint64 offset, uint8 address_size, | |
292 uint8 offset_size, uint64 cu_length, | |
293 uint8 dwarf_version); | |
294 bool StartDIE(uint64 offset, enum DwarfTag tag, | |
295 const AttributeList &attrs); | |
296 void ProcessAttributeUnsigned(uint64 offset, | |
297 enum DwarfAttribute attr, | |
298 enum DwarfForm form, | |
299 uint64 data); | |
300 void ProcessAttributeSigned(uint64 offset, | |
301 enum DwarfAttribute attr, | |
302 enum DwarfForm form, | |
303 int64 data); | |
304 void ProcessAttributeReference(uint64 offset, | |
305 enum DwarfAttribute attr, | |
306 enum DwarfForm form, | |
307 uint64 data); | |
308 void ProcessAttributeBuffer(uint64 offset, | |
309 enum DwarfAttribute attr, | |
310 enum DwarfForm form, | |
311 const char* data, | |
312 uint64 len); | |
313 void ProcessAttributeString(uint64 offset, | |
314 enum DwarfAttribute attr, | |
315 enum DwarfForm form, | |
316 const string &data); | |
317 void EndDIE(uint64 offset); | |
318 | |
319 private: | |
320 | |
321 // The type of a handler stack entry. This includes some fields | |
322 // which don't really need to be on the stack --- they could just be | |
323 // single data members of DIEDispatcher --- but putting them here | |
324 // makes it easier to see that the code is correct. | |
325 struct HandlerStack { | |
326 // The offset of the DIE for this handler stack entry. | |
327 uint64 offset_; | |
328 | |
329 // The handler object interested in this DIE's attributes and | |
330 // children. If NULL, we're not interested in either. | |
331 DIEHandler *handler_; | |
332 | |
333 // Have we reported the end of this DIE's attributes to the handler? | |
334 bool reported_attributes_end_; | |
335 }; | |
336 | |
337 // Stack of DIE attribute handlers. At StartDIE(D), the top of the | |
338 // stack is the handler of D's parent, whom we may ask for a handler | |
339 // for D itself. At EndDIE(D), the top of the stack is D's handler. | |
340 // Special cases: | |
341 // | |
342 // - Before we've seen the compilation unit's root DIE, the stack is | |
343 // empty; we'll call root_handler_'s special member functions, and | |
344 // perhaps push root_handler_ on the stack to look at the root's | |
345 // immediate children. | |
346 // | |
347 // - When we decide to ignore a subtree, we only push an entry on | |
348 // the stack for the root of the tree being ignored, rather than | |
349 // pushing lots of stack entries with handler_ set to NULL. | |
350 stack<HandlerStack> die_handlers_; | |
351 | |
352 // The root handler. We don't push it on die_handlers_ until we | |
353 // actually get the StartDIE call for the root. | |
354 RootDIEHandler *root_handler_; | |
355 }; | |
356 | |
357 } // namespace dwarf2reader | |
358 #endif // COMMON_DWARF_DWARF2DIEHANDLER_H__ | |
OLD | NEW |