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