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 ®isters, 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 ®isters, |
57 | pint_t initialStackValue); |
58 | static pint_t getSavedRegister(A &addressSpace, const R ®isters, |
59 | pint_t cfa, const RegisterLocation &savedReg); |
60 | static double getSavedFloatRegister(A &addressSpace, const R ®isters, |
61 | pint_t cfa, const RegisterLocation &savedReg); |
62 | static v128 getSavedVectorRegister(A &addressSpace, const R ®isters, |
63 | pint_t cfa, const RegisterLocation &savedReg); |
64 | |
65 | static pint_t getCFA(A &addressSpace, const PrologInfo &prolog, |
66 | const R ®isters) { |
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(expression: (pint_t)prolog.cfaExpression, addressSpace, |
72 | registers, initialStackValue: 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 ®isters, 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 | expression: (pint_t)savedReg.value, addressSpace, registers, initialStackValue: cfa)); |
107 | |
108 | case CFI_Parser<A>::kRegisterIsExpression: |
109 | return evaluateExpression(expression: (pint_t)savedReg.value, addressSpace, |
110 | registers, initialStackValue: 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 ®isters, 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(expression: (pint_t)savedReg.value, addressSpace, |
135 | registers, initialStackValue: 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 ®isters, 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(expression: (pint_t)savedReg.value, addressSpace, |
163 | registers, initialStackValue: 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 ®isters, |
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 | 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 | // 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 ®isters, |
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, format: "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, format: "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, format: "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, format: "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, format: "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, format: "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, format: "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, format: "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, format: "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, format: "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, format: "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, format: "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, format: "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, format: "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, format: "duplicate top of stack\n" ); |
553 | break; |
554 | |
555 | case DW_OP_drop: |
556 | // pop |
557 | --sp; |
558 | if (log) |
559 | fprintf(stderr, format: "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, format: "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, format: "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, format: "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, format: "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, format: "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, format: "abs\n" ); |
613 | break; |
614 | |
615 | case DW_OP_and: |
616 | value = *sp--; |
617 | *sp &= value; |
618 | if (log) |
619 | fprintf(stderr, format: "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, format: "div\n" ); |
628 | break; |
629 | |
630 | case DW_OP_minus: |
631 | value = *sp--; |
632 | *sp = *sp - value; |
633 | if (log) |
634 | fprintf(stderr, format: "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, format: "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, format: "mul\n" ); |
651 | break; |
652 | |
653 | case DW_OP_neg: |
654 | *sp = 0 - *sp; |
655 | if (log) |
656 | fprintf(stderr, format: "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, format: "not\n" ); |
664 | break; |
665 | |
666 | case DW_OP_or: |
667 | value = *sp--; |
668 | *sp |= value; |
669 | if (log) |
670 | fprintf(stderr, format: "or\n" ); |
671 | break; |
672 | |
673 | case DW_OP_plus: |
674 | value = *sp--; |
675 | *sp += value; |
676 | if (log) |
677 | fprintf(stderr, format: "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, format: "add constant\n" ); |
685 | break; |
686 | |
687 | case DW_OP_shl: |
688 | value = *sp--; |
689 | *sp = *sp << value; |
690 | if (log) |
691 | fprintf(stderr, format: "shift left\n" ); |
692 | break; |
693 | |
694 | case DW_OP_shr: |
695 | value = *sp--; |
696 | *sp = *sp >> value; |
697 | if (log) |
698 | fprintf(stderr, format: "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, format: "shift left arithmetic\n" ); |
707 | break; |
708 | |
709 | case DW_OP_xor: |
710 | value = *sp--; |
711 | *sp ^= value; |
712 | if (log) |
713 | fprintf(stderr, format: "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, format: "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, format: "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, format: "eq\n" ); |
738 | break; |
739 | |
740 | case DW_OP_ge: |
741 | value = *sp--; |
742 | *sp = (*sp >= value); |
743 | if (log) |
744 | fprintf(stderr, format: "ge\n" ); |
745 | break; |
746 | |
747 | case DW_OP_gt: |
748 | value = *sp--; |
749 | *sp = (*sp > value); |
750 | if (log) |
751 | fprintf(stderr, format: "gt\n" ); |
752 | break; |
753 | |
754 | case DW_OP_le: |
755 | value = *sp--; |
756 | *sp = (*sp <= value); |
757 | if (log) |
758 | fprintf(stderr, format: "le\n" ); |
759 | break; |
760 | |
761 | case DW_OP_lt: |
762 | value = *sp--; |
763 | *sp = (*sp < value); |
764 | if (log) |
765 | fprintf(stderr, format: "lt\n" ); |
766 | break; |
767 | |
768 | case DW_OP_ne: |
769 | value = *sp--; |
770 | *sp = (*sp != value); |
771 | if (log) |
772 | fprintf(stderr, format: "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, format: "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, format: "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, format: "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, format: "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, format: "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, format: "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, format: "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 | |