10b57cec5SDimitry Andric //===--- DwarfCFIEHPrinter.h - DWARF-based Unwind Information Printer -----===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #ifndef LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H
100b57cec5SDimitry Andric #define LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H
110b57cec5SDimitry Andric
120b57cec5SDimitry Andric #include "llvm-readobj.h"
130b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
140b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h"
15e8d8bef9SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h"
160b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
170b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
18e8d8bef9SDimitry Andric #include "llvm/Object/ELF.h"
19e8d8bef9SDimitry Andric #include "llvm/Object/ELFObjectFile.h"
20e8d8bef9SDimitry Andric #include "llvm/Object/ELFTypes.h"
21e8d8bef9SDimitry Andric #include "llvm/Support/Casting.h"
22e8d8bef9SDimitry Andric #include "llvm/Support/Debug.h"
230b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
240b57cec5SDimitry Andric #include "llvm/Support/Format.h"
25e8d8bef9SDimitry Andric #include "llvm/Support/ScopedPrinter.h"
260b57cec5SDimitry Andric #include "llvm/Support/type_traits.h"
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric namespace llvm {
290b57cec5SDimitry Andric namespace DwarfCFIEH {
300b57cec5SDimitry Andric
31e8d8bef9SDimitry Andric template <typename ELFT> class PrinterContext {
325ffd83dbSDimitry Andric using Elf_Shdr = typename ELFT::Shdr;
335ffd83dbSDimitry Andric using Elf_Phdr = typename ELFT::Phdr;
345ffd83dbSDimitry Andric
350b57cec5SDimitry Andric ScopedPrinter &W;
36e8d8bef9SDimitry Andric const object::ELFObjectFile<ELFT> &ObjF;
370b57cec5SDimitry Andric
385ffd83dbSDimitry Andric void printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const;
395ffd83dbSDimitry Andric void printEHFrame(const Elf_Shdr *EHFrameShdr) const;
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric public:
PrinterContext(ScopedPrinter & W,const object::ELFObjectFile<ELFT> & ObjF)42e8d8bef9SDimitry Andric PrinterContext(ScopedPrinter &W, const object::ELFObjectFile<ELFT> &ObjF)
430b57cec5SDimitry Andric : W(W), ObjF(ObjF) {}
440b57cec5SDimitry Andric
450b57cec5SDimitry Andric void printUnwindInformation() const;
460b57cec5SDimitry Andric };
470b57cec5SDimitry Andric
488bcb0991SDimitry Andric template <class ELFT>
495ffd83dbSDimitry Andric static const typename ELFT::Shdr *
findSectionByAddress(const object::ELFObjectFile<ELFT> & ObjF,uint64_t Addr)50e8d8bef9SDimitry Andric findSectionByAddress(const object::ELFObjectFile<ELFT> &ObjF, uint64_t Addr) {
515ffd83dbSDimitry Andric Expected<typename ELFT::ShdrRange> SectionsOrErr =
52e8d8bef9SDimitry Andric ObjF.getELFFile().sections();
535ffd83dbSDimitry Andric if (!SectionsOrErr)
54e8d8bef9SDimitry Andric reportError(SectionsOrErr.takeError(), ObjF.getFileName());
550b57cec5SDimitry Andric
565ffd83dbSDimitry Andric for (const typename ELFT::Shdr &Shdr : *SectionsOrErr)
570b57cec5SDimitry Andric if (Shdr.sh_addr == Addr)
580b57cec5SDimitry Andric return &Shdr;
590b57cec5SDimitry Andric return nullptr;
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric
620b57cec5SDimitry Andric template <typename ELFT>
printUnwindInformation()630b57cec5SDimitry Andric void PrinterContext<ELFT>::printUnwindInformation() const {
64e8d8bef9SDimitry Andric const object::ELFFile<ELFT> &Obj = ObjF.getELFFile();
650b57cec5SDimitry Andric
66e8d8bef9SDimitry Andric Expected<typename ELFT::PhdrRange> PhdrsOrErr = Obj.program_headers();
675ffd83dbSDimitry Andric if (!PhdrsOrErr)
68e8d8bef9SDimitry Andric reportError(PhdrsOrErr.takeError(), ObjF.getFileName());
690b57cec5SDimitry Andric
705ffd83dbSDimitry Andric for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
715ffd83dbSDimitry Andric if (Phdr.p_type != ELF::PT_GNU_EH_FRAME)
725ffd83dbSDimitry Andric continue;
735ffd83dbSDimitry Andric
740b57cec5SDimitry Andric if (Phdr.p_memsz != Phdr.p_filesz)
758bcb0991SDimitry Andric reportError(object::createError(
768bcb0991SDimitry Andric "p_memsz does not match p_filesz for GNU_EH_FRAME"),
77e8d8bef9SDimitry Andric ObjF.getFileName());
785ffd83dbSDimitry Andric printEHFrameHdr(&Phdr);
790b57cec5SDimitry Andric break;
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric
82e8d8bef9SDimitry Andric Expected<typename ELFT::ShdrRange> SectionsOrErr = Obj.sections();
835ffd83dbSDimitry Andric if (!SectionsOrErr)
84e8d8bef9SDimitry Andric reportError(SectionsOrErr.takeError(), ObjF.getFileName());
850b57cec5SDimitry Andric
865ffd83dbSDimitry Andric for (const Elf_Shdr &Shdr : *SectionsOrErr) {
87e8d8bef9SDimitry Andric Expected<StringRef> NameOrErr = Obj.getSectionName(Shdr);
885ffd83dbSDimitry Andric if (!NameOrErr)
89e8d8bef9SDimitry Andric reportError(NameOrErr.takeError(), ObjF.getFileName());
905ffd83dbSDimitry Andric if (*NameOrErr == ".eh_frame")
910b57cec5SDimitry Andric printEHFrame(&Shdr);
920b57cec5SDimitry Andric }
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric
950b57cec5SDimitry Andric template <typename ELFT>
printEHFrameHdr(const Elf_Phdr * EHFramePHdr)965ffd83dbSDimitry Andric void PrinterContext<ELFT>::printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const {
978bcb0991SDimitry Andric DictScope L(W, "EHFrameHeader");
985ffd83dbSDimitry Andric uint64_t EHFrameHdrAddress = EHFramePHdr->p_vaddr;
990b57cec5SDimitry Andric W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress);
1005ffd83dbSDimitry Andric W.startLine() << format("Offset: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_offset);
1015ffd83dbSDimitry Andric W.startLine() << format("Size: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_memsz);
1020b57cec5SDimitry Andric
103e8d8bef9SDimitry Andric const object::ELFFile<ELFT> &Obj = ObjF.getELFFile();
1045ffd83dbSDimitry Andric if (const Elf_Shdr *EHFrameHdr =
1055ffd83dbSDimitry Andric findSectionByAddress(ObjF, EHFramePHdr->p_vaddr)) {
106e8d8bef9SDimitry Andric Expected<StringRef> NameOrErr = Obj.getSectionName(*EHFrameHdr);
1075ffd83dbSDimitry Andric if (!NameOrErr)
108e8d8bef9SDimitry Andric reportError(NameOrErr.takeError(), ObjF.getFileName());
1095ffd83dbSDimitry Andric W.printString("Corresponding Section", *NameOrErr);
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric
112e8d8bef9SDimitry Andric Expected<ArrayRef<uint8_t>> Content = Obj.getSegmentContents(*EHFramePHdr);
1135ffd83dbSDimitry Andric if (!Content)
114e8d8bef9SDimitry Andric reportError(Content.takeError(), ObjF.getFileName());
1155ffd83dbSDimitry Andric
116*0fca6ea1SDimitry Andric DataExtractor DE(*Content, ELFT::Endianness == llvm::endianness::little,
1170b57cec5SDimitry Andric ELFT::Is64Bits ? 8 : 4);
1180b57cec5SDimitry Andric
1190b57cec5SDimitry Andric DictScope D(W, "Header");
1208bcb0991SDimitry Andric uint64_t Offset = 0;
1210b57cec5SDimitry Andric
1220b57cec5SDimitry Andric auto Version = DE.getU8(&Offset);
1230b57cec5SDimitry Andric W.printNumber("version", Version);
1240b57cec5SDimitry Andric if (Version != 1)
1258bcb0991SDimitry Andric reportError(
1268bcb0991SDimitry Andric object::createError("only version 1 of .eh_frame_hdr is supported"),
127e8d8bef9SDimitry Andric ObjF.getFileName());
1280b57cec5SDimitry Andric
1290b57cec5SDimitry Andric uint64_t EHFramePtrEnc = DE.getU8(&Offset);
1300b57cec5SDimitry Andric W.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64 "\n", EHFramePtrEnc);
1310b57cec5SDimitry Andric if (EHFramePtrEnc != (dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4))
1328bcb0991SDimitry Andric reportError(object::createError("unexpected encoding eh_frame_ptr_enc"),
133e8d8bef9SDimitry Andric ObjF.getFileName());
1340b57cec5SDimitry Andric
1350b57cec5SDimitry Andric uint64_t FDECountEnc = DE.getU8(&Offset);
1360b57cec5SDimitry Andric W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc);
1370b57cec5SDimitry Andric if (FDECountEnc != dwarf::DW_EH_PE_udata4)
1388bcb0991SDimitry Andric reportError(object::createError("unexpected encoding fde_count_enc"),
139e8d8bef9SDimitry Andric ObjF.getFileName());
1400b57cec5SDimitry Andric
1410b57cec5SDimitry Andric uint64_t TableEnc = DE.getU8(&Offset);
1420b57cec5SDimitry Andric W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc);
1430b57cec5SDimitry Andric if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4))
1448bcb0991SDimitry Andric reportError(object::createError("unexpected encoding table_enc"),
145e8d8bef9SDimitry Andric ObjF.getFileName());
1460b57cec5SDimitry Andric
1470b57cec5SDimitry Andric auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4;
1480b57cec5SDimitry Andric W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr);
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric auto FDECount = DE.getUnsigned(&Offset, 4);
1510b57cec5SDimitry Andric W.printNumber("fde_count", FDECount);
1520b57cec5SDimitry Andric
1530b57cec5SDimitry Andric unsigned NumEntries = 0;
1540b57cec5SDimitry Andric uint64_t PrevPC = 0;
1555ffd83dbSDimitry Andric while (Offset + 8 <= EHFramePHdr->p_memsz && NumEntries < FDECount) {
1560b57cec5SDimitry Andric DictScope D(W, std::string("entry ") + std::to_string(NumEntries));
1570b57cec5SDimitry Andric
1580b57cec5SDimitry Andric auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
1590b57cec5SDimitry Andric W.startLine() << format("initial_location: 0x%" PRIx64 "\n", InitialPC);
1600b57cec5SDimitry Andric auto Address = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
1610b57cec5SDimitry Andric W.startLine() << format("address: 0x%" PRIx64 "\n", Address);
1620b57cec5SDimitry Andric
1630b57cec5SDimitry Andric if (InitialPC < PrevPC)
1648bcb0991SDimitry Andric reportError(object::createError("initial_location is out of order"),
165e8d8bef9SDimitry Andric ObjF.getFileName());
1660b57cec5SDimitry Andric
1670b57cec5SDimitry Andric PrevPC = InitialPC;
1680b57cec5SDimitry Andric ++NumEntries;
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric
1720b57cec5SDimitry Andric template <typename ELFT>
printEHFrame(const Elf_Shdr * EHFrameShdr)1735ffd83dbSDimitry Andric void PrinterContext<ELFT>::printEHFrame(const Elf_Shdr *EHFrameShdr) const {
1740b57cec5SDimitry Andric uint64_t Address = EHFrameShdr->sh_addr;
1750b57cec5SDimitry Andric uint64_t ShOffset = EHFrameShdr->sh_offset;
1760b57cec5SDimitry Andric W.startLine() << format(".eh_frame section at offset 0x%" PRIx64
1770b57cec5SDimitry Andric " address 0x%" PRIx64 ":\n",
1780b57cec5SDimitry Andric ShOffset, Address);
1790b57cec5SDimitry Andric W.indent();
1800b57cec5SDimitry Andric
1815ffd83dbSDimitry Andric Expected<ArrayRef<uint8_t>> DataOrErr =
182e8d8bef9SDimitry Andric ObjF.getELFFile().getSectionContents(*EHFrameShdr);
1835ffd83dbSDimitry Andric if (!DataOrErr)
184e8d8bef9SDimitry Andric reportError(DataOrErr.takeError(), ObjF.getFileName());
1850b57cec5SDimitry Andric
186e8d8bef9SDimitry Andric // Construct DWARFDataExtractor to handle relocations ("PC Begin" fields).
187349cc55cSDimitry Andric std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(
188349cc55cSDimitry Andric ObjF, DWARFContext::ProcessDebugRelocations::Process, nullptr);
189*0fca6ea1SDimitry Andric DWARFDataExtractor DE(
190*0fca6ea1SDimitry Andric DICtx->getDWARFObj(), DICtx->getDWARFObj().getEHFrameSection(),
191*0fca6ea1SDimitry Andric ELFT::Endianness == llvm::endianness::little, ELFT::Is64Bits ? 8 : 4);
192e8d8bef9SDimitry Andric DWARFDebugFrame EHFrame(Triple::ArchType(ObjF.getArch()), /*IsEH=*/true,
1930b57cec5SDimitry Andric /*EHFrameAddress=*/Address);
1945ffd83dbSDimitry Andric if (Error E = EHFrame.parse(DE))
195e8d8bef9SDimitry Andric reportError(std::move(E), ObjF.getFileName());
1960b57cec5SDimitry Andric
1975ffd83dbSDimitry Andric for (const dwarf::FrameEntry &Entry : EHFrame) {
198*0fca6ea1SDimitry Andric std::optional<uint64_t> InitialLocation;
1995ffd83dbSDimitry Andric if (const dwarf::CIE *CIE = dyn_cast<dwarf::CIE>(&Entry)) {
2000b57cec5SDimitry Andric W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n",
2015ffd83dbSDimitry Andric Address + CIE->getOffset(), CIE->getLength());
2020b57cec5SDimitry Andric W.indent();
2030b57cec5SDimitry Andric
2040b57cec5SDimitry Andric W.printNumber("version", CIE->getVersion());
2050b57cec5SDimitry Andric W.printString("augmentation", CIE->getAugmentationString());
2060b57cec5SDimitry Andric W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor());
2070b57cec5SDimitry Andric W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor());
2080b57cec5SDimitry Andric W.printNumber("return_address_register", CIE->getReturnAddressRegister());
2095ffd83dbSDimitry Andric } else {
2105ffd83dbSDimitry Andric const dwarf::FDE *FDE = cast<dwarf::FDE>(&Entry);
2110b57cec5SDimitry Andric W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64
2120b57cec5SDimitry Andric " cie=[0x%" PRIx64 "]\n",
2135ffd83dbSDimitry Andric Address + FDE->getOffset(), FDE->getLength(),
2140b57cec5SDimitry Andric Address + FDE->getLinkedCIE()->getOffset());
2150b57cec5SDimitry Andric W.indent();
2160b57cec5SDimitry Andric
217*0fca6ea1SDimitry Andric InitialLocation = FDE->getInitialLocation();
2180b57cec5SDimitry Andric W.startLine() << format("initial_location: 0x%" PRIx64 "\n",
219*0fca6ea1SDimitry Andric *InitialLocation);
2205ffd83dbSDimitry Andric W.startLine() << format(
2215ffd83dbSDimitry Andric "address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n",
2220b57cec5SDimitry Andric FDE->getAddressRange(),
2230b57cec5SDimitry Andric FDE->getInitialLocation() + FDE->getAddressRange());
2245ffd83dbSDimitry Andric }
2250b57cec5SDimitry Andric
2260b57cec5SDimitry Andric W.getOStream() << "\n";
2270b57cec5SDimitry Andric W.startLine() << "Program:\n";
2280b57cec5SDimitry Andric W.indent();
229bdd1243dSDimitry Andric auto DumpOpts = DIDumpOptions();
230bdd1243dSDimitry Andric DumpOpts.IsEH = true;
231*0fca6ea1SDimitry Andric Entry.cfis().dump(W.getOStream(), DumpOpts, W.getIndentLevel(),
232*0fca6ea1SDimitry Andric InitialLocation);
2330b57cec5SDimitry Andric W.unindent();
2340b57cec5SDimitry Andric W.unindent();
2350b57cec5SDimitry Andric W.getOStream() << "\n";
2360b57cec5SDimitry Andric }
2370b57cec5SDimitry Andric
2380b57cec5SDimitry Andric W.unindent();
2390b57cec5SDimitry Andric }
240e8d8bef9SDimitry Andric } // namespace DwarfCFIEH
241e8d8bef9SDimitry Andric } // namespace llvm
2420b57cec5SDimitry Andric
2430b57cec5SDimitry Andric #endif
244