1#ifndef COROUTINE_AMD64_CONTEXT_H
2#define COROUTINE_AMD64_CONTEXT_H 1
18#define COROUTINE __attribute__((noreturn)) void
20enum {COROUTINE_REGISTERS = 6};
22#if defined(__SANITIZE_ADDRESS__)
23 #define COROUTINE_SANITIZE_ADDRESS
24#elif defined(__has_feature)
25 #if __has_feature(address_sanitizer)
26 #define COROUTINE_SANITIZE_ADDRESS
30#if defined(COROUTINE_SANITIZE_ADDRESS)
31#include <sanitizer/common_interface_defs.h>
32#include <sanitizer/asan_interface.h>
35#if defined(__SANITIZE_THREAD__)
36 #define COROUTINE_SANITIZE_THREAD
37#elif defined(__has_feature)
38 #if __has_feature(thread_sanitizer)
39 #define COROUTINE_SANITIZE_THREAD
43#if defined(COROUTINE_SANITIZE_THREAD)
48#include <sanitizer/tsan_interface.h>
51#if defined(__linux__) && defined(__CET__) && (__CET__ & 0x02) != 0
52#define COROUTINE_SHADOW_STACK
56#include <sys/syscall.h>
59#ifndef ARCH_SHSTK_STATUS
60#define ARCH_SHSTK_STATUS 0x5005
63#ifndef ARCH_SHSTK_SHSTK
64#define ARCH_SHSTK_SHSTK (1UL << 0)
67#ifndef SYS_map_shadow_stack
68#ifdef __NR_map_shadow_stack
69#define SYS_map_shadow_stack __NR_map_shadow_stack
71#define SYS_map_shadow_stack 453
75#ifndef SHADOW_STACK_SET_TOKEN
76#define SHADOW_STACK_SET_TOKEN (1UL << 0)
79void *coroutine_initialize_shadow_stack(
void *shadow_stack_pointer);
80COROUTINE coroutine_start_trampoline(
void);
82static inline int coroutine_shadow_stack_enabled(
void)
84 unsigned long features = 0;
86 if (syscall(SYS_arch_prctl, ARCH_SHSTK_STATUS, &features) != 0) {
90 return (features & ARCH_SHSTK_SHSTK) != 0;
93static inline void *coroutine_allocate_shadow_stack(
size_t size)
95 void *base = (
void *)syscall(
99 SHADOW_STACK_SET_TOKEN
102 if (base == MAP_FAILED) {
112 void **stack_pointer;
115#if defined(COROUTINE_SANITIZE_ADDRESS)
121#if defined(COROUTINE_SANITIZE_THREAD)
126 int tsan_fiber_owned;
129#if defined(COROUTINE_SHADOW_STACK)
131 size_t shadow_stack_size;
137static inline void coroutine_initialize_main(
struct coroutine_context * context) {
138 context->stack_pointer = NULL;
140#if defined(COROUTINE_SANITIZE_THREAD)
142 context->tsan_fiber = __tsan_get_current_fiber();
143 context->tsan_fiber_owned = 0;
146#if defined(COROUTINE_SHADOW_STACK)
147 context->shadow_stack = NULL;
148 context->shadow_stack_size = 0;
152static inline void coroutine_initialize(
154 coroutine_start start,
158 assert(start && stack && size >= 1024);
160#if defined(COROUTINE_SHADOW_STACK)
161 void *shadow_stack_pointer = NULL;
162 void *entry = (
void *)(uintptr_t)start;
165#if defined(COROUTINE_SANITIZE_ADDRESS)
166 context->fake_stack = NULL;
167 context->stack_base = stack;
168 context->stack_size = size;
171#if defined(COROUTINE_SANITIZE_THREAD)
172 context->tsan_fiber = __tsan_create_fiber(0);
173 context->tsan_fiber_owned = 1;
176#if defined(COROUTINE_SHADOW_STACK)
177 if (coroutine_shadow_stack_enabled()) {
178 size_t shadow_stack_size = (size + 7) & ~(
size_t)7;
180 context->shadow_stack = coroutine_allocate_shadow_stack(shadow_stack_size);
181 context->shadow_stack_size = shadow_stack_size;
182 shadow_stack_pointer = coroutine_initialize_shadow_stack(
183 (
char *)context->shadow_stack + shadow_stack_size
185 entry = (
void *)(uintptr_t)coroutine_start_trampoline;
187 context->shadow_stack = NULL;
188 context->shadow_stack_size = 0;
193 char * top = (
char*)stack + size;
194 context->stack_pointer = (
void**)((uintptr_t)top & ~0xF);
196 *--context->stack_pointer = NULL;
197#if defined(COROUTINE_SHADOW_STACK)
198 *--context->stack_pointer = entry;
200 *--context->stack_pointer = (
void*)(uintptr_t)start;
203 context->stack_pointer -= COROUTINE_REGISTERS;
204 memset(context->stack_pointer, 0,
sizeof(
void*) * COROUTINE_REGISTERS);
206#if defined(COROUTINE_SHADOW_STACK)
207 if (shadow_stack_pointer) {
209 context->stack_pointer[3] = (
void *)(uintptr_t)start;
212 *--context->stack_pointer = shadow_stack_pointer;
220 context->stack_pointer = NULL;
222#if defined(COROUTINE_SANITIZE_THREAD)
226 if (context->tsan_fiber && context->tsan_fiber_owned) {
227 __tsan_destroy_fiber(context->tsan_fiber);
228 context->tsan_fiber = NULL;
229 context->tsan_fiber_owned = 0;
233#if defined(COROUTINE_SHADOW_STACK)
234 if (context->shadow_stack) {
235 munmap(context->shadow_stack, context->shadow_stack_size);
236 context->shadow_stack = NULL;