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 dwarf2reader {
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:
DIEHandler()185   DIEHandler() { }
~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.
ProcessAttributeUnsigned(enum DwarfAttribute attr,enum DwarfForm form,uint64_t data)200   virtual void ProcessAttributeUnsigned(enum DwarfAttribute attr,
201                                         enum DwarfForm form,
202                                         uint64_t data) { }
ProcessAttributeSigned(enum DwarfAttribute attr,enum DwarfForm form,int64_t data)203   virtual void ProcessAttributeSigned(enum DwarfAttribute attr,
204                                       enum DwarfForm form,
205                                       int64_t data) { }
ProcessAttributeReference(enum DwarfAttribute attr,enum DwarfForm form,uint64_t data)206   virtual void ProcessAttributeReference(enum DwarfAttribute attr,
207                                          enum DwarfForm form,
208                                          uint64_t data) { }
ProcessAttributeBuffer(enum DwarfAttribute attr,enum DwarfForm form,const uint8_t * data,uint64_t len)209   virtual void ProcessAttributeBuffer(enum DwarfAttribute attr,
210                                       enum DwarfForm form,
211                                       const uint8_t *data,
212                                       uint64_t len) { }
ProcessAttributeString(enum DwarfAttribute attr,enum DwarfForm form,const string & data)213   virtual void ProcessAttributeString(enum DwarfAttribute attr,
214                                       enum DwarfForm form,
215                                       const string& data) { }
ProcessAttributeSignature(enum DwarfAttribute attr,enum DwarfForm form,uint64_t signture)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.
EndAttributes()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.
FindChildHandler(uint64_t offset,enum DwarfTag tag)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.
Finish()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:
RootDIEHandler()263   RootDIEHandler() { }
~RootDIEHandler()264   virtual ~RootDIEHandler() { }
265 
266   // We pass the values reported via Dwarf2Handler::StartCompilationUnit
267   // to this member function, and skip the entire compilation unit if it
268   // returns false.  So the root DIE handler is actually also
269   // responsible for handling the compilation unit metadata.
270   // The default definition always visits the compilation unit.
StartCompilationUnit(uint64_t offset,uint8_t address_size,uint8_t offset_size,uint64_t cu_length,uint8_t dwarf_version)271   virtual bool StartCompilationUnit(uint64_t offset, uint8_t address_size,
272                                     uint8_t offset_size, uint64_t cu_length,
273                                     uint8_t dwarf_version) { return true; }
274 
275   // For the root DIE handler only, we pass the offset, tag and
276   // attributes of the compilation unit's root DIE.  This is the only
277   // way the root DIE handler can find the root DIE's tag.  If this
278   // function returns true, we will visit the root DIE using the usual
279   // DIEHandler methods; otherwise, we skip the entire compilation
280   // unit.
281   //
282   // The default definition elects to visit the root DIE.
StartRootDIE(uint64_t offset,enum DwarfTag tag)283   virtual bool StartRootDIE(uint64_t offset, enum DwarfTag tag) { return true; }
284 };
285 
286 class DIEDispatcher: public Dwarf2Handler {
287  public:
288   // Create a Dwarf2Handler which uses ROOT_HANDLER as the handler for
289   // the compilation unit's root die, as described for the DIEHandler
290   // class.
DIEDispatcher(RootDIEHandler * root_handler)291   DIEDispatcher(RootDIEHandler *root_handler) : root_handler_(root_handler) { }
292   // Destroying a DIEDispatcher destroys all active handler objects
293   // except the root handler.
294   ~DIEDispatcher();
295   bool StartCompilationUnit(uint64_t offset, uint8_t address_size,
296                             uint8_t offset_size, uint64_t cu_length,
297                             uint8_t dwarf_version);
298   bool StartDIE(uint64_t offset, enum DwarfTag tag);
299   void ProcessAttributeUnsigned(uint64_t offset,
300                                 enum DwarfAttribute attr,
301                                 enum DwarfForm form,
302                                 uint64_t data);
303   void ProcessAttributeSigned(uint64_t offset,
304                               enum DwarfAttribute attr,
305                               enum DwarfForm form,
306                               int64_t data);
307   void ProcessAttributeReference(uint64_t offset,
308                                  enum DwarfAttribute attr,
309                                  enum DwarfForm form,
310                                  uint64_t data);
311   void ProcessAttributeBuffer(uint64_t offset,
312                               enum DwarfAttribute attr,
313                               enum DwarfForm form,
314                               const uint8_t *data,
315                               uint64_t len);
316   void ProcessAttributeString(uint64_t offset,
317                               enum DwarfAttribute attr,
318                               enum DwarfForm form,
319                               const string &data);
320   void ProcessAttributeSignature(uint64_t offset,
321                                  enum DwarfAttribute attr,
322                                  enum DwarfForm form,
323                                  uint64_t signature);
324   void EndDIE(uint64_t 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_t 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__
366