From 72c118f4a6dfb954a80d2f2b9a1794e13b0a8ebd Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Tue, 23 Jun 2020 12:42:27 -0700 Subject: Add and handle various dwarf5 addrx forms. Given the almost nonexistent direct dwarfreader tests, I think the best way to test these dwarf5 additions will be to add a full dwarf5 compilation unit similar to the ones used incidentally in the other tests. But I can't do that until enough dwarf5 is correctly implemented. Change-Id: I3418bda7212ae85c4b67232a2ab8fea9b9ca5d42 Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/2258838 Reviewed-by: Mark Mentovai Reviewed-by: Mike Frysinger --- src/common/dwarf/bytereader-inl.h | 11 +++++++++++ src/common/dwarf/bytereader.h | 5 +++++ src/common/dwarf/dwarf2enums.h | 6 ++++++ src/common/dwarf/dwarf2reader.cc | 35 ++++++++++++++++++++++++++--------- src/common/dwarf/dwarf2reader.h | 12 ++++++++++++ src/common/dwarf_cu_to_module.cc | 7 ++++++- 6 files changed, 66 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/common/dwarf/bytereader-inl.h b/src/common/dwarf/bytereader-inl.h index f4c068a2..235d75ee 100644 --- a/src/common/dwarf/bytereader-inl.h +++ b/src/common/dwarf/bytereader-inl.h @@ -50,6 +50,17 @@ inline uint16_t ByteReader::ReadTwoBytes(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]; diff --git a/src/common/dwarf/bytereader.h b/src/common/dwarf/bytereader.h index 2b37a12d..d0c3b964 100644 --- a/src/common/dwarf/bytereader.h +++ b/src/common/dwarf/bytereader.h @@ -68,6 +68,11 @@ class ByteReader { // number, using this ByteReader's endianness. uint16_t ReadTwoBytes(const uint8_t *buffer) const; + // Read three bytes from BUFFER and return them as an unsigned 64 bit + // number, using this ByteReader's endianness. DWARF 5 uses this encoding + // for various index-related DW_FORMs. + uint64_t ReadThreeBytes(const uint8_t* buffer) const; + // Read four bytes from BUFFER and return them as an unsigned 32 bit // number, using this ByteReader's endianness. This function returns // a uint64_t so that it is compatible with ReadAddress and diff --git a/src/common/dwarf/dwarf2enums.h b/src/common/dwarf/dwarf2enums.h index f5ccce94..bed70327 100644 --- a/src/common/dwarf/dwarf2enums.h +++ b/src/common/dwarf/dwarf2enums.h @@ -164,6 +164,12 @@ enum DwarfForm { DW_FORM_strx3 = 0x27, DW_FORM_strx4 = 0x28, + DW_FORM_addrx = 0x1b, + 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 diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc index 4f0c31dd..fbfff275 100644 --- a/src/common/dwarf/dwarf2reader.cc +++ b/src/common/dwarf/dwarf2reader.cc @@ -182,17 +182,21 @@ const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start, case DW_FORM_flag_present: 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: @@ -208,6 +212,7 @@ const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start, case DW_FORM_strx: case DW_FORM_GNU_str_index: case DW_FORM_GNU_addr_index: + case DW_FORM_addrx: reader_->ReadUnsignedLEB128(start, &len); return start + len; @@ -549,8 +554,7 @@ const uint8_t *CompilationUnit::ProcessAttribute( return start + 2; } case DW_FORM_strx3: { - uint64_t str_index = reader_->ReadTwoBytes(start); - str_index *= reader_->ReadOneByte(start + 2); + uint64_t str_index = reader_->ReadThreeBytes(start); ProcessFormStringIndex(dieoffset, attr, form, str_index); return start + 3; } @@ -560,14 +564,27 @@ const uint8_t *CompilationUnit::ProcessAttribute( return start + 4; } - 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(); - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadAddress(addr_ptr)); + 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; } fprintf(stderr, "Unhandled form type\n"); return NULL; diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h index 51d92285..593f5c0c 100644 --- a/src/common/dwarf/dwarf2reader.h +++ b/src/common/dwarf/dwarf2reader.h @@ -499,6 +499,18 @@ class CompilationUnit { 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(); diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc index d6e79769..24bbf83b 100644 --- a/src/common/dwarf_cu_to_module.cc +++ b/src/common/dwarf_cu_to_module.cc @@ -593,7 +593,12 @@ void DwarfCUToModule::FuncHandler::Finish() { if (!ranges_) { // Make high_pc_ an address, if it isn't already. if (high_pc_form_ != dwarf2reader::DW_FORM_addr && - high_pc_form_ != dwarf2reader::DW_FORM_GNU_addr_index) { + high_pc_form_ != dwarf2reader::DW_FORM_GNU_addr_index && + high_pc_form_ != dwarf2reader::DW_FORM_addrx && + high_pc_form_ != dwarf2reader::DW_FORM_addrx1 && + high_pc_form_ != dwarf2reader::DW_FORM_addrx2 && + high_pc_form_ != dwarf2reader::DW_FORM_addrx3 && + high_pc_form_ != dwarf2reader::DW_FORM_addrx4) { high_pc_ += low_pc_; } -- cgit v1.2.1