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