return false;
}
+//===-- CompactUnwindInfo.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
#if defined(TARGET_AMD64)
static bool
return true;
}
+static bool
+StepWithCompactEncodingFrameless(const libunwindInfo* info, compact_unwind_encoding_t compactEncoding, unw_word_t functionStart)
+{
+ int mode = compactEncoding & UNWIND_X86_64_MODE_MASK;
+ CONTEXT* context = info->Context;
+
+ uint32_t stack_size = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+ uint32_t register_count = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
+
+ if (mode == UNWIND_X86_64_MODE_STACK_IND)
+ {
+ _ASSERTE(functionStart != 0);
+ unw_word_t addr = functionStart + stack_size;
+ if (!ReadValue32(info, &addr, &stack_size)) {
+ return false;
+ }
+ uint32_t stack_adjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
+ stack_size += stack_adjust * 8;
+ }
+ else
+ {
+ stack_size *= 8;
+ }
+
+ TRACE("Frameless function: encoding %08x stack size %d register count %d\n", compactEncoding, stack_size, register_count);
+
+ // We need to include (up to) 6 registers in 10 bits.
+ // That would be 18 bits if we just used 3 bits per reg to indicate
+ // the order they're saved on the stack.
+ //
+ // This is done with Lehmer code permutation, e.g. see
+ // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
+ int permunreg[6];
+
+ // This decodes the variable-base number in the 10 bits
+ // and gives us the Lehmer code sequence which can then
+ // be decoded.
+ switch (register_count) {
+ case 6:
+ permunreg[0] = permutation / 120; // 120 == 5!
+ permutation -= (permunreg[0] * 120);
+ permunreg[1] = permutation / 24; // 24 == 4!
+ permutation -= (permunreg[1] * 24);
+ permunreg[2] = permutation / 6; // 6 == 3!
+ permutation -= (permunreg[2] * 6);
+ permunreg[3] = permutation / 2; // 2 == 2!
+ permutation -= (permunreg[3] * 2);
+ permunreg[4] = permutation; // 1 == 1!
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation / 120;
+ permutation -= (permunreg[0] * 120);
+ permunreg[1] = permutation / 24;
+ permutation -= (permunreg[1] * 24);
+ permunreg[2] = permutation / 6;
+ permutation -= (permunreg[2] * 6);
+ permunreg[3] = permutation / 2;
+ permutation -= (permunreg[3] * 2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation / 60;
+ permutation -= (permunreg[0] * 60);
+ permunreg[1] = permutation / 12;
+ permutation -= (permunreg[1] * 12);
+ permunreg[2] = permutation / 3;
+ permutation -= (permunreg[2] * 3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation / 20;
+ permutation -= (permunreg[0] * 20);
+ permunreg[1] = permutation / 4;
+ permutation -= (permunreg[1] * 4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation / 5;
+ permutation -= (permunreg[0] * 5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+
+ // Decode the Lehmer code for this permutation of
+ // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
+ int registers[6] = {UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
+ UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
+ UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE};
+ bool used[7] = {false, false, false, false, false, false, false};
+ for (int i = 0; i < register_count; i++)
+ {
+ int renum = 0;
+ for (int j = 1; j < 7; j++)
+ {
+ if (!used[j])
+ {
+ if (renum == permunreg[i])
+ {
+ registers[i] = j;
+ used[j] = true;
+ break;
+ }
+ renum++;
+ }
+ }
+ }
+
+ uint64_t savedRegisters = context->Rsp + stack_size - 8 - (8 * register_count);
+ for (int i = 0; i < register_count; i++)
+ {
+ uint64_t reg;
+ if (!ReadValue64(info, &savedRegisters, ®)) {
+ return false;
+ }
+ switch (registers[i]) {
+ case UNWIND_X86_64_REG_RBX:
+ context->Rbx = reg;
+ break;
+ case UNWIND_X86_64_REG_R12:
+ context->R12 = reg;
+ break;
+ case UNWIND_X86_64_REG_R13:
+ context->R13 = reg;
+ break;
+ case UNWIND_X86_64_REG_R14:
+ context->R14 = reg;
+ break;
+ case UNWIND_X86_64_REG_R15:
+ context->R15 = reg;
+ break;
+ case UNWIND_X86_64_REG_RBP:
+ context->Rbp = reg;
+ break;
+ default:
+ ERROR("Bad register for frameless\n");
+ break;
+ }
+ }
+
+ // Now unwind the frame
+ uint64_t ip;
+ if (!ReadValue64(info, &savedRegisters, &ip)) {
+ return false;
+ }
+ context->Rip = ip;
+ context->Rsp = savedRegisters;
+
+ TRACE("SUCCESS: frameless encoding %08x rip %p rsp %p rbp %p\n",
+ compactEncoding, (void*)context->Rip, (void*)context->Rsp, (void*)context->Rbp);
+ return true;
+}
+
#define AMD64_SYSCALL_OPCODE 0x050f
static bool
case UNWIND_X86_64_MODE_STACK_IMMD:
case UNWIND_X86_64_MODE_STACK_IND:
- break;
+ return StepWithCompactEncodingFrameless(info, compactEncoding, functionStart);
case UNWIND_X86_64_MODE_DWARF:
return false;