Breakpad Linux dumper: Add support for dumping DWARF CFI as STACK CFI records.

Define a new DWARF parser class, dwarf2reader::CallFrameInfo.

Extend google_breakpad::Module to store and write out 'STACK CFI' records.

Define a new google_breakpad::DwarfCFIToModule class, to accept DWARF
CFI data from the parser and populate a Module with the equivalent
STACK CFI records.

Extend the Linux symbol dumping tool, dump_syms, to use
dwarf2reader::CallFrameInfo, google_breakpad::DwarfCFIToModule, and
google_breakpad::Module to extract DWARF CFI from the executable or
shared library files and write it to the Breakpad symbol file.

Define CFISection, a new class derived from TestAssembler::Section,
for use in creating DWARF CFI data for test cases.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@550 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
jimblandy
2010-03-16 16:31:49 +00:00
parent 6d3a825dbf
commit 3e768ed9c0
14 changed files with 4935 additions and 11 deletions

View File

@@ -0,0 +1,103 @@
// 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>
// cfi_assembler.cc: Implementation of google_breakpad::CFISection class.
// See cfi_assembler.h for details.
#include <cassert>
#include "common/dwarf/cfi_assembler.h"
#include "common/dwarf/dwarf2enums.h"
namespace google_breakpad {
CFISection &CFISection::CIEHeader(u_int64_t code_alignment_factor,
int data_alignment_factor,
unsigned return_address_register,
u_int8_t version,
const string &augmentation,
bool dwarf64) {
assert(!entry_length_);
entry_length_ = new PendingLength();
if (dwarf64) {
D32(0xffffffff);
D64(entry_length_->length);
entry_length_->start = Here();
D64(0xffffffffffffffffULL); // CIE distinguished value
} else {
D32(entry_length_->length);
entry_length_->start = Here();
D32(0xffffffff); // CIE distinguished value
}
D8(version);
AppendCString(augmentation);
ULEB128(code_alignment_factor);
LEB128(data_alignment_factor);
if (version == 1)
D8(return_address_register);
else
ULEB128(return_address_register);
return *this;
}
CFISection &CFISection::FDEHeader(Label cie_pointer,
u_int64_t initial_location,
u_int64_t address_range,
bool dwarf64) {
assert(!entry_length_);
entry_length_ = new PendingLength();
if (dwarf64) {
D32(0xffffffff);
D64(entry_length_->length);
entry_length_->start = Here();
D64(cie_pointer);
} else {
D32(entry_length_->length);
entry_length_->start = Here();
D32(cie_pointer);
}
Append(endianness(), address_size_, initial_location);
Append(endianness(), address_size_, address_range);
return *this;
}
CFISection &CFISection::FinishEntry() {
assert(entry_length_);
Align(address_size_, dwarf2reader::DW_CFA_nop);
entry_length_->length = Here() - entry_length_->start;
delete entry_length_;
entry_length_ = NULL;
return *this;
}
};

View File

@@ -0,0 +1,149 @@
// -*- mode: C++ -*-
// 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>
// cfi-assembler.h: Define CFISection, a class for creating properly
// (and improperly) formatted DWARF CFI data for unit tests.
#ifndef PROCESSOR_CFI_ASSEMBLER_H_
#define PROCESSOR_CFI_ASSEMBLER_H_
#include <string>
#include "google_breakpad/common/breakpad_types.h"
#include "processor/test_assembler.h"
namespace google_breakpad {
using google_breakpad::TestAssembler::Endianness;
using google_breakpad::TestAssembler::Label;
using google_breakpad::TestAssembler::Section;
using std::string;
class CFISection: public Section {
public:
// Create a CFISection whose endianness is ENDIANNESS, and where
// machine addresses are ADDRESS_SIZE bytes long.
CFISection(Endianness endianness, size_t address_size)
: Section(endianness), address_size_(address_size),
entry_length_(NULL) {
// The 'start', 'Here', and 'Mark' members of a CFISection all refer
// to section offsets.
start() = 0;
}
// Return this CFISection's address size.
size_t AddressSize() const { return address_size_; }
// Append a Common Information Entry header to this section with the
// given values. If dwarf64 is true, use the 64-bit DWARF initial
// length format for the CIE's initial length. Return a reference to
// this section. You should call FinishEntry after writing the last
// instruction for the CIE.
//
// Before calling this function, you will typically want to use Mark
// or Here to make a label to pass to FDEHeader that refers to this
// CIE's position in the section.
CFISection &CIEHeader(u_int64_t code_alignment_factor,
int data_alignment_factor,
unsigned return_address_register,
u_int8_t version = 3,
const string &augmentation = "",
bool dwarf64 = false);
// Append a Frame Description Entry header to this section with the
// given values. If dwarf64 is true, use the 64-bit DWARF initial
// length format for the CIE's initial length. Return a reference to
// this section. You should call FinishEntry after writing the last
// instruction for the CIE.
//
// This function doesn't support entries that are longer than
// 0xffffff00 bytes. (The "initial length" is always a 32-bit
// value.) Nor does it support .debug_frame sections longer than
// 0xffffff00 bytes.
CFISection &FDEHeader(Label cie_pointer,
u_int64_t initial_location,
u_int64_t address_range,
bool dwarf64 = false);
// Note the current position as the end of the last CIE or FDE we
// started, after padding with DW_CFA_nops for alignment. This
// defines the label representing the entry's length, cited in the
// entry's header. Return a reference to this section.
CFISection &FinishEntry();
// Append the contents of BLOCK as a DW_FORM_block value: an
// unsigned LEB128 length, followed by that many bytes of data.
CFISection &Block(const string &block) {
ULEB128(block.size());
Append(block);
return *this;
}
// Restate some member functions, to keep chaining working nicely.
CFISection &Mark(Label *label) { Section::Mark(label); return *this; }
CFISection &D8(u_int8_t v) { Section::D8(v); return *this; }
CFISection &D16(u_int16_t v) { Section::D16(v); return *this; }
CFISection &D16(Label v) { Section::D16(v); return *this; }
CFISection &D32(u_int32_t v) { Section::D32(v); return *this; }
CFISection &D32(const Label &v) { Section::D32(v); return *this; }
CFISection &D64(u_int64_t v) { Section::D64(v); return *this; }
CFISection &D64(const Label &v) { Section::D64(v); return *this; }
CFISection &LEB128(long long v) { Section::LEB128(v); return *this; }
CFISection &ULEB128(u_int64_t v) { Section::ULEB128(v); return *this; }
private:
// A length value that we've appended to the section, but is not yet
// known. LENGTH is the appended value; START is a label referring
// to the start of the data whose length was cited.
struct PendingLength {
Label length;
Label start;
};
// The size of a machine address for the data in this section.
size_t address_size_;
// The length value for the current entry.
//
// Oddly, this must be dynamically allocated. Labels never get new
// values; they only acquire constraints on the value they already
// have, or assert if you assign them something incompatible. So
// each header needs truly fresh Label objects to cite in their
// headers and track their positions. The alternative is explicit
// destructor invocation and a placement new. Ick.
PendingLength *entry_length_;
};
} // namespace google_breakpad
#endif // PROCESSOR_CFI_ASSEMBLER_H_

View File

@@ -530,5 +530,48 @@ enum DwarfInline {
DW_INL_declared_inlined =0x3,
};
// Call Frame Info instructions.
enum DwarfCFI
{
DW_CFA_advance_loc = 0x40,
DW_CFA_offset = 0x80,
DW_CFA_restore = 0xc0,
DW_CFA_nop = 0x00,
DW_CFA_set_loc = 0x01,
DW_CFA_advance_loc1 = 0x02,
DW_CFA_advance_loc2 = 0x03,
DW_CFA_advance_loc4 = 0x04,
DW_CFA_offset_extended = 0x05,
DW_CFA_restore_extended = 0x06,
DW_CFA_undefined = 0x07,
DW_CFA_same_value = 0x08,
DW_CFA_register = 0x09,
DW_CFA_remember_state = 0x0a,
DW_CFA_restore_state = 0x0b,
DW_CFA_def_cfa = 0x0c,
DW_CFA_def_cfa_register = 0x0d,
DW_CFA_def_cfa_offset = 0x0e,
DW_CFA_def_cfa_expression = 0x0f,
DW_CFA_expression = 0x10,
DW_CFA_offset_extended_sf = 0x11,
DW_CFA_def_cfa_sf = 0x12,
DW_CFA_def_cfa_offset_sf = 0x13,
DW_CFA_val_offset = 0x14,
DW_CFA_val_offset_sf = 0x15,
DW_CFA_val_expression = 0x16,
// Opcodes in this range are reserved for user extensions.
DW_CFA_lo_user = 0x1c,
DW_CFA_hi_user = 0x3f,
// SGI/MIPS specific.
DW_CFA_MIPS_advance_loc8 = 0x1d,
// GNU extensions.
DW_CFA_GNU_window_save = 0x2d,
DW_CFA_GNU_args_size = 0x2e,
DW_CFA_GNU_negative_offset_extended = 0x2f
};
} // namespace dwarf2reader
#endif // COMMON_DWARF_DWARF2ENUMS_H__

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,5 @@
// -*- mode: C++ -*-
// Copyright (c) 2010 Google Inc. All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -26,6 +28,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// CFI reader author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
// This file contains definitions related to the DWARF2/3 reader and
// it's handler interfaces.
// The DWARF2/3 specification can be found at
@@ -398,6 +402,470 @@ class Dwarf2Handler {
};
// This class is a reader for DWARF's Call Frame Information. CFI
// describes how to unwind stack frames --- even for functions that do
// not follow fixed conventions for saving registers, whose frame size
// varies as they execute, etc.
//
// CFI describes, at each machine instruction, how to compute the
// stack frame's base address, how to find the return address, and
// where to find the saved values of the caller's registers (if the
// callee has stashed them somewhere to free up the registers for its
// own use).
//
// For example, suppose we have a function whose machine code looks
// like this (imagine an assembly language that looks like C, for a
// machine with 32-bit registers, and a stack that grows towards lower
// addresses):
//
// func: ; entry point; return address at sp
// func+0: sp = sp - 16 ; allocate space for stack frame
// func+1: sp[12] = r0 ; save r0 at sp+12
// ... ; other code, not frame-related
// func+10: sp -= 4; *sp = x ; push some x on the stack
// ... ; other code, not frame-related
// func+20: r0 = sp[16] ; restore saved r0
// func+21: sp += 20 ; pop whole stack frame
// func+22: pc = *sp; sp += 4 ; pop return address and jump to it
//
// DWARF CFI is (a very compressed representation of) a table with a
// row for each machine instruction address and a column for each
// register showing how to restore it, if possible.
//
// A special column named "CFA", for "Canonical Frame Address", tells how
// to compute the base address of the frame; registers' entries may
// refer to the CFA in describing where the registers are saved.
//
// Another special column, named "RA", represents the return address.
//
// For example, here is a complete (uncompressed) table describing the
// function above:
//
// insn cfa r0 r1 ... ra
// =======================================
// func+0: sp cfa[0]
// func+1: sp+16 cfa[0]
// func+2: sp+16 cfa[-4] cfa[0]
// func+11: sp+20 cfa[-4] cfa[0]
// func+21: sp+20 cfa[0]
// func+22: sp cfa[0]
//
// Some things to note here:
//
// - Each row describes the state of affairs *before* executing the
// instruction at the given address. Thus, the row for func+0
// describes the state before we allocate the stack frame. In the
// next row, the formula for computing the CFA has changed,
// reflecting that allocation.
//
// - The other entries are written in terms of the CFA; this allows
// them to remain unchanged as the stack pointer gets bumped around.
// For example, the rule for recovering the return address (the "ra"
// column) remains unchanged throughout the function, even as the
// stack pointer takes on three different offsets from the return
// address.
//
// - Although we haven't shown it, most calling conventions designate
// "callee-saves" and "caller-saves" registers. The callee must
// preserve the values of callee-saves registers; if it uses them,
// it must save their original values somewhere, and restore them
// before it returns. In contrast, the callee is free to trash
// caller-saves registers; if the callee uses these, it will
// probably not bother to save them anywhere, and the CFI will
// probably mark their values as "unrecoverable".
//
// (However, since the caller cannot assume the callee was going to
// save them, caller-saves registers are probably dead in the caller
// anyway, so compilers usually don't generate CFA for caller-saves
// registers.)
//
// - Exactly where the CFA points is a matter of convention that
// depends on the architecture and ABI in use. In the example, the
// CFA is the value the stack pointer had upon entry to the
// function, pointing at the saved return address. But on the x86,
// the call frame information generated by GCC follows the
// convention that the CFA is the address *after* the saved return
// address.
//
// But by definition, the CFA remains constant throughout the
// lifetime of the frame. This makes it a useful value for other
// columns to refer to. It is also gives debuggers a useful handle
// for identifying a frame.
//
// If you look at the table above, you'll notice that a given entry is
// often the same as the one immediately above it: most instructions
// change only one or two aspects of the stack frame, if they affect
// it at all. The DWARF format takes advantage of this fact, and
// reduces the size of the data by mentioning only the addresses and
// columns at which changes take place. So for the above, DWARF CFI
// data would only actually mention the following:
//
// insn cfa r0 r1 ... ra
// =======================================
// func+0: sp cfa[0]
// func+1: sp+16
// func+2: cfa[-4]
// func+11: sp+20
// func+21: r0
// func+22: sp
//
// In fact, this is the way the parser reports CFI to the consumer: as
// a series of statements of the form, "At address X, column Y changed
// to Z," and related conventions for describing the initial state.
//
// Naturally, it would be impractical to have to scan the entire
// program's CFI, noting changes as we go, just to recover the
// unwinding rules in effect at one particular instruction. To avoid
// this, CFI data is grouped into "entries", each of which covers a
// specified range of addresses and begins with a complete statement
// of the rules for all recoverable registers at that starting
// address. Each entry typically covers a single function.
//
// Thus, to compute the contents of a given row of the table --- that
// is, rules for recovering the CFA, RA, and registers at a given
// instruction --- the consumer should find the entry that covers that
// instruction's address, start with the initial state supplied at the
// beginning of the entry, and work forward until it has processed all
// the changes up to and including those for the present instruction.
//
// There are seven kinds of rules that can appear in an entry of the
// table:
//
// - "undefined": The given register is not preserved by the callee;
// its value cannot be recovered.
//
// - "same value": This register has the same value it did in the callee.
//
// - offset(N): The register is saved at offset N from the CFA.
//
// - val_offset(N): The value the register had in the caller is the
// CFA plus offset N. (This is usually only useful for describing
// the stack pointer.)
//
// - register(R): The register's value was saved in another register R.
//
// - expression(E): Evaluating the DWARF expression E using the
// current frame's registers' values yields the address at which the
// register was saved.
//
// - val_expression(E): Evaluating the DWARF expression E using the
// current frame's registers' values yields the value the register
// had in the caller.
class CallFrameInfo {
public:
// The different kinds of entries one finds in CFI. Used internally,
// and for error reporting.
enum EntryKind { kUnknown, kCIE, kFDE };
// The handler class to which the parser hands the parsed call frame
// information. Defined below.
class Handler;
// A reporter class, which CallFrameInfo uses to report errors
// encountered while parsing call frame information. Defined below.
class Reporter;
// Create a DWARF CFI parser. BUFFER points to the contents of the
// .debug_frame section to parse; BUFFER_LENGTH is its length in
// bytes. REPORTER is an error reporter the parser should use to
// report problems. READER is a ByteReader instance that has the
// endianness and address size set properly. Report the data we find
// to HANDLER.
CallFrameInfo(const char *buffer, size_t buffer_length,
ByteReader *reader, Handler *handler,
Reporter *reporter)
: buffer_(buffer),
buffer_length_(buffer_length),
reader_(reader),
handler_(handler),
reporter_(reporter) { }
~CallFrameInfo() { }
// Parse the entries in BUFFER, reporting what we find to HANDLER.
// Return true if we reach the end of the section successfully, or
// false if we encounter an error.
bool Start();
// Return the textual name of KIND. For error reporting.
static const char *KindName(EntryKind kind);
private:
struct CIE;
// A CFI entry, either an FDE or a CIE.
struct Entry {
// The starting offset of the entry in the section, for error
// reporting.
size_t offset;
// The start of this entry in the buffer.
const char *start;
// The end of this entry's common prologue (initial length and id), and
// the start of this entry's kind-specific fields.
const char *fields;
// The start of this entry's instructions.
const char *instructions;
// The address past the entry's last byte in the buffer. (Note that
// since offset points to the entry's initial length field, and the
// length field is the number of bytes after that field, this is not
// simply buffer_ + offset + length.)
const char *end;
// The CIE pointer or CIE id field.
uint64 id;
// The kind of entry we're parsing.
//
// This may be kUnknown at times, since we want to be able to
// count on it for error reporting even before we've finished
// parsing enough to tell what kind of entry we're looking at.
EntryKind kind;
// The CIE that applies to this entry, if we've parsed it. If this is a
// CIE, then this field points to this structure.
CIE *cie;
};
// A common information entry (CIE).
struct CIE: public Entry {
uint8 version; // CFI data version number
string augmentation; // vendor format extension markers
uint64 code_alignment_factor; // scale for code address adjustments
int data_alignment_factor; // scale for stack pointer adjustments
unsigned return_address_register; // which register holds the return addr
};
// A frame description entry (FDE).
struct FDE: public Entry {
uint64 address; // start address of described code
uint64 size; // size of described code, in bytes
};
// Internal use.
class Rule;
class UndefinedRule;
class SameValueRule;
class OffsetRule;
class ValOffsetRule;
class RegisterRule;
class ExpressionRule;
class ValExpressionRule;
class RuleMap;
class State;
// Parse the initial length and id of a CFI entry, either a CIE or an
// FDE. CURSOR points to the beginning of the data to parse.
// On success, populate ENTRY as appropriate, and return true.
// On failure, report the problem, and return false.
bool ReadEntryPrologue(const char *cursor, Entry *entry);
// Parse the fields of a CIE after the entry prologue. Assume that the
// 'Entry' fields of CIE are populated; use CIE->fields and CIE->end as
// the start and limit for parsing. On success, populate the rest of
// *CIE, and return true; on failure, report the problem and return
// false.
bool ReadCIEFields(CIE *cie);
// Parse the fields of an FDE after the entry prologue. Assume that the
// 'Entry' fields of *FDE are initialized; use FDE->fields and FDE->end
// as the start and limit for parsing. Assume that FDE->cie is fully
// initialized. On success, populate the rest of *FDE, and return true;
// on failure, report the problem and return false.
bool ReadFDEFields(FDE *fde);
// Report that ENTRY is incomplete, and return false. This is just a
// trivial wrapper for invoking reporter_->Incomplete; it provides a
// little brevity.
bool ReportIncomplete(Entry *entry);
// The contents of the DWARF .debug_info section we're parsing.
const char *buffer_;
size_t buffer_length_;
// For reading multi-byte values with the appropriate endianness.
ByteReader *reader_;
// The handler to which we should report the data we find.
Handler *handler_;
// For reporting problems in the info we're parsing.
Reporter *reporter_;
};
// The handler class for CallFrameInfo. The a CFI parser calls the
// member functions of a handler object to report the data it finds.
class CallFrameInfo::Handler {
public:
// The pseudo-register number for the canonical frame address.
enum { kCFARegister = -1 };
Handler() { }
virtual ~Handler() { }
// The parser has found CFI for the machine code at ADDRESS,
// extending for LENGTH bytes. OFFSET is the offset of the frame
// description entry in the section, for use in error messages.
// VERSION is the version number of the CFI format. AUGMENTATION is
// a string describing any producer-specific extensions present in
// the data. RETURN_ADDRESS is the number of the register that holds
// the address to which the function should return.
//
// Entry should return true to process this CFI, or false to skip to
// the next entry.
//
// The parser invokes Entry for each Frame Description Entry (FDE)
// it finds. The parser doesn't report Common Information Entries
// to the handler explicitly; instead, if the handler elects to
// process a given FDE, the parser reiterates the appropriate CIE's
// contents at the beginning of the FDE's rules.
virtual bool Entry(size_t offset, uint64 address, uint64 length,
uint8 version, const string &augmentation,
unsigned return_address) = 0;
// When the Entry function returns true, the parser calls these
// handler functions repeatedly to describe the rules for recovering
// registers at each instruction in the given range of machine code.
// Immediately after a call to Entry, the handler should assume that
// the rule for each callee-saves register is "unchanged" --- that
// is, that the register still has the value it had in the caller.
//
// If a *Rule function returns true, we continue processing this entry's
// instructions. If a *Rule function returns false, we stop evaluating
// instructions, and skip to the next entry. Either way, we call End
// before going on to the next entry.
//
// In all of these functions, if the REG parameter is kCFARegister, then
// the rule describes how to find the canonical frame address.
// kCFARegister may be passed as a BASE_REGISTER argument, meaning that
// the canonical frame address should be used as the base address for the
// computation. All other REG values will be positive.
// At ADDRESS, register REG's value is not recoverable.
virtual bool UndefinedRule(uint64 address, int reg) = 0;
// At ADDRESS, register REG's value is the same as that it had in
// the caller.
virtual bool SameValueRule(uint64 address, int reg) = 0;
// At ADDRESS, register REG has been saved at offset OFFSET from
// BASE_REGISTER.
virtual bool OffsetRule(uint64 address, int reg,
int base_register, long offset) = 0;
// At ADDRESS, the caller's value of register REG is the current
// value of BASE_REGISTER plus OFFSET. (This rule doesn't provide an
// address at which the register's value is saved.)
virtual bool ValOffsetRule(uint64 address, int reg,
int base_register, long offset) = 0;
// At ADDRESS, register REG has been saved in BASE_REGISTER. This differs
// from ValOffsetRule(ADDRESS, REG, BASE_REGISTER, 0), in that
// BASE_REGISTER is the "home" for REG's saved value: if you want to
// assign to a variable whose home is REG in the calling frame, you
// should put the value in BASE_REGISTER.
virtual bool RegisterRule(uint64 address, int reg, int base_register) = 0;
// At ADDRESS, the DWARF expression EXPRESSION yields the address at
// which REG was saved.
virtual bool ExpressionRule(uint64 address, int reg,
const string &expression) = 0;
// At ADDRESS, the DWARF expression EXPRESSION yields the caller's
// value for REG. (This rule doesn't provide an address at which the
// register's value is saved.)
virtual bool ValExpressionRule(uint64 address, int reg,
const string &expression) = 0;
// Indicate that the rules for the address range reported by the
// last call to Entry are complete. End should return true if
// everything is okay, or false if an error has occurred and parsing
// should stop.
virtual bool End() = 0;
};
// The CallFrameInfo class makes calls on an instance of this class to
// report errors or warn about problems in the data it is parsing. The
// default definitions of these methods print a message to stderr, but
// you can make a derived class that overrides them.
class CallFrameInfo::Reporter {
public:
// Create an error reporter which attributes troubles to the section
// named SECTION in FILENAME.
//
// Normally SECTION would be .debug_frame, but the Mac puts CFI data
// in a Mach-O section named __debug_frame. If we support
// Linux-style exception handling data, we could be reading an
// .eh_frame section.
Reporter(const string &filename,
const string &section = ".debug_frame")
: filename_(filename), section_(section) { }
virtual ~Reporter() { }
// The CFI entry at OFFSET ends too early to be well-formed. KIND
// indicates what kind of entry it is; KIND can be kUnknown if we
// haven't parsed enough of the entry to tell yet.
virtual void Incomplete(uint64 offset, CallFrameInfo::EntryKind kind);
// The FDE at OFFSET refers to the CIE at CIE_OFFSET, but the
// section is not that large.
virtual void CIEPointerOutOfRange(uint64 offset, uint64 cie_offset);
// The FDE at OFFSET refers to the CIE at CIE_OFFSET, but the entry
// there is not a CIE.
virtual void BadCIEId(uint64 offset, uint64 cie_offset);
// The FDE at OFFSET refers to a CIE with version number VERSION,
// which we don't recognize. We cannot parse DWARF CFI if it uses
// a version number we don't recognize.
virtual void UnrecognizedVersion(uint64 offset, int version);
// The FDE at OFFSET refers to a CIE with augmentation AUGMENTATION,
// which we don't recognize. We cannot parse DWARF CFI if it uses
// augmentations we don't recognize.
virtual void UnrecognizedAugmentation(uint64 offset,
const string &augmentation);
// The CIE at OFFSET contains a DW_CFA_restore instruction at
// INSN_OFFSET, which may not appear in a CIE.
virtual void RestoreInCIE(uint64 offset, uint64 insn_offset);
// The entry at OFFSET, of kind KIND, has an unrecognized
// instruction at INSN_OFFSET.
virtual void BadInstruction(uint64 offset, CallFrameInfo::EntryKind kind,
uint64 insn_offset);
// The instruction at INSN_OFFSET in the entry at OFFSET, of kind
// KIND, establishes a rule that cites the CFA, but we have not
// established a CFA rule yet.
virtual void NoCFARule(uint64 offset, CallFrameInfo::EntryKind kind,
uint64 insn_offset);
// The instruction at INSN_OFFSET in the entry at OFFSET, of kind
// KIND, is a DW_CFA_restore_state instruction, but the stack of
// saved states is empty.
virtual void EmptyStateStack(uint64 offset, CallFrameInfo::EntryKind kind,
uint64 insn_offset);
// The DW_CFA_remember_state instruction at INSN_OFFSET in the entry
// at OFFSET, of kind KIND, would restore a state that has no CFA
// rule, whereas the current state does have a CFA rule. This is
// bogus input, which the CallFrameInfo::Handler interface doesn't
// (and shouldn't) have any way to report.
virtual void ClearingCFARule(uint64 offset, CallFrameInfo::EntryKind kind,
uint64 insn_offset);
protected:
// The name of the file whose CFI we're reading.
string filename_;
// The name of the CFI section in that file.
string section_;
};
} // namespace dwarf2reader

File diff suppressed because it is too large Load Diff