Breakpad Linux dumper: STABS reader incorrectly assumes a single compilation unit

The stabs reading code in google-breakpad incorrectly assumes that the
stabs data is a single compilation unit. Specifically, it ignores
N_UNDF stabs and assumes that all string indices are relative to the
beginning of the .stabstr section.

This is true when linking with the GNU linker by default, because the
GNU linker optimizes stabs debug info. The gold linker does not do
this optimization. It can be disabled when using the GNU linker with
the --traditional-format command line option.

For more details of the problem, see:

http://sourceware.org/bugzilla/show_bug.cgi?id=10338
http://code.google.com/p/google-breakpad/issues/detail?id=359

This patch adds unit tests that reproduce the failure, and fixes the
stabs parser.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@490 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
jimblandy 2010-01-14 17:19:34 +00:00
parent 7b873221e6
commit 5251e64f48
3 changed files with 194 additions and 35 deletions

View file

@ -43,6 +43,8 @@ StabsReader::StabsReader(const uint8_t *stab, size_t stab_size,
stabstr_(stabstr),
stabstr_size_(stabstr_size),
handler_(handler),
string_offset_(0),
next_cu_string_offset_(0),
symbol_(NULL),
current_source_file_(NULL) {
symbols_ = reinterpret_cast<const struct nlist *>(stab);
@ -50,7 +52,7 @@ StabsReader::StabsReader(const uint8_t *stab, size_t stab_size,
}
const char *StabsReader::SymbolString() {
ptrdiff_t offset = symbol_->n_un.n_strx;
ptrdiff_t offset = string_offset_ + symbol_->n_un.n_strx;
if (offset < 0 || (size_t) offset >= stabstr_size_) {
handler_->Warning("symbol %d: name offset outside the string section",
symbol_ - symbols_);
@ -67,6 +69,21 @@ bool StabsReader::Process() {
if (symbol_->n_type == N_SO) {
if (! ProcessCompilationUnit())
return false;
} else if (symbol_->n_type == N_UNDF) {
// At the head of each compilation unit's entries there is an
// N_UNDF stab giving the number of symbols in the compilation
// unit, and the number of bytes that compilation unit's strings
// take up in the .stabstr section. Each CU's strings are
// separate; the n_strx values are offsets within the current
// CU's portion of the .stabstr section.
//
// As an optimization, the GNU linker combines all the
// compilation units into one, with a single N_UNDF at the
// beginning. However, other linkers, like Gold, do not perform
// this optimization.
string_offset_ = next_cu_string_offset_;
next_cu_string_offset_ = SymbolValue();
symbol_++;
} else
symbol_++;
}