PageRenderTime 28ms CodeModel.GetById 9ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/thirdparty/breakpad/common/dwarf/dwarf2diehandler.h

http://github.com/tomahawk-player/tomahawk
C++ Header | 365 lines | 93 code | 23 blank | 249 comment | 0 complexity | be050006a2e82cf2db61a9deb813a29b MD5 | raw file
  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
165namespace 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
179class 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 std::string& data) { }
212  virtual void ProcessAttributeSignature(enum DwarfAttribute attr,
213                                         enum DwarfForm form,
214                                         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  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  virtual DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag,
245                                       const AttributeList &attrs) {
246    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  virtual void Finish() { };
255};
256
257// A subclass of DIEHandler, with additional kludges for handling the
258// compilation unit's root die.
259class RootDIEHandler: public DIEHandler {
260 public:
261  RootDIEHandler() { }
262  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  virtual bool StartCompilationUnit(uint64 offset, uint8 address_size,
270                                    uint8 offset_size, uint64 cu_length,
271                                    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  virtual bool StartRootDIE(uint64 offset, enum DwarfTag tag,
282                            const AttributeList& attrs) { return true; }
283};
284
285class 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  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 std::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  std::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__