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
169namespace 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
183class 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.
261class 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
289class 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