diff options
Diffstat (limited to 'third_party/llvm-project/DWARFFormValue.cpp')
-rw-r--r-- | third_party/llvm-project/DWARFFormValue.cpp | 720 |
1 files changed, 720 insertions, 0 deletions
diff --git a/third_party/llvm-project/DWARFFormValue.cpp b/third_party/llvm-project/DWARFFormValue.cpp new file mode 100644 index 000000000..26090638b --- /dev/null +++ b/third_party/llvm-project/DWARFFormValue.cpp @@ -0,0 +1,720 @@ +//===- DWARFFormValue.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include <cinttypes> +#include <cstdint> +#include <limits> + +using namespace llvm; +using namespace dwarf; + +static const DWARFFormValue::FormClass DWARF5FormClasses[] = { + DWARFFormValue::FC_Unknown, // 0x0 + DWARFFormValue::FC_Address, // 0x01 DW_FORM_addr + DWARFFormValue::FC_Unknown, // 0x02 unused + DWARFFormValue::FC_Block, // 0x03 DW_FORM_block2 + DWARFFormValue::FC_Block, // 0x04 DW_FORM_block4 + DWARFFormValue::FC_Constant, // 0x05 DW_FORM_data2 + // --- These can be FC_SectionOffset in DWARF3 and below: + DWARFFormValue::FC_Constant, // 0x06 DW_FORM_data4 + DWARFFormValue::FC_Constant, // 0x07 DW_FORM_data8 + // --- + DWARFFormValue::FC_String, // 0x08 DW_FORM_string + DWARFFormValue::FC_Block, // 0x09 DW_FORM_block + DWARFFormValue::FC_Block, // 0x0a DW_FORM_block1 + DWARFFormValue::FC_Constant, // 0x0b DW_FORM_data1 + DWARFFormValue::FC_Flag, // 0x0c DW_FORM_flag + DWARFFormValue::FC_Constant, // 0x0d DW_FORM_sdata + DWARFFormValue::FC_String, // 0x0e DW_FORM_strp + DWARFFormValue::FC_Constant, // 0x0f DW_FORM_udata + DWARFFormValue::FC_Reference, // 0x10 DW_FORM_ref_addr + DWARFFormValue::FC_Reference, // 0x11 DW_FORM_ref1 + DWARFFormValue::FC_Reference, // 0x12 DW_FORM_ref2 + DWARFFormValue::FC_Reference, // 0x13 DW_FORM_ref4 + DWARFFormValue::FC_Reference, // 0x14 DW_FORM_ref8 + DWARFFormValue::FC_Reference, // 0x15 DW_FORM_ref_udata + DWARFFormValue::FC_Indirect, // 0x16 DW_FORM_indirect + DWARFFormValue::FC_SectionOffset, // 0x17 DW_FORM_sec_offset + DWARFFormValue::FC_Exprloc, // 0x18 DW_FORM_exprloc + DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present + DWARFFormValue::FC_String, // 0x1a DW_FORM_strx + DWARFFormValue::FC_Address, // 0x1b DW_FORM_addrx + DWARFFormValue::FC_Reference, // 0x1c DW_FORM_ref_sup4 + DWARFFormValue::FC_String, // 0x1d DW_FORM_strp_sup + DWARFFormValue::FC_Constant, // 0x1e DW_FORM_data16 + DWARFFormValue::FC_String, // 0x1f DW_FORM_line_strp + DWARFFormValue::FC_Reference, // 0x20 DW_FORM_ref_sig8 + DWARFFormValue::FC_Constant, // 0x21 DW_FORM_implicit_const + DWARFFormValue::FC_SectionOffset, // 0x22 DW_FORM_loclistx + DWARFFormValue::FC_SectionOffset, // 0x23 DW_FORM_rnglistx + DWARFFormValue::FC_Reference, // 0x24 DW_FORM_ref_sup8 + DWARFFormValue::FC_String, // 0x25 DW_FORM_strx1 + DWARFFormValue::FC_String, // 0x26 DW_FORM_strx2 + DWARFFormValue::FC_String, // 0x27 DW_FORM_strx3 + DWARFFormValue::FC_String, // 0x28 DW_FORM_strx4 + DWARFFormValue::FC_Address, // 0x29 DW_FORM_addrx1 + DWARFFormValue::FC_Address, // 0x2a DW_FORM_addrx2 + DWARFFormValue::FC_Address, // 0x2b DW_FORM_addrx3 + DWARFFormValue::FC_Address, // 0x2c DW_FORM_addrx4 + +}; + +DWARFFormValue DWARFFormValue::createFromSValue(dwarf::Form F, int64_t V) { + return DWARFFormValue(F, ValueType(V)); +} + +DWARFFormValue DWARFFormValue::createFromUValue(dwarf::Form F, uint64_t V) { + return DWARFFormValue(F, ValueType(V)); +} + +DWARFFormValue DWARFFormValue::createFromPValue(dwarf::Form F, const char *V) { + return DWARFFormValue(F, ValueType(V)); +} + +DWARFFormValue DWARFFormValue::createFromBlockValue(dwarf::Form F, + ArrayRef<uint8_t> D) { + ValueType V; + V.uval = D.size(); + V.data = D.data(); + return DWARFFormValue(F, V); +} + +DWARFFormValue DWARFFormValue::createFromUnit(dwarf::Form F, const DWARFUnit *U, + uint64_t *OffsetPtr) { + DWARFFormValue FormValue(F); + FormValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr, + U->getFormParams(), U); + return FormValue; +} + +bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData, + uint64_t *OffsetPtr, + const dwarf::FormParams Params) { + bool Indirect = false; + do { + switch (Form) { + // Blocks of 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_data16: + 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_ref_sup4: + case DW_FORM_ref_sup8: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx4: + case DW_FORM_addrx1: + case DW_FORM_addrx2: + case DW_FORM_addrx4: + case DW_FORM_sec_offset: + case DW_FORM_strp: + case DW_FORM_strp_sup: + case DW_FORM_line_strp: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + if (Optional<uint8_t> FixedSize = + dwarf::getFixedFormByteSize(Form, Params)) { + *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; +} + +bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { + // First, check DWARF5 form classes. + if (Form < makeArrayRef(DWARF5FormClasses).size() && + DWARF5FormClasses[Form] == FC) + return true; + // Check more forms from extensions and proposals. + switch (Form) { + case DW_FORM_GNU_ref_alt: + return (FC == FC_Reference); + case DW_FORM_GNU_addr_index: + return (FC == FC_Address); + case DW_FORM_GNU_str_index: + case DW_FORM_GNU_strp_alt: + return (FC == FC_String); + default: + break; + } + + if (FC == FC_SectionOffset) { + if (Form == DW_FORM_strp || Form == DW_FORM_line_strp) + return true; + // In DWARF3 DW_FORM_data4 and DW_FORM_data8 served also as a section + // offset. If we don't have a DWARFUnit, default to the old behavior. + if (Form == DW_FORM_data4 || Form == DW_FORM_data8) + return !U || U->getVersion() <= 3; + } + + return false; +} + +bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data, + uint64_t *OffsetPtr, dwarf::FormParams FP, + const DWARFContext *Ctx, + const DWARFUnit *CU) { + if (!Ctx && CU) + Ctx = &CU->getContext(); + C = Ctx; + U = CU; + bool Indirect = false; + bool IsBlock = false; + Value.data = nullptr; + // Read the value for the form into value and follow and DW_FORM_indirect + // instances we run into + do { + Indirect = false; + switch (Form) { + case DW_FORM_addr: + case DW_FORM_ref_addr: { + uint16_t Size = + (Form == DW_FORM_addr) ? FP.AddrSize : FP.getRefAddrByteSize(); + Value.uval = Data.getRelocatedValue(Size, OffsetPtr, &Value.SectionIndex); + break; + } + case DW_FORM_exprloc: + case DW_FORM_block: + Value.uval = Data.getULEB128(OffsetPtr); + IsBlock = true; + break; + case DW_FORM_block1: + Value.uval = Data.getU8(OffsetPtr); + IsBlock = true; + break; + case DW_FORM_block2: + Value.uval = Data.getU16(OffsetPtr); + IsBlock = true; + break; + case DW_FORM_block4: + Value.uval = Data.getU32(OffsetPtr); + IsBlock = true; + break; + case DW_FORM_data1: + case DW_FORM_ref1: + case DW_FORM_flag: + case DW_FORM_strx1: + case DW_FORM_addrx1: + Value.uval = Data.getU8(OffsetPtr); + break; + case DW_FORM_data2: + case DW_FORM_ref2: + case DW_FORM_strx2: + case DW_FORM_addrx2: + Value.uval = Data.getU16(OffsetPtr); + break; + case DW_FORM_strx3: + Value.uval = Data.getU24(OffsetPtr); + break; + case DW_FORM_data4: + case DW_FORM_ref4: + case DW_FORM_ref_sup4: + case DW_FORM_strx4: + case DW_FORM_addrx4: + Value.uval = Data.getRelocatedValue(4, OffsetPtr); + break; + case DW_FORM_data8: + case DW_FORM_ref8: + case DW_FORM_ref_sup8: + Value.uval = Data.getRelocatedValue(8, OffsetPtr); + break; + case DW_FORM_data16: + // Treat this like a 16-byte block. + Value.uval = 16; + IsBlock = true; + break; + case DW_FORM_sdata: + Value.sval = Data.getSLEB128(OffsetPtr); + break; + case DW_FORM_udata: + case DW_FORM_ref_udata: + case DW_FORM_rnglistx: + Value.uval = Data.getULEB128(OffsetPtr); + break; + case DW_FORM_string: + Value.cstr = Data.getCStr(OffsetPtr); + break; + case DW_FORM_indirect: + Form = static_cast<dwarf::Form>(Data.getULEB128(OffsetPtr)); + Indirect = true; + break; + case DW_FORM_strp: + case DW_FORM_sec_offset: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + case DW_FORM_line_strp: + case DW_FORM_strp_sup: { + Value.uval = + Data.getRelocatedValue(FP.getDwarfOffsetByteSize(), OffsetPtr); + break; + } + case DW_FORM_flag_present: + Value.uval = 1; + break; + case DW_FORM_ref_sig8: + Value.uval = Data.getU64(OffsetPtr); + break; + case DW_FORM_GNU_addr_index: + case DW_FORM_GNU_str_index: + case DW_FORM_addrx: + case DW_FORM_strx: + Value.uval = Data.getULEB128(OffsetPtr); + break; + default: + // DWARFFormValue::skipValue() will have caught this and caused all + // DWARF DIEs to fail to be parsed, so this code is not be reachable. + llvm_unreachable("unsupported form"); + } + } while (Indirect); + + if (IsBlock) { + StringRef Str = Data.getData().substr(*OffsetPtr, Value.uval); + Value.data = nullptr; + if (!Str.empty()) { + Value.data = Str.bytes_begin(); + *OffsetPtr += Value.uval; + } + } + + return true; +} + +void DWARFFormValue::dumpSectionedAddress(raw_ostream &OS, + DIDumpOptions DumpOpts, + object::SectionedAddress SA) const { + OS << format("0x%016" PRIx64, SA.Address); + dumpAddressSection(U->getContext().getDWARFObj(), OS, DumpOpts, + SA.SectionIndex); +} + +void DWARFFormValue::dumpAddressSection(const DWARFObject &Obj, raw_ostream &OS, + DIDumpOptions DumpOpts, + uint64_t SectionIndex) { + if (!DumpOpts.Verbose || SectionIndex == -1ULL) + return; + ArrayRef<SectionName> SectionNames = Obj.getSectionNames(); + const auto &SecRef = SectionNames[SectionIndex]; + + OS << " \"" << SecRef.Name << '\"'; + + // Print section index if name is not unique. + if (!SecRef.IsNameUnique) + OS << format(" [%" PRIu64 "]", SectionIndex); +} + +void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { + uint64_t UValue = Value.uval; + bool CURelativeOffset = false; + raw_ostream &AddrOS = DumpOpts.ShowAddresses + ? WithColor(OS, HighlightColor::Address).get() + : nulls(); + switch (Form) { + case DW_FORM_addr: + dumpSectionedAddress(AddrOS, DumpOpts, {Value.uval, Value.SectionIndex}); + break; + case DW_FORM_addrx: + case DW_FORM_addrx1: + case DW_FORM_addrx2: + case DW_FORM_addrx3: + case DW_FORM_addrx4: + case DW_FORM_GNU_addr_index: { + if (U == nullptr) { + OS << "<invalid dwarf unit>"; + break; + } + Optional<object::SectionedAddress> A = U->getAddrOffsetSectionItem(UValue); + if (!A || DumpOpts.Verbose) + AddrOS << format("indexed (%8.8x) address = ", (uint32_t)UValue); + if (A) + dumpSectionedAddress(AddrOS, DumpOpts, *A); + else + OS << "<no .debug_addr section>"; + break; + } + case DW_FORM_flag_present: + OS << "true"; + break; + case DW_FORM_flag: + case DW_FORM_data1: + OS << format("0x%02x", (uint8_t)UValue); + break; + case DW_FORM_data2: + OS << format("0x%04x", (uint16_t)UValue); + break; + case DW_FORM_data4: + OS << format("0x%08x", (uint32_t)UValue); + break; + case DW_FORM_ref_sig8: + AddrOS << format("0x%016" PRIx64, UValue); + break; + case DW_FORM_data8: + OS << format("0x%016" PRIx64, UValue); + break; + case DW_FORM_data16: + OS << format_bytes(ArrayRef<uint8_t>(Value.data, 16), None, 16, 16); + break; + case DW_FORM_string: + OS << '"'; + OS.write_escaped(Value.cstr); + OS << '"'; + break; + case DW_FORM_exprloc: + case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: + if (UValue > 0) { + switch (Form) { + case DW_FORM_exprloc: + case DW_FORM_block: + AddrOS << format("<0x%" PRIx64 "> ", UValue); + break; + case DW_FORM_block1: + AddrOS << format("<0x%2.2x> ", (uint8_t)UValue); + break; + case DW_FORM_block2: + AddrOS << format("<0x%4.4x> ", (uint16_t)UValue); + break; + case DW_FORM_block4: + AddrOS << format("<0x%8.8x> ", (uint32_t)UValue); + break; + default: + break; + } + + const uint8_t *DataPtr = Value.data; + if (DataPtr) { + // UValue contains size of block + const uint8_t *EndDataPtr = DataPtr + UValue; + while (DataPtr < EndDataPtr) { + AddrOS << format("%2.2x ", *DataPtr); + ++DataPtr; + } + } else + OS << "NULL"; + } + break; + + case DW_FORM_sdata: + OS << Value.sval; + break; + case DW_FORM_udata: + OS << Value.uval; + break; + case DW_FORM_strp: + if (DumpOpts.Verbose) + OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)UValue); + dumpString(OS); + break; + case DW_FORM_line_strp: + if (DumpOpts.Verbose) + OS << format(" .debug_line_str[0x%8.8x] = ", (uint32_t)UValue); + dumpString(OS); + break; + case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: + case DW_FORM_GNU_str_index: + if (DumpOpts.Verbose) + OS << format("indexed (%8.8x) string = ", (uint32_t)UValue); + dumpString(OS); + break; + case DW_FORM_GNU_strp_alt: + if (DumpOpts.Verbose) + OS << format("alt indirect string, offset: 0x%" PRIx64 "", UValue); + dumpString(OS); + break; + case DW_FORM_ref_addr: + AddrOS << format("0x%016" PRIx64, UValue); + break; + case DW_FORM_ref1: + CURelativeOffset = true; + if (DumpOpts.Verbose) + AddrOS << format("cu + 0x%2.2x", (uint8_t)UValue); + break; + case DW_FORM_ref2: + CURelativeOffset = true; + if (DumpOpts.Verbose) + AddrOS << format("cu + 0x%4.4x", (uint16_t)UValue); + break; + case DW_FORM_ref4: + CURelativeOffset = true; + if (DumpOpts.Verbose) + AddrOS << format("cu + 0x%4.4x", (uint32_t)UValue); + break; + case DW_FORM_ref8: + CURelativeOffset = true; + if (DumpOpts.Verbose) + AddrOS << format("cu + 0x%8.8" PRIx64, UValue); + break; + case DW_FORM_ref_udata: + CURelativeOffset = true; + if (DumpOpts.Verbose) + AddrOS << format("cu + 0x%" PRIx64, UValue); + break; + case DW_FORM_GNU_ref_alt: + AddrOS << format("<alt 0x%" PRIx64 ">", UValue); + break; + + // All DW_FORM_indirect attributes should be resolved prior to calling + // this function + case DW_FORM_indirect: + OS << "DW_FORM_indirect"; + break; + + case DW_FORM_rnglistx: + OS << format("indexed (0x%x) rangelist = ", (uint32_t)UValue); + break; + + // Should be formatted to 64-bit for DWARF64. + case DW_FORM_sec_offset: + AddrOS << format("0x%08x", (uint32_t)UValue); + break; + + default: + OS << format("DW_FORM(0x%4.4x)", Form); + break; + } + + if (CURelativeOffset) { + if (DumpOpts.Verbose) + OS << " => {"; + if (DumpOpts.ShowAddresses) + WithColor(OS, HighlightColor::Address).get() + << format("0x%8.8" PRIx64, UValue + (U ? U->getOffset() : 0)); + if (DumpOpts.Verbose) + OS << "}"; + } +} + +void DWARFFormValue::dumpString(raw_ostream &OS) const { + Optional<const char *> DbgStr = getAsCString(); + if (DbgStr.hasValue()) { + auto COS = WithColor(OS, HighlightColor::String); + COS.get() << '"'; + COS.get().write_escaped(DbgStr.getValue()); + COS.get() << '"'; + } +} + +Optional<const char *> DWARFFormValue::getAsCString() const { + if (!isFormClass(FC_String)) + return None; + if (Form == DW_FORM_string) + return Value.cstr; + // FIXME: Add support for DW_FORM_GNU_strp_alt + if (Form == DW_FORM_GNU_strp_alt || C == nullptr) + return None; + uint64_t Offset = Value.uval; + if (Form == DW_FORM_line_strp) { + // .debug_line_str is tracked in the Context. + if (const char *Str = C->getLineStringExtractor().getCStr(&Offset)) + return Str; + return None; + } + if (Form == DW_FORM_GNU_str_index || Form == DW_FORM_strx || + Form == DW_FORM_strx1 || Form == DW_FORM_strx2 || Form == DW_FORM_strx3 || + Form == DW_FORM_strx4) { + if (!U) + return None; + Optional<uint64_t> StrOffset = U->getStringOffsetSectionItem(Offset); + if (!StrOffset) + return None; + Offset = *StrOffset; + } + // Prefer the Unit's string extractor, because for .dwo it will point to + // .debug_str.dwo, while the Context's extractor always uses .debug_str. + if (U) { + if (const char *Str = U->getStringExtractor().getCStr(&Offset)) + return Str; + return None; + } + if (const char *Str = C->getStringExtractor().getCStr(&Offset)) + return Str; + return None; +} + +Optional<uint64_t> DWARFFormValue::getAsAddress() const { + if (auto SA = getAsSectionedAddress()) + return SA->Address; + return None; +} + +Optional<object::SectionedAddress> +DWARFFormValue::getAsSectionedAddress() const { + if (!isFormClass(FC_Address)) + return None; + if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx) { + uint32_t Index = Value.uval; + if (!U) + return None; + Optional<object::SectionedAddress> SA = U->getAddrOffsetSectionItem(Index); + if (!SA) + return None; + return SA; + } + return {{Value.uval, Value.SectionIndex}}; +} + +Optional<uint64_t> DWARFFormValue::getAsReference() const { + if (auto R = getAsRelativeReference()) + return R->Unit ? R->Unit->getOffset() + R->Offset : R->Offset; + return None; +} + +Optional<DWARFFormValue::UnitOffset> DWARFFormValue::getAsRelativeReference() const { + if (!isFormClass(FC_Reference)) + return None; + switch (Form) { + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: + if (!U) + return None; + return UnitOffset{const_cast<DWARFUnit*>(U), Value.uval}; + case DW_FORM_ref_addr: + case DW_FORM_ref_sig8: + case DW_FORM_GNU_ref_alt: + return UnitOffset{nullptr, Value.uval}; + default: + return None; + } +} + +Optional<uint64_t> DWARFFormValue::getAsSectionOffset() const { + if (!isFormClass(FC_SectionOffset)) + return None; + return Value.uval; +} + +Optional<uint64_t> DWARFFormValue::getAsUnsignedConstant() const { + if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) || + Form == DW_FORM_sdata) + return None; + return Value.uval; +} + +Optional<int64_t> DWARFFormValue::getAsSignedConstant() const { + if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) || + (Form == DW_FORM_udata && + uint64_t(std::numeric_limits<int64_t>::max()) < Value.uval)) + return None; + switch (Form) { + case DW_FORM_data4: + return int32_t(Value.uval); + case DW_FORM_data2: + return int16_t(Value.uval); + case DW_FORM_data1: + return int8_t(Value.uval); + case DW_FORM_sdata: + case DW_FORM_data8: + default: + return Value.sval; + } +} + +Optional<ArrayRef<uint8_t>> DWARFFormValue::getAsBlock() const { + if (!isFormClass(FC_Block) && !isFormClass(FC_Exprloc) && + Form != DW_FORM_data16) + return None; + return makeArrayRef(Value.data, Value.uval); +} + +Optional<uint64_t> DWARFFormValue::getAsCStringOffset() const { + if (!isFormClass(FC_String) && Form == DW_FORM_string) + return None; + return Value.uval; +} + +Optional<uint64_t> DWARFFormValue::getAsReferenceUVal() const { + if (!isFormClass(FC_Reference)) + return None; + return Value.uval; +} |