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