1 // Copyright (c) 2010 Google Inc. All Rights Reserved. 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google Inc. nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 // This is a client for the dwarf2reader to extract function and line 30 // information from the debug info. 31 32 #include <assert.h> 33 #include <limits.h> 34 #include <stdio.h> 35 36 #include <map> 37 #include <queue> 38 #include <vector> 39 40 #include "common/dwarf/functioninfo.h" 41 #include "common/dwarf/bytereader.h" 42 #include "common/scoped_ptr.h" 43 #include "common/using_std_string.h" 44 45 using google_breakpad::scoped_ptr; 46 47 namespace dwarf2reader { 48 49 CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files, 50 std::vector<string>* dirs, 51 LineMap* linemap):linemap_(linemap), 52 files_(files), 53 dirs_(dirs) { 54 // The dirs and files are 1 indexed, so just make sure we put 55 // nothing in the 0 vector. 56 assert(dirs->size() == 0); 57 assert(files->size() == 0); 58 dirs->push_back(""); 59 SourceFileInfo s; 60 s.name = ""; 61 s.lowpc = ULLONG_MAX; 62 files->push_back(s); 63 } 64 65 void CULineInfoHandler::DefineDir(const string& name, uint32 dir_num) { 66 // These should never come out of order, actually 67 assert(dir_num == dirs_->size()); 68 dirs_->push_back(name); 69 } 70 71 void CULineInfoHandler::DefineFile(const string& name, 72 int32 file_num, uint32 dir_num, 73 uint64 mod_time, uint64 length) { 74 assert(dir_num >= 0); 75 assert(dir_num < dirs_->size()); 76 77 // These should never come out of order, actually. 78 if (file_num == (int32)files_->size() || file_num == -1) { 79 string dir = dirs_->at(dir_num); 80 81 SourceFileInfo s; 82 s.lowpc = ULLONG_MAX; 83 84 if (dir == "") { 85 s.name = name; 86 } else { 87 s.name = dir + "/" + name; 88 } 89 90 files_->push_back(s); 91 } else { 92 fprintf(stderr, "error in DefineFile"); 93 } 94 } 95 96 void CULineInfoHandler::AddLine(uint64 address, uint64 length, uint32 file_num, 97 uint32 line_num, uint32 column_num) { 98 if (file_num < files_->size()) { 99 linemap_->insert( 100 std::make_pair(address, 101 std::make_pair(files_->at(file_num).name.c_str(), 102 line_num))); 103 104 if (address < files_->at(file_num).lowpc) { 105 files_->at(file_num).lowpc = address; 106 } 107 } else { 108 fprintf(stderr, "error in AddLine"); 109 } 110 } 111 112 bool CUFunctionInfoHandler::StartCompilationUnit(uint64 offset, 113 uint8 address_size, 114 uint8 offset_size, 115 uint64 cu_length, 116 uint8 dwarf_version) { 117 current_compilation_unit_offset_ = offset; 118 return true; 119 } 120 121 122 // For function info, we only care about subprograms and inlined 123 // subroutines. For line info, the DW_AT_stmt_list lives in the 124 // compile unit tag. 125 126 bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag) { 127 switch (tag) { 128 case DW_TAG_subprogram: 129 case DW_TAG_inlined_subroutine: { 130 current_function_info_ = new FunctionInfo; 131 current_function_info_->lowpc = current_function_info_->highpc = 0; 132 current_function_info_->name = ""; 133 current_function_info_->line = 0; 134 current_function_info_->file = ""; 135 offset_to_funcinfo_->insert(std::make_pair(offset, 136 current_function_info_)); 137 }; 138 // FALLTHROUGH 139 case DW_TAG_compile_unit: 140 return true; 141 default: 142 return false; 143 } 144 return false; 145 } 146 147 // Only care about the name attribute for functions 148 149 void CUFunctionInfoHandler::ProcessAttributeString(uint64 offset, 150 enum DwarfAttribute attr, 151 enum DwarfForm form, 152 const string &data) { 153 if (current_function_info_) { 154 if (attr == DW_AT_name) 155 current_function_info_->name = data; 156 else if (attr == DW_AT_MIPS_linkage_name) 157 current_function_info_->mangled_name = data; 158 } 159 } 160 161 void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset, 162 enum DwarfAttribute attr, 163 enum DwarfForm form, 164 uint64 data) { 165 if (attr == DW_AT_stmt_list) { 166 SectionMap::const_iterator iter = sections_.find("__debug_line"); 167 assert(iter != sections_.end()); 168 169 scoped_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data, 170 iter->second.second - data, 171 reader_, linehandler_)); 172 lireader->Start(); 173 } else if (current_function_info_) { 174 switch (attr) { 175 case DW_AT_low_pc: 176 current_function_info_->lowpc = data; 177 break; 178 case DW_AT_high_pc: 179 current_function_info_->highpc = data; 180 break; 181 case DW_AT_decl_line: 182 current_function_info_->line = data; 183 break; 184 case DW_AT_decl_file: 185 current_function_info_->file = files_->at(data).name; 186 break; 187 default: 188 break; 189 } 190 } 191 } 192 193 void CUFunctionInfoHandler::ProcessAttributeReference(uint64 offset, 194 enum DwarfAttribute attr, 195 enum DwarfForm form, 196 uint64 data) { 197 if (current_function_info_) { 198 switch (attr) { 199 case DW_AT_specification: { 200 // Some functions have a "specification" attribute 201 // which means they were defined elsewhere. The name 202 // attribute is not repeated, and must be taken from 203 // the specification DIE. Here we'll assume that 204 // any DIE referenced in this manner will already have 205 // been seen, but that's not really required by the spec. 206 FunctionMap::iterator iter = offset_to_funcinfo_->find(data); 207 if (iter != offset_to_funcinfo_->end()) { 208 current_function_info_->name = iter->second->name; 209 current_function_info_->mangled_name = iter->second->mangled_name; 210 } else { 211 // If you hit this, this code probably needs to be rewritten. 212 fprintf(stderr, 213 "Error: DW_AT_specification was seen before the referenced " 214 "DIE! (Looking for DIE at offset %08llx, in DIE at " 215 "offset %08llx)\n", data, offset); 216 } 217 break; 218 } 219 default: 220 break; 221 } 222 } 223 } 224 225 void CUFunctionInfoHandler::EndDIE(uint64 offset) { 226 if (current_function_info_ && current_function_info_->lowpc) 227 address_to_funcinfo_->insert(std::make_pair(current_function_info_->lowpc, 228 current_function_info_)); 229 } 230 231 } // namespace dwarf2reader 232