dwarf_cu_to_module.h revision fd18beeb5c817aa3ecdb21caceee8e6ce08c6ab3
1// -*- mode: c++ -*-
2
3// Copyright (c) 2010 Google Inc.
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10//     * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12//     * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16//     * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
33
34// Add DWARF debugging information to a Breakpad symbol file. This
35// file defines the DwarfCUToModule class, which accepts parsed DWARF
36// data and populates a google_breakpad::Module with the results; the
37// Module can then write its contents as a Breakpad symbol file.
38
39#ifndef COMMON_LINUX_DWARF_CU_TO_MODULE_H__
40#define COMMON_LINUX_DWARF_CU_TO_MODULE_H__
41
42#include <string>
43
44#include "common/language.h"
45#include "common/module.h"
46#include "common/dwarf/bytereader.h"
47#include "common/dwarf/dwarf2diehandler.h"
48#include "common/dwarf/dwarf2reader.h"
49
50namespace google_breakpad {
51
52using dwarf2reader::AttributeList;
53using dwarf2reader::DwarfAttribute;
54using dwarf2reader::DwarfForm;
55using dwarf2reader::DwarfLanguage;
56using dwarf2reader::DwarfTag;
57
58// Populate a google_breakpad::Module with DWARF debugging information.
59//
60// An instance of this class can be provided as a handler to a
61// dwarf2reader::CompilationUnit DWARF parser. The handler uses the
62// results of parsing to populate a google_breakpad::Module with
63// source file, function, and source line information.
64class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
65  struct FilePrivate;
66 public:
67
68  // Information global to the DWARF-bearing file we are processing,
69  // for use by DwarfCUToModule. Each DwarfCUToModule instance deals
70  // with a single compilation unit within the file, but information
71  // global to the whole file is held here. The client is responsible
72  // for filling it in appropriately (except for the 'file_private'
73  // field, which the constructor and destructor take care of), and
74  // then providing it to the DwarfCUToModule instance for each
75  // compilation unit we process in that file.
76  struct FileContext {
77    FileContext(const string &filename_arg, Module *module_arg);
78    ~FileContext();
79
80    // The name of this file, for use in error messages.
81    string filename;
82
83    // A map of this file's sections, used for finding other DWARF
84    // sections that the .debug_info section may refer to.
85    dwarf2reader::SectionMap section_map;
86
87    // The Module to which we're contributing definitions.
88    Module *module;
89
90    // Inter-compilation unit data used internally by the handlers.
91    FilePrivate *file_private;
92  };
93
94  // An abstract base class for functors that handle DWARF line data
95  // for DwarfCUToModule. DwarfCUToModule could certainly just use
96  // dwarf2reader::LineInfo itself directly, but decoupling things
97  // this way makes unit testing a little easier.
98  class LineToModuleFunctor {
99   public:
100    LineToModuleFunctor() { }
101    virtual ~LineToModuleFunctor() { }
102
103    // Populate MODULE and LINES with source file names and code/line
104    // mappings, given a pointer to some DWARF line number data
105    // PROGRAM, and an overestimate of its size. Add no zero-length
106    // lines to LINES.
107    virtual void operator()(const char *program, uint64 length,
108                            Module *module, vector<Module::Line> *lines) = 0;
109  };
110
111  // The interface DwarfCUToModule uses to report warnings. The member
112  // function definitions for this class write messages to stderr, but
113  // you can override them if you'd like to detect or report these
114  // conditions yourself.
115  class WarningReporter {
116   public:
117    // Warn about problems in the DWARF file FILENAME, in the
118    // compilation unit at OFFSET.
119    WarningReporter(const string &filename, uint64 cu_offset)
120        : filename_(filename), cu_offset_(cu_offset), printed_cu_header_(false),
121          printed_unpaired_header_(false),
122          uncovered_warnings_enabled_(false) { }
123    virtual ~WarningReporter() { }
124
125    // Set the name of the compilation unit we're processing to NAME.
126    virtual void SetCUName(const string &name) { cu_name_ = name; }
127
128    // Accessor and setter for uncovered_warnings_enabled_.
129    // UncoveredFunction and UncoveredLine only report a problem if that is
130    // true. By default, these warnings are disabled, because those
131    // conditions occur occasionally in healthy code.
132    virtual bool uncovered_warnings_enabled() const {
133      return uncovered_warnings_enabled_;
134    }
135    virtual void set_uncovered_warnings_enabled(bool value) {
136      uncovered_warnings_enabled_ = value;
137    }
138
139    // A DW_AT_specification in the DIE at OFFSET refers to a DIE we
140    // haven't processed yet, or that wasn't marked as a declaration,
141    // at TARGET.
142    virtual void UnknownSpecification(uint64 offset, uint64 target);
143
144    // A DW_AT_abstract_origin in the DIE at OFFSET refers to a DIE we
145    // haven't processed yet, or that wasn't marked as inline, at TARGET.
146    virtual void UnknownAbstractOrigin(uint64 offset, uint64 target);
147
148    // We were unable to find the DWARF section named SECTION_NAME.
149    virtual void MissingSection(const string &section_name);
150
151    // The CU's DW_AT_stmt_list offset OFFSET is bogus.
152    virtual void BadLineInfoOffset(uint64 offset);
153
154    // FUNCTION includes code covered by no line number data.
155    virtual void UncoveredFunction(const Module::Function &function);
156
157    // Line number NUMBER in LINE_FILE, of length LENGTH, includes code
158    // covered by no function.
159    virtual void UncoveredLine(const Module::Line &line);
160
161    // The DW_TAG_subprogram DIE at OFFSET has no name specified directly
162    // in the DIE, nor via a DW_AT_specification or DW_AT_abstract_origin
163    // link.
164    virtual void UnnamedFunction(uint64 offset);
165
166   protected:
167    string filename_;
168    uint64 cu_offset_;
169    string cu_name_;
170    bool printed_cu_header_;
171    bool printed_unpaired_header_;
172    bool uncovered_warnings_enabled_;
173
174   private:
175    // Print a per-CU heading, once.
176    void CUHeading();
177    // Print an unpaired function/line heading, once.
178    void UncoveredHeading();
179  };
180
181  // Create a DWARF debugging info handler for a compilation unit
182  // within FILE_CONTEXT. This uses information received from the
183  // dwarf2reader::CompilationUnit DWARF parser to populate
184  // FILE_CONTEXT->module. Use LINE_READER to handle the compilation
185  // unit's line number data. Use REPORTER to report problems with the
186  // data we find.
187  DwarfCUToModule(FileContext *file_context,
188                  LineToModuleFunctor *line_reader,
189                  WarningReporter *reporter);
190  ~DwarfCUToModule();
191
192  void ProcessAttributeSigned(enum DwarfAttribute attr,
193                              enum DwarfForm form,
194                              int64 data);
195  void ProcessAttributeUnsigned(enum DwarfAttribute attr,
196                                enum DwarfForm form,
197                                uint64 data);
198  void ProcessAttributeString(enum DwarfAttribute attr,
199                              enum DwarfForm form,
200                              const string &data);
201  bool EndAttributes();
202  DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag,
203                               const AttributeList &attrs);
204
205  // Assign all our source Lines to the Functions that cover their
206  // addresses, and then add them to module_.
207  void Finish();
208
209  bool StartCompilationUnit(uint64 offset, uint8 address_size,
210                            uint8 offset_size, uint64 cu_length,
211                            uint8 dwarf_version);
212  bool StartRootDIE(uint64 offset, enum DwarfTag tag,
213                    const AttributeList& attrs);
214
215 private:
216
217  // Used internally by the handler. Full definitions are in
218  // dwarf_cu_to_module.cc.
219  struct FilePrivate;
220  struct Specification;
221  struct CUContext;
222  struct DIEContext;
223  class GenericDIEHandler;
224  class FuncHandler;
225  class NamedScopeHandler;
226
227  // A map from section offsets to specifications.
228  typedef map<uint64, Specification> SpecificationByOffset;
229
230  // Set this compilation unit's source language to LANGUAGE.
231  void SetLanguage(DwarfLanguage language);
232
233  // Read source line information at OFFSET in the .debug_line
234  // section.  Record source files in module_, but record source lines
235  // in lines_; we apportion them to functions in
236  // AssignLinesToFunctions.
237  void ReadSourceLines(uint64 offset);
238
239  // Assign the lines in lines_ to the individual line lists of the
240  // functions in functions_.  (DWARF line information maps an entire
241  // compilation unit at a time, and gives no indication of which
242  // lines belong to which functions, beyond their addresses.)
243  void AssignLinesToFunctions();
244
245  // The only reason cu_context_ and child_context_ are pointers is
246  // that we want to keep their definitions private to
247  // dwarf_cu_to_module.cc, instead of listing them all here. They are
248  // owned by this DwarfCUToModule: the constructor sets them, and the
249  // destructor deletes them.
250
251  // The functor to use to handle line number data.
252  LineToModuleFunctor *line_reader_;
253
254  // This compilation unit's context.
255  CUContext *cu_context_;
256
257  // A context for our children.
258  DIEContext *child_context_;
259
260  // True if this compilation unit has source line information.
261  bool has_source_line_info_;
262
263  // The offset of this compilation unit's line number information in
264  // the .debug_line section.
265  uint64 source_line_offset_;
266
267  // The line numbers we have seen thus far.  We accumulate these here
268  // during parsing.  Then, in Finish, we call AssignLinesToFunctions
269  // to dole them out to the appropriate functions.
270  vector<Module::Line> lines_;
271};
272
273} // namespace google_breakpad
274
275#endif  // COMMON_LINUX_DWARF_CU_TO_MODULE_H__
276