annotate lld/ELF/EhFrame.cpp @ 173:0572611fdcc8 llvm10 llvm12

reorgnization done
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 11:55:54 +0900
parents 1d019706d866
children 2e18cbf3894f
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===- EhFrame.cpp -------------------------------------------------------===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // .eh_frame section contains information on how to unwind the stack when
anatofuz
parents:
diff changeset
10 // an exception is thrown. The section consists of sequence of CIE and FDE
anatofuz
parents:
diff changeset
11 // records. The linker needs to merge CIEs and associate FDEs to CIEs.
anatofuz
parents:
diff changeset
12 // That means the linker has to understand the format of the section.
anatofuz
parents:
diff changeset
13 //
anatofuz
parents:
diff changeset
14 // This file contains a few utility functions to read .eh_frame contents.
anatofuz
parents:
diff changeset
15 //
anatofuz
parents:
diff changeset
16 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
17
anatofuz
parents:
diff changeset
18 #include "EhFrame.h"
anatofuz
parents:
diff changeset
19 #include "Config.h"
anatofuz
parents:
diff changeset
20 #include "InputSection.h"
anatofuz
parents:
diff changeset
21 #include "Relocations.h"
anatofuz
parents:
diff changeset
22 #include "Target.h"
anatofuz
parents:
diff changeset
23 #include "lld/Common/ErrorHandler.h"
anatofuz
parents:
diff changeset
24 #include "lld/Common/Strings.h"
anatofuz
parents:
diff changeset
25 #include "llvm/BinaryFormat/Dwarf.h"
anatofuz
parents:
diff changeset
26 #include "llvm/Object/ELF.h"
anatofuz
parents:
diff changeset
27
anatofuz
parents:
diff changeset
28 using namespace llvm;
anatofuz
parents:
diff changeset
29 using namespace llvm::ELF;
anatofuz
parents:
diff changeset
30 using namespace llvm::dwarf;
anatofuz
parents:
diff changeset
31 using namespace llvm::object;
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
32 using namespace lld;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
33 using namespace lld::elf;
150
anatofuz
parents:
diff changeset
34
anatofuz
parents:
diff changeset
35 namespace {
anatofuz
parents:
diff changeset
36 class EhReader {
anatofuz
parents:
diff changeset
37 public:
anatofuz
parents:
diff changeset
38 EhReader(InputSectionBase *s, ArrayRef<uint8_t> d) : isec(s), d(d) {}
anatofuz
parents:
diff changeset
39 size_t readEhRecordSize();
anatofuz
parents:
diff changeset
40 uint8_t getFdeEncoding();
anatofuz
parents:
diff changeset
41
anatofuz
parents:
diff changeset
42 private:
anatofuz
parents:
diff changeset
43 template <class P> void failOn(const P *loc, const Twine &msg) {
anatofuz
parents:
diff changeset
44 fatal("corrupted .eh_frame: " + msg + "\n>>> defined in " +
anatofuz
parents:
diff changeset
45 isec->getObjMsg((const uint8_t *)loc - isec->data().data()));
anatofuz
parents:
diff changeset
46 }
anatofuz
parents:
diff changeset
47
anatofuz
parents:
diff changeset
48 uint8_t readByte();
anatofuz
parents:
diff changeset
49 void skipBytes(size_t count);
anatofuz
parents:
diff changeset
50 StringRef readString();
anatofuz
parents:
diff changeset
51 void skipLeb128();
anatofuz
parents:
diff changeset
52 void skipAugP();
anatofuz
parents:
diff changeset
53
anatofuz
parents:
diff changeset
54 InputSectionBase *isec;
anatofuz
parents:
diff changeset
55 ArrayRef<uint8_t> d;
anatofuz
parents:
diff changeset
56 };
anatofuz
parents:
diff changeset
57 }
anatofuz
parents:
diff changeset
58
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
59 size_t elf::readEhRecordSize(InputSectionBase *s, size_t off) {
150
anatofuz
parents:
diff changeset
60 return EhReader(s, s->data().slice(off)).readEhRecordSize();
anatofuz
parents:
diff changeset
61 }
anatofuz
parents:
diff changeset
62
anatofuz
parents:
diff changeset
63 // .eh_frame section is a sequence of records. Each record starts with
anatofuz
parents:
diff changeset
64 // a 4 byte length field. This function reads the length.
anatofuz
parents:
diff changeset
65 size_t EhReader::readEhRecordSize() {
anatofuz
parents:
diff changeset
66 if (d.size() < 4)
anatofuz
parents:
diff changeset
67 failOn(d.data(), "CIE/FDE too small");
anatofuz
parents:
diff changeset
68
anatofuz
parents:
diff changeset
69 // First 4 bytes of CIE/FDE is the size of the record.
anatofuz
parents:
diff changeset
70 // If it is 0xFFFFFFFF, the next 8 bytes contain the size instead,
anatofuz
parents:
diff changeset
71 // but we do not support that format yet.
anatofuz
parents:
diff changeset
72 uint64_t v = read32(d.data());
anatofuz
parents:
diff changeset
73 if (v == UINT32_MAX)
anatofuz
parents:
diff changeset
74 failOn(d.data(), "CIE/FDE too large");
anatofuz
parents:
diff changeset
75 uint64_t size = v + 4;
anatofuz
parents:
diff changeset
76 if (size > d.size())
anatofuz
parents:
diff changeset
77 failOn(d.data(), "CIE/FDE ends past the end of the section");
anatofuz
parents:
diff changeset
78 return size;
anatofuz
parents:
diff changeset
79 }
anatofuz
parents:
diff changeset
80
anatofuz
parents:
diff changeset
81 // Read a byte and advance D by one byte.
anatofuz
parents:
diff changeset
82 uint8_t EhReader::readByte() {
anatofuz
parents:
diff changeset
83 if (d.empty())
anatofuz
parents:
diff changeset
84 failOn(d.data(), "unexpected end of CIE");
anatofuz
parents:
diff changeset
85 uint8_t b = d.front();
anatofuz
parents:
diff changeset
86 d = d.slice(1);
anatofuz
parents:
diff changeset
87 return b;
anatofuz
parents:
diff changeset
88 }
anatofuz
parents:
diff changeset
89
anatofuz
parents:
diff changeset
90 void EhReader::skipBytes(size_t count) {
anatofuz
parents:
diff changeset
91 if (d.size() < count)
anatofuz
parents:
diff changeset
92 failOn(d.data(), "CIE is too small");
anatofuz
parents:
diff changeset
93 d = d.slice(count);
anatofuz
parents:
diff changeset
94 }
anatofuz
parents:
diff changeset
95
anatofuz
parents:
diff changeset
96 // Read a null-terminated string.
anatofuz
parents:
diff changeset
97 StringRef EhReader::readString() {
anatofuz
parents:
diff changeset
98 const uint8_t *end = llvm::find(d, '\0');
anatofuz
parents:
diff changeset
99 if (end == d.end())
anatofuz
parents:
diff changeset
100 failOn(d.data(), "corrupted CIE (failed to read string)");
anatofuz
parents:
diff changeset
101 StringRef s = toStringRef(d.slice(0, end - d.begin()));
anatofuz
parents:
diff changeset
102 d = d.slice(s.size() + 1);
anatofuz
parents:
diff changeset
103 return s;
anatofuz
parents:
diff changeset
104 }
anatofuz
parents:
diff changeset
105
anatofuz
parents:
diff changeset
106 // Skip an integer encoded in the LEB128 format.
anatofuz
parents:
diff changeset
107 // Actual number is not of interest because only the runtime needs it.
anatofuz
parents:
diff changeset
108 // But we need to be at least able to skip it so that we can read
anatofuz
parents:
diff changeset
109 // the field that follows a LEB128 number.
anatofuz
parents:
diff changeset
110 void EhReader::skipLeb128() {
anatofuz
parents:
diff changeset
111 const uint8_t *errPos = d.data();
anatofuz
parents:
diff changeset
112 while (!d.empty()) {
anatofuz
parents:
diff changeset
113 uint8_t val = d.front();
anatofuz
parents:
diff changeset
114 d = d.slice(1);
anatofuz
parents:
diff changeset
115 if ((val & 0x80) == 0)
anatofuz
parents:
diff changeset
116 return;
anatofuz
parents:
diff changeset
117 }
anatofuz
parents:
diff changeset
118 failOn(errPos, "corrupted CIE (failed to read LEB128)");
anatofuz
parents:
diff changeset
119 }
anatofuz
parents:
diff changeset
120
anatofuz
parents:
diff changeset
121 static size_t getAugPSize(unsigned enc) {
anatofuz
parents:
diff changeset
122 switch (enc & 0x0f) {
anatofuz
parents:
diff changeset
123 case DW_EH_PE_absptr:
anatofuz
parents:
diff changeset
124 case DW_EH_PE_signed:
anatofuz
parents:
diff changeset
125 return config->wordsize;
anatofuz
parents:
diff changeset
126 case DW_EH_PE_udata2:
anatofuz
parents:
diff changeset
127 case DW_EH_PE_sdata2:
anatofuz
parents:
diff changeset
128 return 2;
anatofuz
parents:
diff changeset
129 case DW_EH_PE_udata4:
anatofuz
parents:
diff changeset
130 case DW_EH_PE_sdata4:
anatofuz
parents:
diff changeset
131 return 4;
anatofuz
parents:
diff changeset
132 case DW_EH_PE_udata8:
anatofuz
parents:
diff changeset
133 case DW_EH_PE_sdata8:
anatofuz
parents:
diff changeset
134 return 8;
anatofuz
parents:
diff changeset
135 }
anatofuz
parents:
diff changeset
136 return 0;
anatofuz
parents:
diff changeset
137 }
anatofuz
parents:
diff changeset
138
anatofuz
parents:
diff changeset
139 void EhReader::skipAugP() {
anatofuz
parents:
diff changeset
140 uint8_t enc = readByte();
anatofuz
parents:
diff changeset
141 if ((enc & 0xf0) == DW_EH_PE_aligned)
anatofuz
parents:
diff changeset
142 failOn(d.data() - 1, "DW_EH_PE_aligned encoding is not supported");
anatofuz
parents:
diff changeset
143 size_t size = getAugPSize(enc);
anatofuz
parents:
diff changeset
144 if (size == 0)
anatofuz
parents:
diff changeset
145 failOn(d.data() - 1, "unknown FDE encoding");
anatofuz
parents:
diff changeset
146 if (size >= d.size())
anatofuz
parents:
diff changeset
147 failOn(d.data() - 1, "corrupted CIE");
anatofuz
parents:
diff changeset
148 d = d.slice(size);
anatofuz
parents:
diff changeset
149 }
anatofuz
parents:
diff changeset
150
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
151 uint8_t elf::getFdeEncoding(EhSectionPiece *p) {
150
anatofuz
parents:
diff changeset
152 return EhReader(p->sec, p->data()).getFdeEncoding();
anatofuz
parents:
diff changeset
153 }
anatofuz
parents:
diff changeset
154
anatofuz
parents:
diff changeset
155 uint8_t EhReader::getFdeEncoding() {
anatofuz
parents:
diff changeset
156 skipBytes(8);
anatofuz
parents:
diff changeset
157 int version = readByte();
anatofuz
parents:
diff changeset
158 if (version != 1 && version != 3)
anatofuz
parents:
diff changeset
159 failOn(d.data() - 1,
anatofuz
parents:
diff changeset
160 "FDE version 1 or 3 expected, but got " + Twine(version));
anatofuz
parents:
diff changeset
161
anatofuz
parents:
diff changeset
162 StringRef aug = readString();
anatofuz
parents:
diff changeset
163
anatofuz
parents:
diff changeset
164 // Skip code and data alignment factors.
anatofuz
parents:
diff changeset
165 skipLeb128();
anatofuz
parents:
diff changeset
166 skipLeb128();
anatofuz
parents:
diff changeset
167
anatofuz
parents:
diff changeset
168 // Skip the return address register. In CIE version 1 this is a single
anatofuz
parents:
diff changeset
169 // byte. In CIE version 3 this is an unsigned LEB128.
anatofuz
parents:
diff changeset
170 if (version == 1)
anatofuz
parents:
diff changeset
171 readByte();
anatofuz
parents:
diff changeset
172 else
anatofuz
parents:
diff changeset
173 skipLeb128();
anatofuz
parents:
diff changeset
174
anatofuz
parents:
diff changeset
175 // We only care about an 'R' value, but other records may precede an 'R'
anatofuz
parents:
diff changeset
176 // record. Unfortunately records are not in TLV (type-length-value) format,
anatofuz
parents:
diff changeset
177 // so we need to teach the linker how to skip records for each type.
anatofuz
parents:
diff changeset
178 for (char c : aug) {
anatofuz
parents:
diff changeset
179 if (c == 'R')
anatofuz
parents:
diff changeset
180 return readByte();
anatofuz
parents:
diff changeset
181 if (c == 'z') {
anatofuz
parents:
diff changeset
182 skipLeb128();
anatofuz
parents:
diff changeset
183 continue;
anatofuz
parents:
diff changeset
184 }
anatofuz
parents:
diff changeset
185 if (c == 'P') {
anatofuz
parents:
diff changeset
186 skipAugP();
anatofuz
parents:
diff changeset
187 continue;
anatofuz
parents:
diff changeset
188 }
anatofuz
parents:
diff changeset
189 if (c == 'L') {
anatofuz
parents:
diff changeset
190 readByte();
anatofuz
parents:
diff changeset
191 continue;
anatofuz
parents:
diff changeset
192 }
anatofuz
parents:
diff changeset
193 failOn(aug.data(), "unknown .eh_frame augmentation string: " + aug);
anatofuz
parents:
diff changeset
194 }
anatofuz
parents:
diff changeset
195 return DW_EH_PE_absptr;
anatofuz
parents:
diff changeset
196 }