Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/libunwind/src/DwarfInstructions.hpp
6175 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
// Processor specific interpretation of DWARF unwind info.
9
//
10
//===----------------------------------------------------------------------===//
11
12
#ifndef __DWARF_INSTRUCTIONS_HPP__
13
#define __DWARF_INSTRUCTIONS_HPP__
14
15
#include <stdint.h>
16
#include <stdio.h>
17
#include <stdlib.h>
18
19
#include "DwarfParser.hpp"
20
#include "Registers.hpp"
21
#include "config.h"
22
#include "dwarf2.h"
23
#include "libunwind_ext.h"
24
25
26
namespace libunwind {
27
28
29
/// DwarfInstructions maps abstract DWARF unwind instructions to a particular
30
/// architecture
31
template <typename A, typename R>
32
class DwarfInstructions {
33
public:
34
typedef typename A::pint_t pint_t;
35
typedef typename A::sint_t sint_t;
36
37
static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart,
38
R &registers, bool &isSignalFrame, bool stage2);
39
40
private:
41
42
enum {
43
DW_X86_64_RET_ADDR = 16
44
};
45
46
enum {
47
DW_X86_RET_ADDR = 8
48
};
49
50
typedef typename CFI_Parser<A>::RegisterLocation RegisterLocation;
51
typedef typename CFI_Parser<A>::PrologInfo PrologInfo;
52
typedef typename CFI_Parser<A>::FDE_Info FDE_Info;
53
typedef typename CFI_Parser<A>::CIE_Info CIE_Info;
54
55
static pint_t evaluateExpression(pint_t expression, A &addressSpace,
56
const R &registers,
57
pint_t initialStackValue);
58
static pint_t getSavedRegister(A &addressSpace, const R &registers,
59
pint_t cfa, const RegisterLocation &savedReg);
60
static double getSavedFloatRegister(A &addressSpace, const R &registers,
61
pint_t cfa, const RegisterLocation &savedReg);
62
static v128 getSavedVectorRegister(A &addressSpace, const R &registers,
63
pint_t cfa, const RegisterLocation &savedReg);
64
65
static pint_t getCFA(A &addressSpace, const PrologInfo &prolog,
66
const R &registers) {
67
if (prolog.cfaRegister != 0)
68
return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) +
69
prolog.cfaRegisterOffset);
70
if (prolog.cfaExpression != 0)
71
return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
72
registers, 0);
73
assert(0 && "getCFA(): unknown location");
74
__builtin_unreachable();
75
}
76
#if defined(_LIBUNWIND_TARGET_AARCH64)
77
static bool isReturnAddressSigned(A &addressSpace, R registers, pint_t cfa,
78
PrologInfo &prolog);
79
static bool isReturnAddressSignedWithPC(A &addressSpace, R registers,
80
pint_t cfa, PrologInfo &prolog);
81
#endif
82
};
83
84
template <typename R>
85
auto getSparcWCookie(const R &r, int) -> decltype(r.getWCookie()) {
86
return r.getWCookie();
87
}
88
template <typename R> uint64_t getSparcWCookie(const R &, long) {
89
return 0;
90
}
91
92
template <typename A, typename R>
93
typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
94
A &addressSpace, const R &registers, pint_t cfa,
95
const RegisterLocation &savedReg) {
96
switch (savedReg.location) {
97
case CFI_Parser<A>::kRegisterInCFA:
98
return (pint_t)addressSpace.getRegister(cfa + (pint_t)savedReg.value);
99
100
case CFI_Parser<A>::kRegisterInCFADecrypt: // sparc64 specific
101
return (pint_t)(addressSpace.getP(cfa + (pint_t)savedReg.value) ^
102
getSparcWCookie(registers, 0));
103
104
case CFI_Parser<A>::kRegisterAtExpression:
105
return (pint_t)addressSpace.getRegister(evaluateExpression(
106
(pint_t)savedReg.value, addressSpace, registers, cfa));
107
108
case CFI_Parser<A>::kRegisterIsExpression:
109
return evaluateExpression((pint_t)savedReg.value, addressSpace,
110
registers, cfa);
111
112
case CFI_Parser<A>::kRegisterInRegister:
113
return registers.getRegister((int)savedReg.value);
114
case CFI_Parser<A>::kRegisterUndefined:
115
return 0;
116
case CFI_Parser<A>::kRegisterUnused:
117
case CFI_Parser<A>::kRegisterOffsetFromCFA:
118
// FIX ME
119
break;
120
}
121
_LIBUNWIND_ABORT("unsupported restore location for register");
122
}
123
124
template <typename A, typename R>
125
double DwarfInstructions<A, R>::getSavedFloatRegister(
126
A &addressSpace, const R &registers, pint_t cfa,
127
const RegisterLocation &savedReg) {
128
switch (savedReg.location) {
129
case CFI_Parser<A>::kRegisterInCFA:
130
return addressSpace.getDouble(cfa + (pint_t)savedReg.value);
131
132
case CFI_Parser<A>::kRegisterAtExpression:
133
return addressSpace.getDouble(
134
evaluateExpression((pint_t)savedReg.value, addressSpace,
135
registers, cfa));
136
case CFI_Parser<A>::kRegisterUndefined:
137
return 0.0;
138
case CFI_Parser<A>::kRegisterInRegister:
139
#ifndef _LIBUNWIND_TARGET_ARM
140
return registers.getFloatRegister((int)savedReg.value);
141
#endif
142
case CFI_Parser<A>::kRegisterIsExpression:
143
case CFI_Parser<A>::kRegisterUnused:
144
case CFI_Parser<A>::kRegisterOffsetFromCFA:
145
case CFI_Parser<A>::kRegisterInCFADecrypt:
146
// FIX ME
147
break;
148
}
149
_LIBUNWIND_ABORT("unsupported restore location for float register");
150
}
151
152
template <typename A, typename R>
153
v128 DwarfInstructions<A, R>::getSavedVectorRegister(
154
A &addressSpace, const R &registers, pint_t cfa,
155
const RegisterLocation &savedReg) {
156
switch (savedReg.location) {
157
case CFI_Parser<A>::kRegisterInCFA:
158
return addressSpace.getVector(cfa + (pint_t)savedReg.value);
159
160
case CFI_Parser<A>::kRegisterAtExpression:
161
return addressSpace.getVector(
162
evaluateExpression((pint_t)savedReg.value, addressSpace,
163
registers, cfa));
164
165
case CFI_Parser<A>::kRegisterIsExpression:
166
case CFI_Parser<A>::kRegisterUnused:
167
case CFI_Parser<A>::kRegisterUndefined:
168
case CFI_Parser<A>::kRegisterOffsetFromCFA:
169
case CFI_Parser<A>::kRegisterInRegister:
170
case CFI_Parser<A>::kRegisterInCFADecrypt:
171
// FIX ME
172
break;
173
}
174
_LIBUNWIND_ABORT("unsupported restore location for vector register");
175
}
176
#if defined(_LIBUNWIND_TARGET_AARCH64)
177
template <typename A, typename R>
178
bool DwarfInstructions<A, R>::isReturnAddressSigned(A &addressSpace,
179
R registers, pint_t cfa,
180
PrologInfo &prolog) {
181
pint_t raSignState;
182
auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
183
if (regloc.location == CFI_Parser<A>::kRegisterUnused)
184
raSignState = static_cast<pint_t>(regloc.value);
185
else
186
raSignState = getSavedRegister(addressSpace, registers, cfa, regloc);
187
188
// Only bit[0] is meaningful.
189
return raSignState & 0x01;
190
}
191
192
template <typename A, typename R>
193
bool DwarfInstructions<A, R>::isReturnAddressSignedWithPC(A &addressSpace,
194
R registers,
195
pint_t cfa,
196
PrologInfo &prolog) {
197
pint_t raSignState;
198
auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
199
if (regloc.location == CFI_Parser<A>::kRegisterUnused)
200
raSignState = static_cast<pint_t>(regloc.value);
201
else
202
raSignState = getSavedRegister(addressSpace, registers, cfa, regloc);
203
204
// Only bit[1] is meaningful.
205
return raSignState & 0x02;
206
}
207
#endif
208
209
template <typename A, typename R>
210
int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
211
pint_t fdeStart, R &registers,
212
bool &isSignalFrame, bool stage2) {
213
FDE_Info fdeInfo;
214
CIE_Info cieInfo;
215
if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo,
216
&cieInfo) == NULL) {
217
PrologInfo prolog;
218
if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc,
219
R::getArch(), &prolog)) {
220
// get pointer to cfa (architecture specific)
221
pint_t cfa = getCFA(addressSpace, prolog, registers);
222
223
(void)stage2;
224
// __unw_step_stage2 is not used for cross unwinding, so we use
225
// __aarch64__ rather than LIBUNWIND_TARGET_AARCH64 to make sure we are
226
// building for AArch64 natively.
227
#if defined(__aarch64__)
228
if (stage2 && cieInfo.mteTaggedFrame) {
229
pint_t sp = registers.getSP();
230
pint_t p = sp;
231
// AArch64 doesn't require the value of SP to be 16-byte aligned at
232
// all times, only at memory accesses and public interfaces [1]. Thus,
233
// a signal could arrive at a point where SP is not aligned properly.
234
// In that case, the kernel fixes up [2] the signal frame, but we
235
// still have a misaligned SP in the previous frame. If that signal
236
// handler caused stack unwinding, we would have an unaligned SP.
237
// We do not need to fix up the CFA, as that is the SP at a "public
238
// interface".
239
// [1]:
240
// https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#622the-stack
241
// [2]:
242
// https://github.com/torvalds/linux/blob/1930a6e739c4b4a654a69164dbe39e554d228915/arch/arm64/kernel/signal.c#L718
243
p &= ~0xfULL;
244
// CFA is the bottom of the current stack frame.
245
for (; p < cfa; p += 16) {
246
__asm__ __volatile__(".arch armv8.5-a\n"
247
".arch_extension memtag\n"
248
"stg %[Ptr], [%[Ptr]]\n"
249
:
250
: [Ptr] "r"(p)
251
: "memory");
252
}
253
}
254
#endif
255
// restore registers that DWARF says were saved
256
R newRegisters = registers;
257
258
// Typically, the CFA is the stack pointer at the call site in
259
// the previous frame. However, there are scenarios in which this is not
260
// true. For example, if we switched to a new stack. In that case, the
261
// value of the previous SP might be indicated by a CFI directive.
262
//
263
// We set the SP here to the CFA, allowing for it to be overridden
264
// by a CFI directive later on.
265
newRegisters.setSP(cfa);
266
267
pint_t returnAddress = 0;
268
constexpr int lastReg = R::lastDwarfRegNum();
269
static_assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >=
270
lastReg,
271
"register range too large");
272
assert(lastReg >= (int)cieInfo.returnAddressRegister &&
273
"register range does not contain return address register");
274
for (int i = 0; i <= lastReg; ++i) {
275
if (prolog.savedRegisters[i].location !=
276
CFI_Parser<A>::kRegisterUnused) {
277
if (registers.validFloatRegister(i))
278
newRegisters.setFloatRegister(
279
i, getSavedFloatRegister(addressSpace, registers, cfa,
280
prolog.savedRegisters[i]));
281
else if (registers.validVectorRegister(i))
282
newRegisters.setVectorRegister(
283
i, getSavedVectorRegister(addressSpace, registers, cfa,
284
prolog.savedRegisters[i]));
285
else if (i == (int)cieInfo.returnAddressRegister)
286
returnAddress = getSavedRegister(addressSpace, registers, cfa,
287
prolog.savedRegisters[i]);
288
else if (registers.validRegister(i))
289
newRegisters.setRegister(
290
i, getSavedRegister(addressSpace, registers, cfa,
291
prolog.savedRegisters[i]));
292
else
293
return UNW_EBADREG;
294
} else if (i == (int)cieInfo.returnAddressRegister) {
295
// Leaf function keeps the return address in register and there is no
296
// explicit instructions how to restore it.
297
returnAddress = registers.getRegister(cieInfo.returnAddressRegister);
298
}
299
}
300
301
isSignalFrame = cieInfo.isSignalFrame;
302
303
#if defined(_LIBUNWIND_TARGET_AARCH64)
304
// If the target is aarch64 then the return address may have been signed
305
// using the v8.3 pointer authentication extensions. The original
306
// return address needs to be authenticated before the return address is
307
// restored. autia1716 is used instead of autia as autia1716 assembles
308
// to a NOP on pre-v8.3a architectures.
309
if ((R::getArch() == REGISTERS_ARM64) &&
310
isReturnAddressSigned(addressSpace, registers, cfa, prolog) &&
311
returnAddress != 0) {
312
#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
313
return UNW_ECROSSRASIGNING;
314
#else
315
register unsigned long long x17 __asm("x17") = returnAddress;
316
register unsigned long long x16 __asm("x16") = cfa;
317
318
// We use the hint versions of the authentication instructions below to
319
// ensure they're assembled by the compiler even for targets with no
320
// FEAT_PAuth/FEAT_PAuth_LR support.
321
if (isReturnAddressSignedWithPC(addressSpace, registers, cfa, prolog)) {
322
register unsigned long long x15 __asm("x15") =
323
prolog.ptrAuthDiversifier;
324
if (cieInfo.addressesSignedWithBKey) {
325
asm("hint 0x27\n\t" // pacm
326
"hint 0xe"
327
: "+r"(x17)
328
: "r"(x16), "r"(x15)); // autib1716
329
} else {
330
asm("hint 0x27\n\t" // pacm
331
"hint 0xc"
332
: "+r"(x17)
333
: "r"(x16), "r"(x15)); // autia1716
334
}
335
} else {
336
if (cieInfo.addressesSignedWithBKey)
337
asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
338
else
339
asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
340
}
341
returnAddress = x17;
342
#endif
343
}
344
#endif
345
346
#if defined(_LIBUNWIND_IS_NATIVE_ONLY) && defined(_LIBUNWIND_TARGET_ARM) && \
347
defined(__ARM_FEATURE_PAUTH)
348
if ((R::getArch() == REGISTERS_ARM) &&
349
prolog.savedRegisters[UNW_ARM_RA_AUTH_CODE].value) {
350
pint_t pac =
351
getSavedRegister(addressSpace, registers, cfa,
352
prolog.savedRegisters[UNW_ARM_RA_AUTH_CODE]);
353
__asm__ __volatile__("autg %0, %1, %2"
354
:
355
: "r"(pac), "r"(returnAddress), "r"(cfa)
356
:);
357
}
358
#endif
359
360
#if defined(_LIBUNWIND_TARGET_SPARC)
361
if (R::getArch() == REGISTERS_SPARC) {
362
// Skip call site instruction and delay slot
363
returnAddress += 8;
364
// Skip unimp instruction if function returns a struct
365
if ((addressSpace.get32(returnAddress) & 0xC1C00000) == 0)
366
returnAddress += 4;
367
}
368
#endif
369
370
#if defined(_LIBUNWIND_TARGET_SPARC64)
371
// Skip call site instruction and delay slot.
372
if (R::getArch() == REGISTERS_SPARC64)
373
returnAddress += 8;
374
#endif
375
376
#if defined(_LIBUNWIND_TARGET_PPC64)
377
#define PPC64_ELFV1_R2_LOAD_INST_ENCODING 0xe8410028u // ld r2,40(r1)
378
#define PPC64_ELFV1_R2_OFFSET 40
379
#define PPC64_ELFV2_R2_LOAD_INST_ENCODING 0xe8410018u // ld r2,24(r1)
380
#define PPC64_ELFV2_R2_OFFSET 24
381
// If the instruction at return address is a TOC (r2) restore,
382
// then r2 was saved and needs to be restored.
383
// ELFv2 ABI specifies that the TOC Pointer must be saved at SP + 24,
384
// while in ELFv1 ABI it is saved at SP + 40.
385
if (R::getArch() == REGISTERS_PPC64 && returnAddress != 0) {
386
pint_t sp = newRegisters.getRegister(UNW_REG_SP);
387
pint_t r2 = 0;
388
switch (addressSpace.get32(returnAddress)) {
389
case PPC64_ELFV1_R2_LOAD_INST_ENCODING:
390
r2 = addressSpace.get64(sp + PPC64_ELFV1_R2_OFFSET);
391
break;
392
case PPC64_ELFV2_R2_LOAD_INST_ENCODING:
393
r2 = addressSpace.get64(sp + PPC64_ELFV2_R2_OFFSET);
394
break;
395
}
396
if (r2)
397
newRegisters.setRegister(UNW_PPC64_R2, r2);
398
}
399
#endif
400
401
// Return address is address after call site instruction, so setting IP to
402
// that does simulates a return.
403
newRegisters.setIP(returnAddress);
404
405
// Simulate the step by replacing the register set with the new ones.
406
registers = newRegisters;
407
408
return UNW_STEP_SUCCESS;
409
}
410
}
411
return UNW_EBADFRAME;
412
}
413
414
template <typename A, typename R>
415
typename A::pint_t
416
DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
417
const R &registers,
418
pint_t initialStackValue) {
419
const bool log = false;
420
pint_t p = expression;
421
pint_t expressionEnd = expression + 20; // temp, until len read
422
pint_t length = (pint_t)addressSpace.getULEB128(p, expressionEnd);
423
expressionEnd = p + length;
424
if (log)
425
fprintf(stderr, "evaluateExpression(): length=%" PRIu64 "\n",
426
(uint64_t)length);
427
pint_t stack[100];
428
pint_t *sp = stack;
429
*(++sp) = initialStackValue;
430
431
while (p < expressionEnd) {
432
if (log) {
433
for (pint_t *t = sp; t > stack; --t) {
434
fprintf(stderr, "sp[] = 0x%" PRIx64 "\n", (uint64_t)(*t));
435
}
436
}
437
uint8_t opcode = addressSpace.get8(p++);
438
sint_t svalue, svalue2;
439
pint_t value;
440
uint32_t reg;
441
switch (opcode) {
442
case DW_OP_addr:
443
// push immediate address sized value
444
value = addressSpace.getP(p);
445
p += sizeof(pint_t);
446
*(++sp) = value;
447
if (log)
448
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
449
break;
450
451
case DW_OP_deref:
452
// pop stack, dereference, push result
453
value = *sp--;
454
*(++sp) = addressSpace.getP(value);
455
if (log)
456
fprintf(stderr, "dereference 0x%" PRIx64 "\n", (uint64_t)value);
457
break;
458
459
case DW_OP_const1u:
460
// push immediate 1 byte value
461
value = addressSpace.get8(p);
462
p += 1;
463
*(++sp) = value;
464
if (log)
465
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
466
break;
467
468
case DW_OP_const1s:
469
// push immediate 1 byte signed value
470
svalue = (int8_t) addressSpace.get8(p);
471
p += 1;
472
*(++sp) = (pint_t)svalue;
473
if (log)
474
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
475
break;
476
477
case DW_OP_const2u:
478
// push immediate 2 byte value
479
value = addressSpace.get16(p);
480
p += 2;
481
*(++sp) = value;
482
if (log)
483
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
484
break;
485
486
case DW_OP_const2s:
487
// push immediate 2 byte signed value
488
svalue = (int16_t) addressSpace.get16(p);
489
p += 2;
490
*(++sp) = (pint_t)svalue;
491
if (log)
492
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
493
break;
494
495
case DW_OP_const4u:
496
// push immediate 4 byte value
497
value = addressSpace.get32(p);
498
p += 4;
499
*(++sp) = value;
500
if (log)
501
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
502
break;
503
504
case DW_OP_const4s:
505
// push immediate 4 byte signed value
506
svalue = (int32_t)addressSpace.get32(p);
507
p += 4;
508
*(++sp) = (pint_t)svalue;
509
if (log)
510
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
511
break;
512
513
case DW_OP_const8u:
514
// push immediate 8 byte value
515
value = (pint_t)addressSpace.get64(p);
516
p += 8;
517
*(++sp) = value;
518
if (log)
519
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
520
break;
521
522
case DW_OP_const8s:
523
// push immediate 8 byte signed value
524
value = (pint_t)addressSpace.get64(p);
525
p += 8;
526
*(++sp) = value;
527
if (log)
528
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
529
break;
530
531
case DW_OP_constu:
532
// push immediate ULEB128 value
533
value = (pint_t)addressSpace.getULEB128(p, expressionEnd);
534
*(++sp) = value;
535
if (log)
536
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
537
break;
538
539
case DW_OP_consts:
540
// push immediate SLEB128 value
541
svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
542
*(++sp) = (pint_t)svalue;
543
if (log)
544
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
545
break;
546
547
case DW_OP_dup:
548
// push top of stack
549
value = *sp;
550
*(++sp) = value;
551
if (log)
552
fprintf(stderr, "duplicate top of stack\n");
553
break;
554
555
case DW_OP_drop:
556
// pop
557
--sp;
558
if (log)
559
fprintf(stderr, "pop top of stack\n");
560
break;
561
562
case DW_OP_over:
563
// dup second
564
value = sp[-1];
565
*(++sp) = value;
566
if (log)
567
fprintf(stderr, "duplicate second in stack\n");
568
break;
569
570
case DW_OP_pick:
571
// pick from
572
reg = addressSpace.get8(p);
573
p += 1;
574
value = sp[-(int)reg];
575
*(++sp) = value;
576
if (log)
577
fprintf(stderr, "duplicate %d in stack\n", reg);
578
break;
579
580
case DW_OP_swap:
581
// swap top two
582
value = sp[0];
583
sp[0] = sp[-1];
584
sp[-1] = value;
585
if (log)
586
fprintf(stderr, "swap top of stack\n");
587
break;
588
589
case DW_OP_rot:
590
// rotate top three
591
value = sp[0];
592
sp[0] = sp[-1];
593
sp[-1] = sp[-2];
594
sp[-2] = value;
595
if (log)
596
fprintf(stderr, "rotate top three of stack\n");
597
break;
598
599
case DW_OP_xderef:
600
// pop stack, dereference, push result
601
value = *sp--;
602
*sp = *((pint_t*)value);
603
if (log)
604
fprintf(stderr, "x-dereference 0x%" PRIx64 "\n", (uint64_t)value);
605
break;
606
607
case DW_OP_abs:
608
svalue = (sint_t)*sp;
609
if (svalue < 0)
610
*sp = (pint_t)(-svalue);
611
if (log)
612
fprintf(stderr, "abs\n");
613
break;
614
615
case DW_OP_and:
616
value = *sp--;
617
*sp &= value;
618
if (log)
619
fprintf(stderr, "and\n");
620
break;
621
622
case DW_OP_div:
623
svalue = (sint_t)(*sp--);
624
svalue2 = (sint_t)*sp;
625
*sp = (pint_t)(svalue2 / svalue);
626
if (log)
627
fprintf(stderr, "div\n");
628
break;
629
630
case DW_OP_minus:
631
value = *sp--;
632
*sp = *sp - value;
633
if (log)
634
fprintf(stderr, "minus\n");
635
break;
636
637
case DW_OP_mod:
638
svalue = (sint_t)(*sp--);
639
svalue2 = (sint_t)*sp;
640
*sp = (pint_t)(svalue2 % svalue);
641
if (log)
642
fprintf(stderr, "module\n");
643
break;
644
645
case DW_OP_mul:
646
svalue = (sint_t)(*sp--);
647
svalue2 = (sint_t)*sp;
648
*sp = (pint_t)(svalue2 * svalue);
649
if (log)
650
fprintf(stderr, "mul\n");
651
break;
652
653
case DW_OP_neg:
654
*sp = 0 - *sp;
655
if (log)
656
fprintf(stderr, "neg\n");
657
break;
658
659
case DW_OP_not:
660
svalue = (sint_t)(*sp);
661
*sp = (pint_t)(~svalue);
662
if (log)
663
fprintf(stderr, "not\n");
664
break;
665
666
case DW_OP_or:
667
value = *sp--;
668
*sp |= value;
669
if (log)
670
fprintf(stderr, "or\n");
671
break;
672
673
case DW_OP_plus:
674
value = *sp--;
675
*sp += value;
676
if (log)
677
fprintf(stderr, "plus\n");
678
break;
679
680
case DW_OP_plus_uconst:
681
// pop stack, add uelb128 constant, push result
682
*sp += static_cast<pint_t>(addressSpace.getULEB128(p, expressionEnd));
683
if (log)
684
fprintf(stderr, "add constant\n");
685
break;
686
687
case DW_OP_shl:
688
value = *sp--;
689
*sp = *sp << value;
690
if (log)
691
fprintf(stderr, "shift left\n");
692
break;
693
694
case DW_OP_shr:
695
value = *sp--;
696
*sp = *sp >> value;
697
if (log)
698
fprintf(stderr, "shift left\n");
699
break;
700
701
case DW_OP_shra:
702
value = *sp--;
703
svalue = (sint_t)*sp;
704
*sp = (pint_t)(svalue >> value);
705
if (log)
706
fprintf(stderr, "shift left arithmetic\n");
707
break;
708
709
case DW_OP_xor:
710
value = *sp--;
711
*sp ^= value;
712
if (log)
713
fprintf(stderr, "xor\n");
714
break;
715
716
case DW_OP_skip:
717
svalue = (int16_t) addressSpace.get16(p);
718
p += 2;
719
p = (pint_t)((sint_t)p + svalue);
720
if (log)
721
fprintf(stderr, "skip %" PRIu64 "\n", (uint64_t)svalue);
722
break;
723
724
case DW_OP_bra:
725
svalue = (int16_t) addressSpace.get16(p);
726
p += 2;
727
if (*sp--)
728
p = (pint_t)((sint_t)p + svalue);
729
if (log)
730
fprintf(stderr, "bra %" PRIu64 "\n", (uint64_t)svalue);
731
break;
732
733
case DW_OP_eq:
734
value = *sp--;
735
*sp = (*sp == value);
736
if (log)
737
fprintf(stderr, "eq\n");
738
break;
739
740
case DW_OP_ge:
741
value = *sp--;
742
*sp = (*sp >= value);
743
if (log)
744
fprintf(stderr, "ge\n");
745
break;
746
747
case DW_OP_gt:
748
value = *sp--;
749
*sp = (*sp > value);
750
if (log)
751
fprintf(stderr, "gt\n");
752
break;
753
754
case DW_OP_le:
755
value = *sp--;
756
*sp = (*sp <= value);
757
if (log)
758
fprintf(stderr, "le\n");
759
break;
760
761
case DW_OP_lt:
762
value = *sp--;
763
*sp = (*sp < value);
764
if (log)
765
fprintf(stderr, "lt\n");
766
break;
767
768
case DW_OP_ne:
769
value = *sp--;
770
*sp = (*sp != value);
771
if (log)
772
fprintf(stderr, "ne\n");
773
break;
774
775
case DW_OP_lit0:
776
case DW_OP_lit1:
777
case DW_OP_lit2:
778
case DW_OP_lit3:
779
case DW_OP_lit4:
780
case DW_OP_lit5:
781
case DW_OP_lit6:
782
case DW_OP_lit7:
783
case DW_OP_lit8:
784
case DW_OP_lit9:
785
case DW_OP_lit10:
786
case DW_OP_lit11:
787
case DW_OP_lit12:
788
case DW_OP_lit13:
789
case DW_OP_lit14:
790
case DW_OP_lit15:
791
case DW_OP_lit16:
792
case DW_OP_lit17:
793
case DW_OP_lit18:
794
case DW_OP_lit19:
795
case DW_OP_lit20:
796
case DW_OP_lit21:
797
case DW_OP_lit22:
798
case DW_OP_lit23:
799
case DW_OP_lit24:
800
case DW_OP_lit25:
801
case DW_OP_lit26:
802
case DW_OP_lit27:
803
case DW_OP_lit28:
804
case DW_OP_lit29:
805
case DW_OP_lit30:
806
case DW_OP_lit31:
807
value = static_cast<pint_t>(opcode - DW_OP_lit0);
808
*(++sp) = value;
809
if (log)
810
fprintf(stderr, "push literal 0x%" PRIx64 "\n", (uint64_t)value);
811
break;
812
813
case DW_OP_reg0:
814
case DW_OP_reg1:
815
case DW_OP_reg2:
816
case DW_OP_reg3:
817
case DW_OP_reg4:
818
case DW_OP_reg5:
819
case DW_OP_reg6:
820
case DW_OP_reg7:
821
case DW_OP_reg8:
822
case DW_OP_reg9:
823
case DW_OP_reg10:
824
case DW_OP_reg11:
825
case DW_OP_reg12:
826
case DW_OP_reg13:
827
case DW_OP_reg14:
828
case DW_OP_reg15:
829
case DW_OP_reg16:
830
case DW_OP_reg17:
831
case DW_OP_reg18:
832
case DW_OP_reg19:
833
case DW_OP_reg20:
834
case DW_OP_reg21:
835
case DW_OP_reg22:
836
case DW_OP_reg23:
837
case DW_OP_reg24:
838
case DW_OP_reg25:
839
case DW_OP_reg26:
840
case DW_OP_reg27:
841
case DW_OP_reg28:
842
case DW_OP_reg29:
843
case DW_OP_reg30:
844
case DW_OP_reg31:
845
reg = static_cast<uint32_t>(opcode - DW_OP_reg0);
846
*(++sp) = registers.getRegister((int)reg);
847
if (log)
848
fprintf(stderr, "push reg %d\n", reg);
849
break;
850
851
case DW_OP_regx:
852
reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd));
853
*(++sp) = registers.getRegister((int)reg);
854
if (log)
855
fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
856
break;
857
858
case DW_OP_breg0:
859
case DW_OP_breg1:
860
case DW_OP_breg2:
861
case DW_OP_breg3:
862
case DW_OP_breg4:
863
case DW_OP_breg5:
864
case DW_OP_breg6:
865
case DW_OP_breg7:
866
case DW_OP_breg8:
867
case DW_OP_breg9:
868
case DW_OP_breg10:
869
case DW_OP_breg11:
870
case DW_OP_breg12:
871
case DW_OP_breg13:
872
case DW_OP_breg14:
873
case DW_OP_breg15:
874
case DW_OP_breg16:
875
case DW_OP_breg17:
876
case DW_OP_breg18:
877
case DW_OP_breg19:
878
case DW_OP_breg20:
879
case DW_OP_breg21:
880
case DW_OP_breg22:
881
case DW_OP_breg23:
882
case DW_OP_breg24:
883
case DW_OP_breg25:
884
case DW_OP_breg26:
885
case DW_OP_breg27:
886
case DW_OP_breg28:
887
case DW_OP_breg29:
888
case DW_OP_breg30:
889
case DW_OP_breg31:
890
reg = static_cast<uint32_t>(opcode - DW_OP_breg0);
891
svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
892
svalue += static_cast<sint_t>(registers.getRegister((int)reg));
893
*(++sp) = (pint_t)(svalue);
894
if (log)
895
fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
896
break;
897
898
case DW_OP_bregx:
899
reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd));
900
svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
901
svalue += static_cast<sint_t>(registers.getRegister((int)reg));
902
*(++sp) = (pint_t)(svalue);
903
if (log)
904
fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
905
break;
906
907
case DW_OP_fbreg:
908
_LIBUNWIND_ABORT("DW_OP_fbreg not implemented");
909
break;
910
911
case DW_OP_piece:
912
_LIBUNWIND_ABORT("DW_OP_piece not implemented");
913
break;
914
915
case DW_OP_deref_size:
916
// pop stack, dereference, push result
917
value = *sp--;
918
switch (addressSpace.get8(p++)) {
919
case 1:
920
value = addressSpace.get8(value);
921
break;
922
case 2:
923
value = addressSpace.get16(value);
924
break;
925
case 4:
926
value = addressSpace.get32(value);
927
break;
928
case 8:
929
value = (pint_t)addressSpace.get64(value);
930
break;
931
default:
932
_LIBUNWIND_ABORT("DW_OP_deref_size with bad size");
933
}
934
*(++sp) = value;
935
if (log)
936
fprintf(stderr, "sized dereference 0x%" PRIx64 "\n", (uint64_t)value);
937
break;
938
939
case DW_OP_xderef_size:
940
case DW_OP_nop:
941
case DW_OP_push_object_addres:
942
case DW_OP_call2:
943
case DW_OP_call4:
944
case DW_OP_call_ref:
945
default:
946
_LIBUNWIND_ABORT("DWARF opcode not implemented");
947
}
948
949
}
950
if (log)
951
fprintf(stderr, "expression evaluates to 0x%" PRIx64 "\n", (uint64_t)*sp);
952
return *sp;
953
}
954
955
956
957
} // namespace libunwind
958
959
#endif // __DWARF_INSTRUCTIONS_HPP__
960
961