Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/LowLevel/DWARFUnwindTable.cpp
213845 views
1
//===----------------------------------------------------------------------===//
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 "llvm/DebugInfo/DWARF/LowLevel/DWARFUnwindTable.h"
10
#include "llvm/Support/Errc.h"
11
#include "llvm/Support/ErrorHandling.h"
12
#include "llvm/Support/raw_ostream.h"
13
#include <cassert>
14
#include <cinttypes>
15
#include <cstdint>
16
#include <optional>
17
18
using namespace llvm;
19
using namespace dwarf;
20
21
UnwindLocation UnwindLocation::createUnspecified() { return {Unspecified}; }
22
23
UnwindLocation UnwindLocation::createUndefined() { return {Undefined}; }
24
25
UnwindLocation UnwindLocation::createSame() { return {Same}; }
26
27
UnwindLocation UnwindLocation::createIsConstant(int32_t Value) {
28
return {Constant, InvalidRegisterNumber, Value, std::nullopt, false};
29
}
30
31
UnwindLocation UnwindLocation::createIsCFAPlusOffset(int32_t Offset) {
32
return {CFAPlusOffset, InvalidRegisterNumber, Offset, std::nullopt, false};
33
}
34
35
UnwindLocation UnwindLocation::createAtCFAPlusOffset(int32_t Offset) {
36
return {CFAPlusOffset, InvalidRegisterNumber, Offset, std::nullopt, true};
37
}
38
39
UnwindLocation
40
UnwindLocation::createIsRegisterPlusOffset(uint32_t RegNum, int32_t Offset,
41
std::optional<uint32_t> AddrSpace) {
42
return {RegPlusOffset, RegNum, Offset, AddrSpace, false};
43
}
44
45
UnwindLocation
46
UnwindLocation::createAtRegisterPlusOffset(uint32_t RegNum, int32_t Offset,
47
std::optional<uint32_t> AddrSpace) {
48
return {RegPlusOffset, RegNum, Offset, AddrSpace, true};
49
}
50
51
UnwindLocation UnwindLocation::createIsDWARFExpression(DWARFExpression Expr) {
52
return {Expr, false};
53
}
54
55
UnwindLocation UnwindLocation::createAtDWARFExpression(DWARFExpression Expr) {
56
return {Expr, true};
57
}
58
59
bool UnwindLocation::operator==(const UnwindLocation &RHS) const {
60
if (Kind != RHS.Kind)
61
return false;
62
switch (Kind) {
63
case Unspecified:
64
case Undefined:
65
case Same:
66
return true;
67
case CFAPlusOffset:
68
return Offset == RHS.Offset && Dereference == RHS.Dereference;
69
case RegPlusOffset:
70
return RegNum == RHS.RegNum && Offset == RHS.Offset &&
71
Dereference == RHS.Dereference;
72
case DWARFExpr:
73
return *Expr == *RHS.Expr && Dereference == RHS.Dereference;
74
case Constant:
75
return Offset == RHS.Offset;
76
}
77
return false;
78
}
79
80
Expected<UnwindTable::RowContainer>
81
llvm::dwarf::parseRows(const CFIProgram &CFIP, UnwindRow &Row,
82
const RegisterLocations *InitialLocs) {
83
// All the unwinding rows parsed during processing of the CFI program.
84
UnwindTable::RowContainer Rows;
85
86
// State consists of CFA value and register locations.
87
std::vector<std::pair<UnwindLocation, RegisterLocations>> States;
88
for (const CFIProgram::Instruction &Inst : CFIP) {
89
switch (Inst.Opcode) {
90
case dwarf::DW_CFA_set_loc: {
91
// The DW_CFA_set_loc instruction takes a single operand that
92
// represents a target address. The required action is to create a new
93
// table row using the specified address as the location. All other
94
// values in the new row are initially identical to the current row.
95
// The new location value is always greater than the current one. If
96
// the segment_size field of this FDE's CIE is non- zero, the initial
97
// location is preceded by a segment selector of the given length
98
llvm::Expected<uint64_t> NewAddress = Inst.getOperandAsUnsigned(CFIP, 0);
99
if (!NewAddress)
100
return NewAddress.takeError();
101
if (*NewAddress <= Row.getAddress())
102
return createStringError(
103
errc::invalid_argument,
104
"%s with adrress 0x%" PRIx64 " which must be greater than the "
105
"current row address 0x%" PRIx64,
106
CFIP.callFrameString(Inst.Opcode).str().c_str(), *NewAddress,
107
Row.getAddress());
108
Rows.push_back(Row);
109
Row.setAddress(*NewAddress);
110
break;
111
}
112
113
case dwarf::DW_CFA_advance_loc:
114
case dwarf::DW_CFA_advance_loc1:
115
case dwarf::DW_CFA_advance_loc2:
116
case dwarf::DW_CFA_advance_loc4: {
117
// The DW_CFA_advance instruction takes a single operand that
118
// represents a constant delta. The required action is to create a new
119
// table row with a location value that is computed by taking the
120
// current entry’s location value and adding the value of delta *
121
// code_alignment_factor. All other values in the new row are initially
122
// identical to the current row.
123
Rows.push_back(Row);
124
llvm::Expected<uint64_t> Offset = Inst.getOperandAsUnsigned(CFIP, 0);
125
if (!Offset)
126
return Offset.takeError();
127
Row.slideAddress(*Offset);
128
break;
129
}
130
131
case dwarf::DW_CFA_restore:
132
case dwarf::DW_CFA_restore_extended: {
133
// The DW_CFA_restore instruction takes a single operand (encoded with
134
// the opcode) that represents a register number. The required action
135
// is to change the rule for the indicated register to the rule
136
// assigned it by the initial_instructions in the CIE.
137
if (InitialLocs == nullptr)
138
return createStringError(
139
errc::invalid_argument, "%s encountered while parsing a CIE",
140
CFIP.callFrameString(Inst.Opcode).str().c_str());
141
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
142
if (!RegNum)
143
return RegNum.takeError();
144
if (std::optional<UnwindLocation> O =
145
InitialLocs->getRegisterLocation(*RegNum))
146
Row.getRegisterLocations().setRegisterLocation(*RegNum, *O);
147
else
148
Row.getRegisterLocations().removeRegisterLocation(*RegNum);
149
break;
150
}
151
152
case dwarf::DW_CFA_offset:
153
case dwarf::DW_CFA_offset_extended:
154
case dwarf::DW_CFA_offset_extended_sf: {
155
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
156
if (!RegNum)
157
return RegNum.takeError();
158
llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
159
if (!Offset)
160
return Offset.takeError();
161
Row.getRegisterLocations().setRegisterLocation(
162
*RegNum, UnwindLocation::createAtCFAPlusOffset(*Offset));
163
break;
164
}
165
166
case dwarf::DW_CFA_nop:
167
break;
168
169
case dwarf::DW_CFA_remember_state:
170
States.push_back(
171
std::make_pair(Row.getCFAValue(), Row.getRegisterLocations()));
172
break;
173
174
case dwarf::DW_CFA_restore_state:
175
if (States.empty())
176
return createStringError(errc::invalid_argument,
177
"DW_CFA_restore_state without a matching "
178
"previous DW_CFA_remember_state");
179
Row.getCFAValue() = States.back().first;
180
Row.getRegisterLocations() = States.back().second;
181
States.pop_back();
182
break;
183
184
case dwarf::DW_CFA_GNU_window_save:
185
switch (CFIP.triple()) {
186
case Triple::aarch64:
187
case Triple::aarch64_be:
188
case Triple::aarch64_32: {
189
// DW_CFA_GNU_window_save is used for different things on different
190
// architectures. For aarch64 it is known as
191
// DW_CFA_AARCH64_negate_ra_state. The action is to toggle the
192
// value of the return address state between 1 and 0. If there is
193
// no rule for the AARCH64_DWARF_PAUTH_RA_STATE register, then it
194
// should be initially set to 1.
195
constexpr uint32_t AArch64DWARFPAuthRaState = 34;
196
auto LRLoc = Row.getRegisterLocations().getRegisterLocation(
197
AArch64DWARFPAuthRaState);
198
if (LRLoc) {
199
if (LRLoc->getLocation() == UnwindLocation::Constant) {
200
// Toggle the constant value from 0 to 1 or 1 to 0.
201
LRLoc->setConstant(LRLoc->getConstant() ^ 1);
202
Row.getRegisterLocations().setRegisterLocation(
203
AArch64DWARFPAuthRaState, *LRLoc);
204
} else {
205
return createStringError(
206
errc::invalid_argument,
207
"%s encountered when existing rule for this register is not "
208
"a constant",
209
CFIP.callFrameString(Inst.Opcode).str().c_str());
210
}
211
} else {
212
Row.getRegisterLocations().setRegisterLocation(
213
AArch64DWARFPAuthRaState, UnwindLocation::createIsConstant(1));
214
}
215
break;
216
}
217
218
case Triple::sparc:
219
case Triple::sparcv9:
220
case Triple::sparcel:
221
for (uint32_t RegNum = 16; RegNum < 32; ++RegNum) {
222
Row.getRegisterLocations().setRegisterLocation(
223
RegNum, UnwindLocation::createAtCFAPlusOffset((RegNum - 16) * 8));
224
}
225
break;
226
227
default: {
228
return createStringError(
229
errc::not_supported,
230
"DW_CFA opcode %#x is not supported for architecture %s",
231
Inst.Opcode, Triple::getArchTypeName(CFIP.triple()).str().c_str());
232
233
break;
234
}
235
}
236
break;
237
238
case dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc: {
239
constexpr uint32_t AArch64DWARFPAuthRaState = 34;
240
auto LRLoc = Row.getRegisterLocations().getRegisterLocation(
241
AArch64DWARFPAuthRaState);
242
if (LRLoc) {
243
if (LRLoc->getLocation() == UnwindLocation::Constant) {
244
// Toggle the constant value of bits[1:0] from 0 to 1 or 1 to 0.
245
LRLoc->setConstant(LRLoc->getConstant() ^ 0x3);
246
} else {
247
return createStringError(
248
errc::invalid_argument,
249
"%s encountered when existing rule for this register is not "
250
"a constant",
251
CFIP.callFrameString(Inst.Opcode).str().c_str());
252
}
253
} else {
254
Row.getRegisterLocations().setRegisterLocation(
255
AArch64DWARFPAuthRaState, UnwindLocation::createIsConstant(0x3));
256
}
257
break;
258
}
259
260
case dwarf::DW_CFA_undefined: {
261
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
262
if (!RegNum)
263
return RegNum.takeError();
264
Row.getRegisterLocations().setRegisterLocation(
265
*RegNum, UnwindLocation::createUndefined());
266
break;
267
}
268
269
case dwarf::DW_CFA_same_value: {
270
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
271
if (!RegNum)
272
return RegNum.takeError();
273
Row.getRegisterLocations().setRegisterLocation(
274
*RegNum, UnwindLocation::createSame());
275
break;
276
}
277
278
case dwarf::DW_CFA_GNU_args_size:
279
break;
280
281
case dwarf::DW_CFA_register: {
282
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
283
if (!RegNum)
284
return RegNum.takeError();
285
llvm::Expected<uint64_t> NewRegNum = Inst.getOperandAsUnsigned(CFIP, 1);
286
if (!NewRegNum)
287
return NewRegNum.takeError();
288
Row.getRegisterLocations().setRegisterLocation(
289
*RegNum, UnwindLocation::createIsRegisterPlusOffset(*NewRegNum, 0));
290
break;
291
}
292
293
case dwarf::DW_CFA_val_offset:
294
case dwarf::DW_CFA_val_offset_sf: {
295
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
296
if (!RegNum)
297
return RegNum.takeError();
298
llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
299
if (!Offset)
300
return Offset.takeError();
301
Row.getRegisterLocations().setRegisterLocation(
302
*RegNum, UnwindLocation::createIsCFAPlusOffset(*Offset));
303
break;
304
}
305
306
case dwarf::DW_CFA_expression: {
307
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
308
if (!RegNum)
309
return RegNum.takeError();
310
Row.getRegisterLocations().setRegisterLocation(
311
*RegNum, UnwindLocation::createAtDWARFExpression(*Inst.Expression));
312
break;
313
}
314
315
case dwarf::DW_CFA_val_expression: {
316
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
317
if (!RegNum)
318
return RegNum.takeError();
319
Row.getRegisterLocations().setRegisterLocation(
320
*RegNum, UnwindLocation::createIsDWARFExpression(*Inst.Expression));
321
break;
322
}
323
324
case dwarf::DW_CFA_def_cfa_register: {
325
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
326
if (!RegNum)
327
return RegNum.takeError();
328
if (Row.getCFAValue().getLocation() != UnwindLocation::RegPlusOffset)
329
Row.getCFAValue() =
330
UnwindLocation::createIsRegisterPlusOffset(*RegNum, 0);
331
else
332
Row.getCFAValue().setRegister(*RegNum);
333
break;
334
}
335
336
case dwarf::DW_CFA_def_cfa_offset:
337
case dwarf::DW_CFA_def_cfa_offset_sf: {
338
llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 0);
339
if (!Offset)
340
return Offset.takeError();
341
if (Row.getCFAValue().getLocation() != UnwindLocation::RegPlusOffset) {
342
return createStringError(
343
errc::invalid_argument,
344
"%s found when CFA rule was not RegPlusOffset",
345
CFIP.callFrameString(Inst.Opcode).str().c_str());
346
}
347
Row.getCFAValue().setOffset(*Offset);
348
break;
349
}
350
351
case dwarf::DW_CFA_def_cfa:
352
case dwarf::DW_CFA_def_cfa_sf: {
353
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
354
if (!RegNum)
355
return RegNum.takeError();
356
llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
357
if (!Offset)
358
return Offset.takeError();
359
Row.getCFAValue() =
360
UnwindLocation::createIsRegisterPlusOffset(*RegNum, *Offset);
361
break;
362
}
363
364
case dwarf::DW_CFA_LLVM_def_aspace_cfa:
365
case dwarf::DW_CFA_LLVM_def_aspace_cfa_sf: {
366
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
367
if (!RegNum)
368
return RegNum.takeError();
369
llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
370
if (!Offset)
371
return Offset.takeError();
372
llvm::Expected<uint32_t> CFAAddrSpace =
373
Inst.getOperandAsUnsigned(CFIP, 2);
374
if (!CFAAddrSpace)
375
return CFAAddrSpace.takeError();
376
Row.getCFAValue() = UnwindLocation::createIsRegisterPlusOffset(
377
*RegNum, *Offset, *CFAAddrSpace);
378
break;
379
}
380
381
case dwarf::DW_CFA_def_cfa_expression:
382
Row.getCFAValue() =
383
UnwindLocation::createIsDWARFExpression(*Inst.Expression);
384
break;
385
}
386
}
387
return Rows;
388
}
389
390