Home | History | Annotate | Download | only in processor
      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 (at) 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 
     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 
    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 
    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 
    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 
    258 bool SourceLineResolverBase::ShouldDeleteMemoryBufferAfterLoadModule() {
    259   return true;
    260 }
    261 
    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 
    286 bool SourceLineResolverBase::HasModule(const CodeModule *module) {
    287   if (!module)
    288     return false;
    289   return modules_->find(module->code_file()) != modules_->end();
    290 }
    291 
    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 
    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 
    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 
    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 
    329 bool SourceLineResolverBase::CompareString::operator()(
    330     const string &s1, const string &s2) const {
    331   return strcmp(s1.c_str(), s2.c_str()) < 0;
    332 }
    333 
    334 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