xref: /aosp_15_r20/external/google-breakpad/src/common/dwarf/functioninfo.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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