| //===- 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; | 
 |   Format = FP.Format; | 
 |   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 | 
 |   Error Err = Error::success(); | 
 |   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, &Err); | 
 |       break; | 
 |     } | 
 |     case DW_FORM_exprloc: | 
 |     case DW_FORM_block: | 
 |       Value.uval = Data.getULEB128(OffsetPtr, &Err); | 
 |       IsBlock = true; | 
 |       break; | 
 |     case DW_FORM_block1: | 
 |       Value.uval = Data.getU8(OffsetPtr, &Err); | 
 |       IsBlock = true; | 
 |       break; | 
 |     case DW_FORM_block2: | 
 |       Value.uval = Data.getU16(OffsetPtr, &Err); | 
 |       IsBlock = true; | 
 |       break; | 
 |     case DW_FORM_block4: | 
 |       Value.uval = Data.getU32(OffsetPtr, &Err); | 
 |       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, &Err); | 
 |       break; | 
 |     case DW_FORM_data2: | 
 |     case DW_FORM_ref2: | 
 |     case DW_FORM_strx2: | 
 |     case DW_FORM_addrx2: | 
 |       Value.uval = Data.getU16(OffsetPtr, &Err); | 
 |       break; | 
 |     case DW_FORM_strx3: | 
 |       Value.uval = Data.getU24(OffsetPtr, &Err); | 
 |       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, nullptr, &Err); | 
 |       break; | 
 |     case DW_FORM_data8: | 
 |     case DW_FORM_ref8: | 
 |     case DW_FORM_ref_sup8: | 
 |       Value.uval = Data.getRelocatedValue(8, OffsetPtr, nullptr, &Err); | 
 |       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, &Err); | 
 |       break; | 
 |     case DW_FORM_udata: | 
 |     case DW_FORM_ref_udata: | 
 |     case DW_FORM_rnglistx: | 
 |     case DW_FORM_loclistx: | 
 |     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, &Err); | 
 |       break; | 
 |     case DW_FORM_string: | 
 |       Value.cstr = Data.getCStr(OffsetPtr, &Err); | 
 |       break; | 
 |     case DW_FORM_indirect: | 
 |       Form = static_cast<dwarf::Form>(Data.getULEB128(OffsetPtr, &Err)); | 
 |       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, nullptr, &Err); | 
 |       break; | 
 |     } | 
 |     case DW_FORM_flag_present: | 
 |       Value.uval = 1; | 
 |       break; | 
 |     case DW_FORM_ref_sig8: | 
 |       Value.uval = Data.getU64(OffsetPtr, &Err); | 
 |       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 && !Err); | 
 |  | 
 |   if (IsBlock) | 
 |     Value.data = Data.getBytes(OffsetPtr, Value.uval, &Err).bytes_begin(); | 
 |  | 
 |   return !errorToBool(std::move(Err)); | 
 | } | 
 |  | 
 | 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(); | 
 |   int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format); | 
 |   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 << "<unresolved>"; | 
 |     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%0*" PRIx64 "] = ", OffsetDumpWidth, UValue); | 
 |     dumpString(OS); | 
 |     break; | 
 |   case DW_FORM_line_strp: | 
 |     if (DumpOpts.Verbose) | 
 |       OS << format(" .debug_line_str[0x%0*" PRIx64 "] = ", OffsetDumpWidth, | 
 |                    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; | 
 |  | 
 |   case DW_FORM_loclistx: | 
 |     OS << format("indexed (0x%x) loclist = ", (uint32_t)UValue); | 
 |     break; | 
 |  | 
 |   case DW_FORM_sec_offset: | 
 |     AddrOS << format("0x%0*" PRIx64, OffsetDumpWidth, 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; | 
 | } |