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