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 50 namespace google_breakpad { 51 52 using dwarf2reader::AttributeList; 53 using dwarf2reader::DwarfAttribute; 54 using dwarf2reader::DwarfForm; 55 using dwarf2reader::DwarfLanguage; 56 using 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. 64 class 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: LineToModuleFunctor()100 LineToModuleFunctor() { } ~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. WarningReporter(const string & filename,uint64 cu_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) { } ~WarningReporter()123 virtual ~WarningReporter() { } 124 125 // Set the name of the compilation unit we're processing to NAME. SetCUName(const string & 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. uncovered_warnings_enabled()132 virtual bool uncovered_warnings_enabled() const { 133 return uncovered_warnings_enabled_; 134 } set_uncovered_warnings_enabled(bool value)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 §ion_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