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