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