• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/source_line_resolver_base_types.h"
46 #include "processor/module_factory.h"
47 
48 using std::map;
49 using std::make_pair;
50 
51 namespace google_breakpad {
52 
SourceLineResolverBase(ModuleFactory * module_factory)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 
~SourceLineResolverBase()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 
ReadSymbolFile(const string & map_file,char ** symbol_data,size_t * symbol_data_size)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 
LoadModule(const CodeModule * module,const string & map_file)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 
173   bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer,
174                                                  memory_buffer_size);
175 
176   if (load_result && !ShouldDeleteMemoryBufferAfterLoadModule()) {
177     // memory_buffer has to stay alive as long as the module.
178     memory_buffers_->insert(make_pair(module->code_file(), memory_buffer));
179   } else {
180     delete [] memory_buffer;
181   }
182 
183   return load_result;
184 }
185 
LoadModuleUsingMapBuffer(const CodeModule * module,const string & map_buffer)186 bool SourceLineResolverBase::LoadModuleUsingMapBuffer(
187     const CodeModule *module, const string &map_buffer) {
188   if (module == NULL)
189     return false;
190 
191   // Make sure we don't already have a module with the given name.
192   if (modules_->find(module->code_file()) != modules_->end()) {
193     BPLOG(INFO) << "Symbols for module " << module->code_file()
194                 << " already loaded";
195     return false;
196   }
197 
198   size_t memory_buffer_size = map_buffer.size() + 1;
199   char *memory_buffer = new char[memory_buffer_size];
200   if (memory_buffer == NULL) {
201     BPLOG(ERROR) << "Could not allocate memory for " << module->code_file();
202     return false;
203   }
204 
205   // Can't use strcpy, as the data may contain '\0's before the end.
206   memcpy(memory_buffer, map_buffer.c_str(), map_buffer.size());
207   memory_buffer[map_buffer.size()] = '\0';
208 
209   bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer,
210                                                  memory_buffer_size);
211 
212   if (load_result && !ShouldDeleteMemoryBufferAfterLoadModule()) {
213     // memory_buffer has to stay alive as long as the module.
214     memory_buffers_->insert(make_pair(module->code_file(), memory_buffer));
215   } else {
216     delete [] memory_buffer;
217   }
218 
219   return load_result;
220 }
221 
LoadModuleUsingMemoryBuffer(const CodeModule * module,char * memory_buffer,size_t memory_buffer_size)222 bool SourceLineResolverBase::LoadModuleUsingMemoryBuffer(
223     const CodeModule *module,
224     char *memory_buffer,
225     size_t memory_buffer_size) {
226   if (!module)
227     return false;
228 
229   // Make sure we don't already have a module with the given name.
230   if (modules_->find(module->code_file()) != modules_->end()) {
231     BPLOG(INFO) << "Symbols for module " << module->code_file()
232                 << " already loaded";
233     return false;
234   }
235 
236   BPLOG(INFO) << "Loading symbols for module " << module->code_file()
237              << " from memory buffer";
238 
239   Module *basic_module = module_factory_->CreateModule(module->code_file());
240 
241   // Ownership of memory is NOT transfered to Module::LoadMapFromMemory().
242   if (!basic_module->LoadMapFromMemory(memory_buffer, memory_buffer_size)) {
243     BPLOG(ERROR) << "Too many error while parsing symbol data for module "
244                  << module->code_file();
245     // Returning false from here would be an indication that the symbols for
246     // this module are missing which would be wrong.  Intentionally fall through
247     // and add the module to both the modules_ and the corrupt_modules_ lists.
248     assert(basic_module->IsCorrupt());
249   }
250 
251   modules_->insert(make_pair(module->code_file(), basic_module));
252   if (basic_module->IsCorrupt()) {
253     corrupt_modules_->insert(module->code_file());
254   }
255   return true;
256 }
257 
ShouldDeleteMemoryBufferAfterLoadModule()258 bool SourceLineResolverBase::ShouldDeleteMemoryBufferAfterLoadModule() {
259   return true;
260 }
261 
UnloadModule(const CodeModule * code_module)262 void SourceLineResolverBase::UnloadModule(const CodeModule *code_module) {
263   if (!code_module)
264     return;
265 
266   ModuleMap::iterator mod_iter = modules_->find(code_module->code_file());
267   if (mod_iter != modules_->end()) {
268     Module *symbol_module = mod_iter->second;
269     delete symbol_module;
270     corrupt_modules_->erase(mod_iter->first);
271     modules_->erase(mod_iter);
272   }
273 
274   if (ShouldDeleteMemoryBufferAfterLoadModule()) {
275     // No-op.  Because we never store any memory buffers.
276   } else {
277     // There may be a buffer stored locally, we need to find and delete it.
278     MemoryMap::iterator iter = memory_buffers_->find(code_module->code_file());
279     if (iter != memory_buffers_->end()) {
280       delete [] iter->second;
281       memory_buffers_->erase(iter);
282     }
283   }
284 }
285 
HasModule(const CodeModule * module)286 bool SourceLineResolverBase::HasModule(const CodeModule *module) {
287   if (!module)
288     return false;
289   return modules_->find(module->code_file()) != modules_->end();
290 }
291 
IsModuleCorrupt(const CodeModule * module)292 bool SourceLineResolverBase::IsModuleCorrupt(const CodeModule *module) {
293   if (!module)
294     return false;
295   return corrupt_modules_->find(module->code_file()) != corrupt_modules_->end();
296 }
297 
FillSourceLineInfo(StackFrame * frame)298 void SourceLineResolverBase::FillSourceLineInfo(StackFrame *frame) {
299   if (frame->module) {
300     ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
301     if (it != modules_->end()) {
302       it->second->LookupAddress(frame);
303     }
304   }
305 }
306 
FindWindowsFrameInfo(const StackFrame * frame)307 WindowsFrameInfo *SourceLineResolverBase::FindWindowsFrameInfo(
308     const StackFrame *frame) {
309   if (frame->module) {
310     ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
311     if (it != modules_->end()) {
312       return it->second->FindWindowsFrameInfo(frame);
313     }
314   }
315   return NULL;
316 }
317 
FindCFIFrameInfo(const StackFrame * frame)318 CFIFrameInfo *SourceLineResolverBase::FindCFIFrameInfo(
319     const StackFrame *frame) {
320   if (frame->module) {
321     ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
322     if (it != modules_->end()) {
323       return it->second->FindCFIFrameInfo(frame);
324     }
325   }
326   return NULL;
327 }
328 
operator ()(const string & s1,const string & s2) const329 bool SourceLineResolverBase::CompareString::operator()(
330     const string &s1, const string &s2) const {
331   return strcmp(s1.c_str(), s2.c_str()) < 0;
332 }
333 
ParseCFIRuleSet(const string & rule_set,CFIFrameInfo * frame_info) const334 bool SourceLineResolverBase::Module::ParseCFIRuleSet(
335     const string &rule_set, CFIFrameInfo *frame_info) const {
336   CFIFrameInfoParseHandler handler(frame_info);
337   CFIRuleParser parser(&handler);
338   return parser.Parse(rule_set);
339 }
340 
341 }  // namespace google_breakpad
342