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