1 //===------------------------- EHHeaderParser.hpp -------------------------===//
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
8 // Parses ELF .eh_frame_hdr sections.
10 //===----------------------------------------------------------------------===//
12 #ifndef __EHHEADERPARSER_HPP__
13 #define __EHHEADERPARSER_HPP__
15 #include "libunwind.h"
17 #include "DwarfParser.hpp"
21 /// \brief EHHeaderParser does basic parsing of an ELF .eh_frame_hdr section.
23 /// See DWARF spec for details:
24 /// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
26 template <typename A
> class EHHeaderParser
{
28 typedef typename
A::pint_t pint_t
;
30 /// Information encoded in the EH frame header.
38 static bool decodeEHHdr(A
&addressSpace
, pint_t ehHdrStart
, pint_t ehHdrEnd
,
39 EHHeaderInfo
&ehHdrInfo
);
40 static bool findFDE(A
&addressSpace
, pint_t pc
, pint_t ehHdrStart
,
41 uint32_t sectionLength
,
42 typename CFI_Parser
<A
>::FDE_Info
*fdeInfo
,
43 typename CFI_Parser
<A
>::CIE_Info
*cieInfo
);
46 static bool decodeTableEntry(A
&addressSpace
, pint_t
&tableEntry
,
47 pint_t ehHdrStart
, pint_t ehHdrEnd
,
49 typename CFI_Parser
<A
>::FDE_Info
*fdeInfo
,
50 typename CFI_Parser
<A
>::CIE_Info
*cieInfo
);
51 static size_t getTableEntrySize(uint8_t tableEnc
);
55 bool EHHeaderParser
<A
>::decodeEHHdr(A
&addressSpace
, pint_t ehHdrStart
,
56 pint_t ehHdrEnd
, EHHeaderInfo
&ehHdrInfo
) {
57 pint_t p
= ehHdrStart
;
58 uint8_t version
= addressSpace
.get8(p
++);
60 _LIBUNWIND_LOG0("Unsupported .eh_frame_hdr version");
64 uint8_t eh_frame_ptr_enc
= addressSpace
.get8(p
++);
65 uint8_t fde_count_enc
= addressSpace
.get8(p
++);
66 ehHdrInfo
.table_enc
= addressSpace
.get8(p
++);
68 ehHdrInfo
.eh_frame_ptr
=
69 addressSpace
.getEncodedP(p
, ehHdrEnd
, eh_frame_ptr_enc
, ehHdrStart
);
71 fde_count_enc
== DW_EH_PE_omit
73 : addressSpace
.getEncodedP(p
, ehHdrEnd
, fde_count_enc
, ehHdrStart
);
80 bool EHHeaderParser
<A
>::decodeTableEntry(
81 A
&addressSpace
, pint_t
&tableEntry
, pint_t ehHdrStart
, pint_t ehHdrEnd
,
82 uint8_t tableEnc
, typename CFI_Parser
<A
>::FDE_Info
*fdeInfo
,
83 typename CFI_Parser
<A
>::CIE_Info
*cieInfo
) {
84 // Have to decode the whole FDE for the PC range anyway, so just throw away
86 addressSpace
.getEncodedP(tableEntry
, ehHdrEnd
, tableEnc
, ehHdrStart
);
88 addressSpace
.getEncodedP(tableEntry
, ehHdrEnd
, tableEnc
, ehHdrStart
);
90 CFI_Parser
<A
>::decodeFDE(addressSpace
, fde
, fdeInfo
, cieInfo
);
91 if (message
!= NULL
) {
92 _LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s",
100 template <typename A
>
101 bool EHHeaderParser
<A
>::findFDE(A
&addressSpace
, pint_t pc
, pint_t ehHdrStart
,
102 uint32_t sectionLength
,
103 typename CFI_Parser
<A
>::FDE_Info
*fdeInfo
,
104 typename CFI_Parser
<A
>::CIE_Info
*cieInfo
) {
105 pint_t ehHdrEnd
= ehHdrStart
+ sectionLength
;
107 EHHeaderParser
<A
>::EHHeaderInfo hdrInfo
;
108 if (!EHHeaderParser
<A
>::decodeEHHdr(addressSpace
, ehHdrStart
, ehHdrEnd
,
112 size_t tableEntrySize
= getTableEntrySize(hdrInfo
.table_enc
);
116 for (size_t len
= hdrInfo
.fde_count
; len
> 1;) {
117 size_t mid
= low
+ (len
/ 2);
118 tableEntry
= hdrInfo
.table
+ mid
* tableEntrySize
;
119 pint_t start
= addressSpace
.getEncodedP(tableEntry
, ehHdrEnd
,
120 hdrInfo
.table_enc
, ehHdrStart
);
125 } else if (start
< pc
) {
133 tableEntry
= hdrInfo
.table
+ low
* tableEntrySize
;
134 if (decodeTableEntry(addressSpace
, tableEntry
, ehHdrStart
, ehHdrEnd
,
135 hdrInfo
.table_enc
, fdeInfo
, cieInfo
)) {
136 if (pc
>= fdeInfo
->pcStart
&& pc
< fdeInfo
->pcEnd
)
143 template <typename A
>
144 size_t EHHeaderParser
<A
>::getTableEntrySize(uint8_t tableEnc
) {
145 switch (tableEnc
& 0x0f) {
146 case DW_EH_PE_sdata2
:
147 case DW_EH_PE_udata2
:
149 case DW_EH_PE_sdata4
:
150 case DW_EH_PE_udata4
:
152 case DW_EH_PE_sdata8
:
153 case DW_EH_PE_udata8
:
155 case DW_EH_PE_sleb128
:
156 case DW_EH_PE_uleb128
:
157 _LIBUNWIND_ABORT("Can't binary search on variable length encoded data.");
161 _LIBUNWIND_ABORT("Unknown DWARF encoding for search table.");