aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorjimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e>2009-12-23 21:13:11 +0000
committerjimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e>2009-12-23 21:13:11 +0000
commit5a6e1d3f03ec2c8ccbb63edaccf00ecd02e148bc (patch)
treea8e809508b6e5094cb01801cb843836a4220ef11 /src/common
parentfix compilation on 64-bit, followup from issue 357 (diff)
downloadbreakpad-5a6e1d3f03ec2c8ccbb63edaccf00ecd02e148bc.tar.xz
Breakpad Linux dumper: move DumpStabsHandler into its own file, for testing.
This will make it easier to write unit tests for DumpStabsHandler. a=jimblandy, r=nealsid git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@464 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/common')
-rw-r--r--src/common/linux/dump_stabs.cc174
-rw-r--r--src/common/linux/dump_stabs.h127
-rw-r--r--src/common/linux/dump_symbols.cc214
3 files changed, 304 insertions, 211 deletions
diff --git a/src/common/linux/dump_stabs.cc b/src/common/linux/dump_stabs.cc
new file mode 100644
index 00000000..e61b274e
--- /dev/null
+++ b/src/common/linux/dump_stabs.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2009, 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.
+
+// dump_stabs.cc --- implement the DumpStabsHandler class.
+
+#include <cstdarg>
+#include <cxxabi.h>
+
+#include <algorithm>
+#include <cassert>
+
+#include "common/linux/dump_stabs.h"
+
+namespace google_breakpad {
+
+using std::string;
+
+// 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);
+}
+
+bool DumpStabsHandler::StartCompilationUnit(const char *name, uint64_t address,
+ const char *build_directory) {
+ assert(!comp_unit_base_address_);
+ 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 DumpStabsHandler::EndCompilationUnit(uint64_t address) {
+ assert(comp_unit_base_address_);
+ 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 DumpStabsHandler::StartFunction(const string &name,
+ uint64_t address) {
+ assert(!current_function_);
+ Module::Function *f = new Module::Function;
+ f->name_ = Demangle(name);
+ f->address_ = address;
+ f->size_ = 0; // We compute this in DumpStabsHandler::Finalize().
+ f->parameter_size_ = 0; // We don't provide this information.
+ current_function_ = f;
+ boundaries_.push_back(static_cast<Module::Address>(address));
+ return true;
+}
+
+bool DumpStabsHandler::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; only one
+ // entry can meet this requirement.
+ //
+ // (I don't really understand the above comment; just bringing it
+ // along from the previous code, and leaving the behaivor unchanged.
+ // If you know the whole story, please patch this comment. --jimb)
+ 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 DumpStabsHandler::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 DumpStabsHandler::Finalize().
+ line.file_ = current_source_file_;
+ line.number_ = number;
+ current_function_->lines_.push_back(line);
+ return true;
+}
+
+void DumpStabsHandler::Warning(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
+void DumpStabsHandler::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 *>::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>::iterator boundary
+ = std::upper_bound(boundaries_.begin(), boundaries_.end(), f->address_);
+ if (boundary != boundaries_.end())
+ f->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->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->address_ + f->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
diff --git a/src/common/linux/dump_stabs.h b/src/common/linux/dump_stabs.h
new file mode 100644
index 00000000..a7dbc50f
--- /dev/null
+++ b/src/common/linux/dump_stabs.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2009, Google Inc. -*- mode: C++ -*-
+// 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.
+
+// dump_stabs.h: A StabsHandler that populates a Module.
+
+#ifndef COMMON_LINUX_DUMP_STABS_H__
+#define COMMON_LINUX_DUMP_STABS_H__
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "common/linux/module.h"
+#include "common/linux/stabs_reader.h"
+
+namespace google_breakpad {
+
+using std::string;
+using std::vector;
+
+// A DumpStabsHandler is a handler that receives parsed STABS
+// debugging information from a StabsReader, and uses that to populate
+// a Module. (All classes are in the google_breakpad namespace.) A
+// Module represents the contents of a Breakpad symbol file, and knows
+// how to write itself out as such. A DumpStabsHandler thus acts as
+// the bridge between STABS and Breakpad data.
+class DumpStabsHandler: public google_breakpad::StabsHandler {
+ public:
+ // Receive parsed debugging information from a StabsReader, and
+ // store it all in MODULE.
+ DumpStabsHandler(Module *module) :
+ module_(module),
+ comp_unit_base_address_(0),
+ current_function_(NULL),
+ current_source_file_(NULL),
+ current_source_file_name_(NULL) { }
+
+ // The standard StabsHandler virtual member functions.
+ bool StartCompilationUnit(const char *name, uint64_t address,
+ const char *build_directory);
+ bool EndCompilationUnit(uint64_t address);
+ bool StartFunction(const string &name, uint64_t address);
+ bool EndFunction(uint64_t address);
+ bool Line(uint64_t address, const char *name, int number);
+ void Warning(const char *format, ...);
+
+ // Do any final processing necessary to make module_ contain all the
+ // data provided by the STABS reader.
+ //
+ // Because STABS does not provide reliable size information for
+ // functions and lines, we need to make a pass over the data after
+ // processing all the STABS to compute those sizes. We take care of
+ // that here.
+ void Finalize();
+
+ private:
+
+ // An arbitrary, but very large, size to use for functions whose
+ // size we can't compute properly.
+ static const uint64_t kFallbackSize = 0x10000000;
+
+ // The module we're contributing debugging info to.
+ Module *module_;
+
+ // The functions we've generated so far. We don't add these to
+ // module_ as we parse them. Instead, we wait until we've computed
+ // their ending address, and their lines' ending addresses.
+ //
+ // We could just stick them in module_ from the outset, but if
+ // module_ already contains data gathered from other debugging
+ // formats, that would complicate the size computation.
+ vector<Module::Function *> functions_;
+
+ // Boundary addresses. STABS doesn't necessarily supply sizes for
+ // functions and lines, so we need to compute them ourselves by
+ // finding the next object.
+ vector<Module::Address> boundaries_;
+
+ // The base address of the current compilation unit. We use this to
+ // recognize functions we should omit from the symbol file. (If you
+ // know the details of why we omit these, please patch this
+ // comment.)
+ Module::Address comp_unit_base_address_;
+
+ // The function we're currently contributing lines to.
+ Module::Function *current_function_;
+
+ // The last Module::File we got a line number in.
+ Module::File *current_source_file_;
+
+ // The pointer in the .stabstr section of the name that
+ // current_source_file_ is built from. This allows us to quickly
+ // recognize when the current line is in the same file as the
+ // previous one (which it usually is).
+ const char *current_source_file_name_;
+};
+
+} // namespace google_breakpad
+
+#endif // COMMON_LINUX_DUMP_STABS_H__
diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
index 5d4e8834..c4047ebe 100644
--- a/src/common/linux/dump_symbols.cc
+++ b/src/common/linux/dump_symbols.cc
@@ -27,29 +27,20 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <assert.h>
-#include <cxxabi.h>
#include <elf.h>
-#include <errno.h>
#include <fcntl.h>
#include <link.h>
-#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
-#include <sys/types.h>
#include <unistd.h>
-#include <algorithm>
-#include <cstdarg>
+#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
-#include <functional>
-#include <list>
-#include <map>
#include <string>
-#include <vector>
+#include "common/linux/dump_stabs.h"
#include "common/linux/dump_symbols.h"
#include "common/linux/file_id.h"
#include "common/linux/module.h"
@@ -59,24 +50,11 @@
namespace {
using google_breakpad::Module;
-using std::vector;
+using google_breakpad::DumpStabsHandler;
// Stab section name.
static const char *kStabName = ".stab";
-// Demangle using abi call.
-// Older GCC may not support it.
-static std::string Demangle(const std::string &mangled) {
- int status = 0;
- char *demangled = abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status);
- if (status == 0 && demangled != NULL) {
- std::string str(demangled);
- free(demangled);
- return str;
- }
- return std::string(mangled);
-}
-
// Fix offset into virtual address by adding the mapped base into offsets.
// Make life easier when want to find something by offset.
static void FixAddress(void *obj_base) {
@@ -128,192 +106,6 @@ static const ElfW(Shdr) *FindSectionByName(const char *name,
return NULL;
}
-// Our handler class for STABS data.
-class DumpStabsHandler: public google_breakpad::StabsHandler {
- public:
- DumpStabsHandler(Module *module) :
- module_(module),
- comp_unit_base_address_(0),
- current_function_(NULL),
- current_source_file_(NULL),
- current_source_file_name_(NULL) { }
-
- bool StartCompilationUnit(const char *name, uint64_t address,
- const char *build_directory);
- bool EndCompilationUnit(uint64_t address);
- bool StartFunction(const std::string &name, uint64_t address);
- bool EndFunction(uint64_t address);
- bool Line(uint64_t address, const char *name, int number);
- void Warning(const char *format, ...);
-
- // Do any final processing necessary to make module_ contain all the
- // data provided by the STABS reader.
- //
- // Because STABS does not provide reliable size information for
- // functions and lines, we need to make a pass over the data after
- // processing all the STABS to compute those sizes. We take care of
- // that here.
- void Finalize();
-
- private:
-
- // An arbitrary, but very large, size to use for functions whose
- // size we can't compute properly.
- static const uint64_t kFallbackSize = 0x10000000;
-
- // The module we're contributing debugging info to.
- Module *module_;
-
- // The functions we've generated so far. We don't add these to
- // module_ as we parse them. Instead, we wait until we've computed
- // their ending address, and their lines' ending addresses.
- //
- // We could just stick them in module_ from the outset, but if
- // module_ already contains data gathered from other debugging
- // formats, that would complicate the size computation.
- vector<Module::Function *> functions_;
-
- // Boundary addresses. STABS doesn't necessarily supply sizes for
- // functions and lines, so we need to compute them ourselves by
- // finding the next object.
- vector<Module::Address> boundaries_;
-
- // The base address of the current compilation unit. We use this to
- // recognize functions we should omit from the symbol file. (If you
- // know the details of why we omit these, please patch this
- // comment.)
- Module::Address comp_unit_base_address_;
-
- // The function we're currently contributing lines to.
- Module::Function *current_function_;
-
- // The last Module::File we got a line number in.
- Module::File *current_source_file_;
-
- // The pointer in the .stabstr section of the name that
- // current_source_file_ is built from. This allows us to quickly
- // recognize when the current line is in the same file as the
- // previous one (which it usually is).
- const char *current_source_file_name_;
-};
-
-bool DumpStabsHandler::StartCompilationUnit(const char *name, uint64_t address,
- const char *build_directory) {
- assert(! comp_unit_base_address_);
- 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 DumpStabsHandler::EndCompilationUnit(uint64_t address) {
- assert(comp_unit_base_address_);
- 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 DumpStabsHandler::StartFunction(const std::string &name,
- uint64_t address) {
- assert(! current_function_);
- Module::Function *f = new Module::Function;
- f->name_ = Demangle(name);
- f->address_ = address;
- f->size_ = 0; // We compute this in DumpStabsHandler::Finalize().
- f->parameter_size_ = 0; // We don't provide this information.
- current_function_ = f;
- boundaries_.push_back(static_cast<Module::Address>(address));
- return true;
-}
-
-bool DumpStabsHandler::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; only one
- // entry can meet this requirement.
- //
- // (I don't really understand the above comment; just bringing it
- // along from the previous code, and leaving the behaivor unchanged.
- // If you know the whole story, please patch this comment. --jimb)
- 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 DumpStabsHandler::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 DumpStabsHandler::Finalize().
- line.file_ = current_source_file_;
- line.number_ = number;
- current_function_->lines_.push_back(line);
- return true;
-}
-
-void DumpStabsHandler::Warning(const char *format, ...) {
- va_list args;
- va_start(args, format);
- vfprintf(stderr, format, args);
- va_end(args);
-}
-
-void DumpStabsHandler::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 *>::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>::iterator boundary
- = std::upper_bound(boundaries_.begin(), boundaries_.end(), f->address_);
- if (boundary != boundaries_.end())
- f->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->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->address_ + f->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();
-}
-
static bool LoadSymbols(const ElfW(Shdr) *stab_section,
const ElfW(Shdr) *stabstr_section,
Module *module) {