PageRenderTime 60ms CodeModel.GetById 32ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 1ms

/thirdparty/breakpad/processor/source_line_resolver_base.cc

http://github.com/tomahawk-player/tomahawk
C++ | 311 lines | 208 code | 53 blank | 50 comment | 52 complexity | 95968702c56e949bbf4e053615ba0896 MD5 | raw file
  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
 48using std::map;
 49using std::make_pair;
 50
 51namespace google_breakpad {
 52
 53SourceLineResolverBase::SourceLineResolverBase(
 54    ModuleFactory *module_factory)
 55  : modules_(new ModuleMap),
 56    memory_buffers_(new MemoryMap),
 57    module_factory_(module_factory) {
 58}
 59
 60SourceLineResolverBase::~SourceLineResolverBase() {
 61  ModuleMap::iterator it;
 62  // Iterate through ModuleMap and delete all loaded modules.
 63  for (it = modules_->begin(); it != modules_->end(); ++it) {
 64    // Delete individual module.
 65    delete it->second;
 66  }
 67  // Delete the map of modules.
 68  delete modules_;
 69
 70  MemoryMap::iterator iter = memory_buffers_->begin();
 71  for (; iter != memory_buffers_->end(); ++iter) {
 72    delete [] iter->second;
 73  }
 74  // Delete the map of memory buffers.
 75  delete memory_buffers_;
 76
 77  delete module_factory_;
 78}
 79
 80bool SourceLineResolverBase::ReadSymbolFile(char **symbol_data,
 81                                            const string &map_file) {
 82  if (symbol_data == NULL) {
 83    BPLOG(ERROR) << "Could not Read file into Null memory pointer";
 84    return false;
 85  }
 86
 87  struct stat buf;
 88  int error_code = stat(map_file.c_str(), &buf);
 89  if (error_code == -1) {
 90    string error_string;
 91    error_code = ErrnoString(&error_string);
 92    BPLOG(ERROR) << "Could not open " << map_file <<
 93        ", error " << error_code << ": " << error_string;
 94    return false;
 95  }
 96
 97  off_t file_size = buf.st_size;
 98
 99  // Allocate memory for file contents, plus a null terminator
100  // since we may use strtok() on the contents.
101  *symbol_data = new char[file_size + 1];
102
103  if (*symbol_data == NULL) {
104    BPLOG(ERROR) << "Could not allocate memory for " << map_file;
105    return false;
106  }
107
108  BPLOG(INFO) << "Opening " << map_file;
109
110  FILE *f = fopen(map_file.c_str(), "rt");
111  if (!f) {
112    string error_string;
113    error_code = ErrnoString(&error_string);
114    BPLOG(ERROR) << "Could not open " << map_file <<
115        ", error " << error_code << ": " << error_string;
116    delete [] (*symbol_data);
117    *symbol_data = NULL;
118    return false;
119  }
120
121  AutoFileCloser closer(f);
122
123  int items_read = 0;
124
125  items_read = fread(*symbol_data, 1, file_size, f);
126
127  if (items_read != file_size) {
128    string error_string;
129    error_code = ErrnoString(&error_string);
130    BPLOG(ERROR) << "Could not slurp " << map_file <<
131        ", error " << error_code << ": " << error_string;
132    delete [] (*symbol_data);
133    *symbol_data = NULL;
134    return false;
135  }
136
137  (*symbol_data)[file_size] = '\0';
138  return true;
139}
140
141bool SourceLineResolverBase::LoadModule(const CodeModule *module,
142                                        const string &map_file) {
143  if (module == NULL)
144    return false;
145
146  // Make sure we don't already have a module with the given name.
147  if (modules_->find(module->code_file()) != modules_->end()) {
148    BPLOG(INFO) << "Symbols for module " << module->code_file()
149                << " already loaded";
150    return false;
151  }
152
153  BPLOG(INFO) << "Loading symbols for module " << module->code_file()
154              << " from " << map_file;
155
156  char *memory_buffer;
157  if (!ReadSymbolFile(&memory_buffer, map_file))
158    return false;
159
160  BPLOG(INFO) << "Read symbol file " << map_file << " succeeded";
161
162  bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer);
163
164  if (load_result && !ShouldDeleteMemoryBufferAfterLoadModule()) {
165    // memory_buffer has to stay alive as long as the module.
166    memory_buffers_->insert(make_pair(module->code_file(), memory_buffer));
167  } else {
168    delete [] memory_buffer;
169  }
170
171  return load_result;
172}
173
174bool SourceLineResolverBase::LoadModuleUsingMapBuffer(
175    const CodeModule *module, const string &map_buffer) {
176  if (module == NULL)
177    return false;
178
179  // Make sure we don't already have a module with the given name.
180  if (modules_->find(module->code_file()) != modules_->end()) {
181    BPLOG(INFO) << "Symbols for module " << module->code_file()
182                << " already loaded";
183    return false;
184  }
185
186  char *memory_buffer = new char[map_buffer.size() + 1];
187  if (memory_buffer == NULL) {
188    BPLOG(ERROR) << "Could not allocate memory for " << module->code_file();
189    return false;
190  }
191
192  // Can't use strcpy, as the data may contain '\0's before the end.
193  memcpy(memory_buffer, map_buffer.c_str(), map_buffer.size());
194  memory_buffer[map_buffer.size()] = '\0';
195
196  bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer);
197
198  if (load_result && !ShouldDeleteMemoryBufferAfterLoadModule()) {
199    // memory_buffer has to stay alive as long as the module.
200    memory_buffers_->insert(make_pair(module->code_file(), memory_buffer));
201  } else {
202    delete [] memory_buffer;
203  }
204
205  return load_result;
206}
207
208bool SourceLineResolverBase::LoadModuleUsingMemoryBuffer(
209    const CodeModule *module, char *memory_buffer) {
210  if (!module)
211    return false;
212
213  // Make sure we don't already have a module with the given name.
214  if (modules_->find(module->code_file()) != modules_->end()) {
215    BPLOG(INFO) << "Symbols for module " << module->code_file()
216                << " already loaded";
217    return false;
218  }
219
220  BPLOG(INFO) << "Loading symbols for module " << module->code_file()
221             << " from memory buffer";
222
223  Module *basic_module = module_factory_->CreateModule(module->code_file());
224
225  // Ownership of memory is NOT transfered to Module::LoadMapFromMemory().
226  if (!basic_module->LoadMapFromMemory(memory_buffer)) {
227    delete basic_module;
228    return false;
229  }
230
231  modules_->insert(make_pair(module->code_file(), basic_module));
232  return true;
233}
234
235bool SourceLineResolverBase::ShouldDeleteMemoryBufferAfterLoadModule() {
236  return true;
237}
238
239void SourceLineResolverBase::UnloadModule(const CodeModule *code_module) {
240  if (!code_module)
241    return;
242
243  ModuleMap::iterator mod_iter = modules_->find(code_module->code_file());
244  if (mod_iter != modules_->end()) {
245    Module *symbol_module = mod_iter->second;
246    delete symbol_module;
247    modules_->erase(mod_iter);
248  }
249
250  if (ShouldDeleteMemoryBufferAfterLoadModule()) {
251    // No-op.  Because we never store any memory buffers.
252  } else {
253    // There may be a buffer stored locally, we need to find and delete it.
254    MemoryMap::iterator iter = memory_buffers_->find(code_module->code_file());
255    if (iter != memory_buffers_->end()) {
256      delete [] iter->second;
257      memory_buffers_->erase(iter);
258    }
259  }
260}
261
262bool SourceLineResolverBase::HasModule(const CodeModule *module) {
263  if (!module)
264    return false;
265  return modules_->find(module->code_file()) != modules_->end();
266}
267
268void SourceLineResolverBase::FillSourceLineInfo(StackFrame *frame) {
269  if (frame->module) {
270    ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
271    if (it != modules_->end()) {
272      it->second->LookupAddress(frame);
273    }
274  }
275}
276
277WindowsFrameInfo *SourceLineResolverBase::FindWindowsFrameInfo(
278    const StackFrame *frame) {
279  if (frame->module) {
280    ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
281    if (it != modules_->end()) {
282      return it->second->FindWindowsFrameInfo(frame);
283    }
284  }
285  return NULL;
286}
287
288CFIFrameInfo *SourceLineResolverBase::FindCFIFrameInfo(
289    const StackFrame *frame) {
290  if (frame->module) {
291    ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
292    if (it != modules_->end()) {
293      return it->second->FindCFIFrameInfo(frame);
294    }
295  }
296  return NULL;
297}
298
299bool SourceLineResolverBase::CompareString::operator()(
300    const string &s1, const string &s2) const {
301  return strcmp(s1.c_str(), s2.c_str()) < 0;
302}
303
304bool SourceLineResolverBase::Module::ParseCFIRuleSet(
305    const string &rule_set, CFIFrameInfo *frame_info) const {
306  CFIFrameInfoParseHandler handler(frame_info);
307  CFIRuleParser parser(&handler);
308  return parser.Parse(rule_set);
309}
310
311}  // namespace google_breakpad