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 | |