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