stabs_to_module.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 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> 30 31 // dump_stabs.cc --- implement the StabsToModule class. 32 33 #ifdef HAVE_CONFIG_H 34 #include <config.h> // Must come first 35 #endif 36 37 #include <assert.h> 38 #include <cxxabi.h> 39 #include <stdarg.h> 40 #include <stdio.h> 41 42 #include <algorithm> 43 #include <memory> 44 #include <utility> 45 46 #include "common/stabs_to_module.h" 47 #include "common/using_std_string.h" 48 49 namespace google_breakpad { 50 51 // Demangle using abi call. 52 // Older GCC may not support it. 53 static string Demangle(const string& mangled) { 54 int status = 0; 55 char *demangled = abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status); 56 if (status == 0 && demangled != NULL) { 57 string str(demangled); 58 free(demangled); 59 return str; 60 } 61 return string(mangled); 62 } 63 64 StabsToModule::~StabsToModule() { 65 // Free any functions we've accumulated but not added to the module. 66 for (vector<Module::Function*>::const_iterator func_it = functions_.begin(); 67 func_it != functions_.end(); func_it++) 68 delete *func_it; 69 // Free any function that we're currently within. 70 delete current_function_; 71 } 72 73 bool StabsToModule::StartCompilationUnit(const char *name, uint64_t address, 74 const char *build_directory) { 75 assert(!in_compilation_unit_); 76 in_compilation_unit_ = true; 77 current_source_file_name_ = name; 78 current_source_file_ = module_->FindFile(name); 79 comp_unit_base_address_ = address; 80 boundaries_.push_back(static_cast<Module::Address>(address)); 81 return true; 82 } 83 84 bool StabsToModule::EndCompilationUnit(uint64_t address) { 85 assert(in_compilation_unit_); 86 in_compilation_unit_ = false; 87 comp_unit_base_address_ = 0; 88 current_source_file_ = NULL; 89 current_source_file_name_ = NULL; 90 if (address) 91 boundaries_.push_back(static_cast<Module::Address>(address)); 92 return true; 93 } 94 95 bool StabsToModule::StartFunction(const string& name, 96 uint64_t address) { 97 assert(!current_function_); 98 Module::Function* f = 99 new Module::Function(module_->AddStringToPool(Demangle(name)), address); 100 Module::Range r(address, 0); // We compute this in StabsToModule::Finalize(). 101 f->ranges.push_back(r); 102 f->parameter_size = 0; // We don't provide this information. 103 current_function_ = f; 104 boundaries_.push_back(static_cast<Module::Address>(address)); 105 return true; 106 } 107 108 bool StabsToModule::EndFunction(uint64_t address) { 109 assert(current_function_); 110 // Functions in this compilation unit should have address bigger 111 // than the compilation unit's starting address. There may be a lot 112 // of duplicated entries for functions in the STABS data. We will 113 // count on the Module to remove the duplicates. 114 if (current_function_->address >= comp_unit_base_address_) 115 functions_.push_back(current_function_); 116 else 117 delete current_function_; 118 current_function_ = NULL; 119 if (address) 120 boundaries_.push_back(static_cast<Module::Address>(address)); 121 return true; 122 } 123 124 bool StabsToModule::Line(uint64_t address, const char *name, int number) { 125 assert(current_function_); 126 assert(current_source_file_); 127 if (name != current_source_file_name_) { 128 current_source_file_ = module_->FindFile(name); 129 current_source_file_name_ = name; 130 } 131 Module::Line line; 132 line.address = address; 133 line.size = 0; // We compute this in StabsToModule::Finalize(). 134 line.file = current_source_file_; 135 line.number = number; 136 current_function_->lines.push_back(line); 137 return true; 138 } 139 140 bool StabsToModule::Extern(const string& name, uint64_t address) { 141 auto ext = std::make_unique<Module::Extern>(address); 142 // Older libstdc++ demangle implementations can crash on unexpected 143 // input, so be careful about what gets passed in. 144 if (name.compare(0, 3, "__Z") == 0) { 145 ext->name = Demangle(name.substr(1)); 146 } else if (name[0] == '_') { 147 ext->name = name.substr(1); 148 } else { 149 ext->name = name; 150 } 151 module_->AddExtern(std::move(ext)); 152 return true; 153 } 154 155 void StabsToModule::Warning(const char *format, ...) { 156 va_list args; 157 va_start(args, format); 158 vfprintf(stderr, format, args); 159 va_end(args); 160 } 161 162 void StabsToModule::Finalize() { 163 // Sort our boundary list, so we can search it quickly. 164 sort(boundaries_.begin(), boundaries_.end()); 165 // Sort all functions by address, just for neatness. 166 sort(functions_.begin(), functions_.end(), 167 Module::Function::CompareByAddress); 168 169 for (vector<Module::Function*>::const_iterator func_it = functions_.begin(); 170 func_it != functions_.end(); 171 func_it++) { 172 Module::Function *f = *func_it; 173 // Compute the function f's size. 174 vector<Module::Address>::const_iterator boundary 175 = std::upper_bound(boundaries_.begin(), boundaries_.end(), f->address); 176 if (boundary != boundaries_.end()) 177 f->ranges[0].size = *boundary - f->address; 178 else 179 // If this is the last function in the module, and the STABS 180 // reader was unable to give us its ending address, then assign 181 // it a bogus, very large value. This will happen at most once 182 // per module: since we've added all functions' addresses to the 183 // boundary table, only one can be the last. 184 f->ranges[0].size = kFallbackSize; 185 186 // Compute sizes for each of the function f's lines --- if it has any. 187 if (!f->lines.empty()) { 188 stable_sort(f->lines.begin(), f->lines.end(), 189 Module::Line::CompareByAddress); 190 vector<Module::Line>::iterator last_line = f->lines.end() - 1; 191 for (vector<Module::Line>::iterator line_it = f->lines.begin(); 192 line_it != last_line; line_it++) 193 line_it[0].size = line_it[1].address - line_it[0].address; 194 // Compute the size of the last line from f's end address. 195 last_line->size = 196 (f->ranges[0].address + f->ranges[0].size) - last_line->address; 197 } 198 } 199 // Now that everything has a size, add our functions to the module, and 200 // dispose of our private list. Delete the functions that we fail to add, so 201 // they aren't leaked. 202 for (Module::Function* func: functions_) 203 if (!module_->AddFunction(func)) 204 delete func; 205 functions_.clear(); 206 } 207 208 } // namespace google_breakpad