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