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