[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