From nobody Sun Oct 25 12:12:28 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4jCFxm3LkBz6wHfy for ; Sun, 25 Oct 2026 12:12:28 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 4jCFxm14QBz4DDS for ; Sun, 25 Oct 2026 12:12:28 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1792930348; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=zOvLKNrR5Mr9DqHMGjgF4jkAa9UYSds3WuNuKbVigu4=; b=Tr+dm4TYpExAW2JVG1POhywZI0CL+6uws54/GY9a3hGEsZD7M7HGboPBJZsN7Tklo6OGPs jibdDoz0V4SwuTFIb+wWorhbdZS2EVxtt7yeHOcEWmL/aztEzwVNTMv7gHOgT6aYAt7srb T362LhRKsjXPCjf5vuI5eSqzS+IibMQLDpIGDwjWsH7qqm47uYn9kh2xUbZ/0NyGotJCFX C+LJXPeZnk3wBN7LOLwI0nqo45b0IiZzw0YL5q/P1bLucxm0aYv4XA2jHESdKDp0orA3a9 +vB+afnASpF3g3pnAzemoy1iXJIvvtsXwvbj0YIY2L4HFzIltnv8sHKKUkbZsg== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1792930348; b=iDR3A7gO+TvEkfTIZZpWaXggSVOXMa6D35OHJjywEBNcV5hspLpfGVb/v2kGM+kbUZ2Mes uGAhTQZy8Nz0+8vO1IZa1duwQUjmNt4RzQZ0ghVZj7is7bG4/D6sfZr4nhK3z3/oEg6Y+F 1gCL0t5OhSPJuyed2OO1q6GrMaHSniFLIL8k0FNT83+VyO+0suLsALyijmQFmzPXJ3hZZP s5vR4iCREltztyZ5Fnv5VSHcxWFGxt7O0Bj/eGtiAW2j9oWMwkO2EU1jiyt8/kLxeFM2QO fRXcbcOU3TafLkT5w6bCw8cFnbnGvgU3aigNYzowkx90D/zG9lBcz68tH5HWag== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1792930348; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=zOvLKNrR5Mr9DqHMGjgF4jkAa9UYSds3WuNuKbVigu4=; b=uDYcoW0GFxOfHK9jaeEi1z0PMCAE3QRSsiOWn7GB7nvk+CZYTupV4j8DR1BbHQ0TWdj6xi n21fNaTr0m0n5yYs9KU3GU86Hu+n5uYoF+wSeryG/FhCIqS4ia6TP6NrBuzOa/55jYEooA BPs0lBb98TF5WdNvr09BABXWJ1nKuu8XwwMLUbTeC16C6SU6uWkaEUT4UkLaGwKbPE8q/L sOSS1AteNktvw6zN2wQvuT5EmW2WKuu2wg0Em0sxUgPbtk/caaO4WzgfAUCUUhrS/j6Gsk yFMsCMZT8v3ynOwOLxY+CcYbw0YHsNypNo4GcGbXXQtUPM2OzvwYzh9ZAmdH3A== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4jCFxm0YmxzmY2 for ; Sun, 25 Oct 2026 12:12:28 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 24958 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sun, 25 Oct 2026 12:12:28 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Dimitry Andric Subject: git: 28ec7cb8712f - main - Merge commit fd4113508a64 from llvm-project (by Minsoo Choo): List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: Commit messages for the main branch of the src repository List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: dim X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 28ec7cb8712fde61107126c8ff174578d0ccdf79 Auto-Submitted: auto-generated Date: Sun, 25 Oct 2026 12:12:28 +0000 Message-Id: <6addf22c.24958.33cfe975@gitrepo.freebsd.org> The branch main has been updated by dim: URL: https://cgit.FreeBSD.org/src/commit/?id=28ec7cb8712fde61107126c8ff174578d0ccdf79 commit 28ec7cb8712fde61107126c8ff174578d0ccdf79 Author: Dimitry Andric AuthorDate: 2026-10-25 12:10:59 +0000 Commit: Dimitry Andric CommitDate: 2026-10-25 12:11:27 +0000 Merge commit fd4113508a64 from llvm-project (by Minsoo Choo): [libunwind] Support extended amd64 segment registers (#229176) 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 sigreturn() 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 MFC after: 1 week --- .../libunwind/include/__libunwind_config.h | 2 +- contrib/llvm-project/libunwind/include/libunwind.h | 9 ++ .../llvm-project/libunwind/src/AddressSpace.hpp | 4 +- contrib/llvm-project/libunwind/src/Registers.hpp | 99 ++++++++++++++++++++-- .../llvm-project/libunwind/src/UnwindCursor.hpp | 27 ++++++ .../libunwind/src/UnwindRegistersRestore.S | 69 +++++++++++++-- .../libunwind/src/UnwindRegistersSave.S | 62 ++++++++++++-- contrib/llvm-project/libunwind/src/assembly.h | 18 ++++ contrib/llvm-project/libunwind/src/libunwind.cpp | 52 ++++++++++++ 9 files changed, 320 insertions(+), 22 deletions(-) diff --git a/contrib/llvm-project/libunwind/include/__libunwind_config.h b/contrib/llvm-project/libunwind/include/__libunwind_config.h index 493910c3df51..6db1a71dd73d 100644 --- a/contrib/llvm-project/libunwind/include/__libunwind_config.h +++ b/contrib/llvm-project/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/contrib/llvm-project/libunwind/include/libunwind.h b/contrib/llvm-project/libunwind/include/libunwind.h index b2dae8feed9a..9c6efe1e2629 100644 --- a/contrib/llvm-project/libunwind/include/libunwind.h +++ b/contrib/llvm-project/libunwind/include/libunwind.h @@ -190,6 +190,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/contrib/llvm-project/libunwind/src/AddressSpace.hpp b/contrib/llvm-project/libunwind/src/AddressSpace.hpp index 5551c7d4bef1..082216e1629b 100644 --- a/contrib/llvm-project/libunwind/src/AddressSpace.hpp +++ b/contrib/llvm-project/libunwind/src/AddressSpace.hpp @@ -437,8 +437,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(data); if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr) return 0; diff --git a/contrib/llvm-project/libunwind/src/Registers.hpp b/contrib/llvm-project/libunwind/src/Registers.hpp index 2c3bfb7e8428..32d1ff0579eb 100644 --- a/contrib/llvm-project/libunwind/src/Registers.hpp +++ b/contrib/llvm-project/libunwind/src/Registers.hpp @@ -330,14 +330,26 @@ private: uint64_t __r14; uint64_t __r15; uint64_t __rip; - uint64_t __rflags; - uint64_t __cs; - uint64_t __fs; - uint64_t __gs; + // RFLAGS bits 32-63 are reserved. Pack the selectors with the low flags + // word so the complete segment state fits the existing context ABI. + 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]; @@ -361,9 +373,19 @@ 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; + if (regNum >= UNW_X86_64_RFLAGS && regNum <= UNW_X86_64_GS) + return true; + // Native base capture and restore need an OS interface. Cross unwinding + // can still represent bases recovered from DWARF on any host. +#if (!defined(_LIBUNWIND_IS_BAREMETAL) && \ + (defined(__linux__) || defined(__FreeBSD__))) || \ + !defined(_LIBUNWIND_IS_NATIVE_ONLY) + 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 { @@ -405,6 +427,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"); } @@ -466,6 +506,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(value); + return; + case UNW_X86_64_ES: + _registers.__es = static_cast(value); + return; + case UNW_X86_64_CS: + _registers.__cs = static_cast(value); + return; + case UNW_X86_64_SS: + _registers.__ss = static_cast(value); + return; + case UNW_X86_64_DS: + _registers.__ds = static_cast(value); + return; + case UNW_X86_64_FS: + _registers.__fs = static_cast(value); + return; + case UNW_X86_64_GS: + _registers.__gs = static_cast(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"); } @@ -509,6 +576,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/contrib/llvm-project/libunwind/src/UnwindCursor.hpp b/contrib/llvm-project/libunwind/src/UnwindCursor.hpp index 067a3c238245..0edc4258e846 100644 --- a/contrib/llvm-project/libunwind/src/UnwindCursor.hpp +++ b/contrib/llvm-project/libunwind/src/UnwindCursor.hpp @@ -620,6 +620,7 @@ UnwindCursor::UnwindCursor(unw_context_t *context, A &as) RtlCaptureContext(&_msContext); _msContext.ContextFlags = CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_FLOATING_POINT; #if defined(_LIBUNWIND_TARGET_X86_64) + _msContext.ContextFlags |= CONTEXT_SEGMENTS; _msContext.Rax = r.getRegister(UNW_X86_64_RAX); _msContext.Rcx = r.getRegister(UNW_X86_64_RCX); _msContext.Rdx = r.getRegister(UNW_X86_64_RDX); @@ -637,6 +638,17 @@ UnwindCursor::UnwindCursor(unw_context_t *context, A &as) _msContext.R14 = r.getRegister(UNW_X86_64_R14); _msContext.R15 = r.getRegister(UNW_X86_64_R15); _msContext.Rip = r.getRegister(UNW_REG_IP); + // ARM64EC getcontext leaves these fields zero. Keep the values supplied by + // RtlCaptureContext instead of replacing them with uncaptured x86 state. +#if !defined(__arm64ec__) + _msContext.EFlags = static_cast(r.getRegister(UNW_X86_64_RFLAGS)); + _msContext.SegEs = static_cast(r.getRegister(UNW_X86_64_ES)); + _msContext.SegCs = static_cast(r.getRegister(UNW_X86_64_CS)); + _msContext.SegSs = static_cast(r.getRegister(UNW_X86_64_SS)); + _msContext.SegDs = static_cast(r.getRegister(UNW_X86_64_DS)); + _msContext.SegFs = static_cast(r.getRegister(UNW_X86_64_FS)); + _msContext.SegGs = static_cast(r.getRegister(UNW_X86_64_GS)); +#endif union { v128 v; M128A m; @@ -727,6 +739,7 @@ bool UnwindCursor::validReg(int regNum) { if (regNum == UNW_REG_IP || regNum == UNW_REG_SP) return true; #if defined(_LIBUNWIND_TARGET_X86_64) if (regNum >= UNW_X86_64_RAX && regNum <= UNW_X86_64_RIP) return true; + if (regNum >= UNW_X86_64_RFLAGS && regNum <= UNW_X86_64_GS) return true; #elif defined(_LIBUNWIND_TARGET_ARM) if ((regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) || regNum == UNW_ARM_RA_AUTH_CODE) @@ -760,6 +773,13 @@ unw_word_t UnwindCursor::getReg(int regNum) { case UNW_X86_64_R13: return _msContext.R13; case UNW_X86_64_R14: return _msContext.R14; case UNW_X86_64_R15: return _msContext.R15; + case UNW_X86_64_RFLAGS: return _msContext.EFlags; + case UNW_X86_64_ES: return _msContext.SegEs; + case UNW_X86_64_CS: return _msContext.SegCs; + case UNW_X86_64_SS: return _msContext.SegSs; + case UNW_X86_64_DS: return _msContext.SegDs; + case UNW_X86_64_FS: return _msContext.SegFs; + case UNW_X86_64_GS: return _msContext.SegGs; #elif defined(_LIBUNWIND_TARGET_ARM) case UNW_ARM_R0: return _msContext.R0; case UNW_ARM_R1: return _msContext.R1; @@ -811,6 +831,13 @@ void UnwindCursor::setReg(int regNum, unw_word_t value) { case UNW_X86_64_R13: _msContext.R13 = value; break; case UNW_X86_64_R14: _msContext.R14 = value; break; case UNW_X86_64_R15: _msContext.R15 = value; break; + case UNW_X86_64_RFLAGS: _msContext.EFlags = static_cast(value); break; + case UNW_X86_64_ES: _msContext.SegEs = static_cast(value); break; + case UNW_X86_64_CS: _msContext.SegCs = static_cast(value); break; + case UNW_X86_64_SS: _msContext.SegSs = static_cast(value); break; + case UNW_X86_64_DS: _msContext.SegDs = static_cast(value); break; + case UNW_X86_64_FS: _msContext.SegFs = static_cast(value); break; + case UNW_X86_64_GS: _msContext.SegGs = static_cast(value); break; #elif defined(_LIBUNWIND_TARGET_ARM) case UNW_ARM_R0: _msContext.R0 = value; break; case UNW_ARM_R1: _msContext.R1 = value; break; diff --git a/contrib/llvm-project/libunwind/src/UnwindRegistersRestore.S b/contrib/llvm-project/libunwind/src/UnwindRegistersRestore.S index 1bcd205be260..4627b06c5954 100644 --- a/contrib/llvm-project/libunwind/src/UnwindRegistersRestore.S +++ b/contrib/llvm-project/libunwind/src/UnwindRegistersRestore.S @@ -66,7 +66,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)) DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto) # @@ -91,6 +94,57 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto) movq %rbx, 0(%rax) movq 128(%rdi), %rbx # store new rip on new stack movq %rbx, 8(%rax) + # Segment selectors are 16 bits. In particular, do not reload unchanged + # FS/GS selectors: doing so can clear their hidden base addresses. + movw %fs,%ax + cmpw 148(%rdi),%ax + je 1f + movw 148(%rdi),%fs +1: + movw %gs,%ax + cmpw 150(%rdi),%ax + je 2f + movw 150(%rdi),%gs +2: + movw 146(%rdi),%es + movw 142(%rdi),%ss + movw 144(%rdi),%ds + movw %cs,%ax + cmpw 140(%rdi),%ax + je 3f + # An indirect far jump changes CS without consuming a shadow-stack entry. + movzwq 140(%rdi),%rax + pushq %rax + leaq 3f(%rip),%rax + pushq %rax + rex64 ljmp *(%rsp) +3: + _LIBUNWIND_CET_ENDBR + # The far-jump path used a temporary 16-byte far pointer on the old stack. + # The old stack is discarded below. + +#if defined(X86_64_BASE_SYSCALL) + movq %rdi,%r8 + movq $X86_64_BASE_SYSCALL,%rax + movq $X86_64_SET_FSBASE,%rdi + movq 152(%r8),%rsi + syscall + testq %rax,%rax + js 9f + movq $X86_64_BASE_SYSCALL,%rax + movq $X86_64_SET_GSBASE,%rdi + movq 160(%r8),%rsi + syscall + testq %rax,%rax + js 9f + movq %r8,%rdi +#endif + + # Restore flags after all arithmetic, comparisons, and syscalls. The upper + # half of the packed flags word contains selectors, so zero-extend it first. + movl 136(%rdi),%eax + pushq %rax + popfq # restore all registers movq 0(%rdi), %rax movq 8(%rdi), %rbx @@ -108,10 +162,6 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto) movq 104(%rdi), %r13 movq 112(%rdi), %r14 movq 120(%rdi), %r15 - # skip rflags - # skip cs - # skip fs - # skip gs #if defined(_WIN64) movdqu 176(%rdi),%xmm0 @@ -133,8 +183,13 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto) #endif movq 56(%rdi), %rsp # cut back rsp to new location pop %rdi # rdi was saved here earlier - pop %rcx - jmpq *%rcx + leaq 8(%rsp),%rsp + jmpq *-8(%rsp) +#if defined(X86_64_BASE_SYSCALL) +9: + # A failed base restore cannot safely resume with a different TLS base. + ud2 +#endif #elif defined(__powerpc64__) diff --git a/contrib/llvm-project/libunwind/src/UnwindRegistersSave.S b/contrib/llvm-project/libunwind/src/UnwindRegistersSave.S index bd41dfcb9db4..307508fd9bbe 100644 --- a/contrib/llvm-project/libunwind/src/UnwindRegistersSave.S +++ b/contrib/llvm-project/libunwind/src/UnwindRegistersSave.S @@ -86,6 +86,8 @@ DEFINE_LIBUNWIND_FUNCTION("#__unw_getcontext") stp x19,x20, [x0, #0x060] // r12, r13 stp x21,x22, [x0, #0x070] // r14, r15 str x30, [x0, #0x080] // store return address as pc + stp xzr,xzr, [x0, #0x088] // flags and segment selectors + stp xzr,xzr, [x0, #0x098] // fs.base, gs.base stp q0, q1, [x0, #0x0b0] // xmm0, xmm1 stp q2, q3, [x0, #0x0d0] // xmm2, xmm3 stp q4, q5, [x0, #0x0f0] // xmm4, xmm5 @@ -118,9 +120,11 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) #if defined(_WIN64) #define PTR %rcx #define TMP %rdx +#define TMP32 %edx #else #define PTR %rdi #define TMP %rsi +#define TMP32 %esi #endif _LIBUNWIND_CET_ENDBR @@ -132,7 +136,6 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) movq %rsi, 40(PTR) movq %rbp, 48(PTR) movq %rsp, 56(PTR) - addq $8, 56(PTR) movq %r8, 64(PTR) movq %r9, 72(PTR) movq %r10, 80(PTR) @@ -143,10 +146,53 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) movq %r15,120(PTR) movq (%rsp),TMP movq TMP,128(PTR) # store return address as rip - # skip rflags - # skip cs - # skip fs - # skip gs + # Capture flags before any instruction that changes them. + pushfq + popq TMP + movl TMP32,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) + +#if defined(X86_64_BASE_SYSCALL) + # 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; Linux returns + # a negative errno in rax. Check the appropriate convention after each call. +#if defined(__FreeBSD__) + jc 9f +#else + testq %rax,%rax + js 9f +#endif + movq $X86_64_BASE_SYSCALL,%rax + movq $X86_64_GET_GSBASE,%rdi + leaq 160(%rbx),%rsi + syscall +#if defined(__FreeBSD__) + jc 9f +#else + testq %rax,%rax + js 9f +#endif + movq %rbx,PTR + popq %rbx +#endif #if defined(_WIN64) movdqu %xmm0,176(PTR) @@ -168,6 +214,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/contrib/llvm-project/libunwind/src/assembly.h b/contrib/llvm-project/libunwind/src/assembly.h index f8e83e138eff..53c1ab9cfe59 100644 --- a/contrib/llvm-project/libunwind/src/assembly.h +++ b/contrib/llvm-project/libunwind/src/assembly.h @@ -15,6 +15,24 @@ #ifndef UNWIND_ASSEMBLY_H #define UNWIND_ASSEMBLY_H +#if defined(__x86_64__) && !defined(_LIBUNWIND_IS_BAREMETAL) && \ + (defined(__linux__) || defined(__FreeBSD__)) +#include +#if defined(__linux__) +#include +#define X86_64_GET_FSBASE ARCH_GET_FS +#define X86_64_GET_GSBASE ARCH_GET_GS +#define X86_64_SET_FSBASE ARCH_SET_FS +#define X86_64_SET_GSBASE ARCH_SET_GS +#define X86_64_BASE_SYSCALL SYS_arch_prctl +#else +// 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 +#endif + #if defined(__linux__) && defined(__CET__) #include #define _LIBUNWIND_CET_ENDBR _CET_ENDBR diff --git a/contrib/llvm-project/libunwind/src/libunwind.cpp b/contrib/llvm-project/libunwind/src/libunwind.cpp index cf39ec5f7dbd..1117076349ff 100644 --- a/contrib/llvm-project/libunwind/src/libunwind.cpp +++ b/contrib/llvm-project/libunwind/src/libunwind.cpp @@ -16,6 +16,12 @@ #include +#if defined(__FreeBSD__) && defined(__x86_64__) && \ + !defined(_LIBUNWIND_IS_BAREMETAL) +#include +#include +#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 processes address space LocalAddressSpace LocalAddressSpace::sThisAddressSpace;