diff options
author | wolfbeast <mcwerewolf@wolfbeast.com> | 2019-04-01 13:05:24 +0200 |
---|---|---|
committer | wolfbeast <mcwerewolf@wolfbeast.com> | 2019-04-01 13:05:24 +0200 |
commit | ff2f287f82630ab3887d7d5c1e64e5b888ea0beb (patch) | |
tree | 4e96cb32aa2320a327024942d247c6b56ef8c199 /toolkit/crashreporter/google-breakpad/src/common/dwarf | |
parent | bfc97728065cbbc7f6bbc281b654a2d1e079b48d (diff) | |
download | UXP-ff2f287f82630ab3887d7d5c1e64e5b888ea0beb.tar UXP-ff2f287f82630ab3887d7d5c1e64e5b888ea0beb.tar.gz UXP-ff2f287f82630ab3887d7d5c1e64e5b888ea0beb.tar.lz UXP-ff2f287f82630ab3887d7d5c1e64e5b888ea0beb.tar.xz UXP-ff2f287f82630ab3887d7d5c1e64e5b888ea0beb.zip |
Remove crashreporter toolkit files.
Resolves #20
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/common/dwarf')
22 files changed, 0 insertions, 12806 deletions
diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader-inl.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader-inl.h deleted file mode 100644 index 42c92f943..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader-inl.h +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2006 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef UTIL_DEBUGINFO_BYTEREADER_INL_H__ -#define UTIL_DEBUGINFO_BYTEREADER_INL_H__ - -#include "common/dwarf/bytereader.h" - -#include <assert.h> -#include <stdint.h> - -namespace dwarf2reader { - -inline uint8 ByteReader::ReadOneByte(const uint8_t *buffer) const { - return buffer[0]; -} - -inline uint16 ByteReader::ReadTwoBytes(const uint8_t *buffer) const { - const uint16 buffer0 = buffer[0]; - const uint16 buffer1 = buffer[1]; - if (endian_ == ENDIANNESS_LITTLE) { - return buffer0 | buffer1 << 8; - } else { - return buffer1 | buffer0 << 8; - } -} - -inline uint64 ByteReader::ReadFourBytes(const uint8_t *buffer) const { - const uint32 buffer0 = buffer[0]; - const uint32 buffer1 = buffer[1]; - const uint32 buffer2 = buffer[2]; - const uint32 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 ByteReader::ReadEightBytes(const uint8_t *buffer) const { - const uint64 buffer0 = buffer[0]; - const uint64 buffer1 = buffer[1]; - const uint64 buffer2 = buffer[2]; - const uint64 buffer3 = buffer[3]; - const uint64 buffer4 = buffer[4]; - const uint64 buffer5 = buffer[5]; - const uint64 buffer6 = buffer[6]; - const uint64 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 ByteReader::ReadUnsignedLEB128(const uint8_t *buffer, - size_t* len) const { - uint64 result = 0; - size_t num_read = 0; - unsigned int shift = 0; - uint8_t byte; - - do { - byte = *buffer++; - num_read++; - - result |= (static_cast<uint64>(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 ByteReader::ReadSignedLEB128(const uint8_t *buffer, - size_t* len) const { - int64 result = 0; - unsigned int shift = 0; - size_t num_read = 0; - uint8_t byte; - - do { - byte = *buffer++; - num_read++; - result |= (static_cast<uint64>(byte & 0x7f) << shift); - shift += 7; - } while (byte & 0x80); - - if ((shift < 8 * sizeof (result)) && (byte & 0x40)) - result |= -((static_cast<int64>(1)) << shift); - *len = num_read; - return result; -} - -inline uint64 ByteReader::ReadOffset(const uint8_t *buffer) const { - assert(this->offset_reader_); - return (this->*offset_reader_)(buffer); -} - -inline uint64 ByteReader::ReadAddress(const uint8_t *buffer) const { - assert(this->address_reader_); - return (this->*address_reader_)(buffer); -} - -inline void ByteReader::SetCFIDataBase(uint64 section_base, - const uint8_t *buffer_base) { - section_base_ = section_base; - buffer_base_ = buffer_base; - have_section_base_ = true; -} - -inline void ByteReader::SetTextBase(uint64 text_base) { - text_base_ = text_base; - have_text_base_ = true; -} - -inline void ByteReader::SetDataBase(uint64 data_base) { - data_base_ = data_base; - have_data_base_ = true; -} - -inline void ByteReader::SetFunctionBase(uint64 function_base) { - function_base_ = function_base; - have_function_base_ = true; -} - -inline void ByteReader::ClearFunctionBase() { - have_function_base_ = false; -} - -} // namespace dwarf2reader - -#endif // UTIL_DEBUGINFO_BYTEREADER_INL_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.cc deleted file mode 100644 index 14b43adb8..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.cc +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <assert.h> -#include <stdint.h> -#include <stdlib.h> - -#include "common/dwarf/bytereader-inl.h" -#include "common/dwarf/bytereader.h" - -namespace dwarf2reader { - -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 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 size) { - address_size_ = size; - assert(size == 4 || size == 8); - if (size == 4) { - this->address_reader_ = &ByteReader::ReadFourBytes; - } else { - this->address_reader_ = &ByteReader::ReadEightBytes; - } -} - -uint64 ByteReader::ReadInitialLength(const uint8_t *start, size_t* len) { - const uint64 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 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 skew = section_base_ & (AddressSize() - 1); - // Now find the offset from that aligned address to buffer. - uint64 offset = skew + (buffer - buffer_base_); - // Round up to the next boundary. - uint64 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 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 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 pointer = base + offset; - - // Remove inappropriate upper bits. - if (AddressSize() == 4) - pointer = pointer & 0xffffffff; - else - assert(AddressSize() == sizeof(uint64)); - - return pointer; -} - -Endianness ByteReader::GetEndianness() const { - return endian_; -} - -} // namespace dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.h deleted file mode 100644 index 59d430348..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.h +++ /dev/null @@ -1,315 +0,0 @@ -// -*- mode: C++ -*- - -// Copyright (c) 2010 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#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 dwarf2reader { - -// 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 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 ReadTwoBytes(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 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 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 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 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 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 size); - - // Return the current address size, in bytes. This is either 4, - // indicating 32-bit addresses, or 8, indicating 64-bit addresses. - uint8 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 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 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 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 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 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 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 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 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 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 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 (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 address_size_; - uint8 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 section_base_, text_base_, data_base_, function_base_; - const uint8_t *buffer_base_; -}; - -} // namespace dwarf2reader - -#endif // COMMON_DWARF_BYTEREADER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader_unittest.cc deleted file mode 100644 index e66062d1f..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader_unittest.cc +++ /dev/null @@ -1,707 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// bytereader_unittest.cc: Unit tests for dwarf2reader::ByteReader - -#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 dwarf2reader::ByteReader; -using dwarf2reader::DwarfPointerEncoding; -using dwarf2reader::ENDIANNESS_BIG; -using dwarf2reader::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(dwarf2reader::DW_EH_PE_absptr))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_omit))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_aligned))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::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, dwarf2reader::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, dwarf2reader::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, dwarf2reader::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, dwarf2reader::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, dwarf2reader::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, dwarf2reader::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, dwarf2reader::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, dwarf2reader::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, dwarf2reader::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, dwarf2reader::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, dwarf2reader::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, dwarf2reader::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(dwarf2reader::DW_EH_PE_pcrel - | dwarf2reader::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(dwarf2reader::DW_EH_PE_textrel - | dwarf2reader::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(dwarf2reader::DW_EH_PE_datarel - | dwarf2reader::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(dwarf2reader::DW_EH_PE_funcrel - | dwarf2reader::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(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); - EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); -} - -TEST(UsableBase, Text) { - ByteReader reader(ENDIANNESS_BIG); - reader.SetTextBase(0xa899ccb9); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); - EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); -} - -TEST(UsableBase, Data) { - ByteReader reader(ENDIANNESS_BIG); - reader.SetDataBase(0xf7b10bcd); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); - EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); -} - -TEST(UsableBase, Function) { - ByteReader reader(ENDIANNESS_BIG); - reader.SetFunctionBase(0xc2c0ed81); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::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(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::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, dwarf2reader::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, dwarf2reader::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, dwarf2reader::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, dwarf2reader::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, - dwarf2reader::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, - dwarf2reader::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, - dwarf2reader::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, - dwarf2reader::DW_EH_PE_aligned, - &pointer_size)); - EXPECT_EQ(5U, pointer_size); -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.cc deleted file mode 100644 index dbc2efae6..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.cc +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// cfi_assembler.cc: Implementation of google_breakpad::CFISection class. -// See cfi_assembler.h for details. - -#include "common/dwarf/cfi_assembler.h" - -#include <assert.h> -#include <stdlib.h> - -namespace google_breakpad { - -using dwarf2reader::DwarfPointerEncoding; - -CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor, - int data_alignment_factor, - unsigned return_address_register, - uint8_t version, - const string &augmentation, - bool dwarf64) { - 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); - 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_, dwarf2reader::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 == dwarf2reader::DW_EH_PE_omit) - return *this; - - // If (encoding & dwarf2reader::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 & ~dwarf2reader::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 dwarf2reader::DW_EH_PE_absptr: base = 0; break; - case dwarf2reader::DW_EH_PE_pcrel: base = bases.cfi + Size(); break; - case dwarf2reader::DW_EH_PE_textrel: base = bases.text; break; - case dwarf2reader::DW_EH_PE_datarel: base = bases.data; break; - case dwarf2reader::DW_EH_PE_funcrel: base = fde_start_address_; break; - case dwarf2reader::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) == dwarf2reader::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 dwarf2reader::DW_EH_PE_absptr: - Address(address); - break; - - case dwarf2reader::DW_EH_PE_uleb128: - ULEB128(address); - break; - - case dwarf2reader::DW_EH_PE_sleb128: - LEB128(address); - break; - - case dwarf2reader::DW_EH_PE_udata2: - case dwarf2reader::DW_EH_PE_sdata2: - D16(address); - break; - - case dwarf2reader::DW_EH_PE_udata4: - case dwarf2reader::DW_EH_PE_sdata4: - D32(address); - break; - - case dwarf2reader::DW_EH_PE_udata8: - case dwarf2reader::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 diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.h deleted file mode 100644 index 227812b58..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.h +++ /dev/null @@ -1,269 +0,0 @@ -// -*- mode: C++ -*- - -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// cfi_assembler.h: Define CFISection, a class for creating properly -// (and improperly) formatted DWARF CFI data for unit tests. - -#ifndef PROCESSOR_CFI_ASSEMBLER_H_ -#define PROCESSOR_CFI_ASSEMBLER_H_ - -#include <string> - -#include "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 dwarf2reader::DwarfPointerEncoding; -using google_breakpad::test_assembler::Endianness; -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(Endianness endianness, size_t address_size, - bool eh_frame = false) - : Section(endianness), address_size_(address_size), eh_frame_(eh_frame), - pointer_encoding_(dwarf2reader::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); - - // 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_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.cc deleted file mode 100644 index 94542b5ea..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.cc +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf2diehandler.cc: Implement the dwarf2reader::DieDispatcher class. -// See dwarf2diehandler.h for details. - -#include <assert.h> -#include <stdint.h> - -#include <string> - -#include "common/dwarf/dwarf2diehandler.h" -#include "common/using_std_string.h" - -namespace dwarf2reader { - -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 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 dwarf_version) { - return root_handler_->StartCompilationUnit(offset, address_size, - offset_size, cu_length, - dwarf_version); -} - -bool DIEDispatcher::StartDIE(uint64 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 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 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - HandlerStack ¤t = 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 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - int64 data) { - HandlerStack ¤t = 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 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - HandlerStack ¤t = 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 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const uint8_t *data, - uint64 len) { - HandlerStack ¤t = 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 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const string& data) { - HandlerStack ¤t = 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 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 signature) { - HandlerStack ¤t = 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 dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.h deleted file mode 100644 index a1e589a86..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.h +++ /dev/null @@ -1,365 +0,0 @@ -// -*- mode: c++ -*- - -// Copyright (c) 2010 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// 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 dwarf2reader { - -// 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 data) { } - virtual void ProcessAttributeSigned(enum DwarfAttribute attr, - enum DwarfForm form, - int64 data) { } - virtual void ProcessAttributeReference(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { } - virtual void ProcessAttributeBuffer(enum DwarfAttribute attr, - enum DwarfForm form, - const uint8_t *data, - uint64 len) { } - virtual void ProcessAttributeString(enum DwarfAttribute attr, - enum DwarfForm form, - const string& data) { } - virtual void ProcessAttributeSignature(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 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 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: - RootDIEHandler() { } - 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 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 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 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 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 dwarf_version); - bool StartDIE(uint64 offset, enum DwarfTag tag); - void ProcessAttributeUnsigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - void ProcessAttributeSigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - int64 data); - void ProcessAttributeReference(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - void ProcessAttributeBuffer(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const uint8_t *data, - uint64 len); - void ProcessAttributeString(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const string &data); - void ProcessAttributeSignature(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 signature); - void EndDIE(uint64 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 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 dwarf2reader -#endif // COMMON_DWARF_DWARF2DIEHANDLER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc deleted file mode 100644 index db70eb31b..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc +++ /dev/null @@ -1,527 +0,0 @@ -// -*- mode: c++ -*- - -// Copyright (c) 2010 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf2diehander_unittest.cc: Unit tests for google_breakpad::DIEDispatcher. - -#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 dwarf2reader::DIEDispatcher; -using dwarf2reader::DIEHandler; -using dwarf2reader::DwarfAttribute; -using dwarf2reader::DwarfForm; -using dwarf2reader::DwarfTag; -using dwarf2reader::RootDIEHandler; - -class MockDIEHandler: public DIEHandler { - public: - MOCK_METHOD3(ProcessAttributeUnsigned, - void(DwarfAttribute, DwarfForm, uint64)); - MOCK_METHOD3(ProcessAttributeSigned, - void(DwarfAttribute, DwarfForm, int64)); - MOCK_METHOD3(ProcessAttributeReference, - void(DwarfAttribute, DwarfForm, uint64)); - MOCK_METHOD4(ProcessAttributeBuffer, - void(DwarfAttribute, DwarfForm, const uint8_t *, uint64)); - MOCK_METHOD3(ProcessAttributeString, - void(DwarfAttribute, DwarfForm, const string &)); - MOCK_METHOD3(ProcessAttributeSignature, - void(DwarfAttribute, DwarfForm, uint64)); - MOCK_METHOD0(EndAttributes, bool()); - MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64, DwarfTag)); - MOCK_METHOD0(Finish, void()); -}; - -class MockRootDIEHandler: public RootDIEHandler { - public: - MOCK_METHOD3(ProcessAttributeUnsigned, - void(DwarfAttribute, DwarfForm, uint64)); - MOCK_METHOD3(ProcessAttributeSigned, - void(DwarfAttribute, DwarfForm, int64)); - MOCK_METHOD3(ProcessAttributeReference, - void(DwarfAttribute, DwarfForm, uint64)); - MOCK_METHOD4(ProcessAttributeBuffer, - void(DwarfAttribute, DwarfForm, const uint8_t *, uint64)); - MOCK_METHOD3(ProcessAttributeString, - void(DwarfAttribute, DwarfForm, const string &)); - MOCK_METHOD3(ProcessAttributeSignature, - void(DwarfAttribute, DwarfForm, uint64)); - MOCK_METHOD0(EndAttributes, bool()); - MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64, DwarfTag)); - MOCK_METHOD0(Finish, void()); - MOCK_METHOD5(StartCompilationUnit, bool(uint64, uint8, uint8, uint64, uint8)); - MOCK_METHOD2(StartRootDIE, bool(uint64, 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... - } -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2enums.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2enums.h deleted file mode 100644 index 6b8a72459..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2enums.h +++ /dev/null @@ -1,675 +0,0 @@ -// -*- mode: c++ -*- - -// Copyright (c) 2010 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef COMMON_DWARF_DWARF2ENUMS_H__ -#define COMMON_DWARF_DWARF2ENUMS_H__ - -namespace dwarf2reader { - -// 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, - // 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 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, - DW_FORM_ref_sig8 = 0x20, - // 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, - // 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 -}; - - -// 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_LOC = 5, - DW_SECT_STR_OFFSETS = 6, - DW_SECT_MACINFO = 7, - DW_SECT_MACRO = 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, - // 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 dwarf2reader -#endif // COMMON_DWARF_DWARF2ENUMS_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.cc deleted file mode 100644 index a65b43c8a..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.cc +++ /dev/null @@ -1,2734 +0,0 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// CFI reader author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// Implementation of dwarf2reader::LineInfo, dwarf2reader::CompilationUnit, -// and dwarf2reader::CallFrameInfo. See dwarf2reader.h for details. - -#include "common/dwarf/dwarf2reader.h" - -#include <assert.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> - -#include <map> -#include <memory> -#include <stack> -#include <string> -#include <utility> - -#include <sys/stat.h> - -#include "common/dwarf/bytereader-inl.h" -#include "common/dwarf/bytereader.h" -#include "common/dwarf/line_state_machine.h" -#include "common/using_std_string.h" - -namespace dwarf2reader { - -CompilationUnit::CompilationUnit(const string& path, - const SectionMap& sections, uint64 offset, - ByteReader* reader, Dwarf2Handler* handler) - : path_(path), offset_from_section_start_(offset), reader_(reader), - sections_(sections), handler_(handler), abbrevs_(), - string_buffer_(NULL), string_buffer_length_(0), - str_offsets_buffer_(NULL), str_offsets_buffer_length_(0), - addr_buffer_(NULL), addr_buffer_length_(0), - is_split_dwarf_(false), dwo_id_(0), dwo_name_(), - skeleton_dwo_id_(0), ranges_base_(0), addr_base_(0), - have_checked_for_dwp_(false), dwp_path_(), - dwp_byte_reader_(), dwp_reader_() {} - -// Initialize a compilation unit from a .dwo or .dwp file. -// In this case, we need the .debug_addr section from the -// executable file that contains the corresponding skeleton -// compilation unit. We also inherit the Dwarf2Handler from -// the executable file, and call it as if we were still -// processing the original compilation unit. - -void CompilationUnit::SetSplitDwarf(const uint8_t* addr_buffer, - uint64 addr_buffer_length, - uint64 addr_base, - uint64 ranges_base, - uint64 dwo_id) { - is_split_dwarf_ = true; - addr_buffer_ = addr_buffer; - addr_buffer_length_ = addr_buffer_length; - addr_base_ = addr_base; - ranges_base_ = ranges_base; - skeleton_dwo_id_ = dwo_id; -} - -// Read a DWARF2/3 abbreviation section. -// Each abbrev consists of a abbreviation number, a tag, a byte -// specifying whether the tag has children, and a list of -// attribute/form pairs. -// The list of forms is terminated by a 0 for the attribute, and a -// zero for the form. The entire abbreviation section is terminated -// by a zero for the code. - -void CompilationUnit::ReadAbbrevs() { - if (abbrevs_) - return; - - // First get the debug_abbrev section. ".debug_abbrev" is the name - // recommended in the DWARF spec, and used on Linux; - // "__debug_abbrev" is the name used in Mac OS X Mach-O files. - SectionMap::const_iterator iter = sections_.find(".debug_abbrev"); - if (iter == sections_.end()) - iter = sections_.find("__debug_abbrev"); - assert(iter != sections_.end()); - - abbrevs_ = new std::vector<Abbrev>; - abbrevs_->resize(1); - - // The only way to check whether we are reading over the end of the - // buffer would be to first compute the size of the leb128 data by - // reading it, then go back and read it again. - const uint8_t *abbrev_start = iter->second.first + - header_.abbrev_offset; - const uint8_t *abbrevptr = abbrev_start; -#ifndef NDEBUG - const uint64 abbrev_length = iter->second.second - header_.abbrev_offset; -#endif - - while (1) { - CompilationUnit::Abbrev abbrev; - size_t len; - const uint64 number = reader_->ReadUnsignedLEB128(abbrevptr, &len); - - if (number == 0) - break; - abbrev.number = number; - abbrevptr += len; - - assert(abbrevptr < abbrev_start + abbrev_length); - const uint64 tag = reader_->ReadUnsignedLEB128(abbrevptr, &len); - abbrevptr += len; - abbrev.tag = static_cast<enum DwarfTag>(tag); - - assert(abbrevptr < abbrev_start + abbrev_length); - abbrev.has_children = reader_->ReadOneByte(abbrevptr); - abbrevptr += 1; - - assert(abbrevptr < abbrev_start + abbrev_length); - - while (1) { - const uint64 nametemp = reader_->ReadUnsignedLEB128(abbrevptr, &len); - abbrevptr += len; - - assert(abbrevptr < abbrev_start + abbrev_length); - const uint64 formtemp = reader_->ReadUnsignedLEB128(abbrevptr, &len); - abbrevptr += len; - if (nametemp == 0 && formtemp == 0) - break; - - const enum DwarfAttribute name = - static_cast<enum DwarfAttribute>(nametemp); - const enum DwarfForm form = static_cast<enum DwarfForm>(formtemp); - abbrev.attributes.push_back(std::make_pair(name, form)); - } - assert(abbrev.number == abbrevs_->size()); - abbrevs_->push_back(abbrev); - } -} - -// Skips a single DIE's attributes. -const uint8_t *CompilationUnit::SkipDIE(const uint8_t* start, - const Abbrev& abbrev) { - for (AttributeList::const_iterator i = abbrev.attributes.begin(); - i != abbrev.attributes.end(); - i++) { - start = SkipAttribute(start, i->second); - } - return start; -} - -// Skips a single attribute form's data. -const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start, - enum DwarfForm form) { - size_t len; - - switch (form) { - case DW_FORM_indirect: - form = static_cast<enum DwarfForm>(reader_->ReadUnsignedLEB128(start, - &len)); - start += len; - return SkipAttribute(start, form); - - case DW_FORM_flag_present: - return start; - case DW_FORM_data1: - case DW_FORM_flag: - case DW_FORM_ref1: - return start + 1; - case DW_FORM_ref2: - case DW_FORM_data2: - return start + 2; - case DW_FORM_ref4: - case DW_FORM_data4: - return start + 4; - case DW_FORM_ref8: - case DW_FORM_data8: - case DW_FORM_ref_sig8: - return start + 8; - case DW_FORM_string: - return start + strlen(reinterpret_cast<const char *>(start)) + 1; - case DW_FORM_udata: - case DW_FORM_ref_udata: - case DW_FORM_GNU_str_index: - case DW_FORM_GNU_addr_index: - reader_->ReadUnsignedLEB128(start, &len); - return start + len; - - case DW_FORM_sdata: - reader_->ReadSignedLEB128(start, &len); - return start + len; - case DW_FORM_addr: - return start + reader_->AddressSize(); - case DW_FORM_ref_addr: - // DWARF2 and 3/4 differ on whether ref_addr is address size or - // offset size. - assert(header_.version >= 2); - if (header_.version == 2) { - return start + reader_->AddressSize(); - } else if (header_.version >= 3) { - return start + reader_->OffsetSize(); - } - break; - - case DW_FORM_block1: - return start + 1 + reader_->ReadOneByte(start); - case DW_FORM_block2: - return start + 2 + reader_->ReadTwoBytes(start); - case DW_FORM_block4: - return start + 4 + reader_->ReadFourBytes(start); - case DW_FORM_block: - case DW_FORM_exprloc: { - uint64 size = reader_->ReadUnsignedLEB128(start, &len); - return start + size + len; - } - case DW_FORM_strp: - case DW_FORM_sec_offset: - return start + reader_->OffsetSize(); - } - fprintf(stderr,"Unhandled form type"); - return NULL; -} - -// Read a DWARF2/3 header. -// The header is variable length in DWARF3 (and DWARF2 as extended by -// most compilers), and consists of an length field, a version number, -// the offset in the .debug_abbrev section for our abbrevs, and an -// address size. -void CompilationUnit::ReadHeader() { - const uint8_t *headerptr = buffer_; - size_t initial_length_size; - - assert(headerptr + 4 < buffer_ + buffer_length_); - const uint64 initial_length - = reader_->ReadInitialLength(headerptr, &initial_length_size); - headerptr += initial_length_size; - header_.length = initial_length; - - assert(headerptr + 2 < buffer_ + buffer_length_); - header_.version = reader_->ReadTwoBytes(headerptr); - headerptr += 2; - - assert(headerptr + reader_->OffsetSize() < buffer_ + buffer_length_); - header_.abbrev_offset = reader_->ReadOffset(headerptr); - headerptr += reader_->OffsetSize(); - - // Compare against less than or equal because this may be the last - // section in the file. - assert(headerptr + 1 <= buffer_ + buffer_length_); - header_.address_size = reader_->ReadOneByte(headerptr); - reader_->SetAddressSize(header_.address_size); - headerptr += 1; - - after_header_ = headerptr; - - // This check ensures that we don't have to do checking during the - // reading of DIEs. header_.length does not include the size of the - // initial length. - assert(buffer_ + initial_length_size + header_.length <= - buffer_ + buffer_length_); -} - -uint64 CompilationUnit::Start() { - // First get the debug_info section. ".debug_info" is the name - // recommended in the DWARF spec, and used on Linux; "__debug_info" - // is the name used in Mac OS X Mach-O files. - SectionMap::const_iterator iter = sections_.find(".debug_info"); - if (iter == sections_.end()) - iter = sections_.find("__debug_info"); - assert(iter != sections_.end()); - - // Set up our buffer - buffer_ = iter->second.first + offset_from_section_start_; - buffer_length_ = iter->second.second - offset_from_section_start_; - - // Read the header - ReadHeader(); - - // Figure out the real length from the end of the initial length to - // the end of the compilation unit, since that is the value we - // return. - uint64 ourlength = header_.length; - if (reader_->OffsetSize() == 8) - ourlength += 12; - else - ourlength += 4; - - // See if the user wants this compilation unit, and if not, just return. - if (!handler_->StartCompilationUnit(offset_from_section_start_, - reader_->AddressSize(), - reader_->OffsetSize(), - header_.length, - header_.version)) - return ourlength; - - // Otherwise, continue by reading our abbreviation entries. - ReadAbbrevs(); - - // Set the string section if we have one. ".debug_str" is the name - // recommended in the DWARF spec, and used on Linux; "__debug_str" - // is the name used in Mac OS X Mach-O files. - iter = sections_.find(".debug_str"); - if (iter == sections_.end()) - iter = sections_.find("__debug_str"); - if (iter != sections_.end()) { - string_buffer_ = iter->second.first; - string_buffer_length_ = iter->second.second; - } - - // Set the string offsets section if we have one. - iter = sections_.find(".debug_str_offsets"); - if (iter != sections_.end()) { - str_offsets_buffer_ = iter->second.first; - str_offsets_buffer_length_ = iter->second.second; - } - - // Set the address section if we have one. - iter = sections_.find(".debug_addr"); - if (iter != sections_.end()) { - addr_buffer_ = iter->second.first; - addr_buffer_length_ = iter->second.second; - } - - // Now that we have our abbreviations, start processing DIE's. - ProcessDIEs(); - - // If this is a skeleton compilation unit generated with split DWARF, - // and the client needs the full debug info, we need to find the full - // compilation unit in a .dwo or .dwp file. - if (!is_split_dwarf_ - && dwo_name_ != NULL - && handler_->NeedSplitDebugInfo()) - ProcessSplitDwarf(); - - return ourlength; -} - -// If one really wanted, you could merge SkipAttribute and -// ProcessAttribute -// This is all boring data manipulation and calling of the handler. -const uint8_t *CompilationUnit::ProcessAttribute( - uint64 dieoffset, const uint8_t *start, enum DwarfAttribute attr, - enum DwarfForm form) { - size_t len; - - switch (form) { - // DW_FORM_indirect is never used because it is such a space - // waster. - case DW_FORM_indirect: - form = static_cast<enum DwarfForm>(reader_->ReadUnsignedLEB128(start, - &len)); - start += len; - return ProcessAttribute(dieoffset, start, attr, form); - - case DW_FORM_flag_present: - ProcessAttributeUnsigned(dieoffset, attr, form, 1); - return start; - case DW_FORM_data1: - case DW_FORM_flag: - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadOneByte(start)); - return start + 1; - case DW_FORM_data2: - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadTwoBytes(start)); - return start + 2; - case DW_FORM_data4: - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadFourBytes(start)); - return start + 4; - case DW_FORM_data8: - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadEightBytes(start)); - return start + 8; - case DW_FORM_string: { - const char *str = reinterpret_cast<const char *>(start); - ProcessAttributeString(dieoffset, attr, form, str); - return start + strlen(str) + 1; - } - case DW_FORM_udata: - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadUnsignedLEB128(start, &len)); - return start + len; - - case DW_FORM_sdata: - ProcessAttributeSigned(dieoffset, attr, form, - reader_->ReadSignedLEB128(start, &len)); - return start + len; - case DW_FORM_addr: - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadAddress(start)); - return start + reader_->AddressSize(); - case DW_FORM_sec_offset: - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadOffset(start)); - return start + reader_->OffsetSize(); - - case DW_FORM_ref1: - handler_->ProcessAttributeReference(dieoffset, attr, form, - reader_->ReadOneByte(start) - + offset_from_section_start_); - return start + 1; - case DW_FORM_ref2: - handler_->ProcessAttributeReference(dieoffset, attr, form, - reader_->ReadTwoBytes(start) - + offset_from_section_start_); - return start + 2; - case DW_FORM_ref4: - handler_->ProcessAttributeReference(dieoffset, attr, form, - reader_->ReadFourBytes(start) - + offset_from_section_start_); - return start + 4; - case DW_FORM_ref8: - handler_->ProcessAttributeReference(dieoffset, attr, form, - reader_->ReadEightBytes(start) - + offset_from_section_start_); - return start + 8; - case DW_FORM_ref_udata: - handler_->ProcessAttributeReference(dieoffset, attr, form, - reader_->ReadUnsignedLEB128(start, - &len) - + offset_from_section_start_); - return start + len; - case DW_FORM_ref_addr: - // DWARF2 and 3/4 differ on whether ref_addr is address size or - // offset size. - assert(header_.version >= 2); - if (header_.version == 2) { - handler_->ProcessAttributeReference(dieoffset, attr, form, - reader_->ReadAddress(start)); - return start + reader_->AddressSize(); - } else if (header_.version >= 3) { - handler_->ProcessAttributeReference(dieoffset, attr, form, - reader_->ReadOffset(start)); - return start + reader_->OffsetSize(); - } - break; - case DW_FORM_ref_sig8: - handler_->ProcessAttributeSignature(dieoffset, attr, form, - reader_->ReadEightBytes(start)); - return start + 8; - - case DW_FORM_block1: { - uint64 datalen = reader_->ReadOneByte(start); - handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 1, - datalen); - return start + 1 + datalen; - } - case DW_FORM_block2: { - uint64 datalen = reader_->ReadTwoBytes(start); - handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 2, - datalen); - return start + 2 + datalen; - } - case DW_FORM_block4: { - uint64 datalen = reader_->ReadFourBytes(start); - handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 4, - datalen); - return start + 4 + datalen; - } - case DW_FORM_block: - case DW_FORM_exprloc: { - uint64 datalen = reader_->ReadUnsignedLEB128(start, &len); - handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + len, - datalen); - return start + datalen + len; - } - case DW_FORM_strp: { - assert(string_buffer_ != NULL); - - const uint64 offset = reader_->ReadOffset(start); - assert(string_buffer_ + offset < string_buffer_ + string_buffer_length_); - - const char *str = reinterpret_cast<const char *>(string_buffer_ + offset); - ProcessAttributeString(dieoffset, attr, form, str); - return start + reader_->OffsetSize(); - } - - case DW_FORM_GNU_str_index: { - uint64 str_index = reader_->ReadUnsignedLEB128(start, &len); - const uint8_t* offset_ptr = - str_offsets_buffer_ + str_index * reader_->OffsetSize(); - const uint64 offset = reader_->ReadOffset(offset_ptr); - if (offset >= string_buffer_length_) { - return NULL; - } - - const char* str = reinterpret_cast<const char *>(string_buffer_) + offset; - ProcessAttributeString(dieoffset, attr, form, str); - return start + len; - break; - } - case DW_FORM_GNU_addr_index: { - uint64 addr_index = reader_->ReadUnsignedLEB128(start, &len); - const uint8_t* addr_ptr = - addr_buffer_ + addr_base_ + addr_index * reader_->AddressSize(); - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadAddress(addr_ptr)); - return start + len; - } - } - fprintf(stderr, "Unhandled form type\n"); - return NULL; -} - -const uint8_t *CompilationUnit::ProcessDIE(uint64 dieoffset, - const uint8_t *start, - const Abbrev& abbrev) { - for (AttributeList::const_iterator i = abbrev.attributes.begin(); - i != abbrev.attributes.end(); - i++) { - start = ProcessAttribute(dieoffset, start, i->first, i->second); - } - - // If this is a compilation unit in a split DWARF object, verify that - // the dwo_id matches. If it does not match, we will ignore this - // compilation unit. - if (abbrev.tag == DW_TAG_compile_unit - && is_split_dwarf_ - && dwo_id_ != skeleton_dwo_id_) { - return NULL; - } - - return start; -} - -void CompilationUnit::ProcessDIEs() { - const uint8_t *dieptr = after_header_; - size_t len; - - // lengthstart is the place the length field is based on. - // It is the point in the header after the initial length field - const uint8_t *lengthstart = buffer_; - - // In 64 bit dwarf, the initial length is 12 bytes, because of the - // 0xffffffff at the start. - if (reader_->OffsetSize() == 8) - lengthstart += 12; - else - lengthstart += 4; - - std::stack<uint64> die_stack; - - while (dieptr < (lengthstart + header_.length)) { - // We give the user the absolute offset from the beginning of - // debug_info, since they need it to deal with ref_addr forms. - uint64 absolute_offset = (dieptr - buffer_) + offset_from_section_start_; - - uint64 abbrev_num = reader_->ReadUnsignedLEB128(dieptr, &len); - - dieptr += len; - - // Abbrev == 0 represents the end of a list of children, or padding - // at the end of the compilation unit. - if (abbrev_num == 0) { - if (die_stack.size() == 0) - // If it is padding, then we are done with the compilation unit's DIEs. - return; - const uint64 offset = die_stack.top(); - die_stack.pop(); - handler_->EndDIE(offset); - continue; - } - - const Abbrev& abbrev = abbrevs_->at(static_cast<size_t>(abbrev_num)); - const enum DwarfTag tag = abbrev.tag; - if (!handler_->StartDIE(absolute_offset, tag)) { - dieptr = SkipDIE(dieptr, abbrev); - } else { - dieptr = ProcessDIE(absolute_offset, dieptr, abbrev); - } - - if (abbrev.has_children) { - die_stack.push(absolute_offset); - } else { - handler_->EndDIE(absolute_offset); - } - } -} - -// Check for a valid ELF file and return the Address size. -// Returns 0 if not a valid ELF file. -inline int GetElfWidth(const ElfReader& elf) { - if (elf.IsElf32File()) - return 4; - if (elf.IsElf64File()) - return 8; - return 0; -} - -void CompilationUnit::ProcessSplitDwarf() { - struct stat statbuf; - if (!have_checked_for_dwp_) { - // Look for a .dwp file in the same directory as the executable. - have_checked_for_dwp_ = true; - string dwp_suffix(".dwp"); - dwp_path_ = path_ + dwp_suffix; - if (stat(dwp_path_.c_str(), &statbuf) != 0) { - // Fall back to a split .debug file in the same directory. - string debug_suffix(".debug"); - dwp_path_ = path_; - size_t found = path_.rfind(debug_suffix); - if (found + debug_suffix.length() == path_.length()) - dwp_path_ = dwp_path_.replace(found, debug_suffix.length(), dwp_suffix); - } - if (stat(dwp_path_.c_str(), &statbuf) == 0) { - ElfReader* elf = new ElfReader(dwp_path_); - int width = GetElfWidth(*elf); - if (width != 0) { - dwp_byte_reader_.reset(new ByteReader(reader_->GetEndianness())); - dwp_byte_reader_->SetAddressSize(width); - dwp_reader_.reset(new DwpReader(*dwp_byte_reader_, elf)); - dwp_reader_->Initialize(); - } else { - delete elf; - } - } - } - bool found_in_dwp = false; - if (dwp_reader_) { - // If we have a .dwp file, read the debug sections for the requested CU. - SectionMap sections; - dwp_reader_->ReadDebugSectionsForCU(dwo_id_, §ions); - if (!sections.empty()) { - found_in_dwp = true; - CompilationUnit dwp_comp_unit(dwp_path_, sections, 0, - dwp_byte_reader_.get(), handler_); - dwp_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, addr_base_, - ranges_base_, dwo_id_); - dwp_comp_unit.Start(); - } - } - if (!found_in_dwp) { - // If no .dwp file, try to open the .dwo file. - if (stat(dwo_name_, &statbuf) == 0) { - ElfReader elf(dwo_name_); - int width = GetElfWidth(elf); - if (width != 0) { - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(width); - SectionMap sections; - ReadDebugSectionsFromDwo(&elf, §ions); - CompilationUnit dwo_comp_unit(dwo_name_, sections, 0, &reader, - handler_); - dwo_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, - addr_base_, ranges_base_, dwo_id_); - dwo_comp_unit.Start(); - } - } - } -} - -void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader, - SectionMap* sections) { - static const char* const section_names[] = { - ".debug_abbrev", - ".debug_info", - ".debug_str_offsets", - ".debug_str" - }; - for (unsigned int i = 0u; - i < sizeof(section_names)/sizeof(*(section_names)); ++i) { - string base_name = section_names[i]; - string dwo_name = base_name + ".dwo"; - size_t section_size; - const char* section_data = elf_reader->GetSectionByName(dwo_name, - §ion_size); - if (section_data != NULL) - sections->insert(std::make_pair( - base_name, std::make_pair( - reinterpret_cast<const uint8_t *>(section_data), - section_size))); - } -} - -DwpReader::DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader) - : elf_reader_(elf_reader), byte_reader_(byte_reader), - cu_index_(NULL), cu_index_size_(0), string_buffer_(NULL), - string_buffer_size_(0), version_(0), ncolumns_(0), nunits_(0), - nslots_(0), phash_(NULL), pindex_(NULL), shndx_pool_(NULL), - offset_table_(NULL), size_table_(NULL), abbrev_data_(NULL), - abbrev_size_(0), info_data_(NULL), info_size_(0), - str_offsets_data_(NULL), str_offsets_size_(0) {} - -DwpReader::~DwpReader() { - if (elf_reader_) delete elf_reader_; -} - -void DwpReader::Initialize() { - cu_index_ = elf_reader_->GetSectionByName(".debug_cu_index", - &cu_index_size_); - if (cu_index_ == NULL) { - return; - } - // The .debug_str.dwo section is shared by all CUs in the file. - string_buffer_ = elf_reader_->GetSectionByName(".debug_str.dwo", - &string_buffer_size_); - - version_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_)); - - if (version_ == 1) { - nslots_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) - + 3 * sizeof(uint32)); - phash_ = cu_index_ + 4 * sizeof(uint32); - pindex_ = phash_ + nslots_ * sizeof(uint64); - shndx_pool_ = pindex_ + nslots_ * sizeof(uint32); - if (shndx_pool_ >= cu_index_ + cu_index_size_) { - version_ = 0; - } - } else if (version_ == 2) { - ncolumns_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) + sizeof(uint32)); - nunits_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) + 2 * sizeof(uint32)); - nslots_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) + 3 * sizeof(uint32)); - phash_ = cu_index_ + 4 * sizeof(uint32); - pindex_ = phash_ + nslots_ * sizeof(uint64); - offset_table_ = pindex_ + nslots_ * sizeof(uint32); - size_table_ = offset_table_ + ncolumns_ * (nunits_ + 1) * sizeof(uint32); - abbrev_data_ = elf_reader_->GetSectionByName(".debug_abbrev.dwo", - &abbrev_size_); - info_data_ = elf_reader_->GetSectionByName(".debug_info.dwo", &info_size_); - str_offsets_data_ = elf_reader_->GetSectionByName(".debug_str_offsets.dwo", - &str_offsets_size_); - if (size_table_ >= cu_index_ + cu_index_size_) { - version_ = 0; - } - } -} - -void DwpReader::ReadDebugSectionsForCU(uint64 dwo_id, - SectionMap* sections) { - if (version_ == 1) { - int slot = LookupCU(dwo_id); - if (slot == -1) { - return; - } - - // The index table points to the section index pool, where we - // can read a list of section indexes for the debug sections - // for the CU whose dwo_id we are looking for. - int index = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(pindex_) - + slot * sizeof(uint32)); - const char* shndx_list = shndx_pool_ + index * sizeof(uint32); - for (;;) { - if (shndx_list >= cu_index_ + cu_index_size_) { - version_ = 0; - return; - } - unsigned int shndx = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(shndx_list)); - shndx_list += sizeof(uint32); - if (shndx == 0) - break; - const char* section_name = elf_reader_->GetSectionName(shndx); - size_t section_size; - const char* section_data; - // We're only interested in these four debug sections. - // The section names in the .dwo file end with ".dwo", but we - // add them to the sections table with their normal names. - if (!strncmp(section_name, ".debug_abbrev", strlen(".debug_abbrev"))) { - section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); - sections->insert(std::make_pair( - ".debug_abbrev", - std::make_pair(reinterpret_cast<const uint8_t *> (section_data), - section_size))); - } else if (!strncmp(section_name, ".debug_info", strlen(".debug_info"))) { - section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); - sections->insert(std::make_pair( - ".debug_info", - std::make_pair(reinterpret_cast<const uint8_t *> (section_data), - section_size))); - } else if (!strncmp(section_name, ".debug_str_offsets", - strlen(".debug_str_offsets"))) { - section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); - sections->insert(std::make_pair( - ".debug_str_offsets", - std::make_pair(reinterpret_cast<const uint8_t *> (section_data), - section_size))); - } - } - sections->insert(std::make_pair( - ".debug_str", - std::make_pair(reinterpret_cast<const uint8_t *> (string_buffer_), - string_buffer_size_))); - } else if (version_ == 2) { - uint32 index = LookupCUv2(dwo_id); - if (index == 0) { - return; - } - - // The index points to a row in each of the section offsets table - // and the section size table, where we can read the offsets and sizes - // of the contributions to each debug section from the CU whose dwo_id - // we are looking for. Row 0 of the section offsets table has the - // section ids for each column of the table. The size table begins - // with row 1. - const char* id_row = offset_table_; - const char* offset_row = offset_table_ - + index * ncolumns_ * sizeof(uint32); - const char* size_row = - size_table_ + (index - 1) * ncolumns_ * sizeof(uint32); - if (size_row + ncolumns_ * sizeof(uint32) > cu_index_ + cu_index_size_) { - version_ = 0; - return; - } - for (unsigned int col = 0u; col < ncolumns_; ++col) { - uint32 section_id = - byte_reader_.ReadFourBytes(reinterpret_cast<const uint8_t *>(id_row) - + col * sizeof(uint32)); - uint32 offset = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(offset_row) - + col * sizeof(uint32)); - uint32 size = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(size_row) + col * sizeof(uint32)); - if (section_id == DW_SECT_ABBREV) { - sections->insert(std::make_pair( - ".debug_abbrev", - std::make_pair(reinterpret_cast<const uint8_t *> (abbrev_data_) - + offset, size))); - } else if (section_id == DW_SECT_INFO) { - sections->insert(std::make_pair( - ".debug_info", - std::make_pair(reinterpret_cast<const uint8_t *> (info_data_) - + offset, size))); - } else if (section_id == DW_SECT_STR_OFFSETS) { - sections->insert(std::make_pair( - ".debug_str_offsets", - std::make_pair(reinterpret_cast<const uint8_t *> (str_offsets_data_) - + offset, size))); - } - } - sections->insert(std::make_pair( - ".debug_str", - std::make_pair(reinterpret_cast<const uint8_t *> (string_buffer_), - string_buffer_size_))); - } -} - -int DwpReader::LookupCU(uint64 dwo_id) { - uint32 slot = static_cast<uint32>(dwo_id) & (nslots_ - 1); - uint64 probe = byte_reader_.ReadEightBytes( - reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64)); - if (probe != 0 && probe != dwo_id) { - uint32 secondary_hash = - (static_cast<uint32>(dwo_id >> 32) & (nslots_ - 1)) | 1; - do { - slot = (slot + secondary_hash) & (nslots_ - 1); - probe = byte_reader_.ReadEightBytes( - reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64)); - } while (probe != 0 && probe != dwo_id); - } - if (probe == 0) - return -1; - return slot; -} - -uint32 DwpReader::LookupCUv2(uint64 dwo_id) { - uint32 slot = static_cast<uint32>(dwo_id) & (nslots_ - 1); - uint64 probe = byte_reader_.ReadEightBytes( - reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64)); - uint32 index = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32)); - if (index != 0 && probe != dwo_id) { - uint32 secondary_hash = - (static_cast<uint32>(dwo_id >> 32) & (nslots_ - 1)) | 1; - do { - slot = (slot + secondary_hash) & (nslots_ - 1); - probe = byte_reader_.ReadEightBytes( - reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64)); - index = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32)); - } while (index != 0 && probe != dwo_id); - } - return index; -} - -LineInfo::LineInfo(const uint8_t *buffer, uint64 buffer_length, - ByteReader* reader, LineInfoHandler* handler): - handler_(handler), reader_(reader), buffer_(buffer) { -#ifndef NDEBUG - buffer_length_ = buffer_length; -#endif - header_.std_opcode_lengths = NULL; -} - -uint64 LineInfo::Start() { - ReadHeader(); - ReadLines(); - return after_header_ - buffer_; -} - -// The header for a debug_line section is mildly complicated, because -// the line info is very tightly encoded. -void LineInfo::ReadHeader() { - const uint8_t *lineptr = buffer_; - size_t initial_length_size; - - const uint64 initial_length - = reader_->ReadInitialLength(lineptr, &initial_length_size); - - lineptr += initial_length_size; - header_.total_length = initial_length; - assert(buffer_ + initial_length_size + header_.total_length <= - buffer_ + buffer_length_); - - // Address size *must* be set by CU ahead of time. - assert(reader_->AddressSize() != 0); - - header_.version = reader_->ReadTwoBytes(lineptr); - lineptr += 2; - - header_.prologue_length = reader_->ReadOffset(lineptr); - lineptr += reader_->OffsetSize(); - - header_.min_insn_length = reader_->ReadOneByte(lineptr); - lineptr += 1; - - header_.default_is_stmt = reader_->ReadOneByte(lineptr); - lineptr += 1; - - header_.line_base = *reinterpret_cast<const int8*>(lineptr); - lineptr += 1; - - header_.line_range = reader_->ReadOneByte(lineptr); - lineptr += 1; - - header_.opcode_base = reader_->ReadOneByte(lineptr); - lineptr += 1; - - header_.std_opcode_lengths = new std::vector<unsigned char>; - header_.std_opcode_lengths->resize(header_.opcode_base + 1); - (*header_.std_opcode_lengths)[0] = 0; - for (int i = 1; i < header_.opcode_base; i++) { - (*header_.std_opcode_lengths)[i] = reader_->ReadOneByte(lineptr); - lineptr += 1; - } - - // It is legal for the directory entry table to be empty. - if (*lineptr) { - uint32 dirindex = 1; - while (*lineptr) { - const char *dirname = reinterpret_cast<const char *>(lineptr); - handler_->DefineDir(dirname, dirindex); - lineptr += strlen(dirname) + 1; - dirindex++; - } - } - lineptr++; - - // It is also legal for the file entry table to be empty. - if (*lineptr) { - uint32 fileindex = 1; - size_t len; - while (*lineptr) { - const char *filename = reinterpret_cast<const char *>(lineptr); - lineptr += strlen(filename) + 1; - - uint64 dirindex = reader_->ReadUnsignedLEB128(lineptr, &len); - lineptr += len; - - uint64 mod_time = reader_->ReadUnsignedLEB128(lineptr, &len); - lineptr += len; - - uint64 filelength = reader_->ReadUnsignedLEB128(lineptr, &len); - lineptr += len; - handler_->DefineFile(filename, fileindex, static_cast<uint32>(dirindex), - mod_time, filelength); - fileindex++; - } - } - lineptr++; - - after_header_ = lineptr; -} - -/* static */ -bool LineInfo::ProcessOneOpcode(ByteReader* reader, - LineInfoHandler* handler, - const struct LineInfoHeader &header, - const uint8_t *start, - struct LineStateMachine* lsm, - size_t* len, - uintptr pc, - bool *lsm_passes_pc) { - size_t oplen = 0; - size_t templen; - uint8 opcode = reader->ReadOneByte(start); - oplen++; - start++; - - // If the opcode is great than the opcode_base, it is a special - // opcode. Most line programs consist mainly of special opcodes. - if (opcode >= header.opcode_base) { - opcode -= header.opcode_base; - const int64 advance_address = (opcode / header.line_range) - * header.min_insn_length; - const int32 advance_line = (opcode % header.line_range) - + header.line_base; - - // Check if the lsm passes "pc". If so, mark it as passed. - if (lsm_passes_pc && - lsm->address <= pc && pc < lsm->address + advance_address) { - *lsm_passes_pc = true; - } - - lsm->address += advance_address; - lsm->line_num += advance_line; - lsm->basic_block = true; - *len = oplen; - return true; - } - - // Otherwise, we have the regular opcodes - switch (opcode) { - case DW_LNS_copy: { - lsm->basic_block = false; - *len = oplen; - return true; - } - - case DW_LNS_advance_pc: { - uint64 advance_address = reader->ReadUnsignedLEB128(start, &templen); - oplen += templen; - - // Check if the lsm passes "pc". If so, mark it as passed. - if (lsm_passes_pc && lsm->address <= pc && - pc < lsm->address + header.min_insn_length * advance_address) { - *lsm_passes_pc = true; - } - - lsm->address += header.min_insn_length * advance_address; - } - break; - case DW_LNS_advance_line: { - const int64 advance_line = reader->ReadSignedLEB128(start, &templen); - oplen += templen; - lsm->line_num += static_cast<int32>(advance_line); - - // With gcc 4.2.1, we can get the line_no here for the first time - // since DW_LNS_advance_line is called after DW_LNE_set_address is - // called. So we check if the lsm passes "pc" here, not in - // DW_LNE_set_address. - if (lsm_passes_pc && lsm->address == pc) { - *lsm_passes_pc = true; - } - } - break; - case DW_LNS_set_file: { - const uint64 fileno = reader->ReadUnsignedLEB128(start, &templen); - oplen += templen; - lsm->file_num = static_cast<uint32>(fileno); - } - break; - case DW_LNS_set_column: { - const uint64 colno = reader->ReadUnsignedLEB128(start, &templen); - oplen += templen; - lsm->column_num = static_cast<uint32>(colno); - } - break; - case DW_LNS_negate_stmt: { - lsm->is_stmt = !lsm->is_stmt; - } - break; - case DW_LNS_set_basic_block: { - lsm->basic_block = true; - } - break; - case DW_LNS_fixed_advance_pc: { - const uint16 advance_address = reader->ReadTwoBytes(start); - oplen += 2; - - // Check if the lsm passes "pc". If so, mark it as passed. - if (lsm_passes_pc && - lsm->address <= pc && pc < lsm->address + advance_address) { - *lsm_passes_pc = true; - } - - lsm->address += advance_address; - } - break; - case DW_LNS_const_add_pc: { - const int64 advance_address = header.min_insn_length - * ((255 - header.opcode_base) - / header.line_range); - - // Check if the lsm passes "pc". If so, mark it as passed. - if (lsm_passes_pc && - lsm->address <= pc && pc < lsm->address + advance_address) { - *lsm_passes_pc = true; - } - - lsm->address += advance_address; - } - break; - case DW_LNS_extended_op: { - const uint64 extended_op_len = reader->ReadUnsignedLEB128(start, - &templen); - start += templen; - oplen += templen + extended_op_len; - - const uint64 extended_op = reader->ReadOneByte(start); - start++; - - switch (extended_op) { - case DW_LNE_end_sequence: { - lsm->end_sequence = true; - *len = oplen; - return true; - } - break; - case DW_LNE_set_address: { - // With gcc 4.2.1, we cannot tell the line_no here since - // DW_LNE_set_address is called before DW_LNS_advance_line is - // called. So we do not check if the lsm passes "pc" here. See - // also the comment in DW_LNS_advance_line. - uint64 address = reader->ReadAddress(start); - lsm->address = address; - } - break; - case DW_LNE_define_file: { - const char *filename = reinterpret_cast<const char *>(start); - - templen = strlen(filename) + 1; - start += templen; - - uint64 dirindex = reader->ReadUnsignedLEB128(start, &templen); - oplen += templen; - - const uint64 mod_time = reader->ReadUnsignedLEB128(start, - &templen); - oplen += templen; - - const uint64 filelength = reader->ReadUnsignedLEB128(start, - &templen); - oplen += templen; - - if (handler) { - handler->DefineFile(filename, -1, static_cast<uint32>(dirindex), - mod_time, filelength); - } - } - break; - } - } - break; - - default: { - // Ignore unknown opcode silently - if (header.std_opcode_lengths) { - for (int i = 0; i < (*header.std_opcode_lengths)[opcode]; i++) { - reader->ReadUnsignedLEB128(start, &templen); - start += templen; - oplen += templen; - } - } - } - break; - } - *len = oplen; - return false; -} - -void LineInfo::ReadLines() { - struct LineStateMachine lsm; - - // lengthstart is the place the length field is based on. - // It is the point in the header after the initial length field - const uint8_t *lengthstart = buffer_; - - // In 64 bit dwarf, the initial length is 12 bytes, because of the - // 0xffffffff at the start. - if (reader_->OffsetSize() == 8) - lengthstart += 12; - else - lengthstart += 4; - - const uint8_t *lineptr = after_header_; - lsm.Reset(header_.default_is_stmt); - - // The LineInfoHandler interface expects each line's length along - // with its address, but DWARF only provides addresses (sans - // length), and an end-of-sequence address; one infers the length - // from the next address. So we report a line only when we get the - // next line's address, or the end-of-sequence address. - bool have_pending_line = false; - uint64 pending_address = 0; - uint32 pending_file_num = 0, pending_line_num = 0, pending_column_num = 0; - - while (lineptr < lengthstart + header_.total_length) { - size_t oplength; - bool add_row = ProcessOneOpcode(reader_, handler_, header_, - lineptr, &lsm, &oplength, (uintptr)-1, - NULL); - if (add_row) { - if (have_pending_line) - handler_->AddLine(pending_address, lsm.address - pending_address, - pending_file_num, pending_line_num, - pending_column_num); - if (lsm.end_sequence) { - lsm.Reset(header_.default_is_stmt); - have_pending_line = false; - } else { - pending_address = lsm.address; - pending_file_num = lsm.file_num; - pending_line_num = lsm.line_num; - pending_column_num = lsm.column_num; - have_pending_line = true; - } - } - lineptr += oplength; - } - - after_header_ = lengthstart + header_.total_length; -} - -// A DWARF rule for recovering the address or value of a register, or -// computing the canonical frame address. There is one subclass of this for -// each '*Rule' member function in CallFrameInfo::Handler. -// -// It's annoying that we have to handle Rules using pointers (because -// the concrete instances can have an arbitrary size). They're small, -// so it would be much nicer if we could just handle them by value -// instead of fretting about ownership and destruction. -// -// It seems like all these could simply be instances of std::tr1::bind, -// except that we need instances to be EqualityComparable, too. -// -// This could logically be nested within State, but then the qualified names -// get horrendous. -class CallFrameInfo::Rule { - public: - virtual ~Rule() { } - - // Tell HANDLER that, at ADDRESS in the program, REGISTER can be - // recovered using this rule. If REGISTER is kCFARegister, then this rule - // describes how to compute the canonical frame address. Return what the - // HANDLER member function returned. - virtual bool Handle(Handler *handler, - uint64 address, int register) const = 0; - - // Equality on rules. We use these to decide which rules we need - // to report after a DW_CFA_restore_state instruction. - virtual bool operator==(const Rule &rhs) const = 0; - - bool operator!=(const Rule &rhs) const { return ! (*this == rhs); } - - // Return a pointer to a copy of this rule. - virtual Rule *Copy() const = 0; - - // If this is a base+offset rule, change its base register to REG. - // Otherwise, do nothing. (Ugly, but required for DW_CFA_def_cfa_register.) - virtual void SetBaseRegister(unsigned reg) { } - - // If this is a base+offset rule, change its offset to OFFSET. Otherwise, - // do nothing. (Ugly, but required for DW_CFA_def_cfa_offset.) - virtual void SetOffset(long long offset) { } -}; - -// Rule: the value the register had in the caller cannot be recovered. -class CallFrameInfo::UndefinedRule: public CallFrameInfo::Rule { - public: - UndefinedRule() { } - ~UndefinedRule() { } - bool Handle(Handler *handler, uint64 address, int reg) const { - return handler->UndefinedRule(address, reg); - } - bool operator==(const Rule &rhs) const { - // dynamic_cast is allowed by the Google C++ Style Guide, if the use has - // been carefully considered; cheap RTTI-like workarounds are forbidden. - const UndefinedRule *our_rhs = dynamic_cast<const UndefinedRule *>(&rhs); - return (our_rhs != NULL); - } - Rule *Copy() const { return new UndefinedRule(*this); } -}; - -// Rule: the register's value is the same as that it had in the caller. -class CallFrameInfo::SameValueRule: public CallFrameInfo::Rule { - public: - SameValueRule() { } - ~SameValueRule() { } - bool Handle(Handler *handler, uint64 address, int reg) const { - return handler->SameValueRule(address, reg); - } - bool operator==(const Rule &rhs) const { - // dynamic_cast is allowed by the Google C++ Style Guide, if the use has - // been carefully considered; cheap RTTI-like workarounds are forbidden. - const SameValueRule *our_rhs = dynamic_cast<const SameValueRule *>(&rhs); - return (our_rhs != NULL); - } - Rule *Copy() const { return new SameValueRule(*this); } -}; - -// Rule: the register is saved at OFFSET from BASE_REGISTER. BASE_REGISTER -// may be CallFrameInfo::Handler::kCFARegister. -class CallFrameInfo::OffsetRule: public CallFrameInfo::Rule { - public: - OffsetRule(int base_register, long offset) - : base_register_(base_register), offset_(offset) { } - ~OffsetRule() { } - bool Handle(Handler *handler, uint64 address, int reg) const { - return handler->OffsetRule(address, reg, base_register_, offset_); - } - bool operator==(const Rule &rhs) const { - // dynamic_cast is allowed by the Google C++ Style Guide, if the use has - // been carefully considered; cheap RTTI-like workarounds are forbidden. - const OffsetRule *our_rhs = dynamic_cast<const OffsetRule *>(&rhs); - return (our_rhs && - base_register_ == our_rhs->base_register_ && - offset_ == our_rhs->offset_); - } - Rule *Copy() const { return new OffsetRule(*this); } - // We don't actually need SetBaseRegister or SetOffset here, since they - // are only ever applied to CFA rules, for DW_CFA_def_cfa_offset, and it - // doesn't make sense to use OffsetRule for computing the CFA: it - // computes the address at which a register is saved, not a value. - private: - int base_register_; - long offset_; -}; - -// Rule: the value the register had in the caller is the value of -// BASE_REGISTER plus offset. BASE_REGISTER may be -// CallFrameInfo::Handler::kCFARegister. -class CallFrameInfo::ValOffsetRule: public CallFrameInfo::Rule { - public: - ValOffsetRule(int base_register, long offset) - : base_register_(base_register), offset_(offset) { } - ~ValOffsetRule() { } - bool Handle(Handler *handler, uint64 address, int reg) const { - return handler->ValOffsetRule(address, reg, base_register_, offset_); - } - bool operator==(const Rule &rhs) const { - // dynamic_cast is allowed by the Google C++ Style Guide, if the use has - // been carefully considered; cheap RTTI-like workarounds are forbidden. - const ValOffsetRule *our_rhs = dynamic_cast<const ValOffsetRule *>(&rhs); - return (our_rhs && - base_register_ == our_rhs->base_register_ && - offset_ == our_rhs->offset_); - } - Rule *Copy() const { return new ValOffsetRule(*this); } - void SetBaseRegister(unsigned reg) { base_register_ = reg; } - void SetOffset(long long offset) { offset_ = offset; } - private: - int base_register_; - long offset_; -}; - -// Rule: the register has been saved in another register REGISTER_NUMBER_. -class CallFrameInfo::RegisterRule: public CallFrameInfo::Rule { - public: - explicit RegisterRule(int register_number) - : register_number_(register_number) { } - ~RegisterRule() { } - bool Handle(Handler *handler, uint64 address, int reg) const { - return handler->RegisterRule(address, reg, register_number_); - } - bool operator==(const Rule &rhs) const { - // dynamic_cast is allowed by the Google C++ Style Guide, if the use has - // been carefully considered; cheap RTTI-like workarounds are forbidden. - const RegisterRule *our_rhs = dynamic_cast<const RegisterRule *>(&rhs); - return (our_rhs && register_number_ == our_rhs->register_number_); - } - Rule *Copy() const { return new RegisterRule(*this); } - private: - int register_number_; -}; - -// Rule: EXPRESSION evaluates to the address at which the register is saved. -class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule { - public: - explicit ExpressionRule(const string &expression) - : expression_(expression) { } - ~ExpressionRule() { } - bool Handle(Handler *handler, uint64 address, int reg) const { - return handler->ExpressionRule(address, reg, expression_); - } - bool operator==(const Rule &rhs) const { - // dynamic_cast is allowed by the Google C++ Style Guide, if the use has - // been carefully considered; cheap RTTI-like workarounds are forbidden. - const ExpressionRule *our_rhs = dynamic_cast<const ExpressionRule *>(&rhs); - return (our_rhs && expression_ == our_rhs->expression_); - } - Rule *Copy() const { return new ExpressionRule(*this); } - private: - string expression_; -}; - -// Rule: EXPRESSION evaluates to the address at which the register is saved. -class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule { - public: - explicit ValExpressionRule(const string &expression) - : expression_(expression) { } - ~ValExpressionRule() { } - bool Handle(Handler *handler, uint64 address, int reg) const { - return handler->ValExpressionRule(address, reg, expression_); - } - bool operator==(const Rule &rhs) const { - // dynamic_cast is allowed by the Google C++ Style Guide, if the use has - // been carefully considered; cheap RTTI-like workarounds are forbidden. - const ValExpressionRule *our_rhs = - dynamic_cast<const ValExpressionRule *>(&rhs); - return (our_rhs && expression_ == our_rhs->expression_); - } - Rule *Copy() const { return new ValExpressionRule(*this); } - private: - string expression_; -}; - -// A map from register numbers to rules. -class CallFrameInfo::RuleMap { - public: - RuleMap() : cfa_rule_(NULL) { } - RuleMap(const RuleMap &rhs) : cfa_rule_(NULL) { *this = rhs; } - ~RuleMap() { Clear(); } - - RuleMap &operator=(const RuleMap &rhs); - - // Set the rule for computing the CFA to RULE. Take ownership of RULE. - void SetCFARule(Rule *rule) { delete cfa_rule_; cfa_rule_ = rule; } - - // Return the current CFA rule. Unlike RegisterRule, this RuleMap retains - // ownership of the rule. We use this for DW_CFA_def_cfa_offset and - // DW_CFA_def_cfa_register, and for detecting references to the CFA before - // a rule for it has been established. - Rule *CFARule() const { return cfa_rule_; } - - // Return the rule for REG, or NULL if there is none. The caller takes - // ownership of the result. - Rule *RegisterRule(int reg) const; - - // Set the rule for computing REG to RULE. Take ownership of RULE. - void SetRegisterRule(int reg, Rule *rule); - - // Make all the appropriate calls to HANDLER as if we were changing from - // this RuleMap to NEW_RULES at ADDRESS. We use this to implement - // DW_CFA_restore_state, where lots of rules can change simultaneously. - // Return true if all handlers returned true; otherwise, return false. - bool HandleTransitionTo(Handler *handler, uint64 address, - const RuleMap &new_rules) const; - - private: - // A map from register numbers to Rules. - typedef std::map<int, Rule *> RuleByNumber; - - // Remove all register rules and clear cfa_rule_. - void Clear(); - - // The rule for computing the canonical frame address. This RuleMap owns - // this rule. - Rule *cfa_rule_; - - // A map from register numbers to postfix expressions to recover - // their values. This RuleMap owns the Rules the map refers to. - RuleByNumber registers_; -}; - -CallFrameInfo::RuleMap &CallFrameInfo::RuleMap::operator=(const RuleMap &rhs) { - Clear(); - // Since each map owns the rules it refers to, assignment must copy them. - if (rhs.cfa_rule_) cfa_rule_ = rhs.cfa_rule_->Copy(); - for (RuleByNumber::const_iterator it = rhs.registers_.begin(); - it != rhs.registers_.end(); it++) - registers_[it->first] = it->second->Copy(); - return *this; -} - -CallFrameInfo::Rule *CallFrameInfo::RuleMap::RegisterRule(int reg) const { - assert(reg != Handler::kCFARegister); - RuleByNumber::const_iterator it = registers_.find(reg); - if (it != registers_.end()) - return it->second->Copy(); - else - return NULL; -} - -void CallFrameInfo::RuleMap::SetRegisterRule(int reg, Rule *rule) { - assert(reg != Handler::kCFARegister); - assert(rule); - Rule **slot = ®isters_[reg]; - delete *slot; - *slot = rule; -} - -bool CallFrameInfo::RuleMap::HandleTransitionTo( - Handler *handler, - uint64 address, - const RuleMap &new_rules) const { - // Transition from cfa_rule_ to new_rules.cfa_rule_. - if (cfa_rule_ && new_rules.cfa_rule_) { - if (*cfa_rule_ != *new_rules.cfa_rule_ && - !new_rules.cfa_rule_->Handle(handler, address, - Handler::kCFARegister)) - return false; - } else if (cfa_rule_) { - // this RuleMap has a CFA rule but new_rules doesn't. - // CallFrameInfo::Handler has no way to handle this --- and shouldn't; - // it's garbage input. The instruction interpreter should have - // detected this and warned, so take no action here. - } else if (new_rules.cfa_rule_) { - // This shouldn't be possible: NEW_RULES is some prior state, and - // there's no way to remove entries. - assert(0); - } else { - // Both CFA rules are empty. No action needed. - } - - // Traverse the two maps in order by register number, and report - // whatever differences we find. - RuleByNumber::const_iterator old_it = registers_.begin(); - RuleByNumber::const_iterator new_it = new_rules.registers_.begin(); - while (old_it != registers_.end() && new_it != new_rules.registers_.end()) { - if (old_it->first < new_it->first) { - // This RuleMap has an entry for old_it->first, but NEW_RULES - // doesn't. - // - // This isn't really the right thing to do, but since CFI generally - // only mentions callee-saves registers, and GCC's convention for - // callee-saves registers is that they are unchanged, it's a good - // approximation. - if (!handler->SameValueRule(address, old_it->first)) - return false; - old_it++; - } else if (old_it->first > new_it->first) { - // NEW_RULES has entry for new_it->first, but this RuleMap - // doesn't. This shouldn't be possible: NEW_RULES is some prior - // state, and there's no way to remove entries. - assert(0); - } else { - // Both maps have an entry for this register. Report the new - // rule if it is different. - if (*old_it->second != *new_it->second && - !new_it->second->Handle(handler, address, new_it->first)) - return false; - new_it++, old_it++; - } - } - // Finish off entries from this RuleMap with no counterparts in new_rules. - while (old_it != registers_.end()) { - if (!handler->SameValueRule(address, old_it->first)) - return false; - old_it++; - } - // Since we only make transitions from a rule set to some previously - // saved rule set, and we can only add rules to the map, NEW_RULES - // must have fewer rules than *this. - assert(new_it == new_rules.registers_.end()); - - return true; -} - -// Remove all register rules and clear cfa_rule_. -void CallFrameInfo::RuleMap::Clear() { - delete cfa_rule_; - cfa_rule_ = NULL; - for (RuleByNumber::iterator it = registers_.begin(); - it != registers_.end(); it++) - delete it->second; - registers_.clear(); -} - -// The state of the call frame information interpreter as it processes -// instructions from a CIE and FDE. -class CallFrameInfo::State { - public: - // Create a call frame information interpreter state with the given - // reporter, reader, handler, and initial call frame info address. - State(ByteReader *reader, Handler *handler, Reporter *reporter, - uint64 address) - : reader_(reader), handler_(handler), reporter_(reporter), - address_(address), entry_(NULL), cursor_(NULL) { } - - // Interpret instructions from CIE, save the resulting rule set for - // DW_CFA_restore instructions, and return true. On error, report - // the problem to reporter_ and return false. - bool InterpretCIE(const CIE &cie); - - // Interpret instructions from FDE, and return true. On error, - // report the problem to reporter_ and return false. - bool InterpretFDE(const FDE &fde); - - private: - // The operands of a CFI instruction, for ParseOperands. - struct Operands { - unsigned register_number; // A register number. - uint64 offset; // An offset or address. - long signed_offset; // A signed offset. - string expression; // A DWARF expression. - }; - - // Parse CFI instruction operands from STATE's instruction stream as - // described by FORMAT. On success, populate OPERANDS with the - // results, and return true. On failure, report the problem and - // return false. - // - // Each character of FORMAT should be one of the following: - // - // 'r' unsigned LEB128 register number (OPERANDS->register_number) - // 'o' unsigned LEB128 offset (OPERANDS->offset) - // 's' signed LEB128 offset (OPERANDS->signed_offset) - // 'a' machine-size address (OPERANDS->offset) - // (If the CIE has a 'z' augmentation string, 'a' uses the - // encoding specified by the 'R' argument.) - // '1' a one-byte offset (OPERANDS->offset) - // '2' a two-byte offset (OPERANDS->offset) - // '4' a four-byte offset (OPERANDS->offset) - // '8' an eight-byte offset (OPERANDS->offset) - // 'e' a DW_FORM_block holding a (OPERANDS->expression) - // DWARF expression - bool ParseOperands(const char *format, Operands *operands); - - // Interpret one CFI instruction from STATE's instruction stream, update - // STATE, report any rule changes to handler_, and return true. On - // failure, report the problem and return false. - bool DoInstruction(); - - // The following Do* member functions are subroutines of DoInstruction, - // factoring out the actual work of operations that have several - // different encodings. - - // Set the CFA rule to be the value of BASE_REGISTER plus OFFSET, and - // return true. On failure, report and return false. (Used for - // DW_CFA_def_cfa and DW_CFA_def_cfa_sf.) - bool DoDefCFA(unsigned base_register, long offset); - - // Change the offset of the CFA rule to OFFSET, and return true. On - // failure, report and return false. (Subroutine for - // DW_CFA_def_cfa_offset and DW_CFA_def_cfa_offset_sf.) - bool DoDefCFAOffset(long offset); - - // Specify that REG can be recovered using RULE, and return true. On - // failure, report and return false. - bool DoRule(unsigned reg, Rule *rule); - - // Specify that REG can be found at OFFSET from the CFA, and return true. - // On failure, report and return false. (Subroutine for DW_CFA_offset, - // DW_CFA_offset_extended, and DW_CFA_offset_extended_sf.) - bool DoOffset(unsigned reg, long offset); - - // Specify that the caller's value for REG is the CFA plus OFFSET, - // and return true. On failure, report and return false. (Subroutine - // for DW_CFA_val_offset and DW_CFA_val_offset_sf.) - bool DoValOffset(unsigned reg, long offset); - - // Restore REG to the rule established in the CIE, and return true. On - // failure, report and return false. (Subroutine for DW_CFA_restore and - // DW_CFA_restore_extended.) - bool DoRestore(unsigned reg); - - // Return the section offset of the instruction at cursor. For use - // in error messages. - uint64 CursorOffset() { return entry_->offset + (cursor_ - entry_->start); } - - // Report that entry_ is incomplete, and return false. For brevity. - bool ReportIncomplete() { - reporter_->Incomplete(entry_->offset, entry_->kind); - return false; - } - - // For reading multi-byte values with the appropriate endianness. - ByteReader *reader_; - - // The handler to which we should report the data we find. - Handler *handler_; - - // For reporting problems in the info we're parsing. - Reporter *reporter_; - - // The code address to which the next instruction in the stream applies. - uint64 address_; - - // The entry whose instructions we are currently processing. This is - // first a CIE, and then an FDE. - const Entry *entry_; - - // The next instruction to process. - const uint8_t *cursor_; - - // The current set of rules. - RuleMap rules_; - - // The set of rules established by the CIE, used by DW_CFA_restore - // and DW_CFA_restore_extended. We set this after interpreting the - // CIE's instructions. - RuleMap cie_rules_; - - // A stack of saved states, for DW_CFA_remember_state and - // DW_CFA_restore_state. - std::stack<RuleMap> saved_rules_; -}; - -bool CallFrameInfo::State::InterpretCIE(const CIE &cie) { - entry_ = &cie; - cursor_ = entry_->instructions; - while (cursor_ < entry_->end) - if (!DoInstruction()) - return false; - // Note the rules established by the CIE, for use by DW_CFA_restore - // and DW_CFA_restore_extended. - cie_rules_ = rules_; - return true; -} - -bool CallFrameInfo::State::InterpretFDE(const FDE &fde) { - entry_ = &fde; - cursor_ = entry_->instructions; - while (cursor_ < entry_->end) - if (!DoInstruction()) - return false; - return true; -} - -bool CallFrameInfo::State::ParseOperands(const char *format, - Operands *operands) { - size_t len; - const char *operand; - - for (operand = format; *operand; operand++) { - size_t bytes_left = entry_->end - cursor_; - switch (*operand) { - case 'r': - operands->register_number = reader_->ReadUnsignedLEB128(cursor_, &len); - if (len > bytes_left) return ReportIncomplete(); - cursor_ += len; - break; - - case 'o': - operands->offset = reader_->ReadUnsignedLEB128(cursor_, &len); - if (len > bytes_left) return ReportIncomplete(); - cursor_ += len; - break; - - case 's': - operands->signed_offset = reader_->ReadSignedLEB128(cursor_, &len); - if (len > bytes_left) return ReportIncomplete(); - cursor_ += len; - break; - - case 'a': - operands->offset = - reader_->ReadEncodedPointer(cursor_, entry_->cie->pointer_encoding, - &len); - if (len > bytes_left) return ReportIncomplete(); - cursor_ += len; - break; - - case '1': - if (1 > bytes_left) return ReportIncomplete(); - operands->offset = static_cast<unsigned char>(*cursor_++); - break; - - case '2': - if (2 > bytes_left) return ReportIncomplete(); - operands->offset = reader_->ReadTwoBytes(cursor_); - cursor_ += 2; - break; - - case '4': - if (4 > bytes_left) return ReportIncomplete(); - operands->offset = reader_->ReadFourBytes(cursor_); - cursor_ += 4; - break; - - case '8': - if (8 > bytes_left) return ReportIncomplete(); - operands->offset = reader_->ReadEightBytes(cursor_); - cursor_ += 8; - break; - - case 'e': { - size_t expression_length = reader_->ReadUnsignedLEB128(cursor_, &len); - if (len > bytes_left || expression_length > bytes_left - len) - return ReportIncomplete(); - cursor_ += len; - operands->expression = string(reinterpret_cast<const char *>(cursor_), - expression_length); - cursor_ += expression_length; - break; - } - - default: - assert(0); - } - } - - return true; -} - -bool CallFrameInfo::State::DoInstruction() { - CIE *cie = entry_->cie; - Operands ops; - - // Our entry's kind should have been set by now. - assert(entry_->kind != kUnknown); - - // We shouldn't have been invoked unless there were more - // instructions to parse. - assert(cursor_ < entry_->end); - - unsigned opcode = *cursor_++; - if ((opcode & 0xc0) != 0) { - switch (opcode & 0xc0) { - // Advance the address. - case DW_CFA_advance_loc: { - size_t code_offset = opcode & 0x3f; - address_ += code_offset * cie->code_alignment_factor; - break; - } - - // Find a register at an offset from the CFA. - case DW_CFA_offset: - if (!ParseOperands("o", &ops) || - !DoOffset(opcode & 0x3f, ops.offset * cie->data_alignment_factor)) - return false; - break; - - // Restore the rule established for a register by the CIE. - case DW_CFA_restore: - if (!DoRestore(opcode & 0x3f)) return false; - break; - - // The 'if' above should have excluded this possibility. - default: - assert(0); - } - - // Return here, so the big switch below won't be indented. - return true; - } - - switch (opcode) { - // Set the address. - case DW_CFA_set_loc: - if (!ParseOperands("a", &ops)) return false; - address_ = ops.offset; - break; - - // Advance the address. - case DW_CFA_advance_loc1: - if (!ParseOperands("1", &ops)) return false; - address_ += ops.offset * cie->code_alignment_factor; - break; - - // Advance the address. - case DW_CFA_advance_loc2: - if (!ParseOperands("2", &ops)) return false; - address_ += ops.offset * cie->code_alignment_factor; - break; - - // Advance the address. - case DW_CFA_advance_loc4: - if (!ParseOperands("4", &ops)) return false; - address_ += ops.offset * cie->code_alignment_factor; - break; - - // Advance the address. - case DW_CFA_MIPS_advance_loc8: - if (!ParseOperands("8", &ops)) return false; - address_ += ops.offset * cie->code_alignment_factor; - break; - - // Compute the CFA by adding an offset to a register. - case DW_CFA_def_cfa: - if (!ParseOperands("ro", &ops) || - !DoDefCFA(ops.register_number, ops.offset)) - return false; - break; - - // Compute the CFA by adding an offset to a register. - case DW_CFA_def_cfa_sf: - if (!ParseOperands("rs", &ops) || - !DoDefCFA(ops.register_number, - ops.signed_offset * cie->data_alignment_factor)) - return false; - break; - - // Change the base register used to compute the CFA. - case DW_CFA_def_cfa_register: { - if (!ParseOperands("r", &ops)) return false; - Rule *cfa_rule = rules_.CFARule(); - if (!cfa_rule) { - if (!DoDefCFA(ops.register_number, ops.offset)) { - reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); - return false; - } - } else { - cfa_rule->SetBaseRegister(ops.register_number); - if (!cfa_rule->Handle(handler_, address_, - Handler::kCFARegister)) - return false; - } - break; - } - - // Change the offset used to compute the CFA. - case DW_CFA_def_cfa_offset: - if (!ParseOperands("o", &ops) || - !DoDefCFAOffset(ops.offset)) - return false; - break; - - // Change the offset used to compute the CFA. - case DW_CFA_def_cfa_offset_sf: - if (!ParseOperands("s", &ops) || - !DoDefCFAOffset(ops.signed_offset * cie->data_alignment_factor)) - return false; - break; - - // Specify an expression whose value is the CFA. - case DW_CFA_def_cfa_expression: { - if (!ParseOperands("e", &ops)) - return false; - Rule *rule = new ValExpressionRule(ops.expression); - rules_.SetCFARule(rule); - if (!rule->Handle(handler_, address_, - Handler::kCFARegister)) - return false; - break; - } - - // The register's value cannot be recovered. - case DW_CFA_undefined: { - if (!ParseOperands("r", &ops) || - !DoRule(ops.register_number, new UndefinedRule())) - return false; - break; - } - - // The register's value is unchanged from its value in the caller. - case DW_CFA_same_value: { - if (!ParseOperands("r", &ops) || - !DoRule(ops.register_number, new SameValueRule())) - return false; - break; - } - - // Find a register at an offset from the CFA. - case DW_CFA_offset_extended: - if (!ParseOperands("ro", &ops) || - !DoOffset(ops.register_number, - ops.offset * cie->data_alignment_factor)) - return false; - break; - - // The register is saved at an offset from the CFA. - case DW_CFA_offset_extended_sf: - if (!ParseOperands("rs", &ops) || - !DoOffset(ops.register_number, - ops.signed_offset * cie->data_alignment_factor)) - return false; - break; - - // The register is saved at an offset from the CFA. - case DW_CFA_GNU_negative_offset_extended: - if (!ParseOperands("ro", &ops) || - !DoOffset(ops.register_number, - -ops.offset * cie->data_alignment_factor)) - return false; - break; - - // The register's value is the sum of the CFA plus an offset. - case DW_CFA_val_offset: - if (!ParseOperands("ro", &ops) || - !DoValOffset(ops.register_number, - ops.offset * cie->data_alignment_factor)) - return false; - break; - - // The register's value is the sum of the CFA plus an offset. - case DW_CFA_val_offset_sf: - if (!ParseOperands("rs", &ops) || - !DoValOffset(ops.register_number, - ops.signed_offset * cie->data_alignment_factor)) - return false; - break; - - // The register has been saved in another register. - case DW_CFA_register: { - if (!ParseOperands("ro", &ops) || - !DoRule(ops.register_number, new RegisterRule(ops.offset))) - return false; - break; - } - - // An expression yields the address at which the register is saved. - case DW_CFA_expression: { - if (!ParseOperands("re", &ops) || - !DoRule(ops.register_number, new ExpressionRule(ops.expression))) - return false; - break; - } - - // An expression yields the caller's value for the register. - case DW_CFA_val_expression: { - if (!ParseOperands("re", &ops) || - !DoRule(ops.register_number, new ValExpressionRule(ops.expression))) - return false; - break; - } - - // Restore the rule established for a register by the CIE. - case DW_CFA_restore_extended: - if (!ParseOperands("r", &ops) || - !DoRestore( ops.register_number)) - return false; - break; - - // Save the current set of rules on a stack. - case DW_CFA_remember_state: - saved_rules_.push(rules_); - break; - - // Pop the current set of rules off the stack. - case DW_CFA_restore_state: { - if (saved_rules_.empty()) { - reporter_->EmptyStateStack(entry_->offset, entry_->kind, - CursorOffset()); - return false; - } - const RuleMap &new_rules = saved_rules_.top(); - if (rules_.CFARule() && !new_rules.CFARule()) { - reporter_->ClearingCFARule(entry_->offset, entry_->kind, - CursorOffset()); - return false; - } - rules_.HandleTransitionTo(handler_, address_, new_rules); - rules_ = new_rules; - saved_rules_.pop(); - break; - } - - // No operation. (Padding instruction.) - case DW_CFA_nop: - break; - - // A SPARC register window save: Registers 8 through 15 (%o0-%o7) - // are saved in registers 24 through 31 (%i0-%i7), and registers - // 16 through 31 (%l0-%l7 and %i0-%i7) are saved at CFA offsets - // (0-15 * the register size). The register numbers must be - // hard-coded. A GNU extension, and not a pretty one. - case DW_CFA_GNU_window_save: { - // Save %o0-%o7 in %i0-%i7. - for (int i = 8; i < 16; i++) - if (!DoRule(i, new RegisterRule(i + 16))) - return false; - // Save %l0-%l7 and %i0-%i7 at the CFA. - for (int i = 16; i < 32; i++) - // Assume that the byte reader's address size is the same as - // the architecture's register size. !@#%*^ hilarious. - if (!DoRule(i, new OffsetRule(Handler::kCFARegister, - (i - 16) * reader_->AddressSize()))) - return false; - break; - } - - // I'm not sure what this is. GDB doesn't use it for unwinding. - case DW_CFA_GNU_args_size: - if (!ParseOperands("o", &ops)) return false; - break; - - // An opcode we don't recognize. - default: { - reporter_->BadInstruction(entry_->offset, entry_->kind, CursorOffset()); - return false; - } - } - - return true; -} - -bool CallFrameInfo::State::DoDefCFA(unsigned base_register, long offset) { - Rule *rule = new ValOffsetRule(base_register, offset); - rules_.SetCFARule(rule); - return rule->Handle(handler_, address_, - Handler::kCFARegister); -} - -bool CallFrameInfo::State::DoDefCFAOffset(long offset) { - Rule *cfa_rule = rules_.CFARule(); - if (!cfa_rule) { - reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); - return false; - } - cfa_rule->SetOffset(offset); - return cfa_rule->Handle(handler_, address_, - Handler::kCFARegister); -} - -bool CallFrameInfo::State::DoRule(unsigned reg, Rule *rule) { - rules_.SetRegisterRule(reg, rule); - return rule->Handle(handler_, address_, reg); -} - -bool CallFrameInfo::State::DoOffset(unsigned reg, long offset) { - if (!rules_.CFARule()) { - reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); - return false; - } - return DoRule(reg, - new OffsetRule(Handler::kCFARegister, offset)); -} - -bool CallFrameInfo::State::DoValOffset(unsigned reg, long offset) { - if (!rules_.CFARule()) { - reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); - return false; - } - return DoRule(reg, - new ValOffsetRule(Handler::kCFARegister, offset)); -} - -bool CallFrameInfo::State::DoRestore(unsigned reg) { - // DW_CFA_restore and DW_CFA_restore_extended don't make sense in a CIE. - if (entry_->kind == kCIE) { - reporter_->RestoreInCIE(entry_->offset, CursorOffset()); - return false; - } - Rule *rule = cie_rules_.RegisterRule(reg); - if (!rule) { - // This isn't really the right thing to do, but since CFI generally - // only mentions callee-saves registers, and GCC's convention for - // callee-saves registers is that they are unchanged, it's a good - // approximation. - rule = new SameValueRule(); - } - return DoRule(reg, rule); -} - -bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) { - const uint8_t *buffer_end = buffer_ + buffer_length_; - - // Initialize enough of ENTRY for use in error reporting. - entry->offset = cursor - buffer_; - entry->start = cursor; - entry->kind = kUnknown; - entry->end = NULL; - - // Read the initial length. This sets reader_'s offset size. - size_t length_size; - uint64 length = reader_->ReadInitialLength(cursor, &length_size); - if (length_size > size_t(buffer_end - cursor)) - return ReportIncomplete(entry); - cursor += length_size; - - // In a .eh_frame section, a length of zero marks the end of the series - // of entries. - if (length == 0 && eh_frame_) { - entry->kind = kTerminator; - entry->end = cursor; - return true; - } - - // Validate the length. - if (length > size_t(buffer_end - cursor)) - return ReportIncomplete(entry); - - // The length is the number of bytes after the initial length field; - // we have that position handy at this point, so compute the end - // now. (If we're parsing 64-bit-offset DWARF on a 32-bit machine, - // and the length didn't fit in a size_t, we would have rejected it - // above.) - entry->end = cursor + length; - - // Parse the next field: either the offset of a CIE or a CIE id. - size_t offset_size = reader_->OffsetSize(); - if (offset_size > size_t(entry->end - cursor)) return ReportIncomplete(entry); - entry->id = reader_->ReadOffset(cursor); - - // Don't advance cursor past id field yet; in .eh_frame data we need - // the id's position to compute the section offset of an FDE's CIE. - - // Now we can decide what kind of entry this is. - if (eh_frame_) { - // In .eh_frame data, an ID of zero marks the entry as a CIE, and - // anything else is an offset from the id field of the FDE to the start - // of the CIE. - if (entry->id == 0) { - entry->kind = kCIE; - } else { - entry->kind = kFDE; - // Turn the offset from the id into an offset from the buffer's start. - entry->id = (cursor - buffer_) - entry->id; - } - } else { - // In DWARF CFI data, an ID of ~0 (of the appropriate width, given the - // offset size for the entry) marks the entry as a CIE, and anything - // else is the offset of the CIE from the beginning of the section. - if (offset_size == 4) - entry->kind = (entry->id == 0xffffffff) ? kCIE : kFDE; - else { - assert(offset_size == 8); - entry->kind = (entry->id == 0xffffffffffffffffULL) ? kCIE : kFDE; - } - } - - // Now advance cursor past the id. - cursor += offset_size; - - // The fields specific to this kind of entry start here. - entry->fields = cursor; - - entry->cie = NULL; - - return true; -} - -bool CallFrameInfo::ReadCIEFields(CIE *cie) { - const uint8_t *cursor = cie->fields; - size_t len; - - assert(cie->kind == kCIE); - - // Prepare for early exit. - cie->version = 0; - cie->augmentation.clear(); - cie->code_alignment_factor = 0; - cie->data_alignment_factor = 0; - cie->return_address_register = 0; - cie->has_z_augmentation = false; - cie->pointer_encoding = DW_EH_PE_absptr; - cie->instructions = 0; - - // Parse the version number. - if (cie->end - cursor < 1) - return ReportIncomplete(cie); - cie->version = reader_->ReadOneByte(cursor); - cursor++; - - // If we don't recognize the version, we can't parse any more fields of the - // CIE. For DWARF CFI, we handle versions 1 through 3 (there was never a - // version 2 of CFI data). For .eh_frame, we handle versions 1 and 3 as well; - // the difference between those versions seems to be the same as for - // .debug_frame. - if (cie->version < 1 || cie->version > 3) { - reporter_->UnrecognizedVersion(cie->offset, cie->version); - return false; - } - - const uint8_t *augmentation_start = cursor; - const uint8_t *augmentation_end = - reinterpret_cast<const uint8_t *>(memchr(augmentation_start, '\0', - cie->end - augmentation_start)); - if (! augmentation_end) return ReportIncomplete(cie); - cursor = augmentation_end; - cie->augmentation = string(reinterpret_cast<const char *>(augmentation_start), - cursor - augmentation_start); - // Skip the terminating '\0'. - cursor++; - - // Is this CFI augmented? - if (!cie->augmentation.empty()) { - // Is it an augmentation we recognize? - if (cie->augmentation[0] == DW_Z_augmentation_start) { - // Linux C++ ABI 'z' augmentation, used for exception handling data. - cie->has_z_augmentation = true; - } else { - // Not an augmentation we recognize. Augmentations can have arbitrary - // effects on the form of rest of the content, so we have to give up. - reporter_->UnrecognizedAugmentation(cie->offset, cie->augmentation); - return false; - } - } - - // Parse the code alignment factor. - cie->code_alignment_factor = reader_->ReadUnsignedLEB128(cursor, &len); - if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie); - cursor += len; - - // Parse the data alignment factor. - cie->data_alignment_factor = reader_->ReadSignedLEB128(cursor, &len); - if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie); - cursor += len; - - // Parse the return address register. This is a ubyte in version 1, and - // a ULEB128 in version 3. - if (cie->version == 1) { - if (cursor >= cie->end) return ReportIncomplete(cie); - cie->return_address_register = uint8(*cursor++); - } else { - cie->return_address_register = reader_->ReadUnsignedLEB128(cursor, &len); - if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie); - cursor += len; - } - - // If we have a 'z' augmentation string, find the augmentation data and - // use the augmentation string to parse it. - if (cie->has_z_augmentation) { - uint64_t data_size = reader_->ReadUnsignedLEB128(cursor, &len); - if (size_t(cie->end - cursor) < len + data_size) - return ReportIncomplete(cie); - cursor += len; - const uint8_t *data = cursor; - cursor += data_size; - const uint8_t *data_end = cursor; - - cie->has_z_lsda = false; - cie->has_z_personality = false; - cie->has_z_signal_frame = false; - - // Walk the augmentation string, and extract values from the - // augmentation data as the string directs. - for (size_t i = 1; i < cie->augmentation.size(); i++) { - switch (cie->augmentation[i]) { - case DW_Z_has_LSDA: - // The CIE's augmentation data holds the language-specific data - // area pointer's encoding, and the FDE's augmentation data holds - // the pointer itself. - cie->has_z_lsda = true; - // Fetch the LSDA encoding from the augmentation data. - if (data >= data_end) return ReportIncomplete(cie); - cie->lsda_encoding = DwarfPointerEncoding(*data++); - if (!reader_->ValidEncoding(cie->lsda_encoding)) { - reporter_->InvalidPointerEncoding(cie->offset, cie->lsda_encoding); - return false; - } - // Don't check if the encoding is usable here --- we haven't - // read the FDE's fields yet, so we're not prepared for - // DW_EH_PE_funcrel, although that's a fine encoding for the - // LSDA to use, since it appears in the FDE. - break; - - case DW_Z_has_personality_routine: - // The CIE's augmentation data holds the personality routine - // pointer's encoding, followed by the pointer itself. - cie->has_z_personality = true; - // Fetch the personality routine pointer's encoding from the - // augmentation data. - if (data >= data_end) return ReportIncomplete(cie); - cie->personality_encoding = DwarfPointerEncoding(*data++); - if (!reader_->ValidEncoding(cie->personality_encoding)) { - reporter_->InvalidPointerEncoding(cie->offset, - cie->personality_encoding); - return false; - } - if (!reader_->UsableEncoding(cie->personality_encoding)) { - reporter_->UnusablePointerEncoding(cie->offset, - cie->personality_encoding); - return false; - } - // Fetch the personality routine's pointer itself from the data. - cie->personality_address = - reader_->ReadEncodedPointer(data, cie->personality_encoding, - &len); - if (len > size_t(data_end - data)) - return ReportIncomplete(cie); - data += len; - break; - - case DW_Z_has_FDE_address_encoding: - // The CIE's augmentation data holds the pointer encoding to use - // for addresses in the FDE. - if (data >= data_end) return ReportIncomplete(cie); - cie->pointer_encoding = DwarfPointerEncoding(*data++); - if (!reader_->ValidEncoding(cie->pointer_encoding)) { - reporter_->InvalidPointerEncoding(cie->offset, - cie->pointer_encoding); - return false; - } - if (!reader_->UsableEncoding(cie->pointer_encoding)) { - reporter_->UnusablePointerEncoding(cie->offset, - cie->pointer_encoding); - return false; - } - break; - - case DW_Z_is_signal_trampoline: - // Frames using this CIE are signal delivery frames. - cie->has_z_signal_frame = true; - break; - - default: - // An augmentation we don't recognize. - reporter_->UnrecognizedAugmentation(cie->offset, cie->augmentation); - return false; - } - } - } - - // The CIE's instructions start here. - cie->instructions = cursor; - - return true; -} - -bool CallFrameInfo::ReadFDEFields(FDE *fde) { - const uint8_t *cursor = fde->fields; - size_t size; - - fde->address = reader_->ReadEncodedPointer(cursor, fde->cie->pointer_encoding, - &size); - if (size > size_t(fde->end - cursor)) - return ReportIncomplete(fde); - cursor += size; - reader_->SetFunctionBase(fde->address); - - // For the length, we strip off the upper nybble of the encoding used for - // the starting address. - DwarfPointerEncoding length_encoding = - DwarfPointerEncoding(fde->cie->pointer_encoding & 0x0f); - fde->size = reader_->ReadEncodedPointer(cursor, length_encoding, &size); - if (size > size_t(fde->end - cursor)) - return ReportIncomplete(fde); - cursor += size; - - // If the CIE has a 'z' augmentation string, then augmentation data - // appears here. - if (fde->cie->has_z_augmentation) { - uint64_t data_size = reader_->ReadUnsignedLEB128(cursor, &size); - if (size_t(fde->end - cursor) < size + data_size) - return ReportIncomplete(fde); - cursor += size; - - // In the abstract, we should walk the augmentation string, and extract - // items from the FDE's augmentation data as we encounter augmentation - // string characters that specify their presence: the ordering of items - // in the augmentation string determines the arrangement of values in - // the augmentation data. - // - // In practice, there's only ever one value in FDE augmentation data - // that we support --- the LSDA pointer --- and we have to bail if we - // see any unrecognized augmentation string characters. So if there is - // anything here at all, we know what it is, and where it starts. - if (fde->cie->has_z_lsda) { - // Check whether the LSDA's pointer encoding is usable now: only once - // we've parsed the FDE's starting address do we call reader_-> - // SetFunctionBase, so that the DW_EH_PE_funcrel encoding becomes - // usable. - if (!reader_->UsableEncoding(fde->cie->lsda_encoding)) { - reporter_->UnusablePointerEncoding(fde->cie->offset, - fde->cie->lsda_encoding); - return false; - } - - fde->lsda_address = - reader_->ReadEncodedPointer(cursor, fde->cie->lsda_encoding, &size); - if (size > data_size) - return ReportIncomplete(fde); - // Ideally, we would also complain here if there were unconsumed - // augmentation data. - } - - cursor += data_size; - } - - // The FDE's instructions start after those. - fde->instructions = cursor; - - return true; -} - -bool CallFrameInfo::Start() { - const uint8_t *buffer_end = buffer_ + buffer_length_; - const uint8_t *cursor; - bool all_ok = true; - const uint8_t *entry_end; - bool ok; - - // Traverse all the entries in buffer_, skipping CIEs and offering - // FDEs to the handler. - for (cursor = buffer_; cursor < buffer_end; - cursor = entry_end, all_ok = all_ok && ok) { - FDE fde; - - // Make it easy to skip this entry with 'continue': assume that - // things are not okay until we've checked all the data, and - // prepare the address of the next entry. - ok = false; - - // Read the entry's prologue. - if (!ReadEntryPrologue(cursor, &fde)) { - if (!fde.end) { - // If we couldn't even figure out this entry's extent, then we - // must stop processing entries altogether. - all_ok = false; - break; - } - entry_end = fde.end; - continue; - } - - // The next iteration picks up after this entry. - entry_end = fde.end; - - // Did we see an .eh_frame terminating mark? - if (fde.kind == kTerminator) { - // If there appears to be more data left in the section after the - // terminating mark, warn the user. But this is just a warning; - // we leave all_ok true. - if (fde.end < buffer_end) reporter_->EarlyEHTerminator(fde.offset); - break; - } - - // In this loop, we skip CIEs. We only parse them fully when we - // parse an FDE that refers to them. This limits our memory - // consumption (beyond the buffer itself) to that needed to - // process the largest single entry. - if (fde.kind != kFDE) { - ok = true; - continue; - } - - // Validate the CIE pointer. - if (fde.id > buffer_length_) { - reporter_->CIEPointerOutOfRange(fde.offset, fde.id); - continue; - } - - CIE cie; - - // Parse this FDE's CIE header. - if (!ReadEntryPrologue(buffer_ + fde.id, &cie)) - continue; - // This had better be an actual CIE. - if (cie.kind != kCIE) { - reporter_->BadCIEId(fde.offset, fde.id); - continue; - } - if (!ReadCIEFields(&cie)) - continue; - - // We now have the values that govern both the CIE and the FDE. - cie.cie = &cie; - fde.cie = &cie; - - // Parse the FDE's header. - if (!ReadFDEFields(&fde)) - continue; - - // Call Entry to ask the consumer if they're interested. - if (!handler_->Entry(fde.offset, fde.address, fde.size, - cie.version, cie.augmentation, - cie.return_address_register)) { - // The handler isn't interested in this entry. That's not an error. - ok = true; - continue; - } - - if (cie.has_z_augmentation) { - // Report the personality routine address, if we have one. - if (cie.has_z_personality) { - if (!handler_ - ->PersonalityRoutine(cie.personality_address, - IsIndirectEncoding(cie.personality_encoding))) - continue; - } - - // Report the language-specific data area address, if we have one. - if (cie.has_z_lsda) { - if (!handler_ - ->LanguageSpecificDataArea(fde.lsda_address, - IsIndirectEncoding(cie.lsda_encoding))) - continue; - } - - // If this is a signal-handling frame, report that. - if (cie.has_z_signal_frame) { - if (!handler_->SignalHandler()) - continue; - } - } - - // Interpret the CIE's instructions, and then the FDE's instructions. - State state(reader_, handler_, reporter_, fde.address); - ok = state.InterpretCIE(cie) && state.InterpretFDE(fde); - - // Tell the ByteReader that the function start address from the - // FDE header is no longer valid. - reader_->ClearFunctionBase(); - - // Report the end of the entry. - handler_->End(); - } - - return all_ok; -} - -const char *CallFrameInfo::KindName(EntryKind kind) { - if (kind == CallFrameInfo::kUnknown) - return "entry"; - else if (kind == CallFrameInfo::kCIE) - return "common information entry"; - else if (kind == CallFrameInfo::kFDE) - return "frame description entry"; - else { - assert (kind == CallFrameInfo::kTerminator); - return ".eh_frame sequence terminator"; - } -} - -bool CallFrameInfo::ReportIncomplete(Entry *entry) { - reporter_->Incomplete(entry->offset, entry->kind); - return false; -} - -void CallFrameInfo::Reporter::Incomplete(uint64 offset, - CallFrameInfo::EntryKind kind) { - fprintf(stderr, - "%s: CFI %s at offset 0x%llx in '%s': entry ends early\n", - filename_.c_str(), CallFrameInfo::KindName(kind), offset, - section_.c_str()); -} - -void CallFrameInfo::Reporter::EarlyEHTerminator(uint64 offset) { - fprintf(stderr, - "%s: CFI at offset 0x%llx in '%s': saw end-of-data marker" - " before end of section contents\n", - filename_.c_str(), offset, section_.c_str()); -} - -void CallFrameInfo::Reporter::CIEPointerOutOfRange(uint64 offset, - uint64 cie_offset) { - fprintf(stderr, - "%s: CFI frame description entry at offset 0x%llx in '%s':" - " CIE pointer is out of range: 0x%llx\n", - filename_.c_str(), offset, section_.c_str(), cie_offset); -} - -void CallFrameInfo::Reporter::BadCIEId(uint64 offset, uint64 cie_offset) { - fprintf(stderr, - "%s: CFI frame description entry at offset 0x%llx in '%s':" - " CIE pointer does not point to a CIE: 0x%llx\n", - filename_.c_str(), offset, section_.c_str(), cie_offset); -} - -void CallFrameInfo::Reporter::UnrecognizedVersion(uint64 offset, int version) { - fprintf(stderr, - "%s: CFI frame description entry at offset 0x%llx in '%s':" - " CIE specifies unrecognized version: %d\n", - filename_.c_str(), offset, section_.c_str(), version); -} - -void CallFrameInfo::Reporter::UnrecognizedAugmentation(uint64 offset, - const string &aug) { - fprintf(stderr, - "%s: CFI frame description entry at offset 0x%llx in '%s':" - " CIE specifies unrecognized augmentation: '%s'\n", - filename_.c_str(), offset, section_.c_str(), aug.c_str()); -} - -void CallFrameInfo::Reporter::InvalidPointerEncoding(uint64 offset, - uint8 encoding) { - fprintf(stderr, - "%s: CFI common information entry at offset 0x%llx in '%s':" - " 'z' augmentation specifies invalid pointer encoding: 0x%02x\n", - filename_.c_str(), offset, section_.c_str(), encoding); -} - -void CallFrameInfo::Reporter::UnusablePointerEncoding(uint64 offset, - uint8 encoding) { - fprintf(stderr, - "%s: CFI common information entry at offset 0x%llx in '%s':" - " 'z' augmentation specifies a pointer encoding for which" - " we have no base address: 0x%02x\n", - filename_.c_str(), offset, section_.c_str(), encoding); -} - -void CallFrameInfo::Reporter::RestoreInCIE(uint64 offset, uint64 insn_offset) { - fprintf(stderr, - "%s: CFI common information entry at offset 0x%llx in '%s':" - " the DW_CFA_restore instruction at offset 0x%llx" - " cannot be used in a common information entry\n", - filename_.c_str(), offset, section_.c_str(), insn_offset); -} - -void CallFrameInfo::Reporter::BadInstruction(uint64 offset, - CallFrameInfo::EntryKind kind, - uint64 insn_offset) { - fprintf(stderr, - "%s: CFI %s at offset 0x%llx in section '%s':" - " the instruction at offset 0x%llx is unrecognized\n", - filename_.c_str(), CallFrameInfo::KindName(kind), - offset, section_.c_str(), insn_offset); -} - -void CallFrameInfo::Reporter::NoCFARule(uint64 offset, - CallFrameInfo::EntryKind kind, - uint64 insn_offset) { - fprintf(stderr, - "%s: CFI %s at offset 0x%llx in section '%s':" - " the instruction at offset 0x%llx assumes that a CFA rule has" - " been set, but none has been set\n", - filename_.c_str(), CallFrameInfo::KindName(kind), offset, - section_.c_str(), insn_offset); -} - -void CallFrameInfo::Reporter::EmptyStateStack(uint64 offset, - CallFrameInfo::EntryKind kind, - uint64 insn_offset) { - fprintf(stderr, - "%s: CFI %s at offset 0x%llx in section '%s':" - " the DW_CFA_restore_state instruction at offset 0x%llx" - " should pop a saved state from the stack, but the stack is empty\n", - filename_.c_str(), CallFrameInfo::KindName(kind), offset, - section_.c_str(), insn_offset); -} - -void CallFrameInfo::Reporter::ClearingCFARule(uint64 offset, - CallFrameInfo::EntryKind kind, - uint64 insn_offset) { - fprintf(stderr, - "%s: CFI %s at offset 0x%llx in section '%s':" - " the DW_CFA_restore_state instruction at offset 0x%llx" - " would clear the CFA rule in effect\n", - filename_.c_str(), CallFrameInfo::KindName(kind), offset, - section_.c_str(), insn_offset); -} - -} // namespace dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.h deleted file mode 100644 index 064c42bc8..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.h +++ /dev/null @@ -1,1288 +0,0 @@ -// -*- mode: C++ -*- - -// Copyright (c) 2010 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// CFI reader author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// This file contains definitions related to the DWARF2/3 reader and -// it's handler interfaces. -// The DWARF2/3 specification can be found at -// http://dwarf.freestandards.org and should be considered required -// reading if you wish to modify the implementation. -// Only a cursory attempt is made to explain terminology that is -// used here, as it is much better explained in the standard documents -#ifndef COMMON_DWARF_DWARF2READER_H__ -#define COMMON_DWARF_DWARF2READER_H__ - -#include <stdint.h> - -#include <list> -#include <map> -#include <string> -#include <utility> -#include <vector> -#include <memory> - -#include "common/dwarf/bytereader.h" -#include "common/dwarf/dwarf2enums.h" -#include "common/dwarf/types.h" -#include "common/using_std_string.h" -#include "common/dwarf/elf_reader.h" - -namespace dwarf2reader { -struct LineStateMachine; -class Dwarf2Handler; -class LineInfoHandler; -class DwpReader; - -// This maps from a string naming a section to a pair containing a -// the data for the section, and the size of the section. -typedef std::map<string, std::pair<const uint8_t *, uint64> > SectionMap; -typedef std::list<std::pair<enum DwarfAttribute, enum DwarfForm> > - AttributeList; -typedef AttributeList::iterator AttributeIterator; -typedef AttributeList::const_iterator ConstAttributeIterator; - -struct LineInfoHeader { - uint64 total_length; - uint16 version; - uint64 prologue_length; - uint8 min_insn_length; // insn stands for instructin - bool default_is_stmt; // stmt stands for statement - int8 line_base; - uint8 line_range; - uint8 opcode_base; - // Use a pointer so that signalsafe_addr2line is able to use this structure - // without heap allocation problem. - std::vector<unsigned char> *std_opcode_lengths; -}; - -class LineInfo { - public: - - // Initializes a .debug_line reader. Buffer and buffer length point - // to the beginning and length of the line information to read. - // Reader is a ByteReader class that has the endianness set - // properly. - LineInfo(const uint8_t *buffer_, uint64 buffer_length, - ByteReader* reader, LineInfoHandler* handler); - - virtual ~LineInfo() { - if (header_.std_opcode_lengths) { - delete header_.std_opcode_lengths; - } - } - - // Start processing line info, and calling callbacks in the handler. - // Consumes the line number information for a single compilation unit. - // Returns the number of bytes processed. - uint64 Start(); - - // Process a single line info opcode at START using the state - // machine at LSM. Return true if we should define a line using the - // current state of the line state machine. Place the length of the - // opcode in LEN. - // If LSM_PASSES_PC is non-NULL, this function also checks if the lsm - // passes the address of PC. In other words, LSM_PASSES_PC will be - // set to true, if the following condition is met. - // - // lsm's old address < PC <= lsm's new address - static bool ProcessOneOpcode(ByteReader* reader, - LineInfoHandler* handler, - const struct LineInfoHeader &header, - const uint8_t *start, - struct LineStateMachine* lsm, - size_t* len, - uintptr pc, - bool *lsm_passes_pc); - - private: - // Reads the DWARF2/3 header for this line info. - void ReadHeader(); - - // Reads the DWARF2/3 line information - void ReadLines(); - - // The associated handler to call processing functions in - LineInfoHandler* handler_; - - // The associated ByteReader that handles endianness issues for us - ByteReader* reader_; - - // A DWARF2/3 line info header. This is not the same size as - // in the actual file, as the one in the file may have a 32 bit or - // 64 bit lengths - - struct LineInfoHeader header_; - - // buffer is the buffer for our line info, starting at exactly where - // the line info to read is. after_header is the place right after - // the end of the line information header. - const uint8_t *buffer_; -#ifndef NDEBUG - uint64 buffer_length_; -#endif - const uint8_t *after_header_; -}; - -// This class is the main interface between the line info reader and -// the client. The virtual functions inside this get called for -// interesting events that happen during line info reading. The -// default implementation does nothing - -class LineInfoHandler { - public: - LineInfoHandler() { } - - virtual ~LineInfoHandler() { } - - // Called when we define a directory. NAME is the directory name, - // DIR_NUM is the directory number - virtual void DefineDir(const string& name, uint32 dir_num) { } - - // Called when we define a filename. NAME is the filename, FILE_NUM - // is the file number which is -1 if the file index is the next - // index after the last numbered index (this happens when files are - // dynamically defined by the line program), DIR_NUM is the - // directory index for the directory name of this file, MOD_TIME is - // the modification time of the file, and LENGTH is the length of - // the file - virtual void DefineFile(const string& name, int32 file_num, - uint32 dir_num, uint64 mod_time, - uint64 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 address, uint64 length, - uint32 file_num, uint32 line_num, uint32 column_num) { } -}; - -// This class is the main interface between the reader and the -// client. The virtual functions inside this get called for -// interesting events that happen during DWARF2 reading. -// The default implementation skips everything. -class Dwarf2Handler { - public: - Dwarf2Handler() { } - - virtual ~Dwarf2Handler() { } - - // Start to process a compilation unit at OFFSET from the beginning of the - // .debug_info section. Return false if you would like to skip this - // compilation unit. - virtual bool StartCompilationUnit(uint64 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 dwarf_version) { return false; } - - // When processing a skeleton compilation unit, resulting from a split - // DWARF compilation, once the skeleton debug info has been read, - // the reader will call this function to ask the client if it needs - // the full debug info from the .dwo or .dwp file. Return true if - // you need it, or false to skip processing the split debug info. - virtual bool NeedSplitDebugInfo() { return true; } - - // Start to process a split compilation unit at OFFSET from the beginning of - // the debug_info section in the .dwp/.dwo file. Return false if you would - // like to skip this compilation unit. - virtual bool StartSplitCompilationUnit(uint64 offset, - uint64 cu_length) { return false; } - - // Start to process a DIE at OFFSET from the beginning of the .debug_info - // section. Return false if you would like to skip this DIE. - virtual bool StartDIE(uint64 offset, enum DwarfTag tag) { return false; } - - // 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. Its name is ATTR, its form is FORM, and its value is - // DATA. - virtual void ProcessAttributeUnsigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { } - - // Called when we have an attribute with signed data to give to our handler. - // The attribute is for the DIE at OFFSET from the beginning of the - // .debug_info section. Its name is ATTR, its form is FORM, and its value is - // DATA. - virtual void ProcessAttributeSigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - int64 data) { } - - // Called when we have an attribute whose value is a reference to - // another DIE. The attribute belongs to the DIE at OFFSET from the - // beginning of the .debug_info section. Its name is ATTR, its form - // is FORM, and the offset of the DIE being referred to from the - // beginning of the .debug_info section is DATA. - virtual void ProcessAttributeReference(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { } - - // Called when we have an attribute with a buffer of data to give to our - // handler. The attribute is for the DIE at OFFSET from the beginning of the - // .debug_info section. Its name is ATTR, its form is FORM, DATA points to - // the buffer's contents, and its length in bytes is LENGTH. The buffer is - // owned by the caller, not the callee, and may not persist for very long. - // If you want the data to be available later, it needs to be copied. - virtual void ProcessAttributeBuffer(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const uint8_t *data, - uint64 len) { } - - // 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. Its name is ATTR, its form is FORM, and its value is - // DATA. - virtual void ProcessAttributeString(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const string& data) { } - - // Called when we have an attribute whose value is the 64-bit signature - // of a type unit in the .debug_types section. OFFSET is the offset of - // the DIE whose attribute we're reporting. ATTR and FORM are the - // attribute's name and form. SIGNATURE is the type unit's signature. - virtual void ProcessAttributeSignature(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 signature) { } - - // 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 offset) { } - -}; - -// The base of DWARF2/3 debug info is a DIE (Debugging Information -// Entry. -// DWARF groups DIE's into a tree and calls the root of this tree a -// "compilation unit". Most of the time, there is one compilation -// unit in the .debug_info section for each file that had debug info -// generated. -// Each DIE consists of - -// 1. a tag specifying a thing that is being described (ie -// DW_TAG_subprogram for functions, DW_TAG_variable for variables, etc -// 2. attributes (such as DW_AT_location for location in memory, -// DW_AT_name for name), and data for each attribute. -// 3. A flag saying whether the DIE has children or not - -// In order to gain some amount of compression, the format of -// each DIE (tag name, attributes and data forms for the attributes) -// are stored in a separate table called the "abbreviation table". -// This is done because a large number of DIEs have the exact same tag -// and list of attributes, but different data for those attributes. -// As a result, the .debug_info section is just a stream of data, and -// requires reading of the .debug_abbrev section to say what the data -// means. - -// As a warning to the user, it should be noted that the reason for -// using absolute offsets from the beginning of .debug_info is that -// DWARF2/3 supports referencing DIE's from other DIE's by their offset -// from either the current compilation unit start, *or* the beginning -// of the .debug_info section. This means it is possible to reference -// a DIE in one compilation unit from a DIE in another compilation -// unit. This style of reference is usually used to eliminate -// duplicated information that occurs across compilation -// units, such as base types, etc. GCC 3.4+ support this with -// -feliminate-dwarf2-dups. Other toolchains will sometimes do -// duplicate elimination in the linker. - -class CompilationUnit { - public: - - // Initialize a compilation unit. This requires a map of sections, - // the offset of this compilation unit in the .debug_info section, a - // ByteReader, and a Dwarf2Handler class to call callbacks in. - CompilationUnit(const string& path, const SectionMap& sections, uint64 offset, - ByteReader* reader, Dwarf2Handler* handler); - virtual ~CompilationUnit() { - if (abbrevs_) delete abbrevs_; - } - - // Initialize a compilation unit from a .dwo or .dwp file. - // In this case, we need the .debug_addr section from the - // executable file that contains the corresponding skeleton - // compilation unit. We also inherit the Dwarf2Handler from - // the executable file, and call it as if we were still - // processing the original compilation unit. - void SetSplitDwarf(const uint8_t* addr_buffer, uint64 addr_buffer_length, - uint64 addr_base, uint64 ranges_base, uint64 dwo_id); - - // Begin reading a Dwarf2 compilation unit, and calling the - // callbacks in the Dwarf2Handler - - // Return the full length of the compilation unit, including - // headers. This plus the starting offset passed to the constructor - // is the offset of the end of the compilation unit --- and the - // start of the next compilation unit, if there is one. - uint64 Start(); - - private: - - // This struct represents a single DWARF2/3 abbreviation - // The abbreviation tells how to read a DWARF2/3 DIE, and consist of a - // tag and a list of attributes, as well as the data form of each attribute. - struct Abbrev { - uint64 number; - enum DwarfTag tag; - bool has_children; - AttributeList attributes; - }; - - // A DWARF2/3 compilation unit header. This is not the same size as - // in the actual file, as the one in the file may have a 32 bit or - // 64 bit length. - struct CompilationUnitHeader { - uint64 length; - uint16 version; - uint64 abbrev_offset; - uint8 address_size; - } header_; - - // Reads the DWARF2/3 header for this compilation unit. - void ReadHeader(); - - // Reads the DWARF2/3 abbreviations for this compilation unit - void ReadAbbrevs(); - - // Processes a single DIE for this compilation unit and return a new - // pointer just past the end of it - const uint8_t *ProcessDIE(uint64 dieoffset, - const uint8_t *start, - const Abbrev& abbrev); - - // Processes a single attribute and return a new pointer just past the - // end of it - const uint8_t *ProcessAttribute(uint64 dieoffset, - const uint8_t *start, - enum DwarfAttribute attr, - enum DwarfForm form); - - // 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 compilation unit, has a name of ATTR, a form of - // FORM, and the actual data of the attribute is in DATA. - // If we see a DW_AT_GNU_dwo_id attribute, save the value so that - // we can find the debug info in a .dwo or .dwp file. - void ProcessAttributeUnsigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - if (attr == DW_AT_GNU_dwo_id) { - dwo_id_ = data; - } - else if (attr == DW_AT_GNU_addr_base) { - addr_base_ = data; - } - else if (attr == DW_AT_GNU_ranges_base) { - ranges_base_ = data; - } - // TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5, - // that base will apply to DW_AT_ranges attributes in the - // skeleton CU as well as in the .dwo/.dwp files. - else if (attr == DW_AT_ranges && is_split_dwarf_) { - data += ranges_base_; - } - handler_->ProcessAttributeUnsigned(offset, attr, form, data); - } - - // Called when we have an attribute with signed data to give to - // our handler. The attribute is for the DIE at OFFSET from the - // beginning of compilation unit, has a name of ATTR, a form of - // FORM, and the actual data of the attribute is in DATA. - void ProcessAttributeSigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - int64 data) { - handler_->ProcessAttributeSigned(offset, attr, form, data); - } - - // Called when we have an attribute with a buffer of data to give to - // our handler. The attribute is for the DIE at OFFSET from the - // beginning of compilation unit, has a name of ATTR, a form of - // FORM, and the actual data of the attribute is in DATA, and the - // length of the buffer is LENGTH. - void ProcessAttributeBuffer(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const uint8_t* data, - uint64 len) { - handler_->ProcessAttributeBuffer(offset, attr, form, data, len); - } - - // 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 compilation unit, has a name of ATTR, a form of - // FORM, and the actual data of the attribute is in DATA. - // If we see a DW_AT_GNU_dwo_name attribute, save the value so - // that we can find the debug info in a .dwo or .dwp file. - void ProcessAttributeString(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const char* data) { - if (attr == DW_AT_GNU_dwo_name) - dwo_name_ = data; - handler_->ProcessAttributeString(offset, attr, form, data); - } - - // Processes all DIEs for this compilation unit - void ProcessDIEs(); - - // Skips the die with attributes specified in ABBREV starting at - // START, and return the new place to position the stream to. - const uint8_t *SkipDIE(const uint8_t *start, const Abbrev& abbrev); - - // Skips the attribute starting at START, with FORM, and return the - // new place to position the stream to. - const uint8_t *SkipAttribute(const uint8_t *start, enum DwarfForm form); - - // Process the actual debug information in a split DWARF file. - void ProcessSplitDwarf(); - - // Read the debug sections from a .dwo file. - void ReadDebugSectionsFromDwo(ElfReader* elf_reader, - SectionMap* sections); - - // Path of the file containing the debug information. - const string path_; - - // Offset from section start is the offset of this compilation unit - // from the beginning of the .debug_info section. - uint64 offset_from_section_start_; - - // buffer is the buffer for our CU, starting at .debug_info + offset - // passed in from constructor. - // after_header points to right after the compilation unit header. - const uint8_t *buffer_; - uint64 buffer_length_; - const uint8_t *after_header_; - - // The associated ByteReader that handles endianness issues for us - ByteReader* reader_; - - // The map of sections in our file to buffers containing their data - const SectionMap& sections_; - - // The associated handler to call processing functions in - Dwarf2Handler* handler_; - - // Set of DWARF2/3 abbreviations for this compilation unit. Indexed - // by abbreviation number, which means that abbrevs_[0] is not - // valid. - std::vector<Abbrev>* abbrevs_; - - // String section buffer and length, if we have a string section. - // This is here to avoid doing a section lookup for strings in - // ProcessAttribute, which is in the hot path for DWARF2 reading. - const uint8_t *string_buffer_; - uint64 string_buffer_length_; - - // String offsets section buffer and length, if we have a string offsets - // section (.debug_str_offsets or .debug_str_offsets.dwo). - const uint8_t* str_offsets_buffer_; - uint64 str_offsets_buffer_length_; - - // Address section buffer and length, if we have an address section - // (.debug_addr). - const uint8_t* addr_buffer_; - uint64 addr_buffer_length_; - - // Flag indicating whether this compilation unit is part of a .dwo - // or .dwp file. If true, we are reading this unit because a - // skeleton compilation unit in an executable file had a - // DW_AT_GNU_dwo_name or DW_AT_GNU_dwo_id attribute. - // In a .dwo file, we expect the string offsets section to - // have a ".dwo" suffix, and we will use the ".debug_addr" section - // associated with the skeleton compilation unit. - bool is_split_dwarf_; - - // The value of the DW_AT_GNU_dwo_id attribute, if any. - uint64 dwo_id_; - - // The value of the DW_AT_GNU_dwo_name attribute, if any. - const char* dwo_name_; - - // If this is a split DWARF CU, the value of the DW_AT_GNU_dwo_id attribute - // from the skeleton CU. - uint64 skeleton_dwo_id_; - - // The value of the DW_AT_GNU_ranges_base attribute, if any. - uint64 ranges_base_; - - // The value of the DW_AT_GNU_addr_base attribute, if any. - uint64 addr_base_; - - // True if we have already looked for a .dwp file. - bool have_checked_for_dwp_; - - // Path to the .dwp file. - string dwp_path_; - - // ByteReader for the DWP file. - std::unique_ptr<ByteReader> dwp_byte_reader_; - - // DWP reader. - std::unique_ptr<DwpReader> dwp_reader_; -}; - -// A Reader for a .dwp file. Supports the fetching of DWARF debug -// info for a given dwo_id. -// -// There are two versions of .dwp files. In both versions, the -// .dwp file is an ELF file containing only debug sections. -// In Version 1, the file contains many copies of each debug -// section, one for each .dwo file that is packaged in the .dwp -// file, and the .debug_cu_index section maps from the dwo_id -// to a set of section indexes. In Version 2, the file contains -// one of each debug section, and the .debug_cu_index section -// maps from the dwo_id to a set of offsets and lengths that -// identify each .dwo file's contribution to the larger sections. - -class DwpReader { - public: - DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader); - - ~DwpReader(); - - // Read the CU index and initialize data members. - void Initialize(); - - // Read the debug sections for the given dwo_id. - void ReadDebugSectionsForCU(uint64 dwo_id, SectionMap* sections); - - private: - // Search a v1 hash table for "dwo_id". Returns the slot index - // where the dwo_id was found, or -1 if it was not found. - int LookupCU(uint64 dwo_id); - - // Search a v2 hash table for "dwo_id". Returns the row index - // in the offsets and sizes tables, or 0 if it was not found. - uint32 LookupCUv2(uint64 dwo_id); - - // The ELF reader for the .dwp file. - ElfReader* elf_reader_; - - // The ByteReader for the .dwp file. - const ByteReader& byte_reader_; - - // Pointer to the .debug_cu_index section. - const char* cu_index_; - - // Size of the .debug_cu_index section. - size_t cu_index_size_; - - // Pointer to the .debug_str.dwo section. - const char* string_buffer_; - - // Size of the .debug_str.dwo section. - size_t string_buffer_size_; - - // Version of the .dwp file. We support versions 1 and 2 currently. - int version_; - - // Number of columns in the section tables (version 2). - unsigned int ncolumns_; - - // Number of units in the section tables (version 2). - unsigned int nunits_; - - // Number of slots in the hash table. - unsigned int nslots_; - - // Pointer to the beginning of the hash table. - const char* phash_; - - // Pointer to the beginning of the index table. - const char* pindex_; - - // Pointer to the beginning of the section index pool (version 1). - const char* shndx_pool_; - - // Pointer to the beginning of the section offset table (version 2). - const char* offset_table_; - - // Pointer to the beginning of the section size table (version 2). - const char* size_table_; - - // Contents of the sections of interest (version 2). - const char* abbrev_data_; - size_t abbrev_size_; - const char* info_data_; - size_t info_size_; - const char* str_offsets_data_; - size_t str_offsets_size_; -}; - -// This class is a reader for DWARF's Call Frame Information. CFI -// describes how to unwind stack frames --- even for functions that do -// not follow fixed conventions for saving registers, whose frame size -// varies as they execute, etc. -// -// CFI describes, at each machine instruction, how to compute the -// stack frame's base address, how to find the return address, and -// where to find the saved values of the caller's registers (if the -// callee has stashed them somewhere to free up the registers for its -// own use). -// -// For example, suppose we have a function whose machine code looks -// like this (imagine an assembly language that looks like C, for a -// machine with 32-bit registers, and a stack that grows towards lower -// addresses): -// -// func: ; entry point; return address at sp -// func+0: sp = sp - 16 ; allocate space for stack frame -// func+1: sp[12] = r0 ; save r0 at sp+12 -// ... ; other code, not frame-related -// func+10: sp -= 4; *sp = x ; push some x on the stack -// ... ; other code, not frame-related -// func+20: r0 = sp[16] ; restore saved r0 -// func+21: sp += 20 ; pop whole stack frame -// func+22: pc = *sp; sp += 4 ; pop return address and jump to it -// -// DWARF CFI is (a very compressed representation of) a table with a -// row for each machine instruction address and a column for each -// register showing how to restore it, if possible. -// -// A special column named "CFA", for "Canonical Frame Address", tells how -// to compute the base address of the frame; registers' entries may -// refer to the CFA in describing where the registers are saved. -// -// Another special column, named "RA", represents the return address. -// -// For example, here is a complete (uncompressed) table describing the -// function above: -// -// insn cfa r0 r1 ... ra -// ======================================= -// func+0: sp cfa[0] -// func+1: sp+16 cfa[0] -// func+2: sp+16 cfa[-4] cfa[0] -// func+11: sp+20 cfa[-4] cfa[0] -// func+21: sp+20 cfa[0] -// func+22: sp cfa[0] -// -// Some things to note here: -// -// - Each row describes the state of affairs *before* executing the -// instruction at the given address. Thus, the row for func+0 -// describes the state before we allocate the stack frame. In the -// next row, the formula for computing the CFA has changed, -// reflecting that allocation. -// -// - The other entries are written in terms of the CFA; this allows -// them to remain unchanged as the stack pointer gets bumped around. -// For example, the rule for recovering the return address (the "ra" -// column) remains unchanged throughout the function, even as the -// stack pointer takes on three different offsets from the return -// address. -// -// - Although we haven't shown it, most calling conventions designate -// "callee-saves" and "caller-saves" registers. The callee must -// preserve the values of callee-saves registers; if it uses them, -// it must save their original values somewhere, and restore them -// before it returns. In contrast, the callee is free to trash -// caller-saves registers; if the callee uses these, it will -// probably not bother to save them anywhere, and the CFI will -// probably mark their values as "unrecoverable". -// -// (However, since the caller cannot assume the callee was going to -// save them, caller-saves registers are probably dead in the caller -// anyway, so compilers usually don't generate CFA for caller-saves -// registers.) -// -// - Exactly where the CFA points is a matter of convention that -// depends on the architecture and ABI in use. In the example, the -// CFA is the value the stack pointer had upon entry to the -// function, pointing at the saved return address. But on the x86, -// the call frame information generated by GCC follows the -// convention that the CFA is the address *after* the saved return -// address. -// -// But by definition, the CFA remains constant throughout the -// lifetime of the frame. This makes it a useful value for other -// columns to refer to. It is also gives debuggers a useful handle -// for identifying a frame. -// -// If you look at the table above, you'll notice that a given entry is -// often the same as the one immediately above it: most instructions -// change only one or two aspects of the stack frame, if they affect -// it at all. The DWARF format takes advantage of this fact, and -// reduces the size of the data by mentioning only the addresses and -// columns at which changes take place. So for the above, DWARF CFI -// data would only actually mention the following: -// -// insn cfa r0 r1 ... ra -// ======================================= -// func+0: sp cfa[0] -// func+1: sp+16 -// func+2: cfa[-4] -// func+11: sp+20 -// func+21: r0 -// func+22: sp -// -// In fact, this is the way the parser reports CFI to the consumer: as -// a series of statements of the form, "At address X, column Y changed -// to Z," and related conventions for describing the initial state. -// -// Naturally, it would be impractical to have to scan the entire -// program's CFI, noting changes as we go, just to recover the -// unwinding rules in effect at one particular instruction. To avoid -// this, CFI data is grouped into "entries", each of which covers a -// specified range of addresses and begins with a complete statement -// of the rules for all recoverable registers at that starting -// address. Each entry typically covers a single function. -// -// Thus, to compute the contents of a given row of the table --- that -// is, rules for recovering the CFA, RA, and registers at a given -// instruction --- the consumer should find the entry that covers that -// instruction's address, start with the initial state supplied at the -// beginning of the entry, and work forward until it has processed all -// the changes up to and including those for the present instruction. -// -// There are seven kinds of rules that can appear in an entry of the -// table: -// -// - "undefined": The given register is not preserved by the callee; -// its value cannot be recovered. -// -// - "same value": This register has the same value it did in the callee. -// -// - offset(N): The register is saved at offset N from the CFA. -// -// - val_offset(N): The value the register had in the caller is the -// CFA plus offset N. (This is usually only useful for describing -// the stack pointer.) -// -// - register(R): The register's value was saved in another register R. -// -// - expression(E): Evaluating the DWARF expression E using the -// current frame's registers' values yields the address at which the -// register was saved. -// -// - val_expression(E): Evaluating the DWARF expression E using the -// current frame's registers' values yields the value the register -// had in the caller. - -class CallFrameInfo { - public: - // The different kinds of entries one finds in CFI. Used internally, - // and for error reporting. - enum EntryKind { kUnknown, kCIE, kFDE, kTerminator }; - - // The handler class to which the parser hands the parsed call frame - // information. Defined below. - class Handler; - - // A reporter class, which CallFrameInfo uses to report errors - // encountered while parsing call frame information. Defined below. - class Reporter; - - // Create a DWARF CFI parser. BUFFER points to the contents of the - // .debug_frame section to parse; BUFFER_LENGTH is its length in bytes. - // REPORTER is an error reporter the parser should use to report - // problems. READER is a ByteReader instance that has the endianness and - // address size set properly. Report the data we find to HANDLER. - // - // This class can also parse Linux C++ exception handling data, as found - // in '.eh_frame' sections. This data is a variant of DWARF CFI that is - // placed in loadable segments so that it is present in the program's - // address space, and is interpreted by the C++ runtime to search the - // call stack for a handler interested in the exception being thrown, - // actually pop the frames, and find cleanup code to run. - // - // There are two differences between the call frame information described - // in the DWARF standard and the exception handling data Linux places in - // the .eh_frame section: - // - // - Exception handling data uses uses a different format for call frame - // information entry headers. The distinguished CIE id, the way FDEs - // refer to their CIEs, and the way the end of the series of entries is - // determined are all slightly different. - // - // If the constructor's EH_FRAME argument is true, then the - // CallFrameInfo parses the entry headers as Linux C++ exception - // handling data. If EH_FRAME is false or omitted, the CallFrameInfo - // parses standard DWARF call frame information. - // - // - Linux C++ exception handling data uses CIE augmentation strings - // beginning with 'z' to specify the presence of additional data after - // the CIE and FDE headers and special encodings used for addresses in - // frame description entries. - // - // CallFrameInfo can handle 'z' augmentations in either DWARF CFI or - // exception handling data if you have supplied READER with the base - // addresses needed to interpret the pointer encodings that 'z' - // augmentations can specify. See the ByteReader interface for details - // about the base addresses. See the CallFrameInfo::Handler interface - // for details about the additional information one might find in - // 'z'-augmented data. - // - // Thus: - // - // - If you are parsing standard DWARF CFI, as found in a .debug_frame - // section, you should pass false for the EH_FRAME argument, or omit - // it, and you need not worry about providing READER with the - // additional base addresses. - // - // - If you want to parse Linux C++ exception handling data from a - // .eh_frame section, you should pass EH_FRAME as true, and call - // READER's Set*Base member functions before calling our Start method. - // - // - If you want to parse DWARF CFI that uses the 'z' augmentations - // (although I don't think any toolchain ever emits such data), you - // could pass false for EH_FRAME, but call READER's Set*Base members. - // - // The extensions the Linux C++ ABI makes to DWARF for exception - // handling are described here, rather poorly: - // 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 - // - // The mechanics of C++ exception handling, personality routines, - // and language-specific data areas are described here, rather nicely: - // http://www.codesourcery.com/public/cxx-abi/abi-eh.html - CallFrameInfo(const uint8_t *buffer, size_t buffer_length, - ByteReader *reader, Handler *handler, Reporter *reporter, - bool eh_frame = false) - : buffer_(buffer), buffer_length_(buffer_length), - reader_(reader), handler_(handler), reporter_(reporter), - eh_frame_(eh_frame) { } - - ~CallFrameInfo() { } - - // Parse the entries in BUFFER, reporting what we find to HANDLER. - // Return true if we reach the end of the section successfully, or - // false if we encounter an error. - bool Start(); - - // Return the textual name of KIND. For error reporting. - static const char *KindName(EntryKind kind); - - private: - - struct CIE; - - // A CFI entry, either an FDE or a CIE. - struct Entry { - // The starting offset of the entry in the section, for error - // reporting. - size_t offset; - - // The start of this entry in the buffer. - const uint8_t *start; - - // Which kind of entry this is. - // - // We want to be able to use this for error reporting even while we're - // in the midst of parsing. Error reporting code may assume that kind, - // offset, and start fields are valid, although kind may be kUnknown. - EntryKind kind; - - // The end of this entry's common prologue (initial length and id), and - // the start of this entry's kind-specific fields. - const uint8_t *fields; - - // The start of this entry's instructions. - const uint8_t *instructions; - - // The address past the entry's last byte in the buffer. (Note that - // since offset points to the entry's initial length field, and the - // length field is the number of bytes after that field, this is not - // simply buffer_ + offset + length.) - const uint8_t *end; - - // For both DWARF CFI and .eh_frame sections, this is the CIE id in a - // CIE, and the offset of the associated CIE in an FDE. - uint64 id; - - // The CIE that applies to this entry, if we've parsed it. If this is a - // CIE, then this field points to this structure. - CIE *cie; - }; - - // A common information entry (CIE). - struct CIE: public Entry { - uint8 version; // CFI data version number - string augmentation; // vendor format extension markers - uint64 code_alignment_factor; // scale for code address adjustments - int data_alignment_factor; // scale for stack pointer adjustments - unsigned return_address_register; // which register holds the return addr - - // True if this CIE includes Linux C++ ABI 'z' augmentation data. - bool has_z_augmentation; - - // Parsed 'z' augmentation data. These are meaningful only if - // has_z_augmentation is true. - bool has_z_lsda; // The 'z' augmentation included 'L'. - bool has_z_personality; // The 'z' augmentation included 'P'. - bool has_z_signal_frame; // The 'z' augmentation included 'S'. - - // If has_z_lsda is true, this is the encoding to be used for language- - // specific data area pointers in FDEs. - DwarfPointerEncoding lsda_encoding; - - // If has_z_personality is true, this is the encoding used for the - // personality routine pointer in the augmentation data. - DwarfPointerEncoding personality_encoding; - - // If has_z_personality is true, this is the address of the personality - // routine --- or, if personality_encoding & DW_EH_PE_indirect, the - // address where the personality routine's address is stored. - uint64 personality_address; - - // This is the encoding used for addresses in the FDE header and - // in DW_CFA_set_loc instructions. This is always valid, whether - // or not we saw a 'z' augmentation string; its default value is - // DW_EH_PE_absptr, which is what normal DWARF CFI uses. - DwarfPointerEncoding pointer_encoding; - }; - - // A frame description entry (FDE). - struct FDE: public Entry { - uint64 address; // start address of described code - uint64 size; // size of described code, in bytes - - // If cie->has_z_lsda is true, then this is the language-specific data - // area's address --- or its address's address, if cie->lsda_encoding - // has the DW_EH_PE_indirect bit set. - uint64 lsda_address; - }; - - // Internal use. - class Rule; - class UndefinedRule; - class SameValueRule; - class OffsetRule; - class ValOffsetRule; - class RegisterRule; - class ExpressionRule; - class ValExpressionRule; - class RuleMap; - class State; - - // Parse the initial length and id of a CFI entry, either a CIE, an FDE, - // or a .eh_frame end-of-data mark. CURSOR points to the beginning of the - // data to parse. On success, populate ENTRY as appropriate, and return - // true. On failure, report the problem, and return false. Even if we - // return false, set ENTRY->end to the first byte after the entry if we - // were able to figure that out, or NULL if we weren't. - bool ReadEntryPrologue(const uint8_t *cursor, Entry *entry); - - // Parse the fields of a CIE after the entry prologue, including any 'z' - // augmentation data. Assume that the 'Entry' fields of CIE are - // populated; use CIE->fields and CIE->end as the start and limit for - // parsing. On success, populate the rest of *CIE, and return true; on - // failure, report the problem and return false. - bool ReadCIEFields(CIE *cie); - - // Parse the fields of an FDE after the entry prologue, including any 'z' - // augmentation data. Assume that the 'Entry' fields of *FDE are - // initialized; use FDE->fields and FDE->end as the start and limit for - // parsing. Assume that FDE->cie is fully initialized. On success, - // populate the rest of *FDE, and return true; on failure, report the - // problem and return false. - bool ReadFDEFields(FDE *fde); - - // Report that ENTRY is incomplete, and return false. This is just a - // trivial wrapper for invoking reporter_->Incomplete; it provides a - // little brevity. - bool ReportIncomplete(Entry *entry); - - // Return true if ENCODING has the DW_EH_PE_indirect bit set. - static bool IsIndirectEncoding(DwarfPointerEncoding encoding) { - return encoding & DW_EH_PE_indirect; - } - - // The contents of the DWARF .debug_info section we're parsing. - const uint8_t *buffer_; - size_t buffer_length_; - - // For reading multi-byte values with the appropriate endianness. - ByteReader *reader_; - - // The handler to which we should report the data we find. - Handler *handler_; - - // For reporting problems in the info we're parsing. - Reporter *reporter_; - - // True if we are processing .eh_frame-format data. - bool eh_frame_; -}; - -// The handler class for CallFrameInfo. The a CFI parser calls the -// member functions of a handler object to report the data it finds. -class CallFrameInfo::Handler { - public: - // The pseudo-register number for the canonical frame address. - enum { kCFARegister = -1 }; - - Handler() { } - virtual ~Handler() { } - - // The parser has found CFI for the machine code at ADDRESS, - // extending for LENGTH bytes. OFFSET is the offset of the frame - // description entry in the section, for use in error messages. - // VERSION is the version number of the CFI format. AUGMENTATION is - // a string describing any producer-specific extensions present in - // the data. RETURN_ADDRESS is the number of the register that holds - // the address to which the function should return. - // - // Entry should return true to process this CFI, or false to skip to - // the next entry. - // - // The parser invokes Entry for each Frame Description Entry (FDE) - // it finds. The parser doesn't report Common Information Entries - // to the handler explicitly; instead, if the handler elects to - // process a given FDE, the parser reiterates the appropriate CIE's - // contents at the beginning of the FDE's rules. - virtual bool Entry(size_t offset, uint64 address, uint64 length, - uint8 version, const string &augmentation, - unsigned return_address) = 0; - - // When the Entry function returns true, the parser calls these - // handler functions repeatedly to describe the rules for recovering - // registers at each instruction in the given range of machine code. - // Immediately after a call to Entry, the handler should assume that - // the rule for each callee-saves register is "unchanged" --- that - // is, that the register still has the value it had in the caller. - // - // If a *Rule function returns true, we continue processing this entry's - // instructions. If a *Rule function returns false, we stop evaluating - // instructions, and skip to the next entry. Either way, we call End - // before going on to the next entry. - // - // In all of these functions, if the REG parameter is kCFARegister, then - // the rule describes how to find the canonical frame address. - // kCFARegister may be passed as a BASE_REGISTER argument, meaning that - // the canonical frame address should be used as the base address for the - // computation. All other REG values will be positive. - - // At ADDRESS, register REG's value is not recoverable. - virtual bool UndefinedRule(uint64 address, int reg) = 0; - - // At ADDRESS, register REG's value is the same as that it had in - // the caller. - virtual bool SameValueRule(uint64 address, int reg) = 0; - - // At ADDRESS, register REG has been saved at offset OFFSET from - // BASE_REGISTER. - virtual bool OffsetRule(uint64 address, int reg, - int base_register, long offset) = 0; - - // At ADDRESS, the caller's value of register REG is the current - // value of BASE_REGISTER plus OFFSET. (This rule doesn't provide an - // address at which the register's value is saved.) - virtual bool ValOffsetRule(uint64 address, int reg, - int base_register, long offset) = 0; - - // At ADDRESS, register REG has been saved in BASE_REGISTER. This differs - // from ValOffsetRule(ADDRESS, REG, BASE_REGISTER, 0), in that - // BASE_REGISTER is the "home" for REG's saved value: if you want to - // assign to a variable whose home is REG in the calling frame, you - // should put the value in BASE_REGISTER. - virtual bool RegisterRule(uint64 address, int reg, int base_register) = 0; - - // At ADDRESS, the DWARF expression EXPRESSION yields the address at - // which REG was saved. - virtual bool ExpressionRule(uint64 address, int reg, - const string &expression) = 0; - - // At ADDRESS, the DWARF expression EXPRESSION yields the caller's - // value for REG. (This rule doesn't provide an address at which the - // register's value is saved.) - virtual bool ValExpressionRule(uint64 address, int reg, - const string &expression) = 0; - - // Indicate that the rules for the address range reported by the - // last call to Entry are complete. End should return true if - // everything is okay, or false if an error has occurred and parsing - // should stop. - virtual bool End() = 0; - - // Handler functions for Linux C++ exception handling data. These are - // only called if the data includes 'z' augmentation strings. - - // The Linux C++ ABI uses an extension of the DWARF CFI format to - // walk the stack to propagate exceptions from the throw to the - // appropriate catch, and do the appropriate cleanups along the way. - // CFI entries used for exception handling have two additional data - // associated with them: - // - // - The "language-specific data area" describes which exception - // types the function has 'catch' clauses for, and indicates how - // to go about re-entering the function at the appropriate catch - // clause. If the exception is not caught, it describes the - // destructors that must run before the frame is popped. - // - // - The "personality routine" is responsible for interpreting the - // language-specific data area's contents, and deciding whether - // the exception should continue to propagate down the stack, - // perhaps after doing some cleanup for this frame, or whether the - // exception will be caught here. - // - // In principle, the language-specific data area is opaque to - // everybody but the personality routine. In practice, these values - // may be useful or interesting to readers with extra context, and - // we have to at least skip them anyway, so we might as well report - // them to the handler. - - // This entry's exception handling personality routine's address is - // ADDRESS. If INDIRECT is true, then ADDRESS is the address at - // which the routine's address is stored. The default definition for - // this handler function simply returns true, allowing parsing of - // the entry to continue. - virtual bool PersonalityRoutine(uint64 address, bool indirect) { - return true; - } - - // This entry's language-specific data area (LSDA) is located at - // ADDRESS. If INDIRECT is true, then ADDRESS is the address at - // which the area's address is stored. The default definition for - // this handler function simply returns true, allowing parsing of - // the entry to continue. - virtual bool LanguageSpecificDataArea(uint64 address, bool indirect) { - return true; - } - - // This entry describes a signal trampoline --- this frame is the - // caller of a signal handler. The default definition for this - // handler function simply returns true, allowing parsing of the - // entry to continue. - // - // The best description of the rationale for and meaning of signal - // trampoline CFI entries seems to be in the GCC bug database: - // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=26208 - virtual bool SignalHandler() { return true; } -}; - -// The CallFrameInfo class makes calls on an instance of this class to -// report errors or warn about problems in the data it is parsing. The -// default definitions of these methods print a message to stderr, but -// you can make a derived class that overrides them. -class CallFrameInfo::Reporter { - public: - // Create an error reporter which attributes troubles to the section - // named SECTION in FILENAME. - // - // Normally SECTION would be .debug_frame, but the Mac puts CFI data - // in a Mach-O section named __debug_frame. If we support - // Linux-style exception handling data, we could be reading an - // .eh_frame section. - Reporter(const string &filename, - const string §ion = ".debug_frame") - : filename_(filename), section_(section) { } - virtual ~Reporter() { } - - // The CFI entry at OFFSET ends too early to be well-formed. KIND - // indicates what kind of entry it is; KIND can be kUnknown if we - // haven't parsed enough of the entry to tell yet. - virtual void Incomplete(uint64 offset, CallFrameInfo::EntryKind kind); - - // The .eh_frame data has a four-byte zero at OFFSET where the next - // entry's length would be; this is a terminator. However, the buffer - // length as given to the CallFrameInfo constructor says there should be - // more data. - virtual void EarlyEHTerminator(uint64 offset); - - // The FDE at OFFSET refers to the CIE at CIE_OFFSET, but the - // section is not that large. - virtual void CIEPointerOutOfRange(uint64 offset, uint64 cie_offset); - - // The FDE at OFFSET refers to the CIE at CIE_OFFSET, but the entry - // there is not a CIE. - virtual void BadCIEId(uint64 offset, uint64 cie_offset); - - // The FDE at OFFSET refers to a CIE with version number VERSION, - // which we don't recognize. We cannot parse DWARF CFI if it uses - // a version number we don't recognize. - virtual void UnrecognizedVersion(uint64 offset, int version); - - // The FDE at OFFSET refers to a CIE with augmentation AUGMENTATION, - // which we don't recognize. We cannot parse DWARF CFI if it uses - // augmentations we don't recognize. - virtual void UnrecognizedAugmentation(uint64 offset, - const string &augmentation); - - // The pointer encoding ENCODING, specified by the CIE at OFFSET, is not - // a valid encoding. - virtual void InvalidPointerEncoding(uint64 offset, uint8 encoding); - - // The pointer encoding ENCODING, specified by the CIE at OFFSET, depends - // on a base address which has not been supplied. - virtual void UnusablePointerEncoding(uint64 offset, uint8 encoding); - - // The CIE at OFFSET contains a DW_CFA_restore instruction at - // INSN_OFFSET, which may not appear in a CIE. - virtual void RestoreInCIE(uint64 offset, uint64 insn_offset); - - // The entry at OFFSET, of kind KIND, has an unrecognized - // instruction at INSN_OFFSET. - virtual void BadInstruction(uint64 offset, CallFrameInfo::EntryKind kind, - uint64 insn_offset); - - // The instruction at INSN_OFFSET in the entry at OFFSET, of kind - // KIND, establishes a rule that cites the CFA, but we have not - // established a CFA rule yet. - virtual void NoCFARule(uint64 offset, CallFrameInfo::EntryKind kind, - uint64 insn_offset); - - // The instruction at INSN_OFFSET in the entry at OFFSET, of kind - // KIND, is a DW_CFA_restore_state instruction, but the stack of - // saved states is empty. - virtual void EmptyStateStack(uint64 offset, CallFrameInfo::EntryKind kind, - uint64 insn_offset); - - // The DW_CFA_remember_state instruction at INSN_OFFSET in the entry - // at OFFSET, of kind KIND, would restore a state that has no CFA - // rule, whereas the current state does have a CFA rule. This is - // bogus input, which the CallFrameInfo::Handler interface doesn't - // (and shouldn't) have any way to report. - virtual void ClearingCFARule(uint64 offset, CallFrameInfo::EntryKind kind, - uint64 insn_offset); - - protected: - // The name of the file whose CFI we're reading. - string filename_; - - // The name of the CFI section in that file. - string section_; -}; - -} // namespace dwarf2reader - -#endif // UTIL_DEBUGINFO_DWARF2READER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc deleted file mode 100644 index e50ea5fbd..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc +++ /dev/null @@ -1,2468 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf2reader_cfi_unittest.cc: Unit tests for dwarf2reader::CallFrameInfo - -#include <stdint.h> -#include <stdlib.h> - -#include <string> -#include <vector> - -// The '.eh_frame' format, used by the Linux C++ ABI for exception -// handling, is poorly specified. To help test our support for .eh_frame, -// if you #define WRITE_ELF while compiling this file, and add the -// 'include' directory from the binutils, gcc, or gdb source tree to the -// #include path, then each test that calls the -// PERHAPS_WRITE_DEBUG_FRAME_FILE or PERHAPS_WRITE_EH_FRAME_FILE will write -// an ELF file containing a .debug_frame or .eh_frame section; you can then -// use tools like readelf to examine the test data, and check the tools' -// interpretation against the test's intentions. Each ELF file is named -// "cfitest-TEST", where TEST identifies the particular test. -#ifdef WRITE_ELF -#include <errno.h> -#include <stdio.h> -#include <string.h> -extern "C" { -// To compile with WRITE_ELF, you should add the 'include' directory -// of the binutils, gcc, or gdb source tree to your #include path; -// that directory contains this header. -#include "elf/common.h" -} -#endif - -#include "breakpad_googletest_includes.h" -#include "common/dwarf/bytereader-inl.h" -#include "common/dwarf/cfi_assembler.h" -#include "common/dwarf/dwarf2reader.h" -#include "common/using_std_string.h" -#include "google_breakpad/common/breakpad_types.h" - -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 dwarf2reader::DwarfPointerEncoding; -using dwarf2reader::ENDIANNESS_BIG; -using dwarf2reader::ENDIANNESS_LITTLE; -using dwarf2reader::ByteReader; -using dwarf2reader::CallFrameInfo; - -using std::vector; -using testing::InSequence; -using testing::Return; -using testing::Sequence; -using testing::Test; -using testing::_; - -#ifdef WRITE_ELF -void WriteELFFrameSection(const char *filename, const char *section_name, - const CFISection §ion); -#define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section) \ - WriteELFFrameSection("cfitest-" name, ".debug_frame", section); -#define PERHAPS_WRITE_EH_FRAME_FILE(name, section) \ - WriteELFFrameSection("cfitest-" name, ".eh_frame", section); -#else -#define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section) -#define PERHAPS_WRITE_EH_FRAME_FILE(name, section) -#endif - -class MockCallFrameInfoHandler: public CallFrameInfo::Handler { - public: - MOCK_METHOD6(Entry, bool(size_t offset, uint64 address, uint64 length, - uint8 version, const string &augmentation, - unsigned return_address)); - MOCK_METHOD2(UndefinedRule, bool(uint64 address, int reg)); - MOCK_METHOD2(SameValueRule, bool(uint64 address, int reg)); - MOCK_METHOD4(OffsetRule, bool(uint64 address, int reg, int base_register, - long offset)); - MOCK_METHOD4(ValOffsetRule, bool(uint64 address, int reg, int base_register, - long offset)); - MOCK_METHOD3(RegisterRule, bool(uint64 address, int reg, int base_register)); - MOCK_METHOD3(ExpressionRule, bool(uint64 address, int reg, - const string &expression)); - MOCK_METHOD3(ValExpressionRule, bool(uint64 address, int reg, - const string &expression)); - MOCK_METHOD0(End, bool()); - MOCK_METHOD2(PersonalityRoutine, bool(uint64 address, bool indirect)); - MOCK_METHOD2(LanguageSpecificDataArea, bool(uint64 address, bool indirect)); - MOCK_METHOD0(SignalHandler, bool()); -}; - -class MockCallFrameErrorReporter: public CallFrameInfo::Reporter { - public: - MockCallFrameErrorReporter() : Reporter("mock filename", "mock section") { } - MOCK_METHOD2(Incomplete, void(uint64, CallFrameInfo::EntryKind)); - MOCK_METHOD1(EarlyEHTerminator, void(uint64)); - MOCK_METHOD2(CIEPointerOutOfRange, void(uint64, uint64)); - MOCK_METHOD2(BadCIEId, void(uint64, uint64)); - MOCK_METHOD2(UnrecognizedVersion, void(uint64, int version)); - MOCK_METHOD2(UnrecognizedAugmentation, void(uint64, const string &)); - MOCK_METHOD2(InvalidPointerEncoding, void(uint64, uint8)); - MOCK_METHOD2(UnusablePointerEncoding, void(uint64, uint8)); - MOCK_METHOD2(RestoreInCIE, void(uint64, uint64)); - MOCK_METHOD3(BadInstruction, void(uint64, CallFrameInfo::EntryKind, uint64)); - MOCK_METHOD3(NoCFARule, void(uint64, CallFrameInfo::EntryKind, uint64)); - MOCK_METHOD3(EmptyStateStack, void(uint64, CallFrameInfo::EntryKind, uint64)); -}; - -struct CFIFixture { - - enum { kCFARegister = CallFrameInfo::Handler::kCFARegister }; - - CFIFixture() { - // Default expectations for the data handler. - // - // - Leave Entry and End without expectations, as it's probably a - // good idea to set those explicitly in each test. - // - // - Expect the *Rule functions to not be called, - // so that each test can simply list the calls they expect. - // - // I gather I could use StrictMock for this, but the manual seems - // to suggest using that only as a last resort, and this isn't so - // bad. - EXPECT_CALL(handler, UndefinedRule(_, _)).Times(0); - EXPECT_CALL(handler, SameValueRule(_, _)).Times(0); - EXPECT_CALL(handler, OffsetRule(_, _, _, _)).Times(0); - EXPECT_CALL(handler, ValOffsetRule(_, _, _, _)).Times(0); - EXPECT_CALL(handler, RegisterRule(_, _, _)).Times(0); - EXPECT_CALL(handler, ExpressionRule(_, _, _)).Times(0); - EXPECT_CALL(handler, ValExpressionRule(_, _, _)).Times(0); - EXPECT_CALL(handler, PersonalityRoutine(_, _)).Times(0); - EXPECT_CALL(handler, LanguageSpecificDataArea(_, _)).Times(0); - EXPECT_CALL(handler, SignalHandler()).Times(0); - - // Default expectations for the error/warning reporer. - EXPECT_CALL(reporter, Incomplete(_, _)).Times(0); - EXPECT_CALL(reporter, EarlyEHTerminator(_)).Times(0); - EXPECT_CALL(reporter, CIEPointerOutOfRange(_, _)).Times(0); - EXPECT_CALL(reporter, BadCIEId(_, _)).Times(0); - EXPECT_CALL(reporter, UnrecognizedVersion(_, _)).Times(0); - EXPECT_CALL(reporter, UnrecognizedAugmentation(_, _)).Times(0); - EXPECT_CALL(reporter, InvalidPointerEncoding(_, _)).Times(0); - EXPECT_CALL(reporter, UnusablePointerEncoding(_, _)).Times(0); - EXPECT_CALL(reporter, RestoreInCIE(_, _)).Times(0); - EXPECT_CALL(reporter, BadInstruction(_, _, _)).Times(0); - EXPECT_CALL(reporter, NoCFARule(_, _, _)).Times(0); - EXPECT_CALL(reporter, EmptyStateStack(_, _, _)).Times(0); - } - - MockCallFrameInfoHandler handler; - MockCallFrameErrorReporter reporter; -}; - -class CFI: public CFIFixture, public Test { }; - -TEST_F(CFI, EmptyRegion) { - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - static const uint8_t data[] = { 42 }; - - ByteReader byte_reader(ENDIANNESS_BIG); - CallFrameInfo parser(data, 0, &byte_reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -TEST_F(CFI, IncompleteLength32) { - CFISection section(kBigEndian, 8); - section - // Not even long enough for an initial length. - .D16(0xa0f) - // Padding to keep valgrind happy. We subtract these off when we - // construct the parser. - .D16(0); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) - .WillOnce(Return()); - - string contents; - ASSERT_TRUE(section.GetContents(&contents)); - - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size() - 2, - &byte_reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -TEST_F(CFI, IncompleteLength64) { - CFISection section(kLittleEndian, 4); - section - // An incomplete 64-bit DWARF initial length. - .D32(0xffffffff).D32(0x71fbaec2) - // Padding to keep valgrind happy. We subtract these off when we - // construct the parser. - .D32(0); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) - .WillOnce(Return()); - - string contents; - ASSERT_TRUE(section.GetContents(&contents)); - - ByteReader byte_reader(ENDIANNESS_LITTLE); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size() - 4, - &byte_reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -TEST_F(CFI, IncompleteId32) { - CFISection section(kBigEndian, 8); - section - .D32(3) // Initial length, not long enough for id - .D8(0xd7).D8(0xe5).D8(0xf1) // incomplete id - .CIEHeader(8727, 3983, 8889, 3, "") - .FinishEntry(); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) - .WillOnce(Return()); - - string contents; - ASSERT_TRUE(section.GetContents(&contents)); - - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -TEST_F(CFI, BadId32) { - CFISection section(kBigEndian, 8); - section - .D32(0x100) // Initial length - .D32(0xe802fade) // bogus ID - .Append(0x100 - 4, 0x42); // make the length true - section - .CIEHeader(1672, 9872, 8529, 3, "") - .FinishEntry(); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - EXPECT_CALL(reporter, CIEPointerOutOfRange(_, 0xe802fade)) - .WillOnce(Return()); - - string contents; - ASSERT_TRUE(section.GetContents(&contents)); - - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -// A lone CIE shouldn't cause any handler calls. -TEST_F(CFI, SingleCIE) { - CFISection section(kLittleEndian, 4); - section.CIEHeader(0xffe799a8, 0x3398dcdd, 0x6e9683de, 3, ""); - section.Append(10, dwarf2reader::DW_CFA_nop); - section.FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("SingleCIE", section); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_LITTLE); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// One FDE, one CIE. -TEST_F(CFI, OneFDE) { - CFISection section(kBigEndian, 4); - Label cie; - section - .Mark(&cie) - .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "") - .FinishEntry() - .FDEHeader(cie, 0x7714740d, 0x3d5a10cd) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("OneFDE", section); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0x7714740d, 0x3d5a10cd, 3, "", 0x6b6efb87)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// Two FDEs share a CIE. -TEST_F(CFI, TwoFDEsOneCIE) { - CFISection section(kBigEndian, 4); - Label cie; - section - // First FDE. readelf complains about this one because it makes - // a forward reference to its CIE. - .FDEHeader(cie, 0xa42744df, 0xa3b42121) - .FinishEntry() - // CIE. - .Mark(&cie) - .CIEHeader(0x04f7dc7b, 0x3d00c05f, 0xbd43cb59, 3, "") - .FinishEntry() - // Second FDE. - .FDEHeader(cie, 0x6057d391, 0x700f608d) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsOneCIE", section); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0xa42744df, 0xa3b42121, 3, "", 0xbd43cb59)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0x6057d391, 0x700f608d, 3, "", 0xbd43cb59)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// Two FDEs, two CIEs. -TEST_F(CFI, TwoFDEsTwoCIEs) { - CFISection section(kLittleEndian, 8); - Label cie1, cie2; - section - // First CIE. - .Mark(&cie1) - .CIEHeader(0x694d5d45, 0x4233221b, 0xbf45e65a, 3, "") - .FinishEntry() - // First FDE which cites second CIE. readelf complains about - // this one because it makes a forward reference to its CIE. - .FDEHeader(cie2, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL) - .FinishEntry() - // Second FDE, which cites first CIE. - .FDEHeader(cie1, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL) - .FinishEntry() - // Second CIE. - .Mark(&cie2) - .CIEHeader(0xfba3fad7, 0x6287e1fd, 0x61d2c581, 2, "") - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsTwoCIEs", section); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL, 2, - "", 0x61d2c581)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL, 3, - "", 0xbf45e65a)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_LITTLE); - byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// An FDE whose CIE specifies a version we don't recognize. -TEST_F(CFI, BadVersion) { - CFISection section(kBigEndian, 4); - Label cie1, cie2; - section - .Mark(&cie1) - .CIEHeader(0xca878cf0, 0x7698ec04, 0x7b616f54, 0x52, "") - .FinishEntry() - // We should skip this entry, as its CIE specifies a version we - // don't recognize. - .FDEHeader(cie1, 0x08852292, 0x2204004a) - .FinishEntry() - // Despite the above, we should visit this entry. - .Mark(&cie2) - .CIEHeader(0x7c3ae7c9, 0xb9b9a512, 0x96cb3264, 3, "") - .FinishEntry() - .FDEHeader(cie2, 0x2094735a, 0x6e875501) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("BadVersion", section); - - EXPECT_CALL(reporter, UnrecognizedVersion(_, 0x52)) - .WillOnce(Return()); - - { - InSequence s; - // We should see no mention of the first FDE, but we should get - // a call to Entry for the second. - EXPECT_CALL(handler, Entry(_, 0x2094735a, 0x6e875501, 3, "", - 0x96cb3264)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -// An FDE whose CIE specifies an augmentation we don't recognize. -TEST_F(CFI, BadAugmentation) { - CFISection section(kBigEndian, 4); - Label cie1, cie2; - section - .Mark(&cie1) - .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "spaniels!") - .FinishEntry() - // We should skip this entry, as its CIE specifies an - // augmentation we don't recognize. - .FDEHeader(cie1, 0x7714740d, 0x3d5a10cd) - .FinishEntry() - // Despite the above, we should visit this entry. - .Mark(&cie2) - .CIEHeader(0xf8bc4399, 0x8cf09931, 0xf2f519b2, 3, "") - .FinishEntry() - .FDEHeader(cie2, 0x7bf0fda0, 0xcbcd28d8) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("BadAugmentation", section); - - EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "spaniels!")) - .WillOnce(Return()); - - { - InSequence s; - // We should see no mention of the first FDE, but we should get - // a call to Entry for the second. - EXPECT_CALL(handler, Entry(_, 0x7bf0fda0, 0xcbcd28d8, 3, "", - 0xf2f519b2)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -// The return address column field is a byte in CFI version 1 -// (DWARF2), but a ULEB128 value in version 3 (DWARF3). -TEST_F(CFI, CIEVersion1ReturnColumn) { - CFISection section(kBigEndian, 4); - Label cie; - section - // CIE, using the version 1 format: return column is a ubyte. - .Mark(&cie) - // Use a value for the return column that is parsed differently - // as a ubyte and as a ULEB128. - .CIEHeader(0xbcdea24f, 0x5be28286, 0x9f, 1, "") - .FinishEntry() - // FDE, citing that CIE. - .FDEHeader(cie, 0xb8d347b5, 0x825e55dc) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion1ReturnColumn", section); - - { - InSequence s; - EXPECT_CALL(handler, Entry(_, 0xb8d347b5, 0x825e55dc, 1, "", 0x9f)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// The return address column field is a byte in CFI version 1 -// (DWARF2), but a ULEB128 value in version 3 (DWARF3). -TEST_F(CFI, CIEVersion3ReturnColumn) { - CFISection section(kBigEndian, 4); - Label cie; - section - // CIE, using the version 3 format: return column is a ULEB128. - .Mark(&cie) - // Use a value for the return column that is parsed differently - // as a ubyte and as a ULEB128. - .CIEHeader(0x0ab4758d, 0xc010fdf7, 0x89, 3, "") - .FinishEntry() - // FDE, citing that CIE. - .FDEHeader(cie, 0x86763f2b, 0x2a66dc23) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion3ReturnColumn", section); - - { - InSequence s; - EXPECT_CALL(handler, Entry(_, 0x86763f2b, 0x2a66dc23, 3, "", 0x89)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -struct CFIInsnFixture: public CFIFixture { - CFIInsnFixture() : CFIFixture() { - data_factor = 0xb6f; - return_register = 0x9be1ed9f; - version = 3; - cfa_base_register = 0x383a3aa; - cfa_offset = 0xf748; - } - - // Prepare SECTION to receive FDE instructions. - // - // - Append a stock CIE header that establishes the fixture's - // code_factor, data_factor, return_register, version, and - // augmentation values. - // - Have the CIE set up a CFA rule using cfa_base_register and - // cfa_offset. - // - Append a stock FDE header, referring to the above CIE, for the - // fde_size bytes at fde_start. Choose fde_start and fde_size - // appropriately for the section's address size. - // - Set appropriate expectations on handler in sequence s for the - // frame description entry and the CIE's CFA rule. - // - // On return, SECTION is ready to have FDE instructions appended to - // it, and its FinishEntry member called. - void StockCIEAndFDE(CFISection *section) { - // Choose appropriate constants for our address size. - if (section->AddressSize() == 4) { - fde_start = 0xc628ecfbU; - fde_size = 0x5dee04a2; - code_factor = 0x60b; - } else { - assert(section->AddressSize() == 8); - fde_start = 0x0005c57ce7806bd3ULL; - fde_size = 0x2699521b5e333100ULL; - code_factor = 0x01008e32855274a8ULL; - } - - // Create the CIE. - (*section) - .Mark(&cie_label) - .CIEHeader(code_factor, data_factor, return_register, version, - "") - .D8(dwarf2reader::DW_CFA_def_cfa) - .ULEB128(cfa_base_register) - .ULEB128(cfa_offset) - .FinishEntry(); - - // Create the FDE. - section->FDEHeader(cie_label, fde_start, fde_size); - - // Expect an Entry call for the FDE and a ValOffsetRule call for the - // CIE's CFA rule. - EXPECT_CALL(handler, Entry(_, fde_start, fde_size, version, "", - return_register)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start, kCFARegister, - cfa_base_register, cfa_offset)) - .InSequence(s) - .WillOnce(Return(true)); - } - - // Run the contents of SECTION through a CallFrameInfo parser, - // expecting parser.Start to return SUCCEEDS - void ParseSection(CFISection *section, bool succeeds = true) { - string contents; - EXPECT_TRUE(section->GetContents(&contents)); - dwarf2reader::Endianness endianness; - if (section->endianness() == kBigEndian) - endianness = ENDIANNESS_BIG; - else { - assert(section->endianness() == kLittleEndian); - endianness = ENDIANNESS_LITTLE; - } - ByteReader byte_reader(endianness); - byte_reader.SetAddressSize(section->AddressSize()); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - if (succeeds) - EXPECT_TRUE(parser.Start()); - else - EXPECT_FALSE(parser.Start()); - } - - Label cie_label; - Sequence s; - uint64 code_factor; - int data_factor; - unsigned return_register; - unsigned version; - unsigned cfa_base_register; - int cfa_offset; - uint64 fde_start, fde_size; -}; - -class CFIInsn: public CFIInsnFixture, public Test { }; - -TEST_F(CFIInsn, DW_CFA_set_loc) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_set_loc).D32(0xb1ee3e7a) - // Use DW_CFA_def_cfa to force a handler call that we can use to - // check the effect of the DW_CFA_set_loc. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4defb431).ULEB128(0x6d17b0ee) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_set_loc", section); - - EXPECT_CALL(handler, - ValOffsetRule(0xb1ee3e7a, kCFARegister, 0x4defb431, 0x6d17b0ee)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_advance_loc) { - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_advance_loc | 0x2a) - // Use DW_CFA_def_cfa to force a handler call that we can use to - // check the effect of the DW_CFA_advance_loc. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x5bbb3715).ULEB128(0x0186c7bf) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc", section); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start + 0x2a * code_factor, - kCFARegister, 0x5bbb3715, 0x0186c7bf)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_advance_loc1) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_advance_loc1).D8(0xd8) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x69d5696a).ULEB128(0x1eb7fc93) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc1", section); - - EXPECT_CALL(handler, - ValOffsetRule((fde_start + 0xd8 * code_factor), - kCFARegister, 0x69d5696a, 0x1eb7fc93)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_advance_loc2) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_advance_loc2).D16(0x3adb) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3a368bed).ULEB128(0x3194ee37) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc2", section); - - EXPECT_CALL(handler, - ValOffsetRule((fde_start + 0x3adb * code_factor), - kCFARegister, 0x3a368bed, 0x3194ee37)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_advance_loc4) { - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_advance_loc4).D32(0x15813c88) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x135270c5).ULEB128(0x24bad7cb) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc4", section); - - EXPECT_CALL(handler, - ValOffsetRule((fde_start + 0x15813c88ULL * code_factor), - kCFARegister, 0x135270c5, 0x24bad7cb)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_MIPS_advance_loc8) { - code_factor = 0x2d; - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_MIPS_advance_loc8).D64(0x3c4f3945b92c14ULL) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0xe17ed602).ULEB128(0x3d162e7f) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc8", section); - - EXPECT_CALL(handler, - ValOffsetRule((fde_start + 0x3c4f3945b92c14ULL * code_factor), - kCFARegister, 0xe17ed602, 0x3d162e7f)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_def_cfa) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4e363a85).ULEB128(0x815f9aa7) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_def_cfa", section); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x4e363a85, 0x815f9aa7)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_def_cfa_sf) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x8ccb32b7).LEB128(0x9ea) - .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x9b40f5da).LEB128(-0x40a2) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x8ccb32b7, - 0x9ea * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x9b40f5da, - -0x40a2 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_def_cfa_register) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0x3e7e9363) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x3e7e9363, cfa_offset)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -// DW_CFA_def_cfa_register should have no effect when applied to a -// non-base/offset rule. -TEST_F(CFIInsn, DW_CFA_def_cfa_registerBadRule) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("needle in a haystack") - .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0xf1b49e49) - .FinishEntry(); - - EXPECT_CALL(handler, - ValExpressionRule(fde_start, kCFARegister, - "needle in a haystack")) - .WillRepeatedly(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_def_cfa_offset) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, cfa_base_register, - 0x1e8e3b9b)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_def_cfa_offset_sf) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(0x970) - .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(-0x2cd) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, cfa_base_register, - 0x970 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, cfa_base_register, - -0x2cd * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -// DW_CFA_def_cfa_offset should have no effect when applied to a -// non-base/offset rule. -TEST_F(CFIInsn, DW_CFA_def_cfa_offsetBadRule) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("six ways to Sunday") - .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) - .FinishEntry(); - - EXPECT_CALL(handler, - ValExpressionRule(fde_start, kCFARegister, "six ways to Sunday")) - .WillRepeatedly(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_def_cfa_expression) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("eating crow") - .FinishEntry(); - - EXPECT_CALL(handler, ValExpressionRule(fde_start, kCFARegister, - "eating crow")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_undefined) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x300ce45d) - .FinishEntry(); - - EXPECT_CALL(handler, UndefinedRule(fde_start, 0x300ce45d)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_same_value) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3865a760) - .FinishEntry(); - - EXPECT_CALL(handler, SameValueRule(fde_start, 0x3865a760)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_offset) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x9f6) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x2c, kCFARegister, 0x9f6 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_offset_extended) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_offset_extended).ULEB128(0x402b).ULEB128(0xb48) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x402b, kCFARegister, 0xb48 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_offset_extended_sf) { - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_offset_extended_sf) - .ULEB128(0x997c23ee).LEB128(0x2d00) - .D8(dwarf2reader::DW_CFA_offset_extended_sf) - .ULEB128(0x9519eb82).LEB128(-0xa77) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x997c23ee, - kCFARegister, 0x2d00 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x9519eb82, - kCFARegister, -0xa77 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_val_offset) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x623562fe).ULEB128(0x673) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, 0x623562fe, - kCFARegister, 0x673 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_val_offset_sf) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x6f4f).LEB128(0xaab) - .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x2483).LEB128(-0x8a2) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, 0x6f4f, - kCFARegister, 0xaab * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, - ValOffsetRule(fde_start, 0x2483, - kCFARegister, -0x8a2 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_register) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x278d18f9).ULEB128(0x1a684414) - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0x278d18f9, 0x1a684414)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_expression) { - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xa1619fb2) - .Block("plus ça change, plus c'est la même chose") - .FinishEntry(); - - EXPECT_CALL(handler, - ExpressionRule(fde_start, 0xa1619fb2, - "plus ça change, plus c'est la même chose")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_val_expression) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xc5e4a9e3) - .Block("he who has the gold makes the rules") - .FinishEntry(); - - EXPECT_CALL(handler, - ValExpressionRule(fde_start, 0xc5e4a9e3, - "he who has the gold makes the rules")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_restore) { - CFISection section(kLittleEndian, 8); - code_factor = 0x01bd188a9b1fa083ULL; - data_factor = -0x1ac8; - return_register = 0x8c35b049; - version = 2; - fde_start = 0x2d70fe998298bbb1ULL; - fde_size = 0x46ccc2e63cf0b108ULL; - Label cie; - section - .Mark(&cie) - .CIEHeader(code_factor, data_factor, return_register, version, - "") - // Provide a CFA rule, because register rules require them. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x6ca1d50e).ULEB128(0x372e38e8) - // Provide an offset(N) rule for register 0x3c. - .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0xb348) - .FinishEntry() - // In the FDE... - .FDEHeader(cie, fde_start, fde_size) - // At a second address, provide a new offset(N) rule for register 0x3c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x13) - .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0x9a50) - // At a third address, restore the original rule for register 0x3c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x01) - .D8(dwarf2reader::DW_CFA_restore | 0x3c) - .FinishEntry(); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, fde_start, fde_size, version, "", return_register)) - .WillOnce(Return(true)); - // CIE's CFA rule. - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x6ca1d50e, 0x372e38e8)) - .WillOnce(Return(true)); - // CIE's rule for register 0x3c. - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x3c, kCFARegister, 0xb348 * data_factor)) - .WillOnce(Return(true)); - // FDE's rule for register 0x3c. - EXPECT_CALL(handler, - OffsetRule(fde_start + 0x13 * code_factor, 0x3c, - kCFARegister, 0x9a50 * data_factor)) - .WillOnce(Return(true)); - // Restore CIE's rule for register 0x3c. - EXPECT_CALL(handler, - OffsetRule(fde_start + (0x13 + 0x01) * code_factor, 0x3c, - kCFARegister, 0xb348 * data_factor)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_restoreNoRule) { - CFISection section(kBigEndian, 4); - code_factor = 0x005f78143c1c3b82ULL; - data_factor = 0x25d0; - return_register = 0xe8; - version = 1; - fde_start = 0x4062e30f; - fde_size = 0x5302a389; - Label cie; - section - .Mark(&cie) - .CIEHeader(code_factor, data_factor, return_register, version, "") - // Provide a CFA rule, because register rules require them. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x470aa334).ULEB128(0x099ef127) - .FinishEntry() - // In the FDE... - .FDEHeader(cie, fde_start, fde_size) - // At a second address, provide an offset(N) rule for register 0x2c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x7) - .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x1f47) - // At a third address, restore the (missing) CIE rule for register 0x2c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0xb) - .D8(dwarf2reader::DW_CFA_restore | 0x2c) - .FinishEntry(); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, fde_start, fde_size, version, "", return_register)) - .WillOnce(Return(true)); - // CIE's CFA rule. - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x470aa334, 0x099ef127)) - .WillOnce(Return(true)); - // FDE's rule for register 0x2c. - EXPECT_CALL(handler, - OffsetRule(fde_start + 0x7 * code_factor, 0x2c, - kCFARegister, 0x1f47 * data_factor)) - .WillOnce(Return(true)); - // Restore CIE's (missing) rule for register 0x2c. - EXPECT_CALL(handler, - SameValueRule(fde_start + (0x7 + 0xb) * code_factor, 0x2c)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_restore_extended) { - CFISection section(kBigEndian, 4); - code_factor = 0x126e; - data_factor = -0xd8b; - return_register = 0x77711787; - version = 3; - fde_start = 0x01f55a45; - fde_size = 0x452adb80; - Label cie; - section - .Mark(&cie) - .CIEHeader(code_factor, data_factor, return_register, version, - "", true /* dwarf64 */ ) - // Provide a CFA rule, because register rules require them. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x56fa0edd).ULEB128(0x097f78a5) - // Provide an offset(N) rule for register 0x0f9b8a1c. - .D8(dwarf2reader::DW_CFA_offset_extended) - .ULEB128(0x0f9b8a1c).ULEB128(0xc979) - .FinishEntry() - // In the FDE... - .FDEHeader(cie, fde_start, fde_size) - // At a second address, provide a new offset(N) rule for reg 0x0f9b8a1c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x3) - .D8(dwarf2reader::DW_CFA_offset_extended) - .ULEB128(0x0f9b8a1c).ULEB128(0x3b7b) - // At a third address, restore the original rule for register 0x0f9b8a1c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x04) - .D8(dwarf2reader::DW_CFA_restore_extended).ULEB128(0x0f9b8a1c) - .FinishEntry(); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, fde_start, fde_size, version, "", return_register)) - .WillOnce(Return(true)); - // CIE's CFA rule. - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x56fa0edd, 0x097f78a5)) - .WillOnce(Return(true)); - // CIE's rule for register 0x0f9b8a1c. - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x0f9b8a1c, kCFARegister, - 0xc979 * data_factor)) - .WillOnce(Return(true)); - // FDE's rule for register 0x0f9b8a1c. - EXPECT_CALL(handler, - OffsetRule(fde_start + 0x3 * code_factor, 0x0f9b8a1c, - kCFARegister, 0x3b7b * data_factor)) - .WillOnce(Return(true)); - // Restore CIE's rule for register 0x0f9b8a1c. - EXPECT_CALL(handler, - OffsetRule(fde_start + (0x3 + 0x4) * code_factor, 0x0f9b8a1c, - kCFARegister, 0xc979 * data_factor)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_remember_and_restore_state) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - - // We create a state, save it, modify it, and then restore. We - // refer to the state that is overridden the restore as the - // "outgoing" state, and the restored state the "incoming" state. - // - // Register outgoing incoming expect - // 1 offset(N) no rule new "same value" rule - // 2 register(R) offset(N) report changed rule - // 3 offset(N) offset(M) report changed offset - // 4 offset(N) offset(N) no report - // 5 offset(N) no rule new "same value" rule - section - // Create the "incoming" state, which we will save and later restore. - .D8(dwarf2reader::DW_CFA_offset | 2).ULEB128(0x9806) - .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0x995d) - .D8(dwarf2reader::DW_CFA_offset | 4).ULEB128(0x7055) - .D8(dwarf2reader::DW_CFA_remember_state) - // Advance to a new instruction; an implementation could legitimately - // ignore all but the final rule for a given register at a given address. - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - // Create the "outgoing" state, which we will discard. - .D8(dwarf2reader::DW_CFA_offset | 1).ULEB128(0xea1a) - .D8(dwarf2reader::DW_CFA_register).ULEB128(2).ULEB128(0x1d2a3767) - .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0xdd29) - .D8(dwarf2reader::DW_CFA_offset | 5).ULEB128(0xf1ce) - // At a third address, restore the incoming state. - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - uint64 addr = fde_start; - - // Expect the incoming rules to be reported. - EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 4, kCFARegister, 0x7055 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - - addr += code_factor; - - // After the save, we establish the outgoing rule set. - EXPECT_CALL(handler, OffsetRule(addr, 1, kCFARegister, 0xea1a * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(addr, 2, 0x1d2a3767)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0xdd29 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 5, kCFARegister, 0xf1ce * data_factor)) - .InSequence(s).WillOnce(Return(true)); - - addr += code_factor; - - // Finally, after the restore, expect to see the differences from - // the outgoing to the incoming rules reported. - EXPECT_CALL(handler, SameValueRule(addr, 1)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SameValueRule(addr, 5)) - .InSequence(s).WillOnce(Return(true)); - - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -// Check that restoring a rule set reports changes to the CFA rule. -TEST_F(CFIInsn, DW_CFA_remember_and_restore_stateCFA) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - - section - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x90481102) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, kCFARegister, - cfa_base_register, 0x90481102)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor * 2, kCFARegister, - cfa_base_register, cfa_offset)) - .InSequence(s).WillOnce(Return(true)); - - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_nop) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_nop) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3fb8d4f1).ULEB128(0x078dc67b) - .D8(dwarf2reader::DW_CFA_nop) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x3fb8d4f1, 0x078dc67b)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_GNU_window_save) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_GNU_window_save) - .FinishEntry(); - - // Don't include all the rules in any particular sequence. - - // The caller's %o0-%o7 have become the callee's %i0-%i7. This is - // the GCC register numbering. - for (int i = 8; i < 16; i++) - EXPECT_CALL(handler, RegisterRule(fde_start, i, i + 16)) - .WillOnce(Return(true)); - // The caller's %l0-%l7 and %i0-%i7 have been saved at the top of - // its frame. - for (int i = 16; i < 32; i++) - EXPECT_CALL(handler, OffsetRule(fde_start, i, kCFARegister, (i-16) * 4)) - .WillOnce(Return(true)); - - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_GNU_args_size) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_GNU_args_size).ULEB128(0xeddfa520) - // Verify that we see this, meaning we parsed the above properly. - .D8(dwarf2reader::DW_CFA_offset | 0x23).ULEB128(0x269) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x23, kCFARegister, 0x269 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_GNU_negative_offset_extended) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_GNU_negative_offset_extended) - .ULEB128(0x430cc87a).ULEB128(0x613) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x430cc87a, - kCFARegister, -0x613 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -// Three FDEs: skip the second -TEST_F(CFIInsn, SkipFDE) { - CFISection section(kBigEndian, 4); - Label cie; - section - // CIE, used by all FDEs. - .Mark(&cie) - .CIEHeader(0x010269f2, 0x9177, 0xedca5849, 2, "") - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x42ed390b).ULEB128(0x98f43aad) - .FinishEntry() - // First FDE. - .FDEHeader(cie, 0xa870ebdd, 0x60f6aa4) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x3a860351).ULEB128(0x6c9a6bcf) - .FinishEntry() - // Second FDE. - .FDEHeader(cie, 0xc534f7c0, 0xf6552e9, true /* dwarf64 */) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x1b62c234).ULEB128(0x26586b18) - .FinishEntry() - // Third FDE. - .FDEHeader(cie, 0xf681cfc8, 0x7e4594e) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x26c53934).ULEB128(0x18eeb8a4) - .FinishEntry(); - - { - InSequence s; - - // Process the first FDE. - EXPECT_CALL(handler, Entry(_, 0xa870ebdd, 0x60f6aa4, 2, "", 0xedca5849)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0xa870ebdd, kCFARegister, - 0x42ed390b, 0x98f43aad)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(0xa870ebdd, 0x3a860351, 0x6c9a6bcf)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .WillOnce(Return(true)); - - // Skip the second FDE. - EXPECT_CALL(handler, Entry(_, 0xc534f7c0, 0xf6552e9, 2, "", 0xedca5849)) - .WillOnce(Return(false)); - - // Process the third FDE. - EXPECT_CALL(handler, Entry(_, 0xf681cfc8, 0x7e4594e, 2, "", 0xedca5849)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0xf681cfc8, kCFARegister, - 0x42ed390b, 0x98f43aad)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(0xf681cfc8, 0x26c53934, 0x18eeb8a4)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .WillOnce(Return(true)); - } - - ParseSection(§ion); -} - -// Quit processing in the middle of an entry's instructions. -TEST_F(CFIInsn, QuitMidentry) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe0cf850d).ULEB128(0x15aab431) - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x46750aa5).Block("meat") - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0xe0cf850d, 0x15aab431)) - .InSequence(s).WillOnce(Return(false)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion, false); -} - -class CFIRestore: public CFIInsnFixture, public Test { }; - -TEST_F(CFIRestore, RestoreUndefinedRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x0bac878e) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, UndefinedRule(fde_start, 0x0bac878e)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreUndefinedRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x7dedff5f) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x7dedff5f) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, UndefinedRule(fde_start, 0x7dedff5f)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SameValueRule(fde_start + code_factor, 0x7dedff5f)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + 2 * code_factor, 0x7dedff5f)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreSameValueRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0xadbc9b3a) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, SameValueRule(fde_start, 0xadbc9b3a)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreSameValueRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3d90dcb5) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x3d90dcb5) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, SameValueRule(fde_start, 0x3d90dcb5)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x3d90dcb5)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SameValueRule(fde_start + 2 * code_factor, 0x3d90dcb5)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreOffsetRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_offset | 0x14).ULEB128(0xb6f) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, OffsetRule(fde_start, 0x14, - kCFARegister, 0xb6f * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreOffsetRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xeb7) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x21) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, OffsetRule(fde_start, 0x21, - kCFARegister, 0xeb7 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x21)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21, - kCFARegister, 0xeb7 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreOffsetRuleChangedOffset) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0x134) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xf4f) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, OffsetRule(fde_start, 0x21, - kCFARegister, 0x134 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(fde_start + code_factor, 0x21, - kCFARegister, 0xf4f * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21, - kCFARegister, 0x134 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreValOffsetRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x829caee6).ULEB128(0xe4c) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x829caee6, - kCFARegister, 0xe4c * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreValOffsetRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0xf17c36d6).ULEB128(0xeb7) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xf17c36d6) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValOffsetRule(fde_start, 0xf17c36d6, - kCFARegister, 0xeb7 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xf17c36d6)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0xf17c36d6, - kCFARegister, 0xeb7 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreValOffsetRuleChangedValOffset) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0x562) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0xe88) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x2cf0ab1b, - kCFARegister, 0x562 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, 0x2cf0ab1b, - kCFARegister, 0xe88 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0x2cf0ab1b, - kCFARegister, 0x562 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreRegisterRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x77514acc).ULEB128(0x464de4ce) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0x77514acc, 0x464de4ce)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreRegisterRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe39acce5).ULEB128(0x095f1559) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xe39acce5) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0xe39acce5, 0x095f1559)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xe39acce5)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xe39acce5, - 0x095f1559)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreRegisterRuleChangedRegister) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0x16607d6a) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0xbabb4742) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0xd40e21b1, 0x16607d6a)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(fde_start + code_factor, 0xd40e21b1, - 0xbabb4742)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xd40e21b1, - 0x16607d6a)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreExpressionRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x666ae152).Block("dwarf") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ExpressionRule(fde_start, 0x666ae152, "dwarf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreExpressionRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xb5ca5c46).Block("elf") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ExpressionRule(fde_start, 0xb5ca5c46, "elf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46, - "elf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreExpressionRuleChangedExpression) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("smurf") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("orc") - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ExpressionRule(fde_start, 0x500f5739, "smurf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ExpressionRule(fde_start + code_factor, 0x500f5739, - "orc")) - .InSequence(s).WillOnce(Return(true)); - // Expectations are not wishes. - EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0x500f5739, - "smurf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreValExpressionRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x666ae152) - .Block("hideous") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x666ae152, "hideous")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreValExpressionRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xb5ca5c46) - .Block("revolting") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChanged", section); - - EXPECT_CALL(handler, ValExpressionRule(fde_start, 0xb5ca5c46, "revolting")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46, - "revolting")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreValExpressionRuleChangedValExpression) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739) - .Block("repulsive") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739) - .Block("nauseous") - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChangedValExpression", - section); - - EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x500f5739, "repulsive")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValExpressionRule(fde_start + code_factor, 0x500f5739, - "nauseous")) - .InSequence(s).WillOnce(Return(true)); - // Expectations are not wishes. - EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0x500f5739, - "repulsive")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -struct EHFrameFixture: public CFIInsnFixture { - EHFrameFixture() - : CFIInsnFixture(), section(kBigEndian, 4, true) { - encoded_pointer_bases.cfi = 0x7f496cb2; - encoded_pointer_bases.text = 0x540f67b6; - encoded_pointer_bases.data = 0xe3eab768; - section.SetEncodedPointerBases(encoded_pointer_bases); - } - CFISection section; - CFISection::EncodedPointerBases encoded_pointer_bases; - - // Parse CFIInsnFixture::ParseSection, but parse the section as - // .eh_frame data, supplying stock base addresses. - void ParseEHFrameSection(CFISection *section, bool succeeds = true) { - EXPECT_TRUE(section->ContainsEHFrame()); - string contents; - EXPECT_TRUE(section->GetContents(&contents)); - dwarf2reader::Endianness endianness; - if (section->endianness() == kBigEndian) - endianness = ENDIANNESS_BIG; - else { - assert(section->endianness() == kLittleEndian); - endianness = ENDIANNESS_LITTLE; - } - ByteReader byte_reader(endianness); - byte_reader.SetAddressSize(section->AddressSize()); - byte_reader.SetCFIDataBase(encoded_pointer_bases.cfi, - reinterpret_cast<const uint8_t *>(contents.data())); - byte_reader.SetTextBase(encoded_pointer_bases.text); - byte_reader.SetDataBase(encoded_pointer_bases.data); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter, true); - if (succeeds) - EXPECT_TRUE(parser.Start()); - else - EXPECT_FALSE(parser.Start()); - } - -}; - -class EHFrame: public EHFrameFixture, public Test { }; - -// A simple CIE, an FDE, and a terminator. -TEST_F(EHFrame, Terminator) { - Label cie; - section - .Mark(&cie) - .CIEHeader(9968, 2466, 67, 1, "") - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3772).ULEB128(1372) - .FinishEntry() - .FDEHeader(cie, 0x848037a1, 0x7b30475e) - .D8(dwarf2reader::DW_CFA_set_loc).D32(0x17713850) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(5721) - .FinishEntry() - .D32(0) // Terminate the sequence. - // This FDE should be ignored. - .FDEHeader(cie, 0xf19629fe, 0x439fb09b) - .FinishEntry(); - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.Terminator", section); - - EXPECT_CALL(handler, Entry(_, 0x848037a1, 0x7b30475e, 1, "", 67)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0x848037a1, kCFARegister, 3772, 1372)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(0x17713850, 5721)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(reporter, EarlyEHTerminator(_)) - .InSequence(s).WillOnce(Return()); - - ParseEHFrameSection(§ion); -} - -// The parser should recognize the Linux Standards Base 'z' augmentations. -TEST_F(EHFrame, SimpleFDE) { - DwarfPointerEncoding lsda_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect - | dwarf2reader::DW_EH_PE_datarel - | dwarf2reader::DW_EH_PE_sdata2); - DwarfPointerEncoding fde_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel - | dwarf2reader::DW_EH_PE_udata2); - - section.SetPointerEncoding(fde_encoding); - section.SetEncodedPointerBases(encoded_pointer_bases); - Label cie; - section - .Mark(&cie) - .CIEHeader(4873, 7012, 100, 1, "zSLPR") - .ULEB128(7) // Augmentation data length - .D8(lsda_encoding) // LSDA pointer format - .D8(dwarf2reader::DW_EH_PE_pcrel) // personality pointer format - .EncodedPointer(0x97baa00, dwarf2reader::DW_EH_PE_pcrel) // and value - .D8(fde_encoding) // FDE pointer format - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(6706).ULEB128(31) - .FinishEntry() - .FDEHeader(cie, 0x540f6b56, 0xf686) - .ULEB128(2) // Augmentation data length - .EncodedPointer(0xe3eab475, lsda_encoding) // LSDA pointer, signed - .D8(dwarf2reader::DW_CFA_set_loc) - .EncodedPointer(0x540fa4ce, fde_encoding) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x675e) - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.SimpleFDE", section); - - EXPECT_CALL(handler, Entry(_, 0x540f6b56, 0xf686, 1, "zSLPR", 100)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, PersonalityRoutine(0x97baa00, false)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, LanguageSpecificDataArea(0xe3eab475, true)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SignalHandler()) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0x540f6b56, kCFARegister, 6706, 31)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(0x540fa4ce, 0x675e)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -// Check that we can handle an empty 'z' augmentation. -TEST_F(EHFrame, EmptyZ) { - Label cie; - section - .Mark(&cie) - .CIEHeader(5955, 5805, 228, 1, "z") - .ULEB128(0) // Augmentation data length - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3629).ULEB128(247) - .FinishEntry() - .FDEHeader(cie, 0xda007738, 0xfb55c641) - .ULEB128(0) // Augmentation data length - .D8(dwarf2reader::DW_CFA_advance_loc1).D8(11) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(3769) - .FinishEntry(); - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.EmptyZ", section); - - EXPECT_CALL(handler, Entry(_, 0xda007738, 0xfb55c641, 1, "z", 228)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0xda007738, kCFARegister, 3629, 247)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(0xda007738 + 11 * 5955, 3769)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -// Check that we recognize bad 'z' augmentation characters. -TEST_F(EHFrame, BadZ) { - Label cie; - section - .Mark(&cie) - .CIEHeader(6937, 1045, 142, 1, "zQ") - .ULEB128(0) // Augmentation data length - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(9006).ULEB128(7725) - .FinishEntry() - .FDEHeader(cie, 0x1293efa8, 0x236f53f2) - .ULEB128(0) // Augmentation data length - .D8(dwarf2reader::DW_CFA_advance_loc | 12) - .D8(dwarf2reader::DW_CFA_register).ULEB128(5667).ULEB128(3462) - .FinishEntry(); - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.BadZ", section); - - EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "zQ")) - .WillOnce(Return()); - - ParseEHFrameSection(§ion, false); -} - -TEST_F(EHFrame, zL) { - Label cie; - DwarfPointerEncoding lsda_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel - | dwarf2reader::DW_EH_PE_udata2); - section - .Mark(&cie) - .CIEHeader(9285, 9959, 54, 1, "zL") - .ULEB128(1) // Augmentation data length - .D8(lsda_encoding) // encoding for LSDA pointer in FDE - - .FinishEntry() - .FDEHeader(cie, 0xd40091aa, 0x9aa6e746) - .ULEB128(2) // Augmentation data length - .EncodedPointer(0xd40099cd, lsda_encoding) // LSDA pointer - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zL", section); - - EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zL", 54)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, LanguageSpecificDataArea(0xd40099cd, false)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -TEST_F(EHFrame, zP) { - Label cie; - DwarfPointerEncoding personality_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel - | dwarf2reader::DW_EH_PE_udata2); - section - .Mark(&cie) - .CIEHeader(1097, 6313, 17, 1, "zP") - .ULEB128(3) // Augmentation data length - .D8(personality_encoding) // encoding for personality routine - .EncodedPointer(0xe3eaccac, personality_encoding) // value - .FinishEntry() - .FDEHeader(cie, 0x0c8350c9, 0xbef11087) - .ULEB128(0) // Augmentation data length - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zP", section); - - EXPECT_CALL(handler, Entry(_, 0x0c8350c9, 0xbef11087, 1, "zP", 17)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, PersonalityRoutine(0xe3eaccac, false)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -TEST_F(EHFrame, zR) { - Label cie; - DwarfPointerEncoding pointer_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel - | dwarf2reader::DW_EH_PE_sdata2); - section.SetPointerEncoding(pointer_encoding); - section - .Mark(&cie) - .CIEHeader(8011, 5496, 75, 1, "zR") - .ULEB128(1) // Augmentation data length - .D8(pointer_encoding) // encoding for FDE addresses - .FinishEntry() - .FDEHeader(cie, 0x540f9431, 0xbd0) - .ULEB128(0) // Augmentation data length - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zR", section); - - EXPECT_CALL(handler, Entry(_, 0x540f9431, 0xbd0, 1, "zR", 75)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -TEST_F(EHFrame, zS) { - Label cie; - section - .Mark(&cie) - .CIEHeader(9217, 7694, 57, 1, "zS") - .ULEB128(0) // Augmentation data length - .FinishEntry() - .FDEHeader(cie, 0xd40091aa, 0x9aa6e746) - .ULEB128(0) // Augmentation data length - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zS", section); - - EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zS", 57)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SignalHandler()) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -// These tests require manual inspection of the test output. -struct CFIReporterFixture { - CFIReporterFixture() : reporter("test file name", "test section name") { } - CallFrameInfo::Reporter reporter; -}; - -class CFIReporter: public CFIReporterFixture, public Test { }; - -TEST_F(CFIReporter, Incomplete) { - reporter.Incomplete(0x0102030405060708ULL, CallFrameInfo::kUnknown); -} - -TEST_F(CFIReporter, EarlyEHTerminator) { - reporter.EarlyEHTerminator(0x0102030405060708ULL); -} - -TEST_F(CFIReporter, CIEPointerOutOfRange) { - reporter.CIEPointerOutOfRange(0x0123456789abcdefULL, 0xfedcba9876543210ULL); -} - -TEST_F(CFIReporter, BadCIEId) { - reporter.BadCIEId(0x0123456789abcdefULL, 0xfedcba9876543210ULL); -} - -TEST_F(CFIReporter, UnrecognizedVersion) { - reporter.UnrecognizedVersion(0x0123456789abcdefULL, 43); -} - -TEST_F(CFIReporter, UnrecognizedAugmentation) { - reporter.UnrecognizedAugmentation(0x0123456789abcdefULL, "poodles"); -} - -TEST_F(CFIReporter, InvalidPointerEncoding) { - reporter.InvalidPointerEncoding(0x0123456789abcdefULL, 0x42); -} - -TEST_F(CFIReporter, UnusablePointerEncoding) { - reporter.UnusablePointerEncoding(0x0123456789abcdefULL, 0x42); -} - -TEST_F(CFIReporter, RestoreInCIE) { - reporter.RestoreInCIE(0x0123456789abcdefULL, 0xfedcba9876543210ULL); -} - -TEST_F(CFIReporter, BadInstruction) { - reporter.BadInstruction(0x0123456789abcdefULL, CallFrameInfo::kFDE, - 0xfedcba9876543210ULL); -} - -TEST_F(CFIReporter, NoCFARule) { - reporter.NoCFARule(0x0123456789abcdefULL, CallFrameInfo::kCIE, - 0xfedcba9876543210ULL); -} - -TEST_F(CFIReporter, EmptyStateStack) { - reporter.EmptyStateStack(0x0123456789abcdefULL, CallFrameInfo::kTerminator, - 0xfedcba9876543210ULL); -} - -TEST_F(CFIReporter, ClearingCFARule) { - reporter.ClearingCFARule(0x0123456789abcdefULL, CallFrameInfo::kFDE, - 0xfedcba9876543210ULL); -} - -#ifdef WRITE_ELF -// See comments at the top of the file mentioning WRITE_ELF for details. - -using google_breakpad::test_assembler::Section; - -struct ELFSectionHeader { - ELFSectionHeader(unsigned int set_type) - : type(set_type), flags(0), address(0), link(0), info(0), - alignment(1), entry_size(0) { } - Label name; - unsigned int type; - uint64_t flags; - uint64_t address; - Label file_offset; - Label file_size; - unsigned int link; - unsigned int info; - uint64_t alignment; - uint64_t entry_size; -}; - -void AppendSectionHeader(CFISection *table, const ELFSectionHeader &header) { - (*table) - .D32(header.name) // name, index in string tbl - .D32(header.type) // type - .Address(header.flags) // flags - .Address(header.address) // address in memory - .Address(header.file_offset) // offset in ELF file - .Address(header.file_size) // length in bytes - .D32(header.link) // link to related section - .D32(header.info) // miscellaneous - .Address(header.alignment) // alignment - .Address(header.entry_size); // entry size -} - -void WriteELFFrameSection(const char *filename, const char *cfi_name, - const CFISection &cfi) { - int elf_class = cfi.AddressSize() == 4 ? ELFCLASS32 : ELFCLASS64; - int elf_data = (cfi.endianness() == kBigEndian - ? ELFDATA2MSB : ELFDATA2LSB); - CFISection elf(cfi.endianness(), cfi.AddressSize()); - Label elf_header_size, section_table_offset; - elf - .Append("\x7f" "ELF") - .D8(elf_class) // 32-bit or 64-bit ELF - .D8(elf_data) // endianness - .D8(1) // ELF version - .D8(ELFOSABI_LINUX) // Operating System/ABI indication - .D8(0) // ABI version - .Append(7, 0xda) // padding - .D16(ET_EXEC) // file type: executable file - .D16(EM_386) // architecture: Intel IA-32 - .D32(EV_CURRENT); // ELF version - elf - .Address(0x0123456789abcdefULL) // program entry point - .Address(0) // program header offset - .Address(section_table_offset) // section header offset - .D32(0) // processor-specific flags - .D16(elf_header_size) // ELF header size in bytes */ - .D16(elf_class == ELFCLASS32 ? 32 : 56) // program header entry size - .D16(0) // program header table entry count - .D16(elf_class == ELFCLASS32 ? 40 : 64) // section header entry size - .D16(3) // section count - .D16(1) // section name string table - .Mark(&elf_header_size); - - // The null section. Every ELF file has one, as the first entry in - // the section header table. - ELFSectionHeader null_header(SHT_NULL); - null_header.file_offset = 0; - null_header.file_size = 0; - - // The CFI section. The whole reason for writing out this ELF file - // is to put this in it so that we can run other dumping programs on - // it to check its contents. - ELFSectionHeader cfi_header(SHT_PROGBITS); - cfi_header.file_size = cfi.Size(); - - // The section holding the names of the sections. This is the - // section whose index appears in the e_shstrndx member of the ELF - // header. - ELFSectionHeader section_names_header(SHT_STRTAB); - CFISection section_names(cfi.endianness(), cfi.AddressSize()); - section_names - .Mark(&null_header.name) - .AppendCString("") - .Mark(§ion_names_header.name) - .AppendCString(".shstrtab") - .Mark(&cfi_header.name) - .AppendCString(cfi_name) - .Mark(§ion_names_header.file_size); - - // Create the section table. The ELF header's e_shoff member refers - // to this, and the e_shnum member gives the number of entries it - // contains. - CFISection section_table(cfi.endianness(), cfi.AddressSize()); - AppendSectionHeader(§ion_table, null_header); - AppendSectionHeader(§ion_table, section_names_header); - AppendSectionHeader(§ion_table, cfi_header); - - // Append the section table and the section contents to the ELF file. - elf - .Mark(§ion_table_offset) - .Append(section_table) - .Mark(§ion_names_header.file_offset) - .Append(section_names) - .Mark(&cfi_header.file_offset) - .Append(cfi); - - string contents; - if (!elf.GetContents(&contents)) { - fprintf(stderr, "failed to get ELF file contents\n"); - exit(1); - } - - FILE *out = fopen(filename, "w"); - if (!out) { - fprintf(stderr, "error opening ELF file '%s': %s\n", - filename, strerror(errno)); - exit(1); - } - - if (fwrite(contents.data(), 1, contents.size(), out) != contents.size()) { - fprintf(stderr, "error writing ELF data to '%s': %s\n", - filename, strerror(errno)); - exit(1); - } - - if (fclose(out) == EOF) { - fprintf(stderr, "error closing ELF file '%s': %s\n", - filename, strerror(errno)); - exit(1); - } -} -#endif diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc deleted file mode 100644 index 71418eb8d..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc +++ /dev/null @@ -1,487 +0,0 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit - -#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 dwarf2reader::ByteReader; -using dwarf2reader::CompilationUnit; -using dwarf2reader::Dwarf2Handler; -using dwarf2reader::DwarfAttribute; -using dwarf2reader::DwarfForm; -using dwarf2reader::DwarfHasChild; -using dwarf2reader::DwarfTag; -using dwarf2reader::ENDIANNESS_BIG; -using dwarf2reader::ENDIANNESS_LITTLE; -using dwarf2reader::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 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 dwarf_version)); - MOCK_METHOD2(StartDIE, bool(uint64 offset, enum DwarfTag tag)); - MOCK_METHOD4(ProcessAttributeUnsigned, void(uint64 offset, - DwarfAttribute attr, - enum DwarfForm form, - uint64 data)); - MOCK_METHOD4(ProcessAttributeSigned, void(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - int64 data)); - MOCK_METHOD4(ProcessAttributeReference, void(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data)); - MOCK_METHOD5(ProcessAttributeBuffer, void(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const uint8_t *data, - uint64 len)); - MOCK_METHOD4(ProcessAttributeString, void(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const string& data)); - MOCK_METHOD4(ProcessAttributeSignature, void(uint64 offset, - DwarfAttribute attr, - enum DwarfForm form, - uint64 signature)); - MOCK_METHOD1(EndDIE, void(uint64 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) - : endianness(endianness), format_size(format_size), - version(version), address_size(address_size) { } - Endianness endianness; - size_t format_size; // 4-byte or 8-byte DWARF offsets - int version; - size_t address_size; -}; - -class DwarfHeader: public DIEFixture, - public TestWithParam<DwarfHeaderParams> { }; - -TEST_P(DwarfHeader, Header) { - Label abbrev_table = abbrevs.Here(); - abbrevs.Abbrev(1, dwarf2reader::DW_TAG_compile_unit, - dwarf2reader::DW_children_yes) - .Attribute(dwarf2reader::DW_AT_name, dwarf2reader::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) - .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(_, dwarf2reader::DW_TAG_compile_unit)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name, - dwarf2reader::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()); -} - -INSTANTIATE_TEST_CASE_P( - HeaderVariants, DwarfHeader, - ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4), - DwarfHeaderParams(kLittleEndian, 4, 2, 8), - DwarfHeaderParams(kLittleEndian, 4, 3, 4), - DwarfHeaderParams(kLittleEndian, 4, 3, 8), - DwarfHeaderParams(kLittleEndian, 4, 4, 4), - DwarfHeaderParams(kLittleEndian, 4, 4, 8), - DwarfHeaderParams(kLittleEndian, 8, 2, 4), - DwarfHeaderParams(kLittleEndian, 8, 2, 8), - DwarfHeaderParams(kLittleEndian, 8, 3, 4), - DwarfHeaderParams(kLittleEndian, 8, 3, 8), - DwarfHeaderParams(kLittleEndian, 8, 4, 4), - DwarfHeaderParams(kLittleEndian, 8, 4, 8), - DwarfHeaderParams(kBigEndian, 4, 2, 4), - DwarfHeaderParams(kBigEndian, 4, 2, 8), - DwarfHeaderParams(kBigEndian, 4, 3, 4), - DwarfHeaderParams(kBigEndian, 4, 3, 8), - DwarfHeaderParams(kBigEndian, 4, 4, 4), - DwarfHeaderParams(kBigEndian, 4, 4, 8), - DwarfHeaderParams(kBigEndian, 8, 2, 4), - DwarfHeaderParams(kBigEndian, 8, 2, 8), - DwarfHeaderParams(kBigEndian, 8, 3, 4), - DwarfHeaderParams(kBigEndian, 8, 3, 8), - DwarfHeaderParams(kBigEndian, 8, 4, 4), - DwarfHeaderParams(kBigEndian, 8, 4, 8))); - -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 ¶ms, - DwarfTag tag, DwarfAttribute name, - DwarfForm form) { - // Create the abbreviation table. - Label abbrev_table = abbrevs.Here(); - abbrevs.Abbrev(1, tag, dwarf2reader::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) - .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 ¶ms, - DwarfTag tag, uint64 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 ¶ms, uint64 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(), dwarf2reader::DW_TAG_compile_unit, - dwarf2reader::DW_AT_low_pc, - dwarf2reader::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(), dwarf2reader::DW_TAG_compile_unit); - EXPECT_CALL(handler, ProcessAttributeUnsigned(_, dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, - value)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam()); -} - -TEST_P(DwarfForms, block2_empty) { - StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7, - (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2); - info.D16(0); - info.Finish(); - - ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7); - EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2, - _, 0)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam()); -} - -TEST_P(DwarfForms, block2) { - StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7, - (DwarfAttribute) 0xe52c4463, - dwarf2reader::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, - dwarf2reader::DW_FORM_block2, - Pointee('*'), 258)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam()); -} - -TEST_P(DwarfForms, flag_present) { - StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2, - (DwarfAttribute) 0x359d1972, - dwarf2reader::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, - dwarf2reader::DW_FORM_flag_present, - 1)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam()); -} - -TEST_P(DwarfForms, sec_offset) { - StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689, - (DwarfAttribute) 0xa060bfd1, - dwarf2reader::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, - dwarf2reader::DW_FORM_sec_offset, - value)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam()); -} - -TEST_P(DwarfForms, exprloc) { - StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb, - (DwarfAttribute) 0xba3ae5cb, - dwarf2reader::DW_FORM_exprloc); - info.ULEB128(29) - .Append(29, 173); - info.Finish(); - - ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb); - EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb, - dwarf2reader::DW_FORM_exprloc, - Pointee(173), 29)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam()); -} - -TEST_P(DwarfForms, ref_sig8) { - StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b, - (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8); - info.D64(0xf72fa0cb6ddcf9d6ULL); - info.Finish(); - - ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b); - EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908, - dwarf2reader::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, - dwarf2reader::DW_FORM_ref_sig8); - info.D64(0xf72fa0cb6ddcf9d6ULL); - info.Finish(); - - ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98); - EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8, - 0xf72fa0cb6ddcf9d6ULL)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam(), 98); -} - -// Tests for the other attribute forms could go here. - -INSTANTIATE_TEST_CASE_P( - HeaderVariants, DwarfForms, - ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4), - DwarfHeaderParams(kLittleEndian, 4, 2, 8), - DwarfHeaderParams(kLittleEndian, 4, 3, 4), - DwarfHeaderParams(kLittleEndian, 4, 3, 8), - DwarfHeaderParams(kLittleEndian, 4, 4, 4), - DwarfHeaderParams(kLittleEndian, 4, 4, 8), - DwarfHeaderParams(kLittleEndian, 8, 2, 4), - DwarfHeaderParams(kLittleEndian, 8, 2, 8), - DwarfHeaderParams(kLittleEndian, 8, 3, 4), - DwarfHeaderParams(kLittleEndian, 8, 3, 8), - DwarfHeaderParams(kLittleEndian, 8, 4, 4), - DwarfHeaderParams(kLittleEndian, 8, 4, 8), - DwarfHeaderParams(kBigEndian, 4, 2, 4), - DwarfHeaderParams(kBigEndian, 4, 2, 8), - DwarfHeaderParams(kBigEndian, 4, 3, 4), - DwarfHeaderParams(kBigEndian, 4, 3, 8), - DwarfHeaderParams(kBigEndian, 4, 4, 4), - DwarfHeaderParams(kBigEndian, 4, 4, 8), - DwarfHeaderParams(kBigEndian, 8, 2, 4), - DwarfHeaderParams(kBigEndian, 8, 2, 8), - DwarfHeaderParams(kBigEndian, 8, 3, 4), - DwarfHeaderParams(kBigEndian, 8, 3, 8), - DwarfHeaderParams(kBigEndian, 8, 4, 4), - DwarfHeaderParams(kBigEndian, 8, 4, 8))); diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_test_common.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_test_common.h deleted file mode 100644 index e91de9061..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_test_common.h +++ /dev/null @@ -1,149 +0,0 @@ -// -*- mode: c++ -*- - -// Copyright (c) 2012, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// 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 dwarf2reader::DwarfTag DwarfTag; - typedef dwarf2reader::DwarfAttribute DwarfAttribute; - typedef dwarf2reader::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) { - if (format_size_ == 4) { - D32(length_); - } else { - D32(0xffffffff); - D64(length_); - } - post_length_offset_ = Size(); - D16(version); - SectionOffset(abbrev_offset); - D8(address_size); - 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 dwarf2reader::DwarfTag DwarfTag; - typedef dwarf2reader::DwarfAttribute DwarfAttribute; - typedef dwarf2reader::DwarfForm DwarfForm; - typedef dwarf2reader::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__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.cc deleted file mode 100644 index 4135a51a9..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.cc +++ /dev/null @@ -1,1273 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// Author: chatham@google.com (Andrew Chatham) -// Author: satorux@google.com (Satoru Takabayashi) -// -// Code for reading in ELF files. -// -// For information on the ELF format, see -// http://www.x86.org/ftp/manuals/tools/elf.pdf -// -// I also liked: -// http://www.caldera.com/developers/gabi/1998-04-29/contents.html -// -// A note about types: When dealing with the file format, we use types -// like Elf32_Word, but in the public interfaces we treat all -// addresses as uint64. As a result, we should be able to symbolize -// 64-bit binaries from a 32-bit process (which we don't do, -// anyway). size_t should therefore be avoided, except where required -// by things like mmap(). -// -// Although most of this code can deal with arbitrary ELF files of -// either word size, the public ElfReader interface only examines -// files loaded into the current address space, which must all match -// __WORDSIZE. This code cannot handle ELF files with a non-native -// byte ordering. -// -// TODO(chatham): It would be nice if we could accomplish this task -// without using malloc(), so we could use it as the process is dying. - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE // needed for pread() -#endif - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> - -#include <algorithm> -#include <map> -#include <string> -#include <vector> -// TODO(saugustine): Add support for compressed debug. -// Also need to add configure tests for zlib. -//#include "zlib.h" - -#include "third_party/musl/include/elf.h" -#include "elf_reader.h" -#include "common/using_std_string.h" - -// EM_AARCH64 is not defined by elf.h of GRTE v3 on x86. -// TODO(dougkwan): Remove this when v17 is retired. -#if !defined(EM_AARCH64) -#define EM_AARCH64 183 /* ARM AARCH64 */ -#endif - -// Map Linux macros to their Apple equivalents. -#if __APPLE__ -#ifndef __LITTLE_ENDIAN -#define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ -#endif // __LITTLE_ENDIAN -#ifndef __BIG_ENDIAN -#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ -#endif // __BIG_ENDIAN -#ifndef __BYTE_ORDER -#define __BYTE_ORDER __BYTE_ORDER__ -#endif // __BYTE_ORDER -#endif // __APPLE__ - -// TODO(dthomson): Can be removed once all Java code is using the Google3 -// launcher. We need to avoid processing PLT functions as it causes memory -// fragmentation in malloc, which is fixed in tcmalloc - and if the Google3 -// launcher is used the JVM will then use tcmalloc. b/13735638 -//DEFINE_bool(elfreader_process_dynsyms, true, -// "Activate PLT function processing"); - -using std::vector; - -namespace { - -// The lowest bit of an ARM symbol value is used to indicate a Thumb address. -const int kARMThumbBitOffset = 0; - -// Converts an ARM Thumb symbol value to a true aligned address value. -template <typename T> -T AdjustARMThumbSymbolValue(const T& symbol_table_value) { - return symbol_table_value & ~(1 << kARMThumbBitOffset); -} - -// Names of PLT-related sections. -const char kElfPLTRelSectionName[] = ".rel.plt"; // Use Rel struct. -const char kElfPLTRelaSectionName[] = ".rela.plt"; // Use Rela struct. -const char kElfPLTSectionName[] = ".plt"; -const char kElfDynSymSectionName[] = ".dynsym"; - -const int kX86PLTCodeSize = 0x10; // Size of one x86 PLT function in bytes. -const int kARMPLTCodeSize = 0xc; -const int kAARCH64PLTCodeSize = 0x10; - -const int kX86PLT0Size = 0x10; // Size of the special PLT0 entry. -const int kARMPLT0Size = 0x14; -const int kAARCH64PLT0Size = 0x20; - -// Suffix for PLT functions when it needs to be explicitly identified as such. -const char kPLTFunctionSuffix[] = "@plt"; - -} // namespace - -namespace dwarf2reader { - -template <class ElfArch> class ElfReaderImpl; - -// 32-bit and 64-bit ELF files are processed exactly the same, except -// for various field sizes. Elf32 and Elf64 encompass all of the -// differences between the two formats, and all format-specific code -// in this file is templated on one of them. -class Elf32 { - public: - typedef Elf32_Ehdr Ehdr; - typedef Elf32_Shdr Shdr; - typedef Elf32_Phdr Phdr; - typedef Elf32_Word Word; - typedef Elf32_Sym Sym; - typedef Elf32_Rel Rel; - typedef Elf32_Rela Rela; - - // What should be in the EI_CLASS header. - static const int kElfClass = ELFCLASS32; - - // Given a symbol pointer, return the binding type (eg STB_WEAK). - static char Bind(const Elf32_Sym *sym) { - return ELF32_ST_BIND(sym->st_info); - } - // Given a symbol pointer, return the symbol type (eg STT_FUNC). - static char Type(const Elf32_Sym *sym) { - return ELF32_ST_TYPE(sym->st_info); - } - - // Extract the symbol index from the r_info field of a relocation. - static int r_sym(const Elf32_Word r_info) { - return ELF32_R_SYM(r_info); - } -}; - - -class Elf64 { - public: - typedef Elf64_Ehdr Ehdr; - typedef Elf64_Shdr Shdr; - typedef Elf64_Phdr Phdr; - typedef Elf64_Word Word; - typedef Elf64_Sym Sym; - typedef Elf64_Rel Rel; - typedef Elf64_Rela Rela; - - // What should be in the EI_CLASS header. - static const int kElfClass = ELFCLASS64; - - static char Bind(const Elf64_Sym *sym) { - return ELF64_ST_BIND(sym->st_info); - } - static char Type(const Elf64_Sym *sym) { - return ELF64_ST_TYPE(sym->st_info); - } - static int r_sym(const Elf64_Xword r_info) { - return ELF64_R_SYM(r_info); - } -}; - - -// ElfSectionReader mmaps a section of an ELF file ("section" is ELF -// terminology). The ElfReaderImpl object providing the section header -// must exist for the lifetime of this object. -// -// The motivation for mmaping individual sections of the file is that -// many Google executables are large enough when unstripped that we -// have to worry about running out of virtual address space. -// -// For compressed sections we have no choice but to allocate memory. -template<class ElfArch> -class ElfSectionReader { - public: - ElfSectionReader(const char *name, const string &path, int fd, - const typename ElfArch::Shdr §ion_header) - : contents_aligned_(NULL), - contents_(NULL), - header_(section_header) { - // Back up to the beginning of the page we're interested in. - const size_t additional = header_.sh_offset % getpagesize(); - const size_t offset_aligned = header_.sh_offset - additional; - section_size_ = header_.sh_size; - size_aligned_ = section_size_ + additional; - // If the section has been stripped or is empty, do not attempt - // to process its contents. - if (header_.sh_type == SHT_NOBITS || header_.sh_size == 0) - return; - contents_aligned_ = mmap(NULL, size_aligned_, PROT_READ, MAP_SHARED, - fd, offset_aligned); - // Set where the offset really should begin. - contents_ = reinterpret_cast<char *>(contents_aligned_) + - (header_.sh_offset - offset_aligned); - - // Check for and handle any compressed contents. - //if (strncmp(name, ".zdebug_", strlen(".zdebug_")) == 0) - // DecompressZlibContents(); - // TODO(saugustine): Add support for proposed elf-section flag - // "SHF_COMPRESS". - } - - ~ElfSectionReader() { - if (contents_aligned_ != NULL) - munmap(contents_aligned_, size_aligned_); - else - delete[] contents_; - } - - // Return the section header for this section. - typename ElfArch::Shdr const &header() const { return header_; } - - // Return memory at the given offset within this section. - const char *GetOffset(typename ElfArch::Word bytes) const { - return contents_ + bytes; - } - - const char *contents() const { return contents_; } - size_t section_size() const { return section_size_; } - - private: - // page-aligned file contents - void *contents_aligned_; - // contents as usable by the client. For non-compressed sections, - // pointer within contents_aligned_ to where the section data - // begins; for compressed sections, pointer to the decompressed - // data. - char *contents_; - // size of contents_aligned_ - size_t size_aligned_; - // size of contents. - size_t section_size_; - const typename ElfArch::Shdr header_; -}; - -// An iterator over symbols in a given section. It handles walking -// through the entries in the specified section and mapping symbol -// entries to their names in the appropriate string table (in -// another section). -template<class ElfArch> -class SymbolIterator { - public: - SymbolIterator(ElfReaderImpl<ElfArch> *reader, - typename ElfArch::Word section_type) - : symbol_section_(reader->GetSectionByType(section_type)), - string_section_(NULL), - num_symbols_in_section_(0), - symbol_within_section_(0) { - - // If this section type doesn't exist, leave - // num_symbols_in_section_ as zero, so this iterator is already - // done(). - if (symbol_section_ != NULL) { - num_symbols_in_section_ = symbol_section_->header().sh_size / - symbol_section_->header().sh_entsize; - - // Symbol sections have sh_link set to the section number of - // the string section containing the symbol names. - string_section_ = reader->GetSection(symbol_section_->header().sh_link); - } - } - - // Return true iff we have passed all symbols in this section. - bool done() const { - return symbol_within_section_ >= num_symbols_in_section_; - } - - // Advance to the next symbol in this section. - // REQUIRES: !done() - void Next() { ++symbol_within_section_; } - - // Return a pointer to the current symbol. - // REQUIRES: !done() - const typename ElfArch::Sym *GetSymbol() const { - return reinterpret_cast<const typename ElfArch::Sym*>( - symbol_section_->GetOffset(symbol_within_section_ * - symbol_section_->header().sh_entsize)); - } - - // Return the name of the current symbol, NULL if it has none. - // REQUIRES: !done() - const char *GetSymbolName() const { - int name_offset = GetSymbol()->st_name; - if (name_offset == 0) - return NULL; - return string_section_->GetOffset(name_offset); - } - - int GetCurrentSymbolIndex() const { - return symbol_within_section_; - } - - private: - const ElfSectionReader<ElfArch> *const symbol_section_; - const ElfSectionReader<ElfArch> *string_section_; - int num_symbols_in_section_; - int symbol_within_section_; -}; - - -// Copied from strings/strutil.h. Per chatham, -// this library should not depend on strings. - -static inline bool MyHasSuffixString(const string& str, const string& suffix) { - int len = str.length(); - int suflen = suffix.length(); - return (suflen <= len) && (str.compare(len-suflen, suflen, suffix) == 0); -} - - -// ElfReader loads an ELF binary and can provide information about its -// contents. It is most useful for matching addresses to function -// names. It does not understand debugging formats (eg dwarf2), so it -// can't print line numbers. It takes a path to an elf file and a -// readable file descriptor for that file, which it does not assume -// ownership of. -template<class ElfArch> -class ElfReaderImpl { - public: - explicit ElfReaderImpl(const string &path, int fd) - : path_(path), - fd_(fd), - section_headers_(NULL), - program_headers_(NULL), - opd_section_(NULL), - base_for_text_(0), - plts_supported_(false), - plt_code_size_(0), - plt0_size_(0), - visited_relocation_entries_(false) { - string error; - is_dwp_ = MyHasSuffixString(path, ".dwp"); - ParseHeaders(fd, path); - // Currently we need some extra information for PowerPC64 binaries - // including a way to read the .opd section for function descriptors and a - // way to find the linked base for function symbols. - if (header_.e_machine == EM_PPC64) { - // "opd_section_" must always be checked for NULL before use. - opd_section_ = GetSectionInfoByName(".opd", &opd_info_); - for (unsigned int k = 0u; k < GetNumSections(); ++k) { - const char *name = GetSectionName(section_headers_[k].sh_name); - if (strncmp(name, ".text", strlen(".text")) == 0) { - base_for_text_ = - section_headers_[k].sh_addr - section_headers_[k].sh_offset; - break; - } - } - } - // Turn on PLTs. - if (header_.e_machine == EM_386 || header_.e_machine == EM_X86_64) { - plt_code_size_ = kX86PLTCodeSize; - plt0_size_ = kX86PLT0Size; - plts_supported_ = true; - } else if (header_.e_machine == EM_ARM) { - plt_code_size_ = kARMPLTCodeSize; - plt0_size_ = kARMPLT0Size; - plts_supported_ = true; - } else if (header_.e_machine == EM_AARCH64) { - plt_code_size_ = kAARCH64PLTCodeSize; - plt0_size_ = kAARCH64PLT0Size; - plts_supported_ = true; - } - } - - ~ElfReaderImpl() { - for (unsigned int i = 0u; i < sections_.size(); ++i) - delete sections_[i]; - delete [] section_headers_; - delete [] program_headers_; - } - - // Examine the headers of the file and return whether the file looks - // like an ELF file for this architecture. Takes an already-open - // file descriptor for the candidate file, reading in the prologue - // to see if the ELF file appears to match the current - // architecture. If error is non-NULL, it will be set with a reason - // in case of failure. - static bool IsArchElfFile(int fd, string *error) { - unsigned char header[EI_NIDENT]; - if (pread(fd, header, sizeof(header), 0) != sizeof(header)) { - if (error != NULL) *error = "Could not read header"; - return false; - } - - if (memcmp(header, ELFMAG, SELFMAG) != 0) { - if (error != NULL) *error = "Missing ELF magic"; - return false; - } - - if (header[EI_CLASS] != ElfArch::kElfClass) { - if (error != NULL) *error = "Different word size"; - return false; - } - - int endian = 0; - if (header[EI_DATA] == ELFDATA2LSB) - endian = __LITTLE_ENDIAN; - else if (header[EI_DATA] == ELFDATA2MSB) - endian = __BIG_ENDIAN; - if (endian != __BYTE_ORDER) { - if (error != NULL) *error = "Different byte order"; - return false; - } - - return true; - } - - // Return true if we can use this symbol in Address-to-Symbol map. - bool CanUseSymbol(const char *name, const typename ElfArch::Sym *sym) { - // For now we only save FUNC and NOTYPE symbols. For now we just - // care about functions, but some functions written in assembler - // don't have a proper ELF type attached to them, so we store - // NOTYPE symbols as well. The remaining significant type is - // OBJECT (eg global variables), which represent about 25% of - // the symbols in a typical google3 binary. - if (ElfArch::Type(sym) != STT_FUNC && - ElfArch::Type(sym) != STT_NOTYPE) { - return false; - } - - // Target specific filtering. - switch (header_.e_machine) { - case EM_AARCH64: - case EM_ARM: - // Filter out '$x' special local symbols used by tools - return name[0] != '$' || ElfArch::Bind(sym) != STB_LOCAL; - case EM_X86_64: - // Filter out read-only constants like .LC123. - return name[0] != '.' || ElfArch::Bind(sym) != STB_LOCAL; - default: - return true; - } - } - - // Iterate over the symbols in a section, either SHT_DYNSYM or - // SHT_SYMTAB. Add all symbols to the given SymbolMap. - /* - void GetSymbolPositions(SymbolMap *symbols, - typename ElfArch::Word section_type, - uint64 mem_offset, - uint64 file_offset) { - // This map is used to filter out "nested" functions. - // See comment below. - AddrToSymMap addr_to_sym_map; - for (SymbolIterator<ElfArch> it(this, section_type); - !it.done(); it.Next()) { - const char *name = it.GetSymbolName(); - if (name == NULL) - continue; - const typename ElfArch::Sym *sym = it.GetSymbol(); - if (CanUseSymbol(name, sym)) { - const int sec = sym->st_shndx; - - // We don't support special section indices. The most common - // is SHN_ABS, for absolute symbols used deep in the bowels of - // glibc. Also ignore any undefined symbols. - if (sec == SHN_UNDEF || - (sec >= SHN_LORESERVE && sec <= SHN_HIRESERVE)) { - continue; - } - - const typename ElfArch::Shdr& hdr = section_headers_[sec]; - - // Adjust for difference between where we expected to mmap - // this section, and where it was actually mmapped. - const int64 expected_base = hdr.sh_addr - hdr.sh_offset; - const int64 real_base = mem_offset - file_offset; - const int64 adjust = real_base - expected_base; - - uint64 start = sym->st_value + adjust; - - // Adjust function symbols for PowerPC64 by dereferencing and adjusting - // the function descriptor to get the function address. - if (header_.e_machine == EM_PPC64 && ElfArch::Type(sym) == STT_FUNC) { - const uint64 opd_addr = - AdjustPPC64FunctionDescriptorSymbolValue(sym->st_value); - // Only adjust the returned value if the function address was found. - if (opd_addr != sym->st_value) { - const int64 adjust_function_symbols = - real_base - base_for_text_; - start = opd_addr + adjust_function_symbols; - } - } - - addr_to_sym_map.push_back(std::make_pair(start, sym)); - } - } - std::sort(addr_to_sym_map.begin(), addr_to_sym_map.end(), &AddrToSymSorter); - addr_to_sym_map.erase(std::unique(addr_to_sym_map.begin(), - addr_to_sym_map.end(), &AddrToSymEquals), - addr_to_sym_map.end()); - - // Squeeze out any "nested functions". - // Nested functions are not allowed in C, but libc plays tricks. - // - // For example, here is disassembly of /lib64/tls/libc-2.3.5.so: - // 0x00000000000aa380 <read+0>: cmpl $0x0,0x2781b9(%rip) - // 0x00000000000aa387 <read+7>: jne 0xaa39b <read+27> - // 0x00000000000aa389 <__read_nocancel+0>: mov $0x0,%rax - // 0x00000000000aa390 <__read_nocancel+7>: syscall - // 0x00000000000aa392 <__read_nocancel+9>: cmp $0xfffffffffffff001,%rax - // 0x00000000000aa398 <__read_nocancel+15>: jae 0xaa3ef <read+111> - // 0x00000000000aa39a <__read_nocancel+17>: retq - // 0x00000000000aa39b <read+27>: sub $0x28,%rsp - // 0x00000000000aa39f <read+31>: mov %rdi,0x8(%rsp) - // ... - // Without removing __read_nocancel, symbolizer will return NULL - // given e.g. 0xaa39f (because the lower bound is __read_nocancel, - // but 0xaa39f is beyond its end. - if (addr_to_sym_map.empty()) { - return; - } - const ElfSectionReader<ElfArch> *const symbol_section = - this->GetSectionByType(section_type); - const ElfSectionReader<ElfArch> *const string_section = - this->GetSection(symbol_section->header().sh_link); - - typename AddrToSymMap::iterator curr = addr_to_sym_map.begin(); - // Always insert the first symbol. - symbols->AddSymbol(string_section->GetOffset(curr->second->st_name), - curr->first, curr->second->st_size); - typename AddrToSymMap::iterator prev = curr++; - for (; curr != addr_to_sym_map.end(); ++curr) { - const uint64 prev_addr = prev->first; - const uint64 curr_addr = curr->first; - const typename ElfArch::Sym *const prev_sym = prev->second; - const typename ElfArch::Sym *const curr_sym = curr->second; - if (prev_addr + prev_sym->st_size <= curr_addr || - // The next condition is true if two symbols overlap like this: - // - // Previous symbol |----------------------------| - // Current symbol |-------------------------------| - // - // These symbols are not found in google3 codebase, but in - // jdk1.6.0_01_gg1/jre/lib/i386/server/libjvm.so. - // - // 0619e040 00000046 t CardTableModRefBS::write_region_work() - // 0619e070 00000046 t CardTableModRefBS::write_ref_array_work() - // - // We allow overlapped symbols rather than ignore these. - // Due to the way SymbolMap::GetSymbolAtPosition() works, - // lookup for any address in [curr_addr, curr_addr + its size) - // (e.g. 0619e071) will produce the current symbol, - // which is the desired outcome. - prev_addr + prev_sym->st_size < curr_addr + curr_sym->st_size) { - const char *name = string_section->GetOffset(curr_sym->st_name); - symbols->AddSymbol(name, curr_addr, curr_sym->st_size); - prev = curr; - } else { - // Current symbol is "nested" inside previous one like this: - // - // Previous symbol |----------------------------| - // Current symbol |---------------------| - // - // This happens within glibc, e.g. __read_nocancel is nested - // "inside" __read. Ignore "inner" symbol. - //DCHECK_LE(curr_addr + curr_sym->st_size, - // prev_addr + prev_sym->st_size); - ; - } - } - } -*/ - - void VisitSymbols(typename ElfArch::Word section_type, - ElfReader::SymbolSink *sink) { - VisitSymbols(section_type, sink, -1, -1, false); - } - - void VisitSymbols(typename ElfArch::Word section_type, - ElfReader::SymbolSink *sink, - int symbol_binding, - int symbol_type, - bool get_raw_symbol_values) { - for (SymbolIterator<ElfArch> it(this, section_type); - !it.done(); it.Next()) { - const char *name = it.GetSymbolName(); - if (!name) continue; - const typename ElfArch::Sym *sym = it.GetSymbol(); - if ((symbol_binding < 0 || ElfArch::Bind(sym) == symbol_binding) && - (symbol_type < 0 || ElfArch::Type(sym) == symbol_type)) { - typename ElfArch::Sym symbol = *sym; - // Add a PLT symbol in addition to the main undefined symbol. - // Only do this for SHT_DYNSYM, because PLT symbols are dynamic. - int symbol_index = it.GetCurrentSymbolIndex(); - // TODO(dthomson): Can be removed once all Java code is using the - // Google3 launcher. - if (section_type == SHT_DYNSYM && - static_cast<unsigned int>(symbol_index) < symbols_plt_offsets_.size() && - symbols_plt_offsets_[symbol_index] != 0) { - string plt_name = string(name) + kPLTFunctionSuffix; - if (plt_function_names_[symbol_index].empty()) { - plt_function_names_[symbol_index] = plt_name; - } else if (plt_function_names_[symbol_index] != plt_name) { - ; - } - sink->AddSymbol(plt_function_names_[symbol_index].c_str(), - symbols_plt_offsets_[it.GetCurrentSymbolIndex()], - plt_code_size_); - } - if (!get_raw_symbol_values) - AdjustSymbolValue(&symbol); - sink->AddSymbol(name, symbol.st_value, symbol.st_size); - } - } - } - - void VisitRelocationEntries() { - if (visited_relocation_entries_) { - return; - } - visited_relocation_entries_ = true; - - if (!plts_supported_) { - return; - } - // First determine if PLTs exist. If not, then there is nothing to do. - ElfReader::SectionInfo plt_section_info; - const char* plt_section = - GetSectionInfoByName(kElfPLTSectionName, &plt_section_info); - if (!plt_section) { - return; - } - if (plt_section_info.size == 0) { - return; - } - - // The PLTs could be referenced by either a Rel or Rela (Rel with Addend) - // section. - ElfReader::SectionInfo rel_section_info; - ElfReader::SectionInfo rela_section_info; - const char* rel_section = - GetSectionInfoByName(kElfPLTRelSectionName, &rel_section_info); - const char* rela_section = - GetSectionInfoByName(kElfPLTRelaSectionName, &rela_section_info); - - const typename ElfArch::Rel* rel = - reinterpret_cast<const typename ElfArch::Rel*>(rel_section); - const typename ElfArch::Rela* rela = - reinterpret_cast<const typename ElfArch::Rela*>(rela_section); - - if (!rel_section && !rela_section) { - return; - } - - // Use either Rel or Rela section, depending on which one exists. - size_t section_size = rel_section ? rel_section_info.size - : rela_section_info.size; - size_t entry_size = rel_section ? sizeof(typename ElfArch::Rel) - : sizeof(typename ElfArch::Rela); - - // Determine the number of entries in the dynamic symbol table. - ElfReader::SectionInfo dynsym_section_info; - const char* dynsym_section = - GetSectionInfoByName(kElfDynSymSectionName, &dynsym_section_info); - // The dynsym section might not exist, or it might be empty. In either case - // there is nothing to be done so return. - if (!dynsym_section || dynsym_section_info.size == 0) { - return; - } - size_t num_dynamic_symbols = - dynsym_section_info.size / dynsym_section_info.entsize; - symbols_plt_offsets_.resize(num_dynamic_symbols, 0); - - // TODO(dthomson): Can be removed once all Java code is using the - // Google3 launcher. - // Make storage room for PLT function name strings. - plt_function_names_.resize(num_dynamic_symbols); - - for (size_t i = 0; i < section_size / entry_size; ++i) { - // Determine symbol index from the |r_info| field. - int sym_index = ElfArch::r_sym(rel_section ? rel[i].r_info - : rela[i].r_info); - if (static_cast<unsigned int>(sym_index) >= symbols_plt_offsets_.size()) { - continue; - } - symbols_plt_offsets_[sym_index] = - plt_section_info.addr + plt0_size_ + i * plt_code_size_; - } - } - - // Return an ElfSectionReader for the first section of the given - // type by iterating through all section headers. Returns NULL if - // the section type is not found. - const ElfSectionReader<ElfArch> *GetSectionByType( - typename ElfArch::Word section_type) { - for (unsigned int k = 0u; k < GetNumSections(); ++k) { - if (section_headers_[k].sh_type == section_type) { - return GetSection(k); - } - } - return NULL; - } - - // Return the name of section "shndx". Returns NULL if the section - // is not found. - const char *GetSectionNameByIndex(int shndx) { - return GetSectionName(section_headers_[shndx].sh_name); - } - - // Return a pointer to section "shndx", and store the size in - // "size". Returns NULL if the section is not found. - const char *GetSectionContentsByIndex(int shndx, size_t *size) { - const ElfSectionReader<ElfArch> *section = GetSection(shndx); - if (section != NULL) { - *size = section->section_size(); - return section->contents(); - } - return NULL; - } - - // Return a pointer to the first section of the given name by - // iterating through all section headers, and store the size in - // "size". Returns NULL if the section name is not found. - const char *GetSectionContentsByName(const string §ion_name, - size_t *size) { - for (unsigned int k = 0u; k < GetNumSections(); ++k) { - // When searching for sections in a .dwp file, the sections - // we're looking for will always be at the end of the section - // table, so reverse the direction of iteration. - int shndx = is_dwp_ ? GetNumSections() - k - 1 : k; - const char *name = GetSectionName(section_headers_[shndx].sh_name); - if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) { - const ElfSectionReader<ElfArch> *section = GetSection(shndx); - if (section == NULL) { - return NULL; - } else { - *size = section->section_size(); - return section->contents(); - } - } - } - return NULL; - } - - // This is like GetSectionContentsByName() but it returns a lot of extra - // information about the section. - const char *GetSectionInfoByName(const string §ion_name, - ElfReader::SectionInfo *info) { - for (unsigned int k = 0u; k < GetNumSections(); ++k) { - // When searching for sections in a .dwp file, the sections - // we're looking for will always be at the end of the section - // table, so reverse the direction of iteration. - int shndx = is_dwp_ ? GetNumSections() - k - 1 : k; - const char *name = GetSectionName(section_headers_[shndx].sh_name); - if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) { - const ElfSectionReader<ElfArch> *section = GetSection(shndx); - if (section == NULL) { - return NULL; - } else { - info->type = section->header().sh_type; - info->flags = section->header().sh_flags; - info->addr = section->header().sh_addr; - info->offset = section->header().sh_offset; - info->size = section->header().sh_size; - info->link = section->header().sh_link; - info->info = section->header().sh_info; - info->addralign = section->header().sh_addralign; - info->entsize = section->header().sh_entsize; - return section->contents(); - } - } - } - return NULL; - } - - // 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 VaddrOfFirstLoadSegment() const { - // Relocatable objects (of type ET_REL) do not have LOAD segments. - if (header_.e_type == ET_REL) { - return 0; - } - for (int i = 0; i < GetNumProgramHeaders(); ++i) { - if (program_headers_[i].p_type == PT_LOAD) { - return program_headers_[i].p_vaddr; - } - } - return 0; - } - - // According to the LSB ("ELF special sections"), sections with debug - // info are prefixed by ".debug". The names are not specified, but they - // look like ".debug_line", ".debug_info", etc. - bool HasDebugSections() { - // Debug sections are likely to be near the end, so reverse the - // direction of iteration. - for (int k = GetNumSections() - 1; k >= 0; --k) { - const char *name = GetSectionName(section_headers_[k].sh_name); - if (strncmp(name, ".debug", strlen(".debug")) == 0) return true; - if (strncmp(name, ".zdebug", strlen(".zdebug")) == 0) return true; - } - return false; - } - - bool IsDynamicSharedObject() const { - return header_.e_type == ET_DYN; - } - - // Return the number of sections. - uint64_t GetNumSections() const { - if (HasManySections()) - return first_section_header_.sh_size; - return header_.e_shnum; - } - - private: - typedef vector<pair<uint64, const typename ElfArch::Sym *> > AddrToSymMap; - - static bool AddrToSymSorter(const typename AddrToSymMap::value_type& lhs, - const typename AddrToSymMap::value_type& rhs) { - return lhs.first < rhs.first; - } - - static bool AddrToSymEquals(const typename AddrToSymMap::value_type& lhs, - const typename AddrToSymMap::value_type& rhs) { - return lhs.first == rhs.first; - } - - // Does this ELF file have too many sections to fit in the program header? - bool HasManySections() const { - return header_.e_shnum == SHN_UNDEF; - } - - // Return the number of program headers. - int GetNumProgramHeaders() const { - if (HasManySections() && header_.e_phnum == 0xffff && - first_section_header_.sh_info != 0) - return first_section_header_.sh_info; - return header_.e_phnum; - } - - // Return the index of the string table. - int GetStringTableIndex() const { - if (HasManySections()) { - if (header_.e_shstrndx == 0xffff) - return first_section_header_.sh_link; - else if (header_.e_shstrndx >= GetNumSections()) - return 0; - } - return header_.e_shstrndx; - } - - // Given an offset into the section header string table, return the - // section name. - const char *GetSectionName(typename ElfArch::Word sh_name) { - const ElfSectionReader<ElfArch> *shstrtab = - GetSection(GetStringTableIndex()); - if (shstrtab != NULL) { - return shstrtab->GetOffset(sh_name); - } - return NULL; - } - - // Return an ElfSectionReader for the given section. The reader will - // be freed when this object is destroyed. - const ElfSectionReader<ElfArch> *GetSection(int num) { - const char *name; - // Hard-coding the name for the section-name string table prevents - // infinite recursion. - if (num == GetStringTableIndex()) - name = ".shstrtab"; - else - name = GetSectionNameByIndex(num); - ElfSectionReader<ElfArch> *& reader = sections_[num]; - if (reader == NULL) - reader = new ElfSectionReader<ElfArch>(name, path_, fd_, - section_headers_[num]); - return reader; - } - - // Parse out the overall header information from the file and assert - // that it looks sane. This contains information like the magic - // number and target architecture. - bool ParseHeaders(int fd, const string &path) { - // Read in the global ELF header. - if (pread(fd, &header_, sizeof(header_), 0) != sizeof(header_)) { - return false; - } - - // Must be an executable, dynamic shared object or relocatable object - if (header_.e_type != ET_EXEC && - header_.e_type != ET_DYN && - header_.e_type != ET_REL) { - return false; - } - // Need a section header. - if (header_.e_shoff == 0) { - return false; - } - - if (header_.e_shnum == SHN_UNDEF) { - // The number of sections in the program header is only a 16-bit value. In - // the event of overflow (greater than SHN_LORESERVE sections), e_shnum - // will read SHN_UNDEF and the true number of section header table entries - // is found in the sh_size field of the first section header. - // See: http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html - if (pread(fd, &first_section_header_, sizeof(first_section_header_), - header_.e_shoff) != sizeof(first_section_header_)) { - return false; - } - } - - // Dynamically allocate enough space to store the section headers - // and read them out of the file. - const int section_headers_size = - GetNumSections() * sizeof(*section_headers_); - section_headers_ = new typename ElfArch::Shdr[section_headers_size]; - if (pread(fd, section_headers_, section_headers_size, header_.e_shoff) != - section_headers_size) { - return false; - } - - // Dynamically allocate enough space to store the program headers - // and read them out of the file. - //const int program_headers_size = - // GetNumProgramHeaders() * sizeof(*program_headers_); - program_headers_ = new typename ElfArch::Phdr[GetNumProgramHeaders()]; - - // Presize the sections array for efficiency. - sections_.resize(GetNumSections(), NULL); - return true; - } - - // Given the "value" of a function descriptor return the address of the - // function (i.e. the dereferenced value). Otherwise return "value". - uint64 AdjustPPC64FunctionDescriptorSymbolValue(uint64 value) { - if (opd_section_ != NULL && - opd_info_.addr <= value && - value < opd_info_.addr + opd_info_.size) { - uint64 offset = value - opd_info_.addr; - return (*reinterpret_cast<const uint64*>(opd_section_ + offset)); - } - return value; - } - - void AdjustSymbolValue(typename ElfArch::Sym* sym) { - switch (header_.e_machine) { - case EM_ARM: - // For ARM architecture, if the LSB of the function symbol offset is set, - // it indicates a Thumb function. This bit should not be taken literally. - // Clear it. - if (ElfArch::Type(sym) == STT_FUNC) - sym->st_value = AdjustARMThumbSymbolValue(sym->st_value); - break; - case EM_386: - // No adjustment needed for Intel x86 architecture. However, explicitly - // define this case as we use it quite often. - break; - case EM_PPC64: - // PowerPC64 currently has function descriptors as part of the ABI. - // Function symbols need to be adjusted accordingly. - if (ElfArch::Type(sym) == STT_FUNC) - sym->st_value = AdjustPPC64FunctionDescriptorSymbolValue(sym->st_value); - break; - default: - break; - } - } - - friend class SymbolIterator<ElfArch>; - - // The file we're reading. - const string path_; - // Open file descriptor for path_. Not owned by this object. - const int fd_; - - // The global header of the ELF file. - typename ElfArch::Ehdr header_; - - // The header of the first section. This may be used to supplement the ELF - // file header. - typename ElfArch::Shdr first_section_header_; - - // Array of GetNumSections() section headers, allocated when we read - // in the global header. - typename ElfArch::Shdr *section_headers_; - - // Array of GetNumProgramHeaders() program headers, allocated when we read - // in the global header. - typename ElfArch::Phdr *program_headers_; - - // An array of pointers to ElfSectionReaders. Sections are - // mmaped as they're needed and not released until this object is - // destroyed. - vector<ElfSectionReader<ElfArch>*> sections_; - - // For PowerPC64 we need to keep track of function descriptors when looking up - // values for funtion symbols values. Function descriptors are kept in the - // .opd section and are dereferenced to find the function address. - ElfReader::SectionInfo opd_info_; - const char *opd_section_; // Must be checked for NULL before use. - int64 base_for_text_; - - // Read PLT-related sections for the current architecture. - bool plts_supported_; - // Code size of each PLT function for the current architecture. - size_t plt_code_size_; - // Size of the special first entry in the .plt section that calls the runtime - // loader resolution routine, and that all other entries jump to when doing - // lazy symbol binding. - size_t plt0_size_; - - // Maps a dynamic symbol index to a PLT offset. - // The vector entry index is the dynamic symbol index. - std::vector<uint64> symbols_plt_offsets_; - - // Container for PLT function name strings. These strings are passed by - // reference to SymbolSink::AddSymbol() so they need to be stored somewhere. - std::vector<string> plt_function_names_; - - bool visited_relocation_entries_; - - // True if this is a .dwp file. - bool is_dwp_; -}; - -ElfReader::ElfReader(const string &path) - : path_(path), fd_(-1), impl32_(NULL), impl64_(NULL) { - // linux 2.6.XX kernel can show deleted files like this: - // /var/run/nscd/dbYLJYaE (deleted) - // and the kernel-supplied vdso and vsyscall mappings like this: - // [vdso] - // [vsyscall] - if (MyHasSuffixString(path, " (deleted)")) - return; - if (path == "[vdso]") - return; - if (path == "[vsyscall]") - return; - - fd_ = open(path.c_str(), O_RDONLY); -} - -ElfReader::~ElfReader() { - if (fd_ != -1) - close(fd_); - if (impl32_ != NULL) - delete impl32_; - if (impl64_ != NULL) - delete impl64_; -} - - -// The only word-size specific part of this file is IsNativeElfFile(). -#if __WORDSIZE == 32 -#define NATIVE_ELF_ARCH Elf32 -#elif __WORDSIZE == 64 -#define NATIVE_ELF_ARCH Elf64 -#else -#error "Invalid word size" -#endif - -template <typename ElfArch> -static bool IsElfFile(const int fd, const string &path) { - if (fd < 0) - return false; - if (!ElfReaderImpl<ElfArch>::IsArchElfFile(fd, NULL)) { - // No error message here. IsElfFile gets called many times. - return false; - } - return true; -} - -bool ElfReader::IsNativeElfFile() const { - return IsElfFile<NATIVE_ELF_ARCH>(fd_, path_); -} - -bool ElfReader::IsElf32File() const { - return IsElfFile<Elf32>(fd_, path_); -} - -bool ElfReader::IsElf64File() const { - return IsElfFile<Elf64>(fd_, path_); -} - -/* -void ElfReader::AddSymbols(SymbolMap *symbols, - uint64 mem_offset, uint64 file_offset, - uint64 length) { - if (fd_ < 0) - return; - // TODO(chatham): Actually use the information about file offset and - // the length of the mapped section. On some machines the data - // section gets mapped as executable, and we'll end up reading the - // file twice and getting some of the offsets wrong. - if (IsElf32File()) { - GetImpl32()->GetSymbolPositions(symbols, SHT_SYMTAB, - mem_offset, file_offset); - GetImpl32()->GetSymbolPositions(symbols, SHT_DYNSYM, - mem_offset, file_offset); - } else if (IsElf64File()) { - GetImpl64()->GetSymbolPositions(symbols, SHT_SYMTAB, - mem_offset, file_offset); - GetImpl64()->GetSymbolPositions(symbols, SHT_DYNSYM, - mem_offset, file_offset); - } -} -*/ - -void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink) { - VisitSymbols(sink, -1, -1); -} - -void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink, - int symbol_binding, - int symbol_type) { - VisitSymbols(sink, symbol_binding, symbol_type, false); -} - -void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink, - int symbol_binding, - int symbol_type, - bool get_raw_symbol_values) { - if (IsElf32File()) { - GetImpl32()->VisitRelocationEntries(); - GetImpl32()->VisitSymbols(SHT_SYMTAB, sink, symbol_binding, symbol_type, - get_raw_symbol_values); - GetImpl32()->VisitSymbols(SHT_DYNSYM, sink, symbol_binding, symbol_type, - get_raw_symbol_values); - } else if (IsElf64File()) { - GetImpl64()->VisitRelocationEntries(); - GetImpl64()->VisitSymbols(SHT_SYMTAB, sink, symbol_binding, symbol_type, - get_raw_symbol_values); - GetImpl64()->VisitSymbols(SHT_DYNSYM, sink, symbol_binding, symbol_type, - get_raw_symbol_values); - } -} - -uint64 ElfReader::VaddrOfFirstLoadSegment() { - if (IsElf32File()) { - return GetImpl32()->VaddrOfFirstLoadSegment(); - } else if (IsElf64File()) { - return GetImpl64()->VaddrOfFirstLoadSegment(); - } else { - return 0; - } -} - -const char *ElfReader::GetSectionName(int shndx) { - if (shndx < 0 || static_cast<unsigned int>(shndx) >= GetNumSections()) return NULL; - if (IsElf32File()) { - return GetImpl32()->GetSectionNameByIndex(shndx); - } else if (IsElf64File()) { - return GetImpl64()->GetSectionNameByIndex(shndx); - } else { - return NULL; - } -} - -uint64 ElfReader::GetNumSections() { - if (IsElf32File()) { - return GetImpl32()->GetNumSections(); - } else if (IsElf64File()) { - return GetImpl64()->GetNumSections(); - } else { - return 0; - } -} - -const char *ElfReader::GetSectionByIndex(int shndx, size_t *size) { - if (IsElf32File()) { - return GetImpl32()->GetSectionContentsByIndex(shndx, size); - } else if (IsElf64File()) { - return GetImpl64()->GetSectionContentsByIndex(shndx, size); - } else { - return NULL; - } -} - -const char *ElfReader::GetSectionByName(const string §ion_name, - size_t *size) { - if (IsElf32File()) { - return GetImpl32()->GetSectionContentsByName(section_name, size); - } else if (IsElf64File()) { - return GetImpl64()->GetSectionContentsByName(section_name, size); - } else { - return NULL; - } -} - -const char *ElfReader::GetSectionInfoByName(const string §ion_name, - SectionInfo *info) { - if (IsElf32File()) { - return GetImpl32()->GetSectionInfoByName(section_name, info); - } else if (IsElf64File()) { - return GetImpl64()->GetSectionInfoByName(section_name, info); - } else { - return NULL; - } -} - -bool ElfReader::SectionNamesMatch(const string &name, const string &sh_name) { - if ((name.find(".debug_", 0) == 0) && (sh_name.find(".zdebug_", 0) == 0)) { - const string name_suffix(name, strlen(".debug_")); - const string sh_name_suffix(sh_name, strlen(".zdebug_")); - return name_suffix == sh_name_suffix; - } - return name == sh_name; -} - -bool ElfReader::IsDynamicSharedObject() { - if (IsElf32File()) { - return GetImpl32()->IsDynamicSharedObject(); - } else if (IsElf64File()) { - return GetImpl64()->IsDynamicSharedObject(); - } else { - return false; - } -} - -ElfReaderImpl<Elf32> *ElfReader::GetImpl32() { - if (impl32_ == NULL) { - impl32_ = new ElfReaderImpl<Elf32>(path_, fd_); - } - return impl32_; -} - -ElfReaderImpl<Elf64> *ElfReader::GetImpl64() { - if (impl64_ == NULL) { - impl64_ = new ElfReaderImpl<Elf64>(path_, fd_); - } - return impl64_; -} - -// Return true if file is an ELF binary of ElfArch, with unstripped -// debug info (debug_only=true) or symbol table (debug_only=false). -// Otherwise, return false. -template <typename ElfArch> -static bool IsNonStrippedELFBinaryImpl(const string &path, const int fd, - bool debug_only) { - if (!ElfReaderImpl<ElfArch>::IsArchElfFile(fd, NULL)) return false; - ElfReaderImpl<ElfArch> elf_reader(path, fd); - return debug_only ? - elf_reader.HasDebugSections() - : (elf_reader.GetSectionByType(SHT_SYMTAB) != NULL); -} - -// Helper for the IsNon[Debug]StrippedELFBinary functions. -static bool IsNonStrippedELFBinaryHelper(const string &path, - bool debug_only) { - const int fd = open(path.c_str(), O_RDONLY); - if (fd == -1) { - return false; - } - - if (IsNonStrippedELFBinaryImpl<Elf32>(path, fd, debug_only) || - IsNonStrippedELFBinaryImpl<Elf64>(path, fd, debug_only)) { - close(fd); - return true; - } - close(fd); - return false; -} - -bool ElfReader::IsNonStrippedELFBinary(const string &path) { - return IsNonStrippedELFBinaryHelper(path, false); -} - -bool ElfReader::IsNonDebugStrippedELFBinary(const string &path) { - return IsNonStrippedELFBinaryHelper(path, true); -} -} // namespace dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.h deleted file mode 100644 index 07477341f..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.h +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// 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 <vector> - -#include "common/dwarf/types.h" - -using std::string; -using std::vector; -using std::pair; - -namespace dwarf2reader { - -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 mem_offset, uint64 file_offset, - uint64 length); - - class SymbolSink { - public: - virtual ~SymbolSink() {} - virtual void AddSymbol(const char *name, uint64 address, uint64 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 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 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 §ion_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 type; // Section type (SHT_xxx constant from elf.h). - uint64 flags; // Section flags (SHF_xxx constants from elf.h). - uint64 addr; // Section virtual address at execution. - uint64 offset; // Section file offset. - uint64 size; // Section size in bytes. - uint32 link; // Link to another section. - uint32 info; // Additional section information. - uint64 addralign; // Section alignment. - uint64 entsize; // Entry size if section holds a table. - }; - const char *GetSectionInfoByName(const string §ion_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(const string &name, const string &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 dwarf2reader - -#endif // COMMON_DWARF_ELF_READER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.cc deleted file mode 100644 index 55a255eda..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.cc +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// This is a client for the dwarf2reader to extract function and line -// information from the debug info. - -#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" - -using google_breakpad::scoped_ptr; - -namespace dwarf2reader { - -CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files, - std::vector<string>* dirs, - LineMap* linemap):linemap_(linemap), - files_(files), - dirs_(dirs) { - // The dirs and files are 1 indexed, so just make sure we put - // nothing in the 0 vector. - assert(dirs->size() == 0); - assert(files->size() == 0); - dirs->push_back(""); - SourceFileInfo s; - s.name = ""; - s.lowpc = ULLONG_MAX; - files->push_back(s); -} - -void CULineInfoHandler::DefineDir(const string& name, uint32 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 dir_num, - uint64 mod_time, uint64 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 address, uint64 length, uint32 file_num, - uint32 line_num, uint32 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 offset, - uint8 address_size, - uint8 offset_size, - uint64 cu_length, - uint8 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 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 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 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - if (attr == DW_AT_stmt_list) { - SectionMap::const_iterator iter = sections_.find("__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; - default: - break; - } - } -} - -void CUFunctionInfoHandler::ProcessAttributeReference(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 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 offset) { - if (current_function_info_ && current_function_info_->lowpc) - address_to_funcinfo_->insert(std::make_pair(current_function_info_->lowpc, - current_function_info_)); -} - -} // namespace dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.h deleted file mode 100644 index 0b08a5fc5..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.h +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -// 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 dwarf2reader { - -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 line; - // Beginning address for this function - uint64 lowpc; - // End address for this function. - uint64 highpc; -}; - -struct SourceFileInfo { - // Name of the source file name - string name; - // Low address of source file name - uint64 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 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 dir_num, uint64 mod_time, uint64 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 address, uint64 length, - uint32 file_num, uint32 line_num, uint32 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 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 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 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 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 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 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 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 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 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 current_compilation_unit_offset_; -}; - -} // namespace dwarf2reader -#endif // COMMON_DWARF_FUNCTIONINFO_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/line_state_machine.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/line_state_machine.h deleted file mode 100644 index 0ff72abcf..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/line_state_machine.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -#ifndef COMMON_DWARF_LINE_STATE_MACHINE_H__ -#define COMMON_DWARF_LINE_STATE_MACHINE_H__ - -namespace dwarf2reader { - -// 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 file_num; - uint64 address; - uint32 line_num; - uint32 column_num; - bool is_stmt; // stmt means statement. - bool basic_block; - bool end_sequence; -}; - -} // namespace dwarf2reader - - -#endif // COMMON_DWARF_LINE_STATE_MACHINE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/moz.build b/toolkit/crashreporter/google-breakpad/src/common/dwarf/moz.build deleted file mode 100644 index e1ccc65ac..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/moz.build +++ /dev/null @@ -1,35 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -HostLibrary('host_breakpad_dwarf_s') -HOST_SOURCES += [ - 'bytereader.cc', - 'dwarf2diehandler.cc', - 'dwarf2reader.cc', - 'elf_reader.cc', - 'functioninfo.cc', -] -HOST_CXXFLAGS += [ - '-O2', - '-g', -] - -# need static lib -FORCE_STATIC_LIB = True - -# This code is only compiled for build-time tools, -# so enabling RTTI should be fine. -HOST_CXXFLAGS += [ - '-frtti', - '-funsigned-char', -] - -if CONFIG['OS_ARCH'] == 'Darwin': - HOST_CXXFLAGS += [ - '-stdlib=libc++', - ] - -include('/toolkit/crashreporter/crashreporter.mozbuild') diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/types.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/types.h deleted file mode 100644 index 59dda3160..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/types.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2008 Google, Inc. All Rights reserved -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -// This file contains some typedefs for basic types - - -#ifndef _COMMON_DWARF_TYPES_H__ -#define _COMMON_DWARF_TYPES_H__ - -#include <stdint.h> - -typedef signed char int8; -typedef short int16; -typedef int int32; -typedef long long int64; - -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; -typedef unsigned long long uint64; - -typedef intptr_t intptr; -typedef uintptr_t uintptr; - -#endif // _COMMON_DWARF_TYPES_H__ |