diff options
Diffstat (limited to 'llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp')
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp | 408 |
1 files changed, 233 insertions, 175 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp index 5d9c118473a..dcb491fdd80 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -23,60 +23,6 @@ using namespace llvm; using namespace dwarf; using namespace syntax; -namespace { -uint8_t getRefAddrSize(uint8_t AddrSize, uint16_t Version) { - // FIXME: Support DWARF64. - return (Version == 2) ? AddrSize : 4; -} - -template <uint8_t AddrSize, uint8_t RefAddrSize> -ArrayRef<uint8_t> makeFixedFormSizesArrayRef() { - static const uint8_t sizes[] = { - 0, // 0x00 unused - AddrSize, // 0x01 DW_FORM_addr - 0, // 0x02 unused - 0, // 0x03 DW_FORM_block2 - 0, // 0x04 DW_FORM_block4 - 2, // 0x05 DW_FORM_data2 - 4, // 0x06 DW_FORM_data4 - 8, // 0x07 DW_FORM_data8 - 0, // 0x08 DW_FORM_string - 0, // 0x09 DW_FORM_block - 0, // 0x0a DW_FORM_block1 - 1, // 0x0b DW_FORM_data1 - 1, // 0x0c DW_FORM_flag - 0, // 0x0d DW_FORM_sdata - 4, // 0x0e DW_FORM_strp - 0, // 0x0f DW_FORM_udata - RefAddrSize, // 0x10 DW_FORM_ref_addr - 1, // 0x11 DW_FORM_ref1 - 2, // 0x12 DW_FORM_ref2 - 4, // 0x13 DW_FORM_ref4 - 8, // 0x14 DW_FORM_ref8 - 0, // 0x15 DW_FORM_ref_udata - 0, // 0x16 DW_FORM_indirect - 4, // 0x17 DW_FORM_sec_offset - 0, // 0x18 DW_FORM_exprloc - 0, // 0x19 DW_FORM_flag_present - }; - return makeArrayRef(sizes); -} -} - -ArrayRef<uint8_t> DWARFFormValue::getFixedFormSizes(uint8_t AddrSize, - uint16_t Version) { - uint8_t RefAddrSize = getRefAddrSize(AddrSize, Version); - if (AddrSize == 4 && RefAddrSize == 4) - return makeFixedFormSizesArrayRef<4, 4>(); - if (AddrSize == 4 && RefAddrSize == 8) - return makeFixedFormSizesArrayRef<4, 8>(); - if (AddrSize == 8 && RefAddrSize == 4) - return makeFixedFormSizesArrayRef<8, 4>(); - if (AddrSize == 8 && RefAddrSize == 8) - return makeFixedFormSizesArrayRef<8, 8>(); - return None; -} - static const DWARFFormValue::FormClass DWARF4FormClasses[] = { DWARFFormValue::FC_Unknown, // 0x0 DWARFFormValue::FC_Address, // 0x01 DW_FORM_addr @@ -108,6 +54,214 @@ static const DWARFFormValue::FormClass DWARF4FormClasses[] = { DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present }; +namespace { + +/// A helper class that can be used in DWARFFormValue.cpp functions that need +/// to know the byte size of DW_FORM values that vary in size depending on the +/// DWARF version, address byte size, or DWARF32 or DWARF64. +class FormSizeHelper { + uint16_t Version; + uint8_t AddrSize; + llvm::dwarf::DwarfFormat Format; + +public: + FormSizeHelper(uint16_t V, uint8_t A, llvm::dwarf::DwarfFormat F) + : Version(V), AddrSize(A), Format(F) {} + uint8_t getAddressByteSize() const { return AddrSize; } + uint8_t getRefAddrByteSize() const { + if (Version == 2) + return AddrSize; + return getDwarfOffsetByteSize(); + } + uint8_t getDwarfOffsetByteSize() const { + switch (Format) { + case dwarf::DwarfFormat::DWARF32: + return 4; + case dwarf::DwarfFormat::DWARF64: + return 8; + } + llvm_unreachable("Invalid Format value"); + } +}; + +} // end anonymous namespace + +template <class T> +static Optional<uint8_t> getFixedByteSize(dwarf::Form Form, const T *U) { + switch (Form) { + case DW_FORM_addr: + if (U) + return U->getAddressByteSize(); + return None; + + case DW_FORM_block: // ULEB128 length L followed by L bytes. + case DW_FORM_block1: // 1 byte length L followed by L bytes. + case DW_FORM_block2: // 2 byte length L followed by L bytes. + case DW_FORM_block4: // 4 byte length L followed by L bytes. + case DW_FORM_string: // C-string with null terminator. + case DW_FORM_sdata: // SLEB128. + case DW_FORM_udata: // ULEB128. + case DW_FORM_ref_udata: // ULEB128. + case DW_FORM_indirect: // ULEB128. + case DW_FORM_exprloc: // ULEB128 length L followed by L bytes. + case DW_FORM_strx: // ULEB128. + case DW_FORM_addrx: // ULEB128. + case DW_FORM_loclistx: // ULEB128. + case DW_FORM_rnglistx: // ULEB128. + case DW_FORM_GNU_addr_index: // ULEB128. + case DW_FORM_GNU_str_index: // ULEB128. + return None; + + case DW_FORM_ref_addr: + if (U) + return U->getRefAddrByteSize(); + return None; + + case DW_FORM_flag: + case DW_FORM_data1: + case DW_FORM_ref1: + return 1; + + case DW_FORM_data2: + case DW_FORM_ref2: + return 2; + + case DW_FORM_data4: + case DW_FORM_ref4: + case DW_FORM_strp: + return 4; + + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + case DW_FORM_line_strp: + case DW_FORM_sec_offset: + case DW_FORM_strp_sup: + case DW_FORM_ref_sup: + if (U) + return U->getDwarfOffsetByteSize(); + return None; + + case DW_FORM_data8: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + return 8; + + case DW_FORM_flag_present: + return 0; + + case DW_FORM_data16: + return 16; + + case DW_FORM_implicit_const: + // The implicit value is stored in the abbreviation as a ULEB128, any + // there no data in debug info. + return 0; + + default: + llvm_unreachable("Handle this form in this switch statement"); + } + return None; +} + +template <class T> +static bool skipFormValue(dwarf::Form Form, const DataExtractor &DebugInfoData, + uint32_t *OffsetPtr, const T *U) { + bool Indirect = false; + do { + switch (Form) { + // Blocks if inlined data that have a length field and the data bytes + // inlined in the .debug_info. + case DW_FORM_exprloc: + case DW_FORM_block: { + uint64_t size = DebugInfoData.getULEB128(OffsetPtr); + *OffsetPtr += size; + return true; + } + case DW_FORM_block1: { + uint8_t size = DebugInfoData.getU8(OffsetPtr); + *OffsetPtr += size; + return true; + } + case DW_FORM_block2: { + uint16_t size = DebugInfoData.getU16(OffsetPtr); + *OffsetPtr += size; + return true; + } + case DW_FORM_block4: { + uint32_t size = DebugInfoData.getU32(OffsetPtr); + *OffsetPtr += size; + return true; + } + + // Inlined NULL terminated C-strings. + case DW_FORM_string: + DebugInfoData.getCStr(OffsetPtr); + return true; + + case DW_FORM_addr: + case DW_FORM_ref_addr: + case DW_FORM_flag_present: + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_flag: + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + case DW_FORM_sec_offset: + case DW_FORM_strp: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + if (Optional<uint8_t> FixedSize = ::getFixedByteSize(Form, U)) { + *OffsetPtr += *FixedSize; + return true; + } + return false; + + // signed or unsigned LEB 128 values. + case DW_FORM_sdata: + DebugInfoData.getSLEB128(OffsetPtr); + return true; + + case DW_FORM_udata: + case DW_FORM_ref_udata: + case DW_FORM_strx: + case DW_FORM_addrx: + case DW_FORM_loclistx: + case DW_FORM_rnglistx: + case DW_FORM_GNU_addr_index: + case DW_FORM_GNU_str_index: + DebugInfoData.getULEB128(OffsetPtr); + return true; + + case DW_FORM_indirect: + Indirect = true; + Form = static_cast<dwarf::Form>(DebugInfoData.getULEB128(OffsetPtr)); + break; + + default: + return false; + } + } while (Indirect); + return true; +} + +Optional<uint8_t> DWARFFormValue::getFixedByteSize(dwarf::Form Form, + const DWARFUnit *U) { + return ::getFixedByteSize(Form, U); +} + +Optional<uint8_t> +DWARFFormValue::getFixedByteSize(dwarf::Form Form, uint16_t Version, + uint8_t AddrSize, + llvm::dwarf::DwarfFormat Format) { + FormSizeHelper FSH(Version, AddrSize, Format); + return ::getFixedByteSize(Form, &FSH); +} + bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { // First, check DWARF4 form classes. if (Form < makeArrayRef(DWARF4FormClasses).size() && @@ -155,8 +309,7 @@ bool DWARFFormValue::extractValue(const DataExtractor &data, : U->getRefAddrByteSize(); RelocAddrMap::const_iterator AI = U->getRelocMap()->find(*offset_ptr); if (AI != U->getRelocMap()->end()) { - const std::pair<uint8_t, int64_t> &R = AI->second; - Value.uval = data.getUnsigned(offset_ptr, AddrSize) + R.second; + Value.uval = data.getUnsigned(offset_ptr, AddrSize) + AI->second.second; } else Value.uval = data.getUnsigned(offset_ptr, AddrSize); break; @@ -188,7 +341,8 @@ bool DWARFFormValue::extractValue(const DataExtractor &data, Value.uval = data.getU16(offset_ptr); break; case DW_FORM_data4: - case DW_FORM_ref4: { + case DW_FORM_ref4: + case DW_FORM_strp: { Value.uval = data.getU32(offset_ptr); if (!U) break; @@ -216,15 +370,16 @@ bool DWARFFormValue::extractValue(const DataExtractor &data, indirect = true; break; case DW_FORM_sec_offset: - case DW_FORM_strp: case DW_FORM_GNU_ref_alt: - case DW_FORM_GNU_strp_alt: { - // FIXME: This is 64-bit for DWARF64. - Value.uval = data.getU32(offset_ptr); + case DW_FORM_GNU_strp_alt: + case DW_FORM_line_strp: + case DW_FORM_strp_sup: + case DW_FORM_ref_sup: { if (!U) - break; - RelocAddrMap::const_iterator AI = - U->getRelocMap()->find(*offset_ptr - 4); + return false; + RelocAddrMap::const_iterator AI = U->getRelocMap()->find(*offset_ptr); + uint8_t Size = U->getDwarfOffsetByteSize(); + Value.uval = data.getUnsigned(offset_ptr, Size); if (AI != U->getRelocMap()->end()) Value.uval += AI->second.second; break; @@ -256,120 +411,22 @@ bool DWARFFormValue::extractValue(const DataExtractor &data, return true; } -bool -DWARFFormValue::skipValue(DataExtractor debug_info_data, uint32_t* offset_ptr, - const DWARFUnit *U) const { - return DWARFFormValue::skipValue(Form, debug_info_data, offset_ptr, U); +bool DWARFFormValue::skipValue(DataExtractor DebugInfoData, + uint32_t *offset_ptr, const DWARFUnit *U) const { + return DWARFFormValue::skipValue(Form, DebugInfoData, offset_ptr, U); } -bool -DWARFFormValue::skipValue(dwarf::Form form, DataExtractor debug_info_data, - uint32_t *offset_ptr, const DWARFUnit *cu) { - return skipValue(form, debug_info_data, offset_ptr, cu->getVersion(), - cu->getAddressByteSize()); +bool DWARFFormValue::skipValue(dwarf::Form form, DataExtractor DebugInfoData, + uint32_t *offset_ptr, const DWARFUnit *U) { + return skipFormValue(form, DebugInfoData, offset_ptr, U); } -bool -DWARFFormValue::skipValue(dwarf::Form form, DataExtractor debug_info_data, - uint32_t *offset_ptr, uint16_t Version, - uint8_t AddrSize) { - bool indirect = false; - do { - switch (form) { - // Blocks if inlined data that have a length field and the data bytes - // inlined in the .debug_info - case DW_FORM_exprloc: - case DW_FORM_block: { - uint64_t size = debug_info_data.getULEB128(offset_ptr); - *offset_ptr += size; - return true; - } - case DW_FORM_block1: { - uint8_t size = debug_info_data.getU8(offset_ptr); - *offset_ptr += size; - return true; - } - case DW_FORM_block2: { - uint16_t size = debug_info_data.getU16(offset_ptr); - *offset_ptr += size; - return true; - } - case DW_FORM_block4: { - uint32_t size = debug_info_data.getU32(offset_ptr); - *offset_ptr += size; - return true; - } - - // Inlined NULL terminated C-strings - case DW_FORM_string: - debug_info_data.getCStr(offset_ptr); - return true; - - // Compile unit address sized values - case DW_FORM_addr: - *offset_ptr += AddrSize; - return true; - case DW_FORM_ref_addr: - *offset_ptr += getRefAddrSize(AddrSize, Version); - return true; - - // 0 byte values - implied from the form. - case DW_FORM_flag_present: - return true; - - // 1 byte values - case DW_FORM_data1: - case DW_FORM_flag: - case DW_FORM_ref1: - *offset_ptr += 1; - return true; - - // 2 byte values - case DW_FORM_data2: - case DW_FORM_ref2: - *offset_ptr += 2; - return true; - - // 4 byte values - case DW_FORM_data4: - case DW_FORM_ref4: - *offset_ptr += 4; - return true; - - // 8 byte values - case DW_FORM_data8: - case DW_FORM_ref8: - case DW_FORM_ref_sig8: - *offset_ptr += 8; - return true; - - // signed or unsigned LEB 128 values - // case DW_FORM_APPLE_db_str: - case DW_FORM_sdata: - case DW_FORM_udata: - case DW_FORM_ref_udata: - case DW_FORM_GNU_str_index: - case DW_FORM_GNU_addr_index: - debug_info_data.getULEB128(offset_ptr); - return true; - case DW_FORM_indirect: - indirect = true; - form = static_cast<dwarf::Form>(debug_info_data.getULEB128(offset_ptr)); - break; - - // FIXME: 4 for DWARF32, 8 for DWARF64. - case DW_FORM_sec_offset: - case DW_FORM_strp: - case DW_FORM_GNU_ref_alt: - case DW_FORM_GNU_strp_alt: - *offset_ptr += 4; - return true; - - default: - return false; - } - } while (indirect); - return true; +bool DWARFFormValue::skipValue(dwarf::Form form, DataExtractor DebugInfoData, + uint32_t *offset_ptr, uint16_t Version, + uint8_t AddrSize, + llvm::dwarf::DwarfFormat Format) { + FormSizeHelper FSH(Version, AddrSize, Format); + return skipFormValue(form, DebugInfoData, offset_ptr, &FSH); } void @@ -556,8 +613,9 @@ Optional<uint64_t> DWARFFormValue::getAsReference() const { return None; return Value.uval + U->getOffset(); case DW_FORM_ref_addr: + case DW_FORM_ref_sig8: + case DW_FORM_GNU_ref_alt: return Value.uval; - // FIXME: Add proper support for DW_FORM_ref_sig8 and DW_FORM_GNU_ref_alt. default: return None; } |