diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt index 41d541f475290..41e3fc200ab71 100644 --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -460,6 +460,20 @@ add_header_macro( .llvm_libc_common_h ) +if(LIBC_TARGET_ARCHITECTURE STREQUAL "x86_64") + add_header_macro( + ucontext + ../libc/include/ucontext.yaml + ucontext.h + DEPENDS + .llvm_libc_common_h + .llvm-libc-types.mcontext_t + .llvm-libc-types.ucontext_t + .llvm-libc-types.sigset_t + .llvm-libc-types.stack_t + ) +endif() + add_header_macro( sched ../libc/include/sched.yaml diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt index 0d6bc0982b847..e40f6e194ab3a 100644 --- a/libc/include/llvm-libc-types/CMakeLists.txt +++ b/libc/include/llvm-libc-types/CMakeLists.txt @@ -126,6 +126,31 @@ add_header(union_sigval HDR union_sigval.h) add_header(siginfo_t HDR siginfo_t.h DEPENDS .union_sigval .pid_t .uid_t .clock_t) add_header(sig_atomic_t HDR sig_atomic_t.h) add_header(sigset_t HDR sigset_t.h DEPENDS libc.include.llvm-libc-macros.signal_macros) +set(mcontext_deps) +set(ucontext_deps .sigset_t .stack_t) + +if(LIBC_TARGET_ARCHITECTURE STREQUAL "x86_64") + file(COPY x86_64 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + add_header( + mcontext_t_arch + HDR + x86_64/mcontext_t.h + ) + add_header( + ucontext_t_arch + HDR + x86_64/ucontext_t.h + DEPENDS + .mcontext_t_arch + .sigset_t + .stack_t + ) + list(APPEND mcontext_deps .mcontext_t_arch) + list(APPEND ucontext_deps .ucontext_t_arch) +endif() + +add_header(mcontext_t HDR mcontext_t.h DEPENDS ${mcontext_deps}) +add_header(ucontext_t HDR ucontext_t.h DEPENDS .mcontext_t ${ucontext_deps}) add_header(__jmp_buf HDR __jmp_buf.h DEPENDS .sigset_t) add_header(jmp_buf HDR jmp_buf.h DEPENDS .__jmp_buf) add_header(sigjmp_buf HDR sigjmp_buf.h DEPENDS .__jmp_buf) diff --git a/libc/include/llvm-libc-types/mcontext_t.h b/libc/include/llvm-libc-types/mcontext_t.h new file mode 100644 index 0000000000000..f2226555c2ac8 --- /dev/null +++ b/libc/include/llvm-libc-types/mcontext_t.h @@ -0,0 +1,18 @@ +//===-- Definition of type mcontext_t -------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TYPES_MCONTEXT_T_H +#define LLVM_LIBC_TYPES_MCONTEXT_T_H + +#if defined(__x86_64__) +#include "x86_64/mcontext_t.h" +#else +#error "mcontext_t not available for your target architecture." +#endif + +#endif // LLVM_LIBC_TYPES_MCONTEXT_T_H diff --git a/libc/include/llvm-libc-types/ucontext_t.h b/libc/include/llvm-libc-types/ucontext_t.h new file mode 100644 index 0000000000000..1c5319bf807fa --- /dev/null +++ b/libc/include/llvm-libc-types/ucontext_t.h @@ -0,0 +1,18 @@ +//===-- Definition of type ucontext_t -------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TYPES_UCONTEXT_T_H +#define LLVM_LIBC_TYPES_UCONTEXT_T_H + +#if defined(__x86_64__) +#include "x86_64/ucontext_t.h" +#else +#error "ucontext_t not available for your target architecture." +#endif + +#endif // LLVM_LIBC_TYPES_UCONTEXT_T_H diff --git a/libc/include/llvm-libc-types/x86_64/mcontext_t.h b/libc/include/llvm-libc-types/x86_64/mcontext_t.h new file mode 100644 index 0000000000000..df9263f9411eb --- /dev/null +++ b/libc/include/llvm-libc-types/x86_64/mcontext_t.h @@ -0,0 +1,121 @@ +//===-- Definition of type mcontext_t -------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Note: Definitions in this file are based on the Linux kernel ABI. + +#ifndef LLVM_LIBC_TYPES_MCONTEXT_T_H +#define LLVM_LIBC_TYPES_MCONTEXT_T_H + +// The following definitions correspond to the general purpose registers. +// The layout of gregset_t and the enum indices must match the layout of +// 'struct sigcontext' in the Linux kernel on x86_64 (see +// arch/x86/include/uapi/asm/sigcontext.h). The kernel uses named fields +// (like r8, r9) while we use an array indexed by these enum values. +// +// Note: The kernel defines segment registers (cs, gs, fs, ss) as four +// separate 16-bit fields. In our flat 64-bit array representation, they +// are packed into a single 64-bit slot at index REG_CSGSFS, occupying +// the exact same 8 bytes of memory. +typedef long long int greg_t; +typedef greg_t gregset_t[23]; + +enum { + REG_R8 = 0, +#define REG_R8 REG_R8 + REG_R9, +#define REG_R9 REG_R9 + REG_R10, +#define REG_R10 REG_R10 + REG_R11, +#define REG_R11 REG_R11 + REG_R12, +#define REG_R12 REG_R12 + REG_R13, +#define REG_R13 REG_R13 + REG_R14, +#define REG_R14 REG_R14 + REG_R15, +#define REG_R15 REG_R15 + REG_RDI, +#define REG_RDI REG_RDI + REG_RSI, +#define REG_RSI REG_RSI + REG_RBP, +#define REG_RBP REG_RBP + REG_RBX, +#define REG_RBX REG_RBX + REG_RDX, +#define REG_RDX REG_RDX + REG_RAX, +#define REG_RAX REG_RAX + REG_RCX, +#define REG_RCX REG_RCX + REG_RSP, +#define REG_RSP REG_RSP + REG_RIP, +#define REG_RIP REG_RIP + REG_EFL, +#define REG_EFL REG_EFL + REG_CSGSFS, +#define REG_CSGSFS REG_CSGSFS + REG_ERR, +#define REG_ERR REG_ERR + REG_TRAPNO, +#define REG_TRAPNO REG_TRAPNO + REG_OLDMASK, +#define REG_OLDMASK REG_OLDMASK + REG_CR2 +#define REG_CR2 REG_CR2 +}; + +// The following structures (_libc_fpxreg, _libc_xmmreg, _libc_fpstate) +// represent the floating-point state and must match the layout used by the +// x86 FXSAVE instruction and the kernel's 'struct _fpstate' (see +// arch/x86/include/uapi/asm/sigcontext.h). +struct _libc_fpxreg { + unsigned short significand[4]; + unsigned short exponent; + unsigned short padding[3]; +}; + +struct _libc_xmmreg { + unsigned int element[4]; +}; + +// Note: The kernel's 'struct _fpstate' uses flat arrays like 'st_space[32]' +// and 'xmm_space[64]'. We use structured arrays '_st[8]' and '_xmm[16]' +// instead to allow focused access, but the memory layout and total sizes +// (128 bytes for _st and 256 bytes for _xmm) are identical to FXSAVE. +struct _libc_fpstate { + unsigned short cwd; + unsigned short swd; + unsigned short ftw; // Maps to 'twd' (Tag Word) in the kernel's _fpstate. + unsigned short fop; + unsigned long long rip; + unsigned long long rdp; + unsigned int mxcsr; + unsigned int mxcr_mask; + struct _libc_fpxreg _st[8]; + struct _libc_xmmreg _xmm[16]; + unsigned int padding[24]; +}; + +// fpregset_t is the type used to represent the floating-point register set. +// On x86_64, this is defined as a pointer to the state structure, matching +// the 'fpstate' pointer in the kernel's sigcontext. +typedef struct _libc_fpstate *fpregset_t; + +// mcontext_t represents the machine state. This structure must match the +// layout of 'struct sigcontext' in the Linux kernel on x86_64. +typedef struct { + gregset_t gregs; + fpregset_t fpregs; + unsigned long long __reserved1[8]; +} mcontext_t; + +#endif // LLVM_LIBC_TYPES_MCONTEXT_T_H diff --git a/libc/include/llvm-libc-types/x86_64/ucontext_t.h b/libc/include/llvm-libc-types/x86_64/ucontext_t.h new file mode 100644 index 0000000000000..607c2d1a6b2a0 --- /dev/null +++ b/libc/include/llvm-libc-types/x86_64/ucontext_t.h @@ -0,0 +1,43 @@ +//===-- Definition of type ucontext_t -------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Note: Definitions in this file are based on the Linux kernel ABI. + +#ifndef LLVM_LIBC_TYPES_UCONTEXT_T_H +#define LLVM_LIBC_TYPES_UCONTEXT_T_H + +#include "../sigset_t.h" +#include "../stack_t.h" +#include "mcontext_t.h" + +typedef struct alignas(16) ucontext_t { + // The following fields must match the Linux kernel's struct ucontext + // on x86_64 to ensure ABI compatibility for signal handling. + unsigned long uc_flags; + struct ucontext_t *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; + + // Additional fields appended by the C library. These are not part of the + // kernel's struct ucontext, but are needed for user-space context management. + // Since they are at the end, they do not break ABI compatibility with the + // kernel. + + // On x86_64, uc_mcontext contains a pointer to the floating point state + // rather than the state itself. To make ucontext_t self-contained, we + // provide space here for the FP state, and the pointer in uc_mcontext + // can be set to point here. 64 long ints provide 512 bytes, which is + // the size required for FXSAVE. + alignas(16) long int __fpregs_mem[64]; + + // Support for Shadow Stack Pointer (Intel CET). + unsigned long long __ssp[4]; +} ucontext_t; + +#endif // LLVM_LIBC_TYPES_UCONTEXT_T_H diff --git a/libc/include/ucontext.h.def b/libc/include/ucontext.h.def new file mode 100644 index 0000000000000..0750d99a4a0c5 --- /dev/null +++ b/libc/include/ucontext.h.def @@ -0,0 +1,16 @@ +//===-- POSIX header ucontext.h --------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_UCONTEXT_H +#define LLVM_LIBC_UCONTEXT_H + +#include "__llvm-libc-common.h" + +%%public_api() + +#endif // LLVM_LIBC_UCONTEXT_H diff --git a/libc/include/ucontext.yaml b/libc/include/ucontext.yaml new file mode 100644 index 0000000000000..05ae5e9d38602 --- /dev/null +++ b/libc/include/ucontext.yaml @@ -0,0 +1,37 @@ +header: ucontext.h +standards: + - posix +types: + - type_name: mcontext_t + - type_name: ucontext_t + - type_name: sigset_t + - type_name: stack_t +functions: + - name: getcontext + standards: + - posix + return_type: int + arguments: + - type: ucontext_t * + - name: setcontext + standards: + - posix + return_type: int + arguments: + - type: const ucontext_t * + - name: makecontext + standards: + - posix + return_type: void + arguments: + - type: ucontext_t * + - type: void(*)(void) + - type: int + - type: ... + - name: swapcontext + standards: + - posix + return_type: int + arguments: + - type: ucontext_t *__restrict + - type: const ucontext_t *__restrict