summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/google-breakpad/src/common/dwarf
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/common/dwarf')
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader-inl.h170
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.cc250
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.h315
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader_unittest.cc707
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.cc198
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.h269
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.cc199
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.h365
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc527
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2enums.h675
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.cc2734
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.h1288
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc2468
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc487
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_test_common.h149
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.cc1273
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.h166
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.cc231
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.h188
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/line_state_machine.h61
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/moz.build35
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/dwarf/types.h51
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 &current = die_handlers_.top();
- // This had better be an attribute of the DIE we were meant to handle.
- assert(offset == current.offset_);
- current.handler_->ProcessAttributeUnsigned(attr, form, data);
-}
-
-void DIEDispatcher::ProcessAttributeSigned(uint64 offset,
- enum DwarfAttribute attr,
- enum DwarfForm form,
- int64 data) {
- HandlerStack &current = die_handlers_.top();
- // This had better be an attribute of the DIE we were meant to handle.
- assert(offset == current.offset_);
- current.handler_->ProcessAttributeSigned(attr, form, data);
-}
-
-void DIEDispatcher::ProcessAttributeReference(uint64 offset,
- enum DwarfAttribute attr,
- enum DwarfForm form,
- uint64 data) {
- HandlerStack &current = die_handlers_.top();
- // This had better be an attribute of the DIE we were meant to handle.
- assert(offset == current.offset_);
- current.handler_->ProcessAttributeReference(attr, form, data);
-}
-
-void DIEDispatcher::ProcessAttributeBuffer(uint64 offset,
- enum DwarfAttribute attr,
- enum DwarfForm form,
- const uint8_t *data,
- uint64 len) {
- HandlerStack &current = die_handlers_.top();
- // This had better be an attribute of the DIE we were meant to handle.
- assert(offset == current.offset_);
- current.handler_->ProcessAttributeBuffer(attr, form, data, len);
-}
-
-void DIEDispatcher::ProcessAttributeString(uint64 offset,
- enum DwarfAttribute attr,
- enum DwarfForm form,
- const string& data) {
- HandlerStack &current = die_handlers_.top();
- // This had better be an attribute of the DIE we were meant to handle.
- assert(offset == current.offset_);
- current.handler_->ProcessAttributeString(attr, form, data);
-}
-
-void DIEDispatcher::ProcessAttributeSignature(uint64 offset,
- enum DwarfAttribute attr,
- enum DwarfForm form,
- uint64 signature) {
- HandlerStack &current = die_handlers_.top();
- // This had better be an attribute of the DIE we were meant to handle.
- assert(offset == current.offset_);
- current.handler_->ProcessAttributeSignature(attr, form, signature);
-}
-
-} // namespace 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_, &sections);
- 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, &sections);
- 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,
- &section_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, &section_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, &section_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, &section_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 = &registers_[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 &section = ".debug_frame")
- : filename_(filename), section_(section) { }
- virtual ~Reporter() { }
-
- // The CFI entry at OFFSET ends too early to be well-formed. KIND
- // indicates what kind of entry it is; KIND can be kUnknown if we
- // haven't parsed enough of the entry to tell yet.
- virtual void Incomplete(uint64 offset, CallFrameInfo::EntryKind kind);
-
- // The .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 &section);
-#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(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_advance_loc) {
- CFISection section(kBigEndian, 8);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_advance_loc1) {
- CFISection section(kLittleEndian, 8);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_advance_loc2) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_advance_loc4) {
- CFISection section(kBigEndian, 8);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_MIPS_advance_loc8) {
- code_factor = 0x2d;
- CFISection section(kBigEndian, 8);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_def_cfa) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_def_cfa_sf) {
- CFISection section(kBigEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_def_cfa_register) {
- CFISection section(kLittleEndian, 8);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-// 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(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_def_cfa_offset) {
- CFISection section(kBigEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_def_cfa_offset_sf) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-// 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(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_def_cfa_expression) {
- CFISection section(kLittleEndian, 8);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_undefined) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_same_value) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_offset) {
- CFISection section(kBigEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_offset_extended) {
- CFISection section(kBigEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_offset_extended_sf) {
- CFISection section(kBigEndian, 8);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_val_offset) {
- CFISection section(kBigEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_val_offset_sf) {
- CFISection section(kBigEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_register) {
- CFISection section(kLittleEndian, 8);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_expression) {
- CFISection section(kBigEndian, 8);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_val_expression) {
- CFISection section(kBigEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-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(&section);
-}
-
-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(&section);
-}
-
-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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_remember_and_restore_state) {
- CFISection section(kLittleEndian, 8);
- StockCIEAndFDE(&section);
-
- // 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(&section);
-}
-
-// 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(&section);
-
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_nop) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_GNU_window_save) {
- CFISection section(kBigEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_GNU_args_size) {
- CFISection section(kLittleEndian, 8);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIInsn, DW_CFA_GNU_negative_offset_extended) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-// 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(&section);
-}
-
-// Quit processing in the middle of an entry's instructions.
-TEST_F(CFIInsn, QuitMidentry) {
- CFISection section(kLittleEndian, 8);
- StockCIEAndFDE(&section);
- 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(&section, false);
-}
-
-class CFIRestore: public CFIInsnFixture, public Test { };
-
-TEST_F(CFIRestore, RestoreUndefinedRuleUnchanged) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreUndefinedRuleChanged) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreSameValueRuleUnchanged) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreSameValueRuleChanged) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreOffsetRuleUnchanged) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreOffsetRuleChanged) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreOffsetRuleChangedOffset) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreValOffsetRuleUnchanged) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreValOffsetRuleChanged) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreValOffsetRuleChangedValOffset) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreRegisterRuleUnchanged) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreRegisterRuleChanged) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreRegisterRuleChangedRegister) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreExpressionRuleUnchanged) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreExpressionRuleChanged) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreExpressionRuleChangedExpression) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreValExpressionRuleUnchanged) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreValExpressionRuleChanged) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-TEST_F(CFIRestore, RestoreValExpressionRuleChangedValExpression) {
- CFISection section(kLittleEndian, 4);
- StockCIEAndFDE(&section);
- 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(&section);
-}
-
-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(&section);
-}
-
-// 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(&section);
-}
-
-// 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(&section);
-}
-
-// 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(&section, 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(&section);
-}
-
-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(&section);
-}
-
-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(&section);
-}
-
-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(&section);
-}
-
-// 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(&section_names_header.name)
- .AppendCString(".shstrtab")
- .Mark(&cfi_header.name)
- .AppendCString(cfi_name)
- .Mark(&section_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(&section_table, null_header);
- AppendSectionHeader(&section_table, section_names_header);
- AppendSectionHeader(&section_table, cfi_header);
-
- // Append the section table and the section contents to the ELF file.
- elf
- .Mark(&section_table_offset)
- .Append(section_table)
- .Mark(&section_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 &params,
- 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 &params,
- 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 &params, 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 &section_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 &section_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 &section_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 &section_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 &section_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 &section_name, size_t *size);
-
- // This is like GetSectionByName() but it returns a lot of extra information
- // about the section. The SectionInfo structure is almost identical to
- // the typedef struct Elf64_Shdr defined in <elf.h>, but is redefined
- // here so that the many short macro names in <elf.h> don't have to be
- // added to our already cluttered namespace.
- struct SectionInfo {
- uint32 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 &section_name,
- SectionInfo *info);
-
- // Check if "path" is an ELF binary that has not been stripped of symbol
- // tables. This function supports both 32-bit and 64-bit ELF binaries.
- static bool IsNonStrippedELFBinary(const string &path);
-
- // Check if "path" is an ELF binary that has not been stripped of debug
- // info. Unlike IsNonStrippedELFBinary, this function will return
- // false for binaries passed through "strip -S".
- static bool IsNonDebugStrippedELFBinary(const string &path);
-
- // Match a requested section name with the section name as it
- // appears in the elf-file, adjusting for compressed debug section
- // names. For example, returns true if name == ".debug_abbrev" and
- // sh_name == ".zdebug_abbrev"
- static bool SectionNamesMatch(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__