[libc-commits] [libc] [libc] Add ucontext types and headers (PR #191789)
Jeff Bailey via libc-commits
libc-commits at lists.llvm.org
Tue Apr 14 05:45:40 PDT 2026
https://github.com/kaladron updated https://github.com/llvm/llvm-project/pull/191789
>From a1307e736866dfa6cc9d927cb6da7af911bbe6f1 Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jbailey at raspberryginger.com>
Date: Mon, 13 Apr 2026 10:39:41 +0100
Subject: [PATCH 1/3] [libc] Add ucontext types and headers
Added mcontext_t and ucontext_t types for x86_64 Linux, and the ucontext.h header definition. Used a dispatcher pattern for mcontext_t and ucontext_t to support future architecture ports, mirroring the pattern used in FPUtil.
Definitions are based on the Linux kernel ABI for x86_64.
---
libc/include/CMakeLists.txt | 14 +++
libc/include/llvm-libc-types/CMakeLists.txt | 25 +++++
libc/include/llvm-libc-types/mcontext_t.h | 18 ++++
libc/include/llvm-libc-types/ucontext_t.h | 18 ++++
.../llvm-libc-types/x86_64/mcontext_t.h | 98 +++++++++++++++++++
.../llvm-libc-types/x86_64/ucontext_t.h | 43 ++++++++
libc/include/ucontext.h.def | 16 +++
libc/include/ucontext.yaml | 37 +++++++
8 files changed, 269 insertions(+)
create mode 100644 libc/include/llvm-libc-types/mcontext_t.h
create mode 100644 libc/include/llvm-libc-types/ucontext_t.h
create mode 100644 libc/include/llvm-libc-types/x86_64/mcontext_t.h
create mode 100644 libc/include/llvm-libc-types/x86_64/ucontext_t.h
create mode 100644 libc/include/ucontext.h.def
create mode 100644 libc/include/ucontext.yaml
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..9bca0a6d52fe4
--- /dev/null
+++ b/libc/include/llvm-libc-types/x86_64/mcontext_t.h
@@ -0,0 +1,98 @@
+//===-- 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 __LIBC_REG_CSGSFS, occupying
+// the exact same 8 bytes of memory.
+typedef long long int greg_t;
+typedef greg_t gregset_t[23];
+
+enum {
+ __LIBC_REG_R8 = 0,
+ __LIBC_REG_R9,
+ __LIBC_REG_R10,
+ __LIBC_REG_R11,
+ __LIBC_REG_R12,
+ __LIBC_REG_R13,
+ __LIBC_REG_R14,
+ __LIBC_REG_R15,
+ __LIBC_REG_RDI,
+ __LIBC_REG_RSI,
+ __LIBC_REG_RBP,
+ __LIBC_REG_RBX,
+ __LIBC_REG_RDX,
+ __LIBC_REG_RAX,
+ __LIBC_REG_RCX,
+ __LIBC_REG_RSP,
+ __LIBC_REG_RIP,
+ __LIBC_REG_EFL,
+ __LIBC_REG_CSGSFS,
+ __LIBC_REG_ERR,
+ __LIBC_REG_TRAPNO,
+ __LIBC_REG_OLDMASK,
+ __LIBC_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
>From 33cbf356c2720347a06e4c24730780a5e0666a7e Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jbailey at raspberryginger.com>
Date: Mon, 13 Apr 2026 18:04:10 +0100
Subject: [PATCH 2/3] [libc] Rename x86_64 register enum values for glibc
compatibility
Updated the register enum in include/llvm-libc-types/x86_64/mcontext_t.h to use names compatible with glibc's sys/ucontext.h (e.g., REG_R8).
Added corresponding #define directives for each register.
---
.../llvm-libc-types/x86_64/mcontext_t.h | 69 ++++++++++++-------
1 file changed, 46 insertions(+), 23 deletions(-)
diff --git a/libc/include/llvm-libc-types/x86_64/mcontext_t.h b/libc/include/llvm-libc-types/x86_64/mcontext_t.h
index 9bca0a6d52fe4..0759d268c32c4 100644
--- a/libc/include/llvm-libc-types/x86_64/mcontext_t.h
+++ b/libc/include/llvm-libc-types/x86_64/mcontext_t.h
@@ -25,29 +25,52 @@ typedef long long int greg_t;
typedef greg_t gregset_t[23];
enum {
- __LIBC_REG_R8 = 0,
- __LIBC_REG_R9,
- __LIBC_REG_R10,
- __LIBC_REG_R11,
- __LIBC_REG_R12,
- __LIBC_REG_R13,
- __LIBC_REG_R14,
- __LIBC_REG_R15,
- __LIBC_REG_RDI,
- __LIBC_REG_RSI,
- __LIBC_REG_RBP,
- __LIBC_REG_RBX,
- __LIBC_REG_RDX,
- __LIBC_REG_RAX,
- __LIBC_REG_RCX,
- __LIBC_REG_RSP,
- __LIBC_REG_RIP,
- __LIBC_REG_EFL,
- __LIBC_REG_CSGSFS,
- __LIBC_REG_ERR,
- __LIBC_REG_TRAPNO,
- __LIBC_REG_OLDMASK,
- __LIBC_REG_CR2
+ 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)
>From 7c396360980b2d2fa7efae402105cd7e06a25ef2 Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jbailey at raspberryginger.com>
Date: Tue, 14 Apr 2026 13:45:29 +0100
Subject: [PATCH 3/3] Update libc/include/llvm-libc-types/x86_64/mcontext_t.h
Fix comment missed in name changes.
Co-authored-by: Pavel Labath <pavel at labath.sk>
---
libc/include/llvm-libc-types/x86_64/mcontext_t.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/include/llvm-libc-types/x86_64/mcontext_t.h b/libc/include/llvm-libc-types/x86_64/mcontext_t.h
index 0759d268c32c4..df9263f9411eb 100644
--- a/libc/include/llvm-libc-types/x86_64/mcontext_t.h
+++ b/libc/include/llvm-libc-types/x86_64/mcontext_t.h
@@ -19,7 +19,7 @@
//
// 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 __LIBC_REG_CSGSFS, occupying
+// 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];
More information about the libc-commits
mailing list