//===- DWARFDataExtractor.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/DWARFDataExtractor.h" #include "llvm/DebugInfo/DWARF/DWARFObject.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/Errc.h" using namespace llvm; std::pair DWARFDataExtractor::getInitialLength(uint64_t *Off, Error *Err) const { ErrorAsOutParameter ErrAsOut(Err); if (Err && *Err) return {0, dwarf::DWARF32}; Cursor C(*Off); uint64_t Length = getRelocatedValue(C, 4); dwarf::DwarfFormat Format = dwarf::DWARF32; if (Length == dwarf::DW_LENGTH_DWARF64) { Length = getRelocatedValue(C, 8); Format = dwarf::DWARF64; } else if (Length >= dwarf::DW_LENGTH_lo_reserved) { cantFail(C.takeError()); if (Err) *Err = createStringError( errc::invalid_argument, "unsupported reserved unit length of value 0x%8.8" PRIx64, Length); return {0, dwarf::DWARF32}; } if (C) { *Off = C.tell(); return {Length, Format}; } if (Err) *Err = C.takeError(); else consumeError(C.takeError()); return {0, dwarf::DWARF32}; } uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint64_t *Off, uint64_t *SecNdx, Error *Err) const { if (SecNdx) *SecNdx = object::SectionedAddress::UndefSection; if (!Section) return getUnsigned(Off, Size, Err); ErrorAsOutParameter ErrAsOut(Err); std::optional E = Obj->find(*Section, *Off); uint64_t LocData = getUnsigned(Off, Size, Err); if (!E || (Err && *Err)) return LocData; if (SecNdx) *SecNdx = E->SectionIndex; uint64_t R = object::resolveRelocation(E->Resolver, E->Reloc, E->SymbolValue, LocData); if (E->Reloc2) R = object::resolveRelocation(E->Resolver, *E->Reloc2, E->SymbolValue2, R); return R; } std::optional DWARFDataExtractor::getEncodedPointer(uint64_t *Offset, uint8_t Encoding, uint64_t PCRelOffset) const { if (Encoding == dwarf::DW_EH_PE_omit) return std::nullopt; uint64_t Result = 0; uint64_t OldOffset = *Offset; // First get value switch (Encoding & 0x0F) { case dwarf::DW_EH_PE_absptr: switch (getAddressSize()) { case 2: case 4: case 8: Result = getUnsigned(Offset, getAddressSize()); break; default: return std::nullopt; } break; case dwarf::DW_EH_PE_uleb128: Result = getULEB128(Offset); break; case dwarf::DW_EH_PE_sleb128: Result = getSLEB128(Offset); break; case dwarf::DW_EH_PE_udata2: Result = getUnsigned(Offset, 2); break; case dwarf::DW_EH_PE_udata4: Result = getUnsigned(Offset, 4); break; case dwarf::DW_EH_PE_udata8: Result = getUnsigned(Offset, 8); break; case dwarf::DW_EH_PE_sdata2: Result = getSigned(Offset, 2); break; case dwarf::DW_EH_PE_sdata4: Result = SignExtend64<32>(getRelocatedValue(4, Offset)); break; case dwarf::DW_EH_PE_sdata8: Result = getRelocatedValue(8, Offset); break; default: return std::nullopt; } // Then add relative offset, if required switch (Encoding & 0x70) { case dwarf::DW_EH_PE_absptr: // do nothing break; case dwarf::DW_EH_PE_pcrel: Result += PCRelOffset; break; case dwarf::DW_EH_PE_datarel: case dwarf::DW_EH_PE_textrel: case dwarf::DW_EH_PE_funcrel: case dwarf::DW_EH_PE_aligned: default: *Offset = OldOffset; return std::nullopt; } return Result; }