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