EHHeaderParser.hpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. //===----------------------------------------------------------------------===//
  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. // Parses ELF .eh_frame_hdr sections.
  9. //
  10. //===----------------------------------------------------------------------===//
  11. #ifndef __EHHEADERPARSER_HPP__
  12. #define __EHHEADERPARSER_HPP__
  13. #include "libunwind.h"
  14. #include "DwarfParser.hpp"
  15. namespace libunwind {
  16. /// \brief EHHeaderParser does basic parsing of an ELF .eh_frame_hdr section.
  17. ///
  18. /// See DWARF spec for details:
  19. /// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
  20. ///
  21. template <typename A> class EHHeaderParser {
  22. public:
  23. typedef typename A::pint_t pint_t;
  24. /// Information encoded in the EH frame header.
  25. struct EHHeaderInfo {
  26. pint_t eh_frame_ptr;
  27. size_t fde_count;
  28. pint_t table;
  29. uint8_t table_enc;
  30. };
  31. static bool decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd,
  32. EHHeaderInfo &ehHdrInfo);
  33. static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
  34. uint32_t sectionLength,
  35. typename CFI_Parser<A>::FDE_Info *fdeInfo,
  36. typename CFI_Parser<A>::CIE_Info *cieInfo);
  37. private:
  38. static bool decodeTableEntry(A &addressSpace, pint_t &tableEntry,
  39. pint_t ehHdrStart, pint_t ehHdrEnd,
  40. uint8_t tableEnc,
  41. typename CFI_Parser<A>::FDE_Info *fdeInfo,
  42. typename CFI_Parser<A>::CIE_Info *cieInfo);
  43. static size_t getTableEntrySize(uint8_t tableEnc);
  44. };
  45. template <typename A>
  46. bool EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
  47. pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) {
  48. pint_t p = ehHdrStart;
  49. uint8_t version = addressSpace.get8(p++);
  50. if (version != 1) {
  51. _LIBUNWIND_LOG0("Unsupported .eh_frame_hdr version");
  52. return false;
  53. }
  54. uint8_t eh_frame_ptr_enc = addressSpace.get8(p++);
  55. uint8_t fde_count_enc = addressSpace.get8(p++);
  56. ehHdrInfo.table_enc = addressSpace.get8(p++);
  57. ehHdrInfo.eh_frame_ptr =
  58. addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart);
  59. ehHdrInfo.fde_count =
  60. fde_count_enc == DW_EH_PE_omit
  61. ? 0
  62. : addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart);
  63. ehHdrInfo.table = p;
  64. return true;
  65. }
  66. template <typename A>
  67. bool EHHeaderParser<A>::decodeTableEntry(
  68. A &addressSpace, pint_t &tableEntry, pint_t ehHdrStart, pint_t ehHdrEnd,
  69. uint8_t tableEnc, typename CFI_Parser<A>::FDE_Info *fdeInfo,
  70. typename CFI_Parser<A>::CIE_Info *cieInfo) {
  71. // Have to decode the whole FDE for the PC range anyway, so just throw away
  72. // the PC start.
  73. addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart);
  74. pint_t fde =
  75. addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart);
  76. const char *message =
  77. CFI_Parser<A>::decodeFDE(addressSpace, fde, fdeInfo, cieInfo);
  78. if (message != NULL) {
  79. _LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s",
  80. message);
  81. return false;
  82. }
  83. return true;
  84. }
  85. template <typename A>
  86. bool EHHeaderParser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
  87. uint32_t sectionLength,
  88. typename CFI_Parser<A>::FDE_Info *fdeInfo,
  89. typename CFI_Parser<A>::CIE_Info *cieInfo) {
  90. pint_t ehHdrEnd = ehHdrStart + sectionLength;
  91. EHHeaderParser<A>::EHHeaderInfo hdrInfo;
  92. if (!EHHeaderParser<A>::decodeEHHdr(addressSpace, ehHdrStart, ehHdrEnd,
  93. hdrInfo))
  94. return false;
  95. if (hdrInfo.fde_count == 0) return false;
  96. size_t tableEntrySize = getTableEntrySize(hdrInfo.table_enc);
  97. pint_t tableEntry;
  98. size_t low = 0;
  99. for (size_t len = hdrInfo.fde_count; len > 1;) {
  100. size_t mid = low + (len / 2);
  101. tableEntry = hdrInfo.table + mid * tableEntrySize;
  102. pint_t start = addressSpace.getEncodedP(tableEntry, ehHdrEnd,
  103. hdrInfo.table_enc, ehHdrStart);
  104. if (start == pc) {
  105. low = mid;
  106. break;
  107. } else if (start < pc) {
  108. low = mid;
  109. len -= (len / 2);
  110. } else {
  111. len /= 2;
  112. }
  113. }
  114. tableEntry = hdrInfo.table + low * tableEntrySize;
  115. if (decodeTableEntry(addressSpace, tableEntry, ehHdrStart, ehHdrEnd,
  116. hdrInfo.table_enc, fdeInfo, cieInfo)) {
  117. if (pc >= fdeInfo->pcStart && pc < fdeInfo->pcEnd)
  118. return true;
  119. }
  120. return false;
  121. }
  122. template <typename A>
  123. size_t EHHeaderParser<A>::getTableEntrySize(uint8_t tableEnc) {
  124. switch (tableEnc & 0x0f) {
  125. case DW_EH_PE_sdata2:
  126. case DW_EH_PE_udata2:
  127. return 4;
  128. case DW_EH_PE_sdata4:
  129. case DW_EH_PE_udata4:
  130. return 8;
  131. case DW_EH_PE_sdata8:
  132. case DW_EH_PE_udata8:
  133. return 16;
  134. case DW_EH_PE_sleb128:
  135. case DW_EH_PE_uleb128:
  136. _LIBUNWIND_ABORT("Can't binary search on variable length encoded data.");
  137. case DW_EH_PE_omit:
  138. return 0;
  139. default:
  140. _LIBUNWIND_ABORT("Unknown DWARF encoding for search table.");
  141. }
  142. }
  143. }
  144. #endif