michael@0: // Copyright (c) 2010 Google Inc. michael@0: // All rights reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: // Original author: Jim Blandy michael@0: michael@0: // dump_stabs.cc --- implement the StabsToModule class. michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: michael@0: #include "common/stabs_to_module.h" michael@0: #include "common/using_std_string.h" michael@0: michael@0: namespace google_breakpad { michael@0: michael@0: // Demangle using abi call. michael@0: // Older GCC may not support it. michael@0: static string Demangle(const string &mangled) { michael@0: int status = 0; michael@0: char *demangled = abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status); michael@0: if (status == 0 && demangled != NULL) { michael@0: string str(demangled); michael@0: free(demangled); michael@0: return str; michael@0: } michael@0: return string(mangled); michael@0: } michael@0: michael@0: StabsToModule::~StabsToModule() { michael@0: // Free any functions we've accumulated but not added to the module. michael@0: for (vector::const_iterator func_it = functions_.begin(); michael@0: func_it != functions_.end(); func_it++) michael@0: delete *func_it; michael@0: // Free any function that we're currently within. michael@0: delete current_function_; michael@0: } michael@0: michael@0: bool StabsToModule::StartCompilationUnit(const char *name, uint64_t address, michael@0: const char *build_directory) { michael@0: assert(!in_compilation_unit_); michael@0: in_compilation_unit_ = true; michael@0: current_source_file_name_ = name; michael@0: current_source_file_ = module_->FindFile(name); michael@0: comp_unit_base_address_ = address; michael@0: boundaries_.push_back(static_cast(address)); michael@0: return true; michael@0: } michael@0: michael@0: bool StabsToModule::EndCompilationUnit(uint64_t address) { michael@0: assert(in_compilation_unit_); michael@0: in_compilation_unit_ = false; michael@0: comp_unit_base_address_ = 0; michael@0: current_source_file_ = NULL; michael@0: current_source_file_name_ = NULL; michael@0: if (address) michael@0: boundaries_.push_back(static_cast(address)); michael@0: return true; michael@0: } michael@0: michael@0: bool StabsToModule::StartFunction(const string &name, michael@0: uint64_t address) { michael@0: assert(!current_function_); michael@0: Module::Function *f = new Module::Function; michael@0: f->name = Demangle(name); michael@0: f->address = address; michael@0: f->size = 0; // We compute this in StabsToModule::Finalize(). michael@0: f->parameter_size = 0; // We don't provide this information. michael@0: current_function_ = f; michael@0: boundaries_.push_back(static_cast(address)); michael@0: return true; michael@0: } michael@0: michael@0: bool StabsToModule::EndFunction(uint64_t address) { michael@0: assert(current_function_); michael@0: // Functions in this compilation unit should have address bigger michael@0: // than the compilation unit's starting address. There may be a lot michael@0: // of duplicated entries for functions in the STABS data. We will michael@0: // count on the Module to remove the duplicates. michael@0: if (current_function_->address >= comp_unit_base_address_) michael@0: functions_.push_back(current_function_); michael@0: else michael@0: delete current_function_; michael@0: current_function_ = NULL; michael@0: if (address) michael@0: boundaries_.push_back(static_cast(address)); michael@0: return true; michael@0: } michael@0: michael@0: bool StabsToModule::Line(uint64_t address, const char *name, int number) { michael@0: assert(current_function_); michael@0: assert(current_source_file_); michael@0: if (name != current_source_file_name_) { michael@0: current_source_file_ = module_->FindFile(name); michael@0: current_source_file_name_ = name; michael@0: } michael@0: Module::Line line; michael@0: line.address = address; michael@0: line.size = 0; // We compute this in StabsToModule::Finalize(). michael@0: line.file = current_source_file_; michael@0: line.number = number; michael@0: current_function_->lines.push_back(line); michael@0: return true; michael@0: } michael@0: michael@0: bool StabsToModule::Extern(const string &name, uint64_t address) { michael@0: Module::Extern *ext = new Module::Extern; michael@0: // Older libstdc++ demangle implementations can crash on unexpected michael@0: // input, so be careful about what gets passed in. michael@0: if (name.compare(0, 3, "__Z") == 0) { michael@0: ext->name = Demangle(name.substr(1)); michael@0: } else if (name[0] == '_') { michael@0: ext->name = name.substr(1); michael@0: } else { michael@0: ext->name = name; michael@0: } michael@0: ext->address = address; michael@0: module_->AddExtern(ext); michael@0: return true; michael@0: } michael@0: michael@0: void StabsToModule::Warning(const char *format, ...) { michael@0: va_list args; michael@0: va_start(args, format); michael@0: vfprintf(stderr, format, args); michael@0: va_end(args); michael@0: } michael@0: michael@0: void StabsToModule::Finalize() { michael@0: // Sort our boundary list, so we can search it quickly. michael@0: sort(boundaries_.begin(), boundaries_.end()); michael@0: // Sort all functions by address, just for neatness. michael@0: sort(functions_.begin(), functions_.end(), michael@0: Module::Function::CompareByAddress); michael@0: michael@0: for (vector::const_iterator func_it = functions_.begin(); michael@0: func_it != functions_.end(); michael@0: func_it++) { michael@0: Module::Function *f = *func_it; michael@0: // Compute the function f's size. michael@0: vector::const_iterator boundary michael@0: = std::upper_bound(boundaries_.begin(), boundaries_.end(), f->address); michael@0: if (boundary != boundaries_.end()) michael@0: f->size = *boundary - f->address; michael@0: else michael@0: // If this is the last function in the module, and the STABS michael@0: // reader was unable to give us its ending address, then assign michael@0: // it a bogus, very large value. This will happen at most once michael@0: // per module: since we've added all functions' addresses to the michael@0: // boundary table, only one can be the last. michael@0: f->size = kFallbackSize; michael@0: michael@0: // Compute sizes for each of the function f's lines --- if it has any. michael@0: if (!f->lines.empty()) { michael@0: stable_sort(f->lines.begin(), f->lines.end(), michael@0: Module::Line::CompareByAddress); michael@0: vector::iterator last_line = f->lines.end() - 1; michael@0: for (vector::iterator line_it = f->lines.begin(); michael@0: line_it != last_line; line_it++) michael@0: line_it[0].size = line_it[1].address - line_it[0].address; michael@0: // Compute the size of the last line from f's end address. michael@0: last_line->size = (f->address + f->size) - last_line->address; michael@0: } michael@0: } michael@0: // Now that everything has a size, add our functions to the module, and michael@0: // dispose of our private list. michael@0: module_->AddFunctions(functions_.begin(), functions_.end()); michael@0: functions_.clear(); michael@0: } michael@0: michael@0: } // namespace google_breakpad