| Rafael Auler | 86fb7bf | 2018-03-08 00:46:53 +0000 | [diff] [blame] | 1 | //===--- DwarfCFIEHPrinter.h - DWARF-based Unwind Information Printer -----===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 |  | 
|  | 10 | #ifndef LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H | 
|  | 11 | #define LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H | 
|  | 12 |  | 
|  | 13 | #include "Error.h" | 
| Benjamin Kramer | 7bbcd1d | 2018-03-12 15:02:59 +0000 | [diff] [blame] | 14 | #include "llvm-readobj.h" | 
| Rafael Auler | 86fb7bf | 2018-03-08 00:46:53 +0000 | [diff] [blame] | 15 | #include "llvm/ADT/STLExtras.h" | 
|  | 16 | #include "llvm/BinaryFormat/Dwarf.h" | 
|  | 17 | #include "llvm/Object/ELF.h" | 
|  | 18 | #include "llvm/Object/ELFTypes.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; | 
| Luke Cheeseman | 8e5676b | 2018-09-27 16:47:30 +0000 | [diff] [blame] | 34 | const object::ELFFile<ELFT> *Obj; | 
| Rafael Auler | 86fb7bf | 2018-03-08 00:46:53 +0000 | [diff] [blame] | 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: | 
| Luke Cheeseman | 8e5676b | 2018-09-27 16:47:30 +0000 | [diff] [blame] | 41 | PrinterContext(ScopedPrinter &W, const object::ELFFile<ELFT> *Obj) | 
|  | 42 | : W(W), Obj(Obj) {} | 
| Rafael Auler | 86fb7bf | 2018-03-08 00:46:53 +0000 | [diff] [blame] | 43 |  | 
|  | 44 | void printUnwindInformation() const; | 
|  | 45 | }; | 
|  | 46 |  | 
|  | 47 | template <class ELFO> | 
|  | 48 | static const typename ELFO::Elf_Shdr *findSectionByAddress(const ELFO *Obj, | 
|  | 49 | uint64_t Addr) { | 
|  | 50 | auto Sections = Obj->sections(); | 
|  | 51 | if (Error E = Sections.takeError()) | 
|  | 52 | reportError(toString(std::move(E))); | 
|  | 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 typename ELFT::Phdr *EHFramePhdr = nullptr; | 
|  | 63 |  | 
|  | 64 | auto PHs = Obj->program_headers(); | 
|  | 65 | if (Error E = PHs.takeError()) | 
|  | 66 | reportError(toString(std::move(E))); | 
|  | 67 |  | 
|  | 68 | for (const auto &Phdr : *PHs) { | 
|  | 69 | if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) { | 
|  | 70 | EHFramePhdr = &Phdr; | 
|  | 71 | if (Phdr.p_memsz != Phdr.p_filesz) | 
|  | 72 | reportError("p_memsz does not match p_filesz for GNU_EH_FRAME"); | 
|  | 73 | break; | 
|  | 74 | } | 
|  | 75 | } | 
|  | 76 |  | 
|  | 77 | if (EHFramePhdr) | 
|  | 78 | printEHFrameHdr(EHFramePhdr->p_offset, EHFramePhdr->p_vaddr, | 
|  | 79 | EHFramePhdr->p_memsz); | 
|  | 80 |  | 
|  | 81 | auto Sections = Obj->sections(); | 
|  | 82 | if (Error E = Sections.takeError()) | 
|  | 83 | reportError(toString(std::move(E))); | 
|  | 84 |  | 
|  | 85 | for (const auto &Shdr : *Sections) { | 
|  | 86 | auto SectionName = Obj->getSectionName(&Shdr); | 
|  | 87 | if (Error E = SectionName.takeError()) | 
|  | 88 | reportError(toString(std::move(E))); | 
|  | 89 |  | 
|  | 90 | if (*SectionName == ".eh_frame") | 
|  | 91 | printEHFrame(&Shdr); | 
|  | 92 | } | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | template <typename ELFT> | 
|  | 96 | void PrinterContext<ELFT>::printEHFrameHdr(uint64_t EHFrameHdrOffset, | 
|  | 97 | uint64_t EHFrameHdrAddress, | 
|  | 98 | uint64_t EHFrameHdrSize) const { | 
|  | 99 | ListScope L(W, "EH_FRAME Header"); | 
|  | 100 | W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress); | 
|  | 101 | W.startLine() << format("Offset: 0x%" PRIx64 "\n", EHFrameHdrOffset); | 
|  | 102 | W.startLine() << format("Size: 0x%" PRIx64 "\n", EHFrameHdrSize); | 
|  | 103 |  | 
|  | 104 | const auto *EHFrameHdrShdr = findSectionByAddress(Obj, EHFrameHdrAddress); | 
|  | 105 | if (EHFrameHdrShdr) { | 
|  | 106 | auto SectionName = Obj->getSectionName(EHFrameHdrShdr); | 
|  | 107 | if (Error E = SectionName.takeError()) | 
|  | 108 | reportError(toString(std::move(E))); | 
|  | 109 |  | 
|  | 110 | W.printString("Corresponding Section", *SectionName); | 
|  | 111 | } | 
|  | 112 |  | 
|  | 113 | DataExtractor DE( | 
|  | 114 | StringRef(reinterpret_cast<const char *>(Obj->base()) + EHFrameHdrOffset, | 
|  | 115 | EHFrameHdrSize), | 
|  | 116 | ELFT::TargetEndianness == support::endianness::little, | 
|  | 117 | ELFT::Is64Bits ? 8 : 4); | 
|  | 118 |  | 
|  | 119 | DictScope D(W, "Header"); | 
|  | 120 | uint32_t Offset = 0; | 
|  | 121 |  | 
|  | 122 | auto Version = DE.getU8(&Offset); | 
|  | 123 | W.printNumber("version", Version); | 
|  | 124 | if (Version != 1) | 
|  | 125 | reportError("only version 1 of .eh_frame_hdr is supported"); | 
|  | 126 |  | 
|  | 127 | uint64_t EHFramePtrEnc = DE.getU8(&Offset); | 
|  | 128 | W.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64 "\n", EHFramePtrEnc); | 
|  | 129 | if (EHFramePtrEnc != (dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4)) | 
|  | 130 | reportError("unexpected encoding eh_frame_ptr_enc"); | 
|  | 131 |  | 
|  | 132 | uint64_t FDECountEnc = DE.getU8(&Offset); | 
|  | 133 | W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc); | 
|  | 134 | if (FDECountEnc != dwarf::DW_EH_PE_udata4) | 
|  | 135 | reportError("unexpected encoding fde_count_enc"); | 
|  | 136 |  | 
|  | 137 | uint64_t TableEnc = DE.getU8(&Offset); | 
|  | 138 | W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc); | 
|  | 139 | if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4)) | 
|  | 140 | reportError("unexpected encoding table_enc"); | 
|  | 141 |  | 
|  | 142 | auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4; | 
|  | 143 | W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr); | 
|  | 144 |  | 
|  | 145 | auto FDECount = DE.getUnsigned(&Offset, 4); | 
|  | 146 | W.printNumber("fde_count", FDECount); | 
|  | 147 |  | 
|  | 148 | unsigned NumEntries = 0; | 
|  | 149 | uint64_t PrevPC = 0; | 
|  | 150 | while (Offset + 8 <= EHFrameHdrSize && NumEntries < FDECount) { | 
|  | 151 | DictScope D(W, std::string("entry ")  + std::to_string(NumEntries)); | 
|  | 152 |  | 
|  | 153 | auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress; | 
|  | 154 | W.startLine() << format("initial_location: 0x%" PRIx64 "\n", InitialPC); | 
|  | 155 | auto Address = DE.getSigned(&Offset, 4) + EHFrameHdrAddress; | 
|  | 156 | W.startLine() << format("address: 0x%" PRIx64 "\n", Address); | 
|  | 157 |  | 
|  | 158 | if (InitialPC < PrevPC) | 
|  | 159 | reportError("initial_location is out of order"); | 
|  | 160 |  | 
|  | 161 | PrevPC = InitialPC; | 
|  | 162 | ++NumEntries; | 
|  | 163 | } | 
|  | 164 | } | 
|  | 165 |  | 
|  | 166 | template <typename ELFT> | 
|  | 167 | void PrinterContext<ELFT>::printEHFrame( | 
|  | 168 | const typename ELFT::Shdr *EHFrameShdr) const { | 
|  | 169 | uint64_t Address = EHFrameShdr->sh_addr; | 
|  | 170 | uint64_t ShOffset = EHFrameShdr->sh_offset; | 
|  | 171 | W.startLine() << format(".eh_frame section at offset 0x%" PRIx64 | 
|  | 172 | " address 0x%" PRIx64 ":\n", | 
|  | 173 | ShOffset, Address); | 
|  | 174 | W.indent(); | 
|  | 175 |  | 
|  | 176 | auto Result = Obj->getSectionContents(EHFrameShdr); | 
|  | 177 | if (Error E = Result.takeError()) | 
|  | 178 | reportError(toString(std::move(E))); | 
|  | 179 |  | 
|  | 180 | auto Contents = Result.get(); | 
|  | 181 | DWARFDataExtractor DE( | 
|  | 182 | StringRef(reinterpret_cast<const char *>(Contents.data()), | 
|  | 183 | Contents.size()), | 
|  | 184 | ELFT::TargetEndianness == support::endianness::little, | 
|  | 185 | ELFT::Is64Bits ? 8 : 4); | 
| Luke Cheeseman | 8e5676b | 2018-09-27 16:47:30 +0000 | [diff] [blame] | 186 | DWARFDebugFrame EHFrame(/*IsEH=*/true, /*EHFrameAddress=*/Address); | 
| Rafael Auler | 86fb7bf | 2018-03-08 00:46:53 +0000 | [diff] [blame] | 187 | EHFrame.parse(DE); | 
|  | 188 |  | 
|  | 189 | for (const auto &Entry : EHFrame) { | 
|  | 190 | if (const auto *CIE = dyn_cast<dwarf::CIE>(&Entry)) { | 
|  | 191 | W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n", | 
|  | 192 | Address + CIE->getOffset(), | 
|  | 193 | CIE->getLength()); | 
|  | 194 | W.indent(); | 
|  | 195 |  | 
|  | 196 | W.printNumber("version", CIE->getVersion()); | 
|  | 197 | W.printString("augmentation", CIE->getAugmentationString()); | 
|  | 198 | W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor()); | 
|  | 199 | W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor()); | 
|  | 200 | W.printNumber("return_address_register", CIE->getReturnAddressRegister()); | 
|  | 201 |  | 
|  | 202 | W.getOStream() << "\n"; | 
|  | 203 | W.startLine() << "Program:\n"; | 
|  | 204 | W.indent(); | 
|  | 205 | CIE->cfis().dump(W.getOStream(), nullptr, W.getIndentLevel()); | 
|  | 206 | W.unindent(); | 
|  | 207 |  | 
|  | 208 | W.unindent(); | 
|  | 209 | W.getOStream() << "\n"; | 
|  | 210 |  | 
|  | 211 | } else if (const auto *FDE = dyn_cast<dwarf::FDE>(&Entry)) { | 
|  | 212 | W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64 | 
|  | 213 | " cie=[0x%" PRIx64 "]\n", | 
|  | 214 | Address + FDE->getOffset(), | 
|  | 215 | FDE->getLength(), | 
|  | 216 | Address + FDE->getLinkedCIE()->getOffset()); | 
|  | 217 | W.indent(); | 
|  | 218 |  | 
|  | 219 | W.startLine() << format("initial_location: 0x%" PRIx64 "\n", | 
|  | 220 | FDE->getInitialLocation()); | 
|  | 221 | W.startLine() | 
|  | 222 | << format("address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n", | 
|  | 223 | FDE->getAddressRange(), | 
|  | 224 | FDE->getInitialLocation() + FDE->getAddressRange()); | 
|  | 225 |  | 
|  | 226 | W.getOStream() << "\n"; | 
|  | 227 | W.startLine() << "Program:\n"; | 
|  | 228 | W.indent(); | 
|  | 229 | FDE->cfis().dump(W.getOStream(), nullptr, W.getIndentLevel()); | 
|  | 230 | W.unindent(); | 
|  | 231 |  | 
|  | 232 | W.unindent(); | 
|  | 233 | W.getOStream() << "\n"; | 
|  | 234 | } else { | 
|  | 235 | llvm_unreachable("unexpected DWARF frame kind"); | 
|  | 236 | } | 
|  | 237 | } | 
|  | 238 |  | 
|  | 239 | W.unindent(); | 
|  | 240 | } | 
|  | 241 |  | 
|  | 242 | } | 
|  | 243 | } | 
|  | 244 |  | 
|  | 245 | #endif |