brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.8 KiB · c61f757 Raw
415 lines · cpp
1//===- DWARFDebugFrame.h - Parsing of .debug_frame ------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"10#include "llvm/ADT/DenseMap.h"11#include "llvm/ADT/StringExtras.h"12#include "llvm/ADT/StringRef.h"13#include "llvm/BinaryFormat/Dwarf.h"14#include "llvm/DebugInfo/DIContext.h"15#include "llvm/DebugInfo/DWARF/DWARFCFIPrinter.h"16#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"17#include "llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h"18#include "llvm/DebugInfo/DWARF/DWARFUnwindTablePrinter.h"19#include "llvm/DebugInfo/DWARF/LowLevel/DWARFCFIProgram.h"20#include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"21#include "llvm/Support/Compiler.h"22#include "llvm/Support/DataExtractor.h"23#include "llvm/Support/Errc.h"24#include "llvm/Support/Error.h"25#include "llvm/Support/ErrorHandling.h"26#include "llvm/Support/Format.h"27#include "llvm/Support/raw_ostream.h"28#include <cassert>29#include <cinttypes>30#include <cstdint>31#include <optional>32 33using namespace llvm;34using namespace dwarf;35 36Expected<UnwindTable> llvm::dwarf::createUnwindTable(const FDE *Fde) {37  const CIE *Cie = Fde->getLinkedCIE();38  if (Cie == nullptr)39    return createStringError(errc::invalid_argument,40                             "unable to get CIE for FDE at offset 0x%" PRIx64,41                             Fde->getOffset());42 43  // Rows will be empty if there are no CFI instructions.44  if (Cie->cfis().empty() && Fde->cfis().empty())45    return UnwindTable({});46 47  UnwindTable::RowContainer CieRows;48  UnwindRow Row;49  Row.setAddress(Fde->getInitialLocation());50  if (Error CieError = parseRows(Cie->cfis(), Row, nullptr).moveInto(CieRows))51    return std::move(CieError);52  // We need to save the initial locations of registers from the CIE parsing53  // in case we run into DW_CFA_restore or DW_CFA_restore_extended opcodes.54  UnwindTable::RowContainer FdeRows;55  const RegisterLocations InitialLocs = Row.getRegisterLocations();56  if (Error FdeError =57          parseRows(Fde->cfis(), Row, &InitialLocs).moveInto(FdeRows))58    return std::move(FdeError);59 60  UnwindTable::RowContainer AllRows;61  AllRows.insert(AllRows.end(), CieRows.begin(), CieRows.end());62  AllRows.insert(AllRows.end(), FdeRows.begin(), FdeRows.end());63 64  // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.65  // Do not add that to the unwind table.66  if (Row.getRegisterLocations().hasLocations() ||67      Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)68    AllRows.push_back(Row);69  return UnwindTable(std::move(AllRows));70}71 72Expected<UnwindTable> llvm::dwarf::createUnwindTable(const CIE *Cie) {73  // Rows will be empty if there are no CFI instructions.74  if (Cie->cfis().empty())75    return UnwindTable({});76 77  UnwindTable::RowContainer Rows;78  UnwindRow Row;79  if (Error CieError = parseRows(Cie->cfis(), Row, nullptr).moveInto(Rows))80    return std::move(CieError);81  // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.82  // Do not add that to the unwind table.83  if (Row.getRegisterLocations().hasLocations() ||84      Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)85    Rows.push_back(Row);86  return UnwindTable(std::move(Rows));87}88 89// Returns the CIE identifier to be used by the requested format.90// CIE ids for .debug_frame sections are defined in Section 7.24 of DWARFv5.91// For CIE ID in .eh_frame sections see92// https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html93constexpr uint64_t getCIEId(bool IsDWARF64, bool IsEH) {94  if (IsEH)95    return 0;96  if (IsDWARF64)97    return DW64_CIE_ID;98  return DW_CIE_ID;99}100 101void CIE::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {102  // A CIE with a zero length is a terminator entry in the .eh_frame section.103  if (DumpOpts.IsEH && Length == 0) {104    OS << format("%08" PRIx64, Offset) << " ZERO terminator\n";105    return;106  }107 108  OS << format("%08" PRIx64, Offset)109     << format(" %0*" PRIx64, IsDWARF64 ? 16 : 8, Length)110     << format(" %0*" PRIx64, IsDWARF64 && !DumpOpts.IsEH ? 16 : 8,111               getCIEId(IsDWARF64, DumpOpts.IsEH))112     << " CIE\n"113     << "  Format:                " << FormatString(IsDWARF64) << "\n";114  if (DumpOpts.IsEH && Version != 1)115    OS << "WARNING: unsupported CIE version\n";116  OS << format("  Version:               %d\n", Version)117     << "  Augmentation:          \"" << Augmentation << "\"\n";118  if (Version >= 4) {119    OS << format("  Address size:          %u\n", (uint32_t)AddressSize);120    OS << format("  Segment desc size:     %u\n",121                 (uint32_t)SegmentDescriptorSize);122  }123  OS << format("  Code alignment factor: %u\n", (uint32_t)CodeAlignmentFactor);124  OS << format("  Data alignment factor: %d\n", (int32_t)DataAlignmentFactor);125  OS << format("  Return address column: %d\n", (int32_t)ReturnAddressRegister);126  if (Personality)127    OS << format("  Personality Address: %016" PRIx64 "\n", *Personality);128  if (!AugmentationData.empty()) {129    OS << "  Augmentation data:    ";130    for (uint8_t Byte : AugmentationData)131      OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf);132    OS << "\n";133  }134  OS << "\n";135  printCFIProgram(CFIs, OS, DumpOpts, /*IndentLevel=*/1,136                  /*InitialLocation=*/{});137  OS << "\n";138 139  if (Expected<UnwindTable> RowsOrErr = createUnwindTable(this))140    printUnwindTable(*RowsOrErr, OS, DumpOpts, 1);141  else {142    DumpOpts.RecoverableErrorHandler(joinErrors(143        createStringError(errc::invalid_argument,144                          "decoding the CIE opcodes into rows failed"),145        RowsOrErr.takeError()));146  }147  OS << "\n";148}149 150void FDE::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {151  OS << format("%08" PRIx64, Offset)152     << format(" %0*" PRIx64, IsDWARF64 ? 16 : 8, Length)153     << format(" %0*" PRIx64, IsDWARF64 && !DumpOpts.IsEH ? 16 : 8, CIEPointer)154     << " FDE cie=";155  if (LinkedCIE)156    OS << format("%08" PRIx64, LinkedCIE->getOffset());157  else158    OS << "<invalid offset>";159  OS << format(" pc=%08" PRIx64 "...%08" PRIx64 "\n", InitialLocation,160               InitialLocation + AddressRange);161  OS << "  Format:       " << FormatString(IsDWARF64) << "\n";162  if (LSDAAddress)163    OS << format("  LSDA Address: %016" PRIx64 "\n", *LSDAAddress);164  printCFIProgram(CFIs, OS, DumpOpts, /*IndentLevel=*/1, InitialLocation);165  OS << "\n";166 167  if (Expected<UnwindTable> RowsOrErr = createUnwindTable(this))168    printUnwindTable(*RowsOrErr, OS, DumpOpts, 1);169  else {170    DumpOpts.RecoverableErrorHandler(joinErrors(171        createStringError(errc::invalid_argument,172                          "decoding the FDE opcodes into rows failed"),173        RowsOrErr.takeError()));174  }175  OS << "\n";176}177 178DWARFDebugFrame::DWARFDebugFrame(Triple::ArchType Arch,179    bool IsEH, uint64_t EHFrameAddress)180    : Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {}181 182DWARFDebugFrame::~DWARFDebugFrame() = default;183 184[[maybe_unused]] static void dumpDataAux(DataExtractor Data, uint64_t Offset,185                                         int Length) {186  errs() << "DUMP: ";187  for (int i = 0; i < Length; ++i) {188    uint8_t c = Data.getU8(&Offset);189    errs().write_hex(c); errs() << " ";190  }191  errs() << "\n";192}193 194Error DWARFDebugFrame::parse(DWARFDataExtractor Data) {195  uint64_t Offset = 0;196  DenseMap<uint64_t, CIE *> CIEs;197 198  while (Data.isValidOffset(Offset)) {199    uint64_t StartOffset = Offset;200 201    uint64_t Length;202    DwarfFormat Format;203    std::tie(Length, Format) = Data.getInitialLength(&Offset);204    bool IsDWARF64 = Format == DWARF64;205 206    // If the Length is 0, then this CIE is a terminator. We add it because some207    // dumper tools might need it to print something special for such entries208    // (e.g. llvm-objdump --dwarf=frames prints "ZERO terminator").209    if (Length == 0) {210      auto Cie = std::make_unique<CIE>(211          IsDWARF64, StartOffset, 0, 0, SmallString<8>(), 0, 0, 0, 0, 0,212          SmallString<8>(), 0, 0, std::nullopt, std::nullopt, Arch);213      CIEs[StartOffset] = Cie.get();214      Entries.push_back(std::move(Cie));215      break;216    }217 218    // At this point, Offset points to the next field after Length.219    // Length is the structure size excluding itself. Compute an offset one220    // past the end of the structure (needed to know how many instructions to221    // read).222    uint64_t StartStructureOffset = Offset;223    uint64_t EndStructureOffset = Offset + Length;224 225    // The Id field's size depends on the DWARF format226    Error Err = Error::success();227    uint64_t Id = Data.getRelocatedValue((IsDWARF64 && !IsEH) ? 8 : 4, &Offset,228                                         /*SectionIndex=*/nullptr, &Err);229    if (Err)230      return Err;231 232    if (Id == getCIEId(IsDWARF64, IsEH)) {233      uint8_t Version = Data.getU8(&Offset);234      const char *Augmentation = Data.getCStr(&Offset);235      StringRef AugmentationString(Augmentation ? Augmentation : "");236      uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :237                                          Data.getU8(&Offset);238      Data.setAddressSize(AddressSize);239      uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset);240      uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);241      int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);242      uint64_t ReturnAddressRegister =243          Version == 1 ? Data.getU8(&Offset) : Data.getULEB128(&Offset);244 245      // Parse the augmentation data for EH CIEs246      StringRef AugmentationData("");247      uint32_t FDEPointerEncoding = DW_EH_PE_absptr;248      uint32_t LSDAPointerEncoding = DW_EH_PE_omit;249      std::optional<uint64_t> Personality;250      std::optional<uint32_t> PersonalityEncoding;251      if (IsEH) {252        std::optional<uint64_t> AugmentationLength;253        uint64_t StartAugmentationOffset;254        uint64_t EndAugmentationOffset;255 256        // Walk the augmentation string to get all the augmentation data.257        for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {258          switch (AugmentationString[i]) {259          default:260            return createStringError(261                errc::invalid_argument,262                "unknown augmentation character %c in entry at 0x%" PRIx64,263                AugmentationString[i], StartOffset);264          case 'L':265            LSDAPointerEncoding = Data.getU8(&Offset);266            break;267          case 'P': {268            if (Personality)269              return createStringError(270                  errc::invalid_argument,271                  "duplicate personality in entry at 0x%" PRIx64, StartOffset);272            PersonalityEncoding = Data.getU8(&Offset);273            Personality = Data.getEncodedPointer(274                &Offset, *PersonalityEncoding,275                EHFrameAddress ? EHFrameAddress + Offset : 0);276            break;277          }278          case 'R':279            FDEPointerEncoding = Data.getU8(&Offset);280            break;281          case 'S':282            // Current frame is a signal trampoline.283            break;284          case 'z':285            if (i)286              return createStringError(287                  errc::invalid_argument,288                  "'z' must be the first character at 0x%" PRIx64, StartOffset);289            // Parse the augmentation length first.  We only parse it if290            // the string contains a 'z'.291            AugmentationLength = Data.getULEB128(&Offset);292            StartAugmentationOffset = Offset;293            EndAugmentationOffset = Offset + *AugmentationLength;294            break;295          case 'B':296            // B-Key is used for signing functions associated with this297            // augmentation string298            break;299            // This stack frame contains MTE tagged data, so needs to be300            // untagged on unwind.301          case 'G':302            break;303          }304        }305 306        if (AugmentationLength) {307          if (Offset != EndAugmentationOffset)308            return createStringError(errc::invalid_argument,309                                     "parsing augmentation data at 0x%" PRIx64310                                     " failed",311                                     StartOffset);312          AugmentationData = Data.getData().slice(StartAugmentationOffset,313                                                  EndAugmentationOffset);314        }315      }316 317      auto Cie = std::make_unique<CIE>(318          IsDWARF64, StartOffset, Length, Version, AugmentationString,319          AddressSize, SegmentDescriptorSize, CodeAlignmentFactor,320          DataAlignmentFactor, ReturnAddressRegister, AugmentationData,321          FDEPointerEncoding, LSDAPointerEncoding, Personality,322          PersonalityEncoding, Arch);323      CIEs[StartOffset] = Cie.get();324      Entries.emplace_back(std::move(Cie));325    } else {326      // FDE327      uint64_t CIEPointer = Id;328      uint64_t InitialLocation = 0;329      uint64_t AddressRange = 0;330      std::optional<uint64_t> LSDAAddress;331      CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer];332 333      if (IsEH) {334        // The address size is encoded in the CIE we reference.335        if (!Cie)336          return createStringError(errc::invalid_argument,337                                   "parsing FDE data at 0x%" PRIx64338                                   " failed due to missing CIE",339                                   StartOffset);340        if (auto Val =341                Data.getEncodedPointer(&Offset, Cie->getFDEPointerEncoding(),342                                       EHFrameAddress + Offset)) {343          InitialLocation = *Val;344        }345        if (auto Val = Data.getEncodedPointer(346                &Offset, Cie->getFDEPointerEncoding(), 0)) {347          AddressRange = *Val;348        }349 350        StringRef AugmentationString = Cie->getAugmentationString();351        if (!AugmentationString.empty()) {352          // Parse the augmentation length and data for this FDE.353          uint64_t AugmentationLength = Data.getULEB128(&Offset);354 355          uint64_t EndAugmentationOffset = Offset + AugmentationLength;356 357          // Decode the LSDA if the CIE augmentation string said we should.358          if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit) {359            LSDAAddress = Data.getEncodedPointer(360                &Offset, Cie->getLSDAPointerEncoding(),361                EHFrameAddress ? Offset + EHFrameAddress : 0);362          }363 364          if (Offset != EndAugmentationOffset)365            return createStringError(errc::invalid_argument,366                                     "parsing augmentation data at 0x%" PRIx64367                                     " failed",368                                     StartOffset);369        }370      } else {371        InitialLocation = Data.getRelocatedAddress(&Offset);372        AddressRange = Data.getRelocatedAddress(&Offset);373      }374 375      Entries.emplace_back(new FDE(IsDWARF64, StartOffset, Length, CIEPointer,376                                   InitialLocation, AddressRange, Cie,377                                   LSDAAddress, Arch));378    }379 380    if (Error E =381            Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset))382      return E;383 384    if (Offset != EndStructureOffset)385      return createStringError(386          errc::invalid_argument,387          "parsing entry instructions at 0x%" PRIx64 " failed", StartOffset);388  }389 390  return Error::success();391}392 393FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const {394  auto It = partition_point(Entries, [=](const std::unique_ptr<FrameEntry> &E) {395    return E->getOffset() < Offset;396  });397  if (It != Entries.end() && (*It)->getOffset() == Offset)398    return It->get();399  return nullptr;400}401 402void DWARFDebugFrame::dump(raw_ostream &OS, DIDumpOptions DumpOpts,403                           std::optional<uint64_t> Offset) const {404  DumpOpts.IsEH = IsEH;405  if (Offset) {406    if (auto *Entry = getEntryAtOffset(*Offset))407      Entry->dump(OS, DumpOpts);408    return;409  }410 411  OS << "\n";412  for (const auto &Entry : Entries)413    Entry->dump(OS, DumpOpts);414}415