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 "Error.h" 13 #include "llvm-readobj.h" 14 #include "llvm/ADT/STLExtras.h" 15 #include "llvm/BinaryFormat/Dwarf.h" 16 #include "llvm/Object/ELF.h" 17 #include "llvm/Object/ELFTypes.h" 18 #include "llvm/Object/ELFObjectFile.h" 19 #include "llvm/Support/Casting.h" 20 #include "llvm/Support/ScopedPrinter.h" 21 #include "llvm/Support/Debug.h" 22 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" 23 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" 24 #include "llvm/Support/Endian.h" 25 #include "llvm/Support/Format.h" 26 #include "llvm/Support/type_traits.h" 27 28 namespace llvm { 29 namespace DwarfCFIEH { 30 31 template <typename ELFT> 32 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 42 public: 43 PrinterContext(ScopedPrinter &W, const object::ELFObjectFile<ELFT> *ObjF) 44 : W(W), ObjF(ObjF) {} 45 46 void printUnwindInformation() const; 47 }; 48 49 template <class ELFT> 50 static const typename ELFT::Shdr * 51 findSectionByAddress(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 63 template <typename ELFT> 64 void 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 = 84 ObjF->getELFFile()->sections(); 85 if (!SectionsOrErr) 86 reportError(SectionsOrErr.takeError(), ObjF->getFileName()); 87 88 for (const Elf_Shdr &Shdr : *SectionsOrErr) { 89 Expected<StringRef> NameOrErr = Obj->getSectionName(&Shdr); 90 if (!NameOrErr) 91 reportError(NameOrErr.takeError(), ObjF->getFileName()); 92 if (*NameOrErr == ".eh_frame") 93 printEHFrame(&Shdr); 94 } 95 } 96 97 template <typename ELFT> 98 void PrinterContext<ELFT>::printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const { 99 DictScope L(W, "EHFrameHeader"); 100 uint64_t EHFrameHdrAddress = EHFramePHdr->p_vaddr; 101 W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress); 102 W.startLine() << format("Offset: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_offset); 103 W.startLine() << format("Size: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_memsz); 104 105 const object::ELFFile<ELFT> *Obj = ObjF->getELFFile(); 106 if (const Elf_Shdr *EHFrameHdr = 107 findSectionByAddress(ObjF, EHFramePHdr->p_vaddr)) { 108 Expected<StringRef> NameOrErr = Obj->getSectionName(EHFrameHdr); 109 if (!NameOrErr) 110 reportError(NameOrErr.takeError(), ObjF->getFileName()); 111 W.printString("Corresponding Section", *NameOrErr); 112 } 113 114 Expected<ArrayRef<uint8_t>> Content = Obj->getSegmentContents(EHFramePHdr); 115 if (!Content) 116 reportError(Content.takeError(), ObjF->getFileName()); 117 118 DataExtractor DE(*Content, 119 ELFT::TargetEndianness == support::endianness::little, 120 ELFT::Is64Bits ? 8 : 4); 121 122 DictScope D(W, "Header"); 123 uint64_t Offset = 0; 124 125 auto Version = DE.getU8(&Offset); 126 W.printNumber("version", Version); 127 if (Version != 1) 128 reportError( 129 object::createError("only version 1 of .eh_frame_hdr is supported"), 130 ObjF->getFileName()); 131 132 uint64_t EHFramePtrEnc = DE.getU8(&Offset); 133 W.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64 "\n", EHFramePtrEnc); 134 if (EHFramePtrEnc != (dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4)) 135 reportError(object::createError("unexpected encoding eh_frame_ptr_enc"), 136 ObjF->getFileName()); 137 138 uint64_t FDECountEnc = DE.getU8(&Offset); 139 W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc); 140 if (FDECountEnc != dwarf::DW_EH_PE_udata4) 141 reportError(object::createError("unexpected encoding fde_count_enc"), 142 ObjF->getFileName()); 143 144 uint64_t TableEnc = DE.getU8(&Offset); 145 W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc); 146 if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4)) 147 reportError(object::createError("unexpected encoding table_enc"), 148 ObjF->getFileName()); 149 150 auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4; 151 W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr); 152 153 auto FDECount = DE.getUnsigned(&Offset, 4); 154 W.printNumber("fde_count", FDECount); 155 156 unsigned NumEntries = 0; 157 uint64_t PrevPC = 0; 158 while (Offset + 8 <= EHFramePHdr->p_memsz && NumEntries < FDECount) { 159 DictScope D(W, std::string("entry ") + std::to_string(NumEntries)); 160 161 auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress; 162 W.startLine() << format("initial_location: 0x%" PRIx64 "\n", InitialPC); 163 auto Address = DE.getSigned(&Offset, 4) + EHFrameHdrAddress; 164 W.startLine() << format("address: 0x%" PRIx64 "\n", Address); 165 166 if (InitialPC < PrevPC) 167 reportError(object::createError("initial_location is out of order"), 168 ObjF->getFileName()); 169 170 PrevPC = InitialPC; 171 ++NumEntries; 172 } 173 } 174 175 template <typename ELFT> 176 void PrinterContext<ELFT>::printEHFrame(const Elf_Shdr *EHFrameShdr) const { 177 uint64_t Address = EHFrameShdr->sh_addr; 178 uint64_t ShOffset = EHFrameShdr->sh_offset; 179 W.startLine() << format(".eh_frame section at offset 0x%" PRIx64 180 " address 0x%" PRIx64 ":\n", 181 ShOffset, Address); 182 W.indent(); 183 184 Expected<ArrayRef<uint8_t>> DataOrErr = 185 ObjF->getELFFile()->getSectionContents(EHFrameShdr); 186 if (!DataOrErr) 187 reportError(DataOrErr.takeError(), ObjF->getFileName()); 188 189 DWARFDataExtractor DE(*DataOrErr, 190 ELFT::TargetEndianness == support::endianness::little, 191 ELFT::Is64Bits ? 8 : 4); 192 DWARFDebugFrame EHFrame(Triple::ArchType(ObjF->getArch()), /*IsEH=*/true, 193 /*EHFrameAddress=*/Address); 194 if (Error E = EHFrame.parse(DE)) 195 reportError(std::move(E), ObjF->getFileName()); 196 197 for (const dwarf::FrameEntry &Entry : EHFrame) { 198 if (const dwarf::CIE *CIE = dyn_cast<dwarf::CIE>(&Entry)) { 199 W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n", 200 Address + CIE->getOffset(), CIE->getLength()); 201 W.indent(); 202 203 W.printNumber("version", CIE->getVersion()); 204 W.printString("augmentation", CIE->getAugmentationString()); 205 W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor()); 206 W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor()); 207 W.printNumber("return_address_register", CIE->getReturnAddressRegister()); 208 } else { 209 const dwarf::FDE *FDE = cast<dwarf::FDE>(&Entry); 210 W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64 211 " cie=[0x%" PRIx64 "]\n", 212 Address + FDE->getOffset(), FDE->getLength(), 213 Address + FDE->getLinkedCIE()->getOffset()); 214 W.indent(); 215 216 W.startLine() << format("initial_location: 0x%" PRIx64 "\n", 217 FDE->getInitialLocation()); 218 W.startLine() << format( 219 "address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n", 220 FDE->getAddressRange(), 221 FDE->getInitialLocation() + FDE->getAddressRange()); 222 } 223 224 W.getOStream() << "\n"; 225 W.startLine() << "Program:\n"; 226 W.indent(); 227 Entry.cfis().dump(W.getOStream(), nullptr, W.getIndentLevel()); 228 W.unindent(); 229 W.unindent(); 230 W.getOStream() << "\n"; 231 } 232 233 W.unindent(); 234 } 235 } 236 } 237 238 #endif 239