aboutsummaryrefslogtreecommitdiff
path: root/src/common/stabs_reader.h
diff options
context:
space:
mode:
authorjimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-05-05 17:09:20 +0000
committerjimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-05-05 17:09:20 +0000
commitb0ec96cee2ab186c9e7e480d03751588f0640bf1 (patch)
tree40fc8df4fbbf5542c27cad2919c025fe3881457f /src/common/stabs_reader.h
parentBreakpad symbol dumper: Define the ByteBuffer and ByteCursor classes. (diff)
downloadbreakpad-b0ec96cee2ab186c9e7e480d03751588f0640bf1.tar.xz
Breakpad Linux dumper: Make StabsReader independent of endianness and word size.
StabsReader simply applies a reinterpret_cast to treat the stab entry data as an array of 'struct nlist' structures, making the parser specific on the host endianness, word size, and alignment rules. On Mac OS X, a single fat binary file may contain object files of different ABIs, of which the user chooses one at run time. This patch changes the parser to read the data using the google_breakpad:: ByteCursor class, which can handle different endiannesses and word sizes. The StabsReader constructor now takes arguments indicating the endianness of the data and the size of each entry's value field. The patch changes src/common/linux/dump_symbols.cc to pass the new argument. This patch changes the StabsReader unit tests to use the google_breakpad:: TestAssembler classes to generate test data, rather than reading it from a file. This makes it easy to generate test data in various endiannesses and word sizes. It also adds tests for the new parser behaviors. a=jimblandy, r=thestig git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@583 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/common/stabs_reader.h')
-rw-r--r--src/common/stabs_reader.h127
1 files changed, 102 insertions, 25 deletions
diff --git a/src/common/stabs_reader.h b/src/common/stabs_reader.h
index 5cfcdfb5..9f954650 100644
--- a/src/common/stabs_reader.h
+++ b/src/common/stabs_reader.h
@@ -38,36 +38,47 @@
//
// The comments here assume you understand the format.
//
-// This parser assumes that the system's <a.out.h> and <stab.h>
-// headers accurately describe the layout of the STABS data; this code
-// will not parse STABS data for a system with a different address
-// size or endianness.
+// This parser can handle big-endian and little-endian data, and the symbol
+// values may be either 32 or 64 bits long. It handles both STABS in
+// sections (as used on Linux) and STABS appearing directly in an
+// a.out-like symbol table (as used in Darwin OS X Mach-O files).
-#ifndef COMMON_LINUX_STABS_READER_H__
-#define COMMON_LINUX_STABS_READER_H__
+#ifndef COMMON_STABS_READER_H__
+#define COMMON_STABS_READER_H__
+#include <stddef.h>
#include <stdint.h>
-#include <cstddef>
+
+#ifdef HAVE_A_OUT_H
#include <a.out.h>
+#endif
#include <string>
+#include "common/byte_cursor.h"
+
namespace google_breakpad {
class StabsHandler;
class StabsReader {
public:
- // Create a reader for the STABS debug information whose .stab
- // section is the STAB_SIZE bytes at STAB, and whose .stabstr
- // section is the STABSTR_SIZE bytes at STABSTR. The reader will
- // call the member functions of HANDLER to report the information it
- // finds, when the reader's 'Process' member function is called.
+ // Create a reader for the STABS debug information whose .stab section is
+ // being traversed by ITERATOR, and whose .stabstr section is referred to
+ // by STRINGS. The reader will call the member functions of HANDLER to
+ // report the information it finds, when the reader's 'Process' member
+ // function is called.
+ //
+ // BIG_ENDIAN should be true if the entries in the .stab section are in
+ // big-endian form, or false if they are in little-endian form.
+ // VALUE_SIZE should be either 4 or 8, indicating the size of the 'value'
+ // field in each entry in bytes.
//
// Note that, in ELF, the .stabstr section should be found using the
// 'sh_link' field of the .stab section header, not by name.
StabsReader(const uint8_t *stab, size_t stab_size,
const uint8_t *stabstr, size_t stabstr_size,
+ bool big_endian, size_t value_size,
StabsHandler *handler);
// Process the STABS data, calling the handler's member functions to
@@ -75,17 +86,82 @@ class StabsReader {
// continue to process until we reach the end of the section. If we
// processed the entire section and all handlers returned true,
// return true. If any handler returned false, return false.
+ //
+ // This is only meant to be called once per StabsReader instance;
+ // resuming a prior processing pass that stopped abruptly isn't supported.
bool Process();
private:
+
+ // An class for walking arrays of STABS entries. This isolates the main
+ // STABS reader from the exact format (size; endianness) of the entries
+ // themselves.
+ class EntryIterator {
+ public:
+ // The contents of a STABS entry, adjusted for the host's endianness,
+ // word size, 'struct nlist' layout, and so on.
+ struct Entry {
+ // True if this iterator has reached the end of the entry array. When
+ // this is set, the other members of this structure are not valid.
+ bool at_end;
+
+ // The number of this entry within the list.
+ size_t index;
+
+ // The current entry's name offset. This is the offset within the
+ // current compilation unit's strings, as establish by the N_UNDF entries.
+ size_t name_offset;
+
+ // The current entry's type, 'other' field, descriptor, and value.
+ unsigned char type;
+ unsigned char other;
+ short descriptor;
+ uint64_t value;
+ };
+
+ // Create a EntryIterator walking the entries in BUFFER. Treat the
+ // entries as big-endian if BIG_ENDIAN is true, as little-endian
+ // otherwise. Assume each entry has a 'value' field whose size is
+ // VALUE_SIZE.
+ //
+ // This would not be terribly clean to extend to other format variations,
+ // but it's enough to handle Linux and Mac, and we'd like STABS to die
+ // anyway.
+ //
+ // For the record: on Linux, STABS entry values are always 32 bits,
+ // regardless of the architecture address size (don't ask me why); on
+ // Mac, they are 32 or 64 bits long. Oddly, the section header's entry
+ // size for a Linux ELF .stab section varies according to the ELF class
+ // from 12 to 20 even as the actual entries remain unchanged.
+ EntryIterator(const ByteBuffer *buffer, bool big_endian, size_t value_size);
+
+ // Move to the next entry. This function's behavior is undefined if
+ // at_end() is true when it is called.
+ EntryIterator &operator++() { Fetch(); entry_.index++; return *this; }
+
+ // Dereferencing this iterator produces a reference to an Entry structure
+ // that holds the current entry's values. The entry is owned by this
+ // EntryIterator, and will be invalidated at the next call to operator++.
+ const Entry &operator*() const { return entry_; }
+ const Entry *operator->() const { return &entry_; }
+
+ private:
+ // Read the STABS entry at cursor_, and set entry_ appropriately.
+ void Fetch();
+
+ // The size of entries' value field, in bytes.
+ size_t value_size_;
+
+ // A byte cursor traversing buffer_.
+ ByteCursor cursor_;
+
+ // Values for the entry this iterator refers to.
+ Entry entry_;
+ };
+
// Return the name of the current symbol.
const char *SymbolString();
- // Return the value of the current symbol.
- const uint64_t SymbolValue() {
- return symbol_->n_value;
- }
-
// Process a compilation unit starting at symbol_. Return true
// to continue processing, or false to abort.
bool ProcessCompilationUnit();
@@ -94,10 +170,14 @@ class StabsReader {
// Return true to continue processing, or false to abort.
bool ProcessFunction();
- // The debugging information we're reading.
- const struct nlist *symbols_, *symbols_end_;
- const uint8_t *stabstr_;
- size_t stabstr_size_;
+ // The STABS entries we're parsing.
+ ByteBuffer entries_;
+
+ // The string section to which the entries refer.
+ ByteBuffer strings_;
+
+ // The iterator walking the STABS entries.
+ EntryIterator iterator_;
StabsHandler *handler_;
@@ -108,9 +188,6 @@ class StabsReader {
// as established by N_UNDF entries.
size_t next_cu_string_offset_;
- // The current symbol we're processing.
- const struct nlist *symbol_;
-
// The current source file name.
const char *current_source_file_;
};
@@ -203,4 +280,4 @@ class StabsHandler {
} // namespace google_breakpad
-#endif // COMMON_LINUX_STABS_READER_H__
+#endif // COMMON_STABS_READER_H__