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 ScopedPrinter &W; 34 const object::ELFObjectFile<ELFT> *ObjF; 35 36 void printEHFrameHdr(uint64_t Offset, uint64_t Address, uint64_t Size) const; 37 38 void printEHFrame(const typename ELFT::Shdr *EHFrameShdr) const; 39 40 public: 41 PrinterContext(ScopedPrinter &W, const object::ELFObjectFile<ELFT> *ObjF) 42 : W(W), ObjF(ObjF) {} 43 44 void printUnwindInformation() const; 45 }; 46 47 template <class ELFT> 48 static const typename object::ELFObjectFile<ELFT>::Elf_Shdr * 49 findSectionByAddress(const object::ELFObjectFile<ELFT> *ObjF, uint64_t Addr) { 50 auto Sections = ObjF->getELFFile()->sections(); 51 if (Error E = Sections.takeError()) 52 reportError(std::move(E), ObjF->getFileName()); 53 54 for (const auto &Shdr : *Sections) 55 if (Shdr.sh_addr == Addr) 56 return &Shdr; 57 return nullptr; 58 } 59 60 template <typename ELFT> 61 void PrinterContext<ELFT>::printUnwindInformation() const { 62 const object::ELFFile<ELFT> *Obj = ObjF->getELFFile(); 63 const typename ELFT::Phdr *EHFramePhdr = nullptr; 64 65 auto PHs = Obj->program_headers(); 66 if (Error E = PHs.takeError()) 67 reportError(std::move(E), ObjF->getFileName()); 68 69 for (const auto &Phdr : *PHs) { 70 if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) { 71 EHFramePhdr = &Phdr; 72 if (Phdr.p_memsz != Phdr.p_filesz) 73 reportError(object::createError( 74 "p_memsz does not match p_filesz for GNU_EH_FRAME"), 75 ObjF->getFileName()); 76 break; 77 } 78 } 79 80 if (EHFramePhdr) 81 printEHFrameHdr(EHFramePhdr->p_offset, EHFramePhdr->p_vaddr, 82 EHFramePhdr->p_memsz); 83 84 auto Sections = Obj->sections(); 85 if (Error E = Sections.takeError()) 86 reportError(std::move(E), ObjF->getFileName()); 87 88 for (const auto &Shdr : *Sections) { 89 auto SectionName = Obj->getSectionName(&Shdr); 90 if (Error E = SectionName.takeError()) 91 reportError(std::move(E), ObjF->getFileName()); 92 93 if (*SectionName == ".eh_frame") 94 printEHFrame(&Shdr); 95 } 96 } 97 98 template <typename ELFT> 99 void PrinterContext<ELFT>::printEHFrameHdr(uint64_t EHFrameHdrOffset, 100 uint64_t EHFrameHdrAddress, 101 uint64_t EHFrameHdrSize) const { 102 DictScope L(W, "EHFrameHeader"); 103 W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress); 104 W.startLine() << format("Offset: 0x%" PRIx64 "\n", EHFrameHdrOffset); 105 W.startLine() << format("Size: 0x%" PRIx64 "\n", EHFrameHdrSize); 106 107 const object::ELFFile<ELFT> *Obj = ObjF->getELFFile(); 108 const auto *EHFrameHdrShdr = findSectionByAddress(ObjF, EHFrameHdrAddress); 109 if (EHFrameHdrShdr) { 110 auto SectionName = Obj->getSectionName(EHFrameHdrShdr); 111 if (Error E = SectionName.takeError()) 112 reportError(std::move(E), ObjF->getFileName()); 113 114 W.printString("Corresponding Section", *SectionName); 115 } 116 117 DataExtractor DE(makeArrayRef(Obj->base() + EHFrameHdrOffset, EHFrameHdrSize), 118 ELFT::TargetEndianness == support::endianness::little, 119 ELFT::Is64Bits ? 8 : 4); 120 121 DictScope D(W, "Header"); 122 uint64_t Offset = 0; 123 124 auto Version = DE.getU8(&Offset); 125 W.printNumber("version", Version); 126 if (Version != 1) 127 reportError( 128 object::createError("only version 1 of .eh_frame_hdr is supported"), 129 ObjF->getFileName()); 130 131 uint64_t EHFramePtrEnc = DE.getU8(&Offset); 132 W.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64 "\n", EHFramePtrEnc); 133 if (EHFramePtrEnc != (dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4)) 134 reportError(object::createError("unexpected encoding eh_frame_ptr_enc"), 135 ObjF->getFileName()); 136 137 uint64_t FDECountEnc = DE.getU8(&Offset); 138 W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc); 139 if (FDECountEnc != dwarf::DW_EH_PE_udata4) 140 reportError(object::createError("unexpected encoding fde_count_enc"), 141 ObjF->getFileName()); 142 143 uint64_t TableEnc = DE.getU8(&Offset); 144 W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc); 145 if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4)) 146 reportError(object::createError("unexpected encoding table_enc"), 147 ObjF->getFileName()); 148 149 auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4; 150 W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr); 151 152 auto FDECount = DE.getUnsigned(&Offset, 4); 153 W.printNumber("fde_count", FDECount); 154 155 unsigned NumEntries = 0; 156 uint64_t PrevPC = 0; 157 while (Offset + 8 <= EHFrameHdrSize && NumEntries < FDECount) { 158 DictScope D(W, std::string("entry ") + std::to_string(NumEntries)); 159 160 auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress; 161 W.startLine() << format("initial_location: 0x%" PRIx64 "\n", InitialPC); 162 auto Address = DE.getSigned(&Offset, 4) + EHFrameHdrAddress; 163 W.startLine() << format("address: 0x%" PRIx64 "\n", Address); 164 165 if (InitialPC < PrevPC) 166 reportError(object::createError("initial_location is out of order"), 167 ObjF->getFileName()); 168 169 PrevPC = InitialPC; 170 ++NumEntries; 171 } 172 } 173 174 template <typename ELFT> 175 void PrinterContext<ELFT>::printEHFrame( 176 const typename ELFT::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 const object::ELFFile<ELFT> *Obj = ObjF->getELFFile(); 185 auto Result = Obj->getSectionContents(EHFrameShdr); 186 if (Error E = Result.takeError()) 187 reportError(std::move(E), ObjF->getFileName()); 188 189 auto Contents = Result.get(); 190 DWARFDataExtractor DE( 191 StringRef(reinterpret_cast<const char *>(Contents.data()), 192 Contents.size()), 193 ELFT::TargetEndianness == support::endianness::little, 194 ELFT::Is64Bits ? 8 : 4); 195 DWARFDebugFrame EHFrame(Triple::ArchType(ObjF->getArch()), /*IsEH=*/true, 196 /*EHFrameAddress=*/Address); 197 EHFrame.parse(DE); 198 199 for (const auto &Entry : EHFrame) { 200 if (const auto *CIE = dyn_cast<dwarf::CIE>(&Entry)) { 201 W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n", 202 Address + CIE->getOffset(), 203 CIE->getLength()); 204 W.indent(); 205 206 W.printNumber("version", CIE->getVersion()); 207 W.printString("augmentation", CIE->getAugmentationString()); 208 W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor()); 209 W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor()); 210 W.printNumber("return_address_register", CIE->getReturnAddressRegister()); 211 212 W.getOStream() << "\n"; 213 W.startLine() << "Program:\n"; 214 W.indent(); 215 CIE->cfis().dump(W.getOStream(), nullptr, W.getIndentLevel()); 216 W.unindent(); 217 218 W.unindent(); 219 W.getOStream() << "\n"; 220 221 } else if (const auto *FDE = dyn_cast<dwarf::FDE>(&Entry)) { 222 W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64 223 " cie=[0x%" PRIx64 "]\n", 224 Address + FDE->getOffset(), 225 FDE->getLength(), 226 Address + FDE->getLinkedCIE()->getOffset()); 227 W.indent(); 228 229 W.startLine() << format("initial_location: 0x%" PRIx64 "\n", 230 FDE->getInitialLocation()); 231 W.startLine() 232 << format("address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n", 233 FDE->getAddressRange(), 234 FDE->getInitialLocation() + FDE->getAddressRange()); 235 236 W.getOStream() << "\n"; 237 W.startLine() << "Program:\n"; 238 W.indent(); 239 FDE->cfis().dump(W.getOStream(), nullptr, W.getIndentLevel()); 240 W.unindent(); 241 242 W.unindent(); 243 W.getOStream() << "\n"; 244 } else { 245 llvm_unreachable("unexpected DWARF frame kind"); 246 } 247 } 248 249 W.unindent(); 250 } 251 252 } 253 } 254 255 #endif 256