Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lld/MachO/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
#include "EhFrame.h"
10
#include "InputFiles.h"
11
12
#include "lld/Common/ErrorHandler.h"
13
#include "llvm/BinaryFormat/Dwarf.h"
14
#include "llvm/Support/Endian.h"
15
16
using namespace llvm;
17
using namespace lld;
18
using namespace lld::macho;
19
using namespace llvm::support::endian;
20
21
uint64_t EhReader::readLength(size_t *off) const {
22
const size_t errOff = *off;
23
if (*off + 4 > data.size())
24
failOn(errOff, "CIE/FDE too small");
25
uint64_t len = read32le(data.data() + *off);
26
*off += 4;
27
if (len == dwarf::DW_LENGTH_DWARF64) {
28
// FIXME: test this DWARF64 code path
29
if (*off + 8 > data.size())
30
failOn(errOff, "CIE/FDE too small");
31
len = read64le(data.data() + *off);
32
*off += 8;
33
}
34
if (*off + len > data.size())
35
failOn(errOff, "CIE/FDE extends past the end of the section");
36
return len;
37
}
38
39
void EhReader::skipValidLength(size_t *off) const {
40
uint32_t len = read32le(data.data() + *off);
41
*off += 4;
42
if (len == dwarf::DW_LENGTH_DWARF64)
43
*off += 8;
44
}
45
46
// Read a byte and advance off by one byte.
47
uint8_t EhReader::readByte(size_t *off) const {
48
if (*off + 1 > data.size())
49
failOn(*off, "unexpected end of CIE/FDE");
50
return data[(*off)++];
51
}
52
53
uint32_t EhReader::readU32(size_t *off) const {
54
if (*off + 4 > data.size())
55
failOn(*off, "unexpected end of CIE/FDE");
56
uint32_t v = read32le(data.data() + *off);
57
*off += 4;
58
return v;
59
}
60
61
uint64_t EhReader::readPointer(size_t *off, uint8_t size) const {
62
if (*off + size > data.size())
63
failOn(*off, "unexpected end of CIE/FDE");
64
uint64_t v;
65
if (size == 8)
66
v = read64le(data.data() + *off);
67
else {
68
assert(size == 4);
69
v = read32le(data.data() + *off);
70
}
71
*off += size;
72
return v;
73
}
74
75
// Read a null-terminated string.
76
StringRef EhReader::readString(size_t *off) const {
77
if (*off > data.size())
78
failOn(*off, "corrupted CIE (failed to read string)");
79
const size_t maxlen = data.size() - *off;
80
auto *c = reinterpret_cast<const char *>(data.data() + *off);
81
size_t len = strnlen(c, maxlen);
82
if (len == maxlen) // we failed to find the null terminator
83
failOn(*off, "corrupted CIE (failed to read string)");
84
*off += len + 1; // skip the null byte too
85
return StringRef(c, len);
86
}
87
88
void EhReader::skipLeb128(size_t *off) const {
89
const size_t errOff = *off;
90
while (*off < data.size()) {
91
uint8_t val = data[(*off)++];
92
if ((val & 0x80) == 0)
93
return;
94
}
95
failOn(errOff, "corrupted CIE (failed to read LEB128)");
96
}
97
98
void EhReader::failOn(size_t errOff, const Twine &msg) const {
99
fatal(toString(file) + ":(__eh_frame+0x" +
100
Twine::utohexstr(dataOff + errOff) + "): " + msg);
101
}
102
103
/*
104
* Create a pair of relocs to write the value of:
105
* `b - (offset + a)` if Invert == false
106
* `(a + offset) - b` if Invert == true
107
*/
108
template <bool Invert = false>
109
static void createSubtraction(PointerUnion<Symbol *, InputSection *> a,
110
PointerUnion<Symbol *, InputSection *> b,
111
uint64_t off, uint8_t length,
112
SmallVectorImpl<Reloc> *newRelocs) {
113
auto subtrahend = a;
114
auto minuend = b;
115
if (Invert)
116
std::swap(subtrahend, minuend);
117
assert(subtrahend.is<Symbol *>());
118
Reloc subtrahendReloc(target->subtractorRelocType, /*pcrel=*/false, length,
119
off, /*addend=*/0, subtrahend);
120
Reloc minuendReloc(target->unsignedRelocType, /*pcrel=*/false, length, off,
121
(Invert ? 1 : -1) * off, minuend);
122
newRelocs->push_back(subtrahendReloc);
123
newRelocs->push_back(minuendReloc);
124
}
125
126
void EhRelocator::makePcRel(uint64_t off,
127
PointerUnion<Symbol *, InputSection *> target,
128
uint8_t length) {
129
createSubtraction(isec->symbols[0], target, off, length, &newRelocs);
130
}
131
132
void EhRelocator::makeNegativePcRel(
133
uint64_t off, PointerUnion<Symbol *, InputSection *> target,
134
uint8_t length) {
135
createSubtraction</*Invert=*/true>(isec, target, off, length, &newRelocs);
136
}
137
138
void EhRelocator::commit() {
139
isec->relocs.insert(isec->relocs.end(), newRelocs.begin(), newRelocs.end());
140
}
141
142