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@mozilla.com> <jimb@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 44namespace google_breakpad { 45 46// Demangle using abi call. 47// Older GCC may not support it. 48static 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 59StabsToModule::~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 68bool 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 79bool 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 90bool 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 101bool 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 117bool 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 133bool 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 148void 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 155void 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