Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/libunwind/src/DwarfParser.hpp
35154 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
// Parses DWARF CFIs (FDEs and CIEs).
9
//
10
//===----------------------------------------------------------------------===//
11
12
#ifndef __DWARF_PARSER_HPP__
13
#define __DWARF_PARSER_HPP__
14
15
#include <inttypes.h>
16
#include <stdint.h>
17
#include <stdio.h>
18
#include <stdlib.h>
19
20
#include "libunwind.h"
21
#include "dwarf2.h"
22
#include "Registers.hpp"
23
24
#include "config.h"
25
26
namespace libunwind {
27
28
/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
29
/// See DWARF Spec for details:
30
/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
31
///
32
template <typename A>
33
class CFI_Parser {
34
public:
35
typedef typename A::pint_t pint_t;
36
37
/// Information encoded in a CIE (Common Information Entry)
38
struct CIE_Info {
39
pint_t cieStart;
40
pint_t cieLength;
41
pint_t cieInstructions;
42
uint8_t pointerEncoding;
43
uint8_t lsdaEncoding;
44
uint8_t personalityEncoding;
45
uint8_t personalityOffsetInCIE;
46
pint_t personality;
47
uint32_t codeAlignFactor;
48
int dataAlignFactor;
49
bool isSignalFrame;
50
bool fdesHaveAugmentationData;
51
uint8_t returnAddressRegister;
52
#if defined(_LIBUNWIND_TARGET_AARCH64)
53
bool addressesSignedWithBKey;
54
bool mteTaggedFrame;
55
#endif
56
};
57
58
/// Information about an FDE (Frame Description Entry)
59
struct FDE_Info {
60
pint_t fdeStart;
61
pint_t fdeLength;
62
pint_t fdeInstructions;
63
pint_t pcStart;
64
pint_t pcEnd;
65
pint_t lsda;
66
};
67
68
enum {
69
kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
70
};
71
enum RegisterSavedWhere {
72
kRegisterUnused,
73
kRegisterInCFA,
74
kRegisterInCFADecrypt, // sparc64 specific
75
kRegisterOffsetFromCFA,
76
kRegisterInRegister,
77
kRegisterAtExpression,
78
kRegisterIsExpression
79
};
80
struct RegisterLocation {
81
RegisterSavedWhere location;
82
bool initialStateSaved;
83
int64_t value;
84
};
85
/// Information about a frame layout and registers saved determined
86
/// by "running" the DWARF FDE "instructions"
87
struct PrologInfo {
88
uint32_t cfaRegister;
89
int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
90
int64_t cfaExpression; // CFA = expression
91
uint32_t spExtraArgSize;
92
RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
93
enum class InitializeTime { kLazy, kNormal };
94
95
// When saving registers, this data structure is lazily initialized.
96
PrologInfo(InitializeTime IT = InitializeTime::kNormal) {
97
if (IT == InitializeTime::kNormal)
98
memset(this, 0, sizeof(*this));
99
}
100
void checkSaveRegister(uint64_t reg, PrologInfo &initialState) {
101
if (!savedRegisters[reg].initialStateSaved) {
102
initialState.savedRegisters[reg] = savedRegisters[reg];
103
savedRegisters[reg].initialStateSaved = true;
104
}
105
}
106
void setRegister(uint64_t reg, RegisterSavedWhere newLocation,
107
int64_t newValue, PrologInfo &initialState) {
108
checkSaveRegister(reg, initialState);
109
savedRegisters[reg].location = newLocation;
110
savedRegisters[reg].value = newValue;
111
}
112
void setRegisterLocation(uint64_t reg, RegisterSavedWhere newLocation,
113
PrologInfo &initialState) {
114
checkSaveRegister(reg, initialState);
115
savedRegisters[reg].location = newLocation;
116
}
117
void setRegisterValue(uint64_t reg, int64_t newValue,
118
PrologInfo &initialState) {
119
checkSaveRegister(reg, initialState);
120
savedRegisters[reg].value = newValue;
121
}
122
void restoreRegisterToInitialState(uint64_t reg, PrologInfo &initialState) {
123
if (savedRegisters[reg].initialStateSaved)
124
savedRegisters[reg] = initialState.savedRegisters[reg];
125
// else the register still holds its initial state
126
}
127
};
128
129
struct PrologInfoStackEntry {
130
PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
131
: next(n), info(i) {}
132
PrologInfoStackEntry *next;
133
PrologInfo info;
134
};
135
136
struct RememberStack {
137
PrologInfoStackEntry *entry;
138
RememberStack() : entry(nullptr) {}
139
~RememberStack() {
140
#if defined(_LIBUNWIND_REMEMBER_CLEANUP_NEEDED)
141
// Clean up rememberStack. Even in the case where every
142
// DW_CFA_remember_state is paired with a DW_CFA_restore_state,
143
// parseInstructions can skip restore opcodes if it reaches the target PC
144
// and stops interpreting, so we have to make sure we don't leak memory.
145
while (entry) {
146
PrologInfoStackEntry *next = entry->next;
147
_LIBUNWIND_REMEMBER_FREE(entry);
148
entry = next;
149
}
150
#endif
151
}
152
};
153
154
static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
155
size_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
156
CIE_Info *cieInfo);
157
static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
158
FDE_Info *fdeInfo, CIE_Info *cieInfo,
159
bool useCIEInfo = false);
160
static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
161
const CIE_Info &cieInfo, pint_t upToPC,
162
int arch, PrologInfo *results);
163
164
static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
165
};
166
167
/// Parse a FDE into a CIE_Info and an FDE_Info. If useCIEInfo is
168
/// true, treat cieInfo as already-parsed CIE_Info (whose start offset
169
/// must match the one specified by the FDE) rather than parsing the
170
/// one indicated within the FDE.
171
template <typename A>
172
const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
173
FDE_Info *fdeInfo, CIE_Info *cieInfo,
174
bool useCIEInfo) {
175
pint_t p = fdeStart;
176
pint_t cfiLength = (pint_t)addressSpace.get32(p);
177
p += 4;
178
if (cfiLength == 0xffffffff) {
179
// 0xffffffff means length is really next 8 bytes
180
cfiLength = (pint_t)addressSpace.get64(p);
181
p += 8;
182
}
183
if (cfiLength == 0)
184
return "FDE has zero length"; // zero terminator
185
uint32_t ciePointer = addressSpace.get32(p);
186
if (ciePointer == 0)
187
return "FDE is really a CIE"; // this is a CIE not an FDE
188
pint_t nextCFI = p + cfiLength;
189
pint_t cieStart = p - ciePointer;
190
if (useCIEInfo) {
191
if (cieInfo->cieStart != cieStart)
192
return "CIE start does not match";
193
} else {
194
const char *err = parseCIE(addressSpace, cieStart, cieInfo);
195
if (err != NULL)
196
return err;
197
}
198
p += 4;
199
// Parse pc begin and range.
200
pint_t pcStart =
201
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
202
pint_t pcRange =
203
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
204
// Parse rest of info.
205
fdeInfo->lsda = 0;
206
// Check for augmentation length.
207
if (cieInfo->fdesHaveAugmentationData) {
208
pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
209
pint_t endOfAug = p + augLen;
210
if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
211
// Peek at value (without indirection). Zero means no LSDA.
212
pint_t lsdaStart = p;
213
if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
214
0) {
215
// Reset pointer and re-parse LSDA address.
216
p = lsdaStart;
217
fdeInfo->lsda =
218
addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
219
}
220
}
221
p = endOfAug;
222
}
223
fdeInfo->fdeStart = fdeStart;
224
fdeInfo->fdeLength = nextCFI - fdeStart;
225
fdeInfo->fdeInstructions = p;
226
fdeInfo->pcStart = pcStart;
227
fdeInfo->pcEnd = pcStart + pcRange;
228
return NULL; // success
229
}
230
231
/// Scan an eh_frame section to find an FDE for a pc
232
template <typename A>
233
bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
234
size_t sectionLength, pint_t fdeHint,
235
FDE_Info *fdeInfo, CIE_Info *cieInfo) {
236
//fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
237
pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
238
const pint_t ehSectionEnd = (sectionLength == SIZE_MAX)
239
? static_cast<pint_t>(-1)
240
: (ehSectionStart + sectionLength);
241
while (p < ehSectionEnd) {
242
pint_t currentCFI = p;
243
//fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
244
pint_t cfiLength = addressSpace.get32(p);
245
p += 4;
246
if (cfiLength == 0xffffffff) {
247
// 0xffffffff means length is really next 8 bytes
248
cfiLength = (pint_t)addressSpace.get64(p);
249
p += 8;
250
}
251
if (cfiLength == 0)
252
return false; // zero terminator
253
uint32_t id = addressSpace.get32(p);
254
if (id == 0) {
255
// Skip over CIEs.
256
p += cfiLength;
257
} else {
258
// Process FDE to see if it covers pc.
259
pint_t nextCFI = p + cfiLength;
260
uint32_t ciePointer = addressSpace.get32(p);
261
pint_t cieStart = p - ciePointer;
262
// Validate pointer to CIE is within section.
263
if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
264
if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
265
p += 4;
266
// Parse pc begin and range.
267
pint_t pcStart =
268
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
269
pint_t pcRange = addressSpace.getEncodedP(
270
p, nextCFI, cieInfo->pointerEncoding & 0x0F);
271
// Test if pc is within the function this FDE covers.
272
if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
273
// parse rest of info
274
fdeInfo->lsda = 0;
275
// check for augmentation length
276
if (cieInfo->fdesHaveAugmentationData) {
277
pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
278
pint_t endOfAug = p + augLen;
279
if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
280
// Peek at value (without indirection). Zero means no LSDA.
281
pint_t lsdaStart = p;
282
if (addressSpace.getEncodedP(
283
p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
284
// Reset pointer and re-parse LSDA address.
285
p = lsdaStart;
286
fdeInfo->lsda = addressSpace
287
.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
288
}
289
}
290
p = endOfAug;
291
}
292
fdeInfo->fdeStart = currentCFI;
293
fdeInfo->fdeLength = nextCFI - currentCFI;
294
fdeInfo->fdeInstructions = p;
295
fdeInfo->pcStart = pcStart;
296
fdeInfo->pcEnd = pcStart + pcRange;
297
return true;
298
} else {
299
// pc is not in begin/range, skip this FDE
300
}
301
} else {
302
// Malformed CIE, now augmentation describing pc range encoding.
303
}
304
} else {
305
// malformed FDE. CIE is bad
306
}
307
p = nextCFI;
308
}
309
}
310
return false;
311
}
312
313
/// Extract info from a CIE
314
template <typename A>
315
const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
316
CIE_Info *cieInfo) {
317
cieInfo->pointerEncoding = 0;
318
cieInfo->lsdaEncoding = DW_EH_PE_omit;
319
cieInfo->personalityEncoding = 0;
320
cieInfo->personalityOffsetInCIE = 0;
321
cieInfo->personality = 0;
322
cieInfo->codeAlignFactor = 0;
323
cieInfo->dataAlignFactor = 0;
324
cieInfo->isSignalFrame = false;
325
cieInfo->fdesHaveAugmentationData = false;
326
#if defined(_LIBUNWIND_TARGET_AARCH64)
327
cieInfo->addressesSignedWithBKey = false;
328
cieInfo->mteTaggedFrame = false;
329
#endif
330
cieInfo->cieStart = cie;
331
pint_t p = cie;
332
pint_t cieLength = (pint_t)addressSpace.get32(p);
333
p += 4;
334
pint_t cieContentEnd = p + cieLength;
335
if (cieLength == 0xffffffff) {
336
// 0xffffffff means length is really next 8 bytes
337
cieLength = (pint_t)addressSpace.get64(p);
338
p += 8;
339
cieContentEnd = p + cieLength;
340
}
341
if (cieLength == 0)
342
return NULL;
343
// CIE ID is always 0
344
if (addressSpace.get32(p) != 0)
345
return "CIE ID is not zero";
346
p += 4;
347
// Version is always 1 or 3
348
uint8_t version = addressSpace.get8(p);
349
if ((version != 1) && (version != 3))
350
return "CIE version is not 1 or 3";
351
++p;
352
// save start of augmentation string and find end
353
pint_t strStart = p;
354
while (addressSpace.get8(p) != 0)
355
++p;
356
++p;
357
// parse code alignment factor
358
cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
359
// parse data alignment factor
360
cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
361
// parse return address register
362
uint64_t raReg = (version == 1) ? addressSpace.get8(p++)
363
: addressSpace.getULEB128(p, cieContentEnd);
364
assert(raReg < 255 && "return address register too large");
365
cieInfo->returnAddressRegister = (uint8_t)raReg;
366
// parse augmentation data based on augmentation string
367
const char *result = NULL;
368
if (addressSpace.get8(strStart) == 'z') {
369
// parse augmentation data length
370
addressSpace.getULEB128(p, cieContentEnd);
371
for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
372
switch (addressSpace.get8(s)) {
373
case 'z':
374
cieInfo->fdesHaveAugmentationData = true;
375
break;
376
case 'P':
377
cieInfo->personalityEncoding = addressSpace.get8(p);
378
++p;
379
cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
380
cieInfo->personality = addressSpace
381
.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
382
break;
383
case 'L':
384
cieInfo->lsdaEncoding = addressSpace.get8(p);
385
++p;
386
break;
387
case 'R':
388
cieInfo->pointerEncoding = addressSpace.get8(p);
389
++p;
390
break;
391
case 'S':
392
cieInfo->isSignalFrame = true;
393
break;
394
#if defined(_LIBUNWIND_TARGET_AARCH64)
395
case 'B':
396
cieInfo->addressesSignedWithBKey = true;
397
break;
398
case 'G':
399
cieInfo->mteTaggedFrame = true;
400
break;
401
#endif
402
default:
403
// ignore unknown letters
404
break;
405
}
406
}
407
}
408
cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
409
cieInfo->cieInstructions = p;
410
return result;
411
}
412
413
414
/// "run" the DWARF instructions and create the abstract PrologInfo for an FDE
415
template <typename A>
416
bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
417
const FDE_Info &fdeInfo,
418
const CIE_Info &cieInfo, pint_t upToPC,
419
int arch, PrologInfo *results) {
420
// Alloca is used for the allocation of the rememberStack entries. It removes
421
// the dependency on new/malloc but the below for loop can not be refactored
422
// into functions. Entry could be saved during the processing of a CIE and
423
// restored by an FDE.
424
RememberStack rememberStack;
425
426
struct ParseInfo {
427
pint_t instructions;
428
pint_t instructionsEnd;
429
pint_t pcoffset;
430
};
431
432
ParseInfo parseInfoArray[] = {
433
{cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength,
434
(pint_t)(-1)},
435
{fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength,
436
upToPC - fdeInfo.pcStart}};
437
438
for (const auto &info : parseInfoArray) {
439
pint_t p = info.instructions;
440
pint_t instructionsEnd = info.instructionsEnd;
441
pint_t pcoffset = info.pcoffset;
442
pint_t codeOffset = 0;
443
444
// initialState initialized as registers in results are modified. Use
445
// PrologInfo accessor functions to avoid reading uninitialized data.
446
PrologInfo initialState(PrologInfo::InitializeTime::kLazy);
447
448
_LIBUNWIND_TRACE_DWARF("parseFDEInstructions(instructions=0x%0" PRIx64
449
")\n",
450
static_cast<uint64_t>(instructionsEnd));
451
452
// see DWARF Spec, section 6.4.2 for details on unwind opcodes
453
while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
454
uint64_t reg;
455
uint64_t reg2;
456
int64_t offset;
457
uint64_t length;
458
uint8_t opcode = addressSpace.get8(p);
459
uint8_t operand;
460
461
++p;
462
switch (opcode) {
463
case DW_CFA_nop:
464
_LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
465
break;
466
case DW_CFA_set_loc:
467
codeOffset = addressSpace.getEncodedP(p, instructionsEnd,
468
cieInfo.pointerEncoding);
469
_LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
470
break;
471
case DW_CFA_advance_loc1:
472
codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
473
p += 1;
474
_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
475
static_cast<uint64_t>(codeOffset));
476
break;
477
case DW_CFA_advance_loc2:
478
codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
479
p += 2;
480
_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
481
static_cast<uint64_t>(codeOffset));
482
break;
483
case DW_CFA_advance_loc4:
484
codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
485
p += 4;
486
_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
487
static_cast<uint64_t>(codeOffset));
488
break;
489
case DW_CFA_offset_extended:
490
reg = addressSpace.getULEB128(p, instructionsEnd);
491
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
492
cieInfo.dataAlignFactor;
493
if (reg > kMaxRegisterNumber) {
494
_LIBUNWIND_LOG0(
495
"malformed DW_CFA_offset_extended DWARF unwind, reg too big");
496
return false;
497
}
498
results->setRegister(reg, kRegisterInCFA, offset, initialState);
499
_LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
500
"offset=%" PRId64 ")\n",
501
reg, offset);
502
break;
503
case DW_CFA_restore_extended:
504
reg = addressSpace.getULEB128(p, instructionsEnd);
505
if (reg > kMaxRegisterNumber) {
506
_LIBUNWIND_LOG0(
507
"malformed DW_CFA_restore_extended DWARF unwind, reg too big");
508
return false;
509
}
510
results->restoreRegisterToInitialState(reg, initialState);
511
_LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n",
512
reg);
513
break;
514
case DW_CFA_undefined:
515
reg = addressSpace.getULEB128(p, instructionsEnd);
516
if (reg > kMaxRegisterNumber) {
517
_LIBUNWIND_LOG0(
518
"malformed DW_CFA_undefined DWARF unwind, reg too big");
519
return false;
520
}
521
results->setRegisterLocation(reg, kRegisterUnused, initialState);
522
_LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
523
break;
524
case DW_CFA_same_value:
525
reg = addressSpace.getULEB128(p, instructionsEnd);
526
if (reg > kMaxRegisterNumber) {
527
_LIBUNWIND_LOG0(
528
"malformed DW_CFA_same_value DWARF unwind, reg too big");
529
return false;
530
}
531
// <rdar://problem/8456377> DW_CFA_same_value unsupported
532
// "same value" means register was stored in frame, but its current
533
// value has not changed, so no need to restore from frame.
534
// We model this as if the register was never saved.
535
results->setRegisterLocation(reg, kRegisterUnused, initialState);
536
_LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
537
break;
538
case DW_CFA_register:
539
reg = addressSpace.getULEB128(p, instructionsEnd);
540
reg2 = addressSpace.getULEB128(p, instructionsEnd);
541
if (reg > kMaxRegisterNumber) {
542
_LIBUNWIND_LOG0(
543
"malformed DW_CFA_register DWARF unwind, reg too big");
544
return false;
545
}
546
if (reg2 > kMaxRegisterNumber) {
547
_LIBUNWIND_LOG0(
548
"malformed DW_CFA_register DWARF unwind, reg2 too big");
549
return false;
550
}
551
results->setRegister(reg, kRegisterInRegister, (int64_t)reg2,
552
initialState);
553
_LIBUNWIND_TRACE_DWARF(
554
"DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
555
break;
556
case DW_CFA_remember_state: {
557
// Avoid operator new because that would be an upward dependency.
558
// Avoid malloc because it needs heap allocation.
559
PrologInfoStackEntry *entry =
560
(PrologInfoStackEntry *)_LIBUNWIND_REMEMBER_ALLOC(
561
sizeof(PrologInfoStackEntry));
562
if (entry != NULL) {
563
entry->next = rememberStack.entry;
564
entry->info = *results;
565
rememberStack.entry = entry;
566
} else {
567
return false;
568
}
569
_LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
570
break;
571
}
572
case DW_CFA_restore_state:
573
if (rememberStack.entry != NULL) {
574
PrologInfoStackEntry *top = rememberStack.entry;
575
*results = top->info;
576
rememberStack.entry = top->next;
577
_LIBUNWIND_REMEMBER_FREE(top);
578
} else {
579
return false;
580
}
581
_LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
582
break;
583
case DW_CFA_def_cfa:
584
reg = addressSpace.getULEB128(p, instructionsEnd);
585
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
586
if (reg > kMaxRegisterNumber) {
587
_LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
588
return false;
589
}
590
results->cfaRegister = (uint32_t)reg;
591
results->cfaRegisterOffset = (int32_t)offset;
592
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64
593
")\n",
594
reg, offset);
595
break;
596
case DW_CFA_def_cfa_register:
597
reg = addressSpace.getULEB128(p, instructionsEnd);
598
if (reg > kMaxRegisterNumber) {
599
_LIBUNWIND_LOG0(
600
"malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
601
return false;
602
}
603
results->cfaRegister = (uint32_t)reg;
604
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
605
break;
606
case DW_CFA_def_cfa_offset:
607
results->cfaRegisterOffset =
608
(int32_t)addressSpace.getULEB128(p, instructionsEnd);
609
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
610
results->cfaRegisterOffset);
611
break;
612
case DW_CFA_def_cfa_expression:
613
results->cfaRegister = 0;
614
results->cfaExpression = (int64_t)p;
615
length = addressSpace.getULEB128(p, instructionsEnd);
616
assert(length < static_cast<pint_t>(~0) && "pointer overflow");
617
p += static_cast<pint_t>(length);
618
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
619
", length=%" PRIu64 ")\n",
620
results->cfaExpression, length);
621
break;
622
case DW_CFA_expression:
623
reg = addressSpace.getULEB128(p, instructionsEnd);
624
if (reg > kMaxRegisterNumber) {
625
_LIBUNWIND_LOG0(
626
"malformed DW_CFA_expression DWARF unwind, reg too big");
627
return false;
628
}
629
results->setRegister(reg, kRegisterAtExpression, (int64_t)p,
630
initialState);
631
length = addressSpace.getULEB128(p, instructionsEnd);
632
assert(length < static_cast<pint_t>(~0) && "pointer overflow");
633
p += static_cast<pint_t>(length);
634
_LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
635
"expression=0x%" PRIx64 ", "
636
"length=%" PRIu64 ")\n",
637
reg, results->savedRegisters[reg].value, length);
638
break;
639
case DW_CFA_offset_extended_sf:
640
reg = addressSpace.getULEB128(p, instructionsEnd);
641
if (reg > kMaxRegisterNumber) {
642
_LIBUNWIND_LOG0(
643
"malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
644
return false;
645
}
646
offset = addressSpace.getSLEB128(p, instructionsEnd) *
647
cieInfo.dataAlignFactor;
648
results->setRegister(reg, kRegisterInCFA, offset, initialState);
649
_LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
650
"offset=%" PRId64 ")\n",
651
reg, offset);
652
break;
653
case DW_CFA_def_cfa_sf:
654
reg = addressSpace.getULEB128(p, instructionsEnd);
655
offset = addressSpace.getSLEB128(p, instructionsEnd) *
656
cieInfo.dataAlignFactor;
657
if (reg > kMaxRegisterNumber) {
658
_LIBUNWIND_LOG0(
659
"malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
660
return false;
661
}
662
results->cfaRegister = (uint32_t)reg;
663
results->cfaRegisterOffset = (int32_t)offset;
664
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
665
"offset=%" PRId64 ")\n",
666
reg, offset);
667
break;
668
case DW_CFA_def_cfa_offset_sf:
669
results->cfaRegisterOffset =
670
(int32_t)(addressSpace.getSLEB128(p, instructionsEnd) *
671
cieInfo.dataAlignFactor);
672
_LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
673
results->cfaRegisterOffset);
674
break;
675
case DW_CFA_val_offset:
676
reg = addressSpace.getULEB128(p, instructionsEnd);
677
if (reg > kMaxRegisterNumber) {
678
_LIBUNWIND_LOG(
679
"malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
680
") out of range\n",
681
reg);
682
return false;
683
}
684
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
685
cieInfo.dataAlignFactor;
686
results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
687
_LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
688
"offset=%" PRId64 "\n",
689
reg, offset);
690
break;
691
case DW_CFA_val_offset_sf:
692
reg = addressSpace.getULEB128(p, instructionsEnd);
693
if (reg > kMaxRegisterNumber) {
694
_LIBUNWIND_LOG0(
695
"malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
696
return false;
697
}
698
offset = addressSpace.getSLEB128(p, instructionsEnd) *
699
cieInfo.dataAlignFactor;
700
results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
701
_LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
702
"offset=%" PRId64 "\n",
703
reg, offset);
704
break;
705
case DW_CFA_val_expression:
706
reg = addressSpace.getULEB128(p, instructionsEnd);
707
if (reg > kMaxRegisterNumber) {
708
_LIBUNWIND_LOG0(
709
"malformed DW_CFA_val_expression DWARF unwind, reg too big");
710
return false;
711
}
712
results->setRegister(reg, kRegisterIsExpression, (int64_t)p,
713
initialState);
714
length = addressSpace.getULEB128(p, instructionsEnd);
715
assert(length < static_cast<pint_t>(~0) && "pointer overflow");
716
p += static_cast<pint_t>(length);
717
_LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
718
"expression=0x%" PRIx64 ", length=%" PRIu64
719
")\n",
720
reg, results->savedRegisters[reg].value, length);
721
break;
722
case DW_CFA_GNU_args_size:
723
length = addressSpace.getULEB128(p, instructionsEnd);
724
results->spExtraArgSize = (uint32_t)length;
725
_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
726
break;
727
case DW_CFA_GNU_negative_offset_extended:
728
reg = addressSpace.getULEB128(p, instructionsEnd);
729
if (reg > kMaxRegisterNumber) {
730
_LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
731
"unwind, reg too big");
732
return false;
733
}
734
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
735
cieInfo.dataAlignFactor;
736
results->setRegister(reg, kRegisterInCFA, -offset, initialState);
737
_LIBUNWIND_TRACE_DWARF(
738
"DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
739
break;
740
741
#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) || \
742
defined(_LIBUNWIND_TARGET_SPARC64)
743
// The same constant is used to represent different instructions on
744
// AArch64 (negate_ra_state) and SPARC (window_save).
745
static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
746
"uses the same constant");
747
case DW_CFA_AARCH64_negate_ra_state:
748
switch (arch) {
749
#if defined(_LIBUNWIND_TARGET_AARCH64)
750
case REGISTERS_ARM64: {
751
int64_t value =
752
results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x1;
753
results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
754
initialState);
755
_LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
756
} break;
757
#endif
758
759
#if defined(_LIBUNWIND_TARGET_SPARC)
760
// case DW_CFA_GNU_window_save:
761
case REGISTERS_SPARC:
762
_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
763
for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
764
results->setRegister(reg, kRegisterInRegister,
765
((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0,
766
initialState);
767
}
768
769
for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
770
results->setRegister(reg, kRegisterInCFA,
771
((int64_t)reg - UNW_SPARC_L0) * 4,
772
initialState);
773
}
774
break;
775
#endif
776
777
#if defined(_LIBUNWIND_TARGET_SPARC64)
778
// case DW_CFA_GNU_window_save:
779
case REGISTERS_SPARC64:
780
// Don't save %o0-%o7 on sparc64.
781
// https://reviews.llvm.org/D32450#736405
782
783
for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
784
if (reg == UNW_SPARC_I7)
785
results->setRegister(
786
reg, kRegisterInCFADecrypt,
787
static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
788
initialState);
789
else
790
results->setRegister(
791
reg, kRegisterInCFA,
792
static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
793
initialState);
794
}
795
_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save\n");
796
break;
797
#endif
798
}
799
break;
800
801
#else
802
(void)arch;
803
#endif
804
805
default:
806
operand = opcode & 0x3F;
807
switch (opcode & 0xC0) {
808
case DW_CFA_offset:
809
reg = operand;
810
if (reg > kMaxRegisterNumber) {
811
_LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
812
") out of range",
813
reg);
814
return false;
815
}
816
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
817
cieInfo.dataAlignFactor;
818
results->setRegister(reg, kRegisterInCFA, offset, initialState);
819
_LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
820
operand, offset);
821
break;
822
case DW_CFA_advance_loc:
823
codeOffset += operand * cieInfo.codeAlignFactor;
824
_LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
825
static_cast<uint64_t>(codeOffset));
826
break;
827
case DW_CFA_restore:
828
reg = operand;
829
if (reg > kMaxRegisterNumber) {
830
_LIBUNWIND_LOG(
831
"malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
832
") out of range",
833
reg);
834
return false;
835
}
836
results->restoreRegisterToInitialState(reg, initialState);
837
_LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
838
static_cast<uint64_t>(operand));
839
break;
840
default:
841
_LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
842
return false;
843
}
844
}
845
}
846
}
847
return true;
848
}
849
850
} // namespace libunwind
851
852
#endif // __DWARF_PARSER_HPP__
853
854