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