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