michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: michael@0: // Copyright 2006, 2010 Google Inc. All Rights Reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: // Original author: Jim Blandy michael@0: michael@0: // This file is derived from the following files in michael@0: // toolkit/crashreporter/google-breakpad: michael@0: // src/common/dwarf/types.h michael@0: // src/common/dwarf/dwarf2enums.h michael@0: // src/common/dwarf/bytereader.h michael@0: // src/common/dwarf_cfi_to_module.h michael@0: // src/common/dwarf/dwarf2reader.h michael@0: michael@0: #ifndef LulDwarfExt_h michael@0: #define LulDwarfExt_h michael@0: michael@0: #include michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: michael@0: #include "LulDwarfSummariser.h" michael@0: michael@0: typedef signed char int8; michael@0: typedef short int16; michael@0: typedef int int32; michael@0: typedef long long int64; michael@0: michael@0: typedef unsigned char uint8; michael@0: typedef unsigned short uint16; michael@0: typedef unsigned int uint32; michael@0: typedef unsigned long long uint64; michael@0: michael@0: #ifdef __PTRDIFF_TYPE__ michael@0: typedef __PTRDIFF_TYPE__ intptr; michael@0: typedef unsigned __PTRDIFF_TYPE__ uintptr; michael@0: #else michael@0: #error "Can't find pointer-sized integral types." michael@0: #endif michael@0: michael@0: michael@0: namespace lul { michael@0: michael@0: // Exception handling frame description pointer formats, as described michael@0: // by the Linux Standard Base Core Specification 4.0, section 11.5, michael@0: // DWARF Extensions. michael@0: enum DwarfPointerEncoding michael@0: { michael@0: DW_EH_PE_absptr = 0x00, michael@0: DW_EH_PE_omit = 0xff, michael@0: DW_EH_PE_uleb128 = 0x01, michael@0: DW_EH_PE_udata2 = 0x02, michael@0: DW_EH_PE_udata4 = 0x03, michael@0: DW_EH_PE_udata8 = 0x04, michael@0: DW_EH_PE_sleb128 = 0x09, michael@0: DW_EH_PE_sdata2 = 0x0A, michael@0: DW_EH_PE_sdata4 = 0x0B, michael@0: DW_EH_PE_sdata8 = 0x0C, michael@0: DW_EH_PE_pcrel = 0x10, michael@0: DW_EH_PE_textrel = 0x20, michael@0: DW_EH_PE_datarel = 0x30, michael@0: DW_EH_PE_funcrel = 0x40, michael@0: DW_EH_PE_aligned = 0x50, michael@0: michael@0: // The GNU toolchain sources define this enum value as well, michael@0: // simply to help classify the lower nybble values into signed and michael@0: // unsigned groups. michael@0: DW_EH_PE_signed = 0x08, michael@0: michael@0: // This is not documented in LSB 4.0, but it is used in both the michael@0: // Linux and OS X toolchains. It can be added to any other michael@0: // encoding (except DW_EH_PE_aligned), and indicates that the michael@0: // encoded value represents the address at which the true address michael@0: // is stored, not the true address itself. michael@0: DW_EH_PE_indirect = 0x80 michael@0: }; michael@0: michael@0: michael@0: // We can't use the obvious name of LITTLE_ENDIAN and BIG_ENDIAN michael@0: // because it conflicts with a macro michael@0: enum Endianness { michael@0: ENDIANNESS_BIG, michael@0: ENDIANNESS_LITTLE michael@0: }; michael@0: michael@0: // A ByteReader knows how to read single- and multi-byte values of michael@0: // various endiannesses, sizes, and encodings, as used in DWARF michael@0: // debugging information and Linux C++ exception handling data. michael@0: class ByteReader { michael@0: public: michael@0: // Construct a ByteReader capable of reading one-, two-, four-, and michael@0: // eight-byte values according to ENDIANNESS, absolute machine-sized michael@0: // addresses, DWARF-style "initial length" values, signed and michael@0: // unsigned LEB128 numbers, and Linux C++ exception handling data's michael@0: // encoded pointers. michael@0: explicit ByteReader(enum Endianness endianness); michael@0: virtual ~ByteReader(); michael@0: michael@0: // Read a single byte from BUFFER and return it as an unsigned 8 bit michael@0: // number. michael@0: uint8 ReadOneByte(const char* buffer) const; michael@0: michael@0: // Read two bytes from BUFFER and return them as an unsigned 16 bit michael@0: // number, using this ByteReader's endianness. michael@0: uint16 ReadTwoBytes(const char* buffer) const; michael@0: michael@0: // Read four bytes from BUFFER and return them as an unsigned 32 bit michael@0: // number, using this ByteReader's endianness. This function returns michael@0: // a uint64 so that it is compatible with ReadAddress and michael@0: // ReadOffset. The number it returns will never be outside the range michael@0: // of an unsigned 32 bit integer. michael@0: uint64 ReadFourBytes(const char* buffer) const; michael@0: michael@0: // Read eight bytes from BUFFER and return them as an unsigned 64 michael@0: // bit number, using this ByteReader's endianness. michael@0: uint64 ReadEightBytes(const char* buffer) const; michael@0: michael@0: // Read an unsigned LEB128 (Little Endian Base 128) number from michael@0: // BUFFER and return it as an unsigned 64 bit integer. Set LEN to michael@0: // the number of bytes read. michael@0: // michael@0: // The unsigned LEB128 representation of an integer N is a variable michael@0: // number of bytes: michael@0: // michael@0: // - If N is between 0 and 0x7f, then its unsigned LEB128 michael@0: // representation is a single byte whose value is N. michael@0: // michael@0: // - Otherwise, its unsigned LEB128 representation is (N & 0x7f) | michael@0: // 0x80, followed by the unsigned LEB128 representation of N / michael@0: // 128, rounded towards negative infinity. michael@0: // michael@0: // In other words, we break VALUE into groups of seven bits, put michael@0: // them in little-endian order, and then write them as eight-bit michael@0: // bytes with the high bit on all but the last. michael@0: uint64 ReadUnsignedLEB128(const char* buffer, size_t* len) const; michael@0: michael@0: // Read a signed LEB128 number from BUFFER and return it as an michael@0: // signed 64 bit integer. Set LEN to the number of bytes read. michael@0: // michael@0: // The signed LEB128 representation of an integer N is a variable michael@0: // number of bytes: michael@0: // michael@0: // - If N is between -0x40 and 0x3f, then its signed LEB128 michael@0: // representation is a single byte whose value is N in two's michael@0: // complement. michael@0: // michael@0: // - Otherwise, its signed LEB128 representation is (N & 0x7f) | michael@0: // 0x80, followed by the signed LEB128 representation of N / 128, michael@0: // rounded towards negative infinity. michael@0: // michael@0: // In other words, we break VALUE into groups of seven bits, put michael@0: // them in little-endian order, and then write them as eight-bit michael@0: // bytes with the high bit on all but the last. michael@0: int64 ReadSignedLEB128(const char* buffer, size_t* len) const; michael@0: michael@0: // Indicate that addresses on this architecture are SIZE bytes long. SIZE michael@0: // must be either 4 or 8. (DWARF allows addresses to be any number of michael@0: // bytes in length from 1 to 255, but we only support 32- and 64-bit michael@0: // addresses at the moment.) You must call this before using the michael@0: // ReadAddress member function. michael@0: // michael@0: // For data in a .debug_info section, or something that .debug_info michael@0: // refers to like line number or macro data, the compilation unit michael@0: // header's address_size field indicates the address size to use. Call michael@0: // frame information doesn't indicate its address size (a shortcoming of michael@0: // the spec); you must supply the appropriate size based on the michael@0: // architecture of the target machine. michael@0: void SetAddressSize(uint8 size); michael@0: michael@0: // Return the current address size, in bytes. This is either 4, michael@0: // indicating 32-bit addresses, or 8, indicating 64-bit addresses. michael@0: uint8 AddressSize() const { return address_size_; } michael@0: michael@0: // Read an address from BUFFER and return it as an unsigned 64 bit michael@0: // integer, respecting this ByteReader's endianness and address size. You michael@0: // must call SetAddressSize before calling this function. michael@0: uint64 ReadAddress(const char* buffer) const; michael@0: michael@0: // DWARF actually defines two slightly different formats: 32-bit DWARF michael@0: // and 64-bit DWARF. This is *not* related to the size of registers or michael@0: // addresses on the target machine; it refers only to the size of section michael@0: // offsets and data lengths appearing in the DWARF data. One only needs michael@0: // 64-bit DWARF when the debugging data itself is larger than 4GiB. michael@0: // 32-bit DWARF can handle x86_64 or PPC64 code just fine, unless the michael@0: // debugging data itself is very large. michael@0: // michael@0: // DWARF information identifies itself as 32-bit or 64-bit DWARF: each michael@0: // compilation unit and call frame information entry begins with an michael@0: // "initial length" field, which, in addition to giving the length of the michael@0: // data, also indicates the size of section offsets and lengths appearing michael@0: // in that data. The ReadInitialLength member function, below, reads an michael@0: // initial length and sets the ByteReader's offset size as a side effect. michael@0: // Thus, in the normal process of reading DWARF data, the appropriate michael@0: // offset size is set automatically. So, you should only need to call michael@0: // SetOffsetSize if you are using the same ByteReader to jump from the michael@0: // midst of one block of DWARF data into another. michael@0: michael@0: // Read a DWARF "initial length" field from START, and return it as michael@0: // an unsigned 64 bit integer, respecting this ByteReader's michael@0: // endianness. Set *LEN to the length of the initial length in michael@0: // bytes, either four or twelve. As a side effect, set this michael@0: // ByteReader's offset size to either 4 (if we see a 32-bit DWARF michael@0: // initial length) or 8 (if we see a 64-bit DWARF initial length). michael@0: // michael@0: // A DWARF initial length is either: michael@0: // michael@0: // - a byte count stored as an unsigned 32-bit value less than michael@0: // 0xffffff00, indicating that the data whose length is being michael@0: // measured uses the 32-bit DWARF format, or michael@0: // michael@0: // - The 32-bit value 0xffffffff, followed by a 64-bit byte count, michael@0: // indicating that the data whose length is being measured uses michael@0: // the 64-bit DWARF format. michael@0: uint64 ReadInitialLength(const char* start, size_t* len); michael@0: michael@0: // Read an offset from BUFFER and return it as an unsigned 64 bit michael@0: // integer, respecting the ByteReader's endianness. In 32-bit DWARF, the michael@0: // offset is 4 bytes long; in 64-bit DWARF, the offset is eight bytes michael@0: // long. You must call ReadInitialLength or SetOffsetSize before calling michael@0: // this function; see the comments above for details. michael@0: uint64 ReadOffset(const char* buffer) const; michael@0: michael@0: // Return the current offset size, in bytes. michael@0: // A return value of 4 indicates that we are reading 32-bit DWARF. michael@0: // A return value of 8 indicates that we are reading 64-bit DWARF. michael@0: uint8 OffsetSize() const { return offset_size_; } michael@0: michael@0: // Indicate that section offsets and lengths are SIZE bytes long. SIZE michael@0: // must be either 4 (meaning 32-bit DWARF) or 8 (meaning 64-bit DWARF). michael@0: // Usually, you should not call this function yourself; instead, let a michael@0: // call to ReadInitialLength establish the data's offset size michael@0: // automatically. michael@0: void SetOffsetSize(uint8 size); michael@0: michael@0: // The Linux C++ ABI uses a variant of DWARF call frame information michael@0: // for exception handling. This data is included in the program's michael@0: // address space as the ".eh_frame" section, and intepreted at michael@0: // runtime to walk the stack, find exception handlers, and run michael@0: // cleanup code. The format is mostly the same as DWARF CFI, with michael@0: // some adjustments made to provide the additional michael@0: // exception-handling data, and to make the data easier to work with michael@0: // in memory --- for example, to allow it to be placed in read-only michael@0: // memory even when describing position-independent code. michael@0: // michael@0: // In particular, exception handling data can select a number of michael@0: // different encodings for pointers that appear in the data, as michael@0: // described by the DwarfPointerEncoding enum. There are actually michael@0: // four axes(!) to the encoding: michael@0: // michael@0: // - The pointer size: pointers can be 2, 4, or 8 bytes long, or use michael@0: // the DWARF LEB128 encoding. michael@0: // michael@0: // - The pointer's signedness: pointers can be signed or unsigned. michael@0: // michael@0: // - The pointer's base address: the data stored in the exception michael@0: // handling data can be the actual address (that is, an absolute michael@0: // pointer), or relative to one of a number of different base michael@0: // addreses --- including that of the encoded pointer itself, for michael@0: // a form of "pc-relative" addressing. michael@0: // michael@0: // - The pointer may be indirect: it may be the address where the michael@0: // true pointer is stored. (This is used to refer to things via michael@0: // global offset table entries, program linkage table entries, or michael@0: // other tricks used in position-independent code.) michael@0: // michael@0: // There are also two options that fall outside that matrix michael@0: // altogether: the pointer may be omitted, or it may have padding to michael@0: // align it on an appropriate address boundary. (That last option michael@0: // may seem like it should be just another axis, but it is not.) michael@0: michael@0: // Indicate that the exception handling data is loaded starting at michael@0: // SECTION_BASE, and that the start of its buffer in our own memory michael@0: // is BUFFER_BASE. This allows us to find the address that a given michael@0: // byte in our buffer would have when loaded into the program the michael@0: // data describes. We need this to resolve DW_EH_PE_pcrel pointers. michael@0: void SetCFIDataBase(uint64 section_base, const char *buffer_base); michael@0: michael@0: // Indicate that the base address of the program's ".text" section michael@0: // is TEXT_BASE. We need this to resolve DW_EH_PE_textrel pointers. michael@0: void SetTextBase(uint64 text_base); michael@0: michael@0: // Indicate that the base address for DW_EH_PE_datarel pointers is michael@0: // DATA_BASE. The proper value depends on the ABI; it is usually the michael@0: // address of the global offset table, held in a designated register in michael@0: // position-independent code. You will need to look at the startup code michael@0: // for the target system to be sure. I tried; my eyes bled. michael@0: void SetDataBase(uint64 data_base); michael@0: michael@0: // Indicate that the base address for the FDE we are processing is michael@0: // FUNCTION_BASE. This is the start address of DW_EH_PE_funcrel michael@0: // pointers. (This encoding does not seem to be used by the GNU michael@0: // toolchain.) michael@0: void SetFunctionBase(uint64 function_base); michael@0: michael@0: // Indicate that we are no longer processing any FDE, so any use of michael@0: // a DW_EH_PE_funcrel encoding is an error. michael@0: void ClearFunctionBase(); michael@0: michael@0: // Return true if ENCODING is a valid pointer encoding. michael@0: bool ValidEncoding(DwarfPointerEncoding encoding) const; michael@0: michael@0: // Return true if we have all the information we need to read a michael@0: // pointer that uses ENCODING. This checks that the appropriate michael@0: // SetFooBase function for ENCODING has been called. michael@0: bool UsableEncoding(DwarfPointerEncoding encoding) const; michael@0: michael@0: // Read an encoded pointer from BUFFER using ENCODING; return the michael@0: // absolute address it represents, and set *LEN to the pointer's michael@0: // length in bytes, including any padding for aligned pointers. michael@0: // michael@0: // This function calls 'abort' if ENCODING is invalid or refers to a michael@0: // base address this reader hasn't been given, so you should check michael@0: // with ValidEncoding and UsableEncoding first if you would rather michael@0: // die in a more helpful way. michael@0: uint64 ReadEncodedPointer(const char *buffer, DwarfPointerEncoding encoding, michael@0: size_t *len) const; michael@0: michael@0: private: michael@0: michael@0: // Function pointer type for our address and offset readers. michael@0: typedef uint64 (ByteReader::*AddressReader)(const char*) const; michael@0: michael@0: // Read an offset from BUFFER and return it as an unsigned 64 bit michael@0: // integer. DWARF2/3 define offsets as either 4 or 8 bytes, michael@0: // generally depending on the amount of DWARF2/3 info present. michael@0: // This function pointer gets set by SetOffsetSize. michael@0: AddressReader offset_reader_; michael@0: michael@0: // Read an address from BUFFER and return it as an unsigned 64 bit michael@0: // integer. DWARF2/3 allow addresses to be any size from 0-255 michael@0: // bytes currently. Internally we support 4 and 8 byte addresses, michael@0: // and will CHECK on anything else. michael@0: // This function pointer gets set by SetAddressSize. michael@0: AddressReader address_reader_; michael@0: michael@0: Endianness endian_; michael@0: uint8 address_size_; michael@0: uint8 offset_size_; michael@0: michael@0: // Base addresses for Linux C++ exception handling data's encoded pointers. michael@0: bool have_section_base_, have_text_base_, have_data_base_; michael@0: bool have_function_base_; michael@0: uint64 section_base_; michael@0: uint64 text_base_, data_base_, function_base_; michael@0: const char *buffer_base_; michael@0: }; michael@0: michael@0: michael@0: inline uint8 ByteReader::ReadOneByte(const char* buffer) const { michael@0: return buffer[0]; michael@0: } michael@0: michael@0: inline uint16 ByteReader::ReadTwoBytes(const char* signed_buffer) const { michael@0: const unsigned char *buffer michael@0: = reinterpret_cast(signed_buffer); michael@0: const uint16 buffer0 = buffer[0]; michael@0: const uint16 buffer1 = buffer[1]; michael@0: if (endian_ == ENDIANNESS_LITTLE) { michael@0: return buffer0 | buffer1 << 8; michael@0: } else { michael@0: return buffer1 | buffer0 << 8; michael@0: } michael@0: } michael@0: michael@0: inline uint64 ByteReader::ReadFourBytes(const char* signed_buffer) const { michael@0: const unsigned char *buffer michael@0: = reinterpret_cast(signed_buffer); michael@0: const uint32 buffer0 = buffer[0]; michael@0: const uint32 buffer1 = buffer[1]; michael@0: const uint32 buffer2 = buffer[2]; michael@0: const uint32 buffer3 = buffer[3]; michael@0: if (endian_ == ENDIANNESS_LITTLE) { michael@0: return buffer0 | buffer1 << 8 | buffer2 << 16 | buffer3 << 24; michael@0: } else { michael@0: return buffer3 | buffer2 << 8 | buffer1 << 16 | buffer0 << 24; michael@0: } michael@0: } michael@0: michael@0: inline uint64 ByteReader::ReadEightBytes(const char* signed_buffer) const { michael@0: const unsigned char *buffer michael@0: = reinterpret_cast(signed_buffer); michael@0: const uint64 buffer0 = buffer[0]; michael@0: const uint64 buffer1 = buffer[1]; michael@0: const uint64 buffer2 = buffer[2]; michael@0: const uint64 buffer3 = buffer[3]; michael@0: const uint64 buffer4 = buffer[4]; michael@0: const uint64 buffer5 = buffer[5]; michael@0: const uint64 buffer6 = buffer[6]; michael@0: const uint64 buffer7 = buffer[7]; michael@0: if (endian_ == ENDIANNESS_LITTLE) { michael@0: return buffer0 | buffer1 << 8 | buffer2 << 16 | buffer3 << 24 | michael@0: buffer4 << 32 | buffer5 << 40 | buffer6 << 48 | buffer7 << 56; michael@0: } else { michael@0: return buffer7 | buffer6 << 8 | buffer5 << 16 | buffer4 << 24 | michael@0: buffer3 << 32 | buffer2 << 40 | buffer1 << 48 | buffer0 << 56; michael@0: } michael@0: } michael@0: michael@0: // Read an unsigned LEB128 number. Each byte contains 7 bits of michael@0: // information, plus one bit saying whether the number continues or michael@0: // not. michael@0: michael@0: inline uint64 ByteReader::ReadUnsignedLEB128(const char* buffer, michael@0: size_t* len) const { michael@0: uint64 result = 0; michael@0: size_t num_read = 0; michael@0: unsigned int shift = 0; michael@0: unsigned char byte; michael@0: michael@0: do { michael@0: byte = *buffer++; michael@0: num_read++; michael@0: michael@0: result |= (static_cast(byte & 0x7f)) << shift; michael@0: michael@0: shift += 7; michael@0: michael@0: } while (byte & 0x80); michael@0: michael@0: *len = num_read; michael@0: michael@0: return result; michael@0: } michael@0: michael@0: // Read a signed LEB128 number. These are like regular LEB128 michael@0: // numbers, except the last byte may have a sign bit set. michael@0: michael@0: inline int64 ByteReader::ReadSignedLEB128(const char* buffer, michael@0: size_t* len) const { michael@0: int64 result = 0; michael@0: unsigned int shift = 0; michael@0: size_t num_read = 0; michael@0: unsigned char byte; michael@0: michael@0: do { michael@0: byte = *buffer++; michael@0: num_read++; michael@0: result |= (static_cast(byte & 0x7f) << shift); michael@0: shift += 7; michael@0: } while (byte & 0x80); michael@0: michael@0: if ((shift < 8 * sizeof (result)) && (byte & 0x40)) michael@0: result |= -((static_cast(1)) << shift); michael@0: *len = num_read; michael@0: return result; michael@0: } michael@0: michael@0: inline uint64 ByteReader::ReadOffset(const char* buffer) const { michael@0: MOZ_ASSERT(this->offset_reader_); michael@0: return (this->*offset_reader_)(buffer); michael@0: } michael@0: michael@0: inline uint64 ByteReader::ReadAddress(const char* buffer) const { michael@0: MOZ_ASSERT(this->address_reader_); michael@0: return (this->*address_reader_)(buffer); michael@0: } michael@0: michael@0: inline void ByteReader::SetCFIDataBase(uint64 section_base, michael@0: const char *buffer_base) { michael@0: section_base_ = section_base; michael@0: buffer_base_ = buffer_base; michael@0: have_section_base_ = true; michael@0: } michael@0: michael@0: inline void ByteReader::SetTextBase(uint64 text_base) { michael@0: text_base_ = text_base; michael@0: have_text_base_ = true; michael@0: } michael@0: michael@0: inline void ByteReader::SetDataBase(uint64 data_base) { michael@0: data_base_ = data_base; michael@0: have_data_base_ = true; michael@0: } michael@0: michael@0: inline void ByteReader::SetFunctionBase(uint64 function_base) { michael@0: function_base_ = function_base; michael@0: have_function_base_ = true; michael@0: } michael@0: michael@0: inline void ByteReader::ClearFunctionBase() { michael@0: have_function_base_ = false; michael@0: } michael@0: michael@0: michael@0: // (derived from) michael@0: // dwarf_cfi_to_module.h: Define the DwarfCFIToModule class, which michael@0: // accepts parsed DWARF call frame info and adds it to a Summariser object. michael@0: michael@0: // This class is a reader for DWARF's Call Frame Information. CFI michael@0: // describes how to unwind stack frames --- even for functions that do michael@0: // not follow fixed conventions for saving registers, whose frame size michael@0: // varies as they execute, etc. michael@0: // michael@0: // CFI describes, at each machine instruction, how to compute the michael@0: // stack frame's base address, how to find the return address, and michael@0: // where to find the saved values of the caller's registers (if the michael@0: // callee has stashed them somewhere to free up the registers for its michael@0: // own use). michael@0: // michael@0: // For example, suppose we have a function whose machine code looks michael@0: // like this (imagine an assembly language that looks like C, for a michael@0: // machine with 32-bit registers, and a stack that grows towards lower michael@0: // addresses): michael@0: // michael@0: // func: ; entry point; return address at sp michael@0: // func+0: sp = sp - 16 ; allocate space for stack frame michael@0: // func+1: sp[12] = r0 ; save r0 at sp+12 michael@0: // ... ; other code, not frame-related michael@0: // func+10: sp -= 4; *sp = x ; push some x on the stack michael@0: // ... ; other code, not frame-related michael@0: // func+20: r0 = sp[16] ; restore saved r0 michael@0: // func+21: sp += 20 ; pop whole stack frame michael@0: // func+22: pc = *sp; sp += 4 ; pop return address and jump to it michael@0: // michael@0: // DWARF CFI is (a very compressed representation of) a table with a michael@0: // row for each machine instruction address and a column for each michael@0: // register showing how to restore it, if possible. michael@0: // michael@0: // A special column named "CFA", for "Canonical Frame Address", tells how michael@0: // to compute the base address of the frame; registers' entries may michael@0: // refer to the CFA in describing where the registers are saved. michael@0: // michael@0: // Another special column, named "RA", represents the return address. michael@0: // michael@0: // For example, here is a complete (uncompressed) table describing the michael@0: // function above: michael@0: // michael@0: // insn cfa r0 r1 ... ra michael@0: // ======================================= michael@0: // func+0: sp cfa[0] michael@0: // func+1: sp+16 cfa[0] michael@0: // func+2: sp+16 cfa[-4] cfa[0] michael@0: // func+11: sp+20 cfa[-4] cfa[0] michael@0: // func+21: sp+20 cfa[0] michael@0: // func+22: sp cfa[0] michael@0: // michael@0: // Some things to note here: michael@0: // michael@0: // - Each row describes the state of affairs *before* executing the michael@0: // instruction at the given address. Thus, the row for func+0 michael@0: // describes the state before we allocate the stack frame. In the michael@0: // next row, the formula for computing the CFA has changed, michael@0: // reflecting that allocation. michael@0: // michael@0: // - The other entries are written in terms of the CFA; this allows michael@0: // them to remain unchanged as the stack pointer gets bumped around. michael@0: // For example, the rule for recovering the return address (the "ra" michael@0: // column) remains unchanged throughout the function, even as the michael@0: // stack pointer takes on three different offsets from the return michael@0: // address. michael@0: // michael@0: // - Although we haven't shown it, most calling conventions designate michael@0: // "callee-saves" and "caller-saves" registers. The callee must michael@0: // preserve the values of callee-saves registers; if it uses them, michael@0: // it must save their original values somewhere, and restore them michael@0: // before it returns. In contrast, the callee is free to trash michael@0: // caller-saves registers; if the callee uses these, it will michael@0: // probably not bother to save them anywhere, and the CFI will michael@0: // probably mark their values as "unrecoverable". michael@0: // michael@0: // (However, since the caller cannot assume the callee was going to michael@0: // save them, caller-saves registers are probably dead in the caller michael@0: // anyway, so compilers usually don't generate CFA for caller-saves michael@0: // registers.) michael@0: // michael@0: // - Exactly where the CFA points is a matter of convention that michael@0: // depends on the architecture and ABI in use. In the example, the michael@0: // CFA is the value the stack pointer had upon entry to the michael@0: // function, pointing at the saved return address. But on the x86, michael@0: // the call frame information generated by GCC follows the michael@0: // convention that the CFA is the address *after* the saved return michael@0: // address. michael@0: // michael@0: // But by definition, the CFA remains constant throughout the michael@0: // lifetime of the frame. This makes it a useful value for other michael@0: // columns to refer to. It is also gives debuggers a useful handle michael@0: // for identifying a frame. michael@0: // michael@0: // If you look at the table above, you'll notice that a given entry is michael@0: // often the same as the one immediately above it: most instructions michael@0: // change only one or two aspects of the stack frame, if they affect michael@0: // it at all. The DWARF format takes advantage of this fact, and michael@0: // reduces the size of the data by mentioning only the addresses and michael@0: // columns at which changes take place. So for the above, DWARF CFI michael@0: // data would only actually mention the following: michael@0: // michael@0: // insn cfa r0 r1 ... ra michael@0: // ======================================= michael@0: // func+0: sp cfa[0] michael@0: // func+1: sp+16 michael@0: // func+2: cfa[-4] michael@0: // func+11: sp+20 michael@0: // func+21: r0 michael@0: // func+22: sp michael@0: // michael@0: // In fact, this is the way the parser reports CFI to the consumer: as michael@0: // a series of statements of the form, "At address X, column Y changed michael@0: // to Z," and related conventions for describing the initial state. michael@0: // michael@0: // Naturally, it would be impractical to have to scan the entire michael@0: // program's CFI, noting changes as we go, just to recover the michael@0: // unwinding rules in effect at one particular instruction. To avoid michael@0: // this, CFI data is grouped into "entries", each of which covers a michael@0: // specified range of addresses and begins with a complete statement michael@0: // of the rules for all recoverable registers at that starting michael@0: // address. Each entry typically covers a single function. michael@0: // michael@0: // Thus, to compute the contents of a given row of the table --- that michael@0: // is, rules for recovering the CFA, RA, and registers at a given michael@0: // instruction --- the consumer should find the entry that covers that michael@0: // instruction's address, start with the initial state supplied at the michael@0: // beginning of the entry, and work forward until it has processed all michael@0: // the changes up to and including those for the present instruction. michael@0: // michael@0: // There are seven kinds of rules that can appear in an entry of the michael@0: // table: michael@0: // michael@0: // - "undefined": The given register is not preserved by the callee; michael@0: // its value cannot be recovered. michael@0: // michael@0: // - "same value": This register has the same value it did in the callee. michael@0: // michael@0: // - offset(N): The register is saved at offset N from the CFA. michael@0: // michael@0: // - val_offset(N): The value the register had in the caller is the michael@0: // CFA plus offset N. (This is usually only useful for describing michael@0: // the stack pointer.) michael@0: // michael@0: // - register(R): The register's value was saved in another register R. michael@0: // michael@0: // - expression(E): Evaluating the DWARF expression E using the michael@0: // current frame's registers' values yields the address at which the michael@0: // register was saved. michael@0: // michael@0: // - val_expression(E): Evaluating the DWARF expression E using the michael@0: // current frame's registers' values yields the value the register michael@0: // had in the caller. michael@0: michael@0: class CallFrameInfo { michael@0: public: michael@0: // The different kinds of entries one finds in CFI. Used internally, michael@0: // and for error reporting. michael@0: enum EntryKind { kUnknown, kCIE, kFDE, kTerminator }; michael@0: michael@0: // The handler class to which the parser hands the parsed call frame michael@0: // information. Defined below. michael@0: class Handler; michael@0: michael@0: // A reporter class, which CallFrameInfo uses to report errors michael@0: // encountered while parsing call frame information. Defined below. michael@0: class Reporter; michael@0: michael@0: // Create a DWARF CFI parser. BUFFER points to the contents of the michael@0: // .debug_frame section to parse; BUFFER_LENGTH is its length in bytes. michael@0: // REPORTER is an error reporter the parser should use to report michael@0: // problems. READER is a ByteReader instance that has the endianness and michael@0: // address size set properly. Report the data we find to HANDLER. michael@0: // michael@0: // This class can also parse Linux C++ exception handling data, as found michael@0: // in '.eh_frame' sections. This data is a variant of DWARF CFI that is michael@0: // placed in loadable segments so that it is present in the program's michael@0: // address space, and is interpreted by the C++ runtime to search the michael@0: // call stack for a handler interested in the exception being thrown, michael@0: // actually pop the frames, and find cleanup code to run. michael@0: // michael@0: // There are two differences between the call frame information described michael@0: // in the DWARF standard and the exception handling data Linux places in michael@0: // the .eh_frame section: michael@0: // michael@0: // - Exception handling data uses uses a different format for call frame michael@0: // information entry headers. The distinguished CIE id, the way FDEs michael@0: // refer to their CIEs, and the way the end of the series of entries is michael@0: // determined are all slightly different. michael@0: // michael@0: // If the constructor's EH_FRAME argument is true, then the michael@0: // CallFrameInfo parses the entry headers as Linux C++ exception michael@0: // handling data. If EH_FRAME is false or omitted, the CallFrameInfo michael@0: // parses standard DWARF call frame information. michael@0: // michael@0: // - Linux C++ exception handling data uses CIE augmentation strings michael@0: // beginning with 'z' to specify the presence of additional data after michael@0: // the CIE and FDE headers and special encodings used for addresses in michael@0: // frame description entries. michael@0: // michael@0: // CallFrameInfo can handle 'z' augmentations in either DWARF CFI or michael@0: // exception handling data if you have supplied READER with the base michael@0: // addresses needed to interpret the pointer encodings that 'z' michael@0: // augmentations can specify. See the ByteReader interface for details michael@0: // about the base addresses. See the CallFrameInfo::Handler interface michael@0: // for details about the additional information one might find in michael@0: // 'z'-augmented data. michael@0: // michael@0: // Thus: michael@0: // michael@0: // - If you are parsing standard DWARF CFI, as found in a .debug_frame michael@0: // section, you should pass false for the EH_FRAME argument, or omit michael@0: // it, and you need not worry about providing READER with the michael@0: // additional base addresses. michael@0: // michael@0: // - If you want to parse Linux C++ exception handling data from a michael@0: // .eh_frame section, you should pass EH_FRAME as true, and call michael@0: // READER's Set*Base member functions before calling our Start method. michael@0: // michael@0: // - If you want to parse DWARF CFI that uses the 'z' augmentations michael@0: // (although I don't think any toolchain ever emits such data), you michael@0: // could pass false for EH_FRAME, but call READER's Set*Base members. michael@0: // michael@0: // The extensions the Linux C++ ABI makes to DWARF for exception michael@0: // handling are described here, rather poorly: michael@0: // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html michael@0: // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html michael@0: // michael@0: // The mechanics of C++ exception handling, personality routines, michael@0: // and language-specific data areas are described here, rather nicely: michael@0: // http://www.codesourcery.com/public/cxx-abi/abi-eh.html michael@0: michael@0: CallFrameInfo(const char *buffer, size_t buffer_length, michael@0: ByteReader *reader, Handler *handler, Reporter *reporter, michael@0: bool eh_frame = false) michael@0: : buffer_(buffer), buffer_length_(buffer_length), michael@0: reader_(reader), handler_(handler), reporter_(reporter), michael@0: eh_frame_(eh_frame) { } michael@0: michael@0: ~CallFrameInfo() { } michael@0: michael@0: // Parse the entries in BUFFER, reporting what we find to HANDLER. michael@0: // Return true if we reach the end of the section successfully, or michael@0: // false if we encounter an error. michael@0: bool Start(); michael@0: michael@0: // Return the textual name of KIND. For error reporting. michael@0: static const char *KindName(EntryKind kind); michael@0: michael@0: private: michael@0: michael@0: struct CIE; michael@0: michael@0: // A CFI entry, either an FDE or a CIE. michael@0: struct Entry { michael@0: // The starting offset of the entry in the section, for error michael@0: // reporting. michael@0: size_t offset; michael@0: michael@0: // The start of this entry in the buffer. michael@0: const char *start; michael@0: michael@0: // Which kind of entry this is. michael@0: // michael@0: // We want to be able to use this for error reporting even while we're michael@0: // in the midst of parsing. Error reporting code may assume that kind, michael@0: // offset, and start fields are valid, although kind may be kUnknown. michael@0: EntryKind kind; michael@0: michael@0: // The end of this entry's common prologue (initial length and id), and michael@0: // the start of this entry's kind-specific fields. michael@0: const char *fields; michael@0: michael@0: // The start of this entry's instructions. michael@0: const char *instructions; michael@0: michael@0: // The address past the entry's last byte in the buffer. (Note that michael@0: // since offset points to the entry's initial length field, and the michael@0: // length field is the number of bytes after that field, this is not michael@0: // simply buffer_ + offset + length.) michael@0: const char *end; michael@0: michael@0: // For both DWARF CFI and .eh_frame sections, this is the CIE id in a michael@0: // CIE, and the offset of the associated CIE in an FDE. michael@0: uint64 id; michael@0: michael@0: // The CIE that applies to this entry, if we've parsed it. If this is a michael@0: // CIE, then this field points to this structure. michael@0: CIE *cie; michael@0: }; michael@0: michael@0: // A common information entry (CIE). michael@0: struct CIE: public Entry { michael@0: uint8 version; // CFI data version number michael@0: std::string augmentation; // vendor format extension markers michael@0: uint64 code_alignment_factor; // scale for code address adjustments michael@0: int data_alignment_factor; // scale for stack pointer adjustments michael@0: unsigned return_address_register; // which register holds the return addr michael@0: michael@0: // True if this CIE includes Linux C++ ABI 'z' augmentation data. michael@0: bool has_z_augmentation; michael@0: michael@0: // Parsed 'z' augmentation data. These are meaningful only if michael@0: // has_z_augmentation is true. michael@0: bool has_z_lsda; // The 'z' augmentation included 'L'. michael@0: bool has_z_personality; // The 'z' augmentation included 'P'. michael@0: bool has_z_signal_frame; // The 'z' augmentation included 'S'. michael@0: michael@0: // If has_z_lsda is true, this is the encoding to be used for language- michael@0: // specific data area pointers in FDEs. michael@0: DwarfPointerEncoding lsda_encoding; michael@0: michael@0: // If has_z_personality is true, this is the encoding used for the michael@0: // personality routine pointer in the augmentation data. michael@0: DwarfPointerEncoding personality_encoding; michael@0: michael@0: // If has_z_personality is true, this is the address of the personality michael@0: // routine --- or, if personality_encoding & DW_EH_PE_indirect, the michael@0: // address where the personality routine's address is stored. michael@0: uint64 personality_address; michael@0: michael@0: // This is the encoding used for addresses in the FDE header and michael@0: // in DW_CFA_set_loc instructions. This is always valid, whether michael@0: // or not we saw a 'z' augmentation string; its default value is michael@0: // DW_EH_PE_absptr, which is what normal DWARF CFI uses. michael@0: DwarfPointerEncoding pointer_encoding; michael@0: }; michael@0: michael@0: // A frame description entry (FDE). michael@0: struct FDE: public Entry { michael@0: uint64 address; // start address of described code michael@0: uint64 size; // size of described code, in bytes michael@0: michael@0: // If cie->has_z_lsda is true, then this is the language-specific data michael@0: // area's address --- or its address's address, if cie->lsda_encoding michael@0: // has the DW_EH_PE_indirect bit set. michael@0: uint64 lsda_address; michael@0: }; michael@0: michael@0: // Internal use. michael@0: class Rule; michael@0: class UndefinedRule; michael@0: class SameValueRule; michael@0: class OffsetRule; michael@0: class ValOffsetRule; michael@0: class RegisterRule; michael@0: class ExpressionRule; michael@0: class ValExpressionRule; michael@0: class RuleMap; michael@0: class State; michael@0: michael@0: // Parse the initial length and id of a CFI entry, either a CIE, an FDE, michael@0: // or a .eh_frame end-of-data mark. CURSOR points to the beginning of the michael@0: // data to parse. On success, populate ENTRY as appropriate, and return michael@0: // true. On failure, report the problem, and return false. Even if we michael@0: // return false, set ENTRY->end to the first byte after the entry if we michael@0: // were able to figure that out, or NULL if we weren't. michael@0: bool ReadEntryPrologue(const char *cursor, Entry *entry); michael@0: michael@0: // Parse the fields of a CIE after the entry prologue, including any 'z' michael@0: // augmentation data. Assume that the 'Entry' fields of CIE are michael@0: // populated; use CIE->fields and CIE->end as the start and limit for michael@0: // parsing. On success, populate the rest of *CIE, and return true; on michael@0: // failure, report the problem and return false. michael@0: bool ReadCIEFields(CIE *cie); michael@0: michael@0: // Parse the fields of an FDE after the entry prologue, including any 'z' michael@0: // augmentation data. Assume that the 'Entry' fields of *FDE are michael@0: // initialized; use FDE->fields and FDE->end as the start and limit for michael@0: // parsing. Assume that FDE->cie is fully initialized. On success, michael@0: // populate the rest of *FDE, and return true; on failure, report the michael@0: // problem and return false. michael@0: bool ReadFDEFields(FDE *fde); michael@0: michael@0: // Report that ENTRY is incomplete, and return false. This is just a michael@0: // trivial wrapper for invoking reporter_->Incomplete; it provides a michael@0: // little brevity. michael@0: bool ReportIncomplete(Entry *entry); michael@0: michael@0: // Return true if ENCODING has the DW_EH_PE_indirect bit set. michael@0: static bool IsIndirectEncoding(DwarfPointerEncoding encoding) { michael@0: return encoding & DW_EH_PE_indirect; michael@0: } michael@0: michael@0: // The contents of the DWARF .debug_info section we're parsing. michael@0: const char *buffer_; michael@0: size_t buffer_length_; michael@0: michael@0: // For reading multi-byte values with the appropriate endianness. michael@0: ByteReader *reader_; michael@0: michael@0: // The handler to which we should report the data we find. michael@0: Handler *handler_; michael@0: michael@0: // For reporting problems in the info we're parsing. michael@0: Reporter *reporter_; michael@0: michael@0: // True if we are processing .eh_frame-format data. michael@0: bool eh_frame_; michael@0: }; michael@0: michael@0: michael@0: // The handler class for CallFrameInfo. The a CFI parser calls the michael@0: // member functions of a handler object to report the data it finds. michael@0: class CallFrameInfo::Handler { michael@0: public: michael@0: // The pseudo-register number for the canonical frame address. michael@0: enum { kCFARegister = DW_REG_CFA }; michael@0: michael@0: Handler() { } michael@0: virtual ~Handler() { } michael@0: michael@0: // The parser has found CFI for the machine code at ADDRESS, michael@0: // extending for LENGTH bytes. OFFSET is the offset of the frame michael@0: // description entry in the section, for use in error messages. michael@0: // VERSION is the version number of the CFI format. AUGMENTATION is michael@0: // a string describing any producer-specific extensions present in michael@0: // the data. RETURN_ADDRESS is the number of the register that holds michael@0: // the address to which the function should return. michael@0: // michael@0: // Entry should return true to process this CFI, or false to skip to michael@0: // the next entry. michael@0: // michael@0: // The parser invokes Entry for each Frame Description Entry (FDE) michael@0: // it finds. The parser doesn't report Common Information Entries michael@0: // to the handler explicitly; instead, if the handler elects to michael@0: // process a given FDE, the parser reiterates the appropriate CIE's michael@0: // contents at the beginning of the FDE's rules. michael@0: virtual bool Entry(size_t offset, uint64 address, uint64 length, michael@0: uint8 version, const std::string &augmentation, michael@0: unsigned return_address) = 0; michael@0: michael@0: // When the Entry function returns true, the parser calls these michael@0: // handler functions repeatedly to describe the rules for recovering michael@0: // registers at each instruction in the given range of machine code. michael@0: // Immediately after a call to Entry, the handler should assume that michael@0: // the rule for each callee-saves register is "unchanged" --- that michael@0: // is, that the register still has the value it had in the caller. michael@0: // michael@0: // If a *Rule function returns true, we continue processing this entry's michael@0: // instructions. If a *Rule function returns false, we stop evaluating michael@0: // instructions, and skip to the next entry. Either way, we call End michael@0: // before going on to the next entry. michael@0: // michael@0: // In all of these functions, if the REG parameter is kCFARegister, then michael@0: // the rule describes how to find the canonical frame address. michael@0: // kCFARegister may be passed as a BASE_REGISTER argument, meaning that michael@0: // the canonical frame address should be used as the base address for the michael@0: // computation. All other REG values will be positive. michael@0: michael@0: // At ADDRESS, register REG's value is not recoverable. michael@0: virtual bool UndefinedRule(uint64 address, int reg) = 0; michael@0: michael@0: // At ADDRESS, register REG's value is the same as that it had in michael@0: // the caller. michael@0: virtual bool SameValueRule(uint64 address, int reg) = 0; michael@0: michael@0: // At ADDRESS, register REG has been saved at offset OFFSET from michael@0: // BASE_REGISTER. michael@0: virtual bool OffsetRule(uint64 address, int reg, michael@0: int base_register, long offset) = 0; michael@0: michael@0: // At ADDRESS, the caller's value of register REG is the current michael@0: // value of BASE_REGISTER plus OFFSET. (This rule doesn't provide an michael@0: // address at which the register's value is saved.) michael@0: virtual bool ValOffsetRule(uint64 address, int reg, michael@0: int base_register, long offset) = 0; michael@0: michael@0: // At ADDRESS, register REG has been saved in BASE_REGISTER. This differs michael@0: // from ValOffsetRule(ADDRESS, REG, BASE_REGISTER, 0), in that michael@0: // BASE_REGISTER is the "home" for REG's saved value: if you want to michael@0: // assign to a variable whose home is REG in the calling frame, you michael@0: // should put the value in BASE_REGISTER. michael@0: virtual bool RegisterRule(uint64 address, int reg, int base_register) = 0; michael@0: michael@0: // At ADDRESS, the DWARF expression EXPRESSION yields the address at michael@0: // which REG was saved. michael@0: virtual bool ExpressionRule(uint64 address, int reg, michael@0: const std::string &expression) = 0; michael@0: michael@0: // At ADDRESS, the DWARF expression EXPRESSION yields the caller's michael@0: // value for REG. (This rule doesn't provide an address at which the michael@0: // register's value is saved.) michael@0: virtual bool ValExpressionRule(uint64 address, int reg, michael@0: const std::string &expression) = 0; michael@0: michael@0: // Indicate that the rules for the address range reported by the michael@0: // last call to Entry are complete. End should return true if michael@0: // everything is okay, or false if an error has occurred and parsing michael@0: // should stop. michael@0: virtual bool End() = 0; michael@0: michael@0: // Handler functions for Linux C++ exception handling data. These are michael@0: // only called if the data includes 'z' augmentation strings. michael@0: michael@0: // The Linux C++ ABI uses an extension of the DWARF CFI format to michael@0: // walk the stack to propagate exceptions from the throw to the michael@0: // appropriate catch, and do the appropriate cleanups along the way. michael@0: // CFI entries used for exception handling have two additional data michael@0: // associated with them: michael@0: // michael@0: // - The "language-specific data area" describes which exception michael@0: // types the function has 'catch' clauses for, and indicates how michael@0: // to go about re-entering the function at the appropriate catch michael@0: // clause. If the exception is not caught, it describes the michael@0: // destructors that must run before the frame is popped. michael@0: // michael@0: // - The "personality routine" is responsible for interpreting the michael@0: // language-specific data area's contents, and deciding whether michael@0: // the exception should continue to propagate down the stack, michael@0: // perhaps after doing some cleanup for this frame, or whether the michael@0: // exception will be caught here. michael@0: // michael@0: // In principle, the language-specific data area is opaque to michael@0: // everybody but the personality routine. In practice, these values michael@0: // may be useful or interesting to readers with extra context, and michael@0: // we have to at least skip them anyway, so we might as well report michael@0: // them to the handler. michael@0: michael@0: // This entry's exception handling personality routine's address is michael@0: // ADDRESS. If INDIRECT is true, then ADDRESS is the address at michael@0: // which the routine's address is stored. The default definition for michael@0: // this handler function simply returns true, allowing parsing of michael@0: // the entry to continue. michael@0: virtual bool PersonalityRoutine(uint64 address, bool indirect) { michael@0: return true; michael@0: } michael@0: michael@0: // This entry's language-specific data area (LSDA) is located at michael@0: // ADDRESS. If INDIRECT is true, then ADDRESS is the address at michael@0: // which the area's address is stored. The default definition for michael@0: // this handler function simply returns true, allowing parsing of michael@0: // the entry to continue. michael@0: virtual bool LanguageSpecificDataArea(uint64 address, bool indirect) { michael@0: return true; michael@0: } michael@0: michael@0: // This entry describes a signal trampoline --- this frame is the michael@0: // caller of a signal handler. The default definition for this michael@0: // handler function simply returns true, allowing parsing of the michael@0: // entry to continue. michael@0: // michael@0: // The best description of the rationale for and meaning of signal michael@0: // trampoline CFI entries seems to be in the GCC bug database: michael@0: // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=26208 michael@0: virtual bool SignalHandler() { return true; } michael@0: }; michael@0: michael@0: michael@0: // The CallFrameInfo class makes calls on an instance of this class to michael@0: // report errors or warn about problems in the data it is parsing. michael@0: // These messages are sent to the message sink |aLog| provided to the michael@0: // constructor. michael@0: class CallFrameInfo::Reporter { michael@0: public: michael@0: // Create an error reporter which attributes troubles to the section michael@0: // named SECTION in FILENAME. michael@0: // michael@0: // Normally SECTION would be .debug_frame, but the Mac puts CFI data michael@0: // in a Mach-O section named __debug_frame. If we support michael@0: // Linux-style exception handling data, we could be reading an michael@0: // .eh_frame section. michael@0: Reporter(void (*aLog)(const char*), michael@0: const std::string &filename, michael@0: const std::string §ion = ".debug_frame") michael@0: : log_(aLog), filename_(filename), section_(section) { } michael@0: virtual ~Reporter() { } michael@0: michael@0: // The CFI entry at OFFSET ends too early to be well-formed. KIND michael@0: // indicates what kind of entry it is; KIND can be kUnknown if we michael@0: // haven't parsed enough of the entry to tell yet. michael@0: virtual void Incomplete(uint64 offset, CallFrameInfo::EntryKind kind); michael@0: michael@0: // The .eh_frame data has a four-byte zero at OFFSET where the next michael@0: // entry's length would be; this is a terminator. However, the buffer michael@0: // length as given to the CallFrameInfo constructor says there should be michael@0: // more data. michael@0: virtual void EarlyEHTerminator(uint64 offset); michael@0: michael@0: // The FDE at OFFSET refers to the CIE at CIE_OFFSET, but the michael@0: // section is not that large. michael@0: virtual void CIEPointerOutOfRange(uint64 offset, uint64 cie_offset); michael@0: michael@0: // The FDE at OFFSET refers to the CIE at CIE_OFFSET, but the entry michael@0: // there is not a CIE. michael@0: virtual void BadCIEId(uint64 offset, uint64 cie_offset); michael@0: michael@0: // The FDE at OFFSET refers to a CIE with version number VERSION, michael@0: // which we don't recognize. We cannot parse DWARF CFI if it uses michael@0: // a version number we don't recognize. michael@0: virtual void UnrecognizedVersion(uint64 offset, int version); michael@0: michael@0: // The FDE at OFFSET refers to a CIE with augmentation AUGMENTATION, michael@0: // which we don't recognize. We cannot parse DWARF CFI if it uses michael@0: // augmentations we don't recognize. michael@0: virtual void UnrecognizedAugmentation(uint64 offset, michael@0: const std::string &augmentation); michael@0: michael@0: // The pointer encoding ENCODING, specified by the CIE at OFFSET, is not michael@0: // a valid encoding. michael@0: virtual void InvalidPointerEncoding(uint64 offset, uint8 encoding); michael@0: michael@0: // The pointer encoding ENCODING, specified by the CIE at OFFSET, depends michael@0: // on a base address which has not been supplied. michael@0: virtual void UnusablePointerEncoding(uint64 offset, uint8 encoding); michael@0: michael@0: // The CIE at OFFSET contains a DW_CFA_restore instruction at michael@0: // INSN_OFFSET, which may not appear in a CIE. michael@0: virtual void RestoreInCIE(uint64 offset, uint64 insn_offset); michael@0: michael@0: // The entry at OFFSET, of kind KIND, has an unrecognized michael@0: // instruction at INSN_OFFSET. michael@0: virtual void BadInstruction(uint64 offset, CallFrameInfo::EntryKind kind, michael@0: uint64 insn_offset); michael@0: michael@0: // The instruction at INSN_OFFSET in the entry at OFFSET, of kind michael@0: // KIND, establishes a rule that cites the CFA, but we have not michael@0: // established a CFA rule yet. michael@0: virtual void NoCFARule(uint64 offset, CallFrameInfo::EntryKind kind, michael@0: uint64 insn_offset); michael@0: michael@0: // The instruction at INSN_OFFSET in the entry at OFFSET, of kind michael@0: // KIND, is a DW_CFA_restore_state instruction, but the stack of michael@0: // saved states is empty. michael@0: virtual void EmptyStateStack(uint64 offset, CallFrameInfo::EntryKind kind, michael@0: uint64 insn_offset); michael@0: michael@0: // The DW_CFA_remember_state instruction at INSN_OFFSET in the entry michael@0: // at OFFSET, of kind KIND, would restore a state that has no CFA michael@0: // rule, whereas the current state does have a CFA rule. This is michael@0: // bogus input, which the CallFrameInfo::Handler interface doesn't michael@0: // (and shouldn't) have any way to report. michael@0: virtual void ClearingCFARule(uint64 offset, CallFrameInfo::EntryKind kind, michael@0: uint64 insn_offset); michael@0: michael@0: private: michael@0: // A logging sink function, as supplied by LUL's user. michael@0: void (*log_)(const char*); michael@0: michael@0: protected: michael@0: // The name of the file whose CFI we're reading. michael@0: std::string filename_; michael@0: michael@0: // The name of the CFI section in that file. michael@0: std::string section_; michael@0: }; michael@0: michael@0: michael@0: using lul::CallFrameInfo; michael@0: using lul::Summariser; michael@0: michael@0: // A class that accepts parsed call frame information from the DWARF michael@0: // CFI parser and populates a google_breakpad::Module object with the michael@0: // contents. michael@0: class DwarfCFIToModule: public CallFrameInfo::Handler { michael@0: public: michael@0: michael@0: // DwarfCFIToModule uses an instance of this class to report errors michael@0: // detected while converting DWARF CFI to Breakpad STACK CFI records. michael@0: class Reporter { michael@0: public: michael@0: // Create a reporter that writes messages to the message sink michael@0: // |aLog|. FILE is the name of the file we're processing, and michael@0: // SECTION is the name of the section within that file that we're michael@0: // looking at (.debug_frame, .eh_frame, etc.). michael@0: Reporter(void (*aLog)(const char*), michael@0: const std::string &file, const std::string §ion) michael@0: : log_(aLog), file_(file), section_(section) { } michael@0: virtual ~Reporter() { } michael@0: michael@0: // The DWARF CFI entry at OFFSET says that REG is undefined, but the michael@0: // Breakpad symbol file format cannot express this. michael@0: virtual void UndefinedNotSupported(size_t offset, michael@0: const UniqueString* reg); michael@0: michael@0: // The DWARF CFI entry at OFFSET says that REG uses a DWARF michael@0: // expression to find its value, but DwarfCFIToModule is not michael@0: // capable of translating DWARF expressions to Breakpad postfix michael@0: // expressions. michael@0: virtual void ExpressionsNotSupported(size_t offset, michael@0: const UniqueString* reg); michael@0: michael@0: private: michael@0: // A logging sink function, as supplied by LUL's user. michael@0: void (*log_)(const char*); michael@0: protected: michael@0: std::string file_, section_; michael@0: }; michael@0: michael@0: // Register name tables. If TABLE is a vector returned by one of these michael@0: // functions, then TABLE[R] is the name of the register numbered R in michael@0: // DWARF call frame information. michael@0: class RegisterNames { michael@0: public: michael@0: // Intel's "x86" or IA-32. michael@0: static const unsigned int I386(); michael@0: michael@0: // AMD x86_64, AMD64, Intel EM64T, or Intel 64 michael@0: static const unsigned int X86_64(); michael@0: michael@0: // ARM. michael@0: static const unsigned int ARM(); michael@0: }; michael@0: michael@0: // Create a handler for the dwarf2reader::CallFrameInfo parser that michael@0: // records the stack unwinding information it receives in SUMM. michael@0: // michael@0: // Use REGISTER_NAMES[I] as the name of register number I; *this michael@0: // keeps a reference to the vector, so the vector should remain michael@0: // alive for as long as the DwarfCFIToModule does. michael@0: // michael@0: // Use REPORTER for reporting problems encountered in the conversion michael@0: // process. michael@0: DwarfCFIToModule(const unsigned int num_dw_regs, michael@0: Reporter *reporter, michael@0: /*OUT*/Summariser* summ) michael@0: : summ_(summ), num_dw_regs_(num_dw_regs), reporter_(reporter), michael@0: return_address_(-1) { michael@0: } michael@0: virtual ~DwarfCFIToModule() {} michael@0: michael@0: virtual bool Entry(size_t offset, uint64 address, uint64 length, michael@0: uint8 version, const std::string &augmentation, michael@0: unsigned return_address); michael@0: virtual bool UndefinedRule(uint64 address, int reg); michael@0: virtual bool SameValueRule(uint64 address, int reg); michael@0: virtual bool OffsetRule(uint64 address, int reg, michael@0: int base_register, long offset); michael@0: virtual bool ValOffsetRule(uint64 address, int reg, michael@0: int base_register, long offset); michael@0: virtual bool RegisterRule(uint64 address, int reg, int base_register); michael@0: virtual bool ExpressionRule(uint64 address, int reg, michael@0: const std::string &expression); michael@0: virtual bool ValExpressionRule(uint64 address, int reg, michael@0: const std::string &expression); michael@0: virtual bool End(); michael@0: michael@0: private: michael@0: // Return the name to use for register REG. michael@0: const UniqueString* RegisterName(int i); michael@0: michael@0: // The Summariser to which we should give entries michael@0: Summariser* summ_; michael@0: michael@0: // The number of Dwarf-defined register names for this architecture. michael@0: const unsigned int num_dw_regs_; michael@0: michael@0: // The reporter to use to report problems. michael@0: Reporter *reporter_; michael@0: michael@0: // The section offset of the current frame description entry, for michael@0: // use in error messages. michael@0: size_t entry_offset_; michael@0: michael@0: // The return address column for that entry. michael@0: unsigned return_address_; michael@0: }; michael@0: michael@0: } // namespace lul michael@0: michael@0: #endif // LulDwarfExt_h