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