1 //===- EhFrame.cpp --------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
10 #include "InputFiles.h"
12 #include "lld/Common/ErrorHandler.h"
13 #include "llvm/BinaryFormat/Dwarf.h"
14 #include "llvm/Support/Endian.h"
18 using namespace lld::macho
;
19 using namespace llvm::support::endian
;
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
);
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
);
34 if (*off
+ len
> data
.size())
35 failOn(errOff
, "CIE/FDE extends past the end of the section");
39 void EhReader::skipValidLength(size_t *off
) const {
40 uint32_t len
= read32le(data
.data() + *off
);
42 if (len
== dwarf::DW_LENGTH_DWARF64
)
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
)++];
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
);
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");
66 v
= read64le(data
.data() + *off
);
69 v
= read32le(data
.data() + *off
);
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
);
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)
95 failOn(errOff
, "corrupted CIE (failed to read LEB128)");
98 void EhReader::failOn(size_t errOff
, const Twine
&msg
) const {
99 fatal(toString(file
) + ":(__eh_frame+0x" +
100 Twine::utohexstr(dataOff
+ errOff
) + "): " + msg
);
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
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
) {
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
);
126 void EhRelocator::makePcRel(uint64_t off
,
127 PointerUnion
<Symbol
*, InputSection
*> target
,
129 createSubtraction(isec
->symbols
[0], target
, off
, length
, &newRelocs
);
132 void EhRelocator::makeNegativePcRel(
133 uint64_t off
, PointerUnion
<Symbol
*, InputSection
*> target
,
135 createSubtraction
</*Invert=*/true>(isec
, target
, off
, length
, &newRelocs
);
138 void EhRelocator::commit() {
139 isec
->relocs
.insert(isec
->relocs
.end(), newRelocs
.begin(), newRelocs
.end());