245 lines · c
1//===--- DwarfCFIEHPrinter.h - DWARF-based Unwind Information Printer -----===//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#ifndef LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H10#define LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H11 12#include "llvm-readobj.h"13#include "llvm/ADT/STLExtras.h"14#include "llvm/BinaryFormat/Dwarf.h"15#include "llvm/DebugInfo/DWARF/DWARFCFIPrinter.h"16#include "llvm/DebugInfo/DWARF/DWARFContext.h"17#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"18#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"19#include "llvm/Object/ELF.h"20#include "llvm/Object/ELFObjectFile.h"21#include "llvm/Object/ELFTypes.h"22#include "llvm/Support/Casting.h"23#include "llvm/Support/Debug.h"24#include "llvm/Support/Endian.h"25#include "llvm/Support/Format.h"26#include "llvm/Support/ScopedPrinter.h"27#include "llvm/Support/type_traits.h"28 29namespace llvm {30namespace DwarfCFIEH {31 32template <typename ELFT> class PrinterContext {33 using Elf_Shdr = typename ELFT::Shdr;34 using Elf_Phdr = typename ELFT::Phdr;35 36 ScopedPrinter &W;37 const object::ELFObjectFile<ELFT> &ObjF;38 39 void printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const;40 void printEHFrame(const Elf_Shdr *EHFrameShdr) const;41 42public:43 PrinterContext(ScopedPrinter &W, const object::ELFObjectFile<ELFT> &ObjF)44 : W(W), ObjF(ObjF) {}45 46 void printUnwindInformation() const;47};48 49template <class ELFT>50static const typename ELFT::Shdr *51findSectionByAddress(const object::ELFObjectFile<ELFT> &ObjF, uint64_t Addr) {52 Expected<typename ELFT::ShdrRange> SectionsOrErr =53 ObjF.getELFFile().sections();54 if (!SectionsOrErr)55 reportError(SectionsOrErr.takeError(), ObjF.getFileName());56 57 for (const typename ELFT::Shdr &Shdr : *SectionsOrErr)58 if (Shdr.sh_addr == Addr)59 return &Shdr;60 return nullptr;61}62 63template <typename ELFT>64void PrinterContext<ELFT>::printUnwindInformation() const {65 const object::ELFFile<ELFT> &Obj = ObjF.getELFFile();66 67 Expected<typename ELFT::PhdrRange> PhdrsOrErr = Obj.program_headers();68 if (!PhdrsOrErr)69 reportError(PhdrsOrErr.takeError(), ObjF.getFileName());70 71 for (const Elf_Phdr &Phdr : *PhdrsOrErr) {72 if (Phdr.p_type != ELF::PT_GNU_EH_FRAME)73 continue;74 75 if (Phdr.p_memsz != Phdr.p_filesz)76 reportError(object::createError(77 "p_memsz does not match p_filesz for GNU_EH_FRAME"),78 ObjF.getFileName());79 printEHFrameHdr(&Phdr);80 break;81 }82 83 Expected<typename ELFT::ShdrRange> SectionsOrErr = Obj.sections();84 if (!SectionsOrErr)85 reportError(SectionsOrErr.takeError(), ObjF.getFileName());86 87 for (const Elf_Shdr &Shdr : *SectionsOrErr) {88 Expected<StringRef> NameOrErr = Obj.getSectionName(Shdr);89 if (!NameOrErr)90 reportError(NameOrErr.takeError(), ObjF.getFileName());91 if (*NameOrErr == ".eh_frame")92 printEHFrame(&Shdr);93 }94}95 96template <typename ELFT>97void PrinterContext<ELFT>::printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const {98 DictScope L(W, "EHFrameHeader");99 uint64_t EHFrameHdrAddress = EHFramePHdr->p_vaddr;100 W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress);101 W.startLine() << format("Offset: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_offset);102 W.startLine() << format("Size: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_memsz);103 104 const object::ELFFile<ELFT> &Obj = ObjF.getELFFile();105 if (const Elf_Shdr *EHFrameHdr =106 findSectionByAddress(ObjF, EHFramePHdr->p_vaddr)) {107 Expected<StringRef> NameOrErr = Obj.getSectionName(*EHFrameHdr);108 if (!NameOrErr)109 reportError(NameOrErr.takeError(), ObjF.getFileName());110 W.printString("Corresponding Section", *NameOrErr);111 }112 113 Expected<ArrayRef<uint8_t>> Content = Obj.getSegmentContents(*EHFramePHdr);114 if (!Content)115 reportError(Content.takeError(), ObjF.getFileName());116 117 DataExtractor DE(*Content, ELFT::Endianness == llvm::endianness::little,118 ELFT::Is64Bits ? 8 : 4);119 120 DictScope D(W, "Header");121 uint64_t Offset = 0;122 123 auto Version = DE.getU8(&Offset);124 W.printNumber("version", Version);125 if (Version != 1)126 reportError(127 object::createError("only version 1 of .eh_frame_hdr is supported"),128 ObjF.getFileName());129 130 uint64_t EHFramePtrEnc = DE.getU8(&Offset);131 W.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64 "\n", EHFramePtrEnc);132 if (EHFramePtrEnc != (dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4))133 reportError(object::createError("unexpected encoding eh_frame_ptr_enc"),134 ObjF.getFileName());135 136 uint64_t FDECountEnc = DE.getU8(&Offset);137 W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc);138 if (FDECountEnc != dwarf::DW_EH_PE_udata4)139 reportError(object::createError("unexpected encoding fde_count_enc"),140 ObjF.getFileName());141 142 uint64_t TableEnc = DE.getU8(&Offset);143 W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc);144 if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4))145 reportError(object::createError("unexpected encoding table_enc"),146 ObjF.getFileName());147 148 auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4;149 W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr);150 151 auto FDECount = DE.getUnsigned(&Offset, 4);152 W.printNumber("fde_count", FDECount);153 154 unsigned NumEntries = 0;155 uint64_t PrevPC = 0;156 while (Offset + 8 <= EHFramePHdr->p_memsz && NumEntries < FDECount) {157 DictScope D(W, std::string("entry ") + std::to_string(NumEntries));158 159 auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;160 W.startLine() << format("initial_location: 0x%" PRIx64 "\n", InitialPC);161 auto Address = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;162 W.startLine() << format("address: 0x%" PRIx64 "\n", Address);163 164 if (InitialPC < PrevPC)165 reportError(object::createError("initial_location is out of order"),166 ObjF.getFileName());167 168 PrevPC = InitialPC;169 ++NumEntries;170 }171}172 173template <typename ELFT>174void PrinterContext<ELFT>::printEHFrame(const Elf_Shdr *EHFrameShdr) const {175 uint64_t Address = EHFrameShdr->sh_addr;176 uint64_t ShOffset = EHFrameShdr->sh_offset;177 W.startLine() << format(".eh_frame section at offset 0x%" PRIx64178 " address 0x%" PRIx64 ":\n",179 ShOffset, Address);180 W.indent();181 182 Expected<ArrayRef<uint8_t>> DataOrErr =183 ObjF.getELFFile().getSectionContents(*EHFrameShdr);184 if (!DataOrErr)185 reportError(DataOrErr.takeError(), ObjF.getFileName());186 187 // Construct DWARFDataExtractor to handle relocations ("PC Begin" fields).188 std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(189 ObjF, DWARFContext::ProcessDebugRelocations::Process, nullptr);190 DWARFDataExtractor DE(191 DICtx->getDWARFObj(), DICtx->getDWARFObj().getEHFrameSection(),192 ELFT::Endianness == llvm::endianness::little, ELFT::Is64Bits ? 8 : 4);193 DWARFDebugFrame EHFrame(Triple::ArchType(ObjF.getArch()), /*IsEH=*/true,194 /*EHFrameAddress=*/Address);195 if (Error E = EHFrame.parse(DE))196 reportError(std::move(E), ObjF.getFileName());197 198 for (const dwarf::FrameEntry &Entry : EHFrame) {199 std::optional<uint64_t> InitialLocation;200 if (const dwarf::CIE *CIE = dyn_cast<dwarf::CIE>(&Entry)) {201 W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n",202 Address + CIE->getOffset(), CIE->getLength());203 W.indent();204 205 W.printNumber("version", CIE->getVersion());206 W.printString("augmentation", CIE->getAugmentationString());207 W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor());208 W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor());209 W.printNumber("return_address_register", CIE->getReturnAddressRegister());210 } else {211 const dwarf::FDE *FDE = cast<dwarf::FDE>(&Entry);212 W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64213 " cie=[0x%" PRIx64 "]\n",214 Address + FDE->getOffset(), FDE->getLength(),215 Address + FDE->getLinkedCIE()->getOffset());216 W.indent();217 218 InitialLocation = FDE->getInitialLocation();219 W.startLine() << format("initial_location: 0x%" PRIx64 "\n",220 *InitialLocation);221 W.startLine() << format(222 "address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n",223 FDE->getAddressRange(),224 FDE->getInitialLocation() + FDE->getAddressRange());225 }226 227 W.getOStream() << "\n";228 W.startLine() << "Program:\n";229 W.indent();230 auto DumpOpts = DIDumpOptions();231 DumpOpts.IsEH = true;232 printCFIProgram(Entry.cfis(), W.getOStream(), DumpOpts, W.getIndentLevel(),233 InitialLocation);234 W.unindent();235 W.unindent();236 W.getOStream() << "\n";237 }238 239 W.unindent();240}241} // namespace DwarfCFIEH242} // namespace llvm243 244#endif245