simple_symbol_supplier.cc
1 // Copyright 2006 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 // simple_symbol_supplier.cc: A simple SymbolSupplier implementation 30 // 31 // See simple_symbol_supplier.h for documentation. 32 // 33 // Author: Mark Mentovai 34 35 #ifdef HAVE_CONFIG_H 36 #include <config.h> // Must come first 37 #endif 38 39 #include "processor/simple_symbol_supplier.h" 40 41 #include <assert.h> 42 #include <string.h> 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 46 #include <algorithm> 47 #include <iostream> 48 #include <fstream> 49 50 #include "common/using_std_string.h" 51 #include "google_breakpad/processor/code_module.h" 52 #include "google_breakpad/processor/system_info.h" 53 #include "processor/logging.h" 54 #include "processor/pathname_stripper.h" 55 56 namespace google_breakpad { 57 58 static bool file_exists(const string& file_name) { 59 struct stat sb; 60 return stat(file_name.c_str(), &sb) == 0; 61 } 62 63 SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile( 64 const CodeModule* module, const SystemInfo* system_info, 65 string* symbol_file) { 66 BPLOG_IF(ERROR, !symbol_file) << "SimpleSymbolSupplier::GetSymbolFile " 67 "requires |symbol_file|"; 68 assert(symbol_file); 69 symbol_file->clear(); 70 71 for (unsigned int path_index = 0; path_index < paths_.size(); ++path_index) { 72 SymbolResult result; 73 if ((result = GetSymbolFileAtPathFromRoot(module, system_info, 74 paths_[path_index], 75 symbol_file)) != NOT_FOUND) { 76 return result; 77 } 78 } 79 return NOT_FOUND; 80 } 81 82 SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile( 83 const CodeModule* module, 84 const SystemInfo* system_info, 85 string* symbol_file, 86 string* symbol_data) { 87 assert(symbol_data); 88 symbol_data->clear(); 89 90 SymbolSupplier::SymbolResult s = GetSymbolFile(module, system_info, 91 symbol_file); 92 if (s == FOUND) { 93 std::ifstream in(symbol_file->c_str()); 94 std::getline(in, *symbol_data, string::traits_type::to_char_type( 95 string::traits_type::eof())); 96 in.close(); 97 } 98 return s; 99 } 100 101 SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetCStringSymbolData( 102 const CodeModule* module, 103 const SystemInfo* system_info, 104 string* symbol_file, 105 char** symbol_data, 106 size_t* symbol_data_size) { 107 assert(symbol_data); 108 assert(symbol_data_size); 109 110 string symbol_data_string; 111 SymbolSupplier::SymbolResult s = 112 GetSymbolFile(module, system_info, symbol_file, &symbol_data_string); 113 114 if (s == FOUND) { 115 *symbol_data_size = symbol_data_string.size() + 1; 116 *symbol_data = new char[*symbol_data_size]; 117 if (*symbol_data == NULL) { 118 BPLOG(ERROR) << "Memory allocation for size " << *symbol_data_size 119 << " failed"; 120 return INTERRUPT; 121 } 122 memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size()); 123 (*symbol_data)[symbol_data_string.size()] = '\0'; 124 memory_buffers_.insert(make_pair(module->code_file(), *symbol_data)); 125 } 126 return s; 127 } 128 129 void SimpleSymbolSupplier::FreeSymbolData(const CodeModule* module) { 130 if (!module) { 131 BPLOG(INFO) << "Cannot free symbol data buffer for NULL module"; 132 return; 133 } 134 135 map<string, char*>::iterator it = memory_buffers_.find(module->code_file()); 136 if (it == memory_buffers_.end()) { 137 BPLOG(INFO) << "Cannot find symbol data buffer for module " 138 << module->code_file(); 139 return; 140 } 141 delete [] it->second; 142 memory_buffers_.erase(it); 143 } 144 145 SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFileAtPathFromRoot( 146 const CodeModule* module, const SystemInfo* system_info, 147 const string& root_path, string* symbol_file) { 148 BPLOG_IF(ERROR, !symbol_file) << "SimpleSymbolSupplier::GetSymbolFileAtPath " 149 "requires |symbol_file|"; 150 assert(symbol_file); 151 symbol_file->clear(); 152 153 if (!module) 154 return NOT_FOUND; 155 156 // Start with the base path. 157 string path = root_path; 158 159 // Append the debug (pdb) file name as a directory name. 160 path.append("/"); 161 string debug_file_name = PathnameStripper::File(module->debug_file()); 162 if (debug_file_name.empty()) { 163 BPLOG(ERROR) << "Can't construct symbol file path without debug_file " 164 "(code_file = " << 165 PathnameStripper::File(module->code_file()) << ")"; 166 return NOT_FOUND; 167 } 168 path.append(debug_file_name); 169 170 // Append the identifier as a directory name. 171 path.append("/"); 172 string identifier = module->debug_identifier(); 173 if (identifier.empty()) { 174 BPLOG(ERROR) << "Can't construct symbol file path without debug_identifier " 175 "(code_file = " << 176 PathnameStripper::File(module->code_file()) << 177 ", debug_file = " << debug_file_name << ")"; 178 return NOT_FOUND; 179 } 180 path.append(identifier); 181 182 // Transform the debug file name into one ending in .sym. If the existing 183 // name ends in .pdb, strip the .pdb. Otherwise, add .sym to the non-.pdb 184 // name. 185 path.append("/"); 186 string debug_file_extension; 187 if (debug_file_name.size() > 4) 188 debug_file_extension = debug_file_name.substr(debug_file_name.size() - 4); 189 std::transform(debug_file_extension.begin(), debug_file_extension.end(), 190 debug_file_extension.begin(), tolower); 191 if (debug_file_extension == ".pdb") { 192 path.append(debug_file_name.substr(0, debug_file_name.size() - 4)); 193 } else { 194 path.append(debug_file_name); 195 } 196 path.append(".sym"); 197 198 if (!file_exists(path)) { 199 BPLOG(INFO) << "No symbol file at " << path; 200 return NOT_FOUND; 201 } 202 203 *symbol_file = path; 204 return FOUND; 205 } 206 207 } // namespace google_breakpad