1 | // Copyright (c) 2010 Google Inc. |
2 | // All rights reserved. |
3 | // |
4 | // Redistribution and use in source and binary forms, with or without |
5 | // modification, are permitted provided that the following conditions are |
6 | // met: |
7 | // |
8 | // * Redistributions of source code must retain the above copyright |
9 | // notice, this list of conditions and the following disclaimer. |
10 | // * Redistributions in binary form must reproduce the above |
11 | // copyright notice, this list of conditions and the following disclaimer |
12 | // in the documentation and/or other materials provided with the |
13 | // distribution. |
14 | // * Neither the name of Google Inc. nor the names of its |
15 | // contributors may be used to endorse or promote products derived from |
16 | // this software without specific prior written permission. |
17 | // |
18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | |
30 | // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> |
31 | |
32 | // dump_stabs.cc --- implement the StabsToModule class. |
33 | |
34 | #include <assert.h> |
35 | #include <cxxabi.h> |
36 | #include <stdarg.h> |
37 | #include <stdio.h> |
38 | |
39 | #include <algorithm> |
40 | |
41 | #include "common/stabs_to_module.h" |
42 | #include "common/using_std_string.h" |
43 | |
44 | namespace google_breakpad { |
45 | |
46 | // Demangle using abi call. |
47 | // Older GCC may not support it. |
48 | static string Demangle(const string& mangled) { |
49 | int status = 0; |
50 | char *demangled = abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status); |
51 | if (status == 0 && demangled != NULL) { |
52 | string str(demangled); |
53 | free(demangled); |
54 | return str; |
55 | } |
56 | return string(mangled); |
57 | } |
58 | |
59 | StabsToModule::~StabsToModule() { |
60 | // Free any functions we've accumulated but not added to the module. |
61 | for (vector<Module::Function*>::const_iterator func_it = functions_.begin(); |
62 | func_it != functions_.end(); func_it++) |
63 | delete *func_it; |
64 | // Free any function that we're currently within. |
65 | delete current_function_; |
66 | } |
67 | |
68 | bool StabsToModule::StartCompilationUnit(const char *name, uint64_t address, |
69 | const char *build_directory) { |
70 | assert(!in_compilation_unit_); |
71 | in_compilation_unit_ = true; |
72 | current_source_file_name_ = name; |
73 | current_source_file_ = module_->FindFile(name); |
74 | comp_unit_base_address_ = address; |
75 | boundaries_.push_back(static_cast<Module::Address>(address)); |
76 | return true; |
77 | } |
78 | |
79 | bool StabsToModule::EndCompilationUnit(uint64_t address) { |
80 | assert(in_compilation_unit_); |
81 | in_compilation_unit_ = false; |
82 | comp_unit_base_address_ = 0; |
83 | current_source_file_ = NULL; |
84 | current_source_file_name_ = NULL; |
85 | if (address) |
86 | boundaries_.push_back(static_cast<Module::Address>(address)); |
87 | return true; |
88 | } |
89 | |
90 | bool StabsToModule::StartFunction(const string& name, |
91 | uint64_t address) { |
92 | assert(!current_function_); |
93 | Module::Function* f = |
94 | new Module::Function(module_->AddStringToPool(Demangle(name)), address); |
95 | Module::Range r(address, 0); // We compute this in StabsToModule::Finalize(). |
96 | f->ranges.push_back(r); |
97 | f->parameter_size = 0; // We don't provide this information. |
98 | current_function_ = f; |
99 | boundaries_.push_back(static_cast<Module::Address>(address)); |
100 | return true; |
101 | } |
102 | |
103 | bool StabsToModule::EndFunction(uint64_t address) { |
104 | assert(current_function_); |
105 | // Functions in this compilation unit should have address bigger |
106 | // than the compilation unit's starting address. There may be a lot |
107 | // of duplicated entries for functions in the STABS data. We will |
108 | // count on the Module to remove the duplicates. |
109 | if (current_function_->address >= comp_unit_base_address_) |
110 | functions_.push_back(current_function_); |
111 | else |
112 | delete current_function_; |
113 | current_function_ = NULL; |
114 | if (address) |
115 | boundaries_.push_back(static_cast<Module::Address>(address)); |
116 | return true; |
117 | } |
118 | |
119 | bool StabsToModule::Line(uint64_t address, const char *name, int number) { |
120 | assert(current_function_); |
121 | assert(current_source_file_); |
122 | if (name != current_source_file_name_) { |
123 | current_source_file_ = module_->FindFile(name); |
124 | current_source_file_name_ = name; |
125 | } |
126 | Module::Line line; |
127 | line.address = address; |
128 | line.size = 0; // We compute this in StabsToModule::Finalize(). |
129 | line.file = current_source_file_; |
130 | line.number = number; |
131 | current_function_->lines.push_back(line); |
132 | return true; |
133 | } |
134 | |
135 | bool StabsToModule::Extern(const string& name, uint64_t address) { |
136 | Module::Extern *ext = new Module::Extern(address); |
137 | // Older libstdc++ demangle implementations can crash on unexpected |
138 | // input, so be careful about what gets passed in. |
139 | if (name.compare(0, 3, "__Z" ) == 0) { |
140 | ext->name = Demangle(name.substr(1)); |
141 | } else if (name[0] == '_') { |
142 | ext->name = name.substr(1); |
143 | } else { |
144 | ext->name = name; |
145 | } |
146 | module_->AddExtern(ext); |
147 | return true; |
148 | } |
149 | |
150 | void StabsToModule::Warning(const char *format, ...) { |
151 | va_list args; |
152 | va_start(args, format); |
153 | vfprintf(stderr, format, args); |
154 | va_end(args); |
155 | } |
156 | |
157 | void StabsToModule::Finalize() { |
158 | // Sort our boundary list, so we can search it quickly. |
159 | sort(boundaries_.begin(), boundaries_.end()); |
160 | // Sort all functions by address, just for neatness. |
161 | sort(functions_.begin(), functions_.end(), |
162 | Module::Function::CompareByAddress); |
163 | |
164 | for (vector<Module::Function*>::const_iterator func_it = functions_.begin(); |
165 | func_it != functions_.end(); |
166 | func_it++) { |
167 | Module::Function *f = *func_it; |
168 | // Compute the function f's size. |
169 | vector<Module::Address>::const_iterator boundary |
170 | = std::upper_bound(boundaries_.begin(), boundaries_.end(), f->address); |
171 | if (boundary != boundaries_.end()) |
172 | f->ranges[0].size = *boundary - f->address; |
173 | else |
174 | // If this is the last function in the module, and the STABS |
175 | // reader was unable to give us its ending address, then assign |
176 | // it a bogus, very large value. This will happen at most once |
177 | // per module: since we've added all functions' addresses to the |
178 | // boundary table, only one can be the last. |
179 | f->ranges[0].size = kFallbackSize; |
180 | |
181 | // Compute sizes for each of the function f's lines --- if it has any. |
182 | if (!f->lines.empty()) { |
183 | stable_sort(f->lines.begin(), f->lines.end(), |
184 | Module::Line::CompareByAddress); |
185 | vector<Module::Line>::iterator last_line = f->lines.end() - 1; |
186 | for (vector<Module::Line>::iterator line_it = f->lines.begin(); |
187 | line_it != last_line; line_it++) |
188 | line_it[0].size = line_it[1].address - line_it[0].address; |
189 | // Compute the size of the last line from f's end address. |
190 | last_line->size = |
191 | (f->ranges[0].address + f->ranges[0].size) - last_line->address; |
192 | } |
193 | } |
194 | // Now that everything has a size, add our functions to the module, and |
195 | // dispose of our private list. |
196 | for (Module::Function* func: functions_) |
197 | module_->AddFunction(func); |
198 | functions_.clear(); |
199 | } |
200 | |
201 | } // namespace google_breakpad |
202 | |