mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2025-10-14 00:37:46 +00:00
Move dead submodules in-tree
Signed-off-by: swurl <swurl@swurl.xyz>
This commit is contained in:
parent
c0cceff365
commit
6c655321e6
4081 changed files with 1185566 additions and 45 deletions
181
externals/breakpad/src/common/dwarf/bytereader-inl.h
vendored
Normal file
181
externals/breakpad/src/common/dwarf/bytereader-inl.h
vendored
Normal 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__
|
254
externals/breakpad/src/common/dwarf/bytereader.cc
vendored
Normal file
254
externals/breakpad/src/common/dwarf/bytereader.cc
vendored
Normal 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
|
320
externals/breakpad/src/common/dwarf/bytereader.h
vendored
Normal file
320
externals/breakpad/src/common/dwarf/bytereader.h
vendored
Normal 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__
|
710
externals/breakpad/src/common/dwarf/bytereader_unittest.cc
vendored
Normal file
710
externals/breakpad/src/common/dwarf/bytereader_unittest.cc
vendored
Normal 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);
|
||||
}
|
205
externals/breakpad/src/common/dwarf/cfi_assembler.cc
vendored
Normal file
205
externals/breakpad/src/common/dwarf/cfi_assembler.cc
vendored
Normal 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
|
268
externals/breakpad/src/common/dwarf/cfi_assembler.h
vendored
Normal file
268
externals/breakpad/src/common/dwarf/cfi_assembler.h
vendored
Normal 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_
|
203
externals/breakpad/src/common/dwarf/dwarf2diehandler.cc
vendored
Normal file
203
externals/breakpad/src/common/dwarf/dwarf2diehandler.cc
vendored
Normal 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
|
368
externals/breakpad/src/common/dwarf/dwarf2diehandler.h
vendored
Normal file
368
externals/breakpad/src/common/dwarf/dwarf2diehandler.h
vendored
Normal 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__
|
532
externals/breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc
vendored
Normal file
532
externals/breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc
vendored
Normal 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...
|
||||
}
|
||||
}
|
744
externals/breakpad/src/common/dwarf/dwarf2enums.h
vendored
Normal file
744
externals/breakpad/src/common/dwarf/dwarf2enums.h
vendored
Normal 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__
|
3487
externals/breakpad/src/common/dwarf/dwarf2reader.cc
vendored
Normal file
3487
externals/breakpad/src/common/dwarf/dwarf2reader.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
1527
externals/breakpad/src/common/dwarf/dwarf2reader.h
vendored
Normal file
1527
externals/breakpad/src/common/dwarf/dwarf2reader.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
2590
externals/breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc
vendored
Normal file
2590
externals/breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
968
externals/breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc
vendored
Normal file
968
externals/breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc
vendored
Normal 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(§ion_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()));
|
||||
}
|
190
externals/breakpad/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc
vendored
Normal file
190
externals/breakpad/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc
vendored
Normal 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
|
129
externals/breakpad/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc
vendored
Normal file
129
externals/breakpad/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc
vendored
Normal 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
|
163
externals/breakpad/src/common/dwarf/dwarf2reader_test_common.h
vendored
Normal file
163
externals/breakpad/src/common/dwarf/dwarf2reader_test_common.h
vendored
Normal 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__
|
1302
externals/breakpad/src/common/dwarf/elf_reader.cc
vendored
Normal file
1302
externals/breakpad/src/common/dwarf/elf_reader.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
169
externals/breakpad/src/common/dwarf/elf_reader.h
vendored
Normal file
169
externals/breakpad/src/common/dwarf/elf_reader.h
vendored
Normal 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__
|
232
externals/breakpad/src/common/dwarf/functioninfo.cc
vendored
Normal file
232
externals/breakpad/src/common/dwarf/functioninfo.cc
vendored
Normal 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
|
191
externals/breakpad/src/common/dwarf/functioninfo.h
vendored
Normal file
191
externals/breakpad/src/common/dwarf/functioninfo.h
vendored
Normal 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__
|
63
externals/breakpad/src/common/dwarf/line_state_machine.h
vendored
Normal file
63
externals/breakpad/src/common/dwarf/line_state_machine.h
vendored
Normal 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__
|
41
externals/breakpad/src/common/dwarf/types.h
vendored
Normal file
41
externals/breakpad/src/common/dwarf/types.h
vendored
Normal 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__
|
Loading…
Add table
Add a link
Reference in a new issue