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