/ src / common / stabs_to_module.cc
stabs_to_module.cc
  1  // Copyright 2010 Google LLC
  2  //
  3  // Redistribution and use in source and binary forms, with or without
  4  // modification, are permitted provided that the following conditions are
  5  // met:
  6  //
  7  //     * Redistributions of source code must retain the above copyright
  8  // notice, this list of conditions and the following disclaimer.
  9  //     * Redistributions in binary form must reproduce the above
 10  // copyright notice, this list of conditions and the following disclaimer
 11  // in the documentation and/or other materials provided with the
 12  // distribution.
 13  //     * Neither the name of Google LLC nor the names of its
 14  // contributors may be used to endorse or promote products derived from
 15  // this software without specific prior written permission.
 16  //
 17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 21  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 22  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 23  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 24  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 25  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 26  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 27  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28  
 29  // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
 30  
 31  // dump_stabs.cc --- implement the StabsToModule class.
 32  
 33  #ifdef HAVE_CONFIG_H
 34  #include <config.h>  // Must come first
 35  #endif
 36  
 37  #include <assert.h>
 38  #include <cxxabi.h>
 39  #include <stdarg.h>
 40  #include <stdio.h>
 41  
 42  #include <algorithm>
 43  #include <memory>
 44  #include <utility>
 45  
 46  #include "common/stabs_to_module.h"
 47  #include "common/using_std_string.h"
 48  
 49  namespace google_breakpad {
 50  
 51  // Demangle using abi call.
 52  // Older GCC may not support it.
 53  static string Demangle(const string& mangled) {
 54    int status = 0;
 55    char *demangled = abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status);
 56    if (status == 0 && demangled != NULL) {
 57      string str(demangled);
 58      free(demangled);
 59      return str;
 60    }
 61    return string(mangled);
 62  }
 63  
 64  StabsToModule::~StabsToModule() {
 65    // Free any functions we've accumulated but not added to the module.
 66    for (vector<Module::Function*>::const_iterator func_it = functions_.begin();
 67         func_it != functions_.end(); func_it++)
 68      delete *func_it;
 69    // Free any function that we're currently within.
 70    delete current_function_;
 71  }
 72  
 73  bool StabsToModule::StartCompilationUnit(const char *name, uint64_t address,
 74                                           const char *build_directory) {
 75    assert(!in_compilation_unit_);
 76    in_compilation_unit_ = true;
 77    current_source_file_name_ = name;
 78    current_source_file_ = module_->FindFile(name);
 79    comp_unit_base_address_ = address;
 80    boundaries_.push_back(static_cast<Module::Address>(address));
 81    return true;
 82  }
 83  
 84  bool StabsToModule::EndCompilationUnit(uint64_t address) {
 85    assert(in_compilation_unit_);
 86    in_compilation_unit_ = false;
 87    comp_unit_base_address_ = 0;
 88    current_source_file_ = NULL;
 89    current_source_file_name_ = NULL;
 90    if (address)
 91      boundaries_.push_back(static_cast<Module::Address>(address));
 92    return true;
 93  }
 94  
 95  bool StabsToModule::StartFunction(const string& name,
 96                                    uint64_t address) {
 97    assert(!current_function_);
 98    Module::Function* f =
 99        new Module::Function(module_->AddStringToPool(Demangle(name)), address);
100    Module::Range r(address, 0); // We compute this in StabsToModule::Finalize().
101    f->ranges.push_back(r);
102    f->parameter_size = 0; // We don't provide this information.
103    current_function_ = f;
104    boundaries_.push_back(static_cast<Module::Address>(address));
105    return true;
106  }
107  
108  bool StabsToModule::EndFunction(uint64_t address) {
109    assert(current_function_);
110    // Functions in this compilation unit should have address bigger
111    // than the compilation unit's starting address.  There may be a lot
112    // of duplicated entries for functions in the STABS data. We will
113    // count on the Module to remove the duplicates.
114    if (current_function_->address >= comp_unit_base_address_)
115      functions_.push_back(current_function_);
116    else
117      delete current_function_;
118    current_function_ = NULL;
119    if (address)
120      boundaries_.push_back(static_cast<Module::Address>(address));
121    return true;
122  }
123  
124  bool StabsToModule::Line(uint64_t address, const char *name, int number) {
125    assert(current_function_);
126    assert(current_source_file_);
127    if (name != current_source_file_name_) {
128      current_source_file_ = module_->FindFile(name);
129      current_source_file_name_ = name;
130    }
131    Module::Line line;
132    line.address = address;
133    line.size = 0;  // We compute this in StabsToModule::Finalize().
134    line.file = current_source_file_;
135    line.number = number;
136    current_function_->lines.push_back(line);
137    return true;
138  }
139  
140  bool StabsToModule::Extern(const string& name, uint64_t address) {
141    auto ext = std::make_unique<Module::Extern>(address);
142    // Older libstdc++ demangle implementations can crash on unexpected
143    // input, so be careful about what gets passed in.
144    if (name.compare(0, 3, "__Z") == 0) {
145      ext->name = Demangle(name.substr(1));
146    } else if (name[0] == '_') {
147      ext->name = name.substr(1);
148    } else {
149      ext->name = name;
150    }
151    module_->AddExtern(std::move(ext));
152    return true;
153  }
154  
155  void StabsToModule::Warning(const char *format, ...) {
156    va_list args;
157    va_start(args, format);
158    vfprintf(stderr, format, args);
159    va_end(args);
160  }
161  
162  void StabsToModule::Finalize() {
163    // Sort our boundary list, so we can search it quickly.
164    sort(boundaries_.begin(), boundaries_.end());
165    // Sort all functions by address, just for neatness.
166    sort(functions_.begin(), functions_.end(),
167         Module::Function::CompareByAddress);
168  
169    for (vector<Module::Function*>::const_iterator func_it = functions_.begin();
170         func_it != functions_.end();
171         func_it++) {
172      Module::Function *f = *func_it;
173      // Compute the function f's size.
174      vector<Module::Address>::const_iterator boundary
175          = std::upper_bound(boundaries_.begin(), boundaries_.end(), f->address);
176      if (boundary != boundaries_.end())
177        f->ranges[0].size = *boundary - f->address;
178      else
179        // If this is the last function in the module, and the STABS
180        // reader was unable to give us its ending address, then assign
181        // it a bogus, very large value.  This will happen at most once
182        // per module: since we've added all functions' addresses to the
183        // boundary table, only one can be the last.
184        f->ranges[0].size = kFallbackSize;
185  
186      // Compute sizes for each of the function f's lines --- if it has any.
187      if (!f->lines.empty()) {
188        stable_sort(f->lines.begin(), f->lines.end(),
189                    Module::Line::CompareByAddress);
190        vector<Module::Line>::iterator last_line = f->lines.end() - 1;
191        for (vector<Module::Line>::iterator line_it = f->lines.begin();
192             line_it != last_line; line_it++)
193          line_it[0].size = line_it[1].address - line_it[0].address;
194        // Compute the size of the last line from f's end address.
195        last_line->size =
196          (f->ranges[0].address + f->ranges[0].size) - last_line->address;
197      }
198    }
199    // Now that everything has a size, add our functions to the module, and
200    // dispose of our private list. Delete the functions that we fail to add, so
201    // they aren't leaked.
202    for (Module::Function* func: functions_)
203      if (!module_->AddFunction(func))
204        delete func;
205    functions_.clear();
206  }
207  
208  } // namespace google_breakpad