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 
43 #include "common/dwarf/bytereader.h"
44 
45 
46 namespace dwarf2reader {
47 
CULineInfoHandler(vector<SourceFileInfo> * files,vector<string> * dirs,LineMap * linemap)48 CULineInfoHandler::CULineInfoHandler(vector<SourceFileInfo>* files,
49                                      vector<string>* dirs,
50                                      LineMap* linemap):linemap_(linemap),
51                                                        files_(files),
52                                                        dirs_(dirs) {
53   // The dirs and files are 1 indexed, so just make sure we put
54   // nothing in the 0 vector.
55   assert(dirs->size() == 0);
56   assert(files->size() == 0);
57   dirs->push_back("");
58   SourceFileInfo s;
59   s.name = "";
60   s.lowpc = ULLONG_MAX;
61   files->push_back(s);
62 }
63 
DefineDir(const string & name,uint32 dir_num)64 void CULineInfoHandler::DefineDir(const string& name, uint32 dir_num) {
65   // These should never come out of order, actually
66   assert(dir_num == dirs_->size());
67   dirs_->push_back(name);
68 }
69 
DefineFile(const string & name,int32 file_num,uint32 dir_num,uint64 mod_time,uint64 length)70 void CULineInfoHandler::DefineFile(const string& name,
71                                    int32 file_num, uint32 dir_num,
72                                    uint64 mod_time, uint64 length) {
73   assert(dir_num >= 0);
74   assert(dir_num < dirs_->size());
75 
76   // These should never come out of order, actually.
77   if (file_num == (int32)files_->size() || file_num == -1) {
78     string dir = dirs_->at(dir_num);
79 
80     SourceFileInfo s;
81     s.lowpc = ULLONG_MAX;
82 
83     if (dir == "") {
84       s.name = name;
85     } else {
86       s.name = dir + "/" + name;
87     }
88 
89     files_->push_back(s);
90   } else {
91     fprintf(stderr, "error in DefineFile");
92   }
93 }
94 
AddLine(uint64 address,uint64 length,uint32 file_num,uint32 line_num,uint32 column_num)95 void CULineInfoHandler::AddLine(uint64 address, uint64 length, uint32 file_num,
96                                 uint32 line_num, uint32 column_num) {
97   if (file_num < files_->size()) {
98     linemap_->insert(make_pair(address, 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 offset,uint8 address_size,uint8 offset_size,uint64 cu_length,uint8 dwarf_version)109 bool CUFunctionInfoHandler::StartCompilationUnit(uint64 offset,
110                                                  uint8 address_size,
111                                                  uint8 offset_size,
112                                                  uint64 cu_length,
113                                                  uint8 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 offset,enum DwarfTag tag,const AttributeList & attrs)123 bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag,
124                                      const AttributeList& attrs) {
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(make_pair(offset, 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 offset,enum DwarfAttribute attr,enum DwarfForm form,const string & data)146 void CUFunctionInfoHandler::ProcessAttributeString(uint64 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 offset,enum DwarfAttribute attr,enum DwarfForm form,uint64 data)158 void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset,
159                                                      enum DwarfAttribute attr,
160                                                      enum DwarfForm form,
161                                                      uint64 data) {
162   if (attr == DW_AT_stmt_list) {
163     SectionMap::const_iterator iter = sections_.find("__debug_line");
164     assert(iter != sections_.end());
165 
166     // this should be a scoped_ptr but we dont' use boost :-(
167     auto_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       default:
186         break;
187     }
188   }
189 }
190 
ProcessAttributeReference(uint64 offset,enum DwarfAttribute attr,enum DwarfForm form,uint64 data)191 void CUFunctionInfoHandler::ProcessAttributeReference(uint64 offset,
192                                                       enum DwarfAttribute attr,
193                                                       enum DwarfForm form,
194                                                       uint64 data) {
195   if (current_function_info_) {
196     switch (attr) {
197       case DW_AT_specification: {
198         // Some functions have a "specification" attribute
199         // which means they were defined elsewhere. The name
200         // attribute is not repeated, and must be taken from
201         // the specification DIE. Here we'll assume that
202         // any DIE referenced in this manner will already have
203         // been seen, but that's not really required by the spec.
204         FunctionMap::iterator iter = offset_to_funcinfo_->find(data);
205         if (iter != offset_to_funcinfo_->end()) {
206           current_function_info_->name = iter->second->name;
207           current_function_info_->mangled_name = iter->second->mangled_name;
208         } else {
209           // If you hit this, this code probably needs to be rewritten.
210           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);
211         }
212         break;
213       }
214       default:
215         break;
216     }
217   }
218 }
219 
EndDIE(uint64 offset)220 void CUFunctionInfoHandler::EndDIE(uint64 offset) {
221   if (current_function_info_ && current_function_info_->lowpc)
222     address_to_funcinfo_->insert(make_pair(current_function_info_->lowpc,
223                                            current_function_info_));
224 }
225 
226 }  // namespace dwarf2reader
227