Move dead submodules in-tree

Signed-off-by: swurl <swurl@swurl.xyz>
This commit is contained in:
swurl 2025-05-31 02:33:02 -04:00
parent c0cceff365
commit 6c655321e6
Signed by: crueter
GPG key ID: A5A7629F109C8FD1
4081 changed files with 1185566 additions and 45 deletions

View file

@ -0,0 +1,181 @@
// Copyright 2006 Google LLC
//
// 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 LLC 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.
#ifndef UTIL_DEBUGINFO_BYTEREADER_INL_H__
#define UTIL_DEBUGINFO_BYTEREADER_INL_H__
#include "common/dwarf/bytereader.h"
#include <assert.h>
#include <stdint.h>
namespace google_breakpad {
inline uint8_t ByteReader::ReadOneByte(const uint8_t* buffer) const {
return buffer[0];
}
inline uint16_t ByteReader::ReadTwoBytes(const uint8_t* buffer) const {
const uint16_t buffer0 = buffer[0];
const uint16_t buffer1 = buffer[1];
if (endian_ == ENDIANNESS_LITTLE) {
return buffer0 | buffer1 << 8;
} else {
return buffer1 | buffer0 << 8;
}
}
inline uint64_t ByteReader::ReadThreeBytes(const uint8_t* buffer) const {
const uint32_t buffer0 = buffer[0];
const uint32_t buffer1 = buffer[1];
const uint32_t buffer2 = buffer[2];
if (endian_ == ENDIANNESS_LITTLE) {
return buffer0 | buffer1 << 8 | buffer2 << 16;
} else {
return buffer2 | buffer1 << 8 | buffer0 << 16;
}
}
inline uint64_t ByteReader::ReadFourBytes(const uint8_t* buffer) const {
const uint32_t buffer0 = buffer[0];
const uint32_t buffer1 = buffer[1];
const uint32_t buffer2 = buffer[2];
const uint32_t buffer3 = buffer[3];
if (endian_ == ENDIANNESS_LITTLE) {
return buffer0 | buffer1 << 8 | buffer2 << 16 | buffer3 << 24;
} else {
return buffer3 | buffer2 << 8 | buffer1 << 16 | buffer0 << 24;
}
}
inline uint64_t ByteReader::ReadEightBytes(const uint8_t* buffer) const {
const uint64_t buffer0 = buffer[0];
const uint64_t buffer1 = buffer[1];
const uint64_t buffer2 = buffer[2];
const uint64_t buffer3 = buffer[3];
const uint64_t buffer4 = buffer[4];
const uint64_t buffer5 = buffer[5];
const uint64_t buffer6 = buffer[6];
const uint64_t buffer7 = buffer[7];
if (endian_ == ENDIANNESS_LITTLE) {
return buffer0 | buffer1 << 8 | buffer2 << 16 | buffer3 << 24 |
buffer4 << 32 | buffer5 << 40 | buffer6 << 48 | buffer7 << 56;
} else {
return buffer7 | buffer6 << 8 | buffer5 << 16 | buffer4 << 24 |
buffer3 << 32 | buffer2 << 40 | buffer1 << 48 | buffer0 << 56;
}
}
// Read an unsigned LEB128 number. Each byte contains 7 bits of
// information, plus one bit saying whether the number continues or
// not.
inline uint64_t ByteReader::ReadUnsignedLEB128(const uint8_t* buffer,
size_t* len) const {
uint64_t result = 0;
size_t num_read = 0;
unsigned int shift = 0;
uint8_t byte;
do {
byte = *buffer++;
num_read++;
result |= (static_cast<uint64_t>(byte & 0x7f)) << shift;
shift += 7;
} while (byte & 0x80);
*len = num_read;
return result;
}
// Read a signed LEB128 number. These are like regular LEB128
// numbers, except the last byte may have a sign bit set.
inline int64_t ByteReader::ReadSignedLEB128(const uint8_t* buffer,
size_t* len) const {
int64_t result = 0;
unsigned int shift = 0;
size_t num_read = 0;
uint8_t byte;
do {
byte = *buffer++;
num_read++;
result |= (static_cast<uint64_t>(byte & 0x7f) << shift);
shift += 7;
} while (byte & 0x80);
if ((shift < 8 * sizeof (result)) && (byte & 0x40))
result |= -((static_cast<int64_t>(1)) << shift);
*len = num_read;
return result;
}
inline uint64_t ByteReader::ReadOffset(const uint8_t* buffer) const {
assert(this->offset_reader_);
return (this->*offset_reader_)(buffer);
}
inline uint64_t ByteReader::ReadAddress(const uint8_t* buffer) const {
assert(this->address_reader_);
return (this->*address_reader_)(buffer);
}
inline void ByteReader::SetCFIDataBase(uint64_t section_base,
const uint8_t* buffer_base) {
section_base_ = section_base;
buffer_base_ = buffer_base;
have_section_base_ = true;
}
inline void ByteReader::SetTextBase(uint64_t text_base) {
text_base_ = text_base;
have_text_base_ = true;
}
inline void ByteReader::SetDataBase(uint64_t data_base) {
data_base_ = data_base;
have_data_base_ = true;
}
inline void ByteReader::SetFunctionBase(uint64_t function_base) {
function_base_ = function_base;
have_function_base_ = true;
}
inline void ByteReader::ClearFunctionBase() {
have_function_base_ = false;
}
} // namespace google_breakpad
#endif // UTIL_DEBUGINFO_BYTEREADER_INL_H__

View file

@ -0,0 +1,254 @@
// Copyright 2010 Google LLC
//
// 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 LLC 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.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include "common/dwarf/bytereader-inl.h"
#include "common/dwarf/bytereader.h"
namespace google_breakpad {
ByteReader::ByteReader(enum Endianness endian)
:offset_reader_(NULL), address_reader_(NULL), endian_(endian),
address_size_(0), offset_size_(0),
have_section_base_(), have_text_base_(), have_data_base_(),
have_function_base_() { }
ByteReader::~ByteReader() { }
void ByteReader::SetOffsetSize(uint8_t size) {
offset_size_ = size;
assert(size == 4 || size == 8);
if (size == 4) {
this->offset_reader_ = &ByteReader::ReadFourBytes;
} else {
this->offset_reader_ = &ByteReader::ReadEightBytes;
}
}
void ByteReader::SetAddressSize(uint8_t size) {
address_size_ = size;
assert(size == 4 || size == 8);
if (size == 4) {
this->address_reader_ = &ByteReader::ReadFourBytes;
} else {
this->address_reader_ = &ByteReader::ReadEightBytes;
}
}
uint64_t ByteReader::ReadInitialLength(const uint8_t* start, size_t* len) {
const uint64_t initial_length = ReadFourBytes(start);
start += 4;
// In DWARF2/3, if the initial length is all 1 bits, then the offset
// size is 8 and we need to read the next 8 bytes for the real length.
if (initial_length == 0xffffffff) {
SetOffsetSize(8);
*len = 12;
return ReadOffset(start);
} else {
SetOffsetSize(4);
*len = 4;
}
return initial_length;
}
bool ByteReader::ValidEncoding(DwarfPointerEncoding encoding) const {
if (encoding == DW_EH_PE_omit) return true;
if (encoding == DW_EH_PE_aligned) return true;
if ((encoding & 0x7) > DW_EH_PE_udata8)
return false;
if ((encoding & 0x70) > DW_EH_PE_funcrel)
return false;
return true;
}
bool ByteReader::UsableEncoding(DwarfPointerEncoding encoding) const {
switch (encoding & 0x70) {
case DW_EH_PE_absptr: return true;
case DW_EH_PE_pcrel: return have_section_base_;
case DW_EH_PE_textrel: return have_text_base_;
case DW_EH_PE_datarel: return have_data_base_;
case DW_EH_PE_funcrel: return have_function_base_;
default: return false;
}
}
uint64_t ByteReader::ReadEncodedPointer(const uint8_t* buffer,
DwarfPointerEncoding encoding,
size_t* len) const {
// UsableEncoding doesn't approve of DW_EH_PE_omit, so we shouldn't
// see it here.
assert(encoding != DW_EH_PE_omit);
// The Linux Standards Base 4.0 does not make this clear, but the
// GNU tools (gcc/unwind-pe.h; readelf/dwarf.c; gdb/dwarf2-frame.c)
// agree that aligned pointers are always absolute, machine-sized,
// machine-signed pointers.
if (encoding == DW_EH_PE_aligned) {
assert(have_section_base_);
// We don't need to align BUFFER in *our* address space. Rather, we
// need to find the next position in our buffer that would be aligned
// when the .eh_frame section the buffer contains is loaded into the
// program's memory. So align assuming that buffer_base_ gets loaded at
// address section_base_, where section_base_ itself may or may not be
// aligned.
// First, find the offset to START from the closest prior aligned
// address.
uint64_t skew = section_base_ & (AddressSize() - 1);
// Now find the offset from that aligned address to buffer.
uint64_t offset = skew + (buffer - buffer_base_);
// Round up to the next boundary.
uint64_t aligned = (offset + AddressSize() - 1) & -AddressSize();
// Convert back to a pointer.
const uint8_t* aligned_buffer = buffer_base_ + (aligned - skew);
// Finally, store the length and actually fetch the pointer.
*len = aligned_buffer - buffer + AddressSize();
return ReadAddress(aligned_buffer);
}
// Extract the value first, ignoring whether it's a pointer or an
// offset relative to some base.
uint64_t offset;
switch (encoding & 0x0f) {
case DW_EH_PE_absptr:
// DW_EH_PE_absptr is weird, as it is used as a meaningful value for
// both the high and low nybble of encoding bytes. When it appears in
// the high nybble, it means that the pointer is absolute, not an
// offset from some base address. When it appears in the low nybble,
// as here, it means that the pointer is stored as a normal
// machine-sized and machine-signed address. A low nybble of
// DW_EH_PE_absptr does not imply that the pointer is absolute; it is
// correct for us to treat the value as an offset from a base address
// if the upper nybble is not DW_EH_PE_absptr.
offset = ReadAddress(buffer);
*len = AddressSize();
break;
case DW_EH_PE_uleb128:
offset = ReadUnsignedLEB128(buffer, len);
break;
case DW_EH_PE_udata2:
offset = ReadTwoBytes(buffer);
*len = 2;
break;
case DW_EH_PE_udata4:
offset = ReadFourBytes(buffer);
*len = 4;
break;
case DW_EH_PE_udata8:
offset = ReadEightBytes(buffer);
*len = 8;
break;
case DW_EH_PE_sleb128:
offset = ReadSignedLEB128(buffer, len);
break;
case DW_EH_PE_sdata2:
offset = ReadTwoBytes(buffer);
// Sign-extend from 16 bits.
offset = (offset ^ 0x8000) - 0x8000;
*len = 2;
break;
case DW_EH_PE_sdata4:
offset = ReadFourBytes(buffer);
// Sign-extend from 32 bits.
offset = (offset ^ 0x80000000ULL) - 0x80000000ULL;
*len = 4;
break;
case DW_EH_PE_sdata8:
// No need to sign-extend; this is the full width of our type.
offset = ReadEightBytes(buffer);
*len = 8;
break;
default:
abort();
}
// Find the appropriate base address.
uint64_t base;
switch (encoding & 0x70) {
case DW_EH_PE_absptr:
base = 0;
break;
case DW_EH_PE_pcrel:
assert(have_section_base_);
base = section_base_ + (buffer - buffer_base_);
break;
case DW_EH_PE_textrel:
assert(have_text_base_);
base = text_base_;
break;
case DW_EH_PE_datarel:
assert(have_data_base_);
base = data_base_;
break;
case DW_EH_PE_funcrel:
assert(have_function_base_);
base = function_base_;
break;
default:
abort();
}
uint64_t pointer = base + offset;
// Remove inappropriate upper bits.
if (AddressSize() == 4)
pointer = pointer & 0xffffffff;
else
assert(AddressSize() == sizeof(uint64_t));
return pointer;
}
Endianness ByteReader::GetEndianness() const {
return endian_;
}
} // namespace google_breakpad

View file

@ -0,0 +1,320 @@
// -*- mode: C++ -*-
// Copyright 2010 Google LLC
//
// 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 LLC 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.
#ifndef COMMON_DWARF_BYTEREADER_H__
#define COMMON_DWARF_BYTEREADER_H__
#include <stdint.h>
#include <string>
#include "common/dwarf/types.h"
#include "common/dwarf/dwarf2enums.h"
namespace google_breakpad {
// We can't use the obvious name of LITTLE_ENDIAN and BIG_ENDIAN
// because it conflicts with a macro
enum Endianness {
ENDIANNESS_BIG,
ENDIANNESS_LITTLE
};
// A ByteReader knows how to read single- and multi-byte values of
// various endiannesses, sizes, and encodings, as used in DWARF
// debugging information and Linux C++ exception handling data.
class ByteReader {
public:
// Construct a ByteReader capable of reading one-, two-, four-, and
// eight-byte values according to ENDIANNESS, absolute machine-sized
// addresses, DWARF-style "initial length" values, signed and
// unsigned LEB128 numbers, and Linux C++ exception handling data's
// encoded pointers.
explicit ByteReader(enum Endianness endianness);
virtual ~ByteReader();
// Read a single byte from BUFFER and return it as an unsigned 8 bit
// number.
uint8_t ReadOneByte(const uint8_t* buffer) const;
// Read two bytes from BUFFER and return them as an unsigned 16 bit
// number, using this ByteReader's endianness.
uint16_t ReadTwoBytes(const uint8_t* buffer) const;
// Read three bytes from BUFFER and return them as an unsigned 64 bit
// number, using this ByteReader's endianness. DWARF 5 uses this encoding
// for various index-related DW_FORMs.
uint64_t ReadThreeBytes(const uint8_t* buffer) const;
// Read four bytes from BUFFER and return them as an unsigned 32 bit
// number, using this ByteReader's endianness. This function returns
// a uint64_t so that it is compatible with ReadAddress and
// ReadOffset. The number it returns will never be outside the range
// of an unsigned 32 bit integer.
uint64_t ReadFourBytes(const uint8_t* buffer) const;
// Read eight bytes from BUFFER and return them as an unsigned 64
// bit number, using this ByteReader's endianness.
uint64_t ReadEightBytes(const uint8_t* buffer) const;
// Read an unsigned LEB128 (Little Endian Base 128) number from
// BUFFER and return it as an unsigned 64 bit integer. Set LEN to
// the number of bytes read.
//
// The unsigned LEB128 representation of an integer N is a variable
// number of bytes:
//
// - If N is between 0 and 0x7f, then its unsigned LEB128
// representation is a single byte whose value is N.
//
// - Otherwise, its unsigned LEB128 representation is (N & 0x7f) |
// 0x80, followed by the unsigned LEB128 representation of N /
// 128, rounded towards negative infinity.
//
// In other words, we break VALUE into groups of seven bits, put
// them in little-endian order, and then write them as eight-bit
// bytes with the high bit on all but the last.
uint64_t ReadUnsignedLEB128(const uint8_t* buffer, size_t* len) const;
// Read a signed LEB128 number from BUFFER and return it as an
// signed 64 bit integer. Set LEN to the number of bytes read.
//
// The signed LEB128 representation of an integer N is a variable
// number of bytes:
//
// - If N is between -0x40 and 0x3f, then its signed LEB128
// representation is a single byte whose value is N in two's
// complement.
//
// - Otherwise, its signed LEB128 representation is (N & 0x7f) |
// 0x80, followed by the signed LEB128 representation of N / 128,
// rounded towards negative infinity.
//
// In other words, we break VALUE into groups of seven bits, put
// them in little-endian order, and then write them as eight-bit
// bytes with the high bit on all but the last.
int64_t ReadSignedLEB128(const uint8_t* buffer, size_t* len) const;
// Indicate that addresses on this architecture are SIZE bytes long. SIZE
// must be either 4 or 8. (DWARF allows addresses to be any number of
// bytes in length from 1 to 255, but we only support 32- and 64-bit
// addresses at the moment.) You must call this before using the
// ReadAddress member function.
//
// For data in a .debug_info section, or something that .debug_info
// refers to like line number or macro data, the compilation unit
// header's address_size field indicates the address size to use. Call
// frame information doesn't indicate its address size (a shortcoming of
// the spec); you must supply the appropriate size based on the
// architecture of the target machine.
void SetAddressSize(uint8_t size);
// Return the current address size, in bytes. This is either 4,
// indicating 32-bit addresses, or 8, indicating 64-bit addresses.
uint8_t AddressSize() const { return address_size_; }
// Read an address from BUFFER and return it as an unsigned 64 bit
// integer, respecting this ByteReader's endianness and address size. You
// must call SetAddressSize before calling this function.
uint64_t ReadAddress(const uint8_t* buffer) const;
// DWARF actually defines two slightly different formats: 32-bit DWARF
// and 64-bit DWARF. This is *not* related to the size of registers or
// addresses on the target machine; it refers only to the size of section
// offsets and data lengths appearing in the DWARF data. One only needs
// 64-bit DWARF when the debugging data itself is larger than 4GiB.
// 32-bit DWARF can handle x86_64 or PPC64 code just fine, unless the
// debugging data itself is very large.
//
// DWARF information identifies itself as 32-bit or 64-bit DWARF: each
// compilation unit and call frame information entry begins with an
// "initial length" field, which, in addition to giving the length of the
// data, also indicates the size of section offsets and lengths appearing
// in that data. The ReadInitialLength member function, below, reads an
// initial length and sets the ByteReader's offset size as a side effect.
// Thus, in the normal process of reading DWARF data, the appropriate
// offset size is set automatically. So, you should only need to call
// SetOffsetSize if you are using the same ByteReader to jump from the
// midst of one block of DWARF data into another.
// Read a DWARF "initial length" field from START, and return it as
// an unsigned 64 bit integer, respecting this ByteReader's
// endianness. Set *LEN to the length of the initial length in
// bytes, either four or twelve. As a side effect, set this
// ByteReader's offset size to either 4 (if we see a 32-bit DWARF
// initial length) or 8 (if we see a 64-bit DWARF initial length).
//
// A DWARF initial length is either:
//
// - a byte count stored as an unsigned 32-bit value less than
// 0xffffff00, indicating that the data whose length is being
// measured uses the 32-bit DWARF format, or
//
// - The 32-bit value 0xffffffff, followed by a 64-bit byte count,
// indicating that the data whose length is being measured uses
// the 64-bit DWARF format.
uint64_t ReadInitialLength(const uint8_t* start, size_t* len);
// Read an offset from BUFFER and return it as an unsigned 64 bit
// integer, respecting the ByteReader's endianness. In 32-bit DWARF, the
// offset is 4 bytes long; in 64-bit DWARF, the offset is eight bytes
// long. You must call ReadInitialLength or SetOffsetSize before calling
// this function; see the comments above for details.
uint64_t ReadOffset(const uint8_t* buffer) const;
// Return the current offset size, in bytes.
// A return value of 4 indicates that we are reading 32-bit DWARF.
// A return value of 8 indicates that we are reading 64-bit DWARF.
uint8_t OffsetSize() const { return offset_size_; }
// Indicate that section offsets and lengths are SIZE bytes long. SIZE
// must be either 4 (meaning 32-bit DWARF) or 8 (meaning 64-bit DWARF).
// Usually, you should not call this function yourself; instead, let a
// call to ReadInitialLength establish the data's offset size
// automatically.
void SetOffsetSize(uint8_t size);
// The Linux C++ ABI uses a variant of DWARF call frame information
// for exception handling. This data is included in the program's
// address space as the ".eh_frame" section, and intepreted at
// runtime to walk the stack, find exception handlers, and run
// cleanup code. The format is mostly the same as DWARF CFI, with
// some adjustments made to provide the additional
// exception-handling data, and to make the data easier to work with
// in memory --- for example, to allow it to be placed in read-only
// memory even when describing position-independent code.
//
// In particular, exception handling data can select a number of
// different encodings for pointers that appear in the data, as
// described by the DwarfPointerEncoding enum. There are actually
// four axes(!) to the encoding:
//
// - The pointer size: pointers can be 2, 4, or 8 bytes long, or use
// the DWARF LEB128 encoding.
//
// - The pointer's signedness: pointers can be signed or unsigned.
//
// - The pointer's base address: the data stored in the exception
// handling data can be the actual address (that is, an absolute
// pointer), or relative to one of a number of different base
// addreses --- including that of the encoded pointer itself, for
// a form of "pc-relative" addressing.
//
// - The pointer may be indirect: it may be the address where the
// true pointer is stored. (This is used to refer to things via
// global offset table entries, program linkage table entries, or
// other tricks used in position-independent code.)
//
// There are also two options that fall outside that matrix
// altogether: the pointer may be omitted, or it may have padding to
// align it on an appropriate address boundary. (That last option
// may seem like it should be just another axis, but it is not.)
// Indicate that the exception handling data is loaded starting at
// SECTION_BASE, and that the start of its buffer in our own memory
// is BUFFER_BASE. This allows us to find the address that a given
// byte in our buffer would have when loaded into the program the
// data describes. We need this to resolve DW_EH_PE_pcrel pointers.
void SetCFIDataBase(uint64_t section_base, const uint8_t* buffer_base);
// Indicate that the base address of the program's ".text" section
// is TEXT_BASE. We need this to resolve DW_EH_PE_textrel pointers.
void SetTextBase(uint64_t text_base);
// Indicate that the base address for DW_EH_PE_datarel pointers is
// DATA_BASE. The proper value depends on the ABI; it is usually the
// address of the global offset table, held in a designated register in
// position-independent code. You will need to look at the startup code
// for the target system to be sure. I tried; my eyes bled.
void SetDataBase(uint64_t data_base);
// Indicate that the base address for the FDE we are processing is
// FUNCTION_BASE. This is the start address of DW_EH_PE_funcrel
// pointers. (This encoding does not seem to be used by the GNU
// toolchain.)
void SetFunctionBase(uint64_t function_base);
// Indicate that we are no longer processing any FDE, so any use of
// a DW_EH_PE_funcrel encoding is an error.
void ClearFunctionBase();
// Return true if ENCODING is a valid pointer encoding.
bool ValidEncoding(DwarfPointerEncoding encoding) const;
// Return true if we have all the information we need to read a
// pointer that uses ENCODING. This checks that the appropriate
// SetFooBase function for ENCODING has been called.
bool UsableEncoding(DwarfPointerEncoding encoding) const;
// Read an encoded pointer from BUFFER using ENCODING; return the
// absolute address it represents, and set *LEN to the pointer's
// length in bytes, including any padding for aligned pointers.
//
// This function calls 'abort' if ENCODING is invalid or refers to a
// base address this reader hasn't been given, so you should check
// with ValidEncoding and UsableEncoding first if you would rather
// die in a more helpful way.
uint64_t ReadEncodedPointer(const uint8_t* buffer,
DwarfPointerEncoding encoding,
size_t* len) const;
Endianness GetEndianness() const;
private:
// Function pointer type for our address and offset readers.
typedef uint64_t (ByteReader::*AddressReader)(const uint8_t*) const;
// Read an offset from BUFFER and return it as an unsigned 64 bit
// integer. DWARF2/3 define offsets as either 4 or 8 bytes,
// generally depending on the amount of DWARF2/3 info present.
// This function pointer gets set by SetOffsetSize.
AddressReader offset_reader_;
// Read an address from BUFFER and return it as an unsigned 64 bit
// integer. DWARF2/3 allow addresses to be any size from 0-255
// bytes currently. Internally we support 4 and 8 byte addresses,
// and will CHECK on anything else.
// This function pointer gets set by SetAddressSize.
AddressReader address_reader_;
Endianness endian_;
uint8_t address_size_;
uint8_t offset_size_;
// Base addresses for Linux C++ exception handling data's encoded pointers.
bool have_section_base_, have_text_base_, have_data_base_;
bool have_function_base_;
uint64_t section_base_, text_base_, data_base_, function_base_;
const uint8_t* buffer_base_;
};
} // namespace google_breakpad
#endif // COMMON_DWARF_BYTEREADER_H__

View file

@ -0,0 +1,710 @@
// Copyright 2010 Google LLC
//
// 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 LLC 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>
// bytereader_unittest.cc: Unit tests for google_breakpad::ByteReader
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdint.h>
#include <string>
#include "breakpad_googletest_includes.h"
#include "common/dwarf/bytereader.h"
#include "common/dwarf/bytereader-inl.h"
#include "common/dwarf/cfi_assembler.h"
#include "common/using_std_string.h"
using google_breakpad::ByteReader;
using google_breakpad::DwarfPointerEncoding;
using google_breakpad::ENDIANNESS_BIG;
using google_breakpad::ENDIANNESS_LITTLE;
using google_breakpad::CFISection;
using google_breakpad::test_assembler::Label;
using google_breakpad::test_assembler::kBigEndian;
using google_breakpad::test_assembler::kLittleEndian;
using google_breakpad::test_assembler::Section;
using testing::Test;
struct ReaderFixture {
string contents;
size_t pointer_size;
};
class Reader: public ReaderFixture, public Test { };
class ReaderDeathTest: public ReaderFixture, public Test { };
TEST_F(Reader, SimpleConstructor) {
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
CFISection section(kBigEndian, 4);
section
.D8(0xc0)
.D16(0xcf0d)
.D32(0x96fdd219)
.D64(0xbbf55fef0825f117ULL)
.ULEB128(0xa0927048ba8121afULL)
.LEB128(-0x4f337badf4483f83LL)
.D32(0xfec319c9);
ASSERT_TRUE(section.GetContents(&contents));
const uint8_t* data = reinterpret_cast<const uint8_t*>(contents.data());
EXPECT_EQ(0xc0U, reader.ReadOneByte(data));
EXPECT_EQ(0xcf0dU, reader.ReadTwoBytes(data + 1));
EXPECT_EQ(0x96fdd219U, reader.ReadFourBytes(data + 3));
EXPECT_EQ(0xbbf55fef0825f117ULL, reader.ReadEightBytes(data + 7));
size_t leb128_size;
EXPECT_EQ(0xa0927048ba8121afULL,
reader.ReadUnsignedLEB128(data + 15, &leb128_size));
EXPECT_EQ(10U, leb128_size);
EXPECT_EQ(-0x4f337badf4483f83LL,
reader.ReadSignedLEB128(data + 25, &leb128_size));
EXPECT_EQ(10U, leb128_size);
EXPECT_EQ(0xfec319c9, reader.ReadAddress(data + 35));
}
TEST_F(Reader, ValidEncodings) {
ByteReader reader(ENDIANNESS_LITTLE);
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_omit)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_aligned)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_absptr |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_uleb128 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_udata2 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_udata4 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_udata8 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sleb128 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sdata2 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sdata4 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sdata8 |
google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_absptr |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_uleb128 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_udata2 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_udata4 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_udata8 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sleb128 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sdata2 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sdata4 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sdata8 |
google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_absptr |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_uleb128 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_udata2 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_udata4 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_udata8 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sleb128 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sdata2 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sdata4 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sdata8 |
google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_absptr |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_uleb128 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_udata2 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_udata4 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_udata8 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sleb128 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sdata2 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sdata4 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
google_breakpad::DW_EH_PE_sdata8 |
google_breakpad::DW_EH_PE_funcrel)));
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x05)));
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x07)));
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x0d)));
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x0f)));
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x51)));
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x60)));
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x70)));
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0xf0)));
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0xd0)));
}
TEST_F(ReaderDeathTest, DW_EH_PE_omit) {
static const uint8_t data[] = { 42 };
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
EXPECT_DEATH(reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_omit,
&pointer_size),
"encoding != DW_EH_PE_omit");
}
TEST_F(Reader, DW_EH_PE_absptr4) {
static const uint8_t data[] = { 0x27, 0x57, 0xea, 0x40 };
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(4);
EXPECT_EQ(0x40ea5727U,
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_absptr,
&pointer_size));
EXPECT_EQ(4U, pointer_size);
}
TEST_F(Reader, DW_EH_PE_absptr8) {
static const uint8_t data[] = {
0x60, 0x27, 0x57, 0xea, 0x40, 0xc2, 0x98, 0x05, 0x01, 0x50
};
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(8);
EXPECT_EQ(0x010598c240ea5727ULL,
reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_absptr,
&pointer_size));
EXPECT_EQ(8U, pointer_size);
}
TEST_F(Reader, DW_EH_PE_uleb128) {
static const uint8_t data[] = { 0x81, 0x84, 0x4c };
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(4);
EXPECT_EQ(0x130201U,
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_uleb128,
&pointer_size));
EXPECT_EQ(3U, pointer_size);
}
TEST_F(Reader, DW_EH_PE_udata2) {
static const uint8_t data[] = { 0xf4, 0x8d };
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
EXPECT_EQ(0xf48dU,
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_udata2,
&pointer_size));
EXPECT_EQ(2U, pointer_size);
}
TEST_F(Reader, DW_EH_PE_udata4) {
static const uint8_t data[] = { 0xb2, 0x68, 0xa5, 0x62, 0x8f, 0x8b };
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(8);
EXPECT_EQ(0xa5628f8b,
reader.ReadEncodedPointer(data + 2, google_breakpad::DW_EH_PE_udata4,
&pointer_size));
EXPECT_EQ(4U, pointer_size);
}
TEST_F(Reader, DW_EH_PE_udata8Addr8) {
static const uint8_t data[] = {
0x27, 0x04, 0x73, 0x04, 0x69, 0x9f, 0x19, 0xed, 0x8f, 0xfe
};
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(8);
EXPECT_EQ(0x8fed199f69047304ULL,
reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_udata8,
&pointer_size));
EXPECT_EQ(8U, pointer_size);
}
TEST_F(Reader, DW_EH_PE_udata8Addr4) {
static const uint8_t data[] = {
0x27, 0x04, 0x73, 0x04, 0x69, 0x9f, 0x19, 0xed, 0x8f, 0xfe
};
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(4);
EXPECT_EQ(0x69047304ULL,
reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_udata8,
&pointer_size));
EXPECT_EQ(8U, pointer_size);
}
TEST_F(Reader, DW_EH_PE_sleb128) {
static const uint8_t data[] = { 0x42, 0xff, 0xfb, 0x73 };
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
EXPECT_EQ(-0x030201U & 0xffffffff,
reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_sleb128,
&pointer_size));
EXPECT_EQ(3U, pointer_size);
}
TEST_F(Reader, DW_EH_PE_sdata2) {
static const uint8_t data[] = { 0xb9, 0xbf };
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(8);
EXPECT_EQ(0xffffffffffffbfb9ULL,
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_sdata2,
&pointer_size));
EXPECT_EQ(2U, pointer_size);
}
TEST_F(Reader, DW_EH_PE_sdata4) {
static const uint8_t data[] = { 0xa0, 0xca, 0xf2, 0xb8, 0xc2, 0xad };
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(8);
EXPECT_EQ(0xffffffffadc2b8f2ULL,
reader.ReadEncodedPointer(data + 2, google_breakpad::DW_EH_PE_sdata4,
&pointer_size));
EXPECT_EQ(4U, pointer_size);
}
TEST_F(Reader, DW_EH_PE_sdata8) {
static const uint8_t data[] = {
0xf6, 0x66, 0x57, 0x79, 0xe0, 0x0c, 0x9b, 0x26, 0x87
};
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(8);
EXPECT_EQ(0x87269b0ce0795766ULL,
reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_sdata8,
&pointer_size));
EXPECT_EQ(8U, pointer_size);
}
TEST_F(Reader, DW_EH_PE_pcrel) {
static const uint8_t data[] = {
0x4a, 0x8b, 0x1b, 0x14, 0xc8, 0xc4, 0x02, 0xce
};
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
DwarfPointerEncoding encoding =
DwarfPointerEncoding(google_breakpad::DW_EH_PE_pcrel
| google_breakpad::DW_EH_PE_absptr);
reader.SetCFIDataBase(0x89951377, data);
EXPECT_EQ(0x89951377 + 3 + 0x14c8c402,
reader.ReadEncodedPointer(data + 3, encoding, &pointer_size));
EXPECT_EQ(4U, pointer_size);
}
TEST_F(Reader, DW_EH_PE_textrel) {
static const uint8_t data[] = {
0xd9, 0x0d, 0x05, 0x17, 0xc9, 0x7a, 0x42, 0x1e
};
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(4);
reader.SetTextBase(0xb91beaf0);
DwarfPointerEncoding encoding =
DwarfPointerEncoding(google_breakpad::DW_EH_PE_textrel
| google_breakpad::DW_EH_PE_sdata2);
EXPECT_EQ((0xb91beaf0 + 0xffffc917) & 0xffffffff,
reader.ReadEncodedPointer(data + 3, encoding, &pointer_size));
EXPECT_EQ(2U, pointer_size);
}
TEST_F(Reader, DW_EH_PE_datarel) {
static const uint8_t data[] = {
0x16, 0xf2, 0xbb, 0x82, 0x68, 0xa7, 0xbc, 0x39
};
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(8);
reader.SetDataBase(0xbef308bd25ce74f0ULL);
DwarfPointerEncoding encoding =
DwarfPointerEncoding(google_breakpad::DW_EH_PE_datarel
| google_breakpad::DW_EH_PE_sleb128);
EXPECT_EQ(0xbef308bd25ce74f0ULL + 0xfffffffffffa013bULL,
reader.ReadEncodedPointer(data + 2, encoding, &pointer_size));
EXPECT_EQ(3U, pointer_size);
}
TEST_F(Reader, DW_EH_PE_funcrel) {
static const uint8_t data[] = {
0x84, 0xf8, 0x14, 0x01, 0x61, 0xd1, 0x48, 0xc9
};
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
reader.SetFunctionBase(0x823c3520);
DwarfPointerEncoding encoding =
DwarfPointerEncoding(google_breakpad::DW_EH_PE_funcrel
| google_breakpad::DW_EH_PE_udata2);
EXPECT_EQ(0x823c3520 + 0xd148,
reader.ReadEncodedPointer(data + 5, encoding, &pointer_size));
EXPECT_EQ(2U, pointer_size);
}
TEST(UsableBase, CFI) {
static const uint8_t data[] = { 0x42 };
ByteReader reader(ENDIANNESS_BIG);
reader.SetCFIDataBase(0xb31cbd20, data);
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
}
TEST(UsableBase, Text) {
ByteReader reader(ENDIANNESS_BIG);
reader.SetTextBase(0xa899ccb9);
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
}
TEST(UsableBase, Data) {
ByteReader reader(ENDIANNESS_BIG);
reader.SetDataBase(0xf7b10bcd);
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
}
TEST(UsableBase, Function) {
ByteReader reader(ENDIANNESS_BIG);
reader.SetFunctionBase(0xc2c0ed81);
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
}
TEST(UsableBase, ClearFunction) {
ByteReader reader(ENDIANNESS_BIG);
reader.SetFunctionBase(0xc2c0ed81);
reader.ClearFunctionBase();
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
}
struct AlignedFixture {
AlignedFixture() : reader(ENDIANNESS_BIG) { reader.SetAddressSize(4); }
static const uint8_t data[10];
ByteReader reader;
size_t pointer_size;
};
const uint8_t AlignedFixture::data[10] = {
0xfe, 0x6e, 0x93, 0xd8, 0x34, 0xd5, 0x1c, 0xd3, 0xac, 0x2b
};
class Aligned: public AlignedFixture, public Test { };
TEST_F(Aligned, DW_EH_PE_aligned0) {
reader.SetCFIDataBase(0xb440305c, data);
EXPECT_EQ(0xfe6e93d8U,
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(4U, pointer_size);
}
TEST_F(Aligned, DW_EH_PE_aligned1) {
reader.SetCFIDataBase(0xb440305d, data);
EXPECT_EQ(0xd834d51cU,
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(7U, pointer_size);
}
TEST_F(Aligned, DW_EH_PE_aligned2) {
reader.SetCFIDataBase(0xb440305e, data);
EXPECT_EQ(0x93d834d5U,
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(6U, pointer_size);
}
TEST_F(Aligned, DW_EH_PE_aligned3) {
reader.SetCFIDataBase(0xb440305f, data);
EXPECT_EQ(0x6e93d834U,
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(5U, pointer_size);
}
TEST_F(Aligned, DW_EH_PE_aligned11) {
reader.SetCFIDataBase(0xb4403061, data);
EXPECT_EQ(0xd834d51cU,
reader.ReadEncodedPointer(data + 1,
google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(6U, pointer_size);
}
TEST_F(Aligned, DW_EH_PE_aligned30) {
reader.SetCFIDataBase(0xb4403063, data);
EXPECT_EQ(0x6e93d834U,
reader.ReadEncodedPointer(data + 1,
google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(4U, pointer_size);
}
TEST_F(Aligned, DW_EH_PE_aligned23) {
reader.SetCFIDataBase(0xb4403062, data);
EXPECT_EQ(0x1cd3ac2bU,
reader.ReadEncodedPointer(data + 3,
google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(7U, pointer_size);
}
TEST_F(Aligned, DW_EH_PE_aligned03) {
reader.SetCFIDataBase(0xb4403064, data);
EXPECT_EQ(0x34d51cd3U,
reader.ReadEncodedPointer(data + 3,
google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(5U, pointer_size);
}

View file

@ -0,0 +1,205 @@
// Copyright 2010 Google LLC
//
// 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 LLC 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.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "common/dwarf/cfi_assembler.h"
#include <assert.h>
#include <stdlib.h>
namespace google_breakpad {
CFISection& CFISection::CIEHeader(uint64_t code_alignment_factor,
int data_alignment_factor,
unsigned return_address_register,
uint8_t version,
const string& augmentation,
bool dwarf64,
uint8_t address_size,
uint8_t segment_size) {
assert(!entry_length_);
entry_length_ = new PendingLength();
in_fde_ = false;
if (dwarf64) {
D32(kDwarf64InitialLengthMarker);
D64(entry_length_->length);
entry_length_->start = Here();
D64(eh_frame_ ? kEHFrame64CIEIdentifier : kDwarf64CIEIdentifier);
} else {
D32(entry_length_->length);
entry_length_->start = Here();
D32(eh_frame_ ? kEHFrame32CIEIdentifier : kDwarf32CIEIdentifier);
}
D8(version);
AppendCString(augmentation);
if (version >= 4) {
D8(address_size);
D8(segment_size);
}
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,
uint64_t initial_location,
uint64_t address_range,
bool dwarf64) {
assert(!entry_length_);
entry_length_ = new PendingLength();
in_fde_ = true;
fde_start_address_ = initial_location;
if (dwarf64) {
D32(0xffffffff);
D64(entry_length_->length);
entry_length_->start = Here();
if (eh_frame_)
D64(Here() - cie_pointer);
else
D64(cie_pointer);
} else {
D32(entry_length_->length);
entry_length_->start = Here();
if (eh_frame_)
D32(Here() - cie_pointer);
else
D32(cie_pointer);
}
EncodedPointer(initial_location);
// The FDE length in an .eh_frame section uses the same encoding as the
// initial location, but ignores the base address (selected by the upper
// nybble of the encoding), as it's a length, not an address that can be
// made relative.
EncodedPointer(address_range,
DwarfPointerEncoding(pointer_encoding_ & 0x0f));
return *this;
}
CFISection& CFISection::FinishEntry() {
assert(entry_length_);
Align(address_size_, DW_CFA_nop);
entry_length_->length = Here() - entry_length_->start;
delete entry_length_;
entry_length_ = NULL;
in_fde_ = false;
return *this;
}
CFISection& CFISection::EncodedPointer(uint64_t address,
DwarfPointerEncoding encoding,
const EncodedPointerBases& bases) {
// Omitted data is extremely easy to emit.
if (encoding == DW_EH_PE_omit)
return *this;
// If (encoding & DW_EH_PE_indirect) != 0, then we assume
// that ADDRESS is the address at which the pointer is stored --- in
// other words, that bit has no effect on how we write the pointer.
encoding = DwarfPointerEncoding(encoding & ~DW_EH_PE_indirect);
// Find the base address to which this pointer is relative. The upper
// nybble of the encoding specifies this.
uint64_t base;
switch (encoding & 0xf0) {
case DW_EH_PE_absptr: base = 0; break;
case DW_EH_PE_pcrel: base = bases.cfi + Size(); break;
case DW_EH_PE_textrel: base = bases.text; break;
case DW_EH_PE_datarel: base = bases.data; break;
case DW_EH_PE_funcrel: base = fde_start_address_; break;
case DW_EH_PE_aligned: base = 0; break;
default: abort();
};
// Make ADDRESS relative. Yes, this is appropriate even for "absptr"
// values; see gcc/unwind-pe.h.
address -= base;
// Align the pointer, if required.
if ((encoding & 0xf0) == DW_EH_PE_aligned)
Align(AddressSize());
// Append ADDRESS to this section in the appropriate form. For the
// fixed-width forms, we don't need to differentiate between signed and
// unsigned encodings, because ADDRESS has already been extended to 64
// bits before it was passed to us.
switch (encoding & 0x0f) {
case DW_EH_PE_absptr:
Address(address);
break;
case DW_EH_PE_uleb128:
ULEB128(address);
break;
case DW_EH_PE_sleb128:
LEB128(address);
break;
case DW_EH_PE_udata2:
case DW_EH_PE_sdata2:
D16(address);
break;
case DW_EH_PE_udata4:
case DW_EH_PE_sdata4:
D32(address);
break;
case DW_EH_PE_udata8:
case DW_EH_PE_sdata8:
D64(address);
break;
default:
abort();
}
return *this;
};
const uint32_t CFISection::kDwarf64InitialLengthMarker;
const uint32_t CFISection::kDwarf32CIEIdentifier;
const uint64_t CFISection::kDwarf64CIEIdentifier;
const uint32_t CFISection::kEHFrame32CIEIdentifier;
const uint64_t CFISection::kEHFrame64CIEIdentifier;
} // namespace google_breakpad

View file

@ -0,0 +1,268 @@
// -*- mode: C++ -*-
// Copyright 2010 Google LLC
//
// 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 LLC 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 "common/dwarf/dwarf2enums.h"
#include "common/test_assembler.h"
#include "common/using_std_string.h"
#include "google_breakpad/common/breakpad_types.h"
namespace google_breakpad {
using google_breakpad::test_assembler::Label;
using google_breakpad::test_assembler::Section;
class CFISection: public Section {
public:
// CFI augmentation strings beginning with 'z', defined by the
// Linux/IA-64 C++ ABI, can specify interesting encodings for
// addresses appearing in FDE headers and call frame instructions (and
// for additional fields whose presence the augmentation string
// specifies). In particular, pointers can be specified to be relative
// to various base address: the start of the .text section, the
// location holding the address itself, and so on. These allow the
// frame data to be position-independent even when they live in
// write-protected pages. These variants are specified at the
// following two URLs:
//
// http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html
// http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
//
// CFISection leaves the production of well-formed 'z'-augmented CIEs and
// FDEs to the user, but does provide EncodedPointer, to emit
// properly-encoded addresses for a given pointer encoding.
// EncodedPointer uses an instance of this structure to find the base
// addresses it should use; you can establish a default for all encoded
// pointers appended to this section with SetEncodedPointerBases.
struct EncodedPointerBases {
EncodedPointerBases() : cfi(), text(), data() { }
// The starting address of this CFI section in memory, for
// DW_EH_PE_pcrel. DW_EH_PE_pcrel pointers may only be used in data
// that has is loaded into the program's address space.
uint64_t cfi;
// The starting address of this file's .text section, for DW_EH_PE_textrel.
uint64_t text;
// The starting address of this file's .got or .eh_frame_hdr section,
// for DW_EH_PE_datarel.
uint64_t data;
};
// Create a CFISection whose endianness is ENDIANNESS, and where
// machine addresses are ADDRESS_SIZE bytes long. If EH_FRAME is
// true, use the .eh_frame format, as described by the Linux
// Standards Base Core Specification, instead of the DWARF CFI
// format.
CFISection(google_breakpad::test_assembler::Endianness endianness, size_t address_size,
bool eh_frame = false)
: Section(endianness), address_size_(address_size), eh_frame_(eh_frame),
pointer_encoding_(DW_EH_PE_absptr),
encoded_pointer_bases_(), entry_length_(NULL), in_fde_(false) {
// 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_; }
// Return true if this CFISection uses the .eh_frame format, or
// false if it contains ordinary DWARF CFI data.
bool ContainsEHFrame() const { return eh_frame_; }
// Use ENCODING for pointers in calls to FDEHeader and EncodedPointer.
void SetPointerEncoding(DwarfPointerEncoding encoding) {
pointer_encoding_ = encoding;
}
// Use the addresses in BASES as the base addresses for encoded
// pointers in subsequent calls to FDEHeader or EncodedPointer.
// This function makes a copy of BASES.
void SetEncodedPointerBases(const EncodedPointerBases& bases) {
encoded_pointer_bases_ = bases;
}
// 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(uint64_t code_alignment_factor,
int data_alignment_factor,
unsigned return_address_register,
uint8_t version = 3,
const string& augmentation = "",
bool dwarf64 = false,
uint8_t address_size = 8,
uint8_t segment_size = 0);
// 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,
uint64_t initial_location,
uint64_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;
}
// Append ADDRESS to this section, in the appropriate size and
// endianness. Return a reference to this section.
CFISection& Address(uint64_t address) {
Section::Append(endianness(), address_size_, address);
return *this;
}
CFISection& Address(Label address) {
Section::Append(endianness(), address_size_, address);
return *this;
}
// Append ADDRESS to this section, using ENCODING and BASES. ENCODING
// defaults to this section's default encoding, established by
// SetPointerEncoding. BASES defaults to this section's bases, set by
// SetEncodedPointerBases. If the DW_EH_PE_indirect bit is set in the
// encoding, assume that ADDRESS is where the true address is stored.
// Return a reference to this section.
//
// (C++ doesn't let me use default arguments here, because I want to
// refer to members of *this in the default argument expression.)
CFISection& EncodedPointer(uint64_t address) {
return EncodedPointer(address, pointer_encoding_, encoded_pointer_bases_);
}
CFISection& EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) {
return EncodedPointer(address, encoding, encoded_pointer_bases_);
}
CFISection& EncodedPointer(uint64_t address, DwarfPointerEncoding encoding,
const EncodedPointerBases& bases);
// Restate some member functions, to keep chaining working nicely.
CFISection& Mark(Label* label) { Section::Mark(label); return *this; }
CFISection& D8(uint8_t v) { Section::D8(v); return *this; }
CFISection& D16(uint16_t v) { Section::D16(v); return *this; }
CFISection& D16(Label v) { Section::D16(v); return *this; }
CFISection& D32(uint32_t v) { Section::D32(v); return *this; }
CFISection& D32(const Label& v) { Section::D32(v); return *this; }
CFISection& D64(uint64_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(uint64_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;
};
// Constants used in CFI/.eh_frame data:
// If the first four bytes of an "initial length" are this constant, then
// the data uses the 64-bit DWARF format, and the length itself is the
// subsequent eight bytes.
static const uint32_t kDwarf64InitialLengthMarker = 0xffffffffU;
// The CIE identifier for 32- and 64-bit DWARF CFI and .eh_frame data.
static const uint32_t kDwarf32CIEIdentifier = ~(uint32_t)0;
static const uint64_t kDwarf64CIEIdentifier = ~(uint64_t)0;
static const uint32_t kEHFrame32CIEIdentifier = 0;
static const uint64_t kEHFrame64CIEIdentifier = 0;
// The size of a machine address for the data in this section.
size_t address_size_;
// If true, we are generating a Linux .eh_frame section, instead of
// a standard DWARF .debug_frame section.
bool eh_frame_;
// The encoding to use for FDE pointers.
DwarfPointerEncoding pointer_encoding_;
// The base addresses to use when emitting encoded pointers.
EncodedPointerBases encoded_pointer_bases_;
// 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_;
// True if we are currently emitting an FDE --- that is, we have
// called FDEHeader but have not yet called FinishEntry.
bool in_fde_;
// If in_fde_ is true, this is its starting address. We use this for
// emitting DW_EH_PE_funcrel pointers.
uint64_t fde_start_address_;
};
} // namespace google_breakpad
#endif // PROCESSOR_CFI_ASSEMBLER_H_

View file

@ -0,0 +1,203 @@
// Copyright 2010 Google LLC
//
// 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 LLC 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>
// dwarf2diehandler.cc: Implement the dwarf2reader::DieDispatcher class.
// See dwarf2diehandler.h for details.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <assert.h>
#include <stdint.h>
#include <string>
#include "common/dwarf/dwarf2diehandler.h"
#include "common/using_std_string.h"
namespace google_breakpad {
DIEDispatcher::~DIEDispatcher() {
while (!die_handlers_.empty()) {
HandlerStack& entry = die_handlers_.top();
if (entry.handler_ != root_handler_)
delete entry.handler_;
die_handlers_.pop();
}
}
bool DIEDispatcher::StartCompilationUnit(uint64_t offset, uint8_t address_size,
uint8_t offset_size, uint64_t cu_length,
uint8_t dwarf_version) {
return root_handler_->StartCompilationUnit(offset, address_size,
offset_size, cu_length,
dwarf_version);
}
bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) {
// The stack entry for the parent of this DIE, if there is one.
HandlerStack* parent = die_handlers_.empty() ? NULL : &die_handlers_.top();
// Does this call indicate that we're done receiving the parent's
// attributes' values? If so, call its EndAttributes member function.
if (parent && parent->handler_ && !parent->reported_attributes_end_) {
parent->reported_attributes_end_ = true;
if (!parent->handler_->EndAttributes()) {
// Finish off this handler now. and edit *PARENT to indicate that
// we don't want to visit any of the children.
parent->handler_->Finish();
if (parent->handler_ != root_handler_)
delete parent->handler_;
parent->handler_ = NULL;
return false;
}
}
// Find a handler for this DIE.
DIEHandler* handler;
if (parent) {
if (parent->handler_)
// Ask the parent to find a handler.
handler = parent->handler_->FindChildHandler(offset, tag);
else
// No parent handler means we're not interested in any of our
// children.
handler = NULL;
} else {
// This is the root DIE. For a non-root DIE, the parent's handler
// decides whether to visit it, but the root DIE has no parent
// handler, so we have a special method on the root DIE handler
// itself to decide.
if (root_handler_->StartRootDIE(offset, tag))
handler = root_handler_;
else
handler = NULL;
}
// Push a handler stack entry for this new handler. As an
// optimization, we don't push NULL-handler entries on top of other
// NULL-handler entries; we just let the oldest such entry stand for
// the whole subtree.
if (handler || !parent || parent->handler_) {
HandlerStack entry;
entry.offset_ = offset;
entry.handler_ = handler;
entry.reported_attributes_end_ = false;
die_handlers_.push(entry);
}
return handler != NULL;
}
void DIEDispatcher::EndDIE(uint64_t offset) {
assert(!die_handlers_.empty());
HandlerStack* entry = &die_handlers_.top();
if (entry->handler_) {
// This entry had better be the handler for this DIE.
assert(entry->offset_ == offset);
// If a DIE has no children, this EndDIE call indicates that we're
// done receiving its attributes' values.
if (!entry->reported_attributes_end_)
entry->handler_->EndAttributes(); // Ignore return value: no children.
entry->handler_->Finish();
if (entry->handler_ != root_handler_)
delete entry->handler_;
} else {
// If this DIE is within a tree we're ignoring, then don't pop the
// handler stack: that entry stands for the whole tree.
if (entry->offset_ != offset)
return;
}
die_handlers_.pop();
}
void DIEDispatcher::ProcessAttributeUnsigned(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data) {
HandlerStack& current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.
assert(offset == current.offset_);
current.handler_->ProcessAttributeUnsigned(attr, form, data);
}
void DIEDispatcher::ProcessAttributeSigned(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
int64_t data) {
HandlerStack& current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.
assert(offset == current.offset_);
current.handler_->ProcessAttributeSigned(attr, form, data);
}
void DIEDispatcher::ProcessAttributeReference(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data) {
HandlerStack& current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.
assert(offset == current.offset_);
current.handler_->ProcessAttributeReference(attr, form, data);
}
void DIEDispatcher::ProcessAttributeBuffer(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const uint8_t* data,
uint64_t len) {
HandlerStack& current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.
assert(offset == current.offset_);
current.handler_->ProcessAttributeBuffer(attr, form, data, len);
}
void DIEDispatcher::ProcessAttributeString(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const string& data) {
HandlerStack& current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.
assert(offset == current.offset_);
current.handler_->ProcessAttributeString(attr, form, data);
}
void DIEDispatcher::ProcessAttributeSignature(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t signature) {
HandlerStack& current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.
assert(offset == current.offset_);
current.handler_->ProcessAttributeSignature(attr, form, signature);
}
} // namespace google_breakpad

View file

@ -0,0 +1,368 @@
// -*- mode: c++ -*-
// Copyright 2010 Google LLC
//
// 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 LLC 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>
// dwarf2reader::CompilationUnit is a simple and direct parser for
// DWARF data, but its handler interface is not convenient to use. In
// particular:
//
// - CompilationUnit calls Dwarf2Handler's member functions to report
// every attribute's value, regardless of what sort of DIE it is.
// As a result, the ProcessAttributeX functions end up looking like
// this:
//
// switch (parent_die_tag) {
// case DW_TAG_x:
// switch (attribute_name) {
// case DW_AT_y:
// handle attribute y of DIE type x
// ...
// } break;
// ...
// }
//
// In C++ it's much nicer to use virtual function dispatch to find
// the right code for a given case than to switch on the DIE tag
// like this.
//
// - Processing different kinds of DIEs requires different sets of
// data: lexical block DIEs have start and end addresses, but struct
// type DIEs don't. It would be nice to be able to have separate
// handler classes for separate kinds of DIEs, each with the members
// appropriate to its role, instead of having one handler class that
// needs to hold data for every DIE type.
//
// - There should be a separate instance of the appropriate handler
// class for each DIE, instead of a single object with tables
// tracking all the dies in the compilation unit.
//
// - It's not convenient to take some action after all a DIE's
// attributes have been seen, but before visiting any of its
// children. The only indication you have that a DIE's attribute
// list is complete is that you get either a StartDIE or an EndDIE
// call.
//
// - It's not convenient to make use of the tree structure of the
// DIEs. Skipping all the children of a given die requires
// maintaining state and returning false from StartDIE until we get
// an EndDIE call with the appropriate offset.
//
// This interface tries to take care of all that. (You're shocked, I'm sure.)
//
// Using the classes here, you provide an initial handler for the root
// DIE of the compilation unit. Each handler receives its DIE's
// attributes, and provides fresh handler objects for children of
// interest, if any. The three classes are:
//
// - DIEHandler: the base class for your DIE-type-specific handler
// classes.
//
// - RootDIEHandler: derived from DIEHandler, the base class for your
// root DIE handler class.
//
// - DIEDispatcher: derived from Dwarf2Handler, an instance of this
// invokes your DIE-type-specific handler objects.
//
// In detail:
//
// - Define handler classes specialized for the DIE types you're
// interested in. These handler classes must inherit from
// DIEHandler. Thus:
//
// class My_DW_TAG_X_Handler: public DIEHandler { ... };
// class My_DW_TAG_Y_Handler: public DIEHandler { ... };
//
// DIEHandler subclasses needn't correspond exactly to single DIE
// types, as shown here; the point is that you can have several
// different classes appropriate to different kinds of DIEs.
//
// - In particular, define a handler class for the compilation
// unit's root DIE, that inherits from RootDIEHandler:
//
// class My_DW_TAG_compile_unit_Handler: public RootDIEHandler { ... };
//
// RootDIEHandler inherits from DIEHandler, adding a few additional
// member functions for examining the compilation unit as a whole,
// and other quirks of rootness.
//
// - Then, create a DIEDispatcher instance, passing it an instance of
// your root DIE handler class, and use that DIEDispatcher as the
// dwarf2reader::CompilationUnit's handler:
//
// My_DW_TAG_compile_unit_Handler root_die_handler(...);
// DIEDispatcher die_dispatcher(&root_die_handler);
// CompilationUnit reader(sections, offset, bytereader, &die_dispatcher);
//
// Here, 'die_dispatcher' acts as a shim between 'reader' and the
// various DIE-specific handlers you have defined.
//
// - When you call reader.Start(), die_dispatcher behaves as follows,
// starting with your root die handler and the compilation unit's
// root DIE:
//
// - It calls the handler's ProcessAttributeX member functions for
// each of the DIE's attributes.
//
// - It calls the handler's EndAttributes member function. This
// should return true if any of the DIE's children should be
// visited, in which case:
//
// - For each of the DIE's children, die_dispatcher calls the
// DIE's handler's FindChildHandler member function. If that
// returns a pointer to a DIEHandler instance, then
// die_dispatcher uses that handler to process the child, using
// this procedure recursively. Alternatively, if
// FindChildHandler returns NULL, die_dispatcher ignores that
// child and its descendants.
//
// - When die_dispatcher has finished processing all the DIE's
// children, it invokes the handler's Finish() member function,
// and destroys the handler. (As a special case, it doesn't
// destroy the root DIE handler.)
//
// This allows the code for handling a particular kind of DIE to be
// gathered together in a single class, makes it easy to skip all the
// children or individual children of a particular DIE, and provides
// appropriate parental context for each die.
#ifndef COMMON_DWARF_DWARF2DIEHANDLER_H__
#define COMMON_DWARF_DWARF2DIEHANDLER_H__
#include <stdint.h>
#include <stack>
#include <string>
#include "common/dwarf/types.h"
#include "common/dwarf/dwarf2enums.h"
#include "common/dwarf/dwarf2reader.h"
#include "common/using_std_string.h"
namespace google_breakpad {
// A base class for handlers for specific DIE types. The series of
// calls made on a DIE handler is as follows:
//
// - for each attribute of the DIE:
// - ProcessAttributeX()
// - EndAttributes()
// - if that returned true, then for each child:
// - FindChildHandler()
// - if that returns a non-NULL pointer to a new handler:
// - recurse, with the new handler and the child die
// - Finish()
// - destruction
class DIEHandler {
public:
DIEHandler() { }
virtual ~DIEHandler() { }
// When we visit a DIE, we first use these member functions to
// report the DIE's attributes and their values. These have the
// same restrictions as the corresponding member functions of
// dwarf2reader::Dwarf2Handler.
//
// Since DWARF does not specify in what order attributes must
// appear, avoid making decisions in these functions that would be
// affected by the presence of other attributes. The EndAttributes
// function is a more appropriate place for such work, as all the
// DIE's attributes have been seen at that point.
//
// The default definitions ignore the values they are passed.
virtual void ProcessAttributeUnsigned(enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data) { }
virtual void ProcessAttributeSigned(enum DwarfAttribute attr,
enum DwarfForm form,
int64_t data) { }
virtual void ProcessAttributeReference(enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data) { }
virtual void ProcessAttributeBuffer(enum DwarfAttribute attr,
enum DwarfForm form,
const uint8_t* data,
uint64_t len) { }
virtual void ProcessAttributeString(enum DwarfAttribute attr,
enum DwarfForm form,
const string& data) { }
virtual void ProcessAttributeSignature(enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t signture) { }
// Once we have reported all the DIE's attributes' values, we call
// this member function. If it returns false, we skip all the DIE's
// children. If it returns true, we call FindChildHandler on each
// child. If that returns a handler object, we use that to visit
// the child; otherwise, we skip the child.
//
// This is a good place to make decisions that depend on more than
// one attribute. DWARF does not specify in what order attributes
// must appear, so only when the EndAttributes function is called
// does the handler have a complete picture of the DIE's attributes.
//
// The default definition elects to ignore the DIE's children.
// You'll need to override this if you override FindChildHandler,
// but at least the default behavior isn't to pass the children to
// FindChildHandler, which then ignores them all.
virtual bool EndAttributes() { return false; }
// If EndAttributes returns true to indicate that some of the DIE's
// children might be of interest, then we apply this function to
// each of the DIE's children. If it returns a handler object, then
// we use that to visit the child DIE. If it returns NULL, we skip
// that child DIE (and all its descendants).
//
// OFFSET is the offset of the child; TAG indicates what kind of DIE
// it is.
//
// The default definition skips all children.
virtual DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag) {
return NULL;
}
// When we are done processing a DIE, we call this member function.
// This happens after the EndAttributes call, all FindChildHandler
// calls (if any), and all operations on the children themselves (if
// any). We call Finish on every handler --- even if EndAttributes
// returns false.
virtual void Finish() { };
};
// A subclass of DIEHandler, with additional kludges for handling the
// compilation unit's root die.
class RootDIEHandler : public DIEHandler {
public:
bool handle_inline;
explicit RootDIEHandler(bool handle_inline = false)
: handle_inline(handle_inline) {}
virtual ~RootDIEHandler() {}
// We pass the values reported via Dwarf2Handler::StartCompilationUnit
// to this member function, and skip the entire compilation unit if it
// returns false. So the root DIE handler is actually also
// responsible for handling the compilation unit metadata.
// The default definition always visits the compilation unit.
virtual bool StartCompilationUnit(uint64_t offset, uint8_t address_size,
uint8_t offset_size, uint64_t cu_length,
uint8_t dwarf_version) { return true; }
// For the root DIE handler only, we pass the offset, tag and
// attributes of the compilation unit's root DIE. This is the only
// way the root DIE handler can find the root DIE's tag. If this
// function returns true, we will visit the root DIE using the usual
// DIEHandler methods; otherwise, we skip the entire compilation
// unit.
//
// The default definition elects to visit the root DIE.
virtual bool StartRootDIE(uint64_t offset, enum DwarfTag tag) { return true; }
};
class DIEDispatcher: public Dwarf2Handler {
public:
// Create a Dwarf2Handler which uses ROOT_HANDLER as the handler for
// the compilation unit's root die, as described for the DIEHandler
// class.
DIEDispatcher(RootDIEHandler* root_handler) : root_handler_(root_handler) { }
// Destroying a DIEDispatcher destroys all active handler objects
// except the root handler.
~DIEDispatcher();
bool StartCompilationUnit(uint64_t offset, uint8_t address_size,
uint8_t offset_size, uint64_t cu_length,
uint8_t dwarf_version);
bool StartDIE(uint64_t offset, enum DwarfTag tag);
void ProcessAttributeUnsigned(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data);
void ProcessAttributeSigned(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
int64_t data);
void ProcessAttributeReference(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data);
void ProcessAttributeBuffer(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const uint8_t* data,
uint64_t len);
void ProcessAttributeString(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const string& data);
void ProcessAttributeSignature(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t signature);
void EndDIE(uint64_t offset);
private:
// The type of a handler stack entry. This includes some fields
// which don't really need to be on the stack --- they could just be
// single data members of DIEDispatcher --- but putting them here
// makes it easier to see that the code is correct.
struct HandlerStack {
// The offset of the DIE for this handler stack entry.
uint64_t offset_;
// The handler object interested in this DIE's attributes and
// children. If NULL, we're not interested in either.
DIEHandler* handler_;
// Have we reported the end of this DIE's attributes to the handler?
bool reported_attributes_end_;
};
// Stack of DIE attribute handlers. At StartDIE(D), the top of the
// stack is the handler of D's parent, whom we may ask for a handler
// for D itself. At EndDIE(D), the top of the stack is D's handler.
// Special cases:
//
// - Before we've seen the compilation unit's root DIE, the stack is
// empty; we'll call root_handler_'s special member functions, and
// perhaps push root_handler_ on the stack to look at the root's
// immediate children.
//
// - When we decide to ignore a subtree, we only push an entry on
// the stack for the root of the tree being ignored, rather than
// pushing lots of stack entries with handler_ set to NULL.
std::stack<HandlerStack> die_handlers_;
// The root handler. We don't push it on die_handlers_ until we
// actually get the StartDIE call for the root.
RootDIEHandler* root_handler_;
};
} // namespace google_breakpad
#endif // COMMON_DWARF_DWARF2DIEHANDLER_H__

View file

@ -0,0 +1,532 @@
// -*- mode: c++ -*-
// Copyright 2010 Google LLC
//
// 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 LLC 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>
// dwarf2diehander_unittest.cc: Unit tests for google_breakpad::DIEDispatcher.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdint.h>
#include <string>
#include <utility>
#include "breakpad_googletest_includes.h"
#include "common/dwarf/dwarf2diehandler.h"
#include "common/using_std_string.h"
using std::make_pair;
using ::testing::_;
using ::testing::ContainerEq;
using ::testing::ElementsAreArray;
using ::testing::Eq;
using ::testing::InSequence;
using ::testing::Return;
using ::testing::Sequence;
using ::testing::StrEq;
using google_breakpad::DIEDispatcher;
using google_breakpad::DIEHandler;
using google_breakpad::DwarfAttribute;
using google_breakpad::DwarfForm;
using google_breakpad::DwarfTag;
using google_breakpad::RootDIEHandler;
class MockDIEHandler: public DIEHandler {
public:
MOCK_METHOD3(ProcessAttributeUnsigned,
void(DwarfAttribute, DwarfForm, uint64_t));
MOCK_METHOD3(ProcessAttributeSigned,
void(DwarfAttribute, DwarfForm, int64_t));
MOCK_METHOD3(ProcessAttributeReference,
void(DwarfAttribute, DwarfForm, uint64_t));
MOCK_METHOD4(ProcessAttributeBuffer,
void(DwarfAttribute, DwarfForm, const uint8_t*, uint64_t));
MOCK_METHOD3(ProcessAttributeString,
void(DwarfAttribute, DwarfForm, const string&));
MOCK_METHOD3(ProcessAttributeSignature,
void(DwarfAttribute, DwarfForm, uint64_t));
MOCK_METHOD0(EndAttributes, bool());
MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64_t, DwarfTag));
MOCK_METHOD0(Finish, void());
};
class MockRootDIEHandler: public RootDIEHandler {
public:
MOCK_METHOD3(ProcessAttributeUnsigned,
void(DwarfAttribute, DwarfForm, uint64_t));
MOCK_METHOD3(ProcessAttributeSigned,
void(DwarfAttribute, DwarfForm, int64_t));
MOCK_METHOD3(ProcessAttributeReference,
void(DwarfAttribute, DwarfForm, uint64_t));
MOCK_METHOD4(ProcessAttributeBuffer,
void(DwarfAttribute, DwarfForm, const uint8_t*, uint64_t));
MOCK_METHOD3(ProcessAttributeString,
void(DwarfAttribute, DwarfForm, const string&));
MOCK_METHOD3(ProcessAttributeSignature,
void(DwarfAttribute, DwarfForm, uint64_t));
MOCK_METHOD0(EndAttributes, bool());
MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64_t, DwarfTag));
MOCK_METHOD0(Finish, void());
MOCK_METHOD5(StartCompilationUnit, bool(uint64_t, uint8_t, uint8_t, uint64_t,
uint8_t));
MOCK_METHOD2(StartRootDIE, bool(uint64_t, DwarfTag));
};
// If the handler elects to skip the compilation unit, the dispatcher
// should tell the reader so.
TEST(Dwarf2DIEHandler, SkipCompilationUnit) {
Sequence s;
MockRootDIEHandler mock_root_handler;
DIEDispatcher die_dispatcher(&mock_root_handler);
EXPECT_CALL(mock_root_handler,
StartCompilationUnit(0x8d42aed77cfccf3eLL,
0x89, 0xdc,
0x2ecb4dc778a80f21LL,
0x66))
.InSequence(s)
.WillOnce(Return(false));
EXPECT_FALSE(die_dispatcher.StartCompilationUnit(0x8d42aed77cfccf3eLL,
0x89, 0xdc,
0x2ecb4dc778a80f21LL,
0x66));
}
// If the handler elects to skip the root DIE, the dispatcher should
// tell the reader so.
TEST(Dwarf2DIEHandler, SkipRootDIE) {
Sequence s;
MockRootDIEHandler mock_root_handler;
DIEDispatcher die_dispatcher(&mock_root_handler);
EXPECT_CALL(mock_root_handler,
StartCompilationUnit(0xde8994029fc8b999LL, 0xf4, 0x02,
0xb00febffa76e2b2bLL, 0x5c))
.InSequence(s)
.WillOnce(Return(true));
EXPECT_CALL(mock_root_handler,
StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6))
.InSequence(s)
.WillOnce(Return(false));
EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0xde8994029fc8b999LL,
0xf4, 0x02,
0xb00febffa76e2b2bLL, 0x5c));
EXPECT_FALSE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL,
(DwarfTag) 0xb4f98da6));
die_dispatcher.EndDIE(0x7d08242b4b510cf2LL);
}
// If the handler elects to skip the root DIE's children, the
// dispatcher should tell the reader so --- and avoid deleting the
// root handler.
TEST(Dwarf2DIEHandler, SkipRootDIEChildren) {
MockRootDIEHandler mock_root_handler;
DIEDispatcher die_dispatcher(&mock_root_handler);
{
InSequence s;
EXPECT_CALL(mock_root_handler,
StartCompilationUnit(0x15d6897480cc65a7LL, 0x26, 0xa0,
0x09f8bf0767f91675LL, 0xdb))
.WillOnce(Return(true));
EXPECT_CALL(mock_root_handler,
StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6))
.WillOnce(Return(true));
// Please don't tell me about my children.
EXPECT_CALL(mock_root_handler, EndAttributes())
.WillOnce(Return(false));
EXPECT_CALL(mock_root_handler, Finish())
.WillOnce(Return());
}
EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0x15d6897480cc65a7LL,
0x26, 0xa0,
0x09f8bf0767f91675LL, 0xdb));
EXPECT_TRUE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL,
(DwarfTag) 0xb4f98da6));
EXPECT_FALSE(die_dispatcher.StartDIE(0x435150ceedccda18LL,
(DwarfTag) 0xc3a17bba));
die_dispatcher.EndDIE(0x435150ceedccda18LL);
die_dispatcher.EndDIE(0x7d08242b4b510cf2LL);
}
// The dispatcher should pass attribute values through to the die
// handler accurately.
TEST(Dwarf2DIEHandler, PassAttributeValues) {
MockRootDIEHandler mock_root_handler;
DIEDispatcher die_dispatcher(&mock_root_handler);
const uint8_t buffer[10] = {
0x24, 0x24, 0x35, 0x9a, 0xca, 0xcf, 0xa8, 0x84, 0xa7, 0x18
};
string str = "\xc8\x26\x2e\x0d\xa4\x9c\x37\xd6\xfb\x1d";
// Set expectations.
{
InSequence s;
// We'll like the compilation unit header.
EXPECT_CALL(mock_root_handler,
StartCompilationUnit(0x8d42aed77cfccf3eLL, 0x89, 0xdc,
0x2ecb4dc778a80f21LL, 0x66))
.WillOnce(Return(true));
// We'll like the root DIE.
EXPECT_CALL(mock_root_handler,
StartRootDIE(0xe2222da01e29f2a9LL, (DwarfTag) 0x9829445c))
.WillOnce(Return(true));
// Expect some attribute values.
EXPECT_CALL(mock_root_handler,
ProcessAttributeUnsigned((DwarfAttribute) 0x1cc0bfed,
(DwarfForm) 0x424f1468,
0xa592571997facda1ULL))
.WillOnce(Return());
EXPECT_CALL(mock_root_handler,
ProcessAttributeSigned((DwarfAttribute) 0x43694dc9,
(DwarfForm) 0xf6f78901L,
0x92602a4e3bf1f446LL))
.WillOnce(Return());
EXPECT_CALL(mock_root_handler,
ProcessAttributeReference((DwarfAttribute) 0x4033e8cL,
(DwarfForm) 0xf66fbe0bL,
0x50fddef44734fdecULL))
.WillOnce(Return());
EXPECT_CALL(mock_root_handler,
ProcessAttributeBuffer((DwarfAttribute) 0x25d7e0af,
(DwarfForm) 0xe99a539a,
buffer, sizeof(buffer)))
.WillOnce(Return());
EXPECT_CALL(mock_root_handler,
ProcessAttributeString((DwarfAttribute) 0x310ed065,
(DwarfForm) 0x15762fec,
StrEq(str)))
.WillOnce(Return());
EXPECT_CALL(mock_root_handler,
ProcessAttributeSignature((DwarfAttribute) 0x58790d72,
(DwarfForm) 0x4159f138,
0x94682463613e6a5fULL))
.WillOnce(Return());
EXPECT_CALL(mock_root_handler, EndAttributes())
.WillOnce(Return(true));
EXPECT_CALL(mock_root_handler, FindChildHandler(_, _))
.Times(0);
EXPECT_CALL(mock_root_handler, Finish())
.WillOnce(Return());
}
// Drive the dispatcher.
// Report the CU header.
EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0x8d42aed77cfccf3eLL,
0x89, 0xdc,
0x2ecb4dc778a80f21LL,
0x66));
// Report the root DIE.
EXPECT_TRUE(die_dispatcher.StartDIE(0xe2222da01e29f2a9LL,
(DwarfTag) 0x9829445c));
// Report some attribute values.
die_dispatcher.ProcessAttributeUnsigned(0xe2222da01e29f2a9LL,
(DwarfAttribute) 0x1cc0bfed,
(DwarfForm) 0x424f1468,
0xa592571997facda1ULL);
die_dispatcher.ProcessAttributeSigned(0xe2222da01e29f2a9LL,
(DwarfAttribute) 0x43694dc9,
(DwarfForm) 0xf6f78901,
0x92602a4e3bf1f446LL);
die_dispatcher.ProcessAttributeReference(0xe2222da01e29f2a9LL,
(DwarfAttribute) 0x4033e8c,
(DwarfForm) 0xf66fbe0b,
0x50fddef44734fdecULL);
die_dispatcher.ProcessAttributeBuffer(0xe2222da01e29f2a9LL,
(DwarfAttribute) 0x25d7e0af,
(DwarfForm) 0xe99a539a,
buffer, sizeof(buffer));
die_dispatcher.ProcessAttributeString(0xe2222da01e29f2a9LL,
(DwarfAttribute) 0x310ed065,
(DwarfForm) 0x15762fec,
str);
die_dispatcher.ProcessAttributeSignature(0xe2222da01e29f2a9LL,
(DwarfAttribute) 0x58790d72,
(DwarfForm) 0x4159f138,
0x94682463613e6a5fULL);
// Finish the root DIE (and thus the CU).
die_dispatcher.EndDIE(0xe2222da01e29f2a9LL);
}
TEST(Dwarf2DIEHandler, FindAndSkipChildren) {
MockRootDIEHandler mock_root_handler;
MockDIEHandler *mock_child1_handler = new(MockDIEHandler);
MockDIEHandler *mock_child3_handler = new(MockDIEHandler);
DIEDispatcher die_dispatcher(&mock_root_handler);
{
InSequence s;
// We'll like the compilation unit header.
EXPECT_CALL(mock_root_handler,
StartCompilationUnit(0x9ec1e6d05e434a0eLL, 0xeb, 0x21,
0x47dd3c764275a216LL, 0xa5))
.WillOnce(Return(true));
// Root DIE.
{
EXPECT_CALL(mock_root_handler,
StartRootDIE(0x15f0e06bdfe3c372LL, (DwarfTag) 0xf5d60c59))
.WillOnce(Return(true));
EXPECT_CALL(mock_root_handler,
ProcessAttributeSigned((DwarfAttribute) 0xf779a642,
(DwarfForm) 0x2cb63027,
0x18e744661769d08fLL))
.WillOnce(Return());
EXPECT_CALL(mock_root_handler, EndAttributes())
.WillOnce(Return(true));
// First child DIE.
EXPECT_CALL(mock_root_handler,
FindChildHandler(0x149f644f8116fe8cLL,
(DwarfTag) 0xac2cbd8c))
.WillOnce(Return(mock_child1_handler));
{
EXPECT_CALL(*mock_child1_handler,
ProcessAttributeSigned((DwarfAttribute) 0xa6fd6f65,
(DwarfForm) 0xe4f64c41,
0x1b04e5444a55fe67LL))
.WillOnce(Return());
EXPECT_CALL(*mock_child1_handler, EndAttributes())
.WillOnce(Return(false));
// Skip first grandchild DIE and first great-grandchild DIE.
EXPECT_CALL(*mock_child1_handler, Finish())
.WillOnce(Return());
}
// Second child DIE. Root handler will decline to return a handler
// for this child.
EXPECT_CALL(mock_root_handler,
FindChildHandler(0x97412be24875de9dLL,
(DwarfTag) 0x505a068b))
.WillOnce(Return((DIEHandler*) NULL));
// Third child DIE.
EXPECT_CALL(mock_root_handler,
FindChildHandler(0x753c964c8ab538aeLL,
(DwarfTag) 0x8c22970e))
.WillOnce(Return(mock_child3_handler));
{
EXPECT_CALL(*mock_child3_handler,
ProcessAttributeSigned((DwarfAttribute) 0x4e2b7cfb,
(DwarfForm) 0x610b7ae1,
0x3ea5c609d7d7560fLL))
.WillOnce(Return());
EXPECT_CALL(*mock_child3_handler, EndAttributes())
.WillOnce(Return(true));
EXPECT_CALL(*mock_child3_handler, Finish())
.WillOnce(Return());
}
EXPECT_CALL(mock_root_handler, Finish())
.WillOnce(Return());
}
}
// Drive the dispatcher.
// Report the CU header.
EXPECT_TRUE(die_dispatcher
.StartCompilationUnit(0x9ec1e6d05e434a0eLL, 0xeb, 0x21,
0x47dd3c764275a216LL, 0xa5));
// Report the root DIE.
{
EXPECT_TRUE(die_dispatcher.StartDIE(0x15f0e06bdfe3c372LL,
(DwarfTag) 0xf5d60c59));
die_dispatcher.ProcessAttributeSigned(0x15f0e06bdfe3c372LL,
(DwarfAttribute) 0xf779a642,
(DwarfForm) 0x2cb63027,
0x18e744661769d08fLL);
// First child DIE.
{
EXPECT_TRUE(die_dispatcher.StartDIE(0x149f644f8116fe8cLL,
(DwarfTag) 0xac2cbd8c));
die_dispatcher.ProcessAttributeSigned(0x149f644f8116fe8cLL,
(DwarfAttribute) 0xa6fd6f65,
(DwarfForm) 0xe4f64c41,
0x1b04e5444a55fe67LL);
// First grandchild DIE. Will be skipped.
{
EXPECT_FALSE(die_dispatcher.StartDIE(0xd68de1ee0bd29419LL,
(DwarfTag) 0x22f05a15));
// First great-grandchild DIE. Will be skipped without being
// mentioned to any handler.
{
EXPECT_FALSE(die_dispatcher
.StartDIE(0xb3076285d25cac25LL,
(DwarfTag) 0xcff4061b));
die_dispatcher.EndDIE(0xb3076285d25cac25LL);
}
die_dispatcher.EndDIE(0xd68de1ee0bd29419LL);
}
die_dispatcher.EndDIE(0x149f644f8116fe8cLL);
}
// Second child DIE. Root handler will decline to find a handler for it.
{
EXPECT_FALSE(die_dispatcher.StartDIE(0x97412be24875de9dLL,
(DwarfTag) 0x505a068b));
die_dispatcher.EndDIE(0x97412be24875de9dLL);
}
// Third child DIE.
{
EXPECT_TRUE(die_dispatcher.StartDIE(0x753c964c8ab538aeLL,
(DwarfTag) 0x8c22970e));
die_dispatcher.ProcessAttributeSigned(0x753c964c8ab538aeLL,
(DwarfAttribute) 0x4e2b7cfb,
(DwarfForm) 0x610b7ae1,
0x3ea5c609d7d7560fLL);
die_dispatcher.EndDIE(0x753c964c8ab538aeLL);
}
// Finish the root DIE (and thus the CU).
die_dispatcher.EndDIE(0x15f0e06bdfe3c372LL);
}
}
// The DIEDispatcher destructor is supposed to delete all handlers on
// the stack, except for the root.
TEST(Dwarf2DIEHandler, FreeHandlersOnStack) {
MockRootDIEHandler mock_root_handler;
MockDIEHandler *mock_child_handler = new(MockDIEHandler);
MockDIEHandler *mock_grandchild_handler = new(MockDIEHandler);
{
InSequence s;
// We'll like the compilation unit header.
EXPECT_CALL(mock_root_handler,
StartCompilationUnit(0x87b41ba8381cd71cLL, 0xff, 0x89,
0x76d392ff393ddda2LL, 0xbf))
.WillOnce(Return(true));
// Root DIE.
{
EXPECT_CALL(mock_root_handler,
StartRootDIE(0xbf13b761691ddc91LL, (DwarfTag) 0x98980361))
.WillOnce(Return(true));
EXPECT_CALL(mock_root_handler, EndAttributes())
.WillOnce(Return(true));
// Child DIE.
EXPECT_CALL(mock_root_handler,
FindChildHandler(0x058f09240c5fc8c9LL,
(DwarfTag) 0x898bf0d0))
.WillOnce(Return(mock_child_handler));
{
EXPECT_CALL(*mock_child_handler, EndAttributes())
.WillOnce(Return(true));
// Grandchild DIE.
EXPECT_CALL(*mock_child_handler,
FindChildHandler(0x32dc00c9945dc0c8LL,
(DwarfTag) 0x2802d007))
.WillOnce(Return(mock_grandchild_handler));
{
EXPECT_CALL(*mock_grandchild_handler,
ProcessAttributeSigned((DwarfAttribute) 0x4e2b7cfb,
(DwarfForm) 0x610b7ae1,
0x3ea5c609d7d7560fLL))
.WillOnce(Return());
// At this point, we abandon the traversal, so none of the
// usual stuff should get called.
EXPECT_CALL(*mock_grandchild_handler, EndAttributes())
.Times(0);
EXPECT_CALL(*mock_grandchild_handler, Finish())
.Times(0);
}
EXPECT_CALL(*mock_child_handler, Finish())
.Times(0);
}
EXPECT_CALL(mock_root_handler, Finish())
.Times(0);
}
}
// The dispatcher.
DIEDispatcher die_dispatcher(&mock_root_handler);
// Report the CU header.
EXPECT_TRUE(die_dispatcher
.StartCompilationUnit(0x87b41ba8381cd71cLL, 0xff, 0x89,
0x76d392ff393ddda2LL, 0xbf));
// Report the root DIE.
{
EXPECT_TRUE(die_dispatcher.StartDIE(0xbf13b761691ddc91LL,
(DwarfTag) 0x98980361));
// Child DIE.
{
EXPECT_TRUE(die_dispatcher.StartDIE(0x058f09240c5fc8c9LL,
(DwarfTag) 0x898bf0d0));
// Grandchild DIE.
{
EXPECT_TRUE(die_dispatcher.StartDIE(0x32dc00c9945dc0c8LL,
(DwarfTag) 0x2802d007));
die_dispatcher.ProcessAttributeSigned(0x32dc00c9945dc0c8LL,
(DwarfAttribute) 0x4e2b7cfb,
(DwarfForm) 0x610b7ae1,
0x3ea5c609d7d7560fLL);
// Stop the traversal abruptly, so that there will still be
// handlers on the stack when the dispatcher is destructed.
// No EndDIE call...
}
// No EndDIE call...
}
// No EndDIE call...
}
}

View file

@ -0,0 +1,744 @@
// -*- mode: c++ -*-
// Copyright 2010 Google LLC
//
// 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 LLC 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.
#ifndef COMMON_DWARF_DWARF2ENUMS_H__
#define COMMON_DWARF_DWARF2ENUMS_H__
namespace google_breakpad {
// These enums do not follow the google3 style only because they are
// known universally (specs, other implementations) by the names in
// exactly this capitalization.
// Tag names and codes.
enum DwarfTag {
DW_TAG_padding = 0x00,
DW_TAG_array_type = 0x01,
DW_TAG_class_type = 0x02,
DW_TAG_entry_point = 0x03,
DW_TAG_enumeration_type = 0x04,
DW_TAG_formal_parameter = 0x05,
DW_TAG_imported_declaration = 0x08,
DW_TAG_label = 0x0a,
DW_TAG_lexical_block = 0x0b,
DW_TAG_member = 0x0d,
DW_TAG_pointer_type = 0x0f,
DW_TAG_reference_type = 0x10,
DW_TAG_compile_unit = 0x11,
DW_TAG_string_type = 0x12,
DW_TAG_structure_type = 0x13,
DW_TAG_subroutine_type = 0x15,
DW_TAG_typedef = 0x16,
DW_TAG_union_type = 0x17,
DW_TAG_unspecified_parameters = 0x18,
DW_TAG_variant = 0x19,
DW_TAG_common_block = 0x1a,
DW_TAG_common_inclusion = 0x1b,
DW_TAG_inheritance = 0x1c,
DW_TAG_inlined_subroutine = 0x1d,
DW_TAG_module = 0x1e,
DW_TAG_ptr_to_member_type = 0x1f,
DW_TAG_set_type = 0x20,
DW_TAG_subrange_type = 0x21,
DW_TAG_with_stmt = 0x22,
DW_TAG_access_declaration = 0x23,
DW_TAG_base_type = 0x24,
DW_TAG_catch_block = 0x25,
DW_TAG_const_type = 0x26,
DW_TAG_constant = 0x27,
DW_TAG_enumerator = 0x28,
DW_TAG_file_type = 0x29,
DW_TAG_friend = 0x2a,
DW_TAG_namelist = 0x2b,
DW_TAG_namelist_item = 0x2c,
DW_TAG_packed_type = 0x2d,
DW_TAG_subprogram = 0x2e,
DW_TAG_template_type_param = 0x2f,
DW_TAG_template_value_param = 0x30,
DW_TAG_thrown_type = 0x31,
DW_TAG_try_block = 0x32,
DW_TAG_variant_part = 0x33,
DW_TAG_variable = 0x34,
DW_TAG_volatile_type = 0x35,
// DWARF 3.
DW_TAG_dwarf_procedure = 0x36,
DW_TAG_restrict_type = 0x37,
DW_TAG_interface_type = 0x38,
DW_TAG_namespace = 0x39,
DW_TAG_imported_module = 0x3a,
DW_TAG_unspecified_type = 0x3b,
DW_TAG_partial_unit = 0x3c,
DW_TAG_imported_unit = 0x3d,
// DWARF 4.
DW_TAG_type_unit = 0x41,
// DWARF 5.
DW_TAG_skeleton_unit = 0x4a,
// SGI/MIPS Extensions.
DW_TAG_MIPS_loop = 0x4081,
// HP extensions. See:
// ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz
DW_TAG_HP_array_descriptor = 0x4090,
// GNU extensions.
DW_TAG_format_label = 0x4101, // For FORTRAN 77 and Fortran 90.
DW_TAG_function_template = 0x4102, // For C++.
DW_TAG_class_template = 0x4103, // For C++.
DW_TAG_GNU_BINCL = 0x4104,
DW_TAG_GNU_EINCL = 0x4105,
// Extensions for UPC. See: http://upc.gwu.edu/~upc.
DW_TAG_upc_shared_type = 0x8765,
DW_TAG_upc_strict_type = 0x8766,
DW_TAG_upc_relaxed_type = 0x8767,
// PGI (STMicroelectronics) extensions. No documentation available.
DW_TAG_PGI_kanji_type = 0xA000,
DW_TAG_PGI_interface_block = 0xA020
};
enum DwarfUnitHeader {
DW_UT_compile = 0x01,
DW_UT_type = 0x02,
DW_UT_partial = 0x03,
DW_UT_skeleton = 0x04,
DW_UT_split_compile = 0x05,
DW_UT_split_type = 0x06,
DW_UT_lo_user = 0x80,
DW_UT_hi_user = 0xFF
};
enum DwarfHasChild {
DW_children_no = 0,
DW_children_yes = 1
};
// Form names and codes.
enum DwarfForm {
DW_FORM_addr = 0x01,
DW_FORM_block2 = 0x03,
DW_FORM_block4 = 0x04,
DW_FORM_data2 = 0x05,
DW_FORM_data4 = 0x06,
DW_FORM_data8 = 0x07,
DW_FORM_string = 0x08,
DW_FORM_block = 0x09,
DW_FORM_block1 = 0x0a,
DW_FORM_data1 = 0x0b,
DW_FORM_flag = 0x0c,
DW_FORM_sdata = 0x0d,
DW_FORM_strp = 0x0e,
DW_FORM_udata = 0x0f,
DW_FORM_ref_addr = 0x10,
DW_FORM_ref1 = 0x11,
DW_FORM_ref2 = 0x12,
DW_FORM_ref4 = 0x13,
DW_FORM_ref8 = 0x14,
DW_FORM_ref_udata = 0x15,
DW_FORM_indirect = 0x16,
// Added in DWARF 4:
DW_FORM_sec_offset = 0x17,
DW_FORM_exprloc = 0x18,
DW_FORM_flag_present = 0x19,
// Added in DWARF 5:
DW_FORM_strx = 0x1a,
DW_FORM_addrx = 0x1b,
DW_FORM_ref_sup4 = 0x1c,
DW_FORM_strp_sup = 0x1d,
DW_FORM_data16 = 0x1e,
DW_FORM_line_strp = 0x1f,
// DWARF 4, but value out of order.
DW_FORM_ref_sig8 = 0x20,
// Added in DWARF 5:
DW_FORM_implicit_const = 0x21,
DW_FORM_loclistx = 0x22,
DW_FORM_rnglistx = 0x23,
DW_FORM_ref_sup8 = 0x24,
DW_FORM_strx1 = 0x25,
DW_FORM_strx2 = 0x26,
DW_FORM_strx3 = 0x27,
DW_FORM_strx4 = 0x28,
DW_FORM_addrx1 = 0x29,
DW_FORM_addrx2 = 0x2a,
DW_FORM_addrx3 = 0x2b,
DW_FORM_addrx4 = 0x2c,
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
DW_FORM_GNU_addr_index = 0x1f01,
DW_FORM_GNU_str_index = 0x1f02
};
// Attribute names and codes
enum DwarfAttribute {
DW_AT_sibling = 0x01,
DW_AT_location = 0x02,
DW_AT_name = 0x03,
DW_AT_ordering = 0x09,
DW_AT_subscr_data = 0x0a,
DW_AT_byte_size = 0x0b,
DW_AT_bit_offset = 0x0c,
DW_AT_bit_size = 0x0d,
DW_AT_element_list = 0x0f,
DW_AT_stmt_list = 0x10,
DW_AT_low_pc = 0x11,
DW_AT_high_pc = 0x12,
DW_AT_language = 0x13,
DW_AT_member = 0x14,
DW_AT_discr = 0x15,
DW_AT_discr_value = 0x16,
DW_AT_visibility = 0x17,
DW_AT_import = 0x18,
DW_AT_string_length = 0x19,
DW_AT_common_reference = 0x1a,
DW_AT_comp_dir = 0x1b,
DW_AT_const_value = 0x1c,
DW_AT_containing_type = 0x1d,
DW_AT_default_value = 0x1e,
DW_AT_inline = 0x20,
DW_AT_is_optional = 0x21,
DW_AT_lower_bound = 0x22,
DW_AT_producer = 0x25,
DW_AT_prototyped = 0x27,
DW_AT_return_addr = 0x2a,
DW_AT_start_scope = 0x2c,
DW_AT_stride_size = 0x2e,
DW_AT_upper_bound = 0x2f,
DW_AT_abstract_origin = 0x31,
DW_AT_accessibility = 0x32,
DW_AT_address_class = 0x33,
DW_AT_artificial = 0x34,
DW_AT_base_types = 0x35,
DW_AT_calling_convention = 0x36,
DW_AT_count = 0x37,
DW_AT_data_member_location = 0x38,
DW_AT_decl_column = 0x39,
DW_AT_decl_file = 0x3a,
DW_AT_decl_line = 0x3b,
DW_AT_declaration = 0x3c,
DW_AT_discr_list = 0x3d,
DW_AT_encoding = 0x3e,
DW_AT_external = 0x3f,
DW_AT_frame_base = 0x40,
DW_AT_friend = 0x41,
DW_AT_identifier_case = 0x42,
DW_AT_macro_info = 0x43,
DW_AT_namelist_items = 0x44,
DW_AT_priority = 0x45,
DW_AT_segment = 0x46,
DW_AT_specification = 0x47,
DW_AT_static_link = 0x48,
DW_AT_type = 0x49,
DW_AT_use_location = 0x4a,
DW_AT_variable_parameter = 0x4b,
DW_AT_virtuality = 0x4c,
DW_AT_vtable_elem_location = 0x4d,
// DWARF 3 values.
DW_AT_allocated = 0x4e,
DW_AT_associated = 0x4f,
DW_AT_data_location = 0x50,
DW_AT_stride = 0x51,
DW_AT_entry_pc = 0x52,
DW_AT_use_UTF8 = 0x53,
DW_AT_extension = 0x54,
DW_AT_ranges = 0x55,
DW_AT_trampoline = 0x56,
DW_AT_call_column = 0x57,
DW_AT_call_file = 0x58,
DW_AT_call_line = 0x59,
// DWARF 4
DW_AT_linkage_name = 0x6e,
// DWARF 5
DW_AT_str_offsets_base = 0x72,
DW_AT_addr_base = 0x73,
DW_AT_rnglists_base = 0x74,
DW_AT_dwo_name = 0x76,
// SGI/MIPS extensions.
DW_AT_MIPS_fde = 0x2001,
DW_AT_MIPS_loop_begin = 0x2002,
DW_AT_MIPS_tail_loop_begin = 0x2003,
DW_AT_MIPS_epilog_begin = 0x2004,
DW_AT_MIPS_loop_unroll_factor = 0x2005,
DW_AT_MIPS_software_pipeline_depth = 0x2006,
DW_AT_MIPS_linkage_name = 0x2007,
DW_AT_MIPS_stride = 0x2008,
DW_AT_MIPS_abstract_name = 0x2009,
DW_AT_MIPS_clone_origin = 0x200a,
DW_AT_MIPS_has_inlines = 0x200b,
// HP extensions.
DW_AT_HP_block_index = 0x2000,
DW_AT_HP_unmodifiable = 0x2001, // Same as DW_AT_MIPS_fde.
DW_AT_HP_actuals_stmt_list = 0x2010,
DW_AT_HP_proc_per_section = 0x2011,
DW_AT_HP_raw_data_ptr = 0x2012,
DW_AT_HP_pass_by_reference = 0x2013,
DW_AT_HP_opt_level = 0x2014,
DW_AT_HP_prof_version_id = 0x2015,
DW_AT_HP_opt_flags = 0x2016,
DW_AT_HP_cold_region_low_pc = 0x2017,
DW_AT_HP_cold_region_high_pc = 0x2018,
DW_AT_HP_all_variables_modifiable = 0x2019,
DW_AT_HP_linkage_name = 0x201a,
DW_AT_HP_prof_flags = 0x201b, // In comp unit of procs_info for -g.
// GNU extensions.
DW_AT_sf_names = 0x2101,
DW_AT_src_info = 0x2102,
DW_AT_mac_info = 0x2103,
DW_AT_src_coords = 0x2104,
DW_AT_body_begin = 0x2105,
DW_AT_body_end = 0x2106,
DW_AT_GNU_vector = 0x2107,
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
DW_AT_GNU_dwo_name = 0x2130,
DW_AT_GNU_dwo_id = 0x2131,
DW_AT_GNU_ranges_base = 0x2132,
DW_AT_GNU_addr_base = 0x2133,
DW_AT_GNU_pubnames = 0x2134,
DW_AT_GNU_pubtypes = 0x2135,
// VMS extensions.
DW_AT_VMS_rtnbeg_pd_address = 0x2201,
// UPC extension.
DW_AT_upc_threads_scaled = 0x3210,
// PGI (STMicroelectronics) extensions.
DW_AT_PGI_lbase = 0x3a00,
DW_AT_PGI_soffset = 0x3a01,
DW_AT_PGI_lstride = 0x3a02
};
// .debug_rngslist entry types
enum DwarfRngListEntry {
DW_RLE_end_of_list = 0,
DW_RLE_base_addressx = 1,
DW_RLE_startx_endx = 2,
DW_RLE_startx_length = 3,
DW_RLE_offset_pair = 4,
DW_RLE_base_address = 5,
DW_RLE_start_end = 6,
DW_RLE_start_length = 7,
};
// Line number content type codes (DWARF 5).
enum DwarfLineNumberContentType {
DW_LNCT_path = 1,
DW_LNCT_directory_index = 2,
DW_LNCT_timestamp = 3,
DW_LNCT_size = 4,
DW_LNCT_MD5 = 5,
};
// Line number opcodes.
enum DwarfLineNumberOps {
DW_LNS_extended_op = 0,
DW_LNS_copy = 1,
DW_LNS_advance_pc = 2,
DW_LNS_advance_line = 3,
DW_LNS_set_file = 4,
DW_LNS_set_column = 5,
DW_LNS_negate_stmt = 6,
DW_LNS_set_basic_block = 7,
DW_LNS_const_add_pc = 8,
DW_LNS_fixed_advance_pc = 9,
// DWARF 3.
DW_LNS_set_prologue_end = 10,
DW_LNS_set_epilogue_begin = 11,
DW_LNS_set_isa = 12
};
// Line number extended opcodes.
enum DwarfLineNumberExtendedOps {
DW_LNE_end_sequence = 1,
DW_LNE_set_address = 2,
DW_LNE_define_file = 3,
// HP extensions.
DW_LNE_HP_negate_is_UV_update = 0x11,
DW_LNE_HP_push_context = 0x12,
DW_LNE_HP_pop_context = 0x13,
DW_LNE_HP_set_file_line_column = 0x14,
DW_LNE_HP_set_routine_name = 0x15,
DW_LNE_HP_set_sequence = 0x16,
DW_LNE_HP_negate_post_semantics = 0x17,
DW_LNE_HP_negate_function_exit = 0x18,
DW_LNE_HP_negate_front_end_logical = 0x19,
DW_LNE_HP_define_proc = 0x20
};
// Type encoding names and codes
enum DwarfEncoding {
DW_ATE_address =0x1,
DW_ATE_boolean =0x2,
DW_ATE_complex_float =0x3,
DW_ATE_float =0x4,
DW_ATE_signed =0x5,
DW_ATE_signed_char =0x6,
DW_ATE_unsigned =0x7,
DW_ATE_unsigned_char =0x8,
// DWARF3/DWARF3f
DW_ATE_imaginary_float =0x9,
DW_ATE_packed_decimal =0xa,
DW_ATE_numeric_string =0xb,
DW_ATE_edited =0xc,
DW_ATE_signed_fixed =0xd,
DW_ATE_unsigned_fixed =0xe,
DW_ATE_decimal_float =0xf,
DW_ATE_lo_user =0x80,
DW_ATE_hi_user =0xff
};
// Location virtual machine opcodes
enum DwarfOpcode {
DW_OP_addr =0x03,
DW_OP_deref =0x06,
DW_OP_const1u =0x08,
DW_OP_const1s =0x09,
DW_OP_const2u =0x0a,
DW_OP_const2s =0x0b,
DW_OP_const4u =0x0c,
DW_OP_const4s =0x0d,
DW_OP_const8u =0x0e,
DW_OP_const8s =0x0f,
DW_OP_constu =0x10,
DW_OP_consts =0x11,
DW_OP_dup =0x12,
DW_OP_drop =0x13,
DW_OP_over =0x14,
DW_OP_pick =0x15,
DW_OP_swap =0x16,
DW_OP_rot =0x17,
DW_OP_xderef =0x18,
DW_OP_abs =0x19,
DW_OP_and =0x1a,
DW_OP_div =0x1b,
DW_OP_minus =0x1c,
DW_OP_mod =0x1d,
DW_OP_mul =0x1e,
DW_OP_neg =0x1f,
DW_OP_not =0x20,
DW_OP_or =0x21,
DW_OP_plus =0x22,
DW_OP_plus_uconst =0x23,
DW_OP_shl =0x24,
DW_OP_shr =0x25,
DW_OP_shra =0x26,
DW_OP_xor =0x27,
DW_OP_bra =0x28,
DW_OP_eq =0x29,
DW_OP_ge =0x2a,
DW_OP_gt =0x2b,
DW_OP_le =0x2c,
DW_OP_lt =0x2d,
DW_OP_ne =0x2e,
DW_OP_skip =0x2f,
DW_OP_lit0 =0x30,
DW_OP_lit1 =0x31,
DW_OP_lit2 =0x32,
DW_OP_lit3 =0x33,
DW_OP_lit4 =0x34,
DW_OP_lit5 =0x35,
DW_OP_lit6 =0x36,
DW_OP_lit7 =0x37,
DW_OP_lit8 =0x38,
DW_OP_lit9 =0x39,
DW_OP_lit10 =0x3a,
DW_OP_lit11 =0x3b,
DW_OP_lit12 =0x3c,
DW_OP_lit13 =0x3d,
DW_OP_lit14 =0x3e,
DW_OP_lit15 =0x3f,
DW_OP_lit16 =0x40,
DW_OP_lit17 =0x41,
DW_OP_lit18 =0x42,
DW_OP_lit19 =0x43,
DW_OP_lit20 =0x44,
DW_OP_lit21 =0x45,
DW_OP_lit22 =0x46,
DW_OP_lit23 =0x47,
DW_OP_lit24 =0x48,
DW_OP_lit25 =0x49,
DW_OP_lit26 =0x4a,
DW_OP_lit27 =0x4b,
DW_OP_lit28 =0x4c,
DW_OP_lit29 =0x4d,
DW_OP_lit30 =0x4e,
DW_OP_lit31 =0x4f,
DW_OP_reg0 =0x50,
DW_OP_reg1 =0x51,
DW_OP_reg2 =0x52,
DW_OP_reg3 =0x53,
DW_OP_reg4 =0x54,
DW_OP_reg5 =0x55,
DW_OP_reg6 =0x56,
DW_OP_reg7 =0x57,
DW_OP_reg8 =0x58,
DW_OP_reg9 =0x59,
DW_OP_reg10 =0x5a,
DW_OP_reg11 =0x5b,
DW_OP_reg12 =0x5c,
DW_OP_reg13 =0x5d,
DW_OP_reg14 =0x5e,
DW_OP_reg15 =0x5f,
DW_OP_reg16 =0x60,
DW_OP_reg17 =0x61,
DW_OP_reg18 =0x62,
DW_OP_reg19 =0x63,
DW_OP_reg20 =0x64,
DW_OP_reg21 =0x65,
DW_OP_reg22 =0x66,
DW_OP_reg23 =0x67,
DW_OP_reg24 =0x68,
DW_OP_reg25 =0x69,
DW_OP_reg26 =0x6a,
DW_OP_reg27 =0x6b,
DW_OP_reg28 =0x6c,
DW_OP_reg29 =0x6d,
DW_OP_reg30 =0x6e,
DW_OP_reg31 =0x6f,
DW_OP_breg0 =0x70,
DW_OP_breg1 =0x71,
DW_OP_breg2 =0x72,
DW_OP_breg3 =0x73,
DW_OP_breg4 =0x74,
DW_OP_breg5 =0x75,
DW_OP_breg6 =0x76,
DW_OP_breg7 =0x77,
DW_OP_breg8 =0x78,
DW_OP_breg9 =0x79,
DW_OP_breg10 =0x7a,
DW_OP_breg11 =0x7b,
DW_OP_breg12 =0x7c,
DW_OP_breg13 =0x7d,
DW_OP_breg14 =0x7e,
DW_OP_breg15 =0x7f,
DW_OP_breg16 =0x80,
DW_OP_breg17 =0x81,
DW_OP_breg18 =0x82,
DW_OP_breg19 =0x83,
DW_OP_breg20 =0x84,
DW_OP_breg21 =0x85,
DW_OP_breg22 =0x86,
DW_OP_breg23 =0x87,
DW_OP_breg24 =0x88,
DW_OP_breg25 =0x89,
DW_OP_breg26 =0x8a,
DW_OP_breg27 =0x8b,
DW_OP_breg28 =0x8c,
DW_OP_breg29 =0x8d,
DW_OP_breg30 =0x8e,
DW_OP_breg31 =0x8f,
DW_OP_regX =0x90,
DW_OP_fbreg =0x91,
DW_OP_bregX =0x92,
DW_OP_piece =0x93,
DW_OP_deref_size =0x94,
DW_OP_xderef_size =0x95,
DW_OP_nop =0x96,
// DWARF3/DWARF3f
DW_OP_push_object_address =0x97,
DW_OP_call2 =0x98,
DW_OP_call4 =0x99,
DW_OP_call_ref =0x9a,
DW_OP_form_tls_address =0x9b,
DW_OP_call_frame_cfa =0x9c,
DW_OP_bit_piece =0x9d,
DW_OP_lo_user =0xe0,
DW_OP_hi_user =0xff,
// GNU extensions
DW_OP_GNU_push_tls_address =0xe0,
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
DW_OP_GNU_addr_index =0xfb,
DW_OP_GNU_const_index =0xfc
};
// Section identifiers for DWP files
enum DwarfSectionId {
DW_SECT_INFO = 1,
DW_SECT_TYPES = 2,
DW_SECT_ABBREV = 3,
DW_SECT_LINE = 4,
DW_SECT_LOCLISTS = 5,
DW_SECT_STR_OFFSETS = 6,
DW_SECT_MACRO = 7,
DW_SECT_RNGLISTS = 8
};
// Source languages. These are values for DW_AT_language.
enum DwarfLanguage
{
DW_LANG_none =0x0000,
DW_LANG_C89 =0x0001,
DW_LANG_C =0x0002,
DW_LANG_Ada83 =0x0003,
DW_LANG_C_plus_plus =0x0004,
DW_LANG_Cobol74 =0x0005,
DW_LANG_Cobol85 =0x0006,
DW_LANG_Fortran77 =0x0007,
DW_LANG_Fortran90 =0x0008,
DW_LANG_Pascal83 =0x0009,
DW_LANG_Modula2 =0x000a,
DW_LANG_Java =0x000b,
DW_LANG_C99 =0x000c,
DW_LANG_Ada95 =0x000d,
DW_LANG_Fortran95 =0x000e,
DW_LANG_PLI =0x000f,
DW_LANG_ObjC =0x0010,
DW_LANG_ObjC_plus_plus =0x0011,
DW_LANG_UPC =0x0012,
DW_LANG_D =0x0013,
DW_LANG_Rust =0x001c,
DW_LANG_Swift =0x001e,
// Implementation-defined language code range.
DW_LANG_lo_user = 0x8000,
DW_LANG_hi_user = 0xffff,
// Extensions.
// MIPS assembly language. The GNU toolchain uses this for all
// assembly languages, since there's no generic DW_LANG_ value for that.
// See include/dwarf2.h in the binutils, gdb, or gcc source trees.
DW_LANG_Mips_Assembler =0x8001,
DW_LANG_Upc =0x8765 // Unified Parallel C
};
// Inline codes. These are values for DW_AT_inline.
enum DwarfInline {
DW_INL_not_inlined =0x0,
DW_INL_inlined =0x1,
DW_INL_declared_not_inlined =0x2,
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
};
// Exception handling 'z' augmentation letters.
enum DwarfZAugmentationCodes {
// If the CFI augmentation string begins with 'z', then the CIE and FDE
// have an augmentation data area just before the instructions, whose
// contents are determined by the subsequent augmentation letters.
DW_Z_augmentation_start = 'z',
// If this letter is present in a 'z' augmentation string, the CIE
// augmentation data includes a pointer encoding, and the FDE
// augmentation data includes a language-specific data area pointer,
// represented using that encoding.
DW_Z_has_LSDA = 'L',
// If this letter is present in a 'z' augmentation string, the CIE
// augmentation data includes a pointer encoding, followed by a pointer
// to a personality routine, represented using that encoding.
DW_Z_has_personality_routine = 'P',
// If this letter is present in a 'z' augmentation string, the CIE
// augmentation data includes a pointer encoding describing how the FDE's
// initial location, address range, and DW_CFA_set_loc operands are
// encoded.
DW_Z_has_FDE_address_encoding = 'R',
// If this letter is present in a 'z' augmentation string, then code
// addresses covered by FDEs that cite this CIE are signal delivery
// trampolines. Return addresses of frames in trampolines should not be
// adjusted as described in section 6.4.4 of the DWARF 3 spec.
DW_Z_is_signal_trampoline = 'S'
};
// Exception handling frame description pointer formats, as described
// by the Linux Standard Base Core Specification 4.0, section 11.5,
// DWARF Extensions.
enum DwarfPointerEncoding
{
DW_EH_PE_absptr = 0x00,
DW_EH_PE_omit = 0xff,
DW_EH_PE_uleb128 = 0x01,
DW_EH_PE_udata2 = 0x02,
DW_EH_PE_udata4 = 0x03,
DW_EH_PE_udata8 = 0x04,
DW_EH_PE_sleb128 = 0x09,
DW_EH_PE_sdata2 = 0x0A,
DW_EH_PE_sdata4 = 0x0B,
DW_EH_PE_sdata8 = 0x0C,
DW_EH_PE_pcrel = 0x10,
DW_EH_PE_textrel = 0x20,
DW_EH_PE_datarel = 0x30,
DW_EH_PE_funcrel = 0x40,
DW_EH_PE_aligned = 0x50,
// The GNU toolchain sources define this enum value as well,
// simply to help classify the lower nybble values into signed and
// unsigned groups.
DW_EH_PE_signed = 0x08,
// This is not documented in LSB 4.0, but it is used in both the
// Linux and OS X toolchains. It can be added to any other
// encoding (except DW_EH_PE_aligned), and indicates that the
// encoded value represents the address at which the true address
// is stored, not the true address itself.
DW_EH_PE_indirect = 0x80
};
} // namespace google_breakpad
#endif // COMMON_DWARF_DWARF2ENUMS_H__

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,968 @@
// Copyright 2012 Google LLC
//
// 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 LLC 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>
// dwarf2reader_die_unittest.cc: Unit tests for google_breakpad::CompilationUnit
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdint.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <vector>
#include "breakpad_googletest_includes.h"
#include "common/dwarf/bytereader-inl.h"
#include "common/dwarf/dwarf2reader_test_common.h"
#include "common/dwarf/dwarf2reader.h"
#include "common/using_std_string.h"
#include "google_breakpad/common/breakpad_types.h"
using google_breakpad::test_assembler::Endianness;
using google_breakpad::test_assembler::Label;
using google_breakpad::test_assembler::Section;
using google_breakpad::test_assembler::kBigEndian;
using google_breakpad::test_assembler::kLittleEndian;
using google_breakpad::ByteReader;
using google_breakpad::CompilationUnit;
using google_breakpad::Dwarf2Handler;
using google_breakpad::DwarfAttribute;
using google_breakpad::DwarfForm;
using google_breakpad::DwarfHasChild;
using google_breakpad::DwarfTag;
using google_breakpad::ENDIANNESS_BIG;
using google_breakpad::ENDIANNESS_LITTLE;
using google_breakpad::SectionMap;
using std::vector;
using testing::InSequence;
using testing::Pointee;
using testing::Return;
using testing::Sequence;
using testing::Test;
using testing::TestWithParam;
using testing::_;
class MockDwarf2Handler: public Dwarf2Handler {
public:
MOCK_METHOD5(StartCompilationUnit, bool(uint64_t offset, uint8_t address_size,
uint8_t offset_size,
uint64_t cu_length,
uint8_t dwarf_version));
MOCK_METHOD2(StartDIE, bool(uint64_t offset, enum DwarfTag tag));
MOCK_METHOD4(ProcessAttributeUnsigned, void(uint64_t offset,
DwarfAttribute attr,
enum DwarfForm form,
uint64_t data));
MOCK_METHOD4(ProcessAttributeSigned, void(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
int64_t data));
MOCK_METHOD4(ProcessAttributeReference, void(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data));
MOCK_METHOD5(ProcessAttributeBuffer, void(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const uint8_t* data,
uint64_t len));
MOCK_METHOD4(ProcessAttributeString, void(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const string& data));
MOCK_METHOD4(ProcessAttributeSignature, void(uint64_t offset,
DwarfAttribute attr,
enum DwarfForm form,
uint64_t signature));
MOCK_METHOD1(EndDIE, void(uint64_t offset));
};
struct DIEFixture {
DIEFixture() {
// Fix the initial offset of the .debug_info and .debug_abbrev sections.
info.start() = 0;
abbrevs.start() = 0;
// Default expectations for the data handler.
EXPECT_CALL(handler, StartCompilationUnit(_, _, _, _, _)).Times(0);
EXPECT_CALL(handler, StartDIE(_, _)).Times(0);
EXPECT_CALL(handler, ProcessAttributeUnsigned(_, _, _, _)).Times(0);
EXPECT_CALL(handler, ProcessAttributeSigned(_, _, _, _)).Times(0);
EXPECT_CALL(handler, ProcessAttributeReference(_, _, _, _)).Times(0);
EXPECT_CALL(handler, ProcessAttributeBuffer(_, _, _, _, _)).Times(0);
EXPECT_CALL(handler, ProcessAttributeString(_, _, _, _)).Times(0);
EXPECT_CALL(handler, EndDIE(_)).Times(0);
}
// Return a reference to a section map whose .debug_info section refers
// to |info|, and whose .debug_abbrev section refers to |abbrevs|. This
// function returns a reference to the same SectionMap each time; new
// calls wipe out maps established by earlier calls.
const SectionMap& MakeSectionMap() {
// Copy the sections' contents into strings that will live as long as
// the map itself.
assert(info.GetContents(&info_contents));
assert(abbrevs.GetContents(&abbrevs_contents));
section_map.clear();
section_map[".debug_info"].first
= reinterpret_cast<const uint8_t*>(info_contents.data());
section_map[".debug_info"].second = info_contents.size();
section_map[".debug_abbrev"].first
= reinterpret_cast<const uint8_t*>(abbrevs_contents.data());
section_map[".debug_abbrev"].second = abbrevs_contents.size();
return section_map;
}
TestCompilationUnit info;
TestAbbrevTable abbrevs;
MockDwarf2Handler handler;
string abbrevs_contents, info_contents;
SectionMap section_map;
};
struct DwarfHeaderParams {
DwarfHeaderParams(Endianness endianness, size_t format_size,
int version, size_t address_size, int header_type)
: endianness(endianness), format_size(format_size),
version(version), address_size(address_size), header_type(header_type)
{ }
Endianness endianness;
size_t format_size; // 4-byte or 8-byte DWARF offsets
int version;
size_t address_size;
int header_type; // DW_UT_{compile, type, partial, skeleton, etc}
};
class DwarfHeader: public DIEFixture,
public TestWithParam<DwarfHeaderParams> { };
TEST_P(DwarfHeader, Header) {
Label abbrev_table = abbrevs.Here();
abbrevs.Abbrev(1, google_breakpad::DW_TAG_compile_unit,
google_breakpad::DW_children_yes)
.Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_string)
.EndAbbrev()
.EndTable();
info.set_format_size(GetParam().format_size);
info.set_endianness(GetParam().endianness);
info.Header(GetParam().version, abbrev_table, GetParam().address_size,
google_breakpad::DW_UT_compile)
.ULEB128(1) // DW_TAG_compile_unit, with children
.AppendCString("sam") // DW_AT_name, DW_FORM_string
.D8(0); // end of children
info.Finish();
{
InSequence s;
EXPECT_CALL(handler,
StartCompilationUnit(0, GetParam().address_size,
GetParam().format_size, _,
GetParam().version))
.WillOnce(Return(true));
EXPECT_CALL(handler, StartDIE(_, google_breakpad::DW_TAG_compile_unit))
.WillOnce(Return(true));
EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name,
google_breakpad::DW_FORM_string,
"sam"))
.WillOnce(Return());
EXPECT_CALL(handler, EndDIE(_))
.WillOnce(Return());
}
ByteReader byte_reader(GetParam().endianness == kLittleEndian ?
ENDIANNESS_LITTLE : ENDIANNESS_BIG);
CompilationUnit parser("", MakeSectionMap(), 0, &byte_reader, &handler);
EXPECT_EQ(parser.Start(), info_contents.size());
}
TEST_P(DwarfHeader, TypeUnitHeader) {
Label abbrev_table = abbrevs.Here();
int version = 5;
abbrevs.Abbrev(1, google_breakpad::DW_TAG_type_unit,
google_breakpad::DW_children_yes)
.Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_string)
.EndAbbrev()
.EndTable();
info.set_format_size(GetParam().format_size);
info.set_endianness(GetParam().endianness);
info.Header(version, abbrev_table, GetParam().address_size,
google_breakpad::DW_UT_type)
.ULEB128(0x41) // DW_TAG_type_unit, with children
.AppendCString("sam") // DW_AT_name, DW_FORM_string
.D8(0); // end of children
info.Finish();
{
InSequence s;
EXPECT_CALL(handler,
StartCompilationUnit(0, GetParam().address_size,
GetParam().format_size, _,
version))
.WillOnce(Return(true));
// If the type unit is handled properly, these calls will be skipped.
EXPECT_CALL(handler, StartDIE(_, google_breakpad::DW_TAG_type_unit))
.Times(0);
EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name,
google_breakpad::DW_FORM_string,
"sam"))
.Times(0);
EXPECT_CALL(handler, EndDIE(_))
.Times(0);
}
ByteReader byte_reader(GetParam().endianness == kLittleEndian ?
ENDIANNESS_LITTLE : ENDIANNESS_BIG);
CompilationUnit parser("", MakeSectionMap(), 0, &byte_reader, &handler);
EXPECT_EQ(parser.Start(), info_contents.size());
}
INSTANTIATE_TEST_SUITE_P(
HeaderVariants, DwarfHeader,
::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4, 1),
DwarfHeaderParams(kLittleEndian, 4, 2, 8, 1),
DwarfHeaderParams(kLittleEndian, 4, 3, 4, 1),
DwarfHeaderParams(kLittleEndian, 4, 3, 8, 1),
DwarfHeaderParams(kLittleEndian, 4, 4, 4, 1),
DwarfHeaderParams(kLittleEndian, 4, 4, 8, 1),
DwarfHeaderParams(kLittleEndian, 8, 2, 4, 1),
DwarfHeaderParams(kLittleEndian, 8, 2, 8, 1),
DwarfHeaderParams(kLittleEndian, 8, 3, 4, 1),
DwarfHeaderParams(kLittleEndian, 8, 3, 8, 1),
DwarfHeaderParams(kLittleEndian, 8, 4, 4, 1),
DwarfHeaderParams(kLittleEndian, 8, 4, 8, 1),
DwarfHeaderParams(kLittleEndian, 8, 5, 4, 1),
DwarfHeaderParams(kLittleEndian, 8, 5, 8, 1),
DwarfHeaderParams(kBigEndian, 4, 2, 4, 1),
DwarfHeaderParams(kBigEndian, 4, 2, 8, 1),
DwarfHeaderParams(kBigEndian, 4, 3, 4, 1),
DwarfHeaderParams(kBigEndian, 4, 3, 8, 1),
DwarfHeaderParams(kBigEndian, 4, 4, 4, 1),
DwarfHeaderParams(kBigEndian, 4, 4, 8, 1),
DwarfHeaderParams(kBigEndian, 8, 2, 4, 1),
DwarfHeaderParams(kBigEndian, 8, 2, 8, 1),
DwarfHeaderParams(kBigEndian, 8, 3, 4, 1),
DwarfHeaderParams(kBigEndian, 8, 3, 8, 1),
DwarfHeaderParams(kBigEndian, 8, 4, 4, 1),
DwarfHeaderParams(kBigEndian, 8, 4, 8, 1),
DwarfHeaderParams(kBigEndian, 8, 5, 4, 1),
DwarfHeaderParams(kBigEndian, 8, 5, 8, 1)));
struct DwarfFormsFixture: public DIEFixture {
// Start a compilation unit, as directed by |params|, containing one
// childless DIE of the given tag, with one attribute of the given name
// and form. The 'info' fixture member is left just after the abbrev
// code, waiting for the attribute value to be appended.
void StartSingleAttributeDIE(const DwarfHeaderParams& params,
DwarfTag tag, DwarfAttribute name,
DwarfForm form) {
// Create the abbreviation table.
Label abbrev_table = abbrevs.Here();
abbrevs.Abbrev(1, tag, google_breakpad::DW_children_no)
.Attribute(name, form)
.EndAbbrev()
.EndTable();
// Create the compilation unit, up to the attribute value.
info.set_format_size(params.format_size);
info.set_endianness(params.endianness);
info.Header(params.version, abbrev_table, params.address_size,
google_breakpad::DW_UT_compile)
.ULEB128(1); // abbrev code
}
// Set up handler to expect a compilation unit matching |params|,
// containing one childless DIE of the given tag, in the sequence s. Stop
// just before the expectations.
void ExpectBeginCompilationUnit(const DwarfHeaderParams& params,
DwarfTag tag, uint64_t offset=0) {
EXPECT_CALL(handler,
StartCompilationUnit(offset, params.address_size,
params.format_size, _,
params.version))
.InSequence(s)
.WillOnce(Return(true));
EXPECT_CALL(handler, StartDIE(_, tag))
.InSequence(s)
.WillOnce(Return(true));
}
void ExpectEndCompilationUnit() {
EXPECT_CALL(handler, EndDIE(_))
.InSequence(s)
.WillOnce(Return());
}
void ParseCompilationUnit(const DwarfHeaderParams& params,
uint64_t offset=0) {
ByteReader byte_reader(params.endianness == kLittleEndian ?
ENDIANNESS_LITTLE : ENDIANNESS_BIG);
CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader,
&handler);
EXPECT_EQ(offset + parser.Start(), info_contents.size());
}
// The sequence to which the fixture's methods append expectations.
Sequence s;
};
struct DwarfForms: public DwarfFormsFixture,
public TestWithParam<DwarfHeaderParams> { };
TEST_P(DwarfForms, addr) {
StartSingleAttributeDIE(GetParam(), google_breakpad::DW_TAG_compile_unit,
google_breakpad::DW_AT_low_pc,
google_breakpad::DW_FORM_addr);
uint64_t value;
if (GetParam().address_size == 4) {
value = 0xc8e9ffcc;
info.D32(value);
} else {
value = 0xe942517fc2768564ULL;
info.D64(value);
}
info.Finish();
ExpectBeginCompilationUnit(GetParam(), google_breakpad::DW_TAG_compile_unit);
EXPECT_CALL(handler, ProcessAttributeUnsigned(_, google_breakpad::DW_AT_low_pc,
google_breakpad::DW_FORM_addr,
value))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam());
}
TEST_P(DwarfForms, strx1) {
if (GetParam().version != 5) {
return;
}
Label abbrev_table = abbrevs.Here();
abbrevs.Abbrev(1, google_breakpad::DW_TAG_compile_unit,
google_breakpad::DW_children_no)
.Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_strx1)
.Attribute(google_breakpad::DW_AT_low_pc, google_breakpad::DW_FORM_addr)
.Attribute(google_breakpad::DW_AT_str_offsets_base,
google_breakpad::DW_FORM_sec_offset)
.EndAbbrev()
.EndTable();
info.set_format_size(GetParam().format_size);
info.set_endianness(GetParam().endianness);
info.Header(GetParam().version, abbrev_table, GetParam().address_size,
google_breakpad::DW_UT_compile)
.ULEB128(1) // abbrev index
.D8(2); // string index
uint64_t value;
uint64_t offsets_base;
if (GetParam().address_size == 4) {
value = 0xc8e9ffcc;
offsets_base = 8;
info.D32(value); // low pc
info.D32(offsets_base); // str_offsets_base
} else {
value = 0xe942517fc2768564ULL;
offsets_base = 16;
info.D64(value); // low_pc
info.D64(offsets_base); // str_offsets_base
}
info.Finish();
Section debug_strings;
// no header, just a series of null-terminated strings.
debug_strings.AppendCString("apple"); // offset = 0
debug_strings.AppendCString("bird"); // offset = 6
debug_strings.AppendCString("canary"); // offset = 11
debug_strings.AppendCString("dinosaur"); // offset = 18
Section str_offsets;
str_offsets.set_endianness(GetParam().endianness);
// Header for .debug_str_offsets
if (GetParam().address_size == 4) {
str_offsets.D32(24); // section length (4 bytes)
} else {
str_offsets.D32(0xffffffff);
str_offsets.D64(48); // section length (12 bytes)
}
str_offsets.D16(GetParam().version); // version (2 bytes)
str_offsets.D16(0); // padding (2 bytes)
// .debug_str_offsets data (the offsets)
if (GetParam().address_size == 4) {
str_offsets.D32(0);
str_offsets.D32(6);
str_offsets.D32(11);
str_offsets.D32(18);
} else {
str_offsets.D64(0);
str_offsets.D64(6);
str_offsets.D64(11);
str_offsets.D64(18);
}
ExpectBeginCompilationUnit(GetParam(), google_breakpad::DW_TAG_compile_unit);
EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name,
google_breakpad::DW_FORM_strx1,
"bird"))
.WillOnce(Return());
EXPECT_CALL(handler, ProcessAttributeUnsigned(_, google_breakpad::DW_AT_low_pc,
google_breakpad::DW_FORM_addr,
value))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam());
}
TEST_P(DwarfForms, block2_empty) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
(DwarfAttribute) 0xe52c4463,
google_breakpad::DW_FORM_block2);
info.D16(0);
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
google_breakpad::DW_FORM_block2,
_, 0))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam());
}
TEST_P(DwarfForms, block2) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
(DwarfAttribute) 0xe52c4463,
google_breakpad::DW_FORM_block2);
unsigned char data[258];
memset(data, '*', sizeof(data));
info.D16(sizeof(data))
.Append(data, sizeof(data));
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
google_breakpad::DW_FORM_block2,
Pointee('*'), 258))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam());
}
TEST_P(DwarfForms, flag_present) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2,
(DwarfAttribute) 0x359d1972,
google_breakpad::DW_FORM_flag_present);
// DW_FORM_flag_present occupies no space in the DIE.
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2);
EXPECT_CALL(handler,
ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972,
google_breakpad::DW_FORM_flag_present,
1))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam());
}
TEST_P(DwarfForms, sec_offset) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689,
(DwarfAttribute) 0xa060bfd1,
google_breakpad::DW_FORM_sec_offset);
uint64_t value;
if (GetParam().format_size == 4) {
value = 0xacc9c388;
info.D32(value);
} else {
value = 0xcffe5696ffe3ed0aULL;
info.D64(value);
}
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689);
EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1,
google_breakpad::DW_FORM_sec_offset,
value))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam());
}
TEST_P(DwarfForms, exprloc) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb,
(DwarfAttribute) 0xba3ae5cb,
google_breakpad::DW_FORM_exprloc);
info.ULEB128(29)
.Append(29, 173);
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb);
EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb,
google_breakpad::DW_FORM_exprloc,
Pointee(173), 29))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam());
}
TEST_P(DwarfForms, ref_sig8) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
(DwarfAttribute) 0xd708d908,
google_breakpad::DW_FORM_ref_sig8);
info.D64(0xf72fa0cb6ddcf9d6ULL);
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b);
EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
google_breakpad::DW_FORM_ref_sig8,
0xf72fa0cb6ddcf9d6ULL))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam());
}
// A value passed to ProcessAttributeSignature is just an absolute number,
// not an offset within the compilation unit as most of the other
// DW_FORM_ref forms are. Check that the reader doesn't try to apply any
// offset to the signature, by reading it from a compilation unit that does
// not start at the beginning of the section.
TEST_P(DwarfForms, ref_sig8_not_first) {
info.Append(98, '*');
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
(DwarfAttribute) 0xd708d908,
google_breakpad::DW_FORM_ref_sig8);
info.D64(0xf72fa0cb6ddcf9d6ULL);
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98);
EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
google_breakpad::DW_FORM_ref_sig8,
0xf72fa0cb6ddcf9d6ULL))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam(), 98);
}
TEST_P(DwarfForms, implicit_const) {
const DwarfHeaderParams& params = GetParam();
const uint64_t implicit_constant_value = 0x1234;
// Create the abbreviation table.
Label abbrev_table = abbrevs.Here();
abbrevs.Abbrev(1, (DwarfTag) 0x253e7b2b, google_breakpad::DW_children_no)
.Attribute((DwarfAttribute) 0xd708d908,
google_breakpad::DW_FORM_implicit_const)
.ULEB128(implicit_constant_value);
abbrevs.EndAbbrev().EndTable();
info.set_format_size(params.format_size);
info.set_endianness(params.endianness);
info.Header(params.version, abbrev_table, params.address_size,
google_breakpad::DW_UT_compile)
.ULEB128(1); // abbrev code
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b);
EXPECT_CALL(handler,
ProcessAttributeUnsigned(_, (DwarfAttribute) 0xd708d908,
google_breakpad::DW_FORM_implicit_const,
implicit_constant_value))
.InSequence(s)
.WillOnce(Return());
ExpectEndCompilationUnit();
ParseCompilationUnit(GetParam());
}
// Tests for the other attribute forms could go here.
INSTANTIATE_TEST_SUITE_P(
HeaderVariants, DwarfForms,
::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4, 1),
DwarfHeaderParams(kLittleEndian, 4, 2, 8, 1),
DwarfHeaderParams(kLittleEndian, 4, 3, 4, 1),
DwarfHeaderParams(kLittleEndian, 4, 3, 8, 1),
DwarfHeaderParams(kLittleEndian, 4, 4, 4, 1),
DwarfHeaderParams(kLittleEndian, 4, 4, 8, 1),
DwarfHeaderParams(kLittleEndian, 8, 2, 4, 1),
DwarfHeaderParams(kLittleEndian, 8, 2, 8, 1),
DwarfHeaderParams(kLittleEndian, 8, 3, 4, 1),
DwarfHeaderParams(kLittleEndian, 8, 3, 8, 1),
DwarfHeaderParams(kLittleEndian, 8, 4, 4, 1),
DwarfHeaderParams(kLittleEndian, 8, 4, 8, 1),
DwarfHeaderParams(kBigEndian, 4, 2, 4, 1),
DwarfHeaderParams(kBigEndian, 4, 2, 8, 1),
DwarfHeaderParams(kBigEndian, 4, 3, 4, 1),
DwarfHeaderParams(kBigEndian, 4, 3, 8, 1),
DwarfHeaderParams(kBigEndian, 4, 4, 4, 1),
DwarfHeaderParams(kBigEndian, 4, 4, 8, 1),
DwarfHeaderParams(kBigEndian, 8, 2, 4, 1),
DwarfHeaderParams(kBigEndian, 8, 2, 8, 1),
DwarfHeaderParams(kBigEndian, 8, 3, 4, 1),
DwarfHeaderParams(kBigEndian, 8, 3, 8, 1),
DwarfHeaderParams(kBigEndian, 8, 4, 4, 1),
DwarfHeaderParams(kBigEndian, 8, 4, 8, 1)));
class MockRangeListHandler: public google_breakpad::RangeListHandler {
public:
MOCK_METHOD(void, AddRange, (uint64_t begin, uint64_t end));
MOCK_METHOD(void, Finish, ());
};
TEST(RangeList, Dwarf4ReadRangeList) {
using google_breakpad::RangeListReader;
using google_breakpad::DW_FORM_sec_offset;
// Create a dwarf4 .debug_ranges section.
google_breakpad::test_assembler::Section ranges(kBigEndian);
std::string padding_offset = "padding offset";
ranges.Append(padding_offset);
const uint64_t section_offset = ranges.Size();
ranges.D32(1).D32(2); // (2, 3)
ranges.D32(0xFFFFFFFF).D32(3); // base_address = 3.
ranges.D32(1).D32(2); // (4, 5)
ranges.D32(0).D32(1); // (3, 4) An out of order entry is legal.
ranges.D32(0).D32(0); // End of range.
std::string section_contents;
ranges.GetContents(&section_contents);
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(4);
RangeListReader::CURangesInfo cu_info;
// Only set the fields that matter for dwarf 4.
cu_info.version_ = 4;
cu_info.base_address_ = 1;
cu_info.buffer_ = reinterpret_cast<const uint8_t*>(section_contents.data());
cu_info.size_ = section_contents.size();
MockRangeListHandler handler;
google_breakpad::RangeListReader range_list_reader(&byte_reader, &cu_info,
&handler);
EXPECT_CALL(handler, AddRange(2, 3));
EXPECT_CALL(handler, AddRange(4, 5));
EXPECT_CALL(handler, AddRange(3, 4));
EXPECT_CALL(handler, Finish());
EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset,
section_offset));
}
TEST(RangeList, Dwarf5ReadRangeList_rnglists) {
using google_breakpad::RangeListReader;
using google_breakpad::DW_RLE_base_addressx;
using google_breakpad::DW_RLE_startx_endx;
using google_breakpad::DW_RLE_startx_length;
using google_breakpad::DW_RLE_offset_pair;
using google_breakpad::DW_RLE_end_of_list;
using google_breakpad::DW_RLE_base_address;
using google_breakpad::DW_RLE_start_end;
using google_breakpad::DW_RLE_start_length;
using google_breakpad::DW_FORM_sec_offset;
using google_breakpad::DW_FORM_rnglistx;
// Size of header
const uint64_t header_size = 12;
// Size of length field in header
const uint64_t length_size = 4;
// .debug_addr for the indexed entries like startx.
Section addr;
addr.set_endianness(kBigEndian);
// Test addr_base handling with a padding address at 0.
addr.D32(0).D32(1).D32(2).D32(3).D32(4);
std::string addr_contents;
assert(addr.GetContents(&addr_contents));
// .debug_rnglists is the dwarf 5 section.
Section rnglists1(kBigEndian);
Section rnglists2(kBigEndian);
// First header and body.
Label section_size1;
rnglists1.Append(kBigEndian, length_size, section_size1);
rnglists1.D16(5); // Version
rnglists1.D8(4); // Address size
rnglists1.D8(0); // Segment selector size
rnglists1.D32(2); // Offset entry count
const uint64_t ranges_base_1 = rnglists1.Size();
// Offset entries.
Label range0;
rnglists1.Append(kBigEndian, 4, range0);
Label range1;
rnglists1.Append(kBigEndian, 4, range1);
// Range 0 (will be read via DW_AT_ranges, DW_FORM_rnglistx).
range0 = rnglists1.Size() - header_size;
rnglists1.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1
rnglists1.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3)
rnglists1.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5)
rnglists1.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7)
rnglists1.D8(DW_RLE_end_of_list);
// Range 1 (will be read via DW_AT_ranges, DW_FORM_rnglistx).
range1 = rnglists1.Size() - header_size;
rnglists1.D8(DW_RLE_base_address).D32(8); // base_addr = 8
rnglists1.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [9, 10)
rnglists1.D8(DW_RLE_start_end).D32(10).D32(11); // [10, 11)
rnglists1.D8(DW_RLE_start_length).D32(12).ULEB128(1); // [12, 13)
rnglists1.D8(DW_RLE_end_of_list);
// The size doesn't include the size of length field itself.
section_size1 = rnglists1.Size() - length_size;
// Second header and body.
Label section_size2;
rnglists2.Append(kBigEndian, length_size, section_size2);
rnglists2.D16(5); // Version
rnglists2.D8(4); // Address size
rnglists2.D8(0); // Segment selector size
rnglists2.D32(2); // Offset entry count
const uint64_t ranges_base_2 = rnglists1.Size() + rnglists2.Size();
// Offset entries.
Label range2;
rnglists2.Append(kBigEndian, 4, range2);
Label range3;
rnglists2.Append(kBigEndian, 4, range3);
// Range 2 (will be read via DW_AT_ranges, DW_FORM_sec_offset).
range2 = rnglists2.Size() - header_size;
rnglists2.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1
rnglists2.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3)
rnglists2.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5)
rnglists2.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7)
rnglists2.D8(DW_RLE_end_of_list);
// Range 3 (will be read via DW_AT_ranges, DW_FORM_rnglistx).
range3 = rnglists2.Size() - header_size;
rnglists2.D8(DW_RLE_base_address).D32(15); // base_addr = 15
rnglists2.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [16, 17)
rnglists2.D8(DW_RLE_start_end).D32(17).D32(18); // [17, 18)
rnglists2.D8(DW_RLE_start_length).D32(19).ULEB128(1); // [19, 20)
rnglists2.D8(DW_RLE_end_of_list);
// The size doesn't include the size of length field itself.
section_size2 = rnglists2.Size() - length_size;
rnglists1.Append(rnglists2);
string rnglists_contents;
assert(rnglists1.GetContents(&rnglists_contents));
RangeListReader::CURangesInfo cu_info;
cu_info.version_ = 5;
cu_info.base_address_ = 1;
cu_info.ranges_base_ = ranges_base_1;
cu_info.buffer_ =
reinterpret_cast<const uint8_t*>(rnglists_contents.data());
cu_info.size_ = rnglists_contents.size();
cu_info.addr_buffer_ =
reinterpret_cast<const uint8_t*>(addr_contents.data());
cu_info.addr_buffer_size_ = addr_contents.size();
cu_info.addr_base_ = 4;
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetOffsetSize(4);
byte_reader.SetAddressSize(4);
MockRangeListHandler handler;
google_breakpad::RangeListReader range_list_reader1(&byte_reader, &cu_info,
&handler);
EXPECT_CALL(handler, AddRange(2, 3));
EXPECT_CALL(handler, AddRange(4, 5));
EXPECT_CALL(handler, AddRange(6, 7));
EXPECT_CALL(handler, AddRange(9, 10));
EXPECT_CALL(handler, AddRange(10, 11));
EXPECT_CALL(handler, AddRange(12, 13));
EXPECT_CALL(handler, Finish()).Times(2);
EXPECT_TRUE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 0));
EXPECT_TRUE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 1));
// Out of range index, should result in no calls.
EXPECT_FALSE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 2));
// Set to new ranges_base
cu_info.ranges_base_ = ranges_base_2;
google_breakpad::RangeListReader range_list_reader2(&byte_reader, &cu_info,
&handler);
EXPECT_CALL(handler, AddRange(2, 3));
EXPECT_CALL(handler, AddRange(4, 5));
EXPECT_CALL(handler, AddRange(6, 7));
EXPECT_CALL(handler, AddRange(16, 17));
EXPECT_CALL(handler, AddRange(17, 18));
EXPECT_CALL(handler, AddRange(19, 20));
EXPECT_CALL(handler, Finish()).Times(2);
EXPECT_TRUE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 0));
EXPECT_TRUE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 1));
// Out of range index, should result in no calls.
EXPECT_FALSE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 2));
}
TEST(RangeList, Dwarf5ReadRangeList_sec_offset) {
using google_breakpad::RangeListReader;
using google_breakpad::DW_RLE_base_addressx;
using google_breakpad::DW_RLE_startx_endx;
using google_breakpad::DW_RLE_startx_length;
using google_breakpad::DW_RLE_offset_pair;
using google_breakpad::DW_RLE_end_of_list;
using google_breakpad::DW_RLE_base_address;
using google_breakpad::DW_RLE_start_end;
using google_breakpad::DW_RLE_start_length;
using google_breakpad::DW_FORM_sec_offset;
using google_breakpad::DW_FORM_rnglistx;
// Size of length field in header
const uint64_t length_size = 4;
// .debug_addr for the indexed entries like startx.
Section addr;
addr.set_endianness(kBigEndian);
// Test addr_base handling with a padding address at 0.
addr.D32(0).D32(1).D32(2).D32(3).D32(4).D32(21).D32(22);
std::string addr_contents;
assert(addr.GetContents(&addr_contents));
// .debug_rnglists is the dwarf 5 section.
Section rnglists1(kBigEndian);
Section rnglists2(kBigEndian);
// First header and body.
Label section_size1;
rnglists1.Append(kBigEndian, length_size, section_size1);
rnglists1.D16(5); // Version
rnglists1.D8(4); // Address size
rnglists1.D8(0); // Segment selector size
rnglists1.D32(0); // Offset entry count
const uint64_t offset1 = rnglists1.Size();
rnglists1.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1
rnglists1.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3)
rnglists1.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5)
rnglists1.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7)
rnglists1.D8(DW_RLE_base_address).D32(8); // base_addr = 8
rnglists1.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [9, 10)
rnglists1.D8(DW_RLE_start_end).D32(10).D32(11); // [10, 11)
rnglists1.D8(DW_RLE_start_length).D32(12).ULEB128(1); // [12, 13)
rnglists1.D8(DW_RLE_end_of_list);
// The size doesn't include the size of length field itself.
section_size1 = rnglists1.Size() - length_size;
// Second header and body.
Label section_size2;
rnglists2.Append(kBigEndian, length_size, section_size2);
rnglists2.D16(5); // Version
rnglists2.D8(4); // Address size
rnglists2.D8(0); // Segment selector size
rnglists2.D32(0); // Offset entry count
const uint64_t offset2 = rnglists1.Size() + rnglists2.Size();
rnglists2.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1
rnglists2.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3)
rnglists2.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5)
rnglists2.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7)
rnglists2.D8(DW_RLE_base_address).D32(15); // base_addr = 15
rnglists2.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [16, 17)
rnglists2.D8(DW_RLE_start_end).D32(17).D32(18); // [17, 18)
rnglists2.D8(DW_RLE_start_length).D32(19).ULEB128(1); // [19, 20)
rnglists2.D8(DW_RLE_end_of_list);
// The size doesn't include the size of length field itself.
section_size2 = rnglists2.Size() - length_size;
rnglists1.Append(rnglists2);
string rnglists_contents;
assert(rnglists1.GetContents(&rnglists_contents));
RangeListReader::CURangesInfo cu_info;
cu_info.version_ = 5;
cu_info.base_address_ = 1;
cu_info.buffer_ =
reinterpret_cast<const uint8_t*>(rnglists_contents.data());
cu_info.size_ = rnglists_contents.size();
cu_info.addr_buffer_ =
reinterpret_cast<const uint8_t*>(addr_contents.data());
cu_info.addr_buffer_size_ = addr_contents.size();
cu_info.addr_base_ = 4;
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetOffsetSize(4);
byte_reader.SetAddressSize(4);
MockRangeListHandler handler;
google_breakpad::RangeListReader range_list_reader(&byte_reader, &cu_info,
&handler);
EXPECT_CALL(handler, AddRange(2, 3));
EXPECT_CALL(handler, AddRange(4, 5));
EXPECT_CALL(handler, AddRange(6, 7));
EXPECT_CALL(handler, AddRange(9, 10));
EXPECT_CALL(handler, AddRange(10, 11));
EXPECT_CALL(handler, AddRange(12, 13));
EXPECT_CALL(handler, Finish()).Times(1);
EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, offset1));
// Out of range index, should result in no calls.
EXPECT_FALSE(range_list_reader.ReadRanges(DW_FORM_sec_offset,
rnglists_contents.size()));
EXPECT_CALL(handler, AddRange(2, 3));
EXPECT_CALL(handler, AddRange(4, 5));
EXPECT_CALL(handler, AddRange(6, 7));
EXPECT_CALL(handler, AddRange(16, 17));
EXPECT_CALL(handler, AddRange(17, 18));
EXPECT_CALL(handler, AddRange(19, 20));
EXPECT_CALL(handler, Finish()).Times(1);
EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, offset2));
// Out of range index, should result in no calls.
EXPECT_FALSE(range_list_reader.ReadRanges(DW_FORM_sec_offset,
rnglists_contents.size()));
}

View file

@ -0,0 +1,190 @@
// Copyright 2020 Google LLC
//
// 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 LLC 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: Sterling Augustine <saugustine@google.com>
// dwarf2reader_lineinfo_unittest.cc: Unit tests for google_breakpad::LineInfo
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdint.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include "breakpad_googletest_includes.h"
#include "common/dwarf/bytereader.h"
#include "common/dwarf/dwarf2reader.h"
#include "google_breakpad/common/breakpad_types.h"
using std::vector;
using testing::InSequence;
using testing::Return;
using testing::Sequence;
using testing::Test;
using testing::_;
using namespace google_breakpad;
namespace {
const uint8_t dwarf5_line_program[] = {
0x40, 0x0, 0x0, 0x0, // unit_length (end - begin)
// begin
0x05, 0x0, // version
0x8, // address_size
0x0, // segment_selector_size
0x26, 0x0, 0x0, 0x0, // header_length (end_header_end - begin_header)
// begin_header:
0x1, // minimum_instruction_length
0x1, // maximum_operations_per_instruction
0x1, // default_is_stmt
0xfb, // line_base
0xe, // line_range
0xd, // opcode_base and lengths
0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1,
0x1, // directory entry format count
DW_LNCT_path, DW_FORM_strp,
0x1, // directories count
0x1, 0x0, 0x0, 0x0, // offset into .debug_line_str
0x2, // file_name_entry_format_count
DW_LNCT_directory_index, DW_FORM_data1,
DW_LNCT_path, DW_FORM_line_strp,
0x1, // filename count
0x0, // directory index
0x1, 0x0, 0x0, 0x0, // offset into .debug_str
// end_header
DW_LNS_set_file, 0x0,
// set address to 0x0
0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
// Advance Address by 0 and line by 3
0x15,
// Advance PC by 1
0x2, 0x1,
0x0,
DW_LNE_end_sequence,
DW_LNE_end_sequence,
// end
};
const uint8_t dwarf4_line_program[] = {
0x37, 0x0, 0x0, 0x0, // unit_length (end - begin)
// begin
0x04, 0x0, // version
0x1d, 0x0, 0x0, 0x0, // header_length (end_header - begin_header)
// begin_header:
0x1, // minimum_instruction_length
0x1, // maximum_operations_per_instruction
0x1, // default_is_stmt
0xfb, // line_base
0xe, // line_range
0xd, // opcode_base and lengths
0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1,
'/', 'a', '\0', // directory entry 1 (zeroth entry implied)
'\0', // end of directory table
'b', '/', 'c', '\0', // file entry 1 (zeroth entry implied)
0, // file 1 directory
0, // file 1 modification time
0, // file 1 length
'\0', // end of file table
// end_header
DW_LNS_set_file, 0x0,
// set address to 0x0
0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
// Advance Address by 0 and line by 3
0x15,
// Advance PC by 1
0x2, 0x1,
0x0,
DW_LNE_end_sequence,
DW_LNE_end_sequence,
// end
};
class MockLineInfoHandler: public LineInfoHandler {
public:
MOCK_METHOD(void, DefineDir, (const string&, uint32_t dir_num), (override));
MOCK_METHOD(void, DefineFile, (const string& name, int32_t file_num,
uint32_t dir_num, uint64_t mod_time,
uint64_t length), (override));
MOCK_METHOD(void, AddLine, (uint64_t address, uint64_t length,
uint32_t file_num, uint32_t line_num,
uint32_t column_num), (override));
};
const uint8_t string_section[] = {'x', '/', 'a', '\0'};
const uint8_t line_string_section[] = {'x', 'b', '/', 'c', '\0' };
struct LineProgram: public Test {
MockLineInfoHandler handler_;
};
TEST_F(LineProgram, ReadLinesDwarf5) {
ByteReader byte_reader(ENDIANNESS_LITTLE);
// LineTables don't specify the offset size like Compilation Units do.
byte_reader.SetOffsetSize(4);
LineInfo line_reader(dwarf5_line_program,
sizeof(dwarf5_line_program),
&byte_reader,
string_section,
sizeof(string_section),
line_string_section,
sizeof(line_string_section),
&handler_);
EXPECT_CALL(handler_, DefineDir("/a", 0)).Times(1);
EXPECT_CALL(handler_, DefineFile("b/c", 0, 0, 0, 0)).Times(1);
EXPECT_CALL(handler_, AddLine(0, 1, 0, 4, 0)).Times(1);
EXPECT_EQ(line_reader.Start(), sizeof(dwarf5_line_program));
}
TEST_F(LineProgram, ReadLinesDwarf4) {
ByteReader byte_reader(ENDIANNESS_LITTLE);
// LineTables don't specify the offset size like Compilation Units do.
byte_reader.SetOffsetSize(4);
// dwarf4 line info headers don't encode the address size.
byte_reader.SetAddressSize(8);
LineInfo line_reader(dwarf4_line_program,
sizeof(dwarf4_line_program),
&byte_reader,
// dwarf4 line tables can't access the string sections
// so pass values likely to make assertions fail if
// the code uses them improperly.
nullptr, 0, nullptr, 0,
&handler_);
EXPECT_CALL(handler_, DefineDir("", 0)).Times(1);
EXPECT_CALL(handler_, DefineDir("/a", 1)).Times(1);
EXPECT_CALL(handler_, DefineFile("", 0, 0, 0, 0)).Times(1);
EXPECT_CALL(handler_, DefineFile("b/c", 1, 0, 0, 0)).Times(1);
EXPECT_CALL(handler_, AddLine(0, 1, 0, 4, 0)).Times(1);
EXPECT_EQ(line_reader.Start(), sizeof(dwarf4_line_program));
}
} // anonymous namespace

View file

@ -0,0 +1,129 @@
// Copyright 2020 Google LLC
//
// 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 LLC 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: Snehasish Kumar <snehasishk@google.com>
// dwarf2reader_splitfunctions_unittest.cc: Unit tests for with a focus on debug
// information generated when with splitting optimizations such as
// -fsplit-machine-functions (clang) -freorder-blocks-and-partition (gcc).
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdint.h>
#include <stdlib.h>
#include <string>
#include "breakpad_googletest_includes.h"
#include "common/dwarf/bytereader.h"
#include "common/dwarf/dwarf2reader.h"
#include "google_breakpad/common/breakpad_types.h"
using testing::_;
using namespace google_breakpad;
namespace {
class MockLineInfoHandler: public LineInfoHandler {
public:
MOCK_METHOD(void, DefineFile, (const string& name, int32_t file_num,
uint32_t dir_num, uint64_t mod_time,
uint64_t length), (override));
MOCK_METHOD(void, AddLine, (uint64_t address, uint64_t length,
uint32_t file_num, uint32_t line_num,
uint32_t column_num), (override));
};
struct LineProgram: public testing::Test {
MockLineInfoHandler handler_;
};
// The debug information is generated from the following program --
// $ cat -n split_functions.c
// 1 #include <stdio.h>
// 2
// 3 __attribute__((noinline)) int foo(int i) {
// 4 if (i % 100) {
// 5 return i + 1;
// 6 } else {
// 7 return i * 10 % 3;
// 8 }
// 9 }
// 10
// 11
// 12 int main(int argc, char *argv[]) {
// 13 int total = 0;
// 14 for (int i = 0; i < 1000; ++i) {
// 15 total += foo(i);
// 16 }
// 17 printf("%d\n", total);
// 18 }
//
// $ bin/clang -fprofile-generate -O2 split_functions.c
// $ ./a.out > /dev/null
// $ bin/llvm-profdata merge -o default.profdata default_*.profraw
// $ bin/clang -fprofile-use -O2 -gmlt -gdwarf-5 -fsplit-machine-functions \
// split_functions.c -o split.out
//
// For the test we pick the first instruction in foo.cold which should be the
// else part of the function foo above.
const uint8_t debug_line[] = {
0xb0,0x0,0x0,0x0,0x5,0x0,0x8,0x0,0x37,0x0,0x0,0x0,0x1,0x1,0x1,0xfb,0xe,0xd,0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x1,0x1,0x1f,0x1,0x0,0x0,0x0,0x0,0x3,0x1,0x1f,0x2,0xf,0x5,0x1e,0x1,0x3d,0x0,0x0,0x0,0x0,0x24,0xb2,0xb6,0xb5,0xbb,0xf,0xf7,0x6d,0x27,0x92,0xab,0x55,0x3a,0x29,0x48,0x81,0x4,0x0,0x0,0x9,0x2,0x40,0x10,0x40,0x0,0x0,0x0,0x0,0x0,0x14,0x5,0x9,0xa,0x2f,0x5,0x7,0x6,0x8,0x4a,0x5,0xe,0x6,0x67,0x5,0x1,0x40,0x5,0x0,0xf5,0x5,0xe,0xa,0xf5,0x5,0xb,0x6,0x74,0x5,0x1d,0x6,0x2d,0x5,0x15,0x6,0x3c,0x5,0x3,0x66,0x2,0x7,0x0,0x1,0x1,0x4,0x0,0x5,0xe,0x0,0x9,0x2,0x84,0x11,0x40,0x0,0x0,0x0,0x0,0x0,0x18,0x5,0x13,0x6,0x58,0x5,0x1,0x6,0x8,0xa0,0x2,0x1,0x0,0x1,0x1,0x4,0x0,0x5,0x3,0x0,0x9,0x2,0xa5,0x11,0x40,0x0,0x0,0x0,0x0,0x0,0x3,0x10,0x1,0x5,0x1,0xd7,0x2,0x9,0x0,0x1,0x1
};
const uint8_t debug_str[] = {
0x63,0x6c,0x61,0x6e,0x67,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x32,0x2e,0x30,0x2e,0x30,0x20,0x28,0x67,0x69,0x74,0x40,0x67,0x69,0x74,0x68,0x75,0x62,0x2e,0x63,0x6f,0x6d,0x3a,0x6c,0x6c,0x76,0x6d,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2e,0x67,0x69,0x74,0x20,0x63,0x37,0x35,0x61,0x30,0x61,0x31,0x65,0x39,0x64,0x63,0x32,0x39,0x62,0x65,0x34,0x65,0x30,0x30,0x64,0x33,0x37,0x64,0x30,0x64,0x30,0x30,0x32,0x38,0x38,0x61,0x66,0x63,0x31,0x61,0x36,0x31,0x35,0x33,0x66,0x29,0x0,0x73,0x70,0x6c,0x69,0x74,0x5f,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x63,0x0,0x2f,0x75,0x73,0x72,0x2f,0x6c,0x6f,0x63,0x61,0x6c,0x2f,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2f,0x68,0x6f,0x6d,0x65,0x2f,0x73,0x6e,0x65,0x68,0x61,0x73,0x69,0x73,0x68,0x6b,0x2f,0x77,0x6f,0x72,0x6b,0x69,0x6e,0x67,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2f,0x62,0x75,0x69,0x6c,0x64,0x0,0x66,0x6f,0x6f,0x0,0x69,0x6e,0x74,0x0,0x6d,0x61,0x69,0x6e,0x0,0x69,0x0,0x61,0x72,0x67,0x63,0x0,0x61,0x72,0x67,0x76,0x0,0x63,0x68,0x61,0x72,0x0,0x74,0x6f,0x74,0x61,0x6c,0x0
};
const uint8_t debug_line_str[] = {
0x2f,0x75,0x73,0x72,0x2f,0x6c,0x6f,0x63,0x61,0x6c,0x2f,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2f,0x68,0x6f,0x6d,0x65,0x2f,0x73,0x6e,0x65,0x68,0x61,0x73,0x69,0x73,0x68,0x6b,0x2f,0x77,0x6f,0x72,0x6b,0x69,0x6e,0x67,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2f,0x62,0x75,0x69,0x6c,0x64,0x0,0x73,0x70,0x6c,0x69,0x74,0x5f,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x63,0x0
};
TEST_F(LineProgram, ReadLinesSplitFunctions) {
ByteReader byte_reader(ENDIANNESS_LITTLE);
// LineTables don't specify the offset size like Compilation Units do.
byte_reader.SetOffsetSize(4);
LineInfo line_reader(debug_line,
sizeof(debug_line),
&byte_reader,
debug_str,
sizeof(debug_str),
debug_line_str,
sizeof(debug_line_str),
&handler_);
EXPECT_CALL(handler_, DefineFile("split_functions.c", 0, 0, 0, 0)).Times(1);
EXPECT_CALL(handler_, AddLine(_, _, _, _, _)).Times(testing::AtLeast(1));
// Pick the first address from the foo.cold symbol and check the line number.
EXPECT_CALL(handler_, AddLine(testing::Eq(0x401184lu), _, _, /*line_num*/ 7, _)).Times(1);
EXPECT_EQ(line_reader.Start(), sizeof(debug_line));
}
} // anonymous namespace

View file

@ -0,0 +1,163 @@
// -*- mode: c++ -*-
// Copyright 2012 Google LLC
//
// 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 LLC 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>
// dwarf2reader_test_common.h: Define TestCompilationUnit and
// TestAbbrevTable, classes for creating properly (and improperly)
// formatted DWARF compilation unit data for unit tests.
#ifndef COMMON_DWARF_DWARF2READER_TEST_COMMON_H__
#define COMMON_DWARF_DWARF2READER_TEST_COMMON_H__
#include "common/test_assembler.h"
#include "common/dwarf/dwarf2enums.h"
// A subclass of test_assembler::Section, specialized for constructing
// DWARF compilation units.
class TestCompilationUnit: public google_breakpad::test_assembler::Section {
public:
typedef google_breakpad::DwarfTag DwarfTag;
typedef google_breakpad::DwarfAttribute DwarfAttribute;
typedef google_breakpad::DwarfForm DwarfForm;
typedef google_breakpad::test_assembler::Label Label;
// Set the section's DWARF format size (the 32-bit DWARF format or the
// 64-bit DWARF format, for lengths and section offsets --- not the
// address size) to format_size.
void set_format_size(size_t format_size) {
assert(format_size == 4 || format_size == 8);
format_size_ = format_size;
}
// Append a DWARF section offset value, of the appropriate size for this
// compilation unit.
template<typename T>
void SectionOffset(T offset) {
if (format_size_ == 4)
D32(offset);
else
D64(offset);
}
// Append a DWARF compilation unit header to the section, with the given
// DWARF version, abbrev table offset, and address size.
TestCompilationUnit& Header(int version, const Label& abbrev_offset,
size_t address_size, int header_type) {
if (format_size_ == 4) {
D32(length_);
} else {
D32(0xffffffff);
D64(length_);
}
post_length_offset_ = Size();
D16(version);
if (version <= 4) {
SectionOffset(abbrev_offset);
D8(address_size);
} else {
D8(header_type); // DW_UT_compile, DW_UT_type, etc.
D8(address_size);
SectionOffset(abbrev_offset);
if (header_type == google_breakpad::DW_UT_type) {
uint64_t dummy_type_signature = 0xdeadbeef;
uint64_t dummy_type_offset = 0x2b;
D64(dummy_type_signature);
if (format_size_ == 4)
D32(dummy_type_offset);
else
D64(dummy_type_offset);
}
}
return *this;
}
// Mark the end of this header's DIEs.
TestCompilationUnit& Finish() {
length_ = Size() - post_length_offset_;
return *this;
}
private:
// The DWARF format size for this compilation unit.
size_t format_size_;
// The offset of the point in the compilation unit header immediately
// after the initial length field.
uint64_t post_length_offset_;
// The length of the compilation unit, not including the initial length field.
Label length_;
};
// A subclass of test_assembler::Section specialized for constructing DWARF
// abbreviation tables.
class TestAbbrevTable: public google_breakpad::test_assembler::Section {
public:
typedef google_breakpad::DwarfTag DwarfTag;
typedef google_breakpad::DwarfAttribute DwarfAttribute;
typedef google_breakpad::DwarfForm DwarfForm;
typedef google_breakpad::DwarfHasChild DwarfHasChild;
typedef google_breakpad::test_assembler::Label Label;
// Start a new abbreviation table entry for abbreviation code |code|,
// encoding a DIE whose tag is |tag|, and which has children if and only
// if |has_children| is true.
TestAbbrevTable& Abbrev(int code, DwarfTag tag, DwarfHasChild has_children) {
assert(code != 0);
ULEB128(code);
ULEB128(static_cast<unsigned>(tag));
D8(static_cast<unsigned>(has_children));
return *this;
};
// Add an attribute to the current abbreviation code whose name is |name|
// and whose form is |form|.
TestAbbrevTable& Attribute(DwarfAttribute name, DwarfForm form) {
ULEB128(static_cast<unsigned>(name));
ULEB128(static_cast<unsigned>(form));
return *this;
}
// Finish the current abbreviation code.
TestAbbrevTable& EndAbbrev() {
ULEB128(0);
ULEB128(0);
return *this;
}
// Finish the current abbreviation table.
TestAbbrevTable& EndTable() {
ULEB128(0);
return *this;
}
};
#endif // COMMON_DWARF_DWARF2READER_TEST_COMMON_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,169 @@
// Copyright 2005 Google LLC
// Author: chatham@google.com (Andrew Chatham)
// Author: satorux@google.com (Satoru Takabayashi)
//
// ElfReader handles reading in ELF. It can extract symbols from the
// current process, which may be used to symbolize stack traces
// without having to make a potentially dangerous call to fork().
//
// ElfReader dynamically allocates memory, so it is not appropriate to
// use once the address space might be corrupted, such as during
// process death.
//
// ElfReader supports both 32-bit and 64-bit ELF binaries.
#ifndef COMMON_DWARF_ELF_READER_H__
#define COMMON_DWARF_ELF_READER_H__
#include <string>
#include <string_view>
#include <vector>
#include "common/dwarf/types.h"
#include "common/using_std_string.h"
using std::vector;
using std::pair;
namespace google_breakpad {
class SymbolMap;
class Elf32;
class Elf64;
template<typename ElfArch>
class ElfReaderImpl;
class ElfReader {
public:
explicit ElfReader(const string& path);
~ElfReader();
// Parse the ELF prologue of this file and return whether it was
// successfully parsed and matches the word size and byte order of
// the current process.
bool IsNativeElfFile() const;
// Similar to IsNativeElfFile but checks if it's a 32-bit ELF file.
bool IsElf32File() const;
// Similar to IsNativeElfFile but checks if it's a 64-bit ELF file.
bool IsElf64File() const;
// Checks if it's an ELF file of type ET_DYN (shared object file).
bool IsDynamicSharedObject();
// Add symbols in the given ELF file into the provided SymbolMap,
// assuming that the file has been loaded into the specified
// offset.
//
// The remaining arguments are typically taken from a
// ProcMapsIterator (base/sysinfo.h) and describe which portions of
// the ELF file are mapped into which parts of memory:
//
// mem_offset - position at which the segment is mapped into memory
// file_offset - offset in the file where the mapping begins
// length - length of the mapped segment
void AddSymbols(SymbolMap* symbols,
uint64_t mem_offset, uint64_t file_offset,
uint64_t length);
class SymbolSink {
public:
virtual ~SymbolSink() {}
virtual void AddSymbol(const char* name, uint64_t address,
uint64_t size) = 0;
};
// Like AddSymbols above, but with no address correction.
// Processes any SHT_SYMTAB section, followed by any SHT_DYNSYM section.
void VisitSymbols(SymbolSink* sink);
// Like VisitSymbols above, but for a specific symbol binding/type.
// A negative value for the binding and type parameters means any
// binding or type.
void VisitSymbols(SymbolSink* sink, int symbol_binding, int symbol_type);
// Like VisitSymbols above but can optionally export raw symbol values instead
// of adjusted ones.
void VisitSymbols(SymbolSink* sink, int symbol_binding, int symbol_type,
bool get_raw_symbol_values);
// p_vaddr of the first PT_LOAD segment (if any), or 0 if no PT_LOAD
// segments are present. This is the address an ELF image was linked
// (by static linker) to be loaded at. Usually (but not always) 0 for
// shared libraries and position-independent executables.
uint64_t VaddrOfFirstLoadSegment();
// Return the name of section "shndx". Returns NULL if the section
// is not found.
const char* GetSectionName(int shndx);
// Return the number of sections in the given ELF file.
uint64_t GetNumSections();
// Get section "shndx" from the given ELF file. On success, return
// the pointer to the section and store the size in "size".
// On error, return NULL. The returned section data is only valid
// until the ElfReader gets destroyed.
const char* GetSectionByIndex(int shndx, size_t* size);
// Get section with "section_name" (ex. ".text", ".symtab") in the
// given ELF file. On success, return the pointer to the section
// and store the size in "size". On error, return NULL. The
// returned section data is only valid until the ElfReader gets
// destroyed.
const char* GetSectionByName(const string& section_name, size_t* size);
// This is like GetSectionByName() but it returns a lot of extra information
// about the section. The SectionInfo structure is almost identical to
// the typedef struct Elf64_Shdr defined in <elf.h>, but is redefined
// here so that the many short macro names in <elf.h> don't have to be
// added to our already cluttered namespace.
struct SectionInfo {
uint32_t type; // Section type (SHT_xxx constant from elf.h).
uint64_t flags; // Section flags (SHF_xxx constants from elf.h).
uint64_t addr; // Section virtual address at execution.
uint64_t offset; // Section file offset.
uint64_t size; // Section size in bytes.
uint32_t link; // Link to another section.
uint32_t info; // Additional section information.
uint64_t addralign; // Section alignment.
uint64_t entsize; // Entry size if section holds a table.
};
const char* GetSectionInfoByName(const string& section_name,
SectionInfo* info);
// Check if "path" is an ELF binary that has not been stripped of symbol
// tables. This function supports both 32-bit and 64-bit ELF binaries.
static bool IsNonStrippedELFBinary(const string& path);
// Check if "path" is an ELF binary that has not been stripped of debug
// info. Unlike IsNonStrippedELFBinary, this function will return
// false for binaries passed through "strip -S".
static bool IsNonDebugStrippedELFBinary(const string& path);
// Match a requested section name with the section name as it
// appears in the elf-file, adjusting for compressed debug section
// names. For example, returns true if name == ".debug_abbrev" and
// sh_name == ".zdebug_abbrev"
static bool SectionNamesMatch(std::string_view name,
std::string_view sh_name);
private:
// Lazily initialize impl32_ and return it.
ElfReaderImpl<Elf32>* GetImpl32();
// Ditto for impl64_.
ElfReaderImpl<Elf64>* GetImpl64();
// Path of the file we're reading.
const string path_;
// Read-only file descriptor for the file. May be -1 if there was an
// error during open.
int fd_;
ElfReaderImpl<Elf32>* impl32_;
ElfReaderImpl<Elf64>* impl64_;
};
} // namespace google_breakpad
#endif // COMMON_DWARF_ELF_READER_H__

View file

@ -0,0 +1,232 @@
// Copyright 2010 Google LLC
//
// 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 LLC 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.
// This is a client for the dwarf2reader to extract function and line
// information from the debug info.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <map>
#include <queue>
#include <vector>
#include "common/dwarf/functioninfo.h"
#include "common/dwarf/bytereader.h"
#include "common/scoped_ptr.h"
#include "common/using_std_string.h"
namespace google_breakpad {
CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files,
std::vector<string>* dirs,
LineMap* linemap):linemap_(linemap),
files_(files),
dirs_(dirs) {
// In dwarf4, the dirs and files are 1 indexed, and in dwarf5 they are zero
// indexed. This is handled in the LineInfo reader, so empty files are not
// needed here.
}
void CULineInfoHandler::DefineDir(const string& name, uint32_t dir_num) {
// These should never come out of order, actually
assert(dir_num == dirs_->size());
dirs_->push_back(name);
}
void CULineInfoHandler::DefineFile(const string& name,
int32 file_num, uint32_t dir_num,
uint64_t mod_time, uint64_t length) {
assert(dir_num >= 0);
assert(dir_num < dirs_->size());
// These should never come out of order, actually.
if (file_num == (int32)files_->size() || file_num == -1) {
string dir = dirs_->at(dir_num);
SourceFileInfo s;
s.lowpc = ULLONG_MAX;
if (dir == "") {
s.name = name;
} else {
s.name = dir + "/" + name;
}
files_->push_back(s);
} else {
fprintf(stderr, "error in DefineFile");
}
}
void CULineInfoHandler::AddLine(uint64_t address, uint64_t length,
uint32_t file_num, uint32_t line_num,
uint32_t column_num) {
if (file_num < files_->size()) {
linemap_->insert(
std::make_pair(address,
std::make_pair(files_->at(file_num).name.c_str(),
line_num)));
if (address < files_->at(file_num).lowpc) {
files_->at(file_num).lowpc = address;
}
} else {
fprintf(stderr, "error in AddLine");
}
}
bool CUFunctionInfoHandler::StartCompilationUnit(uint64_t offset,
uint8_t address_size,
uint8_t offset_size,
uint64_t cu_length,
uint8_t dwarf_version) {
current_compilation_unit_offset_ = offset;
return true;
}
// For function info, we only care about subprograms and inlined
// subroutines. For line info, the DW_AT_stmt_list lives in the
// compile unit tag.
bool CUFunctionInfoHandler::StartDIE(uint64_t offset, enum DwarfTag tag) {
switch (tag) {
case DW_TAG_subprogram:
case DW_TAG_inlined_subroutine: {
current_function_info_ = new FunctionInfo;
current_function_info_->lowpc = current_function_info_->highpc = 0;
current_function_info_->name = "";
current_function_info_->line = 0;
current_function_info_->file = "";
offset_to_funcinfo_->insert(std::make_pair(offset,
current_function_info_));
};
// FALLTHROUGH
case DW_TAG_compile_unit:
return true;
default:
return false;
}
return false;
}
// Only care about the name attribute for functions
void CUFunctionInfoHandler::ProcessAttributeString(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const string& data) {
if (current_function_info_) {
if (attr == DW_AT_name)
current_function_info_->name = data;
else if (attr == DW_AT_MIPS_linkage_name)
current_function_info_->mangled_name = data;
}
}
void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data) {
if (attr == DW_AT_stmt_list) {
SectionMap::const_iterator iter =
GetSectionByName(sections_, ".debug_line");
assert(iter != sections_.end());
scoped_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data,
iter->second.second - data,
reader_, linehandler_));
lireader->Start();
} else if (current_function_info_) {
switch (attr) {
case DW_AT_low_pc:
current_function_info_->lowpc = data;
break;
case DW_AT_high_pc:
current_function_info_->highpc = data;
break;
case DW_AT_decl_line:
current_function_info_->line = data;
break;
case DW_AT_decl_file:
current_function_info_->file = files_->at(data).name;
break;
case DW_AT_ranges:
current_function_info_->ranges = data;
break;
default:
break;
}
}
}
void CUFunctionInfoHandler::ProcessAttributeReference(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data) {
if (current_function_info_) {
switch (attr) {
case DW_AT_specification: {
// Some functions have a "specification" attribute
// which means they were defined elsewhere. The name
// attribute is not repeated, and must be taken from
// the specification DIE. Here we'll assume that
// any DIE referenced in this manner will already have
// been seen, but that's not really required by the spec.
FunctionMap::iterator iter = offset_to_funcinfo_->find(data);
if (iter != offset_to_funcinfo_->end()) {
current_function_info_->name = iter->second->name;
current_function_info_->mangled_name = iter->second->mangled_name;
} else {
// If you hit this, this code probably needs to be rewritten.
fprintf(stderr,
"Error: DW_AT_specification was seen before the referenced "
"DIE! (Looking for DIE at offset %08llx, in DIE at "
"offset %08llx)\n", data, offset);
}
break;
}
default:
break;
}
}
}
void CUFunctionInfoHandler::EndDIE(uint64_t offset) {
if (current_function_info_ && current_function_info_->lowpc)
address_to_funcinfo_->insert(std::make_pair(current_function_info_->lowpc,
current_function_info_));
}
} // namespace google_breakpad

View file

@ -0,0 +1,191 @@
// Copyright 2010 Google LLC
//
// 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 LLC 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.
// This file contains the definitions for a DWARF2/3 information
// collector that uses the DWARF2/3 reader interface to build a mapping
// of addresses to files, lines, and functions.
#ifndef COMMON_DWARF_FUNCTIONINFO_H__
#define COMMON_DWARF_FUNCTIONINFO_H__
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "common/dwarf/dwarf2reader.h"
#include "common/using_std_string.h"
namespace google_breakpad {
struct FunctionInfo {
// Name of the function
string name;
// Mangled name of the function
string mangled_name;
// File containing this function
string file;
// Line number for start of function.
uint32_t line;
// Beginning address for this function
uint64_t lowpc;
// End address for this function.
uint64_t highpc;
// Ranges offset
uint64_t ranges;
};
struct SourceFileInfo {
// Name of the source file name
string name;
// Low address of source file name
uint64_t lowpc;
};
typedef std::map<uint64, FunctionInfo*> FunctionMap;
typedef std::map<uint64, std::pair<string, uint32> > LineMap;
// This class is a basic line info handler that fills in the dirs,
// file, and linemap passed into it with the data produced from the
// LineInfoHandler.
class CULineInfoHandler: public LineInfoHandler {
public:
//
CULineInfoHandler(std::vector<SourceFileInfo>* files,
std::vector<string>* dirs,
LineMap* linemap);
virtual ~CULineInfoHandler() { }
// Called when we define a directory. We just place NAME into dirs_
// at position DIR_NUM.
virtual void DefineDir(const string& name, uint32_t dir_num);
// Called when we define a filename. We just place
// concat(dirs_[DIR_NUM], NAME) into files_ at position FILE_NUM.
virtual void DefineFile(const string& name, int32 file_num,
uint32_t dir_num, uint64_t mod_time, uint64_t length);
// Called when the line info reader has a new line, address pair
// ready for us. ADDRESS is the address of the code, LENGTH is the
// length of its machine code in bytes, FILE_NUM is the file number
// containing the code, LINE_NUM is the line number in that file for
// the code, and COLUMN_NUM is the column number the code starts at,
// if we know it (0 otherwise).
virtual void AddLine(uint64_t address, uint64_t length,
uint32_t file_num, uint32_t line_num,
uint32_t column_num);
private:
LineMap* linemap_;
std::vector<SourceFileInfo>* files_;
std::vector<string>* dirs_;
};
class CUFunctionInfoHandler: public Dwarf2Handler {
public:
CUFunctionInfoHandler(std::vector<SourceFileInfo>* files,
std::vector<string>* dirs,
LineMap* linemap,
FunctionMap* offset_to_funcinfo,
FunctionMap* address_to_funcinfo,
CULineInfoHandler* linehandler,
const SectionMap& sections,
ByteReader* reader)
: files_(files), dirs_(dirs), linemap_(linemap),
offset_to_funcinfo_(offset_to_funcinfo),
address_to_funcinfo_(address_to_funcinfo),
linehandler_(linehandler), sections_(sections),
reader_(reader), current_function_info_(NULL) { }
virtual ~CUFunctionInfoHandler() { }
// Start to process a compilation unit at OFFSET from the beginning of the
// .debug_info section. We want to see all compilation units, so we
// always return true.
virtual bool StartCompilationUnit(uint64_t offset, uint8_t address_size,
uint8_t offset_size, uint64_t cu_length,
uint8_t dwarf_version);
// Start to process a DIE at OFFSET from the beginning of the
// .debug_info section. We only care about function related DIE's.
virtual bool StartDIE(uint64_t offset, enum DwarfTag tag);
// Called when we have an attribute with unsigned data to give to
// our handler. The attribute is for the DIE at OFFSET from the
// beginning of the .debug_info section, has a name of ATTR, a form of
// FORM, and the actual data of the attribute is in DATA.
virtual void ProcessAttributeUnsigned(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data);
// Called when we have an attribute with a DIE reference to give to
// our handler. The attribute is for the DIE at OFFSET from the
// beginning of the .debug_info section, has a name of ATTR, a form of
// FORM, and the offset of the referenced DIE from the start of the
// .debug_info section is in DATA.
virtual void ProcessAttributeReference(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data);
// Called when we have an attribute with string data to give to
// our handler. The attribute is for the DIE at OFFSET from the
// beginning of the .debug_info section, has a name of ATTR, a form of
// FORM, and the actual data of the attribute is in DATA.
virtual void ProcessAttributeString(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const string& data);
// Called when finished processing the DIE at OFFSET.
// Because DWARF2/3 specifies a tree of DIEs, you may get starts
// before ends of the previous DIE, as we process children before
// ending the parent.
virtual void EndDIE(uint64_t offset);
private:
std::vector<SourceFileInfo>* files_;
std::vector<string>* dirs_;
LineMap* linemap_;
FunctionMap* offset_to_funcinfo_;
FunctionMap* address_to_funcinfo_;
CULineInfoHandler* linehandler_;
const SectionMap& sections_;
ByteReader* reader_;
FunctionInfo* current_function_info_;
uint64_t current_compilation_unit_offset_;
};
} // namespace google_breakpad
#endif // COMMON_DWARF_FUNCTIONINFO_H__

View file

@ -0,0 +1,63 @@
// Copyright 2008 Google LLC
//
// 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 LLC 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.
#ifndef COMMON_DWARF_LINE_STATE_MACHINE_H__
#define COMMON_DWARF_LINE_STATE_MACHINE_H__
#include <stdint.h>
namespace google_breakpad {
// This is the format of a DWARF2/3 line state machine that we process
// opcodes using. There is no need for anything outside the lineinfo
// processor to know how this works.
struct LineStateMachine {
void Reset(bool default_is_stmt) {
file_num = 1;
address = 0;
line_num = 1;
column_num = 0;
is_stmt = default_is_stmt;
basic_block = false;
end_sequence = false;
}
uint32_t file_num;
uint64_t address;
uint32_t line_num;
uint32_t column_num;
bool is_stmt; // stmt means statement.
bool basic_block;
bool end_sequence;
};
} // namespace google_breakpad
#endif // COMMON_DWARF_LINE_STATE_MACHINE_H__

View file

@ -0,0 +1,41 @@
// Copyright 2008 Google LLC
//
// 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 LLC 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.
// This file contains some typedefs for basic types
#ifndef _COMMON_DWARF_TYPES_H__
#define _COMMON_DWARF_TYPES_H__
#include <stdint.h>
typedef intptr_t intptr;
typedef uintptr_t uintptr;
#endif // _COMMON_DWARF_TYPES_H__