xref: /aosp_15_r20/external/google-breakpad/src/processor/source_line_resolver_base.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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 ([email protected])
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 
SourceLineResolverBase(ModuleFactory * module_factory)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 
~SourceLineResolverBase()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 
ReadSymbolFile(const string & map_file,char ** symbol_data,size_t * symbol_data_size)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 
LoadModule(const CodeModule * module,const string & map_file)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 
LoadModuleUsingMapBuffer(const CodeModule * module,const string & map_buffer)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 
LoadModuleUsingMemoryBuffer(const CodeModule * module,char * memory_buffer,size_t memory_buffer_size)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 
ShouldDeleteMemoryBufferAfterLoadModule()266 bool SourceLineResolverBase::ShouldDeleteMemoryBufferAfterLoadModule() {
267   return true;
268 }
269 
UnloadModule(const CodeModule * code_module)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 
HasModule(const CodeModule * module)294 bool SourceLineResolverBase::HasModule(const CodeModule* module) {
295   if (!module)
296     return false;
297   return modules_->find(module->code_file()) != modules_->end();
298 }
299 
IsModuleCorrupt(const CodeModule * module)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 
FillSourceLineInfo(StackFrame * frame,std::deque<std::unique_ptr<StackFrame>> * inlined_frames)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 
FindWindowsFrameInfo(const StackFrame * frame)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 
FindCFIFrameInfo(const StackFrame * frame)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 
operator ()(const string & s1,const string & s2) const339 bool SourceLineResolverBase::CompareString::operator()(
340     const string& s1, const string& s2) const {
341   return strcmp(s1.c_str(), s2.c_str()) < 0;
342 }
343 
ParseCFIRuleSet(const string & rule_set,CFIFrameInfo * frame_info) const344 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
352