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