/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. // Copyright (c) 2010 Google Inc. All Rights Reserved.
  3. //
  4. // Redistribution and use in source and binary forms, with or without
  5. // modification, are permitted provided that the following conditions are
  6. // met:
  7. //
  8. // * Redistributions of source code must retain the above copyright
  9. // notice, this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above
  11. // copyright notice, this list of conditions and the following disclaimer
  12. // in the documentation and/or other materials provided with the
  13. // distribution.
  14. // * Neither the name of Google Inc. nor the names of its
  15. // contributors may be used to endorse or promote products derived from
  16. // this software without specific prior written permission.
  17. //
  18. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
  30. // dwarf2reader::CompilationUnit is a simple and direct parser for
  31. // DWARF data, but its handler interface is not convenient to use. In
  32. // particular:
  33. //
  34. // - CompilationUnit calls Dwarf2Handler's member functions to report
  35. // every attribute's value, regardless of what sort of DIE it is.
  36. // As a result, the ProcessAttributeX functions end up looking like
  37. // this:
  38. //
  39. // switch (parent_die_tag) {
  40. // case DW_TAG_x:
  41. // switch (attribute_name) {
  42. // case DW_AT_y:
  43. // handle attribute y of DIE type x
  44. // ...
  45. // } break;
  46. // ...
  47. // }
  48. //
  49. // In C++ it's much nicer to use virtual function dispatch to find
  50. // the right code for a given case than to switch on the DIE tag
  51. // like this.
  52. //
  53. // - Processing different kinds of DIEs requires different sets of
  54. // data: lexical block DIEs have start and end addresses, but struct
  55. // type DIEs don't. It would be nice to be able to have separate
  56. // handler classes for separate kinds of DIEs, each with the members
  57. // appropriate to its role, instead of having one handler class that
  58. // needs to hold data for every DIE type.
  59. //
  60. // - There should be a separate instance of the appropriate handler
  61. // class for each DIE, instead of a single object with tables
  62. // tracking all the dies in the compilation unit.
  63. //
  64. // - It's not convenient to take some action after all a DIE's
  65. // attributes have been seen, but before visiting any of its
  66. // children. The only indication you have that a DIE's attribute
  67. // list is complete is that you get either a StartDIE or an EndDIE
  68. // call.
  69. //
  70. // - It's not convenient to make use of the tree structure of the
  71. // DIEs. Skipping all the children of a given die requires
  72. // maintaining state and returning false from StartDIE until we get
  73. // an EndDIE call with the appropriate offset.
  74. //
  75. // This interface tries to take care of all that. (You're shocked, I'm sure.)
  76. //
  77. // Using the classes here, you provide an initial handler for the root
  78. // DIE of the compilation unit. Each handler receives its DIE's
  79. // attributes, and provides fresh handler objects for children of
  80. // interest, if any. The three classes are:
  81. //
  82. // - DIEHandler: the base class for your DIE-type-specific handler
  83. // classes.
  84. //
  85. // - RootDIEHandler: derived from DIEHandler, the base class for your
  86. // root DIE handler class.
  87. //
  88. // - DIEDispatcher: derived from Dwarf2Handler, an instance of this
  89. // invokes your DIE-type-specific handler objects.
  90. //
  91. // In detail:
  92. //
  93. // - Define handler classes specialized for the DIE types you're
  94. // interested in. These handler classes must inherit from
  95. // DIEHandler. Thus:
  96. //
  97. // class My_DW_TAG_X_Handler: public DIEHandler { ... };
  98. // class My_DW_TAG_Y_Handler: public DIEHandler { ... };
  99. //
  100. // DIEHandler subclasses needn't correspond exactly to single DIE
  101. // types, as shown here; the point is that you can have several
  102. // different classes appropriate to different kinds of DIEs.
  103. //
  104. // - In particular, define a handler class for the compilation
  105. // unit's root DIE, that inherits from RootDIEHandler:
  106. //
  107. // class My_DW_TAG_compile_unit_Handler: public RootDIEHandler { ... };
  108. //
  109. // RootDIEHandler inherits from DIEHandler, adding a few additional
  110. // member functions for examining the compilation unit as a whole,
  111. // and other quirks of rootness.
  112. //
  113. // - Then, create a DIEDispatcher instance, passing it an instance of
  114. // your root DIE handler class, and use that DIEDispatcher as the
  115. // dwarf2reader::CompilationUnit's handler:
  116. //
  117. // My_DW_TAG_compile_unit_Handler root_die_handler(...);
  118. // DIEDispatcher die_dispatcher(&root_die_handler);
  119. // CompilationUnit reader(sections, offset, bytereader, &die_dispatcher);
  120. //
  121. // Here, 'die_dispatcher' acts as a shim between 'reader' and the
  122. // various DIE-specific handlers you have defined.
  123. //
  124. // - When you call reader.Start(), die_dispatcher behaves as follows,
  125. // starting with your root die handler and the compilation unit's
  126. // root DIE:
  127. //
  128. // - It calls the handler's ProcessAttributeX member functions for
  129. // each of the DIE's attributes.
  130. //
  131. // - It calls the handler's EndAttributes member function. This
  132. // should return true if any of the DIE's children should be
  133. // visited, in which case:
  134. //
  135. // - For each of the DIE's children, die_dispatcher calls the
  136. // DIE's handler's FindChildHandler member function. If that
  137. // returns a pointer to a DIEHandler instance, then
  138. // die_dispatcher uses that handler to process the child, using
  139. // this procedure recursively. Alternatively, if
  140. // FindChildHandler returns NULL, die_dispatcher ignores that
  141. // child and its descendants.
  142. //
  143. // - When die_dispatcher has finished processing all the DIE's
  144. // children, it invokes the handler's Finish() member function,
  145. // and destroys the handler. (As a special case, it doesn't
  146. // destroy the root DIE handler.)
  147. //
  148. // This allows the code for handling a particular kind of DIE to be
  149. // gathered together in a single class, makes it easy to skip all the
  150. // children or individual children of a particular DIE, and provides
  151. // appropriate parental context for each die.
  152. #ifndef COMMON_DWARF_DWARF2DIEHANDLER_H__
  153. #define COMMON_DWARF_DWARF2DIEHANDLER_H__
  154. #include <stack>
  155. #include "common/dwarf/types.h"
  156. #include "common/dwarf/dwarf2enums.h"
  157. #include "common/dwarf/dwarf2reader.h"
  158. namespace dwarf2reader {
  159. // A base class for handlers for specific DIE types. The series of
  160. // calls made on a DIE handler is as follows:
  161. //
  162. // - for each attribute of the DIE:
  163. // - ProcessAttributeX()
  164. // - EndAttributes()
  165. // - if that returned true, then for each child:
  166. // - FindChildHandler()
  167. // - if that returns a non-NULL pointer to a new handler:
  168. // - recurse, with the new handler and the child die
  169. // - Finish()
  170. // - destruction
  171. class DIEHandler {
  172. public:
  173. DIEHandler() { }
  174. virtual ~DIEHandler() { }
  175. // When we visit a DIE, we first use these member functions to
  176. // report the DIE's attributes and their values. These have the
  177. // same restrictions as the corresponding member functions of
  178. // dwarf2reader::Dwarf2Handler.
  179. //
  180. // Since DWARF does not specify in what order attributes must
  181. // appear, avoid making decisions in these functions that would be
  182. // affected by the presence of other attributes. The EndAttributes
  183. // function is a more appropriate place for such work, as all the
  184. // DIE's attributes have been seen at that point.
  185. //
  186. // The default definitions ignore the values they are passed.
  187. virtual void ProcessAttributeUnsigned(enum DwarfAttribute attr,
  188. enum DwarfForm form,
  189. uint64 data) { }
  190. virtual void ProcessAttributeSigned(enum DwarfAttribute attr,
  191. enum DwarfForm form,
  192. int64 data) { }
  193. virtual void ProcessAttributeReference(enum DwarfAttribute attr,
  194. enum DwarfForm form,
  195. uint64 data) { }
  196. virtual void ProcessAttributeBuffer(enum DwarfAttribute attr,
  197. enum DwarfForm form,
  198. const char* data,
  199. uint64 len) { }
  200. virtual void ProcessAttributeString(enum DwarfAttribute attr,
  201. enum DwarfForm form,
  202. const std::string& data) { }
  203. virtual void ProcessAttributeSignature(enum DwarfAttribute attr,
  204. enum DwarfForm form,
  205. uint64 signture) { }
  206. // Once we have reported all the DIE's attributes' values, we call
  207. // this member function. If it returns false, we skip all the DIE's
  208. // children. If it returns true, we call FindChildHandler on each
  209. // child. If that returns a handler object, we use that to visit
  210. // the child; otherwise, we skip the child.
  211. //
  212. // This is a good place to make decisions that depend on more than
  213. // one attribute. DWARF does not specify in what order attributes
  214. // must appear, so only when the EndAttributes function is called
  215. // does the handler have a complete picture of the DIE's attributes.
  216. //
  217. // The default definition elects to ignore the DIE's children.
  218. // You'll need to override this if you override FindChildHandler,
  219. // but at least the default behavior isn't to pass the children to
  220. // FindChildHandler, which then ignores them all.
  221. virtual bool EndAttributes() { return false; }
  222. // If EndAttributes returns true to indicate that some of the DIE's
  223. // children might be of interest, then we apply this function to
  224. // each of the DIE's children. If it returns a handler object, then
  225. // we use that to visit the child DIE. If it returns NULL, we skip
  226. // that child DIE (and all its descendants).
  227. //
  228. // OFFSET is the offset of the child; TAG indicates what kind of DIE
  229. // it is; and ATTRS is the list of attributes the DIE will have, and
  230. // their forms (their values are not provided).
  231. //
  232. // The default definition skips all children.
  233. virtual DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag,
  234. const AttributeList &attrs) {
  235. return NULL;
  236. }
  237. // When we are done processing a DIE, we call this member function.
  238. // This happens after the EndAttributes call, all FindChildHandler
  239. // calls (if any), and all operations on the children themselves (if
  240. // any). We call Finish on every handler --- even if EndAttributes
  241. // returns false.
  242. virtual void Finish() { };
  243. };
  244. // A subclass of DIEHandler, with additional kludges for handling the
  245. // compilation unit's root die.
  246. class RootDIEHandler: public DIEHandler {
  247. public:
  248. RootDIEHandler() { }
  249. virtual ~RootDIEHandler() { }
  250. // We pass the values reported via Dwarf2Handler::StartCompilationUnit
  251. // to this member function, and skip the entire compilation unit if it
  252. // returns false. So the root DIE handler is actually also
  253. // responsible for handling the compilation unit metadata.
  254. // The default definition always visits the compilation unit.
  255. virtual bool StartCompilationUnit(uint64 offset, uint8 address_size,
  256. uint8 offset_size, uint64 cu_length,
  257. uint8 dwarf_version) { return true; }
  258. // For the root DIE handler only, we pass the offset, tag and
  259. // attributes of the compilation unit's root DIE. This is the only
  260. // way the root DIE handler can find the root DIE's tag. If this
  261. // function returns true, we will visit the root DIE using the usual
  262. // DIEHandler methods; otherwise, we skip the entire compilation
  263. // unit.
  264. //
  265. // The default definition elects to visit the root DIE.
  266. virtual bool StartRootDIE(uint64 offset, enum DwarfTag tag,
  267. const AttributeList& attrs) { return true; }
  268. };
  269. class DIEDispatcher: public Dwarf2Handler {
  270. public:
  271. // Create a Dwarf2Handler which uses ROOT_HANDLER as the handler for
  272. // the compilation unit's root die, as described for the DIEHandler
  273. // class.
  274. DIEDispatcher(RootDIEHandler *root_handler) : root_handler_(root_handler) { }
  275. // Destroying a DIEDispatcher destroys all active handler objects
  276. // except the root handler.
  277. ~DIEDispatcher();
  278. bool StartCompilationUnit(uint64 offset, uint8 address_size,
  279. uint8 offset_size, uint64 cu_length,
  280. uint8 dwarf_version);
  281. bool StartDIE(uint64 offset, enum DwarfTag tag,
  282. const AttributeList &attrs);
  283. void ProcessAttributeUnsigned(uint64 offset,
  284. enum DwarfAttribute attr,
  285. enum DwarfForm form,
  286. uint64 data);
  287. void ProcessAttributeSigned(uint64 offset,
  288. enum DwarfAttribute attr,
  289. enum DwarfForm form,
  290. int64 data);
  291. void ProcessAttributeReference(uint64 offset,
  292. enum DwarfAttribute attr,
  293. enum DwarfForm form,
  294. uint64 data);
  295. void ProcessAttributeBuffer(uint64 offset,
  296. enum DwarfAttribute attr,
  297. enum DwarfForm form,
  298. const char* data,
  299. uint64 len);
  300. void ProcessAttributeString(uint64 offset,
  301. enum DwarfAttribute attr,
  302. enum DwarfForm form,
  303. const std::string &data);
  304. void ProcessAttributeSignature(uint64 offset,
  305. enum DwarfAttribute attr,
  306. enum DwarfForm form,
  307. uint64 signature);
  308. void EndDIE(uint64 offset);
  309. private:
  310. // The type of a handler stack entry. This includes some fields
  311. // which don't really need to be on the stack --- they could just be
  312. // single data members of DIEDispatcher --- but putting them here
  313. // makes it easier to see that the code is correct.
  314. struct HandlerStack {
  315. // The offset of the DIE for this handler stack entry.
  316. uint64 offset_;
  317. // The handler object interested in this DIE's attributes and
  318. // children. If NULL, we're not interested in either.
  319. DIEHandler *handler_;
  320. // Have we reported the end of this DIE's attributes to the handler?
  321. bool reported_attributes_end_;
  322. };
  323. // Stack of DIE attribute handlers. At StartDIE(D), the top of the
  324. // stack is the handler of D's parent, whom we may ask for a handler
  325. // for D itself. At EndDIE(D), the top of the stack is D's handler.
  326. // Special cases:
  327. //
  328. // - Before we've seen the compilation unit's root DIE, the stack is
  329. // empty; we'll call root_handler_'s special member functions, and
  330. // perhaps push root_handler_ on the stack to look at the root's
  331. // immediate children.
  332. //
  333. // - When we decide to ignore a subtree, we only push an entry on
  334. // the stack for the root of the tree being ignored, rather than
  335. // pushing lots of stack entries with handler_ set to NULL.
  336. std::stack<HandlerStack> die_handlers_;
  337. // The root handler. We don't push it on die_handlers_ until we
  338. // actually get the StartDIE call for the root.
  339. RootDIEHandler *root_handler_;
  340. };
  341. } // namespace dwarf2reader
  342. #endif // COMMON_DWARF_DWARF2DIEHANDLER_H__