diff options
Diffstat (limited to 'llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp')
| -rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp | 720 | 
1 files changed, 720 insertions, 0 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp new file mode 100644 index 000000000000..26090638b34c --- /dev/null +++ b/llvm/lib/DebugInfo/DWARF/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; +}  | 
