1 // Copyright 2010 Google LLC
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 LLC 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 #ifdef HAVE_CONFIG_H
33 #include <config.h> // Must come first
34 #endif
35
36 #include <assert.h>
37 #include <limits.h>
38 #include <stdio.h>
39
40 #include <map>
41 #include <queue>
42 #include <vector>
43
44 #include "common/dwarf/functioninfo.h"
45 #include "common/dwarf/bytereader.h"
46 #include "common/scoped_ptr.h"
47 #include "common/using_std_string.h"
48
49 namespace google_breakpad {
50
CULineInfoHandler(std::vector<SourceFileInfo> * files,std::vector<string> * dirs,LineMap * linemap)51 CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files,
52 std::vector<string>* dirs,
53 LineMap* linemap):linemap_(linemap),
54 files_(files),
55 dirs_(dirs) {
56 // In dwarf4, the dirs and files are 1 indexed, and in dwarf5 they are zero
57 // indexed. This is handled in the LineInfo reader, so empty files are not
58 // needed here.
59 }
60
DefineDir(const string & name,uint32_t dir_num)61 void CULineInfoHandler::DefineDir(const string& name, uint32_t dir_num) {
62 // These should never come out of order, actually
63 assert(dir_num == dirs_->size());
64 dirs_->push_back(name);
65 }
66
DefineFile(const string & name,int32 file_num,uint32_t dir_num,uint64_t mod_time,uint64_t length)67 void CULineInfoHandler::DefineFile(const string& name,
68 int32 file_num, uint32_t dir_num,
69 uint64_t mod_time, uint64_t length) {
70 assert(dir_num >= 0);
71 assert(dir_num < dirs_->size());
72
73 // These should never come out of order, actually.
74 if (file_num == (int32)files_->size() || file_num == -1) {
75 string dir = dirs_->at(dir_num);
76
77 SourceFileInfo s;
78 s.lowpc = ULLONG_MAX;
79
80 if (dir == "") {
81 s.name = name;
82 } else {
83 s.name = dir + "/" + name;
84 }
85
86 files_->push_back(s);
87 } else {
88 fprintf(stderr, "error in DefineFile");
89 }
90 }
91
AddLine(uint64_t address,uint64_t length,uint32_t file_num,uint32_t line_num,uint32_t column_num)92 void CULineInfoHandler::AddLine(uint64_t address, uint64_t length,
93 uint32_t file_num, uint32_t line_num,
94 uint32_t column_num) {
95 if (file_num < files_->size()) {
96 linemap_->insert(
97 std::make_pair(address,
98 std::make_pair(files_->at(file_num).name.c_str(),
99 line_num)));
100
101 if (address < files_->at(file_num).lowpc) {
102 files_->at(file_num).lowpc = address;
103 }
104 } else {
105 fprintf(stderr, "error in AddLine");
106 }
107 }
108
StartCompilationUnit(uint64_t offset,uint8_t address_size,uint8_t offset_size,uint64_t cu_length,uint8_t dwarf_version)109 bool CUFunctionInfoHandler::StartCompilationUnit(uint64_t offset,
110 uint8_t address_size,
111 uint8_t offset_size,
112 uint64_t cu_length,
113 uint8_t dwarf_version) {
114 current_compilation_unit_offset_ = offset;
115 return true;
116 }
117
118
119 // For function info, we only care about subprograms and inlined
120 // subroutines. For line info, the DW_AT_stmt_list lives in the
121 // compile unit tag.
122
StartDIE(uint64_t offset,enum DwarfTag tag)123 bool CUFunctionInfoHandler::StartDIE(uint64_t offset, enum DwarfTag tag) {
124 switch (tag) {
125 case DW_TAG_subprogram:
126 case DW_TAG_inlined_subroutine: {
127 current_function_info_ = new FunctionInfo;
128 current_function_info_->lowpc = current_function_info_->highpc = 0;
129 current_function_info_->name = "";
130 current_function_info_->line = 0;
131 current_function_info_->file = "";
132 offset_to_funcinfo_->insert(std::make_pair(offset,
133 current_function_info_));
134 };
135 // FALLTHROUGH
136 case DW_TAG_compile_unit:
137 return true;
138 default:
139 return false;
140 }
141 return false;
142 }
143
144 // Only care about the name attribute for functions
145
ProcessAttributeString(uint64_t offset,enum DwarfAttribute attr,enum DwarfForm form,const string & data)146 void CUFunctionInfoHandler::ProcessAttributeString(uint64_t offset,
147 enum DwarfAttribute attr,
148 enum DwarfForm form,
149 const string& data) {
150 if (current_function_info_) {
151 if (attr == DW_AT_name)
152 current_function_info_->name = data;
153 else if (attr == DW_AT_MIPS_linkage_name)
154 current_function_info_->mangled_name = data;
155 }
156 }
157
ProcessAttributeUnsigned(uint64_t offset,enum DwarfAttribute attr,enum DwarfForm form,uint64_t data)158 void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64_t offset,
159 enum DwarfAttribute attr,
160 enum DwarfForm form,
161 uint64_t data) {
162 if (attr == DW_AT_stmt_list) {
163 SectionMap::const_iterator iter =
164 GetSectionByName(sections_, ".debug_line");
165 assert(iter != sections_.end());
166
167 scoped_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data,
168 iter->second.second - data,
169 reader_, linehandler_));
170 lireader->Start();
171 } else if (current_function_info_) {
172 switch (attr) {
173 case DW_AT_low_pc:
174 current_function_info_->lowpc = data;
175 break;
176 case DW_AT_high_pc:
177 current_function_info_->highpc = data;
178 break;
179 case DW_AT_decl_line:
180 current_function_info_->line = data;
181 break;
182 case DW_AT_decl_file:
183 current_function_info_->file = files_->at(data).name;
184 break;
185 case DW_AT_ranges:
186 current_function_info_->ranges = data;
187 break;
188 default:
189 break;
190 }
191 }
192 }
193
ProcessAttributeReference(uint64_t offset,enum DwarfAttribute attr,enum DwarfForm form,uint64_t data)194 void CUFunctionInfoHandler::ProcessAttributeReference(uint64_t offset,
195 enum DwarfAttribute attr,
196 enum DwarfForm form,
197 uint64_t data) {
198 if (current_function_info_) {
199 switch (attr) {
200 case DW_AT_specification: {
201 // Some functions have a "specification" attribute
202 // which means they were defined elsewhere. The name
203 // attribute is not repeated, and must be taken from
204 // the specification DIE. Here we'll assume that
205 // any DIE referenced in this manner will already have
206 // been seen, but that's not really required by the spec.
207 FunctionMap::iterator iter = offset_to_funcinfo_->find(data);
208 if (iter != offset_to_funcinfo_->end()) {
209 current_function_info_->name = iter->second->name;
210 current_function_info_->mangled_name = iter->second->mangled_name;
211 } else {
212 // If you hit this, this code probably needs to be rewritten.
213 fprintf(stderr,
214 "Error: DW_AT_specification was seen before the referenced "
215 "DIE! (Looking for DIE at offset %08llx, in DIE at "
216 "offset %08llx)\n", data, offset);
217 }
218 break;
219 }
220 default:
221 break;
222 }
223 }
224 }
225
EndDIE(uint64_t offset)226 void CUFunctionInfoHandler::EndDIE(uint64_t offset) {
227 if (current_function_info_ && current_function_info_->lowpc)
228 address_to_funcinfo_->insert(std::make_pair(current_function_info_->lowpc,
229 current_function_info_));
230 }
231
232 } // namespace google_breakpad
233