Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lld/ELF/EhFrame.cpp
34878 views
1
//===- EhFrame.cpp -------------------------------------------------------===//
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
//
9
// .eh_frame section contains information on how to unwind the stack when
10
// an exception is thrown. The section consists of sequence of CIE and FDE
11
// records. The linker needs to merge CIEs and associate FDEs to CIEs.
12
// That means the linker has to understand the format of the section.
13
//
14
// This file contains a few utility functions to read .eh_frame contents.
15
//
16
//===----------------------------------------------------------------------===//
17
18
#include "EhFrame.h"
19
#include "Config.h"
20
#include "InputSection.h"
21
#include "Relocations.h"
22
#include "Target.h"
23
#include "lld/Common/ErrorHandler.h"
24
#include "lld/Common/Strings.h"
25
#include "llvm/BinaryFormat/Dwarf.h"
26
#include "llvm/Object/ELF.h"
27
28
using namespace llvm;
29
using namespace llvm::ELF;
30
using namespace llvm::dwarf;
31
using namespace llvm::object;
32
using namespace lld;
33
using namespace lld::elf;
34
35
namespace {
36
class EhReader {
37
public:
38
EhReader(InputSectionBase *s, ArrayRef<uint8_t> d) : isec(s), d(d) {}
39
uint8_t getFdeEncoding();
40
bool hasLSDA();
41
42
private:
43
template <class P> void failOn(const P *loc, const Twine &msg) {
44
fatal("corrupted .eh_frame: " + msg + "\n>>> defined in " +
45
isec->getObjMsg((const uint8_t *)loc - isec->content().data()));
46
}
47
48
uint8_t readByte();
49
void skipBytes(size_t count);
50
StringRef readString();
51
void skipLeb128();
52
void skipAugP();
53
StringRef getAugmentation();
54
55
InputSectionBase *isec;
56
ArrayRef<uint8_t> d;
57
};
58
}
59
60
// Read a byte and advance D by one byte.
61
uint8_t EhReader::readByte() {
62
if (d.empty())
63
failOn(d.data(), "unexpected end of CIE");
64
uint8_t b = d.front();
65
d = d.slice(1);
66
return b;
67
}
68
69
void EhReader::skipBytes(size_t count) {
70
if (d.size() < count)
71
failOn(d.data(), "CIE is too small");
72
d = d.slice(count);
73
}
74
75
// Read a null-terminated string.
76
StringRef EhReader::readString() {
77
const uint8_t *end = llvm::find(d, '\0');
78
if (end == d.end())
79
failOn(d.data(), "corrupted CIE (failed to read string)");
80
StringRef s = toStringRef(d.slice(0, end - d.begin()));
81
d = d.slice(s.size() + 1);
82
return s;
83
}
84
85
// Skip an integer encoded in the LEB128 format.
86
// Actual number is not of interest because only the runtime needs it.
87
// But we need to be at least able to skip it so that we can read
88
// the field that follows a LEB128 number.
89
void EhReader::skipLeb128() {
90
const uint8_t *errPos = d.data();
91
while (!d.empty()) {
92
uint8_t val = d.front();
93
d = d.slice(1);
94
if ((val & 0x80) == 0)
95
return;
96
}
97
failOn(errPos, "corrupted CIE (failed to read LEB128)");
98
}
99
100
static size_t getAugPSize(unsigned enc) {
101
switch (enc & 0x0f) {
102
case DW_EH_PE_absptr:
103
case DW_EH_PE_signed:
104
return config->wordsize;
105
case DW_EH_PE_udata2:
106
case DW_EH_PE_sdata2:
107
return 2;
108
case DW_EH_PE_udata4:
109
case DW_EH_PE_sdata4:
110
return 4;
111
case DW_EH_PE_udata8:
112
case DW_EH_PE_sdata8:
113
return 8;
114
}
115
return 0;
116
}
117
118
void EhReader::skipAugP() {
119
uint8_t enc = readByte();
120
if ((enc & 0xf0) == DW_EH_PE_aligned)
121
failOn(d.data() - 1, "DW_EH_PE_aligned encoding is not supported");
122
size_t size = getAugPSize(enc);
123
if (size == 0)
124
failOn(d.data() - 1, "unknown FDE encoding");
125
if (size >= d.size())
126
failOn(d.data() - 1, "corrupted CIE");
127
d = d.slice(size);
128
}
129
130
uint8_t elf::getFdeEncoding(EhSectionPiece *p) {
131
return EhReader(p->sec, p->data()).getFdeEncoding();
132
}
133
134
bool elf::hasLSDA(const EhSectionPiece &p) {
135
return EhReader(p.sec, p.data()).hasLSDA();
136
}
137
138
StringRef EhReader::getAugmentation() {
139
skipBytes(8);
140
int version = readByte();
141
if (version != 1 && version != 3)
142
failOn(d.data() - 1,
143
"FDE version 1 or 3 expected, but got " + Twine(version));
144
145
StringRef aug = readString();
146
147
// Skip code and data alignment factors.
148
skipLeb128();
149
skipLeb128();
150
151
// Skip the return address register. In CIE version 1 this is a single
152
// byte. In CIE version 3 this is an unsigned LEB128.
153
if (version == 1)
154
readByte();
155
else
156
skipLeb128();
157
return aug;
158
}
159
160
uint8_t EhReader::getFdeEncoding() {
161
// We only care about an 'R' value, but other records may precede an 'R'
162
// record. Unfortunately records are not in TLV (type-length-value) format,
163
// so we need to teach the linker how to skip records for each type.
164
StringRef aug = getAugmentation();
165
for (char c : aug) {
166
if (c == 'R')
167
return readByte();
168
if (c == 'z')
169
skipLeb128();
170
else if (c == 'L')
171
readByte();
172
else if (c == 'P')
173
skipAugP();
174
else if (c != 'B' && c != 'S' && c != 'G')
175
failOn(aug.data(), "unknown .eh_frame augmentation string: " + aug);
176
}
177
return DW_EH_PE_absptr;
178
}
179
180
bool EhReader::hasLSDA() {
181
StringRef aug = getAugmentation();
182
for (char c : aug) {
183
if (c == 'L')
184
return true;
185
if (c == 'z')
186
skipLeb128();
187
else if (c == 'P')
188
skipAugP();
189
else if (c == 'R')
190
readByte();
191
else if (c != 'B' && c != 'S' && c != 'G')
192
failOn(aug.data(), "unknown .eh_frame augmentation string: " + aug);
193
}
194
return false;
195
}
196
197