Path: blob/main/contrib/llvm-project/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
35230 views
//===--- DwarfCFIEHPrinter.h - DWARF-based Unwind Information Printer -----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H9#define LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H1011#include "llvm-readobj.h"12#include "llvm/ADT/STLExtras.h"13#include "llvm/BinaryFormat/Dwarf.h"14#include "llvm/DebugInfo/DWARF/DWARFContext.h"15#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"16#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"17#include "llvm/Object/ELF.h"18#include "llvm/Object/ELFObjectFile.h"19#include "llvm/Object/ELFTypes.h"20#include "llvm/Support/Casting.h"21#include "llvm/Support/Debug.h"22#include "llvm/Support/Endian.h"23#include "llvm/Support/Format.h"24#include "llvm/Support/ScopedPrinter.h"25#include "llvm/Support/type_traits.h"2627namespace llvm {28namespace DwarfCFIEH {2930template <typename ELFT> class PrinterContext {31using Elf_Shdr = typename ELFT::Shdr;32using Elf_Phdr = typename ELFT::Phdr;3334ScopedPrinter &W;35const object::ELFObjectFile<ELFT> &ObjF;3637void printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const;38void printEHFrame(const Elf_Shdr *EHFrameShdr) const;3940public:41PrinterContext(ScopedPrinter &W, const object::ELFObjectFile<ELFT> &ObjF)42: W(W), ObjF(ObjF) {}4344void printUnwindInformation() const;45};4647template <class ELFT>48static const typename ELFT::Shdr *49findSectionByAddress(const object::ELFObjectFile<ELFT> &ObjF, uint64_t Addr) {50Expected<typename ELFT::ShdrRange> SectionsOrErr =51ObjF.getELFFile().sections();52if (!SectionsOrErr)53reportError(SectionsOrErr.takeError(), ObjF.getFileName());5455for (const typename ELFT::Shdr &Shdr : *SectionsOrErr)56if (Shdr.sh_addr == Addr)57return &Shdr;58return nullptr;59}6061template <typename ELFT>62void PrinterContext<ELFT>::printUnwindInformation() const {63const object::ELFFile<ELFT> &Obj = ObjF.getELFFile();6465Expected<typename ELFT::PhdrRange> PhdrsOrErr = Obj.program_headers();66if (!PhdrsOrErr)67reportError(PhdrsOrErr.takeError(), ObjF.getFileName());6869for (const Elf_Phdr &Phdr : *PhdrsOrErr) {70if (Phdr.p_type != ELF::PT_GNU_EH_FRAME)71continue;7273if (Phdr.p_memsz != Phdr.p_filesz)74reportError(object::createError(75"p_memsz does not match p_filesz for GNU_EH_FRAME"),76ObjF.getFileName());77printEHFrameHdr(&Phdr);78break;79}8081Expected<typename ELFT::ShdrRange> SectionsOrErr = Obj.sections();82if (!SectionsOrErr)83reportError(SectionsOrErr.takeError(), ObjF.getFileName());8485for (const Elf_Shdr &Shdr : *SectionsOrErr) {86Expected<StringRef> NameOrErr = Obj.getSectionName(Shdr);87if (!NameOrErr)88reportError(NameOrErr.takeError(), ObjF.getFileName());89if (*NameOrErr == ".eh_frame")90printEHFrame(&Shdr);91}92}9394template <typename ELFT>95void PrinterContext<ELFT>::printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const {96DictScope L(W, "EHFrameHeader");97uint64_t EHFrameHdrAddress = EHFramePHdr->p_vaddr;98W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress);99W.startLine() << format("Offset: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_offset);100W.startLine() << format("Size: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_memsz);101102const object::ELFFile<ELFT> &Obj = ObjF.getELFFile();103if (const Elf_Shdr *EHFrameHdr =104findSectionByAddress(ObjF, EHFramePHdr->p_vaddr)) {105Expected<StringRef> NameOrErr = Obj.getSectionName(*EHFrameHdr);106if (!NameOrErr)107reportError(NameOrErr.takeError(), ObjF.getFileName());108W.printString("Corresponding Section", *NameOrErr);109}110111Expected<ArrayRef<uint8_t>> Content = Obj.getSegmentContents(*EHFramePHdr);112if (!Content)113reportError(Content.takeError(), ObjF.getFileName());114115DataExtractor DE(*Content, ELFT::Endianness == llvm::endianness::little,116ELFT::Is64Bits ? 8 : 4);117118DictScope D(W, "Header");119uint64_t Offset = 0;120121auto Version = DE.getU8(&Offset);122W.printNumber("version", Version);123if (Version != 1)124reportError(125object::createError("only version 1 of .eh_frame_hdr is supported"),126ObjF.getFileName());127128uint64_t EHFramePtrEnc = DE.getU8(&Offset);129W.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64 "\n", EHFramePtrEnc);130if (EHFramePtrEnc != (dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4))131reportError(object::createError("unexpected encoding eh_frame_ptr_enc"),132ObjF.getFileName());133134uint64_t FDECountEnc = DE.getU8(&Offset);135W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc);136if (FDECountEnc != dwarf::DW_EH_PE_udata4)137reportError(object::createError("unexpected encoding fde_count_enc"),138ObjF.getFileName());139140uint64_t TableEnc = DE.getU8(&Offset);141W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc);142if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4))143reportError(object::createError("unexpected encoding table_enc"),144ObjF.getFileName());145146auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4;147W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr);148149auto FDECount = DE.getUnsigned(&Offset, 4);150W.printNumber("fde_count", FDECount);151152unsigned NumEntries = 0;153uint64_t PrevPC = 0;154while (Offset + 8 <= EHFramePHdr->p_memsz && NumEntries < FDECount) {155DictScope D(W, std::string("entry ") + std::to_string(NumEntries));156157auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;158W.startLine() << format("initial_location: 0x%" PRIx64 "\n", InitialPC);159auto Address = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;160W.startLine() << format("address: 0x%" PRIx64 "\n", Address);161162if (InitialPC < PrevPC)163reportError(object::createError("initial_location is out of order"),164ObjF.getFileName());165166PrevPC = InitialPC;167++NumEntries;168}169}170171template <typename ELFT>172void PrinterContext<ELFT>::printEHFrame(const Elf_Shdr *EHFrameShdr) const {173uint64_t Address = EHFrameShdr->sh_addr;174uint64_t ShOffset = EHFrameShdr->sh_offset;175W.startLine() << format(".eh_frame section at offset 0x%" PRIx64176" address 0x%" PRIx64 ":\n",177ShOffset, Address);178W.indent();179180Expected<ArrayRef<uint8_t>> DataOrErr =181ObjF.getELFFile().getSectionContents(*EHFrameShdr);182if (!DataOrErr)183reportError(DataOrErr.takeError(), ObjF.getFileName());184185// Construct DWARFDataExtractor to handle relocations ("PC Begin" fields).186std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(187ObjF, DWARFContext::ProcessDebugRelocations::Process, nullptr);188DWARFDataExtractor DE(189DICtx->getDWARFObj(), DICtx->getDWARFObj().getEHFrameSection(),190ELFT::Endianness == llvm::endianness::little, ELFT::Is64Bits ? 8 : 4);191DWARFDebugFrame EHFrame(Triple::ArchType(ObjF.getArch()), /*IsEH=*/true,192/*EHFrameAddress=*/Address);193if (Error E = EHFrame.parse(DE))194reportError(std::move(E), ObjF.getFileName());195196for (const dwarf::FrameEntry &Entry : EHFrame) {197std::optional<uint64_t> InitialLocation;198if (const dwarf::CIE *CIE = dyn_cast<dwarf::CIE>(&Entry)) {199W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n",200Address + CIE->getOffset(), CIE->getLength());201W.indent();202203W.printNumber("version", CIE->getVersion());204W.printString("augmentation", CIE->getAugmentationString());205W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor());206W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor());207W.printNumber("return_address_register", CIE->getReturnAddressRegister());208} else {209const dwarf::FDE *FDE = cast<dwarf::FDE>(&Entry);210W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64211" cie=[0x%" PRIx64 "]\n",212Address + FDE->getOffset(), FDE->getLength(),213Address + FDE->getLinkedCIE()->getOffset());214W.indent();215216InitialLocation = FDE->getInitialLocation();217W.startLine() << format("initial_location: 0x%" PRIx64 "\n",218*InitialLocation);219W.startLine() << format(220"address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n",221FDE->getAddressRange(),222FDE->getInitialLocation() + FDE->getAddressRange());223}224225W.getOStream() << "\n";226W.startLine() << "Program:\n";227W.indent();228auto DumpOpts = DIDumpOptions();229DumpOpts.IsEH = true;230Entry.cfis().dump(W.getOStream(), DumpOpts, W.getIndentLevel(),231InitialLocation);232W.unindent();233W.unindent();234W.getOStream() << "\n";235}236237W.unindent();238}239} // namespace DwarfCFIEH240} // namespace llvm241242#endif243244245