llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-libunwind Author: Minsoo Choo (mchoo7) <details> <summary>Changes</summary> Raise the amd64 DWARF register limit to 59 and add RFLAGS, all six segment selectors, FS.base, and GS.base to the register model. Capture the extended state and restore it when resuming, using setcontext on FreeBSD to restore selectors and bases together. Pack the state into the existing context buffers without changing their public sizes or the Windows XMM offsets. Add tests for register access, signal-frame CFI recovery, register bounds, and resume behavior. Assisted-by: GPT --- Patch is 27.01 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/237265.diff 12 Files Affected: - (modified) libunwind/include/__libunwind_config.h (+1-1) - (modified) libunwind/include/libunwind.h (+9) - (modified) libunwind/src/AddressSpace.hpp (+2-2) - (modified) libunwind/src/Registers.hpp (+87-7) - (modified) libunwind/src/UnwindRegistersRestore.S (+4-1) - (modified) libunwind/src/UnwindRegistersSave.S (+45) - (modified) libunwind/src/assembly.h (+9) - (modified) libunwind/src/libunwind.cpp (+52) - (added) libunwind/test/x86_64_dwarf_registers.pass.cpp (+58) - (added) libunwind/test/x86_64_extended_registers.pass.cpp (+146) - (added) libunwind/test/x86_64_getcontext_preserves_rbx.pass.cpp (+67) - (added) libunwind/test/x86_64_resume_extended_registers.pass.cpp (+122) ``````````diff diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h index 60ab1bdc2cf757..30a6e891bac5c1 100644 --- a/libunwind/include/__libunwind_config.h +++ b/libunwind/include/__libunwind_config.h @@ -17,7 +17,7 @@ #endif #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 8 -#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 32 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 59 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC 112 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64 116 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 95 diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h index 6c2dfe58e53bf1..7c2f611e208923 100644 --- a/libunwind/include/libunwind.h +++ b/libunwind/include/libunwind.h @@ -295,6 +295,15 @@ enum { UNW_X86_64_XMM13 = 30, UNW_X86_64_XMM14 = 31, UNW_X86_64_XMM15 = 32, + UNW_X86_64_RFLAGS = 49, + UNW_X86_64_ES = 50, + UNW_X86_64_CS = 51, + UNW_X86_64_SS = 52, + UNW_X86_64_DS = 53, + UNW_X86_64_FS = 54, + UNW_X86_64_GS = 55, + UNW_X86_64_FS_BASE = 58, + UNW_X86_64_GS_BASE = 59, }; diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp index 3711189f57b1d1..d446f6abd9578f 100644 --- a/libunwind/src/AddressSpace.hpp +++ b/libunwind/src/AddressSpace.hpp @@ -453,8 +453,8 @@ static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base, #endif } -static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, - size_t pinfo_size, void *data) { +static inline int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, + size_t pinfo_size, void *data) { auto cbdata = static_cast<dl_iterate_cb_data *>(data); if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr) return 0; diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp index 4870e315962e09..8a7cad848ac298 100644 --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -347,14 +347,24 @@ class _LIBUNWIND_HIDDEN Registers_x86_64 { uint64_t __r14; uint64_t __r15; uint64_t __rip; - uint64_t __rflags; - uint64_t __cs; - uint64_t __fs; - uint64_t __gs; + uint32_t __rflags; + uint16_t __cs; + uint16_t __ss; + uint16_t __ds; + uint16_t __es; + uint16_t __fs; + uint16_t __gs; + uint64_t __fs_base; + uint64_t __gs_base; #if defined(_WIN64) uint64_t __padding; // 16-byte align #endif }; + static_assert(offsetof(GPRs, __rflags) == 136 && + offsetof(GPRs, __cs) == 140 && + offsetof(GPRs, __fs_base) == 152 && + offsetof(GPRs, __gs_base) == 160, + "x86_64 segment state must match the assembly offsets"); GPRs _registers; #if defined(_WIN64) v128 _xmm[16]; @@ -378,9 +388,16 @@ inline bool Registers_x86_64::validRegister(int regNum) const { return true; if (regNum < 0) return false; - if (regNum > 16) - return false; - return true; + if (regNum <= UNW_X86_64_RIP) + return true; + // Extended native register state is captured and restored only on FreeBSD. +#if defined(__FreeBSD__) && !defined(_LIBUNWIND_IS_BAREMETAL) + if (regNum >= UNW_X86_64_RFLAGS && regNum <= UNW_X86_64_GS) + return true; + if (regNum == UNW_X86_64_FS_BASE || regNum == UNW_X86_64_GS_BASE) + return true; +#endif + return false; } inline uint64_t Registers_x86_64::getRegister(int regNum) const { @@ -422,6 +439,24 @@ inline uint64_t Registers_x86_64::getRegister(int regNum) const { return _registers.__r14; case UNW_X86_64_R15: return _registers.__r15; + case UNW_X86_64_RFLAGS: + return _registers.__rflags; + case UNW_X86_64_ES: + return _registers.__es; + case UNW_X86_64_CS: + return _registers.__cs; + case UNW_X86_64_SS: + return _registers.__ss; + case UNW_X86_64_DS: + return _registers.__ds; + case UNW_X86_64_FS: + return _registers.__fs; + case UNW_X86_64_GS: + return _registers.__gs; + case UNW_X86_64_FS_BASE: + return _registers.__fs_base; + case UNW_X86_64_GS_BASE: + return _registers.__gs_base; } _LIBUNWIND_ABORT("unsupported x86_64 register"); } @@ -483,6 +518,33 @@ inline void Registers_x86_64::setRegister(int regNum, uint64_t value) { case UNW_X86_64_R15: _registers.__r15 = value; return; + case UNW_X86_64_RFLAGS: + _registers.__rflags = static_cast<uint32_t>(value); + return; + case UNW_X86_64_ES: + _registers.__es = static_cast<uint16_t>(value); + return; + case UNW_X86_64_CS: + _registers.__cs = static_cast<uint16_t>(value); + return; + case UNW_X86_64_SS: + _registers.__ss = static_cast<uint16_t>(value); + return; + case UNW_X86_64_DS: + _registers.__ds = static_cast<uint16_t>(value); + return; + case UNW_X86_64_FS: + _registers.__fs = static_cast<uint16_t>(value); + return; + case UNW_X86_64_GS: + _registers.__gs = static_cast<uint16_t>(value); + return; + case UNW_X86_64_FS_BASE: + _registers.__fs_base = value; + return; + case UNW_X86_64_GS_BASE: + _registers.__gs_base = value; + return; } _LIBUNWIND_ABORT("unsupported x86_64 register"); } @@ -526,6 +588,24 @@ inline const char *Registers_x86_64::getRegisterName(int regNum) { return "r14"; case UNW_X86_64_R15: return "r15"; + case UNW_X86_64_RFLAGS: + return "rflags"; + case UNW_X86_64_ES: + return "es"; + case UNW_X86_64_CS: + return "cs"; + case UNW_X86_64_SS: + return "ss"; + case UNW_X86_64_DS: + return "ds"; + case UNW_X86_64_FS: + return "fs"; + case UNW_X86_64_GS: + return "gs"; + case UNW_X86_64_FS_BASE: + return "fs.base"; + case UNW_X86_64_GS_BASE: + return "gs.base"; case UNW_X86_64_XMM0: return "xmm0"; case UNW_X86_64_XMM1: diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S index 6c9dcc48c309ad..b1b075ba556f91 100644 --- a/libunwind/src/UnwindRegistersRestore.S +++ b/libunwind/src/UnwindRegistersRestore.S @@ -72,7 +72,10 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto) # skip fs # skip gs -#elif defined(__x86_64__) && !defined(__arm64ec__) +// Native FreeBSD restores selectors and bases together through sigreturn in +// libunwind.cpp; its sysarch base setters also replace the segment selectors. +#elif defined(__x86_64__) && !defined(__arm64ec__) && \ + (!defined(__FreeBSD__) || defined(_LIBUNWIND_IS_BAREMETAL)) .att_syntax DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto) diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S index 81d32009952895..1dbc1f697bc14a 100644 --- a/libunwind/src/UnwindRegistersSave.S +++ b/libunwind/src/UnwindRegistersSave.S @@ -138,7 +138,9 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) movq %rsi, 40(PTR) movq %rbp, 48(PTR) movq %rsp, 56(PTR) +#if !defined(X86_64_BASE_SYSCALL) addq $8, 56(PTR) +#endif movq %r8, 64(PTR) movq %r9, 72(PTR) movq %r10, 80(PTR) @@ -152,10 +154,47 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) #endif movq (%rsp),TMP movq TMP,128(PTR) # store return address as rip +#if defined(X86_64_BASE_SYSCALL) + # Capture flags before any instruction that changes them. + pushfq + popq TMP + movl %esi,136(PTR) + leaq 8(%rsp),TMP + movq TMP,56(PTR) # store what sp was at call site as rsp + movw %cs,140(PTR) + movw %fs,148(PTR) + movw %gs,150(PTR) + movw %es,146(PTR) + movw %ss,142(PTR) + movw %ds,144(PTR) + movq $0,152(PTR) + movq $0,160(PTR) + + # Use syscalls rather than FSGSBASE instructions, which require both CPU + # support and OS enablement. All syscall-clobbered registers are saved above. + # FreeBSD may clear r8-r10 on syscall return. Keep the context pointer in + # the callee-saved rbx, preserving its value for our caller as well. + pushq %rbx + movq PTR,%rbx + movq $X86_64_BASE_SYSCALL,%rax + movq $X86_64_GET_FSBASE,%rdi + leaq 152(%rbx),%rsi + syscall + # FreeBSD reports errors in CF with a positive errno in rax. + jc 9f + movq $X86_64_BASE_SYSCALL,%rax + movq $X86_64_GET_GSBASE,%rdi + leaq 160(%rbx),%rsi + syscall + jc 9f + movq %rbx,PTR + popq %rbx +#else # skip rflags # skip cs # skip fs # skip gs +#endif #if defined(_WIN64) movdqu %xmm0,176(PTR) @@ -177,6 +216,12 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) #endif xorl %eax, %eax # return UNW_ESUCCESS ret +#if defined(X86_64_BASE_SYSCALL) +9: + popq %rbx + movl $-6540,%eax # UNW_EUNSPEC: segment base capture failed + ret +#endif #elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 diff --git a/libunwind/src/assembly.h b/libunwind/src/assembly.h index 84c9d526f1d759..43c2ad78f3a0ba 100644 --- a/libunwind/src/assembly.h +++ b/libunwind/src/assembly.h @@ -15,6 +15,15 @@ #ifndef UNWIND_ASSEMBLY_H #define UNWIND_ASSEMBLY_H +#if defined(__x86_64__) && defined(__FreeBSD__) && \ + !defined(_LIBUNWIND_IS_BAREMETAL) +#include <sys/syscall.h> +// <machine/sysarch.h> contains C declarations and cannot be included here. +#define X86_64_GET_FSBASE 128 // AMD64_GET_FSBASE +#define X86_64_GET_GSBASE 130 // AMD64_GET_GSBASE +#define X86_64_BASE_SYSCALL SYS_sysarch +#endif + #if defined(__CET__) #include <cet.h> #define _LIBUNWIND_CET_ENDBR _CET_ENDBR diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp index 0b9d56ec805bca..29364a0fe2818f 100644 --- a/libunwind/src/libunwind.cpp +++ b/libunwind/src/libunwind.cpp @@ -16,6 +16,12 @@ #include <stdlib.h> +#if defined(__FreeBSD__) && defined(__x86_64__) && \ + !defined(_LIBUNWIND_IS_BAREMETAL) +#include <signal.h> +#include <ucontext.h> +#endif + // Define the __has_feature extension for compilers that do not support it so // that we can later check for the presence of ASan in a compiler-neutral way. #if !defined(__has_feature) @@ -32,6 +38,52 @@ using namespace libunwind; +#if defined(__FreeBSD__) && defined(__x86_64__) && \ + !defined(_LIBUNWIND_IS_BAREMETAL) +// Changing FS/GS selectors can clear their bases, while sysarch base setters +// replace the selectors. Let sigreturn restore the complete state atomically. +// use sigreturn() over setcontext() as setcontext() intentionally leaves CS +// unchanged. +extern "C" _LIBUNWIND_HIDDEN void +__libunwind_Registers_x86_64_jumpto(Registers_x86_64 *registers) { + ucontext_t context; + if (getcontext(&context) != 0) + _LIBUNWIND_ABORT("getcontext failed"); + mcontext_t &mc = context.uc_mcontext; +#define RESTORE(reg, field) mc.field = registers->getRegister(UNW_X86_64_##reg) + RESTORE(RAX, mc_rax); + RESTORE(RBX, mc_rbx); + RESTORE(RCX, mc_rcx); + RESTORE(RDX, mc_rdx); + RESTORE(RDI, mc_rdi); + RESTORE(RSI, mc_rsi); + RESTORE(RBP, mc_rbp); + RESTORE(RSP, mc_rsp); + RESTORE(R8, mc_r8); + RESTORE(R9, mc_r9); + RESTORE(R10, mc_r10); + RESTORE(R11, mc_r11); + RESTORE(R12, mc_r12); + RESTORE(R13, mc_r13); + RESTORE(R14, mc_r14); + RESTORE(R15, mc_r15); + RESTORE(RIP, mc_rip); + RESTORE(RFLAGS, mc_rflags); + RESTORE(CS, mc_cs); + RESTORE(SS, mc_ss); + RESTORE(DS, mc_ds); + RESTORE(ES, mc_es); + RESTORE(FS, mc_fs); + RESTORE(GS, mc_gs); + RESTORE(FS_BASE, mc_fsbase); + RESTORE(GS_BASE, mc_gsbase); +#undef RESTORE + mc.mc_flags |= _MC_HASSEGS | _MC_HASBASES; + sigreturn(&context); + _LIBUNWIND_ABORT("sigreturn failed"); +} +#endif + /// internal object to represent this process's address space LocalAddressSpace LocalAddressSpace::sThisAddressSpace; diff --git a/libunwind/test/x86_64_dwarf_registers.pass.cpp b/libunwind/test/x86_64_dwarf_registers.pass.cpp new file mode 100644 index 00000000000000..fc7de291542dec --- /dev/null +++ b/libunwind/test/x86_64_dwarf_registers.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: target={{x86_64-.*-freebsd.*}} +// ADDITIONAL_COMPILE_FLAGS: -D_LIBUNWIND_IS_NATIVE_ONLY + +// Disable internal tracing, which depends on private library symbols. +#ifndef NDEBUG +#define NDEBUG +#endif +#include "../src/AddressSpace.hpp" +#include "../src/DwarfParser.hpp" +#undef NDEBUG +#include <assert.h> + +using namespace libunwind; + +int main(int, char **) { + using Parser = CFI_Parser<LocalAddressSpace>; + LocalAddressSpace addressSpace; + Parser::CIE_Info cie = {}; + cie.codeAlignFactor = 1; + cie.dataAlignFactor = -8; + Parser::FDE_Info fde = {}; + const uint8_t instructions[] = { + DW_CFA_offset_extended, 49, 1, DW_CFA_offset_extended, 50, 2, + DW_CFA_offset_extended, 51, 3, DW_CFA_offset_extended, 52, 4, + DW_CFA_offset_extended, 53, 5, DW_CFA_offset_extended, 54, 6, + DW_CFA_offset_extended, 55, 7, DW_CFA_offset_extended, 58, 8, + DW_CFA_offset_extended, 59, 9}; + fde.fdeInstructions = reinterpret_cast<uintptr_t>(instructions); + fde.fdeStart = fde.fdeInstructions; + fde.fdeLength = sizeof(instructions); + Parser::PrologInfo prolog; + assert(Parser::parseFDEInstructions<Registers_x86_64>( + addressSpace, fde, cie, 1, REGISTERS_X86_64, &prolog)); + const int regs[] = {49, 50, 51, 52, 53, 54, 55, 58, 59}; + Registers_x86_64 registers; + for (unsigned i = 0; i != sizeof(regs) / sizeof(regs[0]); ++i) { + assert(prolog.savedRegisters[regs[i]].location == Parser::kRegisterInCFA); + assert(prolog.savedRegisters[regs[i]].value == -8 * int(i + 1)); + // Also exercise the stored values for the extended registers. + registers.setRegister(regs[i], i + 1); + assert(registers.getRegister(regs[i]) == i + 1); + } + const uint8_t invalid[] = {DW_CFA_offset_extended, 60, 1}; + fde.fdeInstructions = reinterpret_cast<uintptr_t>(invalid); + fde.fdeStart = fde.fdeInstructions; + fde.fdeLength = sizeof(invalid); + assert(!Parser::parseFDEInstructions<Registers_x86_64>( + addressSpace, fde, cie, 1, REGISTERS_X86_64, &prolog)); + return 0; +} diff --git a/libunwind/test/x86_64_extended_registers.pass.cpp b/libunwind/test/x86_64_extended_registers.pass.cpp new file mode 100644 index 00000000000000..ac966073beae75 --- /dev/null +++ b/libunwind/test/x86_64_extended_registers.pass.cpp @@ -0,0 +1,146 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: target={{x86_64-.*-freebsd.*}} +// UNSUPPORTED: msan + +#undef NDEBUG +#include <assert.h> +#include <libunwind.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include <machine/sysarch.h> + +#define STRINGIFY_IMPL(x) #x +#define STRINGIFY(x) STRINGIFY_IMPL(x) +#define SYMBOL(x) STRINGIFY(__USER_LABEL_PREFIX__) #x + +static const int selectors[] = {UNW_X86_64_ES, UNW_X86_64_CS, UNW_X86_64_SS, + UNW_X86_64_DS, UNW_X86_64_FS, UNW_X86_64_GS}; +static const char *names[] = {"es", "cs", "ss", "ds", "fs", "gs"}; + +static unw_word_t get(unw_cursor_t &cursor, int reg) { + unw_word_t value; + assert(unw_get_reg(&cursor, reg, &value) == UNW_ESUCCESS); + return value; +} + +// A tail call preserves the flags and stack pointer of our caller. In +// particular, getcontext must capture CF before adjusting its saved SP. +extern "C" __attribute__((naked)) int capture(unw_context_t *) { + __asm__("stc\n" + "jmp " SYMBOL(unw_getcontext) "\n"); +} + +static void test_capture_and_access() { + unw_context_t context; + // Resolve the shared-library entry point before testing CF: lazy binding + // can change flags between capture's tail call and getcontext's entry. + assert(unw_getcontext(&context) == UNW_ESUCCESS); + memset(&context, 0xa5, sizeof(context)); + assert(capture(&context) == UNW_ESUCCESS); + unw_cursor_t cursor; + assert(unw_init_local(&cursor, &context) == UNW_ESUCCESS); + assert(get(cursor, UNW_X86_64_RFLAGS) & 1); + assert(strcmp(unw_regname(&cursor, UNW_X86_64_RFLAGS), "rflags") == 0); + + uint16_t actual[6]; + __asm__ volatile("movw %%es, %0\n" + "movw %%cs, %1\n" + "movw %%ss, %2\n" + "movw %%ds, %3\n" + "movw %%fs, %4\n" + "movw %%gs, %5\n" + : "=m"(actual[0]), "=m"(actual[1]), "=m"(actual[2]), + "=m"(actual[3]), "=m"(actual[4]), "=m"(actual[5])); + for (unsigned i = 0; i != 6; ++i) { + assert(get(cursor, selectors[i]) == actual[i]); + assert(strcmp(unw_regname(&cursor, selectors[i]), names[i]) == 0); + assert(unw_set_reg(&cursor, selectors[i], 0x12345678) == UNW_ESUCCESS); + assert(get(cursor, selectors[i]) == 0x5678); + } + + uintptr_t fs, gs; + assert(sysarch(AMD64_GET_FSBASE, &fs) == 0); + assert(sysarch(AMD64_GET_GSBASE, &gs) == 0); + assert(get(cursor, UNW_X86_64_FS_BASE) == fs); + assert(get(cursor, UNW_X86_64_GS_BASE) == gs); + assert(strcmp(unw_regname(&cursor, UNW_X86_64_FS_BASE), "fs.base") == 0); + assert(strcmp(unw_regname(&cursor, UNW_X86_64_GS_BASE), "gs.base") == 0); + assert(unw_set_reg(&cursor, UNW_X86_64_FS_BASE, 0x12345678) == UNW_ESUCCESS); + assert(get(cursor, UNW_X86_64_FS_BASE) == 0x12345678); + assert(unw_set_reg(&cursor, UNW_X86_64_GS_BASE, 0x87654321) == UNW_ESUCCESS); + assert(get(cursor, UNW_X86_64_GS_BASE) == 0x87654321); + + unw_word_t value; + assert(unw_get_reg(&cursor, 56, &value) == UNW_EBADREG); + assert(unw_get_reg(&cursor, 57, &value) == UNW_EBADREG); + assert(unw_get_reg(&cursor, 60, &value) == UNW_EBADREG); +} + +extern "C" void check_cfi() { + unw_context_t context; + unw_cursor_t cursor; + assert(unw_getcontext(&context) == UNW_ESUCCESS); + assert(unw_init_local(&cursor, &context) == UNW_ESUCCESS); + assert(unw_step(&cursor) > 0); // to the synthetic trampoline + assert(unw_step(&cursor) > 0); // recover its saved registers + assert(get(cursor, UNW_X86_64_RFLAGS) == 0x203); + for (unsigned i = 0; i != 6; ++i) + assert(get(cursor, selectors[i]) == unsigned(selectors[i])); + assert(get(cursor, UNW_X86_64_FS_BASE) == 0x12345678); + assert(get(cursor, UNW_X86_64_GS_BASE) == 0x87654321); +} + +// Model the previously disabled FreeBSD sigtramp CFI, including the packed +// 16-bit selectors whose adjacent data must not become part of their values. +__attribute__((naked)) void trampoline() { + __asm__(".cfi_signal_frame\n" + "pushq %rbp\n" + ".cfi_def_cfa_offset 16\n" + ".cfi_offset 6, -16\n" + "movq %rsp, %rbp\n" + ".cfi_def_cfa_register 6\n" + "subq $80, %rsp\n" + "movq $0x203, -8(%rbp)\n" + ".cfi_offset 49, -24\n" + "movq $50, -16(%rbp)\n" + "movw $0xabcd, -14(%rbp)\n" + ".cfi_offset 50, -32\n" + "movq $51, -24(%rbp)\n" + ".cfi_offset 51, -40\n" + "movq $52, -32(%rbp)\n" + ".cfi_offset 52, -48\n" + "movq $53, -40(%rbp)\n" + "movw $0xabcd, -38(%rbp)\n" + ".cfi_offset 53, -56\n" + "movq $54, -48(%rbp)\n" + "movw $0xabcd, -46(%rbp)\n" + ".cfi_offset 54, -64\n" + "movq $55, -56(%rbp)\n" + "movw $0xabcd, -54(%rbp)\n" + ".cfi_offset 55, -72\n" + "movq $0x12345678, -64(%rbp)\n" + ".cfi_offset 58, -80\n" + "movl $0x87654321, -72(%rbp)\n" + "movl $0, -68(%rbp)\n" + ".cfi_offset 59, -88\n" + "call " SYMBOL(check_cfi) "\n" + "leave\n" + ".cfi_def_cfa 7, 8\n" + ".cfi_restore 6\n" + "ret\n"); +} + +int main(int, char **) { + test_capture_and_access(); + trampoline(); + return 0; +} diff --git a/libunwind/test/x86_64_getcontext_preserves_rbx.pass.cpp b/libunwind/... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/237265 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
