ucontext.h
1 /*
2  * Copyright (C) 2013 - 2016 Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de>
3  * Copyright (C) 2025 carl-tud
4  *
5  * This file is subject to the terms and conditions of the GNU Lesser
6  * General Public License v2.1. See the file LICENSE in the top level
7  * directory for more details.
8  */
9 
10 #ifndef UTIL_UCONTEXT_H
11 #define UTIL_UCONTEXT_H
12 
13 #if USE_LIBUCONTEXT
14 # include <libucontext/libucontext.h>
15 #else
16 # include <ucontext.h>
17 #endif /* USE_LIBUCONTEXT */
18 
19 #include <stdint.h>
20 #include <stdbool.h>
21 
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25 
31 /* MARK: - Context accessors */
42 static inline uintptr_t _context_get_fptr(ucontext_t *context) {
43 # if defined(__FreeBSD__) /* FreeBSD */
44  return (uintptr_t)((struct sigcontext *)context)->sc_eip;
45 # elif defined(__linux__) /* Linux */
46 # if defined(__arm__)
47  return (uintptr_t)((ucontext_t *)context)->uc_mcontext.arm_pc;
48 # elif defined(__x86_64__)
49  return (uintptr_t)((ucontext_t *)context)->uc_mcontext.gregs[REG_RIP];
50 # elif defined(__i386__)
51  return (uintptr_t)((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP];
52 # else
53 # error "Unsupported Linux architecture"
54 # endif
55 # else
56 # error "Operating system unsupported"
57 # endif
58 }
59 
65 static inline void _context_set_fptr(ucontext_t *context, uintptr_t func) {
66 # if defined(__FreeBSD__) /* FreeBSD */
67  ((struct sigcontext *)context)->sc_eip = (unsigned int)func;
68 # elif defined(__linux__) /* Linux */
69 # if defined(__arm__)
70  ((ucontext_t *)context)->uc_mcontext.arm_lr = func;
71  ((ucontext_t *)context)->uc_mcontext.arm_pc = func;
72 # elif defined(__x86_64__)
73  ((ucontext_t *)context)->uc_mcontext.gregs[REG_RIP] = (greg_t)func;
74 # elif defined(__i386__)
75  ((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP] = func;
76 # else
77 # error "Unsupported Linux architecture"
78 # endif
79 # else
80 # error "Operating system unsupported"
81 # endif
82 }
85 /* MARK: - 64-bit support for makecontext */
90 #if defined(__LP64__) || defined(DOXYGEN)
98 extern void _start_task_func64(void);
99 #endif
100 
110 static inline void makecontext64(ucontext_t *context, void (*func)(void), void* arg) {
111 # if defined(__LP64__)
112  /* makecontext accepts int arguments. In RIOT, we use void* for the optional argument.
113  * To not truncate the argument pointer, we pass it in a register to _start_task_func64. */
114  makecontext(context, (void (*)(void))_start_task_func64, 0);
115 
116 # if defined(__x86_64__)
117 # if defined(__linux__)
118  context->uc_mcontext.gregs[REG_R14] = (greg_t)func;
119  context->uc_mcontext.gregs[REG_R15] = (greg_t)arg;
120 # endif
121 # endif
122 
123 # else
124  /* On 32-bit platforms, the width of an int is enough to fit a pointer. */
125  makecontext(context, (void (*)(void))func, 1, arg);
126 # endif
127 }
132 #ifdef __cplusplus
133 }
134 #endif
135 
136 #endif /* UTIL_UCONTEXT_H */
void _start_task_func64(void)
Invokes thread task function.
static void _context_set_fptr(ucontext_t *context, uintptr_t func)
Retrieves function pointer generated during calls to makecontext/setcontext/swapcontext
Definition: ucontext.h:65
static uintptr_t _context_get_fptr(ucontext_t *context)
Retrieves function pointer generated during calls to makecontext/setcontext/swapcontext
Definition: ucontext.h:42
static void makecontext64(ucontext_t *context, void(*func)(void), void *arg)
Like makecontext, allows 64-bit wide function argument on 64-bit platforms.
Definition: ucontext.h:110