Home | History | Annotate | Line # | Download | only in llvm-readobj
      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-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 
      9 #ifndef LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H
     10 #define LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H
     11 
     12 #include "llvm-readobj.h"
     13 #include "llvm/ADT/STLExtras.h"
     14 #include "llvm/BinaryFormat/Dwarf.h"
     15 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
     16 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
     17 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
     18 #include "llvm/Object/ELF.h"
     19 #include "llvm/Object/ELFObjectFile.h"
     20 #include "llvm/Object/ELFTypes.h"
     21 #include "llvm/Support/Casting.h"
     22 #include "llvm/Support/Debug.h"
     23 #include "llvm/Support/Endian.h"
     24 #include "llvm/Support/Format.h"
     25 #include "llvm/Support/ScopedPrinter.h"
     26 #include "llvm/Support/type_traits.h"
     27 
     28 namespace llvm {
     29 namespace DwarfCFIEH {
     30 
     31 template <typename ELFT> class PrinterContext {
     32   using Elf_Shdr = typename ELFT::Shdr;
     33   using Elf_Phdr = typename ELFT::Phdr;
     34 
     35   ScopedPrinter &W;
     36   const object::ELFObjectFile<ELFT> &ObjF;
     37 
     38   void printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const;
     39   void printEHFrame(const Elf_Shdr *EHFrameShdr) const;
     40 
     41 public:
     42   PrinterContext(ScopedPrinter &W, const object::ELFObjectFile<ELFT> &ObjF)
     43       : W(W), ObjF(ObjF) {}
     44 
     45   void printUnwindInformation() const;
     46 };
     47 
     48 template <class ELFT>
     49 static const typename ELFT::Shdr *
     50 findSectionByAddress(const object::ELFObjectFile<ELFT> &ObjF, uint64_t Addr) {
     51   Expected<typename ELFT::ShdrRange> SectionsOrErr =
     52       ObjF.getELFFile().sections();
     53   if (!SectionsOrErr)
     54     reportError(SectionsOrErr.takeError(), ObjF.getFileName());
     55 
     56   for (const typename ELFT::Shdr &Shdr : *SectionsOrErr)
     57     if (Shdr.sh_addr == Addr)
     58       return &Shdr;
     59   return nullptr;
     60 }
     61 
     62 template <typename ELFT>
     63 void PrinterContext<ELFT>::printUnwindInformation() const {
     64   const object::ELFFile<ELFT> &Obj = ObjF.getELFFile();
     65 
     66   Expected<typename ELFT::PhdrRange> PhdrsOrErr = Obj.program_headers();
     67   if (!PhdrsOrErr)
     68     reportError(PhdrsOrErr.takeError(), ObjF.getFileName());
     69 
     70   for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
     71     if (Phdr.p_type != ELF::PT_GNU_EH_FRAME)
     72       continue;
     73 
     74     if (Phdr.p_memsz != Phdr.p_filesz)
     75       reportError(object::createError(
     76                       "p_memsz does not match p_filesz for GNU_EH_FRAME"),
     77                   ObjF.getFileName());
     78     printEHFrameHdr(&Phdr);
     79     break;
     80   }
     81 
     82   Expected<typename ELFT::ShdrRange> SectionsOrErr = Obj.sections();
     83   if (!SectionsOrErr)
     84     reportError(SectionsOrErr.takeError(), ObjF.getFileName());
     85 
     86   for (const Elf_Shdr &Shdr : *SectionsOrErr) {
     87     Expected<StringRef> NameOrErr = Obj.getSectionName(Shdr);
     88     if (!NameOrErr)
     89       reportError(NameOrErr.takeError(), ObjF.getFileName());
     90     if (*NameOrErr == ".eh_frame")
     91       printEHFrame(&Shdr);
     92   }
     93 }
     94 
     95 template <typename ELFT>
     96 void PrinterContext<ELFT>::printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const {
     97   DictScope L(W, "EHFrameHeader");
     98   uint64_t EHFrameHdrAddress = EHFramePHdr->p_vaddr;
     99   W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress);
    100   W.startLine() << format("Offset: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_offset);
    101   W.startLine() << format("Size: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_memsz);
    102 
    103   const object::ELFFile<ELFT> &Obj = ObjF.getELFFile();
    104   if (const Elf_Shdr *EHFrameHdr =
    105           findSectionByAddress(ObjF, EHFramePHdr->p_vaddr)) {
    106     Expected<StringRef> NameOrErr = Obj.getSectionName(*EHFrameHdr);
    107     if (!NameOrErr)
    108       reportError(NameOrErr.takeError(), ObjF.getFileName());
    109     W.printString("Corresponding Section", *NameOrErr);
    110   }
    111 
    112   Expected<ArrayRef<uint8_t>> Content = Obj.getSegmentContents(*EHFramePHdr);
    113   if (!Content)
    114     reportError(Content.takeError(), ObjF.getFileName());
    115 
    116   DataExtractor DE(*Content,
    117                    ELFT::TargetEndianness == support::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 
    173 template <typename ELFT>
    174 void 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%" PRIx64
    178                           " 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(ObjF, nullptr);
    189   DWARFDataExtractor DE(DICtx->getDWARFObj(),
    190                         DICtx->getDWARFObj().getEHFrameSection(),
    191                         ELFT::TargetEndianness == support::endianness::little,
    192                         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     if (const dwarf::CIE *CIE = dyn_cast<dwarf::CIE>(&Entry)) {
    200       W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n",
    201                               Address + CIE->getOffset(), CIE->getLength());
    202       W.indent();
    203 
    204       W.printNumber("version", CIE->getVersion());
    205       W.printString("augmentation", CIE->getAugmentationString());
    206       W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor());
    207       W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor());
    208       W.printNumber("return_address_register", CIE->getReturnAddressRegister());
    209     } else {
    210       const dwarf::FDE *FDE = cast<dwarf::FDE>(&Entry);
    211       W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64
    212                               " cie=[0x%" PRIx64 "]\n",
    213                               Address + FDE->getOffset(), FDE->getLength(),
    214                               Address + FDE->getLinkedCIE()->getOffset());
    215       W.indent();
    216 
    217       W.startLine() << format("initial_location: 0x%" PRIx64 "\n",
    218                               FDE->getInitialLocation());
    219       W.startLine() << format(
    220           "address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n",
    221           FDE->getAddressRange(),
    222           FDE->getInitialLocation() + FDE->getAddressRange());
    223     }
    224 
    225     W.getOStream() << "\n";
    226     W.startLine() << "Program:\n";
    227     W.indent();
    228     Entry.cfis().dump(W.getOStream(), DIDumpOptions(), nullptr,
    229                       W.getIndentLevel());
    230     W.unindent();
    231     W.unindent();
    232     W.getOStream() << "\n";
    233   }
    234 
    235   W.unindent();
    236 }
    237 } // namespace DwarfCFIEH
    238 } // namespace llvm
    239 
    240 #endif
    241