source_line_resolver_base.cc
1 // Copyright 2010 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 // 29 // source_line_resolver_base.cc: Implementation of SourceLineResolverBase. 30 // 31 // See source_line_resolver_base.h and source_line_resolver_base_types.h for 32 // more documentation. 33 // 34 // Author: Siyang Xie (lambxsy@google.com) 35 36 #ifdef HAVE_CONFIG_H 37 #include <config.h> // Must come first 38 #endif 39 40 #include <stdio.h> 41 #include <string.h> 42 #include <sys/stat.h> 43 44 #include <map> 45 #include <utility> 46 47 #include "google_breakpad/processor/source_line_resolver_base.h" 48 #include "processor/logging.h" 49 #include "processor/module_factory.h" 50 #include "processor/source_line_resolver_base_types.h" 51 52 using std::make_pair; 53 54 namespace google_breakpad { 55 56 SourceLineResolverBase::SourceLineResolverBase( 57 ModuleFactory* module_factory) 58 : modules_(new ModuleMap), 59 corrupt_modules_(new ModuleSet), 60 memory_buffers_(new MemoryMap), 61 module_factory_(module_factory) { 62 } 63 64 SourceLineResolverBase::~SourceLineResolverBase() { 65 ModuleMap::iterator it; 66 // Iterate through ModuleMap and delete all loaded modules. 67 for (it = modules_->begin(); it != modules_->end(); ++it) { 68 // Delete individual module. 69 delete it->second; 70 } 71 // Delete the map of modules. 72 delete modules_; 73 modules_ = NULL; 74 75 // Delete the set of corrupt modules. 76 delete corrupt_modules_; 77 corrupt_modules_ = NULL; 78 79 MemoryMap::iterator iter = memory_buffers_->begin(); 80 for (; iter != memory_buffers_->end(); ++iter) { 81 delete [] iter->second; 82 } 83 // Delete the map of memory buffers. 84 delete memory_buffers_; 85 memory_buffers_ = NULL; 86 87 delete module_factory_; 88 module_factory_ = NULL; 89 } 90 91 bool SourceLineResolverBase::ReadSymbolFile(const string& map_file, 92 char** symbol_data, 93 size_t* symbol_data_size) { 94 if (symbol_data == NULL || symbol_data_size == NULL) { 95 BPLOG(ERROR) << "Could not Read file into Null memory pointer"; 96 return false; 97 } 98 99 struct stat buf; 100 int error_code = stat(map_file.c_str(), &buf); 101 if (error_code == -1) { 102 string error_string; 103 error_code = ErrnoString(&error_string); 104 BPLOG(ERROR) << "Could not open " << map_file << 105 ", error " << error_code << ": " << error_string; 106 return false; 107 } 108 109 off_t file_size = buf.st_size; 110 111 // Allocate memory for file contents, plus a null terminator 112 // since we may use strtok() on the contents. 113 *symbol_data_size = file_size + 1; 114 *symbol_data = new char[file_size + 1]; 115 116 if (*symbol_data == NULL) { 117 BPLOG(ERROR) << "Could not allocate memory for " << map_file; 118 return false; 119 } 120 121 BPLOG(INFO) << "Opening " << map_file; 122 123 FILE* f = fopen(map_file.c_str(), "rt"); 124 if (!f) { 125 string error_string; 126 error_code = ErrnoString(&error_string); 127 BPLOG(ERROR) << "Could not open " << map_file << 128 ", error " << error_code << ": " << error_string; 129 delete [] (*symbol_data); 130 *symbol_data = NULL; 131 return false; 132 } 133 134 AutoFileCloser closer(f); 135 136 int items_read = 0; 137 138 items_read = fread(*symbol_data, 1, file_size, f); 139 140 if (items_read != file_size) { 141 string error_string; 142 error_code = ErrnoString(&error_string); 143 BPLOG(ERROR) << "Could not slurp " << map_file << 144 ", error " << error_code << ": " << error_string; 145 delete [] (*symbol_data); 146 *symbol_data = NULL; 147 return false; 148 } 149 150 (*symbol_data)[file_size] = '\0'; 151 return true; 152 } 153 154 bool SourceLineResolverBase::LoadModule(const CodeModule* module, 155 const string& map_file) { 156 if (module == NULL) 157 return false; 158 159 // Make sure we don't already have a module with the given name. 160 if (modules_->find(module->code_file()) != modules_->end()) { 161 BPLOG(INFO) << "Symbols for module " << module->code_file() 162 << " already loaded"; 163 return false; 164 } 165 166 BPLOG(INFO) << "Loading symbols for module " << module->code_file() 167 << " from " << map_file; 168 169 char* memory_buffer; 170 size_t memory_buffer_size; 171 if (!ReadSymbolFile(map_file, &memory_buffer, &memory_buffer_size)) 172 return false; 173 174 BPLOG(INFO) << "Read symbol file " << map_file << " succeeded. " 175 << "module = " << module->code_file() 176 << ", memory_buffer_size = " << memory_buffer_size; 177 178 bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer, 179 memory_buffer_size); 180 181 if (load_result && !ShouldDeleteMemoryBufferAfterLoadModule()) { 182 // memory_buffer has to stay alive as long as the module. 183 memory_buffers_->insert(make_pair(module->code_file(), memory_buffer)); 184 } else { 185 delete [] memory_buffer; 186 } 187 188 return load_result; 189 } 190 191 bool SourceLineResolverBase::LoadModuleUsingMapBuffer( 192 const CodeModule* module, const string& map_buffer) { 193 BPLOG(INFO) << "SourceLineResolverBase::LoadModuleUsingMapBuffer(module = " 194 << module->code_file() 195 << ", map_buffer.size() = " << map_buffer.size() << ")"; 196 if (module == NULL) 197 return false; 198 199 // Make sure we don't already have a module with the given name. 200 if (modules_->find(module->code_file()) != modules_->end()) { 201 BPLOG(INFO) << "Symbols for module " << module->code_file() 202 << " already loaded"; 203 return false; 204 } 205 206 size_t memory_buffer_size = map_buffer.size() + 1; 207 char* memory_buffer = new char[memory_buffer_size]; 208 if (memory_buffer == NULL) { 209 BPLOG(ERROR) << "Could not allocate memory for " << module->code_file(); 210 return false; 211 } 212 213 // Can't use strcpy, as the data may contain '\0's before the end. 214 memcpy(memory_buffer, map_buffer.c_str(), map_buffer.size()); 215 memory_buffer[map_buffer.size()] = '\0'; 216 217 bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer, 218 memory_buffer_size); 219 220 if (load_result && !ShouldDeleteMemoryBufferAfterLoadModule()) { 221 // memory_buffer has to stay alive as long as the module. 222 memory_buffers_->insert(make_pair(module->code_file(), memory_buffer)); 223 } else { 224 delete [] memory_buffer; 225 } 226 227 return load_result; 228 } 229 230 bool SourceLineResolverBase::LoadModuleUsingMemoryBuffer( 231 const CodeModule* module, 232 char* memory_buffer, 233 size_t memory_buffer_size) { 234 if (!module) 235 return false; 236 237 // Make sure we don't already have a module with the given name. 238 if (modules_->find(module->code_file()) != modules_->end()) { 239 BPLOG(INFO) << "Symbols for module " << module->code_file() 240 << " already loaded"; 241 return false; 242 } 243 244 BPLOG(INFO) << "Loading symbols for module " << module->code_file() 245 << " from memory buffer, size: " << memory_buffer_size; 246 247 Module* basic_module = module_factory_->CreateModule(module->code_file()); 248 249 // Ownership of memory is NOT transfered to Module::LoadMapFromMemory(). 250 if (!basic_module->LoadMapFromMemory(memory_buffer, memory_buffer_size)) { 251 BPLOG(ERROR) << "Too many error while parsing symbol data for module " 252 << module->code_file(); 253 // Returning false from here would be an indication that the symbols for 254 // this module are missing which would be wrong. Intentionally fall through 255 // and add the module to both the modules_ and the corrupt_modules_ lists. 256 assert(basic_module->IsCorrupt()); 257 } 258 259 modules_->insert(make_pair(module->code_file(), basic_module)); 260 if (basic_module->IsCorrupt()) { 261 corrupt_modules_->insert(module->code_file()); 262 } 263 return true; 264 } 265 266 bool SourceLineResolverBase::ShouldDeleteMemoryBufferAfterLoadModule() { 267 return true; 268 } 269 270 void SourceLineResolverBase::UnloadModule(const CodeModule* code_module) { 271 if (!code_module) 272 return; 273 274 ModuleMap::iterator mod_iter = modules_->find(code_module->code_file()); 275 if (mod_iter != modules_->end()) { 276 Module* symbol_module = mod_iter->second; 277 delete symbol_module; 278 corrupt_modules_->erase(mod_iter->first); 279 modules_->erase(mod_iter); 280 } 281 282 if (ShouldDeleteMemoryBufferAfterLoadModule()) { 283 // No-op. Because we never store any memory buffers. 284 } else { 285 // There may be a buffer stored locally, we need to find and delete it. 286 MemoryMap::iterator iter = memory_buffers_->find(code_module->code_file()); 287 if (iter != memory_buffers_->end()) { 288 delete [] iter->second; 289 memory_buffers_->erase(iter); 290 } 291 } 292 } 293 294 bool SourceLineResolverBase::HasModule(const CodeModule* module) { 295 if (!module) 296 return false; 297 return modules_->find(module->code_file()) != modules_->end(); 298 } 299 300 bool SourceLineResolverBase::IsModuleCorrupt(const CodeModule* module) { 301 if (!module) 302 return false; 303 return corrupt_modules_->find(module->code_file()) != corrupt_modules_->end(); 304 } 305 306 void SourceLineResolverBase::FillSourceLineInfo( 307 StackFrame* frame, 308 std::deque<std::unique_ptr<StackFrame>>* inlined_frames) { 309 if (frame->module) { 310 ModuleMap::const_iterator it = modules_->find(frame->module->code_file()); 311 if (it != modules_->end()) { 312 it->second->LookupAddress(frame, inlined_frames); 313 } 314 } 315 } 316 317 WindowsFrameInfo* SourceLineResolverBase::FindWindowsFrameInfo( 318 const StackFrame* frame) { 319 if (frame->module) { 320 ModuleMap::const_iterator it = modules_->find(frame->module->code_file()); 321 if (it != modules_->end()) { 322 return it->second->FindWindowsFrameInfo(frame); 323 } 324 } 325 return NULL; 326 } 327 328 CFIFrameInfo* SourceLineResolverBase::FindCFIFrameInfo( 329 const StackFrame* frame) { 330 if (frame->module) { 331 ModuleMap::const_iterator it = modules_->find(frame->module->code_file()); 332 if (it != modules_->end()) { 333 return it->second->FindCFIFrameInfo(frame); 334 } 335 } 336 return NULL; 337 } 338 339 bool SourceLineResolverBase::CompareString::operator()( 340 const string& s1, const string& s2) const { 341 return strcmp(s1.c_str(), s2.c_str()) < 0; 342 } 343 344 bool SourceLineResolverBase::Module::ParseCFIRuleSet( 345 const string& rule_set, CFIFrameInfo* frame_info) const { 346 CFIFrameInfoParseHandler handler(frame_info); 347 CFIRuleParser parser(&handler); 348 return parser.Parse(rule_set); 349 } 350 351 } // namespace google_breakpad