Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/libunwind/src/EHHeaderParser.hpp
35148 views
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
12
#ifndef __EHHEADERPARSER_HPP__
13
#define __EHHEADERPARSER_HPP__
14
15
#include "libunwind.h"
16
17
#include "DwarfParser.hpp"
18
19
namespace libunwind {
20
21
/// \brief EHHeaderParser does basic parsing of an ELF .eh_frame_hdr section.
22
///
23
/// See DWARF spec for details:
24
/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
25
///
26
template <typename A> class EHHeaderParser {
27
public:
28
typedef typename A::pint_t pint_t;
29
30
/// Information encoded in the EH frame header.
31
struct EHHeaderInfo {
32
pint_t eh_frame_ptr;
33
size_t fde_count;
34
pint_t table;
35
uint8_t table_enc;
36
};
37
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);
44
45
private:
46
static bool decodeTableEntry(A &addressSpace, pint_t &tableEntry,
47
pint_t ehHdrStart, pint_t ehHdrEnd,
48
uint8_t tableEnc,
49
typename CFI_Parser<A>::FDE_Info *fdeInfo,
50
typename CFI_Parser<A>::CIE_Info *cieInfo);
51
static size_t getTableEntrySize(uint8_t tableEnc);
52
};
53
54
template <typename A>
55
bool EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
56
pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) {
57
pint_t p = ehHdrStart;
58
59
// Ensure that we don't read data beyond the end of .eh_frame_hdr
60
if (ehHdrEnd - ehHdrStart < 4) {
61
// Don't print a message for an empty .eh_frame_hdr (this can happen if
62
// the linker script defines symbols for it even in the empty case).
63
if (ehHdrEnd == ehHdrStart)
64
return false;
65
_LIBUNWIND_LOG("unsupported .eh_frame_hdr at %" PRIx64
66
": need at least 4 bytes of data but only got %zd",
67
static_cast<uint64_t>(ehHdrStart),
68
static_cast<size_t>(ehHdrEnd - ehHdrStart));
69
return false;
70
}
71
uint8_t version = addressSpace.get8(p++);
72
if (version != 1) {
73
_LIBUNWIND_LOG("unsupported .eh_frame_hdr version: %" PRIu8 " at %" PRIx64,
74
version, static_cast<uint64_t>(ehHdrStart));
75
return false;
76
}
77
78
uint8_t eh_frame_ptr_enc = addressSpace.get8(p++);
79
uint8_t fde_count_enc = addressSpace.get8(p++);
80
ehHdrInfo.table_enc = addressSpace.get8(p++);
81
82
ehHdrInfo.eh_frame_ptr =
83
addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart);
84
ehHdrInfo.fde_count =
85
fde_count_enc == DW_EH_PE_omit
86
? 0
87
: addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart);
88
ehHdrInfo.table = p;
89
90
return true;
91
}
92
93
template <typename A>
94
bool EHHeaderParser<A>::decodeTableEntry(
95
A &addressSpace, pint_t &tableEntry, pint_t ehHdrStart, pint_t ehHdrEnd,
96
uint8_t tableEnc, typename CFI_Parser<A>::FDE_Info *fdeInfo,
97
typename CFI_Parser<A>::CIE_Info *cieInfo) {
98
// Have to decode the whole FDE for the PC range anyway, so just throw away
99
// the PC start.
100
addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart);
101
pint_t fde =
102
addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart);
103
const char *message =
104
CFI_Parser<A>::decodeFDE(addressSpace, fde, fdeInfo, cieInfo);
105
if (message != NULL) {
106
_LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s",
107
message);
108
return false;
109
}
110
111
return true;
112
}
113
114
template <typename A>
115
bool EHHeaderParser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
116
uint32_t sectionLength,
117
typename CFI_Parser<A>::FDE_Info *fdeInfo,
118
typename CFI_Parser<A>::CIE_Info *cieInfo) {
119
pint_t ehHdrEnd = ehHdrStart + sectionLength;
120
121
EHHeaderParser<A>::EHHeaderInfo hdrInfo;
122
if (!EHHeaderParser<A>::decodeEHHdr(addressSpace, ehHdrStart, ehHdrEnd,
123
hdrInfo))
124
return false;
125
126
if (hdrInfo.fde_count == 0) return false;
127
128
size_t tableEntrySize = getTableEntrySize(hdrInfo.table_enc);
129
pint_t tableEntry;
130
131
size_t low = 0;
132
for (size_t len = hdrInfo.fde_count; len > 1;) {
133
size_t mid = low + (len / 2);
134
tableEntry = hdrInfo.table + mid * tableEntrySize;
135
pint_t start = addressSpace.getEncodedP(tableEntry, ehHdrEnd,
136
hdrInfo.table_enc, ehHdrStart);
137
138
if (start == pc) {
139
low = mid;
140
break;
141
} else if (start < pc) {
142
low = mid;
143
len -= (len / 2);
144
} else {
145
len /= 2;
146
}
147
}
148
149
tableEntry = hdrInfo.table + low * tableEntrySize;
150
if (decodeTableEntry(addressSpace, tableEntry, ehHdrStart, ehHdrEnd,
151
hdrInfo.table_enc, fdeInfo, cieInfo)) {
152
if (pc >= fdeInfo->pcStart && pc < fdeInfo->pcEnd)
153
return true;
154
}
155
156
return false;
157
}
158
159
template <typename A>
160
size_t EHHeaderParser<A>::getTableEntrySize(uint8_t tableEnc) {
161
switch (tableEnc & 0x0f) {
162
case DW_EH_PE_sdata2:
163
case DW_EH_PE_udata2:
164
return 4;
165
case DW_EH_PE_sdata4:
166
case DW_EH_PE_udata4:
167
return 8;
168
case DW_EH_PE_sdata8:
169
case DW_EH_PE_udata8:
170
return 16;
171
case DW_EH_PE_sleb128:
172
case DW_EH_PE_uleb128:
173
_LIBUNWIND_ABORT("Can't binary search on variable length encoded data.");
174
case DW_EH_PE_omit:
175
return 0;
176
default:
177
_LIBUNWIND_ABORT("Unknown DWARF encoding for search table.");
178
}
179
}
180
181
}
182
183
#endif
184
185