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