diff options
Diffstat (limited to 'src/common/dwarf')
23 files changed, 2962 insertions, 1254 deletions
diff --git a/src/common/dwarf/bytereader-inl.h b/src/common/dwarf/bytereader-inl.h index f4c068a2..21026484 100644 --- a/src/common/dwarf/bytereader-inl.h +++ b/src/common/dwarf/bytereader-inl.h @@ -1,4 +1,4 @@ -// Copyright 2006 Google Inc. All Rights Reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -34,13 +34,13 @@ #include <assert.h> #include <stdint.h> -namespace dwarf2reader { +namespace google_breakpad { -inline uint8_t ByteReader::ReadOneByte(const uint8_t *buffer) const { +inline uint8_t ByteReader::ReadOneByte(const uint8_t* buffer) const { return buffer[0]; } -inline uint16_t ByteReader::ReadTwoBytes(const uint8_t *buffer) const { +inline uint16_t ByteReader::ReadTwoBytes(const uint8_t* buffer) const { const uint16_t buffer0 = buffer[0]; const uint16_t buffer1 = buffer[1]; if (endian_ == ENDIANNESS_LITTLE) { @@ -50,7 +50,18 @@ inline uint16_t ByteReader::ReadTwoBytes(const uint8_t *buffer) const { } } -inline uint64_t ByteReader::ReadFourBytes(const uint8_t *buffer) const { +inline uint64_t ByteReader::ReadThreeBytes(const uint8_t* buffer) const { + const uint32_t buffer0 = buffer[0]; + const uint32_t buffer1 = buffer[1]; + const uint32_t buffer2 = buffer[2]; + if (endian_ == ENDIANNESS_LITTLE) { + return buffer0 | buffer1 << 8 | buffer2 << 16; + } else { + return buffer2 | buffer1 << 8 | buffer0 << 16; + } +} + +inline uint64_t ByteReader::ReadFourBytes(const uint8_t* buffer) const { const uint32_t buffer0 = buffer[0]; const uint32_t buffer1 = buffer[1]; const uint32_t buffer2 = buffer[2]; @@ -62,7 +73,7 @@ inline uint64_t ByteReader::ReadFourBytes(const uint8_t *buffer) const { } } -inline uint64_t ByteReader::ReadEightBytes(const uint8_t *buffer) const { +inline uint64_t ByteReader::ReadEightBytes(const uint8_t* buffer) const { const uint64_t buffer0 = buffer[0]; const uint64_t buffer1 = buffer[1]; const uint64_t buffer2 = buffer[2]; @@ -84,7 +95,7 @@ inline uint64_t ByteReader::ReadEightBytes(const uint8_t *buffer) const { // information, plus one bit saying whether the number continues or // not. -inline uint64_t ByteReader::ReadUnsignedLEB128(const uint8_t *buffer, +inline uint64_t ByteReader::ReadUnsignedLEB128(const uint8_t* buffer, size_t* len) const { uint64_t result = 0; size_t num_read = 0; @@ -109,7 +120,7 @@ inline uint64_t ByteReader::ReadUnsignedLEB128(const uint8_t *buffer, // Read a signed LEB128 number. These are like regular LEB128 // numbers, except the last byte may have a sign bit set. -inline int64_t ByteReader::ReadSignedLEB128(const uint8_t *buffer, +inline int64_t ByteReader::ReadSignedLEB128(const uint8_t* buffer, size_t* len) const { int64_t result = 0; unsigned int shift = 0; @@ -129,18 +140,18 @@ inline int64_t ByteReader::ReadSignedLEB128(const uint8_t *buffer, return result; } -inline uint64_t ByteReader::ReadOffset(const uint8_t *buffer) const { +inline uint64_t ByteReader::ReadOffset(const uint8_t* buffer) const { assert(this->offset_reader_); return (this->*offset_reader_)(buffer); } -inline uint64_t ByteReader::ReadAddress(const uint8_t *buffer) const { +inline uint64_t ByteReader::ReadAddress(const uint8_t* buffer) const { assert(this->address_reader_); return (this->*address_reader_)(buffer); } inline void ByteReader::SetCFIDataBase(uint64_t section_base, - const uint8_t *buffer_base) { + const uint8_t* buffer_base) { section_base_ = section_base; buffer_base_ = buffer_base; have_section_base_ = true; @@ -165,6 +176,6 @@ inline void ByteReader::ClearFunctionBase() { have_function_base_ = false; } -} // namespace dwarf2reader +} // namespace google_breakpad #endif // UTIL_DEBUGINFO_BYTEREADER_INL_H__ diff --git a/src/common/dwarf/bytereader.cc b/src/common/dwarf/bytereader.cc index 0b27dd58..46bed6d0 100644 --- a/src/common/dwarf/bytereader.cc +++ b/src/common/dwarf/bytereader.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -33,7 +33,7 @@ #include "common/dwarf/bytereader-inl.h" #include "common/dwarf/bytereader.h" -namespace dwarf2reader { +namespace google_breakpad { ByteReader::ByteReader(enum Endianness endian) :offset_reader_(NULL), address_reader_(NULL), endian_(endian), @@ -63,7 +63,7 @@ void ByteReader::SetAddressSize(uint8_t size) { } } -uint64_t ByteReader::ReadInitialLength(const uint8_t *start, size_t* len) { +uint64_t ByteReader::ReadInitialLength(const uint8_t* start, size_t* len) { const uint64_t initial_length = ReadFourBytes(start); start += 4; @@ -101,9 +101,9 @@ bool ByteReader::UsableEncoding(DwarfPointerEncoding encoding) const { } } -uint64_t ByteReader::ReadEncodedPointer(const uint8_t *buffer, +uint64_t ByteReader::ReadEncodedPointer(const uint8_t* buffer, DwarfPointerEncoding encoding, - size_t *len) const { + 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); @@ -130,7 +130,7 @@ uint64_t ByteReader::ReadEncodedPointer(const uint8_t *buffer, // Round up to the next boundary. uint64_t aligned = (offset + AddressSize() - 1) & -AddressSize(); // Convert back to a pointer. - const uint8_t *aligned_buffer = buffer_base_ + (aligned - skew); + 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); @@ -247,4 +247,4 @@ Endianness ByteReader::GetEndianness() const { return endian_; } -} // namespace dwarf2reader +} // namespace google_breakpad diff --git a/src/common/dwarf/bytereader.h b/src/common/dwarf/bytereader.h index 2b37a12d..761eaf68 100644 --- a/src/common/dwarf/bytereader.h +++ b/src/common/dwarf/bytereader.h @@ -1,6 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -12,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -38,7 +38,7 @@ #include "common/dwarf/types.h" #include "common/dwarf/dwarf2enums.h" -namespace dwarf2reader { +namespace google_breakpad { // We can't use the obvious name of LITTLE_ENDIAN and BIG_ENDIAN // because it conflicts with a macro @@ -62,22 +62,27 @@ class ByteReader { // Read a single byte from BUFFER and return it as an unsigned 8 bit // number. - uint8_t ReadOneByte(const uint8_t *buffer) const; + uint8_t ReadOneByte(const uint8_t* buffer) const; // Read two bytes from BUFFER and return them as an unsigned 16 bit // number, using this ByteReader's endianness. - uint16_t ReadTwoBytes(const uint8_t *buffer) const; + uint16_t ReadTwoBytes(const uint8_t* buffer) const; + + // Read three bytes from BUFFER and return them as an unsigned 64 bit + // number, using this ByteReader's endianness. DWARF 5 uses this encoding + // for various index-related DW_FORMs. + uint64_t ReadThreeBytes(const uint8_t* buffer) const; // Read four bytes from BUFFER and return them as an unsigned 32 bit // number, using this ByteReader's endianness. This function returns // a uint64_t so that it is compatible with ReadAddress and // ReadOffset. The number it returns will never be outside the range // of an unsigned 32 bit integer. - uint64_t ReadFourBytes(const uint8_t *buffer) const; + uint64_t ReadFourBytes(const uint8_t* buffer) const; // Read eight bytes from BUFFER and return them as an unsigned 64 // bit number, using this ByteReader's endianness. - uint64_t ReadEightBytes(const uint8_t *buffer) const; + uint64_t ReadEightBytes(const uint8_t* buffer) const; // Read an unsigned LEB128 (Little Endian Base 128) number from // BUFFER and return it as an unsigned 64 bit integer. Set LEN to @@ -96,7 +101,7 @@ class ByteReader { // In other words, we break VALUE into groups of seven bits, put // them in little-endian order, and then write them as eight-bit // bytes with the high bit on all but the last. - uint64_t ReadUnsignedLEB128(const uint8_t *buffer, size_t *len) const; + uint64_t ReadUnsignedLEB128(const uint8_t* buffer, size_t* len) const; // Read a signed LEB128 number from BUFFER and return it as an // signed 64 bit integer. Set LEN to the number of bytes read. @@ -115,7 +120,7 @@ class ByteReader { // In other words, we break VALUE into groups of seven bits, put // them in little-endian order, and then write them as eight-bit // bytes with the high bit on all but the last. - int64_t ReadSignedLEB128(const uint8_t *buffer, size_t *len) const; + int64_t ReadSignedLEB128(const uint8_t* buffer, size_t* len) const; // Indicate that addresses on this architecture are SIZE bytes long. SIZE // must be either 4 or 8. (DWARF allows addresses to be any number of @@ -138,7 +143,7 @@ class ByteReader { // Read an address from BUFFER and return it as an unsigned 64 bit // integer, respecting this ByteReader's endianness and address size. You // must call SetAddressSize before calling this function. - uint64_t ReadAddress(const uint8_t *buffer) const; + uint64_t ReadAddress(const uint8_t* buffer) const; // DWARF actually defines two slightly different formats: 32-bit DWARF // and 64-bit DWARF. This is *not* related to the size of registers or @@ -175,14 +180,14 @@ class ByteReader { // - The 32-bit value 0xffffffff, followed by a 64-bit byte count, // indicating that the data whose length is being measured uses // the 64-bit DWARF format. - uint64_t ReadInitialLength(const uint8_t *start, size_t *len); + uint64_t ReadInitialLength(const uint8_t* start, size_t* len); // Read an offset from BUFFER and return it as an unsigned 64 bit // integer, respecting the ByteReader's endianness. In 32-bit DWARF, the // offset is 4 bytes long; in 64-bit DWARF, the offset is eight bytes // long. You must call ReadInitialLength or SetOffsetSize before calling // this function; see the comments above for details. - uint64_t ReadOffset(const uint8_t *buffer) const; + uint64_t ReadOffset(const uint8_t* buffer) const; // Return the current offset size, in bytes. // A return value of 4 indicates that we are reading 32-bit DWARF. @@ -237,7 +242,7 @@ class ByteReader { // is BUFFER_BASE. This allows us to find the address that a given // byte in our buffer would have when loaded into the program the // data describes. We need this to resolve DW_EH_PE_pcrel pointers. - void SetCFIDataBase(uint64_t section_base, const uint8_t *buffer_base); + void SetCFIDataBase(uint64_t section_base, const uint8_t* buffer_base); // Indicate that the base address of the program's ".text" section // is TEXT_BASE. We need this to resolve DW_EH_PE_textrel pointers. @@ -276,15 +281,15 @@ class ByteReader { // base address this reader hasn't been given, so you should check // with ValidEncoding and UsableEncoding first if you would rather // die in a more helpful way. - uint64_t ReadEncodedPointer(const uint8_t *buffer, + uint64_t ReadEncodedPointer(const uint8_t* buffer, DwarfPointerEncoding encoding, - size_t *len) const; + size_t* len) const; Endianness GetEndianness() const; private: // Function pointer type for our address and offset readers. - typedef uint64_t (ByteReader::*AddressReader)(const uint8_t *) const; + typedef uint64_t (ByteReader::*AddressReader)(const uint8_t*) const; // Read an offset from BUFFER and return it as an unsigned 64 bit // integer. DWARF2/3 define offsets as either 4 or 8 bytes, @@ -307,9 +312,9 @@ class ByteReader { bool have_section_base_, have_text_base_, have_data_base_; bool have_function_base_; uint64_t section_base_, text_base_, data_base_, function_base_; - const uint8_t *buffer_base_; + const uint8_t* buffer_base_; }; -} // namespace dwarf2reader +} // namespace google_breakpad #endif // COMMON_DWARF_BYTEREADER_H__ diff --git a/src/common/dwarf/bytereader_unittest.cc b/src/common/dwarf/bytereader_unittest.cc index e66062d1..c23c737b 100644 --- a/src/common/dwarf/bytereader_unittest.cc +++ b/src/common/dwarf/bytereader_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -29,7 +28,7 @@ // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> -// bytereader_unittest.cc: Unit tests for dwarf2reader::ByteReader +// bytereader_unittest.cc: Unit tests for google_breakpad::ByteReader #include <stdint.h> @@ -41,10 +40,10 @@ #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::ByteReader; +using google_breakpad::DwarfPointerEncoding; +using google_breakpad::ENDIANNESS_BIG; +using google_breakpad::ENDIANNESS_LITTLE; using google_breakpad::CFISection; using google_breakpad::test_assembler::Label; using google_breakpad::test_assembler::kBigEndian; @@ -73,7 +72,7 @@ TEST_F(Reader, SimpleConstructor) { .LEB128(-0x4f337badf4483f83LL) .D32(0xfec319c9); ASSERT_TRUE(section.GetContents(&contents)); - const uint8_t *data = reinterpret_cast<const uint8_t *>(contents.data()); + 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)); @@ -91,279 +90,279 @@ TEST_F(Reader, SimpleConstructor) { TEST_F(Reader, ValidEncodings) { ByteReader reader(ENDIANNESS_LITTLE); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_omit))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_omit))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_aligned))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_aligned))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x05))); EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x07))); @@ -380,7 +379,7 @@ 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, + EXPECT_DEATH(reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_omit, &pointer_size), "encoding != DW_EH_PE_omit"); } @@ -390,7 +389,7 @@ TEST_F(Reader, DW_EH_PE_absptr4) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(4); EXPECT_EQ(0x40ea5727U, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_absptr, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_absptr, &pointer_size)); EXPECT_EQ(4U, pointer_size); } @@ -402,7 +401,7 @@ TEST_F(Reader, DW_EH_PE_absptr8) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(8); EXPECT_EQ(0x010598c240ea5727ULL, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_absptr, + reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_absptr, &pointer_size)); EXPECT_EQ(8U, pointer_size); } @@ -412,7 +411,7 @@ TEST_F(Reader, DW_EH_PE_uleb128) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(4); EXPECT_EQ(0x130201U, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_uleb128, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_uleb128, &pointer_size)); EXPECT_EQ(3U, pointer_size); } @@ -422,7 +421,7 @@ TEST_F(Reader, DW_EH_PE_udata2) { ByteReader reader(ENDIANNESS_BIG); reader.SetAddressSize(4); EXPECT_EQ(0xf48dU, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_udata2, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_udata2, &pointer_size)); EXPECT_EQ(2U, pointer_size); } @@ -432,7 +431,7 @@ TEST_F(Reader, DW_EH_PE_udata4) { ByteReader reader(ENDIANNESS_BIG); reader.SetAddressSize(8); EXPECT_EQ(0xa5628f8b, - reader.ReadEncodedPointer(data + 2, dwarf2reader::DW_EH_PE_udata4, + reader.ReadEncodedPointer(data + 2, google_breakpad::DW_EH_PE_udata4, &pointer_size)); EXPECT_EQ(4U, pointer_size); } @@ -444,7 +443,7 @@ TEST_F(Reader, DW_EH_PE_udata8Addr8) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(8); EXPECT_EQ(0x8fed199f69047304ULL, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_udata8, + reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_udata8, &pointer_size)); EXPECT_EQ(8U, pointer_size); } @@ -456,7 +455,7 @@ TEST_F(Reader, DW_EH_PE_udata8Addr4) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(4); EXPECT_EQ(0x69047304ULL, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_udata8, + reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_udata8, &pointer_size)); EXPECT_EQ(8U, pointer_size); } @@ -466,7 +465,7 @@ TEST_F(Reader, DW_EH_PE_sleb128) { ByteReader reader(ENDIANNESS_BIG); reader.SetAddressSize(4); EXPECT_EQ(-0x030201U & 0xffffffff, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_sleb128, + reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_sleb128, &pointer_size)); EXPECT_EQ(3U, pointer_size); } @@ -476,7 +475,7 @@ TEST_F(Reader, DW_EH_PE_sdata2) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(8); EXPECT_EQ(0xffffffffffffbfb9ULL, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_sdata2, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_sdata2, &pointer_size)); EXPECT_EQ(2U, pointer_size); } @@ -486,7 +485,7 @@ TEST_F(Reader, DW_EH_PE_sdata4) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(8); EXPECT_EQ(0xffffffffadc2b8f2ULL, - reader.ReadEncodedPointer(data + 2, dwarf2reader::DW_EH_PE_sdata4, + reader.ReadEncodedPointer(data + 2, google_breakpad::DW_EH_PE_sdata4, &pointer_size)); EXPECT_EQ(4U, pointer_size); } @@ -498,7 +497,7 @@ TEST_F(Reader, DW_EH_PE_sdata8) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(8); EXPECT_EQ(0x87269b0ce0795766ULL, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_sdata8, + reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_sdata8, &pointer_size)); EXPECT_EQ(8U, pointer_size); } @@ -510,8 +509,8 @@ TEST_F(Reader, DW_EH_PE_pcrel) { ByteReader reader(ENDIANNESS_BIG); reader.SetAddressSize(4); DwarfPointerEncoding encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_pcrel - | dwarf2reader::DW_EH_PE_absptr); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_pcrel + | google_breakpad::DW_EH_PE_absptr); reader.SetCFIDataBase(0x89951377, data); EXPECT_EQ(0x89951377 + 3 + 0x14c8c402, reader.ReadEncodedPointer(data + 3, encoding, &pointer_size)); @@ -526,8 +525,8 @@ TEST_F(Reader, DW_EH_PE_textrel) { reader.SetAddressSize(4); reader.SetTextBase(0xb91beaf0); DwarfPointerEncoding encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel - | dwarf2reader::DW_EH_PE_sdata2); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_textrel + | google_breakpad::DW_EH_PE_sdata2); EXPECT_EQ((0xb91beaf0 + 0xffffc917) & 0xffffffff, reader.ReadEncodedPointer(data + 3, encoding, &pointer_size)); EXPECT_EQ(2U, pointer_size); @@ -541,8 +540,8 @@ TEST_F(Reader, DW_EH_PE_datarel) { reader.SetAddressSize(8); reader.SetDataBase(0xbef308bd25ce74f0ULL); DwarfPointerEncoding encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel - | dwarf2reader::DW_EH_PE_sleb128); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_datarel + | google_breakpad::DW_EH_PE_sleb128); EXPECT_EQ(0xbef308bd25ce74f0ULL + 0xfffffffffffa013bULL, reader.ReadEncodedPointer(data + 2, encoding, &pointer_size)); EXPECT_EQ(3U, pointer_size); @@ -556,8 +555,8 @@ TEST_F(Reader, DW_EH_PE_funcrel) { reader.SetAddressSize(4); reader.SetFunctionBase(0x823c3520); DwarfPointerEncoding encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel - | dwarf2reader::DW_EH_PE_udata2); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_funcrel + | google_breakpad::DW_EH_PE_udata2); EXPECT_EQ(0x823c3520 + 0xd148, reader.ReadEncodedPointer(data + 5, encoding, &pointer_size)); EXPECT_EQ(2U, pointer_size); @@ -567,48 +566,48 @@ 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_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr)); + EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit)); EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); } TEST(UsableBase, Text) { ByteReader reader(ENDIANNESS_BIG); reader.SetTextBase(0xa899ccb9); - EXPECT_TRUE(reader.UsableEncoding(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_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel)); + EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit)); EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); } TEST(UsableBase, Data) { ByteReader reader(ENDIANNESS_BIG); reader.SetDataBase(0xf7b10bcd); - EXPECT_TRUE(reader.UsableEncoding(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_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel)); + EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit)); EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); } TEST(UsableBase, Function) { ByteReader reader(ENDIANNESS_BIG); reader.SetFunctionBase(0xc2c0ed81); - EXPECT_TRUE(reader.UsableEncoding(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_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel)); + EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit)); EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); } @@ -616,12 +615,12 @@ 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_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit)); EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); } @@ -641,7 +640,7 @@ 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, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(4U, pointer_size); } @@ -649,7 +648,7 @@ TEST_F(Aligned, DW_EH_PE_aligned0) { TEST_F(Aligned, DW_EH_PE_aligned1) { reader.SetCFIDataBase(0xb440305d, data); EXPECT_EQ(0xd834d51cU, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(7U, pointer_size); } @@ -657,7 +656,7 @@ TEST_F(Aligned, DW_EH_PE_aligned1) { TEST_F(Aligned, DW_EH_PE_aligned2) { reader.SetCFIDataBase(0xb440305e, data); EXPECT_EQ(0x93d834d5U, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(6U, pointer_size); } @@ -665,7 +664,7 @@ TEST_F(Aligned, DW_EH_PE_aligned2) { TEST_F(Aligned, DW_EH_PE_aligned3) { reader.SetCFIDataBase(0xb440305f, data); EXPECT_EQ(0x6e93d834U, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(5U, pointer_size); } @@ -674,7 +673,7 @@ TEST_F(Aligned, DW_EH_PE_aligned11) { reader.SetCFIDataBase(0xb4403061, data); EXPECT_EQ(0xd834d51cU, reader.ReadEncodedPointer(data + 1, - dwarf2reader::DW_EH_PE_aligned, + google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(6U, pointer_size); } @@ -683,7 +682,7 @@ TEST_F(Aligned, DW_EH_PE_aligned30) { reader.SetCFIDataBase(0xb4403063, data); EXPECT_EQ(0x6e93d834U, reader.ReadEncodedPointer(data + 1, - dwarf2reader::DW_EH_PE_aligned, + google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(4U, pointer_size); } @@ -692,7 +691,7 @@ TEST_F(Aligned, DW_EH_PE_aligned23) { reader.SetCFIDataBase(0xb4403062, data); EXPECT_EQ(0x1cd3ac2bU, reader.ReadEncodedPointer(data + 3, - dwarf2reader::DW_EH_PE_aligned, + google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(7U, pointer_size); } @@ -701,7 +700,7 @@ TEST_F(Aligned, DW_EH_PE_aligned03) { reader.SetCFIDataBase(0xb4403064, data); EXPECT_EQ(0x34d51cd3U, reader.ReadEncodedPointer(data + 3, - dwarf2reader::DW_EH_PE_aligned, + google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(5U, pointer_size); } diff --git a/src/common/dwarf/cfi_assembler.cc b/src/common/dwarf/cfi_assembler.cc index 2dc22085..9ed979b4 100644 --- a/src/common/dwarf/cfi_assembler.cc +++ b/src/common/dwarf/cfi_assembler.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -38,14 +37,12 @@ #include <stdlib.h> namespace google_breakpad { - -using dwarf2reader::DwarfPointerEncoding; -CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor, +CFISection& CFISection::CIEHeader(uint64_t code_alignment_factor, int data_alignment_factor, unsigned return_address_register, uint8_t version, - const string &augmentation, + const string& augmentation, bool dwarf64, uint8_t address_size, uint8_t segment_size) { @@ -78,7 +75,7 @@ CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor, return *this; } -CFISection &CFISection::FDEHeader(Label cie_pointer, +CFISection& CFISection::FDEHeader(Label cie_pointer, uint64_t initial_location, uint64_t address_range, bool dwarf64) { @@ -113,9 +110,9 @@ CFISection &CFISection::FDEHeader(Label cie_pointer, return *this; } -CFISection &CFISection::FinishEntry() { +CFISection& CFISection::FinishEntry() { assert(entry_length_); - Align(address_size_, dwarf2reader::DW_CFA_nop); + Align(address_size_, DW_CFA_nop); entry_length_->length = Here() - entry_length_->start; delete entry_length_; entry_length_ = NULL; @@ -123,28 +120,28 @@ CFISection &CFISection::FinishEntry() { return *this; } -CFISection &CFISection::EncodedPointer(uint64_t address, +CFISection& CFISection::EncodedPointer(uint64_t address, DwarfPointerEncoding encoding, - const EncodedPointerBases &bases) { + const EncodedPointerBases& bases) { // Omitted data is extremely easy to emit. - if (encoding == dwarf2reader::DW_EH_PE_omit) + if (encoding == DW_EH_PE_omit) return *this; - // If (encoding & dwarf2reader::DW_EH_PE_indirect) != 0, then we assume + // If (encoding & DW_EH_PE_indirect) != 0, then we assume // that ADDRESS is the address at which the pointer is stored --- in // other words, that bit has no effect on how we write the pointer. - encoding = DwarfPointerEncoding(encoding & ~dwarf2reader::DW_EH_PE_indirect); + encoding = DwarfPointerEncoding(encoding & ~DW_EH_PE_indirect); // Find the base address to which this pointer is relative. The upper // nybble of the encoding specifies this. uint64_t base; switch (encoding & 0xf0) { - case 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; + case DW_EH_PE_absptr: base = 0; break; + case DW_EH_PE_pcrel: base = bases.cfi + Size(); break; + case DW_EH_PE_textrel: base = bases.text; break; + case DW_EH_PE_datarel: base = bases.data; break; + case DW_EH_PE_funcrel: base = fde_start_address_; break; + case DW_EH_PE_aligned: base = 0; break; default: abort(); }; @@ -153,7 +150,7 @@ CFISection &CFISection::EncodedPointer(uint64_t address, address -= base; // Align the pointer, if required. - if ((encoding & 0xf0) == dwarf2reader::DW_EH_PE_aligned) + if ((encoding & 0xf0) == DW_EH_PE_aligned) Align(AddressSize()); // Append ADDRESS to this section in the appropriate form. For the @@ -161,30 +158,30 @@ CFISection &CFISection::EncodedPointer(uint64_t address, // 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: + case DW_EH_PE_absptr: Address(address); break; - case dwarf2reader::DW_EH_PE_uleb128: + case DW_EH_PE_uleb128: ULEB128(address); break; - case dwarf2reader::DW_EH_PE_sleb128: + case DW_EH_PE_sleb128: LEB128(address); break; - case dwarf2reader::DW_EH_PE_udata2: - case dwarf2reader::DW_EH_PE_sdata2: + case DW_EH_PE_udata2: + case DW_EH_PE_sdata2: D16(address); break; - case dwarf2reader::DW_EH_PE_udata4: - case dwarf2reader::DW_EH_PE_sdata4: + case DW_EH_PE_udata4: + case DW_EH_PE_sdata4: D32(address); break; - case dwarf2reader::DW_EH_PE_udata8: - case dwarf2reader::DW_EH_PE_sdata8: + case DW_EH_PE_udata8: + case DW_EH_PE_sdata8: D64(address); break; diff --git a/src/common/dwarf/cfi_assembler.h b/src/common/dwarf/cfi_assembler.h index bd7354d1..a33d5d84 100644 --- a/src/common/dwarf/cfi_assembler.h +++ b/src/common/dwarf/cfi_assembler.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -46,8 +45,6 @@ namespace google_breakpad { -using dwarf2reader::DwarfPointerEncoding; -using google_breakpad::test_assembler::Endianness; using google_breakpad::test_assembler::Label; using google_breakpad::test_assembler::Section; @@ -95,10 +92,10 @@ class CFISection: public Section { // 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, + CFISection(google_breakpad::test_assembler::Endianness endianness, size_t address_size, bool eh_frame = false) : Section(endianness), address_size_(address_size), eh_frame_(eh_frame), - pointer_encoding_(dwarf2reader::DW_EH_PE_absptr), + pointer_encoding_(DW_EH_PE_absptr), encoded_pointer_bases_(), entry_length_(NULL), in_fde_(false) { // The 'start', 'Here', and 'Mark' members of a CFISection all refer // to section offsets. @@ -120,7 +117,7 @@ class CFISection: public Section { // 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) { + void SetEncodedPointerBases(const EncodedPointerBases& bases) { encoded_pointer_bases_ = bases; } @@ -133,11 +130,11 @@ class CFISection: public Section { // 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, + CFISection& CIEHeader(uint64_t code_alignment_factor, int data_alignment_factor, unsigned return_address_register, uint8_t version = 3, - const string &augmentation = "", + const string& augmentation = "", bool dwarf64 = false, uint8_t address_size = 8, uint8_t segment_size = 0); @@ -152,7 +149,7 @@ class CFISection: public Section { // 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, + CFISection& FDEHeader(Label cie_pointer, uint64_t initial_location, uint64_t address_range, bool dwarf64 = false); @@ -161,11 +158,11 @@ class CFISection: public Section { // 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(); + 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) { + CFISection& Block(const string& block) { ULEB128(block.size()); Append(block); return *this; @@ -173,11 +170,11 @@ class CFISection: public Section { // Append ADDRESS to this section, in the appropriate size and // endianness. Return a reference to this section. - CFISection &Address(uint64_t address) { + CFISection& Address(uint64_t address) { Section::Append(endianness(), address_size_, address); return *this; } - CFISection &Address(Label address) { + CFISection& Address(Label address) { Section::Append(endianness(), address_size_, address); return *this; } @@ -191,26 +188,26 @@ class CFISection: public 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) { + CFISection& EncodedPointer(uint64_t address) { return EncodedPointer(address, pointer_encoding_, encoded_pointer_bases_); } - CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) { + CFISection& EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) { return EncodedPointer(address, encoding, encoded_pointer_bases_); } - CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding, - const EncodedPointerBases &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; } + 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 diff --git a/src/common/dwarf/dwarf2diehandler.cc b/src/common/dwarf/dwarf2diehandler.cc index 63845018..ea3ac71c 100644 --- a/src/common/dwarf/dwarf2diehandler.cc +++ b/src/common/dwarf/dwarf2diehandler.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -39,11 +39,11 @@ #include "common/dwarf/dwarf2diehandler.h" #include "common/using_std_string.h" -namespace dwarf2reader { +namespace google_breakpad { DIEDispatcher::~DIEDispatcher() { while (!die_handlers_.empty()) { - HandlerStack &entry = die_handlers_.top(); + HandlerStack& entry = die_handlers_.top(); if (entry.handler_ != root_handler_) delete entry.handler_; die_handlers_.pop(); @@ -60,7 +60,7 @@ bool DIEDispatcher::StartCompilationUnit(uint64_t offset, uint8_t address_size, bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) { // The stack entry for the parent of this DIE, if there is one. - HandlerStack *parent = die_handlers_.empty() ? NULL : &die_handlers_.top(); + 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. @@ -78,7 +78,7 @@ bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) { } // Find a handler for this DIE. - DIEHandler *handler; + DIEHandler* handler; if (parent) { if (parent->handler_) // Ask the parent to find a handler. @@ -115,7 +115,7 @@ bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) { void DIEDispatcher::EndDIE(uint64_t offset) { assert(!die_handlers_.empty()); - HandlerStack *entry = &die_handlers_.top(); + HandlerStack* entry = &die_handlers_.top(); if (entry->handler_) { // This entry had better be the handler for this DIE. assert(entry->offset_ == offset); @@ -139,7 +139,7 @@ void DIEDispatcher::ProcessAttributeUnsigned(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, uint64_t data) { - HandlerStack ¤t = die_handlers_.top(); + 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); @@ -149,7 +149,7 @@ void DIEDispatcher::ProcessAttributeSigned(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, int64_t data) { - HandlerStack ¤t = die_handlers_.top(); + 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); @@ -159,7 +159,7 @@ void DIEDispatcher::ProcessAttributeReference(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, uint64_t data) { - HandlerStack ¤t = die_handlers_.top(); + 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); @@ -168,9 +168,9 @@ void DIEDispatcher::ProcessAttributeReference(uint64_t offset, void DIEDispatcher::ProcessAttributeBuffer(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, - const uint8_t *data, + const uint8_t* data, uint64_t len) { - HandlerStack ¤t = die_handlers_.top(); + 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); @@ -180,7 +180,7 @@ void DIEDispatcher::ProcessAttributeString(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, const string& data) { - HandlerStack ¤t = die_handlers_.top(); + 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); @@ -190,10 +190,10 @@ void DIEDispatcher::ProcessAttributeSignature(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, uint64_t signature) { - HandlerStack ¤t = die_handlers_.top(); + 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 +} // namespace google_breakpad diff --git a/src/common/dwarf/dwarf2diehandler.h b/src/common/dwarf/dwarf2diehandler.h index 871ba436..02c22853 100644 --- a/src/common/dwarf/dwarf2diehandler.h +++ b/src/common/dwarf/dwarf2diehandler.h @@ -1,6 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -12,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -166,7 +166,7 @@ #include "common/dwarf/dwarf2reader.h" #include "common/using_std_string.h" -namespace dwarf2reader { +namespace google_breakpad { // A base class for handlers for specific DIE types. The series of // calls made on a DIE handler is as follows: @@ -208,7 +208,7 @@ class DIEHandler { uint64_t data) { } virtual void ProcessAttributeBuffer(enum DwarfAttribute attr, enum DwarfForm form, - const uint8_t *data, + const uint8_t* data, uint64_t len) { } virtual void ProcessAttributeString(enum DwarfAttribute attr, enum DwarfForm form, @@ -244,7 +244,7 @@ class DIEHandler { // it is. // // The default definition skips all children. - virtual DIEHandler *FindChildHandler(uint64_t offset, enum DwarfTag tag) { + virtual DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag) { return NULL; } @@ -258,10 +258,13 @@ class DIEHandler { // A subclass of DIEHandler, with additional kludges for handling the // compilation unit's root die. -class RootDIEHandler: public DIEHandler { +class RootDIEHandler : public DIEHandler { public: - RootDIEHandler() { } - virtual ~RootDIEHandler() { } + bool handle_inline; + + explicit RootDIEHandler(bool handle_inline = false) + : handle_inline(handle_inline) {} + virtual ~RootDIEHandler() {} // We pass the values reported via Dwarf2Handler::StartCompilationUnit // to this member function, and skip the entire compilation unit if it @@ -288,7 +291,7 @@ class DIEDispatcher: public Dwarf2Handler { // 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) { } + DIEDispatcher(RootDIEHandler* root_handler) : root_handler_(root_handler) { } // Destroying a DIEDispatcher destroys all active handler objects // except the root handler. ~DIEDispatcher(); @@ -311,12 +314,12 @@ class DIEDispatcher: public Dwarf2Handler { void ProcessAttributeBuffer(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, - const uint8_t *data, + const uint8_t* data, uint64_t len); void ProcessAttributeString(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, - const string &data); + const string& data); void ProcessAttributeSignature(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, @@ -335,7 +338,7 @@ class DIEDispatcher: public Dwarf2Handler { // The handler object interested in this DIE's attributes and // children. If NULL, we're not interested in either. - DIEHandler *handler_; + DIEHandler* handler_; // Have we reported the end of this DIE's attributes to the handler? bool reported_attributes_end_; @@ -358,8 +361,8 @@ class DIEDispatcher: public Dwarf2Handler { // The root handler. We don't push it on die_handlers_ until we // actually get the StartDIE call for the root. - RootDIEHandler *root_handler_; + RootDIEHandler* root_handler_; }; -} // namespace dwarf2reader +} // namespace google_breakpad #endif // COMMON_DWARF_DWARF2DIEHANDLER_H__ diff --git a/src/common/dwarf/dwarf2diehandler_unittest.cc b/src/common/dwarf/dwarf2diehandler_unittest.cc index 01b70489..67c9489d 100644 --- a/src/common/dwarf/dwarf2diehandler_unittest.cc +++ b/src/common/dwarf/dwarf2diehandler_unittest.cc @@ -1,6 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -12,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -53,12 +53,12 @@ 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; +using google_breakpad::DIEDispatcher; +using google_breakpad::DIEHandler; +using google_breakpad::DwarfAttribute; +using google_breakpad::DwarfForm; +using google_breakpad::DwarfTag; +using google_breakpad::RootDIEHandler; class MockDIEHandler: public DIEHandler { public: @@ -69,9 +69,9 @@ class MockDIEHandler: public DIEHandler { MOCK_METHOD3(ProcessAttributeReference, void(DwarfAttribute, DwarfForm, uint64_t)); MOCK_METHOD4(ProcessAttributeBuffer, - void(DwarfAttribute, DwarfForm, const uint8_t *, uint64_t)); + void(DwarfAttribute, DwarfForm, const uint8_t*, uint64_t)); MOCK_METHOD3(ProcessAttributeString, - void(DwarfAttribute, DwarfForm, const string &)); + void(DwarfAttribute, DwarfForm, const string&)); MOCK_METHOD3(ProcessAttributeSignature, void(DwarfAttribute, DwarfForm, uint64_t)); MOCK_METHOD0(EndAttributes, bool()); @@ -88,9 +88,9 @@ class MockRootDIEHandler: public RootDIEHandler { MOCK_METHOD3(ProcessAttributeReference, void(DwarfAttribute, DwarfForm, uint64_t)); MOCK_METHOD4(ProcessAttributeBuffer, - void(DwarfAttribute, DwarfForm, const uint8_t *, uint64_t)); + void(DwarfAttribute, DwarfForm, const uint8_t*, uint64_t)); MOCK_METHOD3(ProcessAttributeString, - void(DwarfAttribute, DwarfForm, const string &)); + void(DwarfAttribute, DwarfForm, const string&)); MOCK_METHOD3(ProcessAttributeSignature, void(DwarfAttribute, DwarfForm, uint64_t)); MOCK_METHOD0(EndAttributes, bool()); @@ -339,7 +339,7 @@ TEST(Dwarf2DIEHandler, FindAndSkipChildren) { EXPECT_CALL(mock_root_handler, FindChildHandler(0x97412be24875de9dLL, (DwarfTag) 0x505a068b)) - .WillOnce(Return((DIEHandler *) NULL)); + .WillOnce(Return((DIEHandler*) NULL)); // Third child DIE. EXPECT_CALL(mock_root_handler, diff --git a/src/common/dwarf/dwarf2enums.h b/src/common/dwarf/dwarf2enums.h index 4316a89c..777d9bfc 100644 --- a/src/common/dwarf/dwarf2enums.h +++ b/src/common/dwarf/dwarf2enums.h @@ -1,6 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -12,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -31,7 +31,7 @@ #ifndef COMMON_DWARF_DWARF2ENUMS_H__ #define COMMON_DWARF_DWARF2ENUMS_H__ -namespace dwarf2reader { +namespace google_breakpad { // These enums do not follow the google3 style only because they are // known universally (specs, other implementations) by the names in @@ -95,6 +95,10 @@ enum DwarfTag { DW_TAG_unspecified_type = 0x3b, DW_TAG_partial_unit = 0x3c, DW_TAG_imported_unit = 0x3d, + // DWARF 4. + DW_TAG_type_unit = 0x41, + // DWARF 5. + DW_TAG_skeleton_unit = 0x4a, // SGI/MIPS Extensions. DW_TAG_MIPS_loop = 0x4081, // HP extensions. See: @@ -115,6 +119,16 @@ enum DwarfTag { DW_TAG_PGI_interface_block = 0xA020 }; +enum DwarfUnitHeader { + DW_UT_compile = 0x01, + DW_UT_type = 0x02, + DW_UT_partial = 0x03, + DW_UT_skeleton = 0x04, + DW_UT_split_compile = 0x05, + DW_UT_split_type = 0x06, + DW_UT_lo_user = 0x80, + DW_UT_hi_user = 0xFF +}; enum DwarfHasChild { DW_children_no = 0, @@ -149,7 +163,33 @@ enum DwarfForm { DW_FORM_sec_offset = 0x17, DW_FORM_exprloc = 0x18, DW_FORM_flag_present = 0x19, + + // Added in DWARF 5: + DW_FORM_strx = 0x1a, + DW_FORM_addrx = 0x1b, + DW_FORM_ref_sup4 = 0x1c, + DW_FORM_strp_sup = 0x1d, + DW_FORM_data16 = 0x1e, + DW_FORM_line_strp = 0x1f, + + // DWARF 4, but value out of order. DW_FORM_ref_sig8 = 0x20, + + // Added in DWARF 5: + DW_FORM_implicit_const = 0x21, + DW_FORM_loclistx = 0x22, + DW_FORM_rnglistx = 0x23, + DW_FORM_ref_sup8 = 0x24, + DW_FORM_strx1 = 0x25, + DW_FORM_strx2 = 0x26, + DW_FORM_strx3 = 0x27, + DW_FORM_strx4 = 0x28, + + DW_FORM_addrx1 = 0x29, + DW_FORM_addrx2 = 0x2a, + DW_FORM_addrx3 = 0x2b, + DW_FORM_addrx4 = 0x2c, + // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. DW_FORM_GNU_addr_index = 0x1f01, DW_FORM_GNU_str_index = 0x1f02 @@ -234,6 +274,11 @@ enum DwarfAttribute { DW_AT_call_line = 0x59, // DWARF 4 DW_AT_linkage_name = 0x6e, + // DWARF 5 + DW_AT_str_offsets_base = 0x72, + DW_AT_addr_base = 0x73, + DW_AT_rnglists_base = 0x74, + DW_AT_dwo_name = 0x76, // SGI/MIPS extensions. DW_AT_MIPS_fde = 0x2001, DW_AT_MIPS_loop_begin = 0x2002, @@ -286,6 +331,26 @@ enum DwarfAttribute { DW_AT_PGI_lstride = 0x3a02 }; +// .debug_rngslist entry types +enum DwarfRngListEntry { + DW_RLE_end_of_list = 0, + DW_RLE_base_addressx = 1, + DW_RLE_startx_endx = 2, + DW_RLE_startx_length = 3, + DW_RLE_offset_pair = 4, + DW_RLE_base_address = 5, + DW_RLE_start_end = 6, + DW_RLE_start_length = 7, +}; + +// Line number content type codes (DWARF 5). +enum DwarfLineNumberContentType { + DW_LNCT_path = 1, + DW_LNCT_directory_index = 2, + DW_LNCT_timestamp = 3, + DW_LNCT_size = 4, + DW_LNCT_MD5 = 5, +}; // Line number opcodes. enum DwarfLineNumberOps { @@ -675,5 +740,5 @@ enum DwarfPointerEncoding DW_EH_PE_indirect = 0x80 }; -} // namespace dwarf2reader +} // namespace google_breakpad #endif // COMMON_DWARF_DWARF2ENUMS_H__ diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc index 6b9ce2b4..b191d78c 100644 --- a/src/common/dwarf/dwarf2reader.cc +++ b/src/common/dwarf/dwarf2reader.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -28,16 +28,16 @@ // 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. +// Implementation of LineInfo, CompilationUnit, +// and CallFrameInfo. See dwarf2reader.h for details. #include "common/dwarf/dwarf2reader.h" -#include <assert.h> #include <stdint.h> #include <stdio.h> #include <string.h> +#include <algorithm> #include <map> #include <memory> #include <stack> @@ -52,7 +52,19 @@ #include "common/using_std_string.h" #include "google_breakpad/common/breakpad_types.h" -namespace dwarf2reader { +namespace google_breakpad { + +const SectionMap::const_iterator GetSectionByName(const SectionMap& + sections, const char *name) { + assert(name[0] == '.'); + auto iter = sections.find(name); + if (iter != sections.end()) + return iter; + std::string macho_name("__"); + macho_name += name + 1; + iter = sections.find(macho_name); + return iter; +} CompilationUnit::CompilationUnit(const string& path, const SectionMap& sections, uint64_t offset, @@ -60,11 +72,12 @@ CompilationUnit::CompilationUnit(const string& path, : path_(path), offset_from_section_start_(offset), reader_(reader), sections_(sections), handler_(handler), abbrevs_(), string_buffer_(NULL), string_buffer_length_(0), + line_string_buffer_(NULL), line_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_(), + is_split_dwarf_(false), is_type_unit_(false), dwo_id_(0), dwo_name_(), skeleton_dwo_id_(0), ranges_base_(0), addr_base_(0), - have_checked_for_dwp_(false), dwp_path_(), + str_offsets_base_(0), have_checked_for_dwp_(false), dwp_path_(), dwp_byte_reader_(), dwp_reader_() {} // Initialize a compilation unit from a .dwo or .dwp file. @@ -99,12 +112,9 @@ 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"); + // First get the debug_abbrev section. + SectionMap::const_iterator iter = + GetSectionByName(sections_, ".debug_abbrev"); assert(iter != sections_.end()); abbrevs_ = new std::vector<Abbrev>; @@ -113,17 +123,20 @@ void CompilationUnit::ReadAbbrevs() { // 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 + + const uint8_t* abbrev_start = iter->second.first + header_.abbrev_offset; - const uint8_t *abbrevptr = abbrev_start; + const uint8_t* abbrevptr = abbrev_start; #ifndef NDEBUG const uint64_t abbrev_length = iter->second.second - header_.abbrev_offset; #endif + uint64_t highest_number = 0; + while (1) { CompilationUnit::Abbrev abbrev; size_t len; const uint64_t number = reader_->ReadUnsignedLEB128(abbrevptr, &len); + highest_number = std::max(highest_number, number); if (number == 0) break; @@ -151,29 +164,42 @@ void CompilationUnit::ReadAbbrevs() { 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)); + uint64_t value = 0; + if (formtemp == DW_FORM_implicit_const) { + value = reader_->ReadUnsignedLEB128(abbrevptr, &len); + abbrevptr += len; + } + AttrForm abbrev_attr(static_cast<enum DwarfAttribute>(nametemp), + static_cast<enum DwarfForm>(formtemp), + value); + abbrev.attributes.push_back(abbrev_attr); } - assert(abbrev.number == abbrevs_->size()); abbrevs_->push_back(abbrev); } + + // Account of cases where entries are out of order. + std::sort(abbrevs_->begin(), abbrevs_->end(), + [](const CompilationUnit::Abbrev& lhs, const CompilationUnit::Abbrev& rhs) { + return lhs.number < rhs.number; + }); + + // Ensure that there are no missing sections. + assert(abbrevs_->size() == highest_number + 1); } // Skips a single DIE's attributes. -const uint8_t *CompilationUnit::SkipDIE(const uint8_t* start, +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); + start = SkipAttribute(start, i->form_); } return start; } // Skips a single attribute form's data. -const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start, +const uint8_t* CompilationUnit::SkipAttribute(const uint8_t* start, enum DwarfForm form) { size_t len; @@ -185,27 +211,45 @@ const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start, return SkipAttribute(start, form); case DW_FORM_flag_present: + case DW_FORM_implicit_const: return start; + case DW_FORM_addrx1: case DW_FORM_data1: case DW_FORM_flag: case DW_FORM_ref1: + case DW_FORM_strx1: return start + 1; + case DW_FORM_addrx2: case DW_FORM_ref2: case DW_FORM_data2: + case DW_FORM_strx2: return start + 2; + case DW_FORM_addrx3: + case DW_FORM_strx3: + return start + 3; + case DW_FORM_addrx4: case DW_FORM_ref4: case DW_FORM_data4: + case DW_FORM_strx4: + case DW_FORM_ref_sup4: return start + 4; case DW_FORM_ref8: case DW_FORM_data8: case DW_FORM_ref_sig8: + case DW_FORM_ref_sup8: return start + 8; + case DW_FORM_data16: + return start + 16; case DW_FORM_string: - return start + strlen(reinterpret_cast<const char *>(start)) + 1; + return start + strlen(reinterpret_cast<const char*>(start)) + 1; case DW_FORM_udata: case DW_FORM_ref_udata: + case DW_FORM_strx: case DW_FORM_GNU_str_index: case DW_FORM_GNU_addr_index: + case DW_FORM_addrx: + case DW_FORM_rnglistx: + case DW_FORM_loclistx: reader_->ReadUnsignedLEB128(start, &len); return start + len; @@ -237,6 +281,8 @@ const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start, return start + size + len; } case DW_FORM_strp: + case DW_FORM_line_strp: + case DW_FORM_strp_sup: case DW_FORM_sec_offset: return start + reader_->OffsetSize(); } @@ -244,13 +290,52 @@ const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start, 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. +// Read the abbreviation offset from a compilation unit header. +size_t CompilationUnit::ReadAbbrevOffset(const uint8_t* headerptr) { + assert(headerptr + reader_->OffsetSize() < buffer_ + buffer_length_); + header_.abbrev_offset = reader_->ReadOffset(headerptr); + return reader_->OffsetSize(); +} + +// Read the address size from a compilation unit header. +size_t CompilationUnit::ReadAddressSize(const uint8_t* headerptr) { + // 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); + return 1; +} + +// Read the DWO id from a split or skeleton compilation unit header. +size_t CompilationUnit::ReadDwoId(const uint8_t* headerptr) { + assert(headerptr + 8 <= buffer_ + buffer_length_); + dwo_id_ = reader_->ReadEightBytes(headerptr); + return 8; +} + +// Read the type signature from a type or split type compilation unit header. +size_t CompilationUnit::ReadTypeSignature(const uint8_t* headerptr) { + assert(headerptr + 8 <= buffer_ + buffer_length_); + type_signature_ = reader_->ReadEightBytes(headerptr); + return 8; +} + +// Read the DWO id from a split or skeleton compilation unit header. +size_t CompilationUnit::ReadTypeOffset(const uint8_t* headerptr) { + assert(headerptr + reader_->OffsetSize() < buffer_ + buffer_length_); + type_offset_ = reader_->ReadOffset(headerptr); + return reader_->OffsetSize(); +} + + +// Read a DWARF header. The header is variable length in DWARF3 and DWARF4 +// (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. DWARF5 adds a unit_type to distinguish +// between partial-, full-, skeleton-, split-, and type- compilation units. void CompilationUnit::ReadHeader() { - const uint8_t *headerptr = buffer_; + const uint8_t* headerptr = buffer_; size_t initial_length_size; assert(headerptr + 4 < buffer_ + buffer_length_); @@ -263,17 +348,37 @@ void CompilationUnit::ReadHeader() { 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; - + if (header_.version <= 4) { + // Older versions of dwarf have a relatively simple structure. + headerptr += ReadAbbrevOffset(headerptr); + headerptr += ReadAddressSize(headerptr); + } else { + // DWARF5 adds a unit_type field, and various fields based on unit_type. + assert(headerptr + 1 < buffer_ + buffer_length_); + uint8_t unit_type = reader_->ReadOneByte(headerptr); + headerptr += 1; + headerptr += ReadAddressSize(headerptr); + headerptr += ReadAbbrevOffset(headerptr); + switch (unit_type) { + case DW_UT_compile: + case DW_UT_partial: + // nothing else to read + break; + case DW_UT_skeleton: + case DW_UT_split_compile: + headerptr += ReadDwoId(headerptr); + break; + case DW_UT_type: + case DW_UT_split_type: + is_type_unit_ = true; + headerptr += ReadTypeSignature(headerptr); + headerptr += ReadTypeOffset(headerptr); + break; + default: + fprintf(stderr, "Unhandled compilation unit type 0x%x", unit_type); + break; + } + } after_header_ = headerptr; // This check ensures that we don't have to do checking during the @@ -284,12 +389,9 @@ void CompilationUnit::ReadHeader() { } uint64_t 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"); + // First get the debug_info section. + SectionMap::const_iterator iter = + GetSectionByName(sections_, ".debug_info"); assert(iter != sections_.end()); // Set up our buffer @@ -315,30 +417,35 @@ uint64_t CompilationUnit::Start() { header_.length, header_.version)) return ourlength; + else if (header_.version == 5 && is_type_unit_) + 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"); + // Set the string section if we have one. + iter = GetSectionByName(sections_, ".debug_str"); if (iter != sections_.end()) { string_buffer_ = iter->second.first; string_buffer_length_ = iter->second.second; } + // Set the line string section if we have one. + iter = GetSectionByName(sections_, ".debug_line_str"); + if (iter != sections_.end()) { + line_string_buffer_ = iter->second.first; + line_string_buffer_length_ = iter->second.second; + } + // Set the string offsets section if we have one. - iter = sections_.find(".debug_str_offsets"); + iter = GetSectionByName(sections_, ".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"); + iter = GetSectionByName(sections_, ".debug_addr"); if (iter != sections_.end()) { addr_buffer_ = iter->second.first; addr_buffer_length_ = iter->second.second; @@ -358,12 +465,189 @@ uint64_t CompilationUnit::Start() { return ourlength; } +void CompilationUnit::ProcessFormStringIndex( + uint64_t dieoffset, enum DwarfAttribute attr, enum DwarfForm form, + uint64_t str_index) { + const size_t kStringOffsetsTableHeaderSize = + header_.version >= 5 ? (reader_->OffsetSize() == 8 ? 16 : 8) : 0; + const uint8_t* str_offsets_table_after_header = str_offsets_base_ ? + str_offsets_buffer_ + str_offsets_base_ : + str_offsets_buffer_ + kStringOffsetsTableHeaderSize; + const uint8_t* offset_ptr = + str_offsets_table_after_header + str_index * reader_->OffsetSize(); + + const uint64_t offset = reader_->ReadOffset(offset_ptr); + if (offset >= string_buffer_length_) { + return; + } + + const char* str = reinterpret_cast<const char*>(string_buffer_) + offset; + ProcessAttributeString(dieoffset, attr, form, str); +} + +// Special function for pre-processing the +// DW_AT_str_offsets_base and DW_AT_addr_base in a DW_TAG_compile_unit die (for +// DWARF v5). We must make sure to find and process the +// DW_AT_str_offsets_base and DW_AT_addr_base attributes before attempting to +// read any string and address attribute in the compile unit. +const uint8_t* CompilationUnit::ProcessOffsetBaseAttribute( + uint64_t dieoffset, const uint8_t* start, enum DwarfAttribute attr, + enum DwarfForm form, uint64_t implicit_const) { + 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 ProcessOffsetBaseAttribute(dieoffset, start, attr, form, + implicit_const); + + case DW_FORM_flag_present: + return start; + case DW_FORM_data1: + case DW_FORM_flag: + return start + 1; + case DW_FORM_data2: + return start + 2; + case DW_FORM_data4: + return start + 4; + case DW_FORM_data8: + return start + 8; + case DW_FORM_data16: + // This form is designed for an md5 checksum inside line tables. + return start + 16; + case DW_FORM_string: { + const char* str = reinterpret_cast<const char*>(start); + return start + strlen(str) + 1; + } + case DW_FORM_udata: + reader_->ReadUnsignedLEB128(start, &len); + return start + len; + case DW_FORM_sdata: + reader_->ReadSignedLEB128(start, &len); + return start + len; + case DW_FORM_addr: + reader_->ReadAddress(start); + return start + reader_->AddressSize(); + + // This is the important one here! + case DW_FORM_sec_offset: + if (attr == DW_AT_str_offsets_base || + attr == DW_AT_addr_base) + ProcessAttributeUnsigned(dieoffset, attr, form, + reader_->ReadOffset(start)); + else + reader_->ReadOffset(start); + return start + reader_->OffsetSize(); + + case DW_FORM_ref1: + return start + 1; + case DW_FORM_ref2: + return start + 2; + case DW_FORM_ref4: + return start + 4; + case DW_FORM_ref8: + return start + 8; + case DW_FORM_ref_udata: + reader_->ReadUnsignedLEB128(start, &len); + 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) { + reader_->ReadAddress(start); + return start + reader_->AddressSize(); + } else if (header_.version >= 3) { + reader_->ReadOffset(start); + return start + reader_->OffsetSize(); + } + break; + case DW_FORM_ref_sig8: + return start + 8; + case DW_FORM_implicit_const: + return start; + case DW_FORM_block1: { + uint64_t datalen = reader_->ReadOneByte(start); + return start + 1 + datalen; + } + case DW_FORM_block2: { + uint64_t datalen = reader_->ReadTwoBytes(start); + return start + 2 + datalen; + } + case DW_FORM_block4: { + uint64_t datalen = reader_->ReadFourBytes(start); + return start + 4 + datalen; + } + case DW_FORM_block: + case DW_FORM_exprloc: { + uint64_t datalen = reader_->ReadUnsignedLEB128(start, &len); + return start + datalen + len; + } + case DW_FORM_strp: { + reader_->ReadOffset(start); + return start + reader_->OffsetSize(); + } + case DW_FORM_line_strp: { + reader_->ReadOffset(start); + return start + reader_->OffsetSize(); + } + case DW_FORM_strp_sup: + return start + 4; + case DW_FORM_ref_sup4: + return start + 4; + case DW_FORM_ref_sup8: + return start + 8; + case DW_FORM_loclistx: + reader_->ReadUnsignedLEB128(start, &len); + return start + len; + case DW_FORM_strx: + case DW_FORM_GNU_str_index: { + reader_->ReadUnsignedLEB128(start, &len); + return start + len; + } + case DW_FORM_strx1: { + return start + 1; + } + case DW_FORM_strx2: { + return start + 2; + } + case DW_FORM_strx3: { + return start + 3; + } + case DW_FORM_strx4: { + return start + 4; + } + + case DW_FORM_addrx: + case DW_FORM_GNU_addr_index: + reader_->ReadUnsignedLEB128(start, &len); + return start + len; + case DW_FORM_addrx1: + return start + 1; + case DW_FORM_addrx2: + return start + 2; + case DW_FORM_addrx3: + return start + 3; + case DW_FORM_addrx4: + return start + 4; + case DW_FORM_rnglistx: + reader_->ReadUnsignedLEB128(start, &len); + return start + len; + } + fprintf(stderr, "Unhandled form type\n"); + return NULL; +} + // 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_t dieoffset, const uint8_t *start, enum DwarfAttribute attr, - enum DwarfForm form) { +const uint8_t* CompilationUnit::ProcessAttribute( + uint64_t dieoffset, const uint8_t* start, enum DwarfAttribute attr, + enum DwarfForm form, uint64_t implicit_const) { size_t len; switch (form) { @@ -373,7 +657,7 @@ const uint8_t *CompilationUnit::ProcessAttribute( form = static_cast<enum DwarfForm>(reader_->ReadUnsignedLEB128(start, &len)); start += len; - return ProcessAttribute(dieoffset, start, attr, form); + return ProcessAttribute(dieoffset, start, attr, form, implicit_const); case DW_FORM_flag_present: ProcessAttributeUnsigned(dieoffset, attr, form, 1); @@ -395,8 +679,12 @@ const uint8_t *CompilationUnit::ProcessAttribute( ProcessAttributeUnsigned(dieoffset, attr, form, reader_->ReadEightBytes(start)); return start + 8; + case DW_FORM_data16: + // This form is designed for an md5 checksum inside line tables. + fprintf(stderr, "Unhandled form type: DW_FORM_data16\n"); + return start + 16; case DW_FORM_string: { - const char *str = reinterpret_cast<const char *>(start); + const char* str = reinterpret_cast<const char*>(start); ProcessAttributeString(dieoffset, attr, form, str); return start + strlen(str) + 1; } @@ -462,7 +750,10 @@ const uint8_t *CompilationUnit::ProcessAttribute( handler_->ProcessAttributeSignature(dieoffset, attr, form, reader_->ReadEightBytes(start)); return start + 8; - + case DW_FORM_implicit_const: + handler_->ProcessAttributeUnsigned(dieoffset, attr, form, + implicit_const); + return start; case DW_FORM_block1: { uint64_t datalen = reader_->ReadOneByte(start); handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 1, @@ -494,45 +785,118 @@ const uint8_t *CompilationUnit::ProcessAttribute( const uint64_t offset = reader_->ReadOffset(start); assert(string_buffer_ + offset < string_buffer_ + string_buffer_length_); - const char *str = reinterpret_cast<const char *>(string_buffer_ + offset); + const char* str = reinterpret_cast<const char*>(string_buffer_ + offset); ProcessAttributeString(dieoffset, attr, form, str); return start + reader_->OffsetSize(); } + case DW_FORM_line_strp: { + assert(line_string_buffer_ != NULL); - case DW_FORM_GNU_str_index: { - uint64_t str_index = reader_->ReadUnsignedLEB128(start, &len); - const uint8_t* offset_ptr = - str_offsets_buffer_ + str_index * reader_->OffsetSize(); - const uint64_t offset = reader_->ReadOffset(offset_ptr); - if (offset >= string_buffer_length_) { - return NULL; - } + const uint64_t offset = reader_->ReadOffset(start); + assert(line_string_buffer_ + offset < + line_string_buffer_ + line_string_buffer_length_); - const char* str = reinterpret_cast<const char *>(string_buffer_) + offset; + const char* str = + reinterpret_cast<const char*>(line_string_buffer_ + offset); ProcessAttributeString(dieoffset, attr, form, str); - return start + len; - break; + return start + reader_->OffsetSize(); } - case DW_FORM_GNU_addr_index: { - uint64_t addr_index = reader_->ReadUnsignedLEB128(start, &len); - const uint8_t* addr_ptr = - addr_buffer_ + addr_base_ + addr_index * reader_->AddressSize(); + case DW_FORM_strp_sup: + // No support currently for suplementary object files. + fprintf(stderr, "Unhandled form type: DW_FORM_strp_sup\n"); + return start + 4; + case DW_FORM_ref_sup4: + // No support currently for suplementary object files. + fprintf(stderr, "Unhandled form type: DW_FORM_ref_sup4\n"); + return start + 4; + case DW_FORM_ref_sup8: + // No support currently for suplementary object files. + fprintf(stderr, "Unhandled form type: DW_FORM_ref_sup8\n"); + return start + 8; + case DW_FORM_loclistx: ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadAddress(addr_ptr)); + reader_->ReadUnsignedLEB128(start, &len)); return start + len; + case DW_FORM_strx: + case DW_FORM_GNU_str_index: { + uint64_t str_index = reader_->ReadUnsignedLEB128(start, &len); + ProcessFormStringIndex(dieoffset, attr, form, str_index); + return start + len; + } + case DW_FORM_strx1: { + uint64_t str_index = reader_->ReadOneByte(start); + ProcessFormStringIndex(dieoffset, attr, form, str_index); + return start + 1; + } + case DW_FORM_strx2: { + uint64_t str_index = reader_->ReadTwoBytes(start); + ProcessFormStringIndex(dieoffset, attr, form, str_index); + return start + 2; + } + case DW_FORM_strx3: { + uint64_t str_index = reader_->ReadThreeBytes(start); + ProcessFormStringIndex(dieoffset, attr, form, str_index); + return start + 3; + } + case DW_FORM_strx4: { + uint64_t str_index = reader_->ReadFourBytes(start); + ProcessFormStringIndex(dieoffset, attr, form, str_index); + return start + 4; } + + case DW_FORM_addrx: + case DW_FORM_GNU_addr_index: + ProcessAttributeAddrIndex( + dieoffset, attr, form, reader_->ReadUnsignedLEB128(start, &len)); + return start + len; + case DW_FORM_addrx1: + ProcessAttributeAddrIndex( + dieoffset, attr, form, reader_->ReadOneByte(start)); + return start + 1; + case DW_FORM_addrx2: + ProcessAttributeAddrIndex( + dieoffset, attr, form, reader_->ReadTwoBytes(start)); + return start + 2; + case DW_FORM_addrx3: + ProcessAttributeAddrIndex( + dieoffset, attr, form, reader_->ReadThreeBytes(start)); + return start + 3; + case DW_FORM_addrx4: + ProcessAttributeAddrIndex( + dieoffset, attr, form, reader_->ReadFourBytes(start)); + return start + 4; + case DW_FORM_rnglistx: + ProcessAttributeUnsigned( + dieoffset, attr, form, reader_->ReadUnsignedLEB128(start, &len)); + return start + len; } fprintf(stderr, "Unhandled form type\n"); return NULL; } -const uint8_t *CompilationUnit::ProcessDIE(uint64_t dieoffset, - const uint8_t *start, +const uint8_t* CompilationUnit::ProcessDIE(uint64_t dieoffset, + const uint8_t* start, const Abbrev& abbrev) { + // With DWARF v5, the compile_unit die may contain a + // DW_AT_str_offsets_base or DW_AT_addr_base. If it does, that attribute must + // be found and processed before trying to process the other attributes; + // otherwise the string or address values will all come out incorrect. + if (abbrev.tag == DW_TAG_compile_unit && header_.version == 5) { + uint64_t dieoffset_copy = dieoffset; + const uint8_t* start_copy = start; + for (AttributeList::const_iterator i = abbrev.attributes.begin(); + i != abbrev.attributes.end(); + i++) { + start_copy = ProcessOffsetBaseAttribute(dieoffset_copy, start_copy, + i->attr_, i->form_, + i->value_); + } + } + for (AttributeList::const_iterator i = abbrev.attributes.begin(); i != abbrev.attributes.end(); i++) { - start = ProcessAttribute(dieoffset, start, i->first, i->second); + start = ProcessAttribute(dieoffset, start, i->attr_, i->form_, i->value_); } // If this is a compilation unit in a split DWARF object, verify that @@ -548,12 +912,12 @@ const uint8_t *CompilationUnit::ProcessDIE(uint64_t dieoffset, } void CompilationUnit::ProcessDIEs() { - const uint8_t *dieptr = after_header_; + 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_; + const uint8_t* lengthstart = buffer_; // In 64 bit dwarf, the initial length is 12 bytes, because of the // 0xffffffff at the start. @@ -563,7 +927,7 @@ void CompilationUnit::ProcessDIEs() { lengthstart += 4; std::stack<uint64_t> 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. @@ -589,8 +953,23 @@ void CompilationUnit::ProcessDIEs() { const enum DwarfTag tag = abbrev.tag; if (!handler_->StartDIE(absolute_offset, tag)) { dieptr = SkipDIE(dieptr, abbrev); + if (!dieptr) { + fprintf(stderr, + "An error happens when skipping a DIE's attributes at offset " + "0x%" PRIx64 + ". Stopped processing following DIEs in this CU.\n", + absolute_offset); + exit(1); + } } else { dieptr = ProcessDIE(absolute_offset, dieptr, abbrev); + if (!dieptr) { + fprintf(stderr, + "An error happens when processing a DIE at offset 0x%" PRIx64 + ". Stopped processing following DIEs in this CU.\n", + absolute_offset); + exit(1); + } } if (abbrev.has_children) { @@ -691,7 +1070,7 @@ void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader, if (section_data != NULL) sections->insert(std::make_pair( base_name, std::make_pair( - reinterpret_cast<const uint8_t *>(section_data), + reinterpret_cast<const uint8_t*>(section_data), section_size))); } } @@ -720,11 +1099,11 @@ void DwpReader::Initialize() { &string_buffer_size_); version_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_)); + reinterpret_cast<const uint8_t*>(cu_index_)); if (version_ == 1) { nslots_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) + reinterpret_cast<const uint8_t*>(cu_index_) + 3 * sizeof(uint32_t)); phash_ = cu_index_ + 4 * sizeof(uint32_t); pindex_ = phash_ + nslots_ * sizeof(uint64_t); @@ -732,13 +1111,13 @@ void DwpReader::Initialize() { if (shndx_pool_ >= cu_index_ + cu_index_size_) { version_ = 0; } - } else if (version_ == 2) { + } else if (version_ == 2 || version_ == 5) { ncolumns_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) + sizeof(uint32_t)); + reinterpret_cast<const uint8_t*>(cu_index_) + sizeof(uint32_t)); nunits_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) + 2 * sizeof(uint32_t)); + reinterpret_cast<const uint8_t*>(cu_index_) + 2 * sizeof(uint32_t)); nslots_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) + 3 * sizeof(uint32_t)); + reinterpret_cast<const uint8_t*>(cu_index_) + 3 * sizeof(uint32_t)); phash_ = cu_index_ + 4 * sizeof(uint32_t); pindex_ = phash_ + nslots_ * sizeof(uint64_t); offset_table_ = pindex_ + nslots_ * sizeof(uint32_t); @@ -766,7 +1145,7 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id, // 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_) + reinterpret_cast<const uint8_t*>(pindex_) + slot * sizeof(uint32_t)); const char* shndx_list = shndx_pool_ + index * sizeof(uint32_t); for (;;) { @@ -775,7 +1154,7 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id, return; } unsigned int shndx = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(shndx_list)); + reinterpret_cast<const uint8_t*>(shndx_list)); shndx_list += sizeof(uint32_t); if (shndx == 0) break; @@ -789,28 +1168,28 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id, section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); sections->insert(std::make_pair( ".debug_abbrev", - std::make_pair(reinterpret_cast<const uint8_t *> (section_data), + std::make_pair(reinterpret_cast<const uint8_t*> (section_data), section_size))); } else if (!strncmp(section_name, ".debug_info", strlen(".debug_info"))) { section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); sections->insert(std::make_pair( ".debug_info", - std::make_pair(reinterpret_cast<const uint8_t *> (section_data), + std::make_pair(reinterpret_cast<const uint8_t*> (section_data), section_size))); } else if (!strncmp(section_name, ".debug_str_offsets", strlen(".debug_str_offsets"))) { section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); sections->insert(std::make_pair( ".debug_str_offsets", - std::make_pair(reinterpret_cast<const uint8_t *> (section_data), + 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_), + std::make_pair(reinterpret_cast<const uint8_t*> (string_buffer_), string_buffer_size_))); - } else if (version_ == 2) { + } else if (version_ == 2 || version_ == 5) { uint32_t index = LookupCUv2(dwo_id); if (index == 0) { return; @@ -833,33 +1212,33 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id, } for (unsigned int col = 0u; col < ncolumns_; ++col) { uint32_t section_id = - byte_reader_.ReadFourBytes(reinterpret_cast<const uint8_t *>(id_row) + byte_reader_.ReadFourBytes(reinterpret_cast<const uint8_t*>(id_row) + col * sizeof(uint32_t)); uint32_t offset = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(offset_row) + reinterpret_cast<const uint8_t*>(offset_row) + col * sizeof(uint32_t)); uint32_t size = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(size_row) + col * sizeof(uint32_t)); + reinterpret_cast<const uint8_t*>(size_row) + col * sizeof(uint32_t)); if (section_id == DW_SECT_ABBREV) { sections->insert(std::make_pair( ".debug_abbrev", - std::make_pair(reinterpret_cast<const uint8_t *> (abbrev_data_) + 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_) + 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_) + 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_), + std::make_pair(reinterpret_cast<const uint8_t*> (string_buffer_), string_buffer_size_))); } } @@ -867,14 +1246,14 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id, int DwpReader::LookupCU(uint64_t dwo_id) { uint32_t slot = static_cast<uint32_t>(dwo_id) & (nslots_ - 1); uint64_t probe = byte_reader_.ReadEightBytes( - reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64_t)); + reinterpret_cast<const uint8_t*>(phash_) + slot * sizeof(uint64_t)); if (probe != 0 && probe != dwo_id) { uint32_t secondary_hash = (static_cast<uint32_t>(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_t)); + reinterpret_cast<const uint8_t*>(phash_) + slot * sizeof(uint64_t)); } while (probe != 0 && probe != dwo_id); } if (probe == 0) @@ -885,28 +1264,35 @@ int DwpReader::LookupCU(uint64_t dwo_id) { uint32_t DwpReader::LookupCUv2(uint64_t dwo_id) { uint32_t slot = static_cast<uint32_t>(dwo_id) & (nslots_ - 1); uint64_t probe = byte_reader_.ReadEightBytes( - reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64_t)); + reinterpret_cast<const uint8_t*>(phash_) + slot * sizeof(uint64_t)); uint32_t index = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32_t)); + reinterpret_cast<const uint8_t*>(pindex_) + slot * sizeof(uint32_t)); if (index != 0 && probe != dwo_id) { uint32_t secondary_hash = (static_cast<uint32_t>(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_t)); + reinterpret_cast<const uint8_t*>(phash_) + slot * sizeof(uint64_t)); index = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32_t)); + reinterpret_cast<const uint8_t*>(pindex_) + slot * sizeof(uint32_t)); } while (index != 0 && probe != dwo_id); } return index; } -LineInfo::LineInfo(const uint8_t *buffer, uint64_t buffer_length, - ByteReader* reader, LineInfoHandler* handler): - handler_(handler), reader_(reader), buffer_(buffer) { +LineInfo::LineInfo(const uint8_t* buffer, uint64_t buffer_length, + ByteReader* reader, const uint8_t* string_buffer, + size_t string_buffer_length, + const uint8_t* line_string_buffer, + size_t line_string_buffer_length, LineInfoHandler* handler): + handler_(handler), reader_(reader), buffer_(buffer), + string_buffer_(string_buffer), + line_string_buffer_(line_string_buffer) { #ifndef NDEBUG buffer_length_ = buffer_length; + string_buffer_length_ = string_buffer_length; + line_string_buffer_length_ = line_string_buffer_length; #endif header_.std_opcode_lengths = NULL; } @@ -917,10 +1303,132 @@ uint64_t LineInfo::Start() { return after_header_ - buffer_; } +void LineInfo::ReadTypesAndForms(const uint8_t** lineptr, + uint32_t* content_types, + uint32_t* content_forms, + uint32_t max_types, + uint32_t* format_count) { + size_t len; + + uint32_t count = reader_->ReadUnsignedLEB128(*lineptr, &len); + *lineptr += len; + if (count < 1 || count > max_types) { + return; + } + for (uint32_t col = 0; col < count; ++col) { + content_types[col] = reader_->ReadUnsignedLEB128(*lineptr, &len); + *lineptr += len; + content_forms[col] = reader_->ReadUnsignedLEB128(*lineptr, &len); + *lineptr += len; + } + *format_count = count; +} + +const char* LineInfo::ReadStringForm(uint32_t form, const uint8_t** lineptr) { + const char* name = nullptr; + if (form == DW_FORM_string) { + name = reinterpret_cast<const char*>(*lineptr); + *lineptr += strlen(name) + 1; + return name; + } else if (form == DW_FORM_strp) { + uint64_t offset = reader_->ReadOffset(*lineptr); + assert(offset < string_buffer_length_); + *lineptr += reader_->OffsetSize(); + if (string_buffer_ != nullptr) { + name = reinterpret_cast<const char*>(string_buffer_) + offset; + return name; + } + } else if (form == DW_FORM_line_strp) { + uint64_t offset = reader_->ReadOffset(*lineptr); + assert(offset < line_string_buffer_length_); + *lineptr += reader_->OffsetSize(); + if (line_string_buffer_ != nullptr) { + name = reinterpret_cast<const char*>(line_string_buffer_) + offset; + return name; + } + } + // Shouldn't be called with a non-string-form, and + // if there is a string form but no string buffer, + // that is a problem too. + assert(0); + return nullptr; +} + +uint64_t LineInfo::ReadUnsignedData(uint32_t form, const uint8_t** lineptr) { + size_t len; + uint64_t value; + + switch (form) { + case DW_FORM_data1: + value = reader_->ReadOneByte(*lineptr); + *lineptr += 1; + return value; + case DW_FORM_data2: + value = reader_->ReadTwoBytes(*lineptr); + *lineptr += 2; + return value; + case DW_FORM_data4: + value = reader_->ReadFourBytes(*lineptr); + *lineptr += 4; + return value; + case DW_FORM_data8: + value = reader_->ReadEightBytes(*lineptr); + *lineptr += 8; + return value; + case DW_FORM_udata: + value = reader_->ReadUnsignedLEB128(*lineptr, &len); + *lineptr += len; + return value; + default: + fprintf(stderr, "Unrecognized data form."); + return 0; + } +} + +void LineInfo::ReadFileRow(const uint8_t** lineptr, + const uint32_t* content_types, + const uint32_t* content_forms, uint32_t row, + uint32_t format_count) { + const char* filename = nullptr; + uint64_t dirindex = 0; + uint64_t mod_time = 0; + uint64_t filelength = 0; + + for (uint32_t col = 0; col < format_count; ++col) { + switch (content_types[col]) { + case DW_LNCT_path: + filename = ReadStringForm(content_forms[col], lineptr); + break; + case DW_LNCT_directory_index: + dirindex = ReadUnsignedData(content_forms[col], lineptr); + break; + case DW_LNCT_timestamp: + mod_time = ReadUnsignedData(content_forms[col], lineptr); + break; + case DW_LNCT_size: + filelength = ReadUnsignedData(content_forms[col], lineptr); + break; + case DW_LNCT_MD5: + // MD5 entries help a debugger sort different versions of files with + // the same name. It is always paired with a DW_FORM_data16 and is + // unused in this case. + *lineptr += 16; + break; + default: + fprintf(stderr, "Unrecognized form in line table header. %d\n", + content_types[col]); + assert(false); + break; + } + } + assert(filename != nullptr); + handler_->DefineFile(filename, row, dirindex, mod_time, filelength); +} + // 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_; + const uint8_t* lineptr = buffer_; size_t initial_length_size; const uint64_t initial_length @@ -931,12 +1439,24 @@ void LineInfo::ReadHeader() { 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; + if (header_.version >= 5) { + uint8_t address_size = reader_->ReadOneByte(lineptr); + reader_->SetAddressSize(address_size); + lineptr += 1; + uint8_t segment_selector_size = reader_->ReadOneByte(lineptr); + if (segment_selector_size != 0) { + fprintf(stderr,"No support for segmented memory."); + } + lineptr += 1; + } else { + // Address size *must* be set by CU ahead of time. + assert(reader_->AddressSize() != 0); + } + header_.prologue_length = reader_->ReadOffset(lineptr); lineptr += reader_->OffsetSize(); @@ -970,53 +1490,96 @@ void LineInfo::ReadHeader() { lineptr += 1; } - // It is legal for the directory entry table to be empty. - if (*lineptr) { - uint32_t dirindex = 1; - while (*lineptr) { - const char *dirname = reinterpret_cast<const char *>(lineptr); - handler_->DefineDir(dirname, dirindex); - lineptr += strlen(dirname) + 1; - dirindex++; + if (header_.version <= 4) { + // Directory zero is assumed to be the compilation directory and special + // cased where used. It is not actually stored in the dwarf data. But an + // empty entry here avoids off-by-one errors elsewhere in the code. + handler_->DefineDir("", 0); + // It is legal for the directory entry table to be empty. + if (*lineptr) { + uint32_t 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_t fileindex = 1; + lineptr++; + // It is also legal for the file entry table to be empty. + + // Similarly for file zero. + handler_->DefineFile("", 0, 0, 0, 0); + if (*lineptr) { + uint32_t fileindex = 1; + size_t len; + while (*lineptr) { + const char* filename = ReadStringForm(DW_FORM_string, &lineptr); + + uint64_t dirindex = reader_->ReadUnsignedLEB128(lineptr, &len); + lineptr += len; + + uint64_t mod_time = reader_->ReadUnsignedLEB128(lineptr, &len); + lineptr += len; + + uint64_t filelength = reader_->ReadUnsignedLEB128(lineptr, &len); + lineptr += len; + handler_->DefineFile(filename, fileindex, + static_cast<uint32_t>(dirindex), mod_time, + filelength); + fileindex++; + } + } + lineptr++; + } else { + // Read the DWARF-5 directory table. + + // Dwarf5 supports five different types and forms per directory- and + // file-table entry. Theoretically, there could be duplicate entries + // in this table, but that would be quite unusual. + static const uint32_t kMaxTypesAndForms = 5; + uint32_t content_types[kMaxTypesAndForms]; + uint32_t content_forms[kMaxTypesAndForms]; + uint32_t format_count; size_t len; - while (*lineptr) { - const char *filename = reinterpret_cast<const char *>(lineptr); - lineptr += strlen(filename) + 1; - uint64_t dirindex = reader_->ReadUnsignedLEB128(lineptr, &len); - lineptr += len; + ReadTypesAndForms(&lineptr, content_types, content_forms, kMaxTypesAndForms, + &format_count); + uint32_t entry_count = reader_->ReadUnsignedLEB128(lineptr, &len); + lineptr += len; + for (uint32_t row = 0; row < entry_count; ++row) { + const char* dirname = nullptr; + for (uint32_t col = 0; col < format_count; ++col) { + // The path is the only relevant content type for this implementation. + if (content_types[col] == DW_LNCT_path) { + dirname = ReadStringForm(content_forms[col], &lineptr); + } + } + handler_->DefineDir(dirname, row); + } - uint64_t mod_time = reader_->ReadUnsignedLEB128(lineptr, &len); - lineptr += len; + // Read the DWARF-5 filename table. + ReadTypesAndForms(&lineptr, content_types, content_forms, kMaxTypesAndForms, + &format_count); + entry_count = reader_->ReadUnsignedLEB128(lineptr, &len); + lineptr += len; - uint64_t filelength = reader_->ReadUnsignedLEB128(lineptr, &len); - lineptr += len; - handler_->DefineFile(filename, fileindex, static_cast<uint32_t>(dirindex), - mod_time, filelength); - fileindex++; + for (uint32_t row = 0; row < entry_count; ++row) { + ReadFileRow(&lineptr, content_types, content_forms, row, format_count); } } - lineptr++; - after_header_ = lineptr; } /* static */ bool LineInfo::ProcessOneOpcode(ByteReader* reader, LineInfoHandler* handler, - const struct LineInfoHeader &header, - const uint8_t *start, + const struct LineInfoHeader& header, + const uint8_t* start, struct LineStateMachine* lsm, size_t* len, uintptr pc, - bool *lsm_passes_pc) { + bool* lsm_passes_pc) { size_t oplen = 0; size_t templen; uint8_t opcode = reader->ReadOneByte(start); @@ -1153,7 +1716,7 @@ bool LineInfo::ProcessOneOpcode(ByteReader* reader, } break; case DW_LNE_define_file: { - const char *filename = reinterpret_cast<const char *>(start); + const char* filename = reinterpret_cast<const char*>(start); templen = strlen(filename) + 1; start += templen; @@ -1170,7 +1733,7 @@ bool LineInfo::ProcessOneOpcode(ByteReader* reader, oplen += templen; if (handler) { - handler->DefineFile(filename, -1, static_cast<uint32_t>(dirindex), + handler->DefineFile(filename, -1, static_cast<uint32_t>(dirindex), mod_time, filelength); } } @@ -1200,7 +1763,7 @@ void LineInfo::ReadLines() { // 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_; + const uint8_t* lengthstart = buffer_; // In 64 bit dwarf, the initial length is 12 bytes, because of the // 0xffffffff at the start. @@ -1209,7 +1772,7 @@ void LineInfo::ReadLines() { else lengthstart += 4; - const uint8_t *lineptr = after_header_; + const uint8_t* lineptr = after_header_; lsm.Reset(header_.default_is_stmt); // The LineInfoHandler interface expects each line's length along @@ -1232,7 +1795,7 @@ void LineInfo::ReadLines() { pending_file_num, pending_line_num, pending_column_num); if (lsm.end_sequence) { - lsm.Reset(header_.default_is_stmt); + lsm.Reset(header_.default_is_stmt); have_pending_line = false; } else { pending_address = lsm.address; @@ -1248,11 +1811,25 @@ void LineInfo::ReadLines() { after_header_ = lengthstart + header_.total_length; } -RangeListReader::RangeListReader(const uint8_t *buffer, uint64_t size, - ByteReader *reader, RangeListHandler *handler) - : buffer_(buffer), size_(size), reader_(reader), handler_(handler) { } +bool RangeListReader::ReadRanges(enum DwarfForm form, uint64_t data) { + if (form == DW_FORM_sec_offset) { + if (cu_info_->version_ <= 4) { + return ReadDebugRanges(data); + } else { + return ReadDebugRngList(data); + } + } else if (form == DW_FORM_rnglistx) { + offset_array_ = cu_info_->ranges_base_; + uint64_t index_offset = reader_->OffsetSize() * data; + uint64_t range_list_offset = + reader_->ReadOffset(cu_info_->buffer_ + offset_array_ + index_offset); -bool RangeListReader::ReadRangeList(uint64_t offset) { + return ReadDebugRngList(offset_array_ + range_list_offset); + } + return false; +} + +bool RangeListReader::ReadDebugRanges(uint64_t offset) { const uint64_t max_address = (reader_->AddressSize() == 4) ? 0xffffffffUL : 0xffffffffffffffffULL; @@ -1260,21 +1837,22 @@ bool RangeListReader::ReadRangeList(uint64_t offset) { bool list_end = false; do { - if (offset > size_ - entry_size) { + if (offset > cu_info_->size_ - entry_size) { return false; // Invalid range detected } - uint64_t start_address = reader_->ReadAddress(buffer_ + offset); - uint64_t end_address = - reader_->ReadAddress(buffer_ + offset + reader_->AddressSize()); + uint64_t start_address = reader_->ReadAddress(cu_info_->buffer_ + offset); + uint64_t end_address = reader_->ReadAddress( + cu_info_->buffer_ + offset + reader_->AddressSize()); if (start_address == max_address) { // Base address selection - handler_->SetBaseAddress(end_address); + cu_info_->base_address_ = end_address; } else if (start_address == 0 && end_address == 0) { // End-of-list handler_->Finish(); list_end = true; } else { // Add a range entry - handler_->AddRange(start_address, end_address); + handler_->AddRange(start_address + cu_info_->base_address_, + end_address + cu_info_->base_address_); } offset += entry_size; @@ -1283,6 +1861,62 @@ bool RangeListReader::ReadRangeList(uint64_t offset) { return true; } +bool RangeListReader::ReadDebugRngList(uint64_t offset) { + uint64_t start = 0; + uint64_t end = 0; + uint64_t range_len = 0; + uint64_t index = 0; + // A uleb128's length isn't known until after it has been read, so overruns + // are only caught after an entire entry. + while (offset < cu_info_->size_) { + uint8_t entry_type = reader_->ReadOneByte(cu_info_->buffer_ + offset); + offset += 1; + // Handle each entry type per Dwarf 5 Standard, section 2.17.3. + switch (entry_type) { + case DW_RLE_end_of_list: + handler_->Finish(); + return true; + case DW_RLE_base_addressx: + offset += ReadULEB(offset, &index); + cu_info_->base_address_ = GetAddressAtIndex(index); + break; + case DW_RLE_startx_endx: + offset += ReadULEB(offset, &index); + start = GetAddressAtIndex(index); + offset += ReadULEB(offset, &index); + end = GetAddressAtIndex(index); + handler_->AddRange(start, end); + break; + case DW_RLE_startx_length: + offset += ReadULEB(offset, &index); + start = GetAddressAtIndex(index); + offset += ReadULEB(offset, &range_len); + handler_->AddRange(start, start + range_len); + break; + case DW_RLE_offset_pair: + offset += ReadULEB(offset, &start); + offset += ReadULEB(offset, &end); + handler_->AddRange(start + cu_info_->base_address_, + end + cu_info_->base_address_); + break; + case DW_RLE_base_address: + offset += ReadAddress(offset, &cu_info_->base_address_); + break; + case DW_RLE_start_end: + offset += ReadAddress(offset, &start); + offset += ReadAddress(offset, &end); + handler_->AddRange(start, end); + break; + case DW_RLE_start_length: + offset += ReadAddress(offset, &start); + offset += ReadULEB(offset, &end); + handler_->AddRange(start, start + end); + break; + } + } + return false; +} + // 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. @@ -1305,17 +1939,17 @@ class CallFrameInfo::Rule { // this rule. If REG 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, + virtual bool Handle(Handler* handler, uint64_t address, int reg) 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; + virtual bool operator==(const Rule& rhs) const = 0; - bool operator!=(const Rule &rhs) const { return ! (*this == rhs); } + bool operator!=(const Rule& rhs) const { return ! (*this == rhs); } // Return a pointer to a copy of this rule. - virtual Rule *Copy() const = 0; + 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.) @@ -1331,16 +1965,16 @@ class CallFrameInfo::UndefinedRule: public CallFrameInfo::Rule { public: UndefinedRule() { } ~UndefinedRule() { } - bool Handle(Handler *handler, uint64_t address, int reg) const { + bool Handle(Handler* handler, uint64_t address, int reg) const { return handler->UndefinedRule(address, reg); } - bool operator==(const Rule &rhs) const { + 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); + const UndefinedRule* our_rhs = dynamic_cast<const UndefinedRule*>(&rhs); return (our_rhs != NULL); } - Rule *Copy() const { return new UndefinedRule(*this); } + Rule* Copy() const { return new UndefinedRule(*this); } }; // Rule: the register's value is the same as that it had in the caller. @@ -1348,16 +1982,16 @@ class CallFrameInfo::SameValueRule: public CallFrameInfo::Rule { public: SameValueRule() { } ~SameValueRule() { } - bool Handle(Handler *handler, uint64_t address, int reg) const { + bool Handle(Handler* handler, uint64_t address, int reg) const { return handler->SameValueRule(address, reg); } - bool operator==(const Rule &rhs) const { + 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); + const SameValueRule* our_rhs = dynamic_cast<const SameValueRule*>(&rhs); return (our_rhs != NULL); } - Rule *Copy() const { return new SameValueRule(*this); } + Rule* Copy() const { return new SameValueRule(*this); } }; // Rule: the register is saved at OFFSET from BASE_REGISTER. BASE_REGISTER @@ -1367,18 +2001,18 @@ class CallFrameInfo::OffsetRule: public CallFrameInfo::Rule { OffsetRule(int base_register, long offset) : base_register_(base_register), offset_(offset) { } ~OffsetRule() { } - bool Handle(Handler *handler, uint64_t address, int reg) const { + bool Handle(Handler* handler, uint64_t address, int reg) const { return handler->OffsetRule(address, reg, base_register_, offset_); } - bool operator==(const Rule &rhs) const { + 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); + 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); } + 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 @@ -1396,18 +2030,18 @@ class CallFrameInfo::ValOffsetRule: public CallFrameInfo::Rule { ValOffsetRule(int base_register, long offset) : base_register_(base_register), offset_(offset) { } ~ValOffsetRule() { } - bool Handle(Handler *handler, uint64_t address, int reg) const { + bool Handle(Handler* handler, uint64_t address, int reg) const { return handler->ValOffsetRule(address, reg, base_register_, offset_); } - bool operator==(const Rule &rhs) const { + 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); + 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); } + Rule* Copy() const { return new ValOffsetRule(*this); } void SetBaseRegister(unsigned reg) { base_register_ = reg; } void SetOffset(long long offset) { offset_ = offset; } private: @@ -1421,16 +2055,16 @@ class CallFrameInfo::RegisterRule: public CallFrameInfo::Rule { explicit RegisterRule(int register_number) : register_number_(register_number) { } ~RegisterRule() { } - bool Handle(Handler *handler, uint64_t address, int reg) const { + bool Handle(Handler* handler, uint64_t address, int reg) const { return handler->RegisterRule(address, reg, register_number_); } - bool operator==(const Rule &rhs) const { + 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); + 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); } + Rule* Copy() const { return new RegisterRule(*this); } private: int register_number_; }; @@ -1438,19 +2072,19 @@ class CallFrameInfo::RegisterRule: public CallFrameInfo::Rule { // Rule: EXPRESSION evaluates to the address at which the register is saved. class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule { public: - explicit ExpressionRule(const string &expression) + explicit ExpressionRule(const string& expression) : expression_(expression) { } ~ExpressionRule() { } - bool Handle(Handler *handler, uint64_t address, int reg) const { + bool Handle(Handler* handler, uint64_t address, int reg) const { return handler->ExpressionRule(address, reg, expression_); } - bool operator==(const Rule &rhs) const { + 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); + const ExpressionRule* our_rhs = dynamic_cast<const ExpressionRule*>(&rhs); return (our_rhs && expression_ == our_rhs->expression_); } - Rule *Copy() const { return new ExpressionRule(*this); } + Rule* Copy() const { return new ExpressionRule(*this); } private: string expression_; }; @@ -1458,20 +2092,20 @@ class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule { // Rule: EXPRESSION evaluates to the address at which the register is saved. class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule { public: - explicit ValExpressionRule(const string &expression) + explicit ValExpressionRule(const string& expression) : expression_(expression) { } ~ValExpressionRule() { } - bool Handle(Handler *handler, uint64_t address, int reg) const { + bool Handle(Handler* handler, uint64_t address, int reg) const { return handler->ValExpressionRule(address, reg, expression_); } - bool operator==(const Rule &rhs) const { + 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); + const ValExpressionRule* our_rhs = + dynamic_cast<const ValExpressionRule*>(&rhs); return (our_rhs && expression_ == our_rhs->expression_); } - Rule *Copy() const { return new ValExpressionRule(*this); } + Rule* Copy() const { return new ValExpressionRule(*this); } private: string expression_; }; @@ -1480,51 +2114,51 @@ class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule { class CallFrameInfo::RuleMap { public: RuleMap() : cfa_rule_(NULL) { } - RuleMap(const RuleMap &rhs) : cfa_rule_(NULL) { *this = rhs; } + RuleMap(const RuleMap& rhs) : cfa_rule_(NULL) { *this = rhs; } ~RuleMap() { Clear(); } - RuleMap &operator=(const RuleMap &rhs); + 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; } + 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_; } + 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; + Rule* RegisterRule(int reg) const; // Set the rule for computing REG to RULE. Take ownership of RULE. - void SetRegisterRule(int reg, Rule *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_t address, - const RuleMap &new_rules) const; + bool HandleTransitionTo(Handler* handler, uint64_t address, + const RuleMap& new_rules) const; private: // A map from register numbers to Rules. - typedef std::map<int, Rule *> RuleByNumber; + 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_; + 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) { +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(); @@ -1534,7 +2168,7 @@ CallFrameInfo::RuleMap &CallFrameInfo::RuleMap::operator=(const RuleMap &rhs) { return *this; } -CallFrameInfo::Rule *CallFrameInfo::RuleMap::RegisterRule(int reg) const { +CallFrameInfo::Rule* CallFrameInfo::RuleMap::RegisterRule(int reg) const { assert(reg != Handler::kCFARegister); RuleByNumber::const_iterator it = registers_.find(reg); if (it != registers_.end()) @@ -1543,18 +2177,18 @@ CallFrameInfo::Rule *CallFrameInfo::RuleMap::RegisterRule(int reg) const { return NULL; } -void CallFrameInfo::RuleMap::SetRegisterRule(int reg, Rule *rule) { +void CallFrameInfo::RuleMap::SetRegisterRule(int reg, Rule* rule) { assert(reg != Handler::kCFARegister); assert(rule); - Rule **slot = ®isters_[reg]; + Rule** slot = ®isters_[reg]; delete *slot; *slot = rule; } bool CallFrameInfo::RuleMap::HandleTransitionTo( - Handler *handler, + Handler* handler, uint64_t address, - const RuleMap &new_rules) const { + 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_ && @@ -1634,7 +2268,7 @@ 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, + State(ByteReader* reader, Handler* handler, Reporter* reporter, uint64_t address) : reader_(reader), handler_(handler), reporter_(reporter), address_(address), entry_(NULL), cursor_(NULL) { } @@ -1642,13 +2276,13 @@ class CallFrameInfo::State { // 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); + 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); + bool InterpretFDE(const FDE& fde); - private: + private: // The operands of a CFI instruction, for ParseOperands. struct Operands { unsigned register_number; // A register number. @@ -1676,7 +2310,7 @@ class CallFrameInfo::State { // '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); + 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 @@ -1699,7 +2333,7 @@ class CallFrameInfo::State { // Specify that REG can be recovered using RULE, and return true. On // failure, report and return false. - bool DoRule(unsigned reg, Rule *rule); + 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, @@ -1727,23 +2361,23 @@ class CallFrameInfo::State { } // For reading multi-byte values with the appropriate endianness. - ByteReader *reader_; + ByteReader* reader_; // The handler to which we should report the data we find. - Handler *handler_; + Handler* handler_; // For reporting problems in the info we're parsing. - Reporter *reporter_; + Reporter* reporter_; // The code address to which the next instruction in the stream applies. uint64_t address_; // The entry whose instructions we are currently processing. This is // first a CIE, and then an FDE. - const Entry *entry_; + const Entry* entry_; // The next instruction to process. - const uint8_t *cursor_; + const uint8_t* cursor_; // The current set of rules. RuleMap rules_; @@ -1758,7 +2392,7 @@ class CallFrameInfo::State { std::stack<RuleMap> saved_rules_; }; -bool CallFrameInfo::State::InterpretCIE(const CIE &cie) { +bool CallFrameInfo::State::InterpretCIE(const CIE& cie) { entry_ = &cie; cursor_ = entry_->instructions; while (cursor_ < entry_->end) @@ -1770,7 +2404,7 @@ bool CallFrameInfo::State::InterpretCIE(const CIE &cie) { return true; } -bool CallFrameInfo::State::InterpretFDE(const FDE &fde) { +bool CallFrameInfo::State::InterpretFDE(const FDE& fde) { entry_ = &fde; cursor_ = entry_->instructions; while (cursor_ < entry_->end) @@ -1779,10 +2413,10 @@ bool CallFrameInfo::State::InterpretFDE(const FDE &fde) { return true; } -bool CallFrameInfo::State::ParseOperands(const char *format, - Operands *operands) { +bool CallFrameInfo::State::ParseOperands(const char* format, + Operands* operands) { size_t len; - const char *operand; + const char* operand; for (operand = format; *operand; operand++) { size_t bytes_left = entry_->end - cursor_; @@ -1841,7 +2475,7 @@ bool CallFrameInfo::State::ParseOperands(const char *format, if (len > bytes_left || expression_length > bytes_left - len) return ReportIncomplete(); cursor_ += len; - operands->expression = string(reinterpret_cast<const char *>(cursor_), + operands->expression = string(reinterpret_cast<const char*>(cursor_), expression_length); cursor_ += expression_length; break; @@ -1856,7 +2490,7 @@ bool CallFrameInfo::State::ParseOperands(const char *format, } bool CallFrameInfo::State::DoInstruction() { - CIE *cie = entry_->cie; + CIE* cie = entry_->cie; Operands ops; // Our entry's kind should have been set by now. @@ -1909,19 +2543,19 @@ bool CallFrameInfo::State::DoInstruction() { 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; @@ -1946,7 +2580,7 @@ bool CallFrameInfo::State::DoInstruction() { // 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(); + Rule* cfa_rule = rules_.CFARule(); if (!cfa_rule) { if (!DoDefCFA(ops.register_number, ops.offset)) { reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); @@ -1979,7 +2613,7 @@ bool CallFrameInfo::State::DoInstruction() { case DW_CFA_def_cfa_expression: { if (!ParseOperands("e", &ops)) return false; - Rule *rule = new ValExpressionRule(ops.expression); + Rule* rule = new ValExpressionRule(ops.expression); rules_.SetCFARule(rule); if (!rule->Handle(handler_, address_, Handler::kCFARegister)) @@ -2086,7 +2720,7 @@ bool CallFrameInfo::State::DoInstruction() { CursorOffset()); return false; } - const RuleMap &new_rules = saved_rules_.top(); + const RuleMap& new_rules = saved_rules_.top(); if (rules_.CFARule() && !new_rules.CFARule()) { reporter_->ClearingCFARule(entry_->offset, entry_->kind, CursorOffset()); @@ -2102,23 +2736,32 @@ bool CallFrameInfo::State::DoInstruction() { 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_AARCH64_negate_ra_state 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; + if (handler_->Architecture() == "arm64") { + // Indicates that the return address, x30 has been signed. + // Breakpad will speculatively remove pointer-authentication codes when + // interpreting return addresses, regardless of this bit. + } else if (handler_->Architecture() == "sparc" || + handler_->Architecture() == "sparcv9") { + // 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. + + // 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; } @@ -2138,14 +2781,14 @@ bool CallFrameInfo::State::DoInstruction() { } bool CallFrameInfo::State::DoDefCFA(unsigned base_register, long offset) { - Rule *rule = new ValOffsetRule(base_register, 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(); + Rule* cfa_rule = rules_.CFARule(); if (!cfa_rule) { reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); return false; @@ -2155,7 +2798,7 @@ bool CallFrameInfo::State::DoDefCFAOffset(long offset) { Handler::kCFARegister); } -bool CallFrameInfo::State::DoRule(unsigned reg, Rule *rule) { +bool CallFrameInfo::State::DoRule(unsigned reg, Rule* rule) { rules_.SetRegisterRule(reg, rule); return rule->Handle(handler_, address_, reg); } @@ -2184,7 +2827,7 @@ bool CallFrameInfo::State::DoRestore(unsigned reg) { reporter_->RestoreInCIE(entry_->offset, CursorOffset()); return false; } - Rule *rule = cie_rules_.RegisterRule(reg); + 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 @@ -2195,8 +2838,8 @@ bool CallFrameInfo::State::DoRestore(unsigned reg) { return DoRule(reg, rule); } -bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) { - const uint8_t *buffer_end = buffer_ + buffer_length_; +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_; @@ -2222,7 +2865,7 @@ bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) { // 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, @@ -2264,7 +2907,7 @@ bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) { // Now advance cursor past the id. cursor += offset_size; - + // The fields specific to this kind of entry start here. entry->fields = cursor; @@ -2273,8 +2916,8 @@ bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) { return true; } -bool CallFrameInfo::ReadCIEFields(CIE *cie) { - const uint8_t *cursor = cie->fields; +bool CallFrameInfo::ReadCIEFields(CIE* cie) { + const uint8_t* cursor = cie->fields; size_t len; assert(cie->kind == kCIE); @@ -2305,13 +2948,13 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) { return false; } - const uint8_t *augmentation_start = cursor; - const uint8_t *augmentation_end = - reinterpret_cast<const uint8_t *>(memchr(augmentation_start, '\0', + 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), + cie->augmentation = string(reinterpret_cast<const char*>(augmentation_start), cursor - augmentation_start); // Skip the terminating '\0'. cursor++; @@ -2372,9 +3015,9 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) { if (size_t(cie->end - cursor) < len + data_size) return ReportIncomplete(cie); cursor += len; - const uint8_t *data = cursor; + const uint8_t* data = cursor; cursor += data_size; - const uint8_t *data_end = cursor; + const uint8_t* data_end = cursor; cie->has_z_lsda = false; cie->has_z_personality = false; @@ -2465,8 +3108,8 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) { return true; } -bool CallFrameInfo::ReadFDEFields(FDE *fde) { - const uint8_t *cursor = fde->fields; +bool CallFrameInfo::ReadFDEFields(FDE* fde) { + const uint8_t* cursor = fde->fields; size_t size; fde->address = reader_->ReadEncodedPointer(cursor, fde->cie->pointer_encoding, @@ -2492,7 +3135,7 @@ bool CallFrameInfo::ReadFDEFields(FDE *fde) { 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 @@ -2530,12 +3173,12 @@ bool CallFrameInfo::ReadFDEFields(FDE *fde) { return true; } - + bool CallFrameInfo::Start() { - const uint8_t *buffer_end = buffer_ + buffer_length_; - const uint8_t *cursor; + const uint8_t* buffer_end = buffer_ + buffer_length_; + const uint8_t* cursor; bool all_ok = true; - const uint8_t *entry_end; + const uint8_t* entry_end; bool ok; // Traverse all the entries in buffer_, skipping CIEs and offering @@ -2587,7 +3230,7 @@ bool CallFrameInfo::Start() { reporter_->CIEPointerOutOfRange(fde.offset, fde.id); continue; } - + CIE cie; // Parse this FDE's CIE header. @@ -2626,7 +3269,7 @@ bool CallFrameInfo::Start() { ok = true; continue; } - + if (cie.has_z_augmentation) { // Report the personality routine address, if we have one. if (cie.has_z_personality) { @@ -2666,7 +3309,7 @@ bool CallFrameInfo::Start() { return all_ok; } -const char *CallFrameInfo::KindName(EntryKind kind) { +const char* CallFrameInfo::KindName(EntryKind kind) { if (kind == CallFrameInfo::kUnknown) return "entry"; else if (kind == CallFrameInfo::kCIE) @@ -2679,7 +3322,7 @@ const char *CallFrameInfo::KindName(EntryKind kind) { } } -bool CallFrameInfo::ReportIncomplete(Entry *entry) { +bool CallFrameInfo::ReportIncomplete(Entry* entry) { reporter_->Incomplete(entry->offset, entry->kind); return false; } @@ -2738,7 +3381,7 @@ void CallFrameInfo::Reporter::UnrecognizedVersion(uint64_t offset, int version) } void CallFrameInfo::Reporter::UnrecognizedAugmentation(uint64_t offset, - const string &aug) { + const string& aug) { fprintf(stderr, "%s: CFI frame description entry at offset 0x%" PRIx64 " in '%s':" " CIE specifies unrecognized augmentation: '%s'\n", @@ -2813,4 +3456,4 @@ void CallFrameInfo::Reporter::ClearingCFARule(uint64_t offset, section_.c_str(), insn_offset); } -} // namespace dwarf2reader +} // namespace google_breakpad diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h index 0b194c17..ddcdd801 100644 --- a/src/common/dwarf/dwarf2reader.h +++ b/src/common/dwarf/dwarf2reader.h @@ -1,6 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -12,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -40,6 +40,7 @@ #ifndef COMMON_DWARF_DWARF2READER_H__ #define COMMON_DWARF_DWARF2READER_H__ +#include <assert.h> #include <stdint.h> #include <list> @@ -55,7 +56,7 @@ #include "common/using_std_string.h" #include "common/dwarf/elf_reader.h" -namespace dwarf2reader { +namespace google_breakpad { struct LineStateMachine; class Dwarf2Handler; class LineInfoHandler; @@ -63,9 +64,27 @@ 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_t> > SectionMap; -typedef std::list<std::pair<enum DwarfAttribute, enum DwarfForm> > - AttributeList; +typedef std::map<string, std::pair<const uint8_t*, uint64_t> > SectionMap; + +// Abstract away the difference between elf and mach-o section names. +// Elf-names use ".section_name, mach-o uses "__section_name". Pass "name" in +// the elf form, ".section_name". +const SectionMap::const_iterator GetSectionByName(const SectionMap& + sections, const char* name); + +// Most of the time, this struct functions as a simple attribute and form pair. +// However, Dwarf5 DW_FORM_implicit_const means that a form may have its value +// in line in the abbrev table, and that value must be associated with the +// pair until the attr's value is needed. +struct AttrForm { + AttrForm(enum DwarfAttribute attr, enum DwarfForm form, uint64_t value) : + attr_(attr), form_(form), value_(value) { } + + enum DwarfAttribute attr_; + enum DwarfForm form_; + uint64_t value_; +}; +typedef std::list<AttrForm> AttributeList; typedef AttributeList::iterator AttributeIterator; typedef AttributeList::const_iterator ConstAttributeIterator; @@ -80,7 +99,7 @@ struct LineInfoHeader { uint8_t 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; + std::vector<unsigned char>* std_opcode_lengths; }; class LineInfo { @@ -90,8 +109,10 @@ class LineInfo { // 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_t buffer_length, - ByteReader* reader, LineInfoHandler* handler); + LineInfo(const uint8_t* buffer, uint64_t buffer_length, + ByteReader* reader, const uint8_t* string_buffer, + size_t string_buffer_length, const uint8_t* line_string_buffer, + size_t line_string_buffer_length, LineInfoHandler* handler); virtual ~LineInfo() { if (header_.std_opcode_lengths) { @@ -115,12 +136,12 @@ class LineInfo { // lsm's old address < PC <= lsm's new address static bool ProcessOneOpcode(ByteReader* reader, LineInfoHandler* handler, - const struct LineInfoHeader &header, - const uint8_t *start, + const struct LineInfoHeader& header, + const uint8_t* start, struct LineStateMachine* lsm, size_t* len, uintptr pc, - bool *lsm_passes_pc); + bool* lsm_passes_pc); private: // Reads the DWARF2/3 header for this line info. @@ -129,26 +150,54 @@ class LineInfo { // Reads the DWARF2/3 line information void ReadLines(); + // Read the DWARF5 types and forms for the file and directory tables. + void ReadTypesAndForms(const uint8_t** lineptr, uint32_t* content_types, + uint32_t* content_forms, uint32_t max_types, + uint32_t* format_count); + + // Read a row from the dwarf5 LineInfo file table. + void ReadFileRow(const uint8_t** lineptr, const uint32_t* content_types, + const uint32_t* content_forms, uint32_t row, + uint32_t format_count); + + // Read and return the data at *lineptr according to form. Advance + // *lineptr appropriately. + uint64_t ReadUnsignedData(uint32_t form, const uint8_t** lineptr); + + // Read and return the data at *lineptr according to form. Advance + // *lineptr appropriately. + const char* ReadStringForm(uint32_t form, const uint8_t** lineptr); + // 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 + // A DWARF 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_; + const uint8_t* buffer_; #ifndef NDEBUG uint64_t buffer_length_; #endif - const uint8_t *after_header_; + // Convenience pointers into .debug_str and .debug_line_str. These exactly + // correspond to those in the compilation unit. + const uint8_t* string_buffer_; +#ifndef NDEBUG + uint64_t string_buffer_length_; +#endif + const uint8_t* line_string_buffer_; +#ifndef NDEBUG + uint64_t line_string_buffer_length_; +#endif + + const uint8_t* after_header_; }; // This class is the main interface between the line info reader and @@ -196,25 +245,75 @@ class RangeListHandler { // Add a range. virtual void AddRange(uint64_t begin, uint64_t end) { }; - // A new base address must be set for computing the ranges' addresses. - virtual void SetBaseAddress(uint64_t base_address) { }; - // Finish processing the range list. virtual void Finish() { }; }; class RangeListReader { public: - RangeListReader(const uint8_t *buffer, uint64_t size, ByteReader *reader, - RangeListHandler *handler); + // Reading a range list requires quite a bit of information + // from the compilation unit. Package it conveniently. + struct CURangesInfo { + CURangesInfo() : + version_(0), base_address_(0), ranges_base_(0), + buffer_(nullptr), size_(0), addr_buffer_(nullptr), + addr_buffer_size_(0), addr_base_(0) { } + + uint16_t version_; + // Ranges base address. Ordinarily the CU's low_pc. + uint64_t base_address_; + // Offset into .debug_rnglists for this CU's rangelists. + uint64_t ranges_base_; + // Contents of either .debug_ranges or .debug_rnglists. + const uint8_t* buffer_; + uint64_t size_; + // Contents of .debug_addr. This cu's contribution starts at + // addr_base_ + const uint8_t* addr_buffer_; + uint64_t addr_buffer_size_; + uint64_t addr_base_; + }; + + RangeListReader(ByteReader* reader, CURangesInfo* cu_info, + RangeListHandler* handler) : + reader_(reader), cu_info_(cu_info), handler_(handler), + offset_array_(0) { } - bool ReadRangeList(uint64_t offset); + // Read ranges from cu_info as specified by form and data. + bool ReadRanges(enum DwarfForm form, uint64_t data); private: - const uint8_t *buffer_; - uint64_t size_; + // Read dwarf4 .debug_ranges at offset. + bool ReadDebugRanges(uint64_t offset); + // Read dwarf5 .debug_rngslist at offset. + bool ReadDebugRngList(uint64_t offset); + + // Convenience functions to handle the mechanics of reading entries in the + // ranges section. + uint64_t ReadULEB(uint64_t offset, uint64_t* value) { + size_t len; + *value = reader_->ReadUnsignedLEB128(cu_info_->buffer_ + offset, &len); + return len; + } + + uint64_t ReadAddress(uint64_t offset, uint64_t* value) { + *value = reader_->ReadAddress(cu_info_->buffer_ + offset); + return reader_->AddressSize(); + } + + // Read the address at this CU's addr_index in the .debug_addr section. + uint64_t GetAddressAtIndex(uint64_t addr_index) { + assert(cu_info_->addr_buffer_ != nullptr); + uint64_t offset = + cu_info_->addr_base_ + addr_index * reader_->AddressSize(); + assert(offset < cu_info_->addr_buffer_size_); + return reader_->ReadAddress(cu_info_->addr_buffer_ + offset); + } + ByteReader* reader_; - RangeListHandler *handler_; + CURangesInfo* cu_info_; + RangeListHandler* handler_; + uint64_t offset_array_; }; // This class is the main interface between the reader and the @@ -288,7 +387,7 @@ class Dwarf2Handler { virtual void ProcessAttributeBuffer(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, - const uint8_t *data, + const uint8_t* data, uint64_t len) { } // Called when we have an attribute with string data to give to our handler. @@ -410,18 +509,42 @@ class CompilationUnit { // Reads the DWARF2/3 abbreviations for this compilation unit void ReadAbbrevs(); + // Read the abbreviation offset for this compilation unit + size_t ReadAbbrevOffset(const uint8_t* headerptr); + + // Read the address size for this compilation unit + size_t ReadAddressSize(const uint8_t* headerptr); + + // Read the DWO id from a split or skeleton compilation unit header + size_t ReadDwoId(const uint8_t* headerptr); + + // Read the type signature from a type or split type compilation unit header + size_t ReadTypeSignature(const uint8_t* headerptr); + + // Read the DWO id from a split or skeleton compilation unit header + size_t ReadTypeOffset(const uint8_t* headerptr); + // Processes a single DIE for this compilation unit and return a new // pointer just past the end of it - const uint8_t *ProcessDIE(uint64_t dieoffset, - const uint8_t *start, + const uint8_t* ProcessDIE(uint64_t 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_t dieoffset, - const uint8_t *start, + const uint8_t* ProcessAttribute(uint64_t dieoffset, + const uint8_t* start, enum DwarfAttribute attr, - enum DwarfForm form); + enum DwarfForm form, + uint64_t implicit_const); + + // Special version of ProcessAttribute, for finding str_offsets_base and + // DW_AT_addr_base in DW_TAG_compile_unit, for DWARF v5. + const uint8_t* ProcessOffsetBaseAttribute(uint64_t dieoffset, + const uint8_t* start, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64_t implicit_const); // Called when we have an attribute with unsigned data to give to // our handler. The attribute is for the DIE at OFFSET from the @@ -436,10 +559,13 @@ class CompilationUnit { if (attr == DW_AT_GNU_dwo_id) { dwo_id_ = data; } - else if (attr == DW_AT_GNU_addr_base) { + else if (attr == DW_AT_GNU_addr_base || attr == DW_AT_addr_base) { addr_base_ = data; } - else if (attr == DW_AT_GNU_ranges_base) { + else if (attr == DW_AT_str_offsets_base) { + str_offsets_base_ = data; + } + else if (attr == DW_AT_GNU_ranges_base || attr == DW_AT_rnglists_base) { ranges_base_ = data; } // TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5, @@ -475,6 +601,14 @@ class CompilationUnit { handler_->ProcessAttributeBuffer(offset, attr, form, data, len); } + // Handles the common parts of DW_FORM_GNU_str_index, DW_FORM_strx, + // DW_FORM_strx1, DW_FORM_strx2, DW_FORM_strx3, and DW_FORM_strx4. + // Retrieves the data and calls through to ProcessAttributeString. + void ProcessFormStringIndex(uint64_t offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64_t str_index); + // 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 @@ -485,21 +619,33 @@ class CompilationUnit { enum DwarfAttribute attr, enum DwarfForm form, const char* data) { - if (attr == DW_AT_GNU_dwo_name) + if (attr == DW_AT_GNU_dwo_name || attr == DW_AT_dwo_name) dwo_name_ = data; handler_->ProcessAttributeString(offset, attr, form, data); } + // Called to handle common portions of DW_FORM_addrx and variations, as well + // as DW_FORM_GNU_addr_index. + void ProcessAttributeAddrIndex(uint64_t offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64_t addr_index) { + const uint8_t* addr_ptr = + addr_buffer_ + addr_base_ + addr_index * reader_->AddressSize(); + ProcessAttributeUnsigned( + offset, attr, form, reader_->ReadAddress(addr_ptr)); + } + // 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); + 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); + const uint8_t* SkipAttribute(const uint8_t* start, enum DwarfForm form); // Process the actual debug information in a split DWARF file. void ProcessSplitDwarf(); @@ -518,9 +664,9 @@ class CompilationUnit { // 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_; + const uint8_t* buffer_; uint64_t buffer_length_; - const uint8_t *after_header_; + const uint8_t* after_header_; // The associated ByteReader that handles endianness issues for us ByteReader* reader_; @@ -539,9 +685,13 @@ class CompilationUnit { // 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_; + const uint8_t* string_buffer_; uint64_t string_buffer_length_; + // Similarly for .debug_line_string. + const uint8_t* line_string_buffer_; + uint64_t line_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_; @@ -561,9 +711,18 @@ class CompilationUnit { // associated with the skeleton compilation unit. bool is_split_dwarf_; + // Flag indicating if it's a Type Unit (only applicable to DWARF v5). + bool is_type_unit_; + // The value of the DW_AT_GNU_dwo_id attribute, if any. uint64_t dwo_id_; + // The value of the DW_AT_GNU_type_signature attribute, if any. + uint64_t type_signature_; + + // The value of the DW_AT_GNU_type_offset attribute, if any. + size_t type_offset_; + // The value of the DW_AT_GNU_dwo_name attribute, if any. const char* dwo_name_; @@ -571,12 +730,16 @@ class CompilationUnit { // from the skeleton CU. uint64_t skeleton_dwo_id_; - // The value of the DW_AT_GNU_ranges_base attribute, if any. + // The value of the DW_AT_GNU_ranges_base or DW_AT_rnglists_base attribute, + // if any. uint64_t ranges_base_; // The value of the DW_AT_GNU_addr_base attribute, if any. uint64_t addr_base_; + // The value of DW_AT_str_offsets_base attribute, if any. + uint64_t str_offsets_base_; + // True if we have already looked for a .dwp file. bool have_checked_for_dwp_; @@ -905,8 +1068,8 @@ class CallFrameInfo { // 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, + 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), @@ -920,7 +1083,7 @@ class CallFrameInfo { bool Start(); // Return the textual name of KIND. For error reporting. - static const char *KindName(EntryKind kind); + static const char* KindName(EntryKind kind); private: @@ -933,7 +1096,7 @@ class CallFrameInfo { size_t offset; // The start of this entry in the buffer. - const uint8_t *start; + const uint8_t* start; // Which kind of entry this is. // @@ -944,16 +1107,16 @@ class CallFrameInfo { // 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; + const uint8_t* fields; // The start of this entry's instructions. - const uint8_t *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; + 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. @@ -961,7 +1124,7 @@ class CallFrameInfo { // 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; + CIE* cie; }; // A common information entry (CIE). @@ -1035,14 +1198,14 @@ class CallFrameInfo { // 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); + 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); + 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 @@ -1050,12 +1213,12 @@ class CallFrameInfo { // 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); + 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); + bool ReportIncomplete(Entry* entry); // Return true if ENCODING has the DW_EH_PE_indirect bit set. static bool IsIndirectEncoding(DwarfPointerEncoding encoding) { @@ -1063,17 +1226,17 @@ class CallFrameInfo { } // The contents of the DWARF .debug_info section we're parsing. - const uint8_t *buffer_; + const uint8_t* buffer_; size_t buffer_length_; // For reading multi-byte values with the appropriate endianness. - ByteReader *reader_; + ByteReader* reader_; // The handler to which we should report the data we find. - Handler *handler_; + Handler* handler_; // For reporting problems in the info we're parsing. - Reporter *reporter_; + Reporter* reporter_; // True if we are processing .eh_frame-format data. bool eh_frame_; @@ -1106,7 +1269,7 @@ class CallFrameInfo::Handler { // 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_t address, uint64_t length, - uint8_t version, const string &augmentation, + uint8_t version, const string& augmentation, unsigned return_address) = 0; // When the Entry function returns true, the parser calls these @@ -1155,13 +1318,13 @@ class CallFrameInfo::Handler { // At ADDRESS, the DWARF expression EXPRESSION yields the address at // which REG was saved. virtual bool ExpressionRule(uint64_t address, int reg, - const string &expression) = 0; + 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_t address, int reg, - const string &expression) = 0; + 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 @@ -1169,6 +1332,9 @@ class CallFrameInfo::Handler { // should stop. virtual bool End() = 0; + // The target architecture for the data. + virtual string Architecture() = 0; + // Handler functions for Linux C++ exception handling data. These are // only called if the data includes 'z' augmentation strings. @@ -1238,8 +1404,8 @@ class CallFrameInfo::Reporter { // in a Mach-O section named __debug_frame. If we support // Linux-style exception handling data, we could be reading an // .eh_frame section. - Reporter(const string &filename, - const string §ion = ".debug_frame") + Reporter(const string& filename, + const string& section = ".debug_frame") : filename_(filename), section_(section) { } virtual ~Reporter() { } @@ -1279,7 +1445,7 @@ class CallFrameInfo::Reporter { // which we don't recognize. We cannot parse DWARF CFI if it uses // augmentations we don't recognize. virtual void UnrecognizedAugmentation(uint64_t offset, - const string &augmentation); + const string& augmentation); // The pointer encoding ENCODING, specified by the CIE at OFFSET, is not // a valid encoding. @@ -1326,6 +1492,6 @@ class CallFrameInfo::Reporter { string section_; }; -} // namespace dwarf2reader +} // namespace google_breakpad #endif // UTIL_DEBUGINFO_DWARF2READER_H__ diff --git a/src/common/dwarf/dwarf2reader_cfi_unittest.cc b/src/common/dwarf/dwarf2reader_cfi_unittest.cc index ebe612e1..dc4418c7 100644 --- a/src/common/dwarf/dwarf2reader_cfi_unittest.cc +++ b/src/common/dwarf/dwarf2reader_cfi_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -29,7 +28,7 @@ // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> -// dwarf2reader_cfi_unittest.cc: Unit tests for dwarf2reader::CallFrameInfo +// dwarf2reader_cfi_unittest.cc: Unit tests for google_breakpad::CallFrameInfo #include <stdint.h> #include <stdlib.h> @@ -72,11 +71,11 @@ 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 google_breakpad::DwarfPointerEncoding; +using google_breakpad::ENDIANNESS_BIG; +using google_breakpad::ENDIANNESS_LITTLE; +using google_breakpad::ByteReader; +using google_breakpad::CallFrameInfo; using std::vector; using testing::InSequence; @@ -87,7 +86,7 @@ using testing::_; #ifdef WRITE_ELF void WriteELFFrameSection(const char *filename, const char *section_name, - const CFISection §ion); + 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) \ @@ -100,7 +99,7 @@ void WriteELFFrameSection(const char *filename, const char *section_name, class MockCallFrameInfoHandler: public CallFrameInfo::Handler { public: MOCK_METHOD6(Entry, bool(size_t offset, uint64_t address, uint64_t length, - uint8_t version, const string &augmentation, + uint8_t version, const string& augmentation, unsigned return_address)); MOCK_METHOD2(UndefinedRule, bool(uint64_t address, int reg)); MOCK_METHOD2(SameValueRule, bool(uint64_t address, int reg)); @@ -110,10 +109,11 @@ class MockCallFrameInfoHandler: public CallFrameInfo::Handler { long offset)); MOCK_METHOD3(RegisterRule, bool(uint64_t address, int reg, int base_register)); MOCK_METHOD3(ExpressionRule, bool(uint64_t address, int reg, - const string &expression)); + const string& expression)); MOCK_METHOD3(ValExpressionRule, bool(uint64_t address, int reg, - const string &expression)); + const string& expression)); MOCK_METHOD0(End, bool()); + MOCK_METHOD0(Architecture, string()); MOCK_METHOD2(PersonalityRoutine, bool(uint64_t address, bool indirect)); MOCK_METHOD2(LanguageSpecificDataArea, bool(uint64_t address, bool indirect)); MOCK_METHOD0(SignalHandler, bool()); @@ -129,7 +129,7 @@ class MockCallFrameErrorReporter: public CallFrameInfo::Reporter { MOCK_METHOD2(UnexpectedAddressSize, void(uint64_t, uint8_t)); MOCK_METHOD2(UnexpectedSegmentSize, void(uint64_t, uint8_t)); MOCK_METHOD2(UnrecognizedVersion, void(uint64_t, int version)); - MOCK_METHOD2(UnrecognizedAugmentation, void(uint64_t, const string &)); + MOCK_METHOD2(UnrecognizedAugmentation, void(uint64_t, const string&)); MOCK_METHOD2(InvalidPointerEncoding, void(uint64_t, uint8_t)); MOCK_METHOD2(UnusablePointerEncoding, void(uint64_t, uint8_t)); MOCK_METHOD2(RestoreInCIE, void(uint64_t, uint64_t)); @@ -218,7 +218,7 @@ TEST_F(CFI, IncompleteLength32) { ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size() - 2, &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -244,7 +244,7 @@ TEST_F(CFI, IncompleteLength64) { ByteReader byte_reader(ENDIANNESS_LITTLE); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size() - 4, &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -269,7 +269,7 @@ TEST_F(CFI, IncompleteId32) { ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -296,7 +296,7 @@ TEST_F(CFI, BadId32) { ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -306,7 +306,7 @@ TEST_F(CFI, BadId32) { TEST_F(CFI, SingleCIE) { CFISection section(kLittleEndian, 4); section.CIEHeader(0xffe799a8, 0x3398dcdd, 0x6e9683de, 3, ""); - section.Append(10, dwarf2reader::DW_CFA_nop); + section.Append(10, google_breakpad::DW_CFA_nop); section.FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("SingleCIE", section); @@ -318,7 +318,7 @@ TEST_F(CFI, SingleCIE) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_LITTLE); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -349,7 +349,7 @@ TEST_F(CFI, OneFDE) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -393,7 +393,7 @@ TEST_F(CFI, TwoFDEsOneCIE) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -443,7 +443,7 @@ TEST_F(CFI, TwoFDEsTwoCIEs) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_LITTLE); byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -488,7 +488,7 @@ TEST_F(CFI, BadVersion) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -533,7 +533,7 @@ TEST_F(CFI, BadAugmentation) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -568,7 +568,7 @@ TEST_F(CFI, CIEVersion1ReturnColumn) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -603,7 +603,7 @@ TEST_F(CFI, CIEVersion3ReturnColumn) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -633,7 +633,7 @@ TEST_F(CFI, CIEVersion4AdditionalFields) { string contents; EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -663,7 +663,7 @@ TEST_F(CFI, CIEVersion4AdditionalFields32BitAddress) { string contents; EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -690,7 +690,7 @@ TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedAddressSize) { string contents; EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -715,7 +715,7 @@ TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedSegmentSize) { string contents; EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -763,7 +763,7 @@ struct CFIInsnFixture: public CFIFixture { .Mark(&cie_label) .CIEHeader(code_factor, data_factor, return_register, version, "") - .D8(dwarf2reader::DW_CFA_def_cfa) + .D8(google_breakpad::DW_CFA_def_cfa) .ULEB128(cfa_base_register) .ULEB128(cfa_offset) .FinishEntry(); @@ -788,7 +788,7 @@ struct CFIInsnFixture: public CFIFixture { void ParseSection(CFISection *section, bool succeeds = true) { string contents; EXPECT_TRUE(section->GetContents(&contents)); - dwarf2reader::Endianness endianness; + google_breakpad::Endianness endianness; if (section->endianness() == kBigEndian) endianness = ENDIANNESS_BIG; else { @@ -797,7 +797,7 @@ struct CFIInsnFixture: public CFIFixture { } ByteReader byte_reader(endianness); byte_reader.SetAddressSize(section->AddressSize()); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); if (succeeds) @@ -823,10 +823,10 @@ TEST_F(CFIInsn, DW_CFA_set_loc) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_set_loc).D32(0xb1ee3e7a) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x4defb431).ULEB128(0x6d17b0ee) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_set_loc", section); @@ -844,10 +844,10 @@ TEST_F(CFIInsn, DW_CFA_advance_loc) { CFISection section(kBigEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_advance_loc | 0x2a) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x5bbb3715).ULEB128(0x0186c7bf) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc", section); @@ -866,8 +866,8 @@ TEST_F(CFIInsn, DW_CFA_advance_loc1) { CFISection section(kLittleEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_advance_loc1).D8(0xd8) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x69d5696a).ULEB128(0x1eb7fc93) + .D8(google_breakpad::DW_CFA_advance_loc1).D8(0xd8) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x69d5696a).ULEB128(0x1eb7fc93) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc1", section); @@ -886,8 +886,8 @@ TEST_F(CFIInsn, DW_CFA_advance_loc2) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_advance_loc2).D16(0x3adb) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3a368bed).ULEB128(0x3194ee37) + .D8(google_breakpad::DW_CFA_advance_loc2).D16(0x3adb) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x3a368bed).ULEB128(0x3194ee37) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc2", section); @@ -906,8 +906,8 @@ TEST_F(CFIInsn, DW_CFA_advance_loc4) { CFISection section(kBigEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_advance_loc4).D32(0x15813c88) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x135270c5).ULEB128(0x24bad7cb) + .D8(google_breakpad::DW_CFA_advance_loc4).D32(0x15813c88) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x135270c5).ULEB128(0x24bad7cb) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc4", section); @@ -927,8 +927,8 @@ TEST_F(CFIInsn, DW_CFA_MIPS_advance_loc8) { CFISection section(kBigEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_MIPS_advance_loc8).D64(0x3c4f3945b92c14ULL) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0xe17ed602).ULEB128(0x3d162e7f) + .D8(google_breakpad::DW_CFA_MIPS_advance_loc8).D64(0x3c4f3945b92c14ULL) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0xe17ed602).ULEB128(0x3d162e7f) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc8", section); @@ -947,7 +947,7 @@ TEST_F(CFIInsn, DW_CFA_def_cfa) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4e363a85).ULEB128(0x815f9aa7) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x4e363a85).ULEB128(0x815f9aa7) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_def_cfa", section); @@ -964,8 +964,8 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_sf) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x8ccb32b7).LEB128(0x9ea) - .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x9b40f5da).LEB128(-0x40a2) + .D8(google_breakpad::DW_CFA_def_cfa_sf).ULEB128(0x8ccb32b7).LEB128(0x9ea) + .D8(google_breakpad::DW_CFA_def_cfa_sf).ULEB128(0x9b40f5da).LEB128(-0x40a2) .FinishEntry(); EXPECT_CALL(handler, @@ -985,7 +985,7 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_register) { CFISection section(kLittleEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0x3e7e9363) + .D8(google_breakpad::DW_CFA_def_cfa_register).ULEB128(0x3e7e9363) .FinishEntry(); EXPECT_CALL(handler, @@ -1002,8 +1002,8 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_registerBadRule) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("needle in a haystack") - .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0xf1b49e49) + .D8(google_breakpad::DW_CFA_def_cfa_expression).Block("needle in a haystack") + .D8(google_breakpad::DW_CFA_def_cfa_register).ULEB128(0xf1b49e49) .FinishEntry(); EXPECT_CALL(handler, @@ -1019,7 +1019,7 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_offset) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) + .D8(google_breakpad::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) .FinishEntry(); EXPECT_CALL(handler, @@ -1035,8 +1035,8 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_offset_sf) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(0x970) - .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(-0x2cd) + .D8(google_breakpad::DW_CFA_def_cfa_offset_sf).LEB128(0x970) + .D8(google_breakpad::DW_CFA_def_cfa_offset_sf).LEB128(-0x2cd) .FinishEntry(); EXPECT_CALL(handler, @@ -1058,8 +1058,8 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_offsetBadRule) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("six ways to Sunday") - .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) + .D8(google_breakpad::DW_CFA_def_cfa_expression).Block("six ways to Sunday") + .D8(google_breakpad::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) .FinishEntry(); EXPECT_CALL(handler, @@ -1074,7 +1074,7 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_expression) { CFISection section(kLittleEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("eating crow") + .D8(google_breakpad::DW_CFA_def_cfa_expression).Block("eating crow") .FinishEntry(); EXPECT_CALL(handler, ValExpressionRule(fde_start, kCFARegister, @@ -1089,7 +1089,7 @@ TEST_F(CFIInsn, DW_CFA_undefined) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x300ce45d) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x300ce45d) .FinishEntry(); EXPECT_CALL(handler, UndefinedRule(fde_start, 0x300ce45d)) @@ -1103,7 +1103,7 @@ TEST_F(CFIInsn, DW_CFA_same_value) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3865a760) + .D8(google_breakpad::DW_CFA_same_value).ULEB128(0x3865a760) .FinishEntry(); EXPECT_CALL(handler, SameValueRule(fde_start, 0x3865a760)) @@ -1117,7 +1117,7 @@ TEST_F(CFIInsn, DW_CFA_offset) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x9f6) + .D8(google_breakpad::DW_CFA_offset | 0x2c).ULEB128(0x9f6) .FinishEntry(); EXPECT_CALL(handler, @@ -1132,7 +1132,7 @@ TEST_F(CFIInsn, DW_CFA_offset_extended) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_offset_extended).ULEB128(0x402b).ULEB128(0xb48) + .D8(google_breakpad::DW_CFA_offset_extended).ULEB128(0x402b).ULEB128(0xb48) .FinishEntry(); EXPECT_CALL(handler, @@ -1147,9 +1147,9 @@ TEST_F(CFIInsn, DW_CFA_offset_extended_sf) { CFISection section(kBigEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_offset_extended_sf) + .D8(google_breakpad::DW_CFA_offset_extended_sf) .ULEB128(0x997c23ee).LEB128(0x2d00) - .D8(dwarf2reader::DW_CFA_offset_extended_sf) + .D8(google_breakpad::DW_CFA_offset_extended_sf) .ULEB128(0x9519eb82).LEB128(-0xa77) .FinishEntry(); @@ -1170,7 +1170,7 @@ TEST_F(CFIInsn, DW_CFA_val_offset) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x623562fe).ULEB128(0x673) + .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0x623562fe).ULEB128(0x673) .FinishEntry(); EXPECT_CALL(handler, @@ -1186,8 +1186,8 @@ TEST_F(CFIInsn, DW_CFA_val_offset_sf) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x6f4f).LEB128(0xaab) - .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x2483).LEB128(-0x8a2) + .D8(google_breakpad::DW_CFA_val_offset_sf).ULEB128(0x6f4f).LEB128(0xaab) + .D8(google_breakpad::DW_CFA_val_offset_sf).ULEB128(0x2483).LEB128(-0x8a2) .FinishEntry(); EXPECT_CALL(handler, @@ -1207,7 +1207,7 @@ TEST_F(CFIInsn, DW_CFA_register) { CFISection section(kLittleEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x278d18f9).ULEB128(0x1a684414) + .D8(google_breakpad::DW_CFA_register).ULEB128(0x278d18f9).ULEB128(0x1a684414) .FinishEntry(); EXPECT_CALL(handler, RegisterRule(fde_start, 0x278d18f9, 0x1a684414)) @@ -1221,7 +1221,7 @@ TEST_F(CFIInsn, DW_CFA_expression) { CFISection section(kBigEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xa1619fb2) + .D8(google_breakpad::DW_CFA_expression).ULEB128(0xa1619fb2) .Block("plus ça change, plus c'est la même chose") .FinishEntry(); @@ -1238,7 +1238,7 @@ TEST_F(CFIInsn, DW_CFA_val_expression) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xc5e4a9e3) + .D8(google_breakpad::DW_CFA_val_expression).ULEB128(0xc5e4a9e3) .Block("he who has the gold makes the rules") .FinishEntry(); @@ -1265,18 +1265,18 @@ TEST_F(CFIInsn, DW_CFA_restore) { .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) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x6ca1d50e).ULEB128(0x372e38e8) // Provide an offset(N) rule for register 0x3c. - .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0xb348) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_advance_loc | 0x13) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_advance_loc | 0x01) + .D8(google_breakpad::DW_CFA_restore | 0x3c) .FinishEntry(); { @@ -1321,16 +1321,16 @@ TEST_F(CFIInsn, DW_CFA_restoreNoRule) { .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) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_advance_loc | 0x7) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_advance_loc | 0xb) + .D8(google_breakpad::DW_CFA_restore | 0x2c) .FinishEntry(); { @@ -1371,20 +1371,20 @@ TEST_F(CFIInsn, DW_CFA_restore_extended) { .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) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x56fa0edd).ULEB128(0x097f78a5) // Provide an offset(N) rule for register 0x0f9b8a1c. - .D8(dwarf2reader::DW_CFA_offset_extended) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_advance_loc | 0x3) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_advance_loc | 0x04) + .D8(google_breakpad::DW_CFA_restore_extended).ULEB128(0x0f9b8a1c) .FinishEntry(); { @@ -1433,21 +1433,21 @@ TEST_F(CFIInsn, DW_CFA_remember_and_restore_state) { // 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) + .D8(google_breakpad::DW_CFA_offset | 2).ULEB128(0x9806) + .D8(google_breakpad::DW_CFA_offset | 3).ULEB128(0x995d) + .D8(google_breakpad::DW_CFA_offset | 4).ULEB128(0x7055) + .D8(google_breakpad::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) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_offset | 1).ULEB128(0xea1a) + .D8(google_breakpad::DW_CFA_register).ULEB128(2).ULEB128(0x1d2a3767) + .D8(google_breakpad::DW_CFA_offset | 3).ULEB128(0xdd29) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); uint64_t addr = fde_start; @@ -1496,11 +1496,11 @@ TEST_F(CFIInsn, DW_CFA_remember_and_restore_stateCFA) { StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x90481102) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_def_cfa_offset).ULEB128(0x90481102) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, kCFARegister, @@ -1519,9 +1519,9 @@ TEST_F(CFIInsn, DW_CFA_nop) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_nop) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3fb8d4f1).ULEB128(0x078dc67b) - .D8(dwarf2reader::DW_CFA_nop) + .D8(google_breakpad::DW_CFA_nop) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x3fb8d4f1).ULEB128(0x078dc67b) + .D8(google_breakpad::DW_CFA_nop) .FinishEntry(); EXPECT_CALL(handler, @@ -1536,9 +1536,11 @@ TEST_F(CFIInsn, DW_CFA_GNU_window_save) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_GNU_window_save) + .D8(google_breakpad::DW_CFA_GNU_window_save) .FinishEntry(); + EXPECT_CALL(handler, Architecture()).WillRepeatedly(Return("sparc")); + // Don't include all the rules in any particular sequence. // The caller's %o0-%o7 have become the callee's %i0-%i7. This is @@ -1561,9 +1563,9 @@ TEST_F(CFIInsn, DW_CFA_GNU_args_size) { CFISection section(kLittleEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_GNU_args_size).ULEB128(0xeddfa520) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_offset | 0x23).ULEB128(0x269) .FinishEntry(); EXPECT_CALL(handler, @@ -1578,7 +1580,7 @@ TEST_F(CFIInsn, DW_CFA_GNU_negative_offset_extended) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_GNU_negative_offset_extended) + .D8(google_breakpad::DW_CFA_GNU_negative_offset_extended) .ULEB128(0x430cc87a).ULEB128(0x613) .FinishEntry(); @@ -1599,19 +1601,19 @@ TEST_F(CFIInsn, SkipFDE) { // CIE, used by all FDEs. .Mark(&cie) .CIEHeader(0x010269f2, 0x9177, 0xedca5849, 2, "") - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x42ed390b).ULEB128(0x98f43aad) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x42ed390b).ULEB128(0x98f43aad) .FinishEntry() // First FDE. .FDEHeader(cie, 0xa870ebdd, 0x60f6aa4) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x3a860351).ULEB128(0x6c9a6bcf) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_register).ULEB128(0x1b62c234).ULEB128(0x26586b18) .FinishEntry() // Third FDE. .FDEHeader(cie, 0xf681cfc8, 0x7e4594e) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x26c53934).ULEB128(0x18eeb8a4) + .D8(google_breakpad::DW_CFA_register).ULEB128(0x26c53934).ULEB128(0x18eeb8a4) .FinishEntry(); { @@ -1652,8 +1654,8 @@ TEST_F(CFIInsn, QuitMidentry) { CFISection section(kLittleEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe0cf850d).ULEB128(0x15aab431) - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x46750aa5).Block("meat") + .D8(google_breakpad::DW_CFA_register).ULEB128(0xe0cf850d).ULEB128(0x15aab431) + .D8(google_breakpad::DW_CFA_expression).ULEB128(0x46750aa5).Block("meat") .FinishEntry(); EXPECT_CALL(handler, RegisterRule(fde_start, 0xe0cf850d, 0x15aab431)) @@ -1670,10 +1672,10 @@ TEST_F(CFIRestore, RestoreUndefinedRuleUnchanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x0bac878e) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x0bac878e) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, UndefinedRule(fde_start, 0x0bac878e)) @@ -1687,12 +1689,12 @@ TEST_F(CFIRestore, RestoreUndefinedRuleChanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x7dedff5f) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x7dedff5f) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x7dedff5f) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_same_value).ULEB128(0x7dedff5f) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, UndefinedRule(fde_start, 0x7dedff5f)) @@ -1710,10 +1712,10 @@ TEST_F(CFIRestore, RestoreSameValueRuleUnchanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0xadbc9b3a) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_same_value).ULEB128(0xadbc9b3a) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, SameValueRule(fde_start, 0xadbc9b3a)) @@ -1727,12 +1729,12 @@ TEST_F(CFIRestore, RestoreSameValueRuleChanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3d90dcb5) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x3d90dcb5) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_same_value).ULEB128(0x3d90dcb5) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x3d90dcb5) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, SameValueRule(fde_start, 0x3d90dcb5)) @@ -1750,10 +1752,10 @@ TEST_F(CFIRestore, RestoreOffsetRuleUnchanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_offset | 0x14).ULEB128(0xb6f) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_offset | 0x14).ULEB128(0xb6f) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, OffsetRule(fde_start, 0x14, @@ -1768,12 +1770,12 @@ TEST_F(CFIRestore, RestoreOffsetRuleChanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xeb7) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x21) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_offset | 0x21).ULEB128(0xeb7) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x21) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, OffsetRule(fde_start, 0x21, @@ -1793,12 +1795,12 @@ TEST_F(CFIRestore, RestoreOffsetRuleChangedOffset) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0x134) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xf4f) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_offset | 0x21).ULEB128(0x134) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_offset | 0x21).ULEB128(0xf4f) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, OffsetRule(fde_start, 0x21, @@ -1819,10 +1821,10 @@ TEST_F(CFIRestore, RestoreValOffsetRuleUnchanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x829caee6).ULEB128(0xe4c) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0x829caee6).ULEB128(0xe4c) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x829caee6, @@ -1837,12 +1839,12 @@ TEST_F(CFIRestore, RestoreValOffsetRuleChanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0xf17c36d6).ULEB128(0xeb7) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xf17c36d6) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0xf17c36d6).ULEB128(0xeb7) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0xf17c36d6) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ValOffsetRule(fde_start, 0xf17c36d6, @@ -1862,12 +1864,12 @@ TEST_F(CFIRestore, RestoreValOffsetRuleChangedValOffset) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0x562) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0xe88) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0x562) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0xe88) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x2cf0ab1b, @@ -1888,10 +1890,10 @@ TEST_F(CFIRestore, RestoreRegisterRuleUnchanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x77514acc).ULEB128(0x464de4ce) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_register).ULEB128(0x77514acc).ULEB128(0x464de4ce) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, RegisterRule(fde_start, 0x77514acc, 0x464de4ce)) @@ -1905,12 +1907,12 @@ TEST_F(CFIRestore, RestoreRegisterRuleChanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe39acce5).ULEB128(0x095f1559) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xe39acce5) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_register).ULEB128(0xe39acce5).ULEB128(0x095f1559) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0xe39acce5) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, RegisterRule(fde_start, 0xe39acce5, 0x095f1559)) @@ -1929,12 +1931,12 @@ TEST_F(CFIRestore, RestoreRegisterRuleChangedRegister) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0x16607d6a) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0xbabb4742) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0x16607d6a) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0xbabb4742) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, RegisterRule(fde_start, 0xd40e21b1, 0x16607d6a)) @@ -1954,10 +1956,10 @@ TEST_F(CFIRestore, RestoreExpressionRuleUnchanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x666ae152).Block("dwarf") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_expression).ULEB128(0x666ae152).Block("dwarf") + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ExpressionRule(fde_start, 0x666ae152, "dwarf")) @@ -1971,12 +1973,12 @@ TEST_F(CFIRestore, RestoreExpressionRuleChanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xb5ca5c46).Block("elf") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_expression).ULEB128(0xb5ca5c46).Block("elf") + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0xb5ca5c46) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ExpressionRule(fde_start, 0xb5ca5c46, "elf")) @@ -1995,12 +1997,12 @@ TEST_F(CFIRestore, RestoreExpressionRuleChangedExpression) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("smurf") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("orc") - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_expression).ULEB128(0x500f5739).Block("smurf") + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_expression).ULEB128(0x500f5739).Block("orc") + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ExpressionRule(fde_start, 0x500f5739, "smurf")) @@ -2021,11 +2023,11 @@ TEST_F(CFIRestore, RestoreValExpressionRuleUnchanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x666ae152) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x666ae152, "hideous")) @@ -2039,13 +2041,13 @@ TEST_F(CFIRestore, RestoreValExpressionRuleChanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xb5ca5c46) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0xb5ca5c46) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChanged", section); @@ -2066,14 +2068,14 @@ TEST_F(CFIRestore, RestoreValExpressionRuleChangedValExpression) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_val_expression).ULEB128(0x500f5739) .Block("nauseous") - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChangedValExpression", @@ -2110,7 +2112,7 @@ struct EHFrameFixture: public CFIInsnFixture { EXPECT_TRUE(section->ContainsEHFrame()); string contents; EXPECT_TRUE(section->GetContents(&contents)); - dwarf2reader::Endianness endianness; + google_breakpad::Endianness endianness; if (section->endianness() == kBigEndian) endianness = ENDIANNESS_BIG; else { @@ -2120,10 +2122,10 @@ struct EHFrameFixture: public CFIInsnFixture { ByteReader byte_reader(endianness); byte_reader.SetAddressSize(section->AddressSize()); byte_reader.SetCFIDataBase(encoded_pointer_bases.cfi, - reinterpret_cast<const uint8_t *>(contents.data())); + 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()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter, true); if (succeeds) @@ -2142,11 +2144,11 @@ TEST_F(EHFrame, Terminator) { section .Mark(&cie) .CIEHeader(9968, 2466, 67, 1, "") - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3772).ULEB128(1372) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_set_loc).D32(0x17713850) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(5721) .FinishEntry() .D32(0) // Terminate the sequence. // This FDE should be ignored. @@ -2172,12 +2174,12 @@ TEST_F(EHFrame, Terminator) { // 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(google_breakpad::DW_EH_PE_indirect + | google_breakpad::DW_EH_PE_datarel + | google_breakpad::DW_EH_PE_sdata2); DwarfPointerEncoding fde_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel - | dwarf2reader::DW_EH_PE_udata2); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_textrel + | google_breakpad::DW_EH_PE_udata2); section.SetPointerEncoding(fde_encoding); section.SetEncodedPointerBases(encoded_pointer_bases); @@ -2187,17 +2189,17 @@ TEST_F(EHFrame, SimpleFDE) { .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(google_breakpad::DW_EH_PE_pcrel) // personality pointer format + .EncodedPointer(0x97baa00, google_breakpad::DW_EH_PE_pcrel) // and value .D8(fde_encoding) // FDE pointer format - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(6706).ULEB128(31) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_set_loc) .EncodedPointer(0x540fa4ce, fde_encoding) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x675e) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x675e) .FinishEntry() .D32(0); // terminator @@ -2228,12 +2230,12 @@ TEST_F(EHFrame, EmptyZ) { .Mark(&cie) .CIEHeader(5955, 5805, 228, 1, "z") .ULEB128(0) // Augmentation data length - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3629).ULEB128(247) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_advance_loc1).D8(11) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(3769) .FinishEntry(); PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.EmptyZ", section); @@ -2257,12 +2259,12 @@ TEST_F(EHFrame, BadZ) { .Mark(&cie) .CIEHeader(6937, 1045, 142, 1, "zQ") .ULEB128(0) // Augmentation data length - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(9006).ULEB128(7725) + .D8(google_breakpad::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) + .D8(google_breakpad::DW_CFA_advance_loc | 12) + .D8(google_breakpad::DW_CFA_register).ULEB128(5667).ULEB128(3462) .FinishEntry(); PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.BadZ", section); @@ -2276,8 +2278,8 @@ TEST_F(EHFrame, BadZ) { TEST_F(EHFrame, zL) { Label cie; DwarfPointerEncoding lsda_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel - | dwarf2reader::DW_EH_PE_udata2); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_funcrel + | google_breakpad::DW_EH_PE_udata2); section .Mark(&cie) .CIEHeader(9285, 9959, 54, 1, "zL") @@ -2306,8 +2308,8 @@ TEST_F(EHFrame, zL) { TEST_F(EHFrame, zP) { Label cie; DwarfPointerEncoding personality_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel - | dwarf2reader::DW_EH_PE_udata2); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_datarel + | google_breakpad::DW_EH_PE_udata2); section .Mark(&cie) .CIEHeader(1097, 6313, 17, 1, "zP") @@ -2335,8 +2337,8 @@ TEST_F(EHFrame, zP) { TEST_F(EHFrame, zR) { Label cie; DwarfPointerEncoding pointer_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel - | dwarf2reader::DW_EH_PE_sdata2); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_textrel + | google_breakpad::DW_EH_PE_sdata2); section.SetPointerEncoding(pointer_encoding); section .Mark(&cie) @@ -2468,7 +2470,7 @@ struct ELFSectionHeader { uint64_t entry_size; }; -void AppendSectionHeader(CFISection *table, const ELFSectionHeader &header) { +void AppendSectionHeader(CFISection* table, const ELFSectionHeader& header) { (*table) .D32(header.name) // name, index in string tbl .D32(header.type) // type @@ -2483,7 +2485,7 @@ void AppendSectionHeader(CFISection *table, const ELFSectionHeader &header) { } void WriteELFFrameSection(const char *filename, const char *cfi_name, - const CFISection &cfi) { + const CFISection& cfi) { int elf_class = cfi.AddressSize() == 4 ? ELFCLASS32 : ELFCLASS64; int elf_data = (cfi.endianness() == kBigEndian ? ELFDATA2MSB : ELFDATA2LSB); diff --git a/src/common/dwarf/dwarf2reader_die_unittest.cc b/src/common/dwarf/dwarf2reader_die_unittest.cc index ca44cad0..fc639a64 100644 --- a/src/common/dwarf/dwarf2reader_die_unittest.cc +++ b/src/common/dwarf/dwarf2reader_die_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -29,7 +28,7 @@ // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> -// dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit +// dwarf2reader_die_unittest.cc: Unit tests for google_breakpad::CompilationUnit #include <stdint.h> #include <stdlib.h> @@ -51,16 +50,16 @@ 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 google_breakpad::ByteReader; +using google_breakpad::CompilationUnit; +using google_breakpad::Dwarf2Handler; +using google_breakpad::DwarfAttribute; +using google_breakpad::DwarfForm; +using google_breakpad::DwarfHasChild; +using google_breakpad::DwarfTag; +using google_breakpad::ENDIANNESS_BIG; +using google_breakpad::ENDIANNESS_LITTLE; +using google_breakpad::SectionMap; using std::vector; using testing::InSequence; @@ -93,7 +92,7 @@ class MockDwarf2Handler: public Dwarf2Handler { MOCK_METHOD5(ProcessAttributeBuffer, void(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, - const uint8_t *data, + const uint8_t* data, uint64_t len)); MOCK_METHOD4(ProcessAttributeString, void(uint64_t offset, enum DwarfAttribute attr, @@ -128,17 +127,17 @@ struct DIEFixture { // 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() { + 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()); + = 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()); + = reinterpret_cast<const uint8_t*>(abbrevs_contents.data()); section_map[".debug_abbrev"].second = abbrevs_contents.size(); return section_map; } @@ -152,13 +151,15 @@ struct DIEFixture { struct DwarfHeaderParams { DwarfHeaderParams(Endianness endianness, size_t format_size, - int version, size_t address_size) + int version, size_t address_size, int header_type) : endianness(endianness), format_size(format_size), - version(version), address_size(address_size) { } + version(version), address_size(address_size), header_type(header_type) + { } Endianness endianness; size_t format_size; // 4-byte or 8-byte DWARF offsets int version; size_t address_size; + int header_type; // DW_UT_{compile, type, partial, skeleton, etc} }; class DwarfHeader: public DIEFixture, @@ -166,16 +167,17 @@ class DwarfHeader: public DIEFixture, 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) + abbrevs.Abbrev(1, google_breakpad::DW_TAG_compile_unit, + google_breakpad::DW_children_yes) + .Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_string) .EndAbbrev() .EndTable(); info.set_format_size(GetParam().format_size); info.set_endianness(GetParam().endianness); - info.Header(GetParam().version, abbrev_table, GetParam().address_size) + info.Header(GetParam().version, abbrev_table, GetParam().address_size, + google_breakpad::DW_UT_compile) .ULEB128(1) // DW_TAG_compile_unit, with children .AppendCString("sam") // DW_AT_name, DW_FORM_string .D8(0); // end of children @@ -188,10 +190,10 @@ TEST_P(DwarfHeader, Header) { GetParam().format_size, _, GetParam().version)) .WillOnce(Return(true)); - EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit)) + EXPECT_CALL(handler, StartDIE(_, google_breakpad::DW_TAG_compile_unit)) .WillOnce(Return(true)); - EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_string, + EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_string, "sam")) .WillOnce(Return()); EXPECT_CALL(handler, EndDIE(_)) @@ -204,44 +206,91 @@ TEST_P(DwarfHeader, Header) { EXPECT_EQ(parser.Start(), info_contents.size()); } -INSTANTIATE_TEST_CASE_P( +TEST_P(DwarfHeader, TypeUnitHeader) { + Label abbrev_table = abbrevs.Here(); + int version = 5; + abbrevs.Abbrev(1, google_breakpad::DW_TAG_type_unit, + google_breakpad::DW_children_yes) + .Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_string) + .EndAbbrev() + .EndTable(); + + info.set_format_size(GetParam().format_size); + info.set_endianness(GetParam().endianness); + + info.Header(version, abbrev_table, GetParam().address_size, + google_breakpad::DW_UT_type) + .ULEB128(0x41) // DW_TAG_type_unit, with children + .AppendCString("sam") // DW_AT_name, DW_FORM_string + .D8(0); // end of children + info.Finish(); + + { + InSequence s; + EXPECT_CALL(handler, + StartCompilationUnit(0, GetParam().address_size, + GetParam().format_size, _, + version)) + .WillOnce(Return(true)); + // If the type unit is handled properly, these calls will be skipped. + EXPECT_CALL(handler, StartDIE(_, google_breakpad::DW_TAG_type_unit)) + .Times(0); + EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_string, + "sam")) + .Times(0); + EXPECT_CALL(handler, EndDIE(_)) + .Times(0); + } + + ByteReader byte_reader(GetParam().endianness == kLittleEndian ? + ENDIANNESS_LITTLE : ENDIANNESS_BIG); + CompilationUnit parser("", MakeSectionMap(), 0, &byte_reader, &handler); + EXPECT_EQ(parser.Start(), info_contents.size()); +} + +INSTANTIATE_TEST_SUITE_P( HeaderVariants, DwarfHeader, - ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4), - 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))); + ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 2, 8, 1), + DwarfHeaderParams(kLittleEndian, 4, 3, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 3, 8, 1), + DwarfHeaderParams(kLittleEndian, 4, 4, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 4, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 2, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 2, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 3, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 3, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 4, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 4, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 5, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 5, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 2, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 2, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 3, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 3, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 4, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 4, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 2, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 2, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 3, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 3, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 4, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 4, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 5, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 5, 8, 1))); struct DwarfFormsFixture: public DIEFixture { // Start a compilation unit, as directed by |params|, containing one // childless DIE of the given tag, with one attribute of the given name // and form. The 'info' fixture member is left just after the abbrev // code, waiting for the attribute value to be appended. - void StartSingleAttributeDIE(const DwarfHeaderParams ¶ms, + 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) + abbrevs.Abbrev(1, tag, google_breakpad::DW_children_no) .Attribute(name, form) .EndAbbrev() .EndTable(); @@ -249,14 +298,15 @@ struct DwarfFormsFixture: public DIEFixture { // 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) + info.Header(params.version, abbrev_table, params.address_size, + google_breakpad::DW_UT_compile) .ULEB128(1); // abbrev code } // Set up handler to expect a compilation unit matching |params|, // containing one childless DIE of the given tag, in the sequence s. Stop // just before the expectations. - void ExpectBeginCompilationUnit(const DwarfHeaderParams ¶ms, + void ExpectBeginCompilationUnit(const DwarfHeaderParams& params, DwarfTag tag, uint64_t offset=0) { EXPECT_CALL(handler, StartCompilationUnit(offset, params.address_size, @@ -275,7 +325,7 @@ struct DwarfFormsFixture: public DIEFixture { .WillOnce(Return()); } - void ParseCompilationUnit(const DwarfHeaderParams ¶ms, + void ParseCompilationUnit(const DwarfHeaderParams& params, uint64_t offset=0) { ByteReader byte_reader(params.endianness == kLittleEndian ? ENDIANNESS_LITTLE : ENDIANNESS_BIG); @@ -291,9 +341,9 @@ 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); + StartSingleAttributeDIE(GetParam(), google_breakpad::DW_TAG_compile_unit, + google_breakpad::DW_AT_low_pc, + google_breakpad::DW_FORM_addr); uint64_t value; if (GetParam().address_size == 4) { value = 0xc8e9ffcc; @@ -304,9 +354,93 @@ TEST_P(DwarfForms, addr) { } info.Finish(); - ExpectBeginCompilationUnit(GetParam(), dwarf2reader::DW_TAG_compile_unit); - EXPECT_CALL(handler, ProcessAttributeUnsigned(_, dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, + ExpectBeginCompilationUnit(GetParam(), google_breakpad::DW_TAG_compile_unit); + EXPECT_CALL(handler, ProcessAttributeUnsigned(_, google_breakpad::DW_AT_low_pc, + google_breakpad::DW_FORM_addr, + value)) + .InSequence(s) + .WillOnce(Return()); + ExpectEndCompilationUnit(); + + ParseCompilationUnit(GetParam()); +} + +TEST_P(DwarfForms, strx1) { + if (GetParam().version != 5) { + return; + } + Label abbrev_table = abbrevs.Here(); + abbrevs.Abbrev(1, google_breakpad::DW_TAG_compile_unit, + google_breakpad::DW_children_no) + .Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_strx1) + .Attribute(google_breakpad::DW_AT_low_pc, google_breakpad::DW_FORM_addr) + .Attribute(google_breakpad::DW_AT_str_offsets_base, + google_breakpad::DW_FORM_sec_offset) + .EndAbbrev() + .EndTable(); + + info.set_format_size(GetParam().format_size); + info.set_endianness(GetParam().endianness); + info.Header(GetParam().version, abbrev_table, GetParam().address_size, + google_breakpad::DW_UT_compile) + .ULEB128(1) // abbrev index + .D8(2); // string index + + uint64_t value; + uint64_t offsets_base; + if (GetParam().address_size == 4) { + value = 0xc8e9ffcc; + offsets_base = 8; + info.D32(value); // low pc + info.D32(offsets_base); // str_offsets_base + } else { + value = 0xe942517fc2768564ULL; + offsets_base = 16; + info.D64(value); // low_pc + info.D64(offsets_base); // str_offsets_base + } + info.Finish(); + + Section debug_strings; + // no header, just a series of null-terminated strings. + debug_strings.AppendCString("apple"); // offset = 0 + debug_strings.AppendCString("bird"); // offset = 6 + debug_strings.AppendCString("canary"); // offset = 11 + debug_strings.AppendCString("dinosaur"); // offset = 18 + + Section str_offsets; + str_offsets.set_endianness(GetParam().endianness); + // Header for .debug_str_offsets + if (GetParam().address_size == 4) { + str_offsets.D32(24); // section length (4 bytes) + } else { + str_offsets.D32(0xffffffff); + str_offsets.D64(48); // section length (12 bytes) + } + str_offsets.D16(GetParam().version); // version (2 bytes) + str_offsets.D16(0); // padding (2 bytes) + + // .debug_str_offsets data (the offsets) + if (GetParam().address_size == 4) { + str_offsets.D32(0); + str_offsets.D32(6); + str_offsets.D32(11); + str_offsets.D32(18); + } else { + str_offsets.D64(0); + str_offsets.D64(6); + str_offsets.D64(11); + str_offsets.D64(18); + } + + + ExpectBeginCompilationUnit(GetParam(), google_breakpad::DW_TAG_compile_unit); + EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_strx1, + "bird")) + .WillOnce(Return()); + EXPECT_CALL(handler, ProcessAttributeUnsigned(_, google_breakpad::DW_AT_low_pc, + google_breakpad::DW_FORM_addr, value)) .InSequence(s) .WillOnce(Return()); @@ -318,13 +452,13 @@ TEST_P(DwarfForms, addr) { TEST_P(DwarfForms, block2_empty) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2); + google_breakpad::DW_FORM_block2); info.D16(0); info.Finish(); ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7); EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2, + google_breakpad::DW_FORM_block2, _, 0)) .InSequence(s) .WillOnce(Return()); @@ -336,7 +470,7 @@ TEST_P(DwarfForms, block2_empty) { TEST_P(DwarfForms, block2) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2); + google_breakpad::DW_FORM_block2); unsigned char data[258]; memset(data, '*', sizeof(data)); info.D16(sizeof(data)) @@ -345,7 +479,7 @@ TEST_P(DwarfForms, block2) { ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7); EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2, + google_breakpad::DW_FORM_block2, Pointee('*'), 258)) .InSequence(s) .WillOnce(Return()); @@ -357,14 +491,14 @@ TEST_P(DwarfForms, block2) { TEST_P(DwarfForms, flag_present) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2, (DwarfAttribute) 0x359d1972, - dwarf2reader::DW_FORM_flag_present); + google_breakpad::DW_FORM_flag_present); // DW_FORM_flag_present occupies no space in the DIE. info.Finish(); ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2); EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972, - dwarf2reader::DW_FORM_flag_present, + google_breakpad::DW_FORM_flag_present, 1)) .InSequence(s) .WillOnce(Return()); @@ -376,7 +510,7 @@ TEST_P(DwarfForms, flag_present) { TEST_P(DwarfForms, sec_offset) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689, (DwarfAttribute) 0xa060bfd1, - dwarf2reader::DW_FORM_sec_offset); + google_breakpad::DW_FORM_sec_offset); uint64_t value; if (GetParam().format_size == 4) { value = 0xacc9c388; @@ -389,7 +523,7 @@ TEST_P(DwarfForms, sec_offset) { ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689); EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1, - dwarf2reader::DW_FORM_sec_offset, + google_breakpad::DW_FORM_sec_offset, value)) .InSequence(s) .WillOnce(Return()); @@ -401,14 +535,14 @@ TEST_P(DwarfForms, sec_offset) { TEST_P(DwarfForms, exprloc) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb, (DwarfAttribute) 0xba3ae5cb, - dwarf2reader::DW_FORM_exprloc); + google_breakpad::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, + google_breakpad::DW_FORM_exprloc, Pointee(173), 29)) .InSequence(s) .WillOnce(Return()); @@ -420,13 +554,13 @@ TEST_P(DwarfForms, exprloc) { TEST_P(DwarfForms, ref_sig8) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8); + google_breakpad::DW_FORM_ref_sig8); info.D64(0xf72fa0cb6ddcf9d6ULL); info.Finish(); ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b); EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8, + google_breakpad::DW_FORM_ref_sig8, 0xf72fa0cb6ddcf9d6ULL)) .InSequence(s) .WillOnce(Return()); @@ -444,13 +578,13 @@ TEST_P(DwarfForms, ref_sig8_not_first) { info.Append(98, '*'); StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8); + google_breakpad::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, + google_breakpad::DW_FORM_ref_sig8, 0xf72fa0cb6ddcf9d6ULL)) .InSequence(s) .WillOnce(Return()); @@ -459,31 +593,371 @@ TEST_P(DwarfForms, ref_sig8_not_first) { ParseCompilationUnit(GetParam(), 98); } +TEST_P(DwarfForms, implicit_const) { + const DwarfHeaderParams& params = GetParam(); + const uint64_t implicit_constant_value = 0x1234; + // Create the abbreviation table. + Label abbrev_table = abbrevs.Here(); + abbrevs.Abbrev(1, (DwarfTag) 0x253e7b2b, google_breakpad::DW_children_no) + .Attribute((DwarfAttribute) 0xd708d908, + google_breakpad::DW_FORM_implicit_const) + .ULEB128(implicit_constant_value); + abbrevs.EndAbbrev().EndTable(); + + info.set_format_size(params.format_size); + info.set_endianness(params.endianness); + info.Header(params.version, abbrev_table, params.address_size, + google_breakpad::DW_UT_compile) + .ULEB128(1); // abbrev code + info.Finish(); + + ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b); + EXPECT_CALL(handler, + ProcessAttributeUnsigned(_, (DwarfAttribute) 0xd708d908, + google_breakpad::DW_FORM_implicit_const, + implicit_constant_value)) + .InSequence(s) + .WillOnce(Return()); + ExpectEndCompilationUnit(); + + ParseCompilationUnit(GetParam()); +} + // Tests for the other attribute forms could go here. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_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))); + ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 2, 8, 1), + DwarfHeaderParams(kLittleEndian, 4, 3, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 3, 8, 1), + DwarfHeaderParams(kLittleEndian, 4, 4, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 4, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 2, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 2, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 3, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 3, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 4, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 4, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 2, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 2, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 3, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 3, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 4, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 4, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 2, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 2, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 3, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 3, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 4, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 4, 8, 1))); + +class MockRangeListHandler: public google_breakpad::RangeListHandler { + public: + MOCK_METHOD(void, AddRange, (uint64_t begin, uint64_t end)); + MOCK_METHOD(void, Finish, ()); +}; + +TEST(RangeList, Dwarf4ReadRangeList) { + using google_breakpad::RangeListReader; + using google_breakpad::DW_FORM_sec_offset; + + // Create a dwarf4 .debug_ranges section. + google_breakpad::test_assembler::Section ranges(kBigEndian); + std::string padding_offset = "padding offset"; + ranges.Append(padding_offset); + const uint64_t section_offset = ranges.Size(); + ranges.D32(1).D32(2); // (2, 3) + ranges.D32(0xFFFFFFFF).D32(3); // base_address = 3. + ranges.D32(1).D32(2); // (4, 5) + ranges.D32(0).D32(1); // (3, 4) An out of order entry is legal. + ranges.D32(0).D32(0); // End of range. + + std::string section_contents; + ranges.GetContents(§ion_contents); + + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(4); + + RangeListReader::CURangesInfo cu_info; + // Only set the fields that matter for dwarf 4. + cu_info.version_ = 4; + cu_info.base_address_ = 1; + cu_info.buffer_ = reinterpret_cast<const uint8_t*>(section_contents.data()); + cu_info.size_ = section_contents.size(); + + MockRangeListHandler handler; + google_breakpad::RangeListReader range_list_reader(&byte_reader, &cu_info, + &handler); + EXPECT_CALL(handler, AddRange(2, 3)); + EXPECT_CALL(handler, AddRange(4, 5)); + EXPECT_CALL(handler, AddRange(3, 4)); + EXPECT_CALL(handler, Finish()); + EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, + section_offset)); +} + +TEST(RangeList, Dwarf5ReadRangeList_rnglists) { + using google_breakpad::RangeListReader; + using google_breakpad::DW_RLE_base_addressx; + using google_breakpad::DW_RLE_startx_endx; + using google_breakpad::DW_RLE_startx_length; + using google_breakpad::DW_RLE_offset_pair; + using google_breakpad::DW_RLE_end_of_list; + using google_breakpad::DW_RLE_base_address; + using google_breakpad::DW_RLE_start_end; + using google_breakpad::DW_RLE_start_length; + using google_breakpad::DW_FORM_sec_offset; + using google_breakpad::DW_FORM_rnglistx; + + // Size of header + const uint64_t header_size = 12; + // Size of length field in header + const uint64_t length_size = 4; + + // .debug_addr for the indexed entries like startx. + Section addr; + addr.set_endianness(kBigEndian); + // Test addr_base handling with a padding address at 0. + addr.D32(0).D32(1).D32(2).D32(3).D32(4); + std::string addr_contents; + assert(addr.GetContents(&addr_contents)); + + // .debug_rnglists is the dwarf 5 section. + Section rnglists1(kBigEndian); + Section rnglists2(kBigEndian); + + // First header and body. + Label section_size1; + rnglists1.Append(kBigEndian, length_size, section_size1); + rnglists1.D16(5); // Version + rnglists1.D8(4); // Address size + rnglists1.D8(0); // Segment selector size + rnglists1.D32(2); // Offset entry count + const uint64_t ranges_base_1 = rnglists1.Size(); + + // Offset entries. + Label range0; + rnglists1.Append(kBigEndian, 4, range0); + Label range1; + rnglists1.Append(kBigEndian, 4, range1); + + // Range 0 (will be read via DW_AT_ranges, DW_FORM_rnglistx). + range0 = rnglists1.Size() - header_size; + rnglists1.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1 + rnglists1.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3) + rnglists1.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5) + rnglists1.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7) + rnglists1.D8(DW_RLE_end_of_list); + + // Range 1 (will be read via DW_AT_ranges, DW_FORM_rnglistx). + range1 = rnglists1.Size() - header_size; + rnglists1.D8(DW_RLE_base_address).D32(8); // base_addr = 8 + rnglists1.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [9, 10) + rnglists1.D8(DW_RLE_start_end).D32(10).D32(11); // [10, 11) + rnglists1.D8(DW_RLE_start_length).D32(12).ULEB128(1); // [12, 13) + rnglists1.D8(DW_RLE_end_of_list); + // The size doesn't include the size of length field itself. + section_size1 = rnglists1.Size() - length_size; + + // Second header and body. + Label section_size2; + rnglists2.Append(kBigEndian, length_size, section_size2); + rnglists2.D16(5); // Version + rnglists2.D8(4); // Address size + rnglists2.D8(0); // Segment selector size + rnglists2.D32(2); // Offset entry count + const uint64_t ranges_base_2 = rnglists1.Size() + rnglists2.Size(); + + // Offset entries. + Label range2; + rnglists2.Append(kBigEndian, 4, range2); + Label range3; + rnglists2.Append(kBigEndian, 4, range3); + + // Range 2 (will be read via DW_AT_ranges, DW_FORM_sec_offset). + range2 = rnglists2.Size() - header_size; + rnglists2.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1 + rnglists2.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3) + rnglists2.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5) + rnglists2.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7) + rnglists2.D8(DW_RLE_end_of_list); + + // Range 3 (will be read via DW_AT_ranges, DW_FORM_rnglistx). + range3 = rnglists2.Size() - header_size; + rnglists2.D8(DW_RLE_base_address).D32(15); // base_addr = 15 + rnglists2.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [16, 17) + rnglists2.D8(DW_RLE_start_end).D32(17).D32(18); // [17, 18) + rnglists2.D8(DW_RLE_start_length).D32(19).ULEB128(1); // [19, 20) + rnglists2.D8(DW_RLE_end_of_list); + // The size doesn't include the size of length field itself. + section_size2 = rnglists2.Size() - length_size; + + rnglists1.Append(rnglists2); + string rnglists_contents; + assert(rnglists1.GetContents(&rnglists_contents)); + + RangeListReader::CURangesInfo cu_info; + cu_info.version_ = 5; + cu_info.base_address_ = 1; + cu_info.ranges_base_ = ranges_base_1; + cu_info.buffer_ = + reinterpret_cast<const uint8_t*>(rnglists_contents.data()); + cu_info.size_ = rnglists_contents.size(); + cu_info.addr_buffer_ = + reinterpret_cast<const uint8_t*>(addr_contents.data()); + cu_info.addr_buffer_size_ = addr_contents.size(); + cu_info.addr_base_ = 4; + + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetOffsetSize(4); + byte_reader.SetAddressSize(4); + MockRangeListHandler handler; + google_breakpad::RangeListReader range_list_reader1(&byte_reader, &cu_info, + &handler); + EXPECT_CALL(handler, AddRange(2, 3)); + EXPECT_CALL(handler, AddRange(4, 5)); + EXPECT_CALL(handler, AddRange(6, 7)); + EXPECT_CALL(handler, AddRange(9, 10)); + EXPECT_CALL(handler, AddRange(10, 11)); + EXPECT_CALL(handler, AddRange(12, 13)); + EXPECT_CALL(handler, Finish()).Times(2); + EXPECT_TRUE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 0)); + EXPECT_TRUE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 1)); + // Out of range index, should result in no calls. + EXPECT_FALSE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 2)); + + // Set to new ranges_base + cu_info.ranges_base_ = ranges_base_2; + google_breakpad::RangeListReader range_list_reader2(&byte_reader, &cu_info, + &handler); + EXPECT_CALL(handler, AddRange(2, 3)); + EXPECT_CALL(handler, AddRange(4, 5)); + EXPECT_CALL(handler, AddRange(6, 7)); + EXPECT_CALL(handler, AddRange(16, 17)); + EXPECT_CALL(handler, AddRange(17, 18)); + EXPECT_CALL(handler, AddRange(19, 20)); + EXPECT_CALL(handler, Finish()).Times(2); + EXPECT_TRUE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 0)); + EXPECT_TRUE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 1)); + // Out of range index, should result in no calls. + EXPECT_FALSE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 2)); +} + +TEST(RangeList, Dwarf5ReadRangeList_sec_offset) { + using google_breakpad::RangeListReader; + using google_breakpad::DW_RLE_base_addressx; + using google_breakpad::DW_RLE_startx_endx; + using google_breakpad::DW_RLE_startx_length; + using google_breakpad::DW_RLE_offset_pair; + using google_breakpad::DW_RLE_end_of_list; + using google_breakpad::DW_RLE_base_address; + using google_breakpad::DW_RLE_start_end; + using google_breakpad::DW_RLE_start_length; + using google_breakpad::DW_FORM_sec_offset; + using google_breakpad::DW_FORM_rnglistx; + + // Size of length field in header + const uint64_t length_size = 4; + + // .debug_addr for the indexed entries like startx. + Section addr; + addr.set_endianness(kBigEndian); + // Test addr_base handling with a padding address at 0. + addr.D32(0).D32(1).D32(2).D32(3).D32(4).D32(21).D32(22); + std::string addr_contents; + assert(addr.GetContents(&addr_contents)); + + // .debug_rnglists is the dwarf 5 section. + Section rnglists1(kBigEndian); + Section rnglists2(kBigEndian); + + // First header and body. + Label section_size1; + rnglists1.Append(kBigEndian, length_size, section_size1); + rnglists1.D16(5); // Version + rnglists1.D8(4); // Address size + rnglists1.D8(0); // Segment selector size + rnglists1.D32(0); // Offset entry count + + const uint64_t offset1 = rnglists1.Size(); + + rnglists1.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1 + rnglists1.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3) + rnglists1.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5) + rnglists1.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7) + rnglists1.D8(DW_RLE_base_address).D32(8); // base_addr = 8 + rnglists1.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [9, 10) + rnglists1.D8(DW_RLE_start_end).D32(10).D32(11); // [10, 11) + rnglists1.D8(DW_RLE_start_length).D32(12).ULEB128(1); // [12, 13) + rnglists1.D8(DW_RLE_end_of_list); + // The size doesn't include the size of length field itself. + section_size1 = rnglists1.Size() - length_size; + + // Second header and body. + Label section_size2; + rnglists2.Append(kBigEndian, length_size, section_size2); + rnglists2.D16(5); // Version + rnglists2.D8(4); // Address size + rnglists2.D8(0); // Segment selector size + rnglists2.D32(0); // Offset entry count + + const uint64_t offset2 = rnglists1.Size() + rnglists2.Size(); + + rnglists2.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1 + rnglists2.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3) + rnglists2.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5) + rnglists2.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7) + rnglists2.D8(DW_RLE_base_address).D32(15); // base_addr = 15 + rnglists2.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [16, 17) + rnglists2.D8(DW_RLE_start_end).D32(17).D32(18); // [17, 18) + rnglists2.D8(DW_RLE_start_length).D32(19).ULEB128(1); // [19, 20) + rnglists2.D8(DW_RLE_end_of_list); + // The size doesn't include the size of length field itself. + section_size2 = rnglists2.Size() - length_size; + + rnglists1.Append(rnglists2); + string rnglists_contents; + assert(rnglists1.GetContents(&rnglists_contents)); + + RangeListReader::CURangesInfo cu_info; + cu_info.version_ = 5; + cu_info.base_address_ = 1; + cu_info.buffer_ = + reinterpret_cast<const uint8_t*>(rnglists_contents.data()); + cu_info.size_ = rnglists_contents.size(); + cu_info.addr_buffer_ = + reinterpret_cast<const uint8_t*>(addr_contents.data()); + cu_info.addr_buffer_size_ = addr_contents.size(); + cu_info.addr_base_ = 4; + + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetOffsetSize(4); + byte_reader.SetAddressSize(4); + MockRangeListHandler handler; + google_breakpad::RangeListReader range_list_reader(&byte_reader, &cu_info, + &handler); + EXPECT_CALL(handler, AddRange(2, 3)); + EXPECT_CALL(handler, AddRange(4, 5)); + EXPECT_CALL(handler, AddRange(6, 7)); + EXPECT_CALL(handler, AddRange(9, 10)); + EXPECT_CALL(handler, AddRange(10, 11)); + EXPECT_CALL(handler, AddRange(12, 13)); + EXPECT_CALL(handler, Finish()).Times(1); + EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, offset1)); + // Out of range index, should result in no calls. + EXPECT_FALSE(range_list_reader.ReadRanges(DW_FORM_sec_offset, + rnglists_contents.size())); + + EXPECT_CALL(handler, AddRange(2, 3)); + EXPECT_CALL(handler, AddRange(4, 5)); + EXPECT_CALL(handler, AddRange(6, 7)); + EXPECT_CALL(handler, AddRange(16, 17)); + EXPECT_CALL(handler, AddRange(17, 18)); + EXPECT_CALL(handler, AddRange(19, 20)); + EXPECT_CALL(handler, Finish()).Times(1); + EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, offset2)); + // Out of range index, should result in no calls. + EXPECT_FALSE(range_list_reader.ReadRanges(DW_FORM_sec_offset, + rnglists_contents.size())); +} diff --git a/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc b/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc new file mode 100644 index 00000000..033c6333 --- /dev/null +++ b/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc @@ -0,0 +1,186 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Sterling Augustine <saugustine@google.com> + +// dwarf2reader_lineinfo_unittest.cc: Unit tests for google_breakpad::LineInfo + +#include <stdint.h> +#include <stdlib.h> + +#include <string> +#include <vector> + +#include "breakpad_googletest_includes.h" +#include "common/dwarf/bytereader.h" +#include "common/dwarf/dwarf2reader.h" +#include "google_breakpad/common/breakpad_types.h" + +using std::vector; +using testing::InSequence; +using testing::Return; +using testing::Sequence; +using testing::Test; +using testing::_; + +using namespace google_breakpad; + +namespace { + +const uint8_t dwarf5_line_program[] = { + 0x40, 0x0, 0x0, 0x0, // unit_length (end - begin) + // begin + 0x05, 0x0, // version + 0x8, // address_size + 0x0, // segment_selector_size + 0x26, 0x0, 0x0, 0x0, // header_length (end_header_end - begin_header) + // begin_header: + 0x1, // minimum_instruction_length + 0x1, // maximum_operations_per_instruction + 0x1, // default_is_stmt + 0xfb, // line_base + 0xe, // line_range + 0xd, // opcode_base and lengths + 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1, + 0x1, // directory entry format count + DW_LNCT_path, DW_FORM_strp, + 0x1, // directories count + 0x1, 0x0, 0x0, 0x0, // offset into .debug_line_str + 0x2, // file_name_entry_format_count + DW_LNCT_directory_index, DW_FORM_data1, + DW_LNCT_path, DW_FORM_line_strp, + 0x1, // filename count + 0x0, // directory index + 0x1, 0x0, 0x0, 0x0, // offset into .debug_str + // end_header + DW_LNS_set_file, 0x0, + // set address to 0x0 + 0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + // Advance Address by 0 and line by 3 + 0x15, + // Advance PC by 1 + 0x2, 0x1, + 0x0, + DW_LNE_end_sequence, + DW_LNE_end_sequence, + // end +}; + +const uint8_t dwarf4_line_program[] = { + 0x37, 0x0, 0x0, 0x0, // unit_length (end - begin) + // begin + 0x04, 0x0, // version + 0x1d, 0x0, 0x0, 0x0, // header_length (end_header - begin_header) + // begin_header: + 0x1, // minimum_instruction_length + 0x1, // maximum_operations_per_instruction + 0x1, // default_is_stmt + 0xfb, // line_base + 0xe, // line_range + 0xd, // opcode_base and lengths + 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1, + '/', 'a', '\0', // directory entry 1 (zeroth entry implied) + '\0', // end of directory table + 'b', '/', 'c', '\0', // file entry 1 (zeroth entry implied) + 0, // file 1 directory + 0, // file 1 modification time + 0, // file 1 length + '\0', // end of file table + // end_header + DW_LNS_set_file, 0x0, + // set address to 0x0 + 0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + // Advance Address by 0 and line by 3 + 0x15, + // Advance PC by 1 + 0x2, 0x1, + 0x0, + DW_LNE_end_sequence, + DW_LNE_end_sequence, + // end +}; + +class MockLineInfoHandler: public LineInfoHandler { + public: + MOCK_METHOD(void, DefineDir, (const string&, uint32_t dir_num), (override)); + MOCK_METHOD(void, DefineFile, (const string& name, int32_t file_num, + uint32_t dir_num, uint64_t mod_time, + uint64_t length), (override)); + MOCK_METHOD(void, AddLine, (uint64_t address, uint64_t length, + uint32_t file_num, uint32_t line_num, + uint32_t column_num), (override)); +}; + +const uint8_t string_section[] = {'x', '/', 'a', '\0'}; +const uint8_t line_string_section[] = {'x', 'b', '/', 'c', '\0' }; + +struct LineProgram: public Test { + MockLineInfoHandler handler_; +}; + +TEST_F(LineProgram, ReadLinesDwarf5) { + ByteReader byte_reader(ENDIANNESS_LITTLE); + // LineTables don't specify the offset size like Compilation Units do. + byte_reader.SetOffsetSize(4); + LineInfo line_reader(dwarf5_line_program, + sizeof(dwarf5_line_program), + &byte_reader, + string_section, + sizeof(string_section), + line_string_section, + sizeof(line_string_section), + &handler_); + EXPECT_CALL(handler_, DefineDir("/a", 0)).Times(1); + EXPECT_CALL(handler_, DefineFile("b/c", 0, 0, 0, 0)).Times(1); + EXPECT_CALL(handler_, AddLine(0, 1, 0, 4, 0)).Times(1); + EXPECT_EQ(line_reader.Start(), sizeof(dwarf5_line_program)); +} + +TEST_F(LineProgram, ReadLinesDwarf4) { + ByteReader byte_reader(ENDIANNESS_LITTLE); + // LineTables don't specify the offset size like Compilation Units do. + byte_reader.SetOffsetSize(4); + // dwarf4 line info headers don't encode the address size. + byte_reader.SetAddressSize(8); + LineInfo line_reader(dwarf4_line_program, + sizeof(dwarf4_line_program), + &byte_reader, + // dwarf4 line tables can't access the string sections + // so pass values likely to make assertions fail if + // the code uses them improperly. + nullptr, 0, nullptr, 0, + &handler_); + EXPECT_CALL(handler_, DefineDir("", 0)).Times(1); + EXPECT_CALL(handler_, DefineDir("/a", 1)).Times(1); + EXPECT_CALL(handler_, DefineFile("", 0, 0, 0, 0)).Times(1); + EXPECT_CALL(handler_, DefineFile("b/c", 1, 0, 0, 0)).Times(1); + EXPECT_CALL(handler_, AddLine(0, 1, 0, 4, 0)).Times(1); + EXPECT_EQ(line_reader.Start(), sizeof(dwarf4_line_program)); +} + +} // anonymous namespace diff --git a/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc b/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc new file mode 100644 index 00000000..9ceea109 --- /dev/null +++ b/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc @@ -0,0 +1,125 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Snehasish Kumar <snehasishk@google.com> + +// dwarf2reader_splitfunctions_unittest.cc: Unit tests for with a focus on debug +// information generated when with splitting optimizations such as +// -fsplit-machine-functions (clang) -freorder-blocks-and-partition (gcc). + +#include <stdint.h> +#include <stdlib.h> + +#include <string> + +#include "breakpad_googletest_includes.h" +#include "common/dwarf/bytereader.h" +#include "common/dwarf/dwarf2reader.h" +#include "google_breakpad/common/breakpad_types.h" + +using testing::_; +using namespace google_breakpad; + +namespace { + +class MockLineInfoHandler: public LineInfoHandler { + public: + MOCK_METHOD(void, DefineFile, (const string& name, int32_t file_num, + uint32_t dir_num, uint64_t mod_time, + uint64_t length), (override)); + MOCK_METHOD(void, AddLine, (uint64_t address, uint64_t length, + uint32_t file_num, uint32_t line_num, + uint32_t column_num), (override)); +}; + +struct LineProgram: public testing::Test { + MockLineInfoHandler handler_; +}; + +// The debug information is generated from the following program -- +// $ cat -n split_functions.c +// 1 #include <stdio.h> +// 2 +// 3 __attribute__((noinline)) int foo(int i) { +// 4 if (i % 100) { +// 5 return i + 1; +// 6 } else { +// 7 return i * 10 % 3; +// 8 } +// 9 } +// 10 +// 11 +// 12 int main(int argc, char *argv[]) { +// 13 int total = 0; +// 14 for (int i = 0; i < 1000; ++i) { +// 15 total += foo(i); +// 16 } +// 17 printf("%d\n", total); +// 18 } +// +// $ bin/clang -fprofile-generate -O2 split_functions.c +// $ ./a.out > /dev/null +// $ bin/llvm-profdata merge -o default.profdata default_*.profraw +// $ bin/clang -fprofile-use -O2 -gmlt -gdwarf-5 -fsplit-machine-functions \ +// split_functions.c -o split.out +// +// For the test we pick the first instruction in foo.cold which should be the +// else part of the function foo above. + +const uint8_t debug_line[] = { + 0xb0,0x0,0x0,0x0,0x5,0x0,0x8,0x0,0x37,0x0,0x0,0x0,0x1,0x1,0x1,0xfb,0xe,0xd,0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x1,0x1,0x1f,0x1,0x0,0x0,0x0,0x0,0x3,0x1,0x1f,0x2,0xf,0x5,0x1e,0x1,0x3d,0x0,0x0,0x0,0x0,0x24,0xb2,0xb6,0xb5,0xbb,0xf,0xf7,0x6d,0x27,0x92,0xab,0x55,0x3a,0x29,0x48,0x81,0x4,0x0,0x0,0x9,0x2,0x40,0x10,0x40,0x0,0x0,0x0,0x0,0x0,0x14,0x5,0x9,0xa,0x2f,0x5,0x7,0x6,0x8,0x4a,0x5,0xe,0x6,0x67,0x5,0x1,0x40,0x5,0x0,0xf5,0x5,0xe,0xa,0xf5,0x5,0xb,0x6,0x74,0x5,0x1d,0x6,0x2d,0x5,0x15,0x6,0x3c,0x5,0x3,0x66,0x2,0x7,0x0,0x1,0x1,0x4,0x0,0x5,0xe,0x0,0x9,0x2,0x84,0x11,0x40,0x0,0x0,0x0,0x0,0x0,0x18,0x5,0x13,0x6,0x58,0x5,0x1,0x6,0x8,0xa0,0x2,0x1,0x0,0x1,0x1,0x4,0x0,0x5,0x3,0x0,0x9,0x2,0xa5,0x11,0x40,0x0,0x0,0x0,0x0,0x0,0x3,0x10,0x1,0x5,0x1,0xd7,0x2,0x9,0x0,0x1,0x1 +}; + +const uint8_t debug_str[] = { + 0x63,0x6c,0x61,0x6e,0x67,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x32,0x2e,0x30,0x2e,0x30,0x20,0x28,0x67,0x69,0x74,0x40,0x67,0x69,0x74,0x68,0x75,0x62,0x2e,0x63,0x6f,0x6d,0x3a,0x6c,0x6c,0x76,0x6d,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2e,0x67,0x69,0x74,0x20,0x63,0x37,0x35,0x61,0x30,0x61,0x31,0x65,0x39,0x64,0x63,0x32,0x39,0x62,0x65,0x34,0x65,0x30,0x30,0x64,0x33,0x37,0x64,0x30,0x64,0x30,0x30,0x32,0x38,0x38,0x61,0x66,0x63,0x31,0x61,0x36,0x31,0x35,0x33,0x66,0x29,0x0,0x73,0x70,0x6c,0x69,0x74,0x5f,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x63,0x0,0x2f,0x75,0x73,0x72,0x2f,0x6c,0x6f,0x63,0x61,0x6c,0x2f,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2f,0x68,0x6f,0x6d,0x65,0x2f,0x73,0x6e,0x65,0x68,0x61,0x73,0x69,0x73,0x68,0x6b,0x2f,0x77,0x6f,0x72,0x6b,0x69,0x6e,0x67,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2f,0x62,0x75,0x69,0x6c,0x64,0x0,0x66,0x6f,0x6f,0x0,0x69,0x6e,0x74,0x0,0x6d,0x61,0x69,0x6e,0x0,0x69,0x0,0x61,0x72,0x67,0x63,0x0,0x61,0x72,0x67,0x76,0x0,0x63,0x68,0x61,0x72,0x0,0x74,0x6f,0x74,0x61,0x6c,0x0 +}; + +const uint8_t debug_line_str[] = { + 0x2f,0x75,0x73,0x72,0x2f,0x6c,0x6f,0x63,0x61,0x6c,0x2f,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2f,0x68,0x6f,0x6d,0x65,0x2f,0x73,0x6e,0x65,0x68,0x61,0x73,0x69,0x73,0x68,0x6b,0x2f,0x77,0x6f,0x72,0x6b,0x69,0x6e,0x67,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2f,0x62,0x75,0x69,0x6c,0x64,0x0,0x73,0x70,0x6c,0x69,0x74,0x5f,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x63,0x0 +}; + +TEST_F(LineProgram, ReadLinesSplitFunctions) { + ByteReader byte_reader(ENDIANNESS_LITTLE); + // LineTables don't specify the offset size like Compilation Units do. + byte_reader.SetOffsetSize(4); + LineInfo line_reader(debug_line, + sizeof(debug_line), + &byte_reader, + debug_str, + sizeof(debug_str), + debug_line_str, + sizeof(debug_line_str), + &handler_); + EXPECT_CALL(handler_, DefineFile("split_functions.c", 0, 0, 0, 0)).Times(1); + EXPECT_CALL(handler_, AddLine(_, _, _, _, _)).Times(testing::AtLeast(1)); + // Pick the first address from the foo.cold symbol and check the line number. + EXPECT_CALL(handler_, AddLine(testing::Eq(0x401184lu), _, _, /*line_num*/ 7, _)).Times(1); + EXPECT_EQ(line_reader.Start(), sizeof(debug_line)); +} + +} // anonymous namespace diff --git a/src/common/dwarf/dwarf2reader_test_common.h b/src/common/dwarf/dwarf2reader_test_common.h index e91de906..1c45d527 100644 --- a/src/common/dwarf/dwarf2reader_test_common.h +++ b/src/common/dwarf/dwarf2reader_test_common.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -45,9 +44,9 @@ // 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::DwarfTag DwarfTag; + typedef google_breakpad::DwarfAttribute DwarfAttribute; + typedef google_breakpad::DwarfForm DwarfForm; typedef google_breakpad::test_assembler::Label Label; // Set the section's DWARF format size (the 32-bit DWARF format or the @@ -57,7 +56,7 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section { 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> @@ -70,8 +69,8 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section { // 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) { + TestCompilationUnit& Header(int version, const Label& abbrev_offset, + size_t address_size, int header_type) { if (format_size_ == 4) { D32(length_); } else { @@ -80,13 +79,28 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section { } post_length_offset_ = Size(); D16(version); - SectionOffset(abbrev_offset); - D8(address_size); + if (version <= 4) { + SectionOffset(abbrev_offset); + D8(address_size); + } else { + D8(header_type); // DW_UT_compile, DW_UT_type, etc. + D8(address_size); + SectionOffset(abbrev_offset); + if (header_type == google_breakpad::DW_UT_type) { + uint64_t dummy_type_signature = 0xdeadbeef; + uint64_t dummy_type_offset = 0x2b; + D64(dummy_type_signature); + if (format_size_ == 4) + D32(dummy_type_offset); + else + D64(dummy_type_offset); + } + } return *this; } // Mark the end of this header's DIEs. - TestCompilationUnit &Finish() { + TestCompilationUnit& Finish() { length_ = Size() - post_length_offset_; return *this; } @@ -107,16 +121,16 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section { // 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::DwarfTag DwarfTag; + typedef google_breakpad::DwarfAttribute DwarfAttribute; + typedef google_breakpad::DwarfForm DwarfForm; + typedef google_breakpad::DwarfHasChild DwarfHasChild; typedef google_breakpad::test_assembler::Label Label; // Start a new abbreviation table entry for abbreviation code |code|, // encoding a DIE whose tag is |tag|, and which has children if and only // if |has_children| is true. - TestAbbrevTable &Abbrev(int code, DwarfTag tag, DwarfHasChild has_children) { + TestAbbrevTable& Abbrev(int code, DwarfTag tag, DwarfHasChild has_children) { assert(code != 0); ULEB128(code); ULEB128(static_cast<unsigned>(tag)); @@ -126,21 +140,21 @@ class TestAbbrevTable: public google_breakpad::test_assembler::Section { // Add an attribute to the current abbreviation code whose name is |name| // and whose form is |form|. - TestAbbrevTable &Attribute(DwarfAttribute name, DwarfForm 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() { + TestAbbrevTable& EndAbbrev() { ULEB128(0); ULEB128(0); return *this; } // Finish the current abbreviation table. - TestAbbrevTable &EndTable() { + TestAbbrevTable& EndTable() { ULEB128(0); return *this; } diff --git a/src/common/dwarf/elf_reader.cc b/src/common/dwarf/elf_reader.cc index 1b665213..7664377c 100644 --- a/src/common/dwarf/elf_reader.cc +++ b/src/common/dwarf/elf_reader.cc @@ -1,4 +1,4 @@ -// Copyright 2005 Google Inc. All Rights Reserved. +// Copyright 2005 Google LLC // Author: chatham@google.com (Andrew Chatham) // Author: satorux@google.com (Satoru Takabayashi) // @@ -41,6 +41,7 @@ #include <algorithm> #include <map> #include <string> +#include <string_view> #include <vector> // TODO(saugustine): Add support for compressed debug. // Also need to add configure tests for zlib. @@ -106,9 +107,15 @@ const int kAARCH64PLT0Size = 0x20; // Suffix for PLT functions when it needs to be explicitly identified as such. const char kPLTFunctionSuffix[] = "@plt"; +// Replace callsites of this function to std::string_view::starts_with after +// adopting C++20. +bool StringViewStartsWith(std::string_view sv, std::string_view prefix) { + return sv.compare(0, prefix.size(), prefix) == 0; +} + } // namespace -namespace dwarf2reader { +namespace google_breakpad { template <class ElfArch> class ElfReaderImpl; @@ -130,11 +137,11 @@ class Elf32 { static const int kElfClass = ELFCLASS32; // Given a symbol pointer, return the binding type (eg STB_WEAK). - static char Bind(const Elf32_Sym *sym) { + 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) { + static char Type(const Elf32_Sym* sym) { return ELF32_ST_TYPE(sym->st_info); } @@ -158,10 +165,10 @@ class Elf64 { // What should be in the EI_CLASS header. static const int kElfClass = ELFCLASS64; - static char Bind(const Elf64_Sym *sym) { + static char Bind(const Elf64_Sym* sym) { return ELF64_ST_BIND(sym->st_info); } - static char Type(const Elf64_Sym *sym) { + static char Type(const Elf64_Sym* sym) { return ELF64_ST_TYPE(sym->st_info); } static int r_sym(const Elf64_Xword r_info) { @@ -182,8 +189,8 @@ class Elf64 { template<class ElfArch> class ElfSectionReader { public: - ElfSectionReader(const char *name, const string &path, int fd, - const typename ElfArch::Shdr §ion_header) + ElfSectionReader(const char* cname, const string& path, int fd, + const typename ElfArch::Shdr& section_header) : contents_aligned_(NULL), contents_(NULL), header_(section_header) { @@ -196,14 +203,25 @@ class ElfSectionReader { // to process its contents. if (header_.sh_type == SHT_NOBITS || header_.sh_size == 0) return; + // extra sh_type check for string table. + std::string_view name{cname}; + if ((name == ".strtab" || name == ".shstrtab") && + header_.sh_type != SHT_STRTAB) { + fprintf(stderr, + "Invalid sh_type for string table section: expected " + "SHT_STRTAB or SHT_DYNSYM, but got %d\n", + header_.sh_type); + 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_) + + 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) + //if (StringViewStartsWith(name, ".zdebug_")) // DecompressZlibContents(); // TODO(saugustine): Add support for proposed elf-section flag // "SHF_COMPRESS". @@ -217,24 +235,24 @@ class ElfSectionReader { } // Return the section header for this section. - typename ElfArch::Shdr const &header() const { return header_; } + 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 { + const char* GetOffset(typename ElfArch::Word bytes) const { return contents_ + bytes; } - const char *contents() const { return contents_; } + const char* contents() const { return contents_; } size_t section_size() const { return section_size_; } private: // page-aligned file contents - void *contents_aligned_; + 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_; + char* contents_; // size of contents_aligned_ size_t size_aligned_; // size of contents. @@ -249,7 +267,7 @@ class ElfSectionReader { template<class ElfArch> class SymbolIterator { public: - SymbolIterator(ElfReaderImpl<ElfArch> *reader, + SymbolIterator(ElfReaderImpl<ElfArch>* reader, typename ElfArch::Word section_type) : symbol_section_(reader->GetSectionByType(section_type)), string_section_(NULL), @@ -280,7 +298,7 @@ class SymbolIterator { // Return a pointer to the current symbol. // REQUIRES: !done() - const typename ElfArch::Sym *GetSymbol() const { + const typename ElfArch::Sym* GetSymbol() const { return reinterpret_cast<const typename ElfArch::Sym*>( symbol_section_->GetOffset(symbol_within_section_ * symbol_section_->header().sh_entsize)); @@ -288,7 +306,7 @@ class SymbolIterator { // Return the name of the current symbol, NULL if it has none. // REQUIRES: !done() - const char *GetSymbolName() const { + const char* GetSymbolName() const { int name_offset = GetSymbol()->st_name; if (name_offset == 0) return NULL; @@ -300,8 +318,8 @@ class SymbolIterator { } private: - const ElfSectionReader<ElfArch> *const symbol_section_; - const ElfSectionReader<ElfArch> *string_section_; + const ElfSectionReader<ElfArch>* const symbol_section_; + const ElfSectionReader<ElfArch>* string_section_; int num_symbols_in_section_; int symbol_within_section_; }; @@ -326,7 +344,7 @@ static inline bool MyHasSuffixString(const string& str, const string& suffix) { template<class ElfArch> class ElfReaderImpl { public: - explicit ElfReaderImpl(const string &path, int fd) + explicit ElfReaderImpl(const string& path, int fd) : path_(path), fd_(fd), section_headers_(NULL), @@ -347,8 +365,8 @@ class ElfReaderImpl { // "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) { + std::string_view name{GetSectionName(section_headers_[k].sh_name)}; + if (StringViewStartsWith(name, ".text")) { base_for_text_ = section_headers_[k].sh_addr - section_headers_[k].sh_offset; break; @@ -384,7 +402,7 @@ class ElfReaderImpl { // 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) { + 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"; @@ -415,7 +433,7 @@ class ElfReaderImpl { } // Return true if we can use this symbol in Address-to-Symbol map. - bool CanUseSymbol(const char *name, const typename ElfArch::Sym *sym) { + 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 @@ -444,7 +462,7 @@ class ElfReaderImpl { // Iterate over the symbols in a section, either SHT_DYNSYM or // SHT_SYMTAB. Add all symbols to the given SymbolMap. /* - void GetSymbolPositions(SymbolMap *symbols, + void GetSymbolPositions(SymbolMap* symbols, typename ElfArch::Word section_type, uint64_t mem_offset, uint64_t file_offset) { @@ -453,10 +471,10 @@ class ElfReaderImpl { AddrToSymMap addr_to_sym_map; for (SymbolIterator<ElfArch> it(this, section_type); !it.done(); it.Next()) { - const char *name = it.GetSymbolName(); + const char* name = it.GetSymbolName(); if (name == NULL) continue; - const typename ElfArch::Sym *sym = it.GetSymbol(); + const typename ElfArch::Sym* sym = it.GetSymbol(); if (CanUseSymbol(name, sym)) { const int sec = sym->st_shndx; @@ -519,9 +537,9 @@ class ElfReaderImpl { if (addr_to_sym_map.empty()) { return; } - const ElfSectionReader<ElfArch> *const symbol_section = + const ElfSectionReader<ElfArch>* const symbol_section = this->GetSectionByType(section_type); - const ElfSectionReader<ElfArch> *const string_section = + const ElfSectionReader<ElfArch>* const string_section = this->GetSection(symbol_section->header().sh_link); typename AddrToSymMap::iterator curr = addr_to_sym_map.begin(); @@ -532,8 +550,8 @@ class ElfReaderImpl { for (; curr != addr_to_sym_map.end(); ++curr) { const uint64_t prev_addr = prev->first; const uint64_t curr_addr = curr->first; - const typename ElfArch::Sym *const prev_sym = prev->second; - const typename ElfArch::Sym *const curr_sym = curr->second; + 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: // @@ -552,7 +570,7 @@ class ElfReaderImpl { // (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); + const char* name = string_section->GetOffset(curr_sym->st_name); symbols->AddSymbol(name, curr_addr, curr_sym->st_size); prev = curr; } else { @@ -572,20 +590,20 @@ class ElfReaderImpl { */ void VisitSymbols(typename ElfArch::Word section_type, - ElfReader::SymbolSink *sink) { + ElfReader::SymbolSink* sink) { VisitSymbols(section_type, sink, -1, -1, false); } void VisitSymbols(typename ElfArch::Word section_type, - ElfReader::SymbolSink *sink, + 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(); + const char* name = it.GetSymbolName(); if (!name) continue; - const typename ElfArch::Sym *sym = it.GetSymbol(); + 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; @@ -691,7 +709,7 @@ class ElfReaderImpl { // 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( + 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) { @@ -703,14 +721,14 @@ class ElfReaderImpl { // Return the name of section "shndx". Returns NULL if the section // is not found. - const char *GetSectionNameByIndex(int shndx) { + 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); + const char* GetSectionContentsByIndex(int shndx, size_t* size) { + const ElfSectionReader<ElfArch>* section = GetSection(shndx); if (section != NULL) { *size = section->section_size(); return section->contents(); @@ -721,16 +739,16 @@ class ElfReaderImpl { // Return a pointer to the first section of the given name by // iterating through all section headers, and store the size in // "size". Returns NULL if the section name is not found. - const char *GetSectionContentsByName(const string §ion_name, - size_t *size) { + 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); + const char* name = GetSectionName(section_headers_[shndx].sh_name); if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) { - const ElfSectionReader<ElfArch> *section = GetSection(shndx); + const ElfSectionReader<ElfArch>* section = GetSection(shndx); if (section == NULL) { return NULL; } else { @@ -744,16 +762,16 @@ class ElfReaderImpl { // This is like GetSectionContentsByName() but it returns a lot of extra // information about the section. - const char *GetSectionInfoByName(const string §ion_name, - ElfReader::SectionInfo *info) { + 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); + const char* name = GetSectionName(section_headers_[shndx].sh_name); if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) { - const ElfSectionReader<ElfArch> *section = GetSection(shndx); + const ElfSectionReader<ElfArch>* section = GetSection(shndx); if (section == NULL) { return NULL; } else { @@ -797,9 +815,11 @@ class ElfReaderImpl { // 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; + std::string_view name{GetSectionName(section_headers_[k].sh_name)}; + if (StringViewStartsWith(name, ".debug") || + StringViewStartsWith(name, ".zdebug")) { + return true; + } } return false; } @@ -816,7 +836,7 @@ class ElfReaderImpl { } private: - typedef vector<pair<uint64_t, const typename ElfArch::Sym *> > AddrToSymMap; + typedef vector<pair<uint64_t, const typename ElfArch::Sym*> > AddrToSymMap; static bool AddrToSymSorter(const typename AddrToSymMap::value_type& lhs, const typename AddrToSymMap::value_type& rhs) { @@ -854,8 +874,8 @@ class ElfReaderImpl { // 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 = + const char* GetSectionName(typename ElfArch::Word sh_name) { + const ElfSectionReader<ElfArch>* shstrtab = GetSection(GetStringTableIndex()); if (shstrtab != NULL) { return shstrtab->GetOffset(sh_name); @@ -865,25 +885,25 @@ class ElfReaderImpl { // 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; + 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]; + ElfSectionReader<ElfArch>*& reader = sections_[num]; if (reader == NULL) reader = new ElfSectionReader<ElfArch>(name, path_, fd_, section_headers_[num]); - return reader; + return reader->contents() ? reader : nullptr; } // 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) { + bool ParseHeaders(int fd, const string& path) { // Read in the global ELF header. if (pread(fd, &header_, sizeof(header_), 0) != sizeof(header_)) { return false; @@ -985,11 +1005,11 @@ class ElfReaderImpl { // Array of GetNumSections() section headers, allocated when we read // in the global header. - typename ElfArch::Shdr *section_headers_; + typename ElfArch::Shdr* section_headers_; // Array of GetNumProgramHeaders() program headers, allocated when we read // in the global header. - typename ElfArch::Phdr *program_headers_; + 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 @@ -1000,7 +1020,7 @@ class ElfReaderImpl { // 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. + const char* opd_section_; // Must be checked for NULL before use. int64_t base_for_text_; // Read PLT-related sections for the current architecture. @@ -1026,7 +1046,7 @@ class ElfReaderImpl { bool is_dwp_; }; -ElfReader::ElfReader(const string &path) +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) @@ -1063,7 +1083,7 @@ ElfReader::~ElfReader() { #endif template <typename ElfArch> -static bool IsElfFile(const int fd, const string &path) { +static bool IsElfFile(const int fd, const string& path) { if (fd < 0) return false; if (!ElfReaderImpl<ElfArch>::IsArchElfFile(fd, NULL)) { @@ -1086,7 +1106,7 @@ bool ElfReader::IsElf64File() const { } /* -void ElfReader::AddSymbols(SymbolMap *symbols, +void ElfReader::AddSymbols(SymbolMap* symbols, uint64_t mem_offset, uint64_t file_offset, uint64_t length) { if (fd_ < 0) @@ -1109,17 +1129,17 @@ void ElfReader::AddSymbols(SymbolMap *symbols, } */ -void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink) { +void ElfReader::VisitSymbols(ElfReader::SymbolSink* sink) { VisitSymbols(sink, -1, -1); } -void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink, +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, +void ElfReader::VisitSymbols(ElfReader::SymbolSink* sink, int symbol_binding, int symbol_type, bool get_raw_symbol_values) { @@ -1148,7 +1168,7 @@ uint64_t ElfReader::VaddrOfFirstLoadSegment() { } } -const char *ElfReader::GetSectionName(int shndx) { +const char* ElfReader::GetSectionName(int shndx) { if (shndx < 0 || static_cast<unsigned int>(shndx) >= GetNumSections()) return NULL; if (IsElf32File()) { return GetImpl32()->GetSectionNameByIndex(shndx); @@ -1169,7 +1189,7 @@ uint64_t ElfReader::GetNumSections() { } } -const char *ElfReader::GetSectionByIndex(int shndx, size_t *size) { +const char* ElfReader::GetSectionByIndex(int shndx, size_t* size) { if (IsElf32File()) { return GetImpl32()->GetSectionContentsByIndex(shndx, size); } else if (IsElf64File()) { @@ -1179,8 +1199,8 @@ const char *ElfReader::GetSectionByIndex(int shndx, size_t *size) { } } -const char *ElfReader::GetSectionByName(const string §ion_name, - size_t *size) { +const char* ElfReader::GetSectionByName(const string& section_name, + size_t* size) { if (IsElf32File()) { return GetImpl32()->GetSectionContentsByName(section_name, size); } else if (IsElf64File()) { @@ -1190,8 +1210,8 @@ const char *ElfReader::GetSectionByName(const string §ion_name, } } -const char *ElfReader::GetSectionInfoByName(const string §ion_name, - SectionInfo *info) { +const char* ElfReader::GetSectionInfoByName(const string& section_name, + SectionInfo* info) { if (IsElf32File()) { return GetImpl32()->GetSectionInfoByName(section_name, info); } else if (IsElf64File()) { @@ -1201,11 +1221,15 @@ const char *ElfReader::GetSectionInfoByName(const string §ion_name, } } -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; +bool ElfReader::SectionNamesMatch(std::string_view name, + std::string_view sh_name) { + std::string_view debug_prefix{".debug_"}; + std::string_view zdebug_prefix{".zdebug_"}; + if (StringViewStartsWith(name, debug_prefix) && + StringViewStartsWith(sh_name, zdebug_prefix)) { + name.remove_prefix(debug_prefix.length()); + sh_name.remove_prefix(zdebug_prefix.length()); + return name == sh_name; } return name == sh_name; } @@ -1220,14 +1244,14 @@ bool ElfReader::IsDynamicSharedObject() { } } -ElfReaderImpl<Elf32> *ElfReader::GetImpl32() { +ElfReaderImpl<Elf32>* ElfReader::GetImpl32() { if (impl32_ == NULL) { impl32_ = new ElfReaderImpl<Elf32>(path_, fd_); } return impl32_; } -ElfReaderImpl<Elf64> *ElfReader::GetImpl64() { +ElfReaderImpl<Elf64>* ElfReader::GetImpl64() { if (impl64_ == NULL) { impl64_ = new ElfReaderImpl<Elf64>(path_, fd_); } @@ -1238,7 +1262,7 @@ ElfReaderImpl<Elf64> *ElfReader::GetImpl64() { // 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, +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); @@ -1248,7 +1272,7 @@ static bool IsNonStrippedELFBinaryImpl(const string &path, const int fd, } // Helper for the IsNon[Debug]StrippedELFBinary functions. -static bool IsNonStrippedELFBinaryHelper(const string &path, +static bool IsNonStrippedELFBinaryHelper(const string& path, bool debug_only) { const int fd = open(path.c_str(), O_RDONLY); if (fd == -1) { @@ -1264,11 +1288,11 @@ static bool IsNonStrippedELFBinaryHelper(const string &path, return false; } -bool ElfReader::IsNonStrippedELFBinary(const string &path) { +bool ElfReader::IsNonStrippedELFBinary(const string& path) { return IsNonStrippedELFBinaryHelper(path, false); } -bool ElfReader::IsNonDebugStrippedELFBinary(const string &path) { +bool ElfReader::IsNonDebugStrippedELFBinary(const string& path) { return IsNonStrippedELFBinaryHelper(path, true); } -} // namespace dwarf2reader +} // namespace google_breakpad diff --git a/src/common/dwarf/elf_reader.h b/src/common/dwarf/elf_reader.h index 8eaa5aa9..a6dec755 100644 --- a/src/common/dwarf/elf_reader.h +++ b/src/common/dwarf/elf_reader.h @@ -1,4 +1,4 @@ -// Copyright 2005 Google Inc. All Rights Reserved. +// Copyright 2005 Google LLC // Author: chatham@google.com (Andrew Chatham) // Author: satorux@google.com (Satoru Takabayashi) // @@ -16,6 +16,7 @@ #define COMMON_DWARF_ELF_READER_H__ #include <string> +#include <string_view> #include <vector> #include "common/dwarf/types.h" @@ -24,7 +25,7 @@ using std::vector; using std::pair; -namespace dwarf2reader { +namespace google_breakpad { class SymbolMap; class Elf32; @@ -34,7 +35,7 @@ class ElfReaderImpl; class ElfReader { public: - explicit ElfReader(const string &path); + explicit ElfReader(const string& path); ~ElfReader(); // Parse the ELF prologue of this file and return whether it was @@ -62,29 +63,29 @@ class ElfReader { // 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, + void AddSymbols(SymbolMap* symbols, uint64_t mem_offset, uint64_t file_offset, uint64_t length); class SymbolSink { public: virtual ~SymbolSink() {} - virtual void AddSymbol(const char *name, uint64_t address, + virtual void AddSymbol(const char* name, uint64_t address, uint64_t size) = 0; }; // Like AddSymbols above, but with no address correction. // Processes any SHT_SYMTAB section, followed by any SHT_DYNSYM section. - void VisitSymbols(SymbolSink *sink); + 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); + 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, + 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 @@ -95,7 +96,7 @@ class ElfReader { // Return the name of section "shndx". Returns NULL if the section // is not found. - const char *GetSectionName(int shndx); + const char* GetSectionName(int shndx); // Return the number of sections in the given ELF file. uint64_t GetNumSections(); @@ -104,14 +105,14 @@ class ElfReader { // 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); + const char* GetSectionByIndex(int shndx, size_t* size); // Get section with "section_name" (ex. ".text", ".symtab") in the // given ELF file. On success, return the pointer to the section // and store the size in "size". On error, return NULL. The // returned section data is only valid until the ElfReader gets // destroyed. - const char *GetSectionByName(const string §ion_name, size_t *size); + 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 @@ -129,39 +130,40 @@ class ElfReader { uint64_t addralign; // Section alignment. uint64_t entsize; // Entry size if section holds a table. }; - const char *GetSectionInfoByName(const string §ion_name, - SectionInfo *info); + 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); + 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); + 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); + static bool SectionNamesMatch(std::string_view name, + std::string_view sh_name); private: // Lazily initialize impl32_ and return it. - ElfReaderImpl<Elf32> *GetImpl32(); + ElfReaderImpl<Elf32>* GetImpl32(); // Ditto for impl64_. - ElfReaderImpl<Elf64> *GetImpl64(); + 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_; + ElfReaderImpl<Elf32>* impl32_; + ElfReaderImpl<Elf64>* impl64_; }; -} // namespace dwarf2reader +} // namespace google_breakpad #endif // COMMON_DWARF_ELF_READER_H__ diff --git a/src/common/dwarf/functioninfo.cc b/src/common/dwarf/functioninfo.cc index 358a6eef..d8fdb842 100644 --- a/src/common/dwarf/functioninfo.cc +++ b/src/common/dwarf/functioninfo.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -42,24 +42,16 @@ #include "common/scoped_ptr.h" #include "common/using_std_string.h" -using google_breakpad::scoped_ptr; - -namespace dwarf2reader { +namespace google_breakpad { 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); + // In dwarf4, the dirs and files are 1 indexed, and in dwarf5 they are zero + // indexed. This is handled in the LineInfo reader, so empty files are not + // needed here. } void CULineInfoHandler::DefineDir(const string& name, uint32_t dir_num) { @@ -150,7 +142,7 @@ bool CUFunctionInfoHandler::StartDIE(uint64_t offset, enum DwarfTag tag) { void CUFunctionInfoHandler::ProcessAttributeString(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, - const string &data) { + const string& data) { if (current_function_info_) { if (attr == DW_AT_name) current_function_info_->name = data; @@ -164,7 +156,8 @@ void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64_t offset, enum DwarfForm form, uint64_t data) { if (attr == DW_AT_stmt_list) { - SectionMap::const_iterator iter = sections_.find("__debug_line"); + SectionMap::const_iterator iter = + GetSectionByName(sections_, ".debug_line"); assert(iter != sections_.end()); scoped_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data, @@ -232,4 +225,4 @@ void CUFunctionInfoHandler::EndDIE(uint64_t offset) { current_function_info_)); } -} // namespace dwarf2reader +} // namespace google_breakpad diff --git a/src/common/dwarf/functioninfo.h b/src/common/dwarf/functioninfo.h index 5c733c6d..1387c5ba 100644 --- a/src/common/dwarf/functioninfo.h +++ b/src/common/dwarf/functioninfo.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -43,7 +43,7 @@ #include "common/using_std_string.h" -namespace dwarf2reader { +namespace google_breakpad { struct FunctionInfo { // Name of the function @@ -187,5 +187,5 @@ class CUFunctionInfoHandler: public Dwarf2Handler { uint64_t current_compilation_unit_offset_; }; -} // namespace dwarf2reader +} // namespace google_breakpad #endif // COMMON_DWARF_FUNCTIONINFO_H__ diff --git a/src/common/dwarf/line_state_machine.h b/src/common/dwarf/line_state_machine.h index fc301c76..1797e3bc 100644 --- a/src/common/dwarf/line_state_machine.h +++ b/src/common/dwarf/line_state_machine.h @@ -1,4 +1,4 @@ -// Copyright 2008 Google Inc. All Rights Reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -30,7 +30,9 @@ #ifndef COMMON_DWARF_LINE_STATE_MACHINE_H__ #define COMMON_DWARF_LINE_STATE_MACHINE_H__ -namespace dwarf2reader { +#include <stdint.h> + +namespace google_breakpad { // This is the format of a DWARF2/3 line state machine that we process // opcodes using. There is no need for anything outside the lineinfo @@ -55,7 +57,7 @@ struct LineStateMachine { bool end_sequence; }; -} // namespace dwarf2reader +} // namespace google_breakpad #endif // COMMON_DWARF_LINE_STATE_MACHINE_H__ diff --git a/src/common/dwarf/types.h b/src/common/dwarf/types.h index 23412d0e..b14d7a3e 100644 --- a/src/common/dwarf/types.h +++ b/src/common/dwarf/types.h @@ -1,4 +1,4 @@ -// Copyright 2008 Google, Inc. All Rights reserved +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // |