1*9712c20fSFrederick Mayle // Copyright 2010 Google LLC
2*9712c20fSFrederick Mayle //
3*9712c20fSFrederick Mayle // Redistribution and use in source and binary forms, with or without
4*9712c20fSFrederick Mayle // modification, are permitted provided that the following conditions are
5*9712c20fSFrederick Mayle // met:
6*9712c20fSFrederick Mayle //
7*9712c20fSFrederick Mayle // * Redistributions of source code must retain the above copyright
8*9712c20fSFrederick Mayle // notice, this list of conditions and the following disclaimer.
9*9712c20fSFrederick Mayle // * Redistributions in binary form must reproduce the above
10*9712c20fSFrederick Mayle // copyright notice, this list of conditions and the following disclaimer
11*9712c20fSFrederick Mayle // in the documentation and/or other materials provided with the
12*9712c20fSFrederick Mayle // distribution.
13*9712c20fSFrederick Mayle // * Neither the name of Google LLC nor the names of its
14*9712c20fSFrederick Mayle // contributors may be used to endorse or promote products derived from
15*9712c20fSFrederick Mayle // this software without specific prior written permission.
16*9712c20fSFrederick Mayle //
17*9712c20fSFrederick Mayle // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*9712c20fSFrederick Mayle // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*9712c20fSFrederick Mayle // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*9712c20fSFrederick Mayle // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*9712c20fSFrederick Mayle // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*9712c20fSFrederick Mayle // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*9712c20fSFrederick Mayle // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*9712c20fSFrederick Mayle // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*9712c20fSFrederick Mayle // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*9712c20fSFrederick Mayle // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*9712c20fSFrederick Mayle // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*9712c20fSFrederick Mayle
29*9712c20fSFrederick Mayle // This is a client for the dwarf2reader to extract function and line
30*9712c20fSFrederick Mayle // information from the debug info.
31*9712c20fSFrederick Mayle
32*9712c20fSFrederick Mayle #ifdef HAVE_CONFIG_H
33*9712c20fSFrederick Mayle #include <config.h> // Must come first
34*9712c20fSFrederick Mayle #endif
35*9712c20fSFrederick Mayle
36*9712c20fSFrederick Mayle #include <assert.h>
37*9712c20fSFrederick Mayle #include <limits.h>
38*9712c20fSFrederick Mayle #include <stdio.h>
39*9712c20fSFrederick Mayle
40*9712c20fSFrederick Mayle #include <map>
41*9712c20fSFrederick Mayle #include <queue>
42*9712c20fSFrederick Mayle #include <vector>
43*9712c20fSFrederick Mayle
44*9712c20fSFrederick Mayle #include "common/dwarf/functioninfo.h"
45*9712c20fSFrederick Mayle #include "common/dwarf/bytereader.h"
46*9712c20fSFrederick Mayle #include "common/scoped_ptr.h"
47*9712c20fSFrederick Mayle #include "common/using_std_string.h"
48*9712c20fSFrederick Mayle
49*9712c20fSFrederick Mayle namespace google_breakpad {
50*9712c20fSFrederick Mayle
CULineInfoHandler(std::vector<SourceFileInfo> * files,std::vector<string> * dirs,LineMap * linemap)51*9712c20fSFrederick Mayle CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files,
52*9712c20fSFrederick Mayle std::vector<string>* dirs,
53*9712c20fSFrederick Mayle LineMap* linemap):linemap_(linemap),
54*9712c20fSFrederick Mayle files_(files),
55*9712c20fSFrederick Mayle dirs_(dirs) {
56*9712c20fSFrederick Mayle // In dwarf4, the dirs and files are 1 indexed, and in dwarf5 they are zero
57*9712c20fSFrederick Mayle // indexed. This is handled in the LineInfo reader, so empty files are not
58*9712c20fSFrederick Mayle // needed here.
59*9712c20fSFrederick Mayle }
60*9712c20fSFrederick Mayle
DefineDir(const string & name,uint32_t dir_num)61*9712c20fSFrederick Mayle void CULineInfoHandler::DefineDir(const string& name, uint32_t dir_num) {
62*9712c20fSFrederick Mayle // These should never come out of order, actually
63*9712c20fSFrederick Mayle assert(dir_num == dirs_->size());
64*9712c20fSFrederick Mayle dirs_->push_back(name);
65*9712c20fSFrederick Mayle }
66*9712c20fSFrederick Mayle
DefineFile(const string & name,int32 file_num,uint32_t dir_num,uint64_t mod_time,uint64_t length)67*9712c20fSFrederick Mayle void CULineInfoHandler::DefineFile(const string& name,
68*9712c20fSFrederick Mayle int32 file_num, uint32_t dir_num,
69*9712c20fSFrederick Mayle uint64_t mod_time, uint64_t length) {
70*9712c20fSFrederick Mayle assert(dir_num >= 0);
71*9712c20fSFrederick Mayle assert(dir_num < dirs_->size());
72*9712c20fSFrederick Mayle
73*9712c20fSFrederick Mayle // These should never come out of order, actually.
74*9712c20fSFrederick Mayle if (file_num == (int32)files_->size() || file_num == -1) {
75*9712c20fSFrederick Mayle string dir = dirs_->at(dir_num);
76*9712c20fSFrederick Mayle
77*9712c20fSFrederick Mayle SourceFileInfo s;
78*9712c20fSFrederick Mayle s.lowpc = ULLONG_MAX;
79*9712c20fSFrederick Mayle
80*9712c20fSFrederick Mayle if (dir == "") {
81*9712c20fSFrederick Mayle s.name = name;
82*9712c20fSFrederick Mayle } else {
83*9712c20fSFrederick Mayle s.name = dir + "/" + name;
84*9712c20fSFrederick Mayle }
85*9712c20fSFrederick Mayle
86*9712c20fSFrederick Mayle files_->push_back(s);
87*9712c20fSFrederick Mayle } else {
88*9712c20fSFrederick Mayle fprintf(stderr, "error in DefineFile");
89*9712c20fSFrederick Mayle }
90*9712c20fSFrederick Mayle }
91*9712c20fSFrederick Mayle
AddLine(uint64_t address,uint64_t length,uint32_t file_num,uint32_t line_num,uint32_t column_num)92*9712c20fSFrederick Mayle void CULineInfoHandler::AddLine(uint64_t address, uint64_t length,
93*9712c20fSFrederick Mayle uint32_t file_num, uint32_t line_num,
94*9712c20fSFrederick Mayle uint32_t column_num) {
95*9712c20fSFrederick Mayle if (file_num < files_->size()) {
96*9712c20fSFrederick Mayle linemap_->insert(
97*9712c20fSFrederick Mayle std::make_pair(address,
98*9712c20fSFrederick Mayle std::make_pair(files_->at(file_num).name.c_str(),
99*9712c20fSFrederick Mayle line_num)));
100*9712c20fSFrederick Mayle
101*9712c20fSFrederick Mayle if (address < files_->at(file_num).lowpc) {
102*9712c20fSFrederick Mayle files_->at(file_num).lowpc = address;
103*9712c20fSFrederick Mayle }
104*9712c20fSFrederick Mayle } else {
105*9712c20fSFrederick Mayle fprintf(stderr, "error in AddLine");
106*9712c20fSFrederick Mayle }
107*9712c20fSFrederick Mayle }
108*9712c20fSFrederick Mayle
StartCompilationUnit(uint64_t offset,uint8_t address_size,uint8_t offset_size,uint64_t cu_length,uint8_t dwarf_version)109*9712c20fSFrederick Mayle bool CUFunctionInfoHandler::StartCompilationUnit(uint64_t offset,
110*9712c20fSFrederick Mayle uint8_t address_size,
111*9712c20fSFrederick Mayle uint8_t offset_size,
112*9712c20fSFrederick Mayle uint64_t cu_length,
113*9712c20fSFrederick Mayle uint8_t dwarf_version) {
114*9712c20fSFrederick Mayle current_compilation_unit_offset_ = offset;
115*9712c20fSFrederick Mayle return true;
116*9712c20fSFrederick Mayle }
117*9712c20fSFrederick Mayle
118*9712c20fSFrederick Mayle
119*9712c20fSFrederick Mayle // For function info, we only care about subprograms and inlined
120*9712c20fSFrederick Mayle // subroutines. For line info, the DW_AT_stmt_list lives in the
121*9712c20fSFrederick Mayle // compile unit tag.
122*9712c20fSFrederick Mayle
StartDIE(uint64_t offset,enum DwarfTag tag)123*9712c20fSFrederick Mayle bool CUFunctionInfoHandler::StartDIE(uint64_t offset, enum DwarfTag tag) {
124*9712c20fSFrederick Mayle switch (tag) {
125*9712c20fSFrederick Mayle case DW_TAG_subprogram:
126*9712c20fSFrederick Mayle case DW_TAG_inlined_subroutine: {
127*9712c20fSFrederick Mayle current_function_info_ = new FunctionInfo;
128*9712c20fSFrederick Mayle current_function_info_->lowpc = current_function_info_->highpc = 0;
129*9712c20fSFrederick Mayle current_function_info_->name = "";
130*9712c20fSFrederick Mayle current_function_info_->line = 0;
131*9712c20fSFrederick Mayle current_function_info_->file = "";
132*9712c20fSFrederick Mayle offset_to_funcinfo_->insert(std::make_pair(offset,
133*9712c20fSFrederick Mayle current_function_info_));
134*9712c20fSFrederick Mayle };
135*9712c20fSFrederick Mayle // FALLTHROUGH
136*9712c20fSFrederick Mayle case DW_TAG_compile_unit:
137*9712c20fSFrederick Mayle return true;
138*9712c20fSFrederick Mayle default:
139*9712c20fSFrederick Mayle return false;
140*9712c20fSFrederick Mayle }
141*9712c20fSFrederick Mayle return false;
142*9712c20fSFrederick Mayle }
143*9712c20fSFrederick Mayle
144*9712c20fSFrederick Mayle // Only care about the name attribute for functions
145*9712c20fSFrederick Mayle
ProcessAttributeString(uint64_t offset,enum DwarfAttribute attr,enum DwarfForm form,const string & data)146*9712c20fSFrederick Mayle void CUFunctionInfoHandler::ProcessAttributeString(uint64_t offset,
147*9712c20fSFrederick Mayle enum DwarfAttribute attr,
148*9712c20fSFrederick Mayle enum DwarfForm form,
149*9712c20fSFrederick Mayle const string& data) {
150*9712c20fSFrederick Mayle if (current_function_info_) {
151*9712c20fSFrederick Mayle if (attr == DW_AT_name)
152*9712c20fSFrederick Mayle current_function_info_->name = data;
153*9712c20fSFrederick Mayle else if (attr == DW_AT_MIPS_linkage_name)
154*9712c20fSFrederick Mayle current_function_info_->mangled_name = data;
155*9712c20fSFrederick Mayle }
156*9712c20fSFrederick Mayle }
157*9712c20fSFrederick Mayle
ProcessAttributeUnsigned(uint64_t offset,enum DwarfAttribute attr,enum DwarfForm form,uint64_t data)158*9712c20fSFrederick Mayle void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64_t offset,
159*9712c20fSFrederick Mayle enum DwarfAttribute attr,
160*9712c20fSFrederick Mayle enum DwarfForm form,
161*9712c20fSFrederick Mayle uint64_t data) {
162*9712c20fSFrederick Mayle if (attr == DW_AT_stmt_list) {
163*9712c20fSFrederick Mayle SectionMap::const_iterator iter =
164*9712c20fSFrederick Mayle GetSectionByName(sections_, ".debug_line");
165*9712c20fSFrederick Mayle assert(iter != sections_.end());
166*9712c20fSFrederick Mayle
167*9712c20fSFrederick Mayle scoped_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data,
168*9712c20fSFrederick Mayle iter->second.second - data,
169*9712c20fSFrederick Mayle reader_, linehandler_));
170*9712c20fSFrederick Mayle lireader->Start();
171*9712c20fSFrederick Mayle } else if (current_function_info_) {
172*9712c20fSFrederick Mayle switch (attr) {
173*9712c20fSFrederick Mayle case DW_AT_low_pc:
174*9712c20fSFrederick Mayle current_function_info_->lowpc = data;
175*9712c20fSFrederick Mayle break;
176*9712c20fSFrederick Mayle case DW_AT_high_pc:
177*9712c20fSFrederick Mayle current_function_info_->highpc = data;
178*9712c20fSFrederick Mayle break;
179*9712c20fSFrederick Mayle case DW_AT_decl_line:
180*9712c20fSFrederick Mayle current_function_info_->line = data;
181*9712c20fSFrederick Mayle break;
182*9712c20fSFrederick Mayle case DW_AT_decl_file:
183*9712c20fSFrederick Mayle current_function_info_->file = files_->at(data).name;
184*9712c20fSFrederick Mayle break;
185*9712c20fSFrederick Mayle case DW_AT_ranges:
186*9712c20fSFrederick Mayle current_function_info_->ranges = data;
187*9712c20fSFrederick Mayle break;
188*9712c20fSFrederick Mayle default:
189*9712c20fSFrederick Mayle break;
190*9712c20fSFrederick Mayle }
191*9712c20fSFrederick Mayle }
192*9712c20fSFrederick Mayle }
193*9712c20fSFrederick Mayle
ProcessAttributeReference(uint64_t offset,enum DwarfAttribute attr,enum DwarfForm form,uint64_t data)194*9712c20fSFrederick Mayle void CUFunctionInfoHandler::ProcessAttributeReference(uint64_t offset,
195*9712c20fSFrederick Mayle enum DwarfAttribute attr,
196*9712c20fSFrederick Mayle enum DwarfForm form,
197*9712c20fSFrederick Mayle uint64_t data) {
198*9712c20fSFrederick Mayle if (current_function_info_) {
199*9712c20fSFrederick Mayle switch (attr) {
200*9712c20fSFrederick Mayle case DW_AT_specification: {
201*9712c20fSFrederick Mayle // Some functions have a "specification" attribute
202*9712c20fSFrederick Mayle // which means they were defined elsewhere. The name
203*9712c20fSFrederick Mayle // attribute is not repeated, and must be taken from
204*9712c20fSFrederick Mayle // the specification DIE. Here we'll assume that
205*9712c20fSFrederick Mayle // any DIE referenced in this manner will already have
206*9712c20fSFrederick Mayle // been seen, but that's not really required by the spec.
207*9712c20fSFrederick Mayle FunctionMap::iterator iter = offset_to_funcinfo_->find(data);
208*9712c20fSFrederick Mayle if (iter != offset_to_funcinfo_->end()) {
209*9712c20fSFrederick Mayle current_function_info_->name = iter->second->name;
210*9712c20fSFrederick Mayle current_function_info_->mangled_name = iter->second->mangled_name;
211*9712c20fSFrederick Mayle } else {
212*9712c20fSFrederick Mayle // If you hit this, this code probably needs to be rewritten.
213*9712c20fSFrederick Mayle fprintf(stderr,
214*9712c20fSFrederick Mayle "Error: DW_AT_specification was seen before the referenced "
215*9712c20fSFrederick Mayle "DIE! (Looking for DIE at offset %08llx, in DIE at "
216*9712c20fSFrederick Mayle "offset %08llx)\n", data, offset);
217*9712c20fSFrederick Mayle }
218*9712c20fSFrederick Mayle break;
219*9712c20fSFrederick Mayle }
220*9712c20fSFrederick Mayle default:
221*9712c20fSFrederick Mayle break;
222*9712c20fSFrederick Mayle }
223*9712c20fSFrederick Mayle }
224*9712c20fSFrederick Mayle }
225*9712c20fSFrederick Mayle
EndDIE(uint64_t offset)226*9712c20fSFrederick Mayle void CUFunctionInfoHandler::EndDIE(uint64_t offset) {
227*9712c20fSFrederick Mayle if (current_function_info_ && current_function_info_->lowpc)
228*9712c20fSFrederick Mayle address_to_funcinfo_->insert(std::make_pair(current_function_info_->lowpc,
229*9712c20fSFrederick Mayle current_function_info_));
230*9712c20fSFrederick Mayle }
231*9712c20fSFrederick Mayle
232*9712c20fSFrederick Mayle } // namespace google_breakpad
233