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 // source_line_resolver_base.cc: Implementation of SourceLineResolverBase.
30 //
31 // See source_line_resolver_base.h and source_line_resolver_base_types.h for
32 // more documentation.
33 //
34 // Author: Siyang Xie ([email protected])
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h> // Must come first
38 #endif
39
40 #include <stdio.h>
41 #include <string.h>
42 #include <sys/stat.h>
43
44 #include <map>
45 #include <utility>
46
47 #include "google_breakpad/processor/source_line_resolver_base.h"
48 #include "processor/logging.h"
49 #include "processor/module_factory.h"
50 #include "processor/source_line_resolver_base_types.h"
51
52 using std::make_pair;
53
54 namespace google_breakpad {
55
SourceLineResolverBase(ModuleFactory * module_factory)56 SourceLineResolverBase::SourceLineResolverBase(
57 ModuleFactory* module_factory)
58 : modules_(new ModuleMap),
59 corrupt_modules_(new ModuleSet),
60 memory_buffers_(new MemoryMap),
61 module_factory_(module_factory) {
62 }
63
~SourceLineResolverBase()64 SourceLineResolverBase::~SourceLineResolverBase() {
65 ModuleMap::iterator it;
66 // Iterate through ModuleMap and delete all loaded modules.
67 for (it = modules_->begin(); it != modules_->end(); ++it) {
68 // Delete individual module.
69 delete it->second;
70 }
71 // Delete the map of modules.
72 delete modules_;
73 modules_ = NULL;
74
75 // Delete the set of corrupt modules.
76 delete corrupt_modules_;
77 corrupt_modules_ = NULL;
78
79 MemoryMap::iterator iter = memory_buffers_->begin();
80 for (; iter != memory_buffers_->end(); ++iter) {
81 delete [] iter->second;
82 }
83 // Delete the map of memory buffers.
84 delete memory_buffers_;
85 memory_buffers_ = NULL;
86
87 delete module_factory_;
88 module_factory_ = NULL;
89 }
90
ReadSymbolFile(const string & map_file,char ** symbol_data,size_t * symbol_data_size)91 bool SourceLineResolverBase::ReadSymbolFile(const string& map_file,
92 char** symbol_data,
93 size_t* symbol_data_size) {
94 if (symbol_data == NULL || symbol_data_size == NULL) {
95 BPLOG(ERROR) << "Could not Read file into Null memory pointer";
96 return false;
97 }
98
99 struct stat buf;
100 int error_code = stat(map_file.c_str(), &buf);
101 if (error_code == -1) {
102 string error_string;
103 error_code = ErrnoString(&error_string);
104 BPLOG(ERROR) << "Could not open " << map_file <<
105 ", error " << error_code << ": " << error_string;
106 return false;
107 }
108
109 off_t file_size = buf.st_size;
110
111 // Allocate memory for file contents, plus a null terminator
112 // since we may use strtok() on the contents.
113 *symbol_data_size = file_size + 1;
114 *symbol_data = new char[file_size + 1];
115
116 if (*symbol_data == NULL) {
117 BPLOG(ERROR) << "Could not allocate memory for " << map_file;
118 return false;
119 }
120
121 BPLOG(INFO) << "Opening " << map_file;
122
123 FILE* f = fopen(map_file.c_str(), "rt");
124 if (!f) {
125 string error_string;
126 error_code = ErrnoString(&error_string);
127 BPLOG(ERROR) << "Could not open " << map_file <<
128 ", error " << error_code << ": " << error_string;
129 delete [] (*symbol_data);
130 *symbol_data = NULL;
131 return false;
132 }
133
134 AutoFileCloser closer(f);
135
136 int items_read = 0;
137
138 items_read = fread(*symbol_data, 1, file_size, f);
139
140 if (items_read != file_size) {
141 string error_string;
142 error_code = ErrnoString(&error_string);
143 BPLOG(ERROR) << "Could not slurp " << map_file <<
144 ", error " << error_code << ": " << error_string;
145 delete [] (*symbol_data);
146 *symbol_data = NULL;
147 return false;
148 }
149
150 (*symbol_data)[file_size] = '\0';
151 return true;
152 }
153
LoadModule(const CodeModule * module,const string & map_file)154 bool SourceLineResolverBase::LoadModule(const CodeModule* module,
155 const string& map_file) {
156 if (module == NULL)
157 return false;
158
159 // Make sure we don't already have a module with the given name.
160 if (modules_->find(module->code_file()) != modules_->end()) {
161 BPLOG(INFO) << "Symbols for module " << module->code_file()
162 << " already loaded";
163 return false;
164 }
165
166 BPLOG(INFO) << "Loading symbols for module " << module->code_file()
167 << " from " << map_file;
168
169 char* memory_buffer;
170 size_t memory_buffer_size;
171 if (!ReadSymbolFile(map_file, &memory_buffer, &memory_buffer_size))
172 return false;
173
174 BPLOG(INFO) << "Read symbol file " << map_file << " succeeded. "
175 << "module = " << module->code_file()
176 << ", memory_buffer_size = " << memory_buffer_size;
177
178 bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer,
179 memory_buffer_size);
180
181 if (load_result && !ShouldDeleteMemoryBufferAfterLoadModule()) {
182 // memory_buffer has to stay alive as long as the module.
183 memory_buffers_->insert(make_pair(module->code_file(), memory_buffer));
184 } else {
185 delete [] memory_buffer;
186 }
187
188 return load_result;
189 }
190
LoadModuleUsingMapBuffer(const CodeModule * module,const string & map_buffer)191 bool SourceLineResolverBase::LoadModuleUsingMapBuffer(
192 const CodeModule* module, const string& map_buffer) {
193 BPLOG(INFO) << "SourceLineResolverBase::LoadModuleUsingMapBuffer(module = "
194 << module->code_file()
195 << ", map_buffer.size() = " << map_buffer.size() << ")";
196 if (module == NULL)
197 return false;
198
199 // Make sure we don't already have a module with the given name.
200 if (modules_->find(module->code_file()) != modules_->end()) {
201 BPLOG(INFO) << "Symbols for module " << module->code_file()
202 << " already loaded";
203 return false;
204 }
205
206 size_t memory_buffer_size = map_buffer.size() + 1;
207 char* memory_buffer = new char[memory_buffer_size];
208 if (memory_buffer == NULL) {
209 BPLOG(ERROR) << "Could not allocate memory for " << module->code_file();
210 return false;
211 }
212
213 // Can't use strcpy, as the data may contain '\0's before the end.
214 memcpy(memory_buffer, map_buffer.c_str(), map_buffer.size());
215 memory_buffer[map_buffer.size()] = '\0';
216
217 bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer,
218 memory_buffer_size);
219
220 if (load_result && !ShouldDeleteMemoryBufferAfterLoadModule()) {
221 // memory_buffer has to stay alive as long as the module.
222 memory_buffers_->insert(make_pair(module->code_file(), memory_buffer));
223 } else {
224 delete [] memory_buffer;
225 }
226
227 return load_result;
228 }
229
LoadModuleUsingMemoryBuffer(const CodeModule * module,char * memory_buffer,size_t memory_buffer_size)230 bool SourceLineResolverBase::LoadModuleUsingMemoryBuffer(
231 const CodeModule* module,
232 char* memory_buffer,
233 size_t memory_buffer_size) {
234 if (!module)
235 return false;
236
237 // Make sure we don't already have a module with the given name.
238 if (modules_->find(module->code_file()) != modules_->end()) {
239 BPLOG(INFO) << "Symbols for module " << module->code_file()
240 << " already loaded";
241 return false;
242 }
243
244 BPLOG(INFO) << "Loading symbols for module " << module->code_file()
245 << " from memory buffer, size: " << memory_buffer_size;
246
247 Module* basic_module = module_factory_->CreateModule(module->code_file());
248
249 // Ownership of memory is NOT transfered to Module::LoadMapFromMemory().
250 if (!basic_module->LoadMapFromMemory(memory_buffer, memory_buffer_size)) {
251 BPLOG(ERROR) << "Too many error while parsing symbol data for module "
252 << module->code_file();
253 // Returning false from here would be an indication that the symbols for
254 // this module are missing which would be wrong. Intentionally fall through
255 // and add the module to both the modules_ and the corrupt_modules_ lists.
256 assert(basic_module->IsCorrupt());
257 }
258
259 modules_->insert(make_pair(module->code_file(), basic_module));
260 if (basic_module->IsCorrupt()) {
261 corrupt_modules_->insert(module->code_file());
262 }
263 return true;
264 }
265
ShouldDeleteMemoryBufferAfterLoadModule()266 bool SourceLineResolverBase::ShouldDeleteMemoryBufferAfterLoadModule() {
267 return true;
268 }
269
UnloadModule(const CodeModule * code_module)270 void SourceLineResolverBase::UnloadModule(const CodeModule* code_module) {
271 if (!code_module)
272 return;
273
274 ModuleMap::iterator mod_iter = modules_->find(code_module->code_file());
275 if (mod_iter != modules_->end()) {
276 Module* symbol_module = mod_iter->second;
277 delete symbol_module;
278 corrupt_modules_->erase(mod_iter->first);
279 modules_->erase(mod_iter);
280 }
281
282 if (ShouldDeleteMemoryBufferAfterLoadModule()) {
283 // No-op. Because we never store any memory buffers.
284 } else {
285 // There may be a buffer stored locally, we need to find and delete it.
286 MemoryMap::iterator iter = memory_buffers_->find(code_module->code_file());
287 if (iter != memory_buffers_->end()) {
288 delete [] iter->second;
289 memory_buffers_->erase(iter);
290 }
291 }
292 }
293
HasModule(const CodeModule * module)294 bool SourceLineResolverBase::HasModule(const CodeModule* module) {
295 if (!module)
296 return false;
297 return modules_->find(module->code_file()) != modules_->end();
298 }
299
IsModuleCorrupt(const CodeModule * module)300 bool SourceLineResolverBase::IsModuleCorrupt(const CodeModule* module) {
301 if (!module)
302 return false;
303 return corrupt_modules_->find(module->code_file()) != corrupt_modules_->end();
304 }
305
FillSourceLineInfo(StackFrame * frame,std::deque<std::unique_ptr<StackFrame>> * inlined_frames)306 void SourceLineResolverBase::FillSourceLineInfo(
307 StackFrame* frame,
308 std::deque<std::unique_ptr<StackFrame>>* inlined_frames) {
309 if (frame->module) {
310 ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
311 if (it != modules_->end()) {
312 it->second->LookupAddress(frame, inlined_frames);
313 }
314 }
315 }
316
FindWindowsFrameInfo(const StackFrame * frame)317 WindowsFrameInfo* SourceLineResolverBase::FindWindowsFrameInfo(
318 const StackFrame* frame) {
319 if (frame->module) {
320 ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
321 if (it != modules_->end()) {
322 return it->second->FindWindowsFrameInfo(frame);
323 }
324 }
325 return NULL;
326 }
327
FindCFIFrameInfo(const StackFrame * frame)328 CFIFrameInfo* SourceLineResolverBase::FindCFIFrameInfo(
329 const StackFrame* frame) {
330 if (frame->module) {
331 ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
332 if (it != modules_->end()) {
333 return it->second->FindCFIFrameInfo(frame);
334 }
335 }
336 return NULL;
337 }
338
operator ()(const string & s1,const string & s2) const339 bool SourceLineResolverBase::CompareString::operator()(
340 const string& s1, const string& s2) const {
341 return strcmp(s1.c_str(), s2.c_str()) < 0;
342 }
343
ParseCFIRuleSet(const string & rule_set,CFIFrameInfo * frame_info) const344 bool SourceLineResolverBase::Module::ParseCFIRuleSet(
345 const string& rule_set, CFIFrameInfo* frame_info) const {
346 CFIFrameInfoParseHandler handler(frame_info);
347 CFIRuleParser parser(&handler);
348 return parser.Parse(rule_set);
349 }
350
351 } // namespace google_breakpad
352