DwarfCFIEHPrinter.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  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. #ifndef LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H
  9. #define LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H
  10. #include "llvm-readobj.h"
  11. #include "llvm/ADT/STLExtras.h"
  12. #include "llvm/BinaryFormat/Dwarf.h"
  13. #include "llvm/DebugInfo/DWARF/DWARFContext.h"
  14. #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
  15. #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
  16. #include "llvm/Object/ELF.h"
  17. #include "llvm/Object/ELFObjectFile.h"
  18. #include "llvm/Object/ELFTypes.h"
  19. #include "llvm/Support/Casting.h"
  20. #include "llvm/Support/Debug.h"
  21. #include "llvm/Support/Endian.h"
  22. #include "llvm/Support/Format.h"
  23. #include "llvm/Support/ScopedPrinter.h"
  24. #include "llvm/Support/type_traits.h"
  25. namespace llvm {
  26. namespace DwarfCFIEH {
  27. template <typename ELFT> class PrinterContext {
  28. using Elf_Shdr = typename ELFT::Shdr;
  29. using Elf_Phdr = typename ELFT::Phdr;
  30. ScopedPrinter &W;
  31. const object::ELFObjectFile<ELFT> &ObjF;
  32. void printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const;
  33. void printEHFrame(const Elf_Shdr *EHFrameShdr) const;
  34. public:
  35. PrinterContext(ScopedPrinter &W, const object::ELFObjectFile<ELFT> &ObjF)
  36. : W(W), ObjF(ObjF) {}
  37. void printUnwindInformation() const;
  38. };
  39. template <class ELFT>
  40. static const typename ELFT::Shdr *
  41. findSectionByAddress(const object::ELFObjectFile<ELFT> &ObjF, uint64_t Addr) {
  42. Expected<typename ELFT::ShdrRange> SectionsOrErr =
  43. ObjF.getELFFile().sections();
  44. if (!SectionsOrErr)
  45. reportError(SectionsOrErr.takeError(), ObjF.getFileName());
  46. for (const typename ELFT::Shdr &Shdr : *SectionsOrErr)
  47. if (Shdr.sh_addr == Addr)
  48. return &Shdr;
  49. return nullptr;
  50. }
  51. template <typename ELFT>
  52. void PrinterContext<ELFT>::printUnwindInformation() const {
  53. const object::ELFFile<ELFT> &Obj = ObjF.getELFFile();
  54. Expected<typename ELFT::PhdrRange> PhdrsOrErr = Obj.program_headers();
  55. if (!PhdrsOrErr)
  56. reportError(PhdrsOrErr.takeError(), ObjF.getFileName());
  57. for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
  58. if (Phdr.p_type != ELF::PT_GNU_EH_FRAME)
  59. continue;
  60. if (Phdr.p_memsz != Phdr.p_filesz)
  61. reportError(object::createError(
  62. "p_memsz does not match p_filesz for GNU_EH_FRAME"),
  63. ObjF.getFileName());
  64. printEHFrameHdr(&Phdr);
  65. break;
  66. }
  67. Expected<typename ELFT::ShdrRange> SectionsOrErr = Obj.sections();
  68. if (!SectionsOrErr)
  69. reportError(SectionsOrErr.takeError(), ObjF.getFileName());
  70. for (const Elf_Shdr &Shdr : *SectionsOrErr) {
  71. Expected<StringRef> NameOrErr = Obj.getSectionName(Shdr);
  72. if (!NameOrErr)
  73. reportError(NameOrErr.takeError(), ObjF.getFileName());
  74. if (*NameOrErr == ".eh_frame")
  75. printEHFrame(&Shdr);
  76. }
  77. }
  78. template <typename ELFT>
  79. void PrinterContext<ELFT>::printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const {
  80. DictScope L(W, "EHFrameHeader");
  81. uint64_t EHFrameHdrAddress = EHFramePHdr->p_vaddr;
  82. W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress);
  83. W.startLine() << format("Offset: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_offset);
  84. W.startLine() << format("Size: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_memsz);
  85. const object::ELFFile<ELFT> &Obj = ObjF.getELFFile();
  86. if (const Elf_Shdr *EHFrameHdr =
  87. findSectionByAddress(ObjF, EHFramePHdr->p_vaddr)) {
  88. Expected<StringRef> NameOrErr = Obj.getSectionName(*EHFrameHdr);
  89. if (!NameOrErr)
  90. reportError(NameOrErr.takeError(), ObjF.getFileName());
  91. W.printString("Corresponding Section", *NameOrErr);
  92. }
  93. Expected<ArrayRef<uint8_t>> Content = Obj.getSegmentContents(*EHFramePHdr);
  94. if (!Content)
  95. reportError(Content.takeError(), ObjF.getFileName());
  96. DataExtractor DE(*Content,
  97. ELFT::TargetEndianness == support::endianness::little,
  98. ELFT::Is64Bits ? 8 : 4);
  99. DictScope D(W, "Header");
  100. uint64_t Offset = 0;
  101. auto Version = DE.getU8(&Offset);
  102. W.printNumber("version", Version);
  103. if (Version != 1)
  104. reportError(
  105. object::createError("only version 1 of .eh_frame_hdr is supported"),
  106. ObjF.getFileName());
  107. uint64_t EHFramePtrEnc = DE.getU8(&Offset);
  108. W.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64 "\n", EHFramePtrEnc);
  109. if (EHFramePtrEnc != (dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4))
  110. reportError(object::createError("unexpected encoding eh_frame_ptr_enc"),
  111. ObjF.getFileName());
  112. uint64_t FDECountEnc = DE.getU8(&Offset);
  113. W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc);
  114. if (FDECountEnc != dwarf::DW_EH_PE_udata4)
  115. reportError(object::createError("unexpected encoding fde_count_enc"),
  116. ObjF.getFileName());
  117. uint64_t TableEnc = DE.getU8(&Offset);
  118. W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc);
  119. if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4))
  120. reportError(object::createError("unexpected encoding table_enc"),
  121. ObjF.getFileName());
  122. auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4;
  123. W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr);
  124. auto FDECount = DE.getUnsigned(&Offset, 4);
  125. W.printNumber("fde_count", FDECount);
  126. unsigned NumEntries = 0;
  127. uint64_t PrevPC = 0;
  128. while (Offset + 8 <= EHFramePHdr->p_memsz && NumEntries < FDECount) {
  129. DictScope D(W, std::string("entry ") + std::to_string(NumEntries));
  130. auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
  131. W.startLine() << format("initial_location: 0x%" PRIx64 "\n", InitialPC);
  132. auto Address = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
  133. W.startLine() << format("address: 0x%" PRIx64 "\n", Address);
  134. if (InitialPC < PrevPC)
  135. reportError(object::createError("initial_location is out of order"),
  136. ObjF.getFileName());
  137. PrevPC = InitialPC;
  138. ++NumEntries;
  139. }
  140. }
  141. template <typename ELFT>
  142. void PrinterContext<ELFT>::printEHFrame(const Elf_Shdr *EHFrameShdr) const {
  143. uint64_t Address = EHFrameShdr->sh_addr;
  144. uint64_t ShOffset = EHFrameShdr->sh_offset;
  145. W.startLine() << format(".eh_frame section at offset 0x%" PRIx64
  146. " address 0x%" PRIx64 ":\n",
  147. ShOffset, Address);
  148. W.indent();
  149. Expected<ArrayRef<uint8_t>> DataOrErr =
  150. ObjF.getELFFile().getSectionContents(*EHFrameShdr);
  151. if (!DataOrErr)
  152. reportError(DataOrErr.takeError(), ObjF.getFileName());
  153. // Construct DWARFDataExtractor to handle relocations ("PC Begin" fields).
  154. std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(
  155. ObjF, DWARFContext::ProcessDebugRelocations::Process, nullptr);
  156. DWARFDataExtractor DE(DICtx->getDWARFObj(),
  157. DICtx->getDWARFObj().getEHFrameSection(),
  158. ELFT::TargetEndianness == support::endianness::little,
  159. ELFT::Is64Bits ? 8 : 4);
  160. DWARFDebugFrame EHFrame(Triple::ArchType(ObjF.getArch()), /*IsEH=*/true,
  161. /*EHFrameAddress=*/Address);
  162. if (Error E = EHFrame.parse(DE))
  163. reportError(std::move(E), ObjF.getFileName());
  164. for (const dwarf::FrameEntry &Entry : EHFrame) {
  165. if (const dwarf::CIE *CIE = dyn_cast<dwarf::CIE>(&Entry)) {
  166. W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n",
  167. Address + CIE->getOffset(), CIE->getLength());
  168. W.indent();
  169. W.printNumber("version", CIE->getVersion());
  170. W.printString("augmentation", CIE->getAugmentationString());
  171. W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor());
  172. W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor());
  173. W.printNumber("return_address_register", CIE->getReturnAddressRegister());
  174. } else {
  175. const dwarf::FDE *FDE = cast<dwarf::FDE>(&Entry);
  176. W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64
  177. " cie=[0x%" PRIx64 "]\n",
  178. Address + FDE->getOffset(), FDE->getLength(),
  179. Address + FDE->getLinkedCIE()->getOffset());
  180. W.indent();
  181. W.startLine() << format("initial_location: 0x%" PRIx64 "\n",
  182. FDE->getInitialLocation());
  183. W.startLine() << format(
  184. "address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n",
  185. FDE->getAddressRange(),
  186. FDE->getInitialLocation() + FDE->getAddressRange());
  187. }
  188. W.getOStream() << "\n";
  189. W.startLine() << "Program:\n";
  190. W.indent();
  191. auto DumpOpts = DIDumpOptions();
  192. DumpOpts.IsEH = true;
  193. Entry.cfis().dump(W.getOStream(), DumpOpts, W.getIndentLevel());
  194. W.unindent();
  195. W.unindent();
  196. W.getOStream() << "\n";
  197. }
  198. W.unindent();
  199. }
  200. } // namespace DwarfCFIEH
  201. } // namespace llvm
  202. #endif