[NFC][Coroutines] Use structured binding with llvm::enumerate in CoroSplit (#116879)
[llvm-project.git] / lld / ELF / EhFrame.cpp
blob6e0120e14988b44eca9cc264341ddda6a7ad74f3
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.
14 // This file contains a few utility functions to read .eh_frame contents.
16 //===----------------------------------------------------------------------===//
18 #include "EhFrame.h"
19 #include "Config.h"
20 #include "InputFiles.h"
21 #include "InputSection.h"
22 #include "Relocations.h"
23 #include "Target.h"
24 #include "lld/Common/ErrorHandler.h"
25 #include "lld/Common/Strings.h"
26 #include "llvm/BinaryFormat/Dwarf.h"
27 #include "llvm/Object/ELF.h"
29 using namespace llvm;
30 using namespace llvm::ELF;
31 using namespace llvm::dwarf;
32 using namespace llvm::object;
33 using namespace lld;
34 using namespace lld::elf;
36 namespace {
37 class EhReader {
38 public:
39 EhReader(InputSectionBase *s, ArrayRef<uint8_t> d) : isec(s), d(d) {}
40 uint8_t getFdeEncoding();
41 bool hasLSDA();
43 private:
44 template <class P> void failOn(const P *loc, const Twine &msg) {
45 Ctx &ctx = isec->file->ctx;
46 Fatal(ctx) << "corrupted .eh_frame: " << msg << "\n>>> defined in "
47 << isec->getObjMsg((const uint8_t *)loc -
48 isec->content().data());
51 uint8_t readByte();
52 void skipBytes(size_t count);
53 StringRef readString();
54 void skipLeb128();
55 void skipAugP();
56 StringRef getAugmentation();
58 InputSectionBase *isec;
59 ArrayRef<uint8_t> d;
63 // Read a byte and advance D by one byte.
64 uint8_t EhReader::readByte() {
65 if (d.empty())
66 failOn(d.data(), "unexpected end of CIE");
67 uint8_t b = d.front();
68 d = d.slice(1);
69 return b;
72 void EhReader::skipBytes(size_t count) {
73 if (d.size() < count)
74 failOn(d.data(), "CIE is too small");
75 d = d.slice(count);
78 // Read a null-terminated string.
79 StringRef EhReader::readString() {
80 const uint8_t *end = llvm::find(d, '\0');
81 if (end == d.end())
82 failOn(d.data(), "corrupted CIE (failed to read string)");
83 StringRef s = toStringRef(d.slice(0, end - d.begin()));
84 d = d.slice(s.size() + 1);
85 return s;
88 // Skip an integer encoded in the LEB128 format.
89 // Actual number is not of interest because only the runtime needs it.
90 // But we need to be at least able to skip it so that we can read
91 // the field that follows a LEB128 number.
92 void EhReader::skipLeb128() {
93 const uint8_t *errPos = d.data();
94 while (!d.empty()) {
95 uint8_t val = d.front();
96 d = d.slice(1);
97 if ((val & 0x80) == 0)
98 return;
100 failOn(errPos, "corrupted CIE (failed to read LEB128)");
103 static size_t getAugPSize(Ctx &ctx, unsigned enc) {
104 switch (enc & 0x0f) {
105 case DW_EH_PE_absptr:
106 case DW_EH_PE_signed:
107 return ctx.arg.wordsize;
108 case DW_EH_PE_udata2:
109 case DW_EH_PE_sdata2:
110 return 2;
111 case DW_EH_PE_udata4:
112 case DW_EH_PE_sdata4:
113 return 4;
114 case DW_EH_PE_udata8:
115 case DW_EH_PE_sdata8:
116 return 8;
118 return 0;
121 void EhReader::skipAugP() {
122 uint8_t enc = readByte();
123 if ((enc & 0xf0) == DW_EH_PE_aligned)
124 failOn(d.data() - 1, "DW_EH_PE_aligned encoding is not supported");
125 size_t size = getAugPSize(isec->getCtx(), enc);
126 if (size == 0)
127 failOn(d.data() - 1, "unknown FDE encoding");
128 if (size >= d.size())
129 failOn(d.data() - 1, "corrupted CIE");
130 d = d.slice(size);
133 uint8_t elf::getFdeEncoding(EhSectionPiece *p) {
134 return EhReader(p->sec, p->data()).getFdeEncoding();
137 bool elf::hasLSDA(const EhSectionPiece &p) {
138 return EhReader(p.sec, p.data()).hasLSDA();
141 StringRef EhReader::getAugmentation() {
142 skipBytes(8);
143 int version = readByte();
144 if (version != 1 && version != 3)
145 failOn(d.data() - 1,
146 "FDE version 1 or 3 expected, but got " + Twine(version));
148 StringRef aug = readString();
150 // Skip code and data alignment factors.
151 skipLeb128();
152 skipLeb128();
154 // Skip the return address register. In CIE version 1 this is a single
155 // byte. In CIE version 3 this is an unsigned LEB128.
156 if (version == 1)
157 readByte();
158 else
159 skipLeb128();
160 return aug;
163 uint8_t EhReader::getFdeEncoding() {
164 // We only care about an 'R' value, but other records may precede an 'R'
165 // record. Unfortunately records are not in TLV (type-length-value) format,
166 // so we need to teach the linker how to skip records for each type.
167 StringRef aug = getAugmentation();
168 for (char c : aug) {
169 if (c == 'R')
170 return readByte();
171 if (c == 'z')
172 skipLeb128();
173 else if (c == 'L')
174 readByte();
175 else if (c == 'P')
176 skipAugP();
177 else if (c != 'B' && c != 'S' && c != 'G')
178 failOn(aug.data(), "unknown .eh_frame augmentation string: " + aug);
180 return DW_EH_PE_absptr;
183 bool EhReader::hasLSDA() {
184 StringRef aug = getAugmentation();
185 for (char c : aug) {
186 if (c == 'L')
187 return true;
188 if (c == 'z')
189 skipLeb128();
190 else if (c == 'P')
191 skipAugP();
192 else if (c == 'R')
193 readByte();
194 else if (c != 'B' && c != 'S' && c != 'G')
195 failOn(aug.data(), "unknown .eh_frame augmentation string: " + aug);
197 return false;