CHERIoT RTOS
A compartmentalised RTOS for CHERIoT hardware
Loading...
Searching...
No Matches
unwind.h
Go to the documentation of this file.
1#pragma once
2#include <cdefs.h>
3#include <setjmp.h>
4#include <switcher.h>
5#include <thread.h>
6
7/**
8 * \file
9 *
10 * APIs for synchronously handling traps.
11 */
12
13/**
14 * On-stack linked list of cleanup handlers.
15 *
16 * This is managed by the `CHERIOT_HANDLER` macro and should not be used
17 * directly.
18 */
20{
21 /// Next pointer.
23 /// Jump buffer to return to.
24 struct __jmp_buf env;
25};
26
27#include <unwind-assembly.h>
28
29/**
30 * Head of the cleanup list.
31 *
32 * This is stored in the space that the switcher reserves at the top of the
33 * stack. The stack is zeroed on entry to a compartment and so this will be
34 * null until explicitly written to.
35 *
36 * This is managed by the `CHERIOT_HANDLER` macro and should not be used
37 * directly.
38 */
39__always_inline static inline struct CleanupList **cleanup_list_head()
40{
41 static const size_t InvocationLocalUnwindListOffset =
42 INVOCATION_LOCAL_UNWIND_LIST_OFFSET / sizeof(void *) - 1;
43 _Static_assert(InvocationLocalUnwindListOffset == 0,
44 "unwind.h should be using invocation state slot 0");
45
46 return (struct CleanupList **)invocation_state_slot(
47 InvocationLocalUnwindListOffset);
48}
49
50/**
51 * Unwind the stack to the most recent `CHERIOT_HANDLER` block.
52 *
53 * The equivalent of this code is run automatically if you add
54 * `unwind_error_handler` as a dependency for your compartment. If you
55 * implement a stackfull error handler then you can call this function to
56 * return to the last cleanup block. Such error handlers should call
57 * `switcher_handler_invocation_count_reset` if they do not wish the
58 * compartment to be forcibly unwound after an error limit is reached.
59 *
60 * This can also be called directly to unwind to the closest handler on the
61 * stack.
62 */
63__always_inline static inline void cleanup_unwind(void)
64{
65 struct CleanupList **__head = cleanup_list_head();
66 struct CleanupList *__top = *__head;
67 *__head = __top->next;
69 longjmp(&__top->env, 1);
70}
71
72/**
73 * Simple error handling macros. These are modelled on the OpenStep exception
74 * macros and are similarly built on top of `setjmp`. Code between
75 * `CHERIOT_DURING` and `CHERIOT_HANDLER` corresponds to a `try` block. Code
76 * between `CHERIOT_HANDLER` and `CHERIOT_END_HANDLER` corresponds to a `catch`
77 * block, though no exception value is actually thrown.
78 *
79 * Any automatic-storage values accessed in both blocks must be declared
80 * `volatile`.
81 *
82 * \hideinitializer
83 */
84#define CHERIOT_DURING \
85 { \
86 struct CleanupList cleanupListEntry; \
87 struct CleanupList **__head = cleanup_list_head(); \
88 cleanupListEntry.next = *__head; \
89 *__head = &cleanupListEntry; \
90 if (setjmp(&cleanupListEntry.env) == 0) \
91 {
92/**
93 * See `CHERIOT_DURING`.
94 *
95 * \hideinitializer
96 */
97#define CHERIOT_HANDLER \
98 *__head = cleanupListEntry.next; \
99 } \
100 else \
101 { \
102 *__head = cleanupListEntry.next;
103/**
104 * See `CHERIOT_DURING`.
105 *
106 * \hideinitializer
107 */
108#define CHERIOT_END_HANDLER \
109 } \
110 }
111
112#ifdef __cplusplus
113
114/**
115 * On-error helper. Invokes `fn` and, if `cleanup_unwind` is called, invokes
116 * `err`. Destructors in between `fn` and the frame that calls
117 * `cleanup_unwind` are not called, but this function returns normally and so
118 * destructors of objects above this on the stack will be called normally.
119 */
120static inline void on_error(auto fn, auto err)
121{
123 fn();
125 err();
127}
128
129/**
130 * On-error helper with no error handler (returns normally from forced unwind).
131 */
132static inline void on_error(auto fn)
133{
134 on_error(fn, []() {});
135}
136#endif
On-stack linked list of cleanup handlers.
Definition unwind.h:20
struct CleanupList * next
Next pointer.
Definition unwind.h:22
struct __jmp_buf env
Jump buffer to return to.
Definition unwind.h:24
This is a minimal implementation of setjmp/longjmp.
Definition setjmp.h:20
APIs for interacting with the switcher.
__cheri_libcall uint16_t switcher_handler_invocation_count_reset(void)
Resets the switcher's count of invocations.
Functions and types used for thread management.
static void ** invocation_state_slot(size_t index)
Compute a pointer to a Compartment-Invocation-Local Storage slot.
Definition thread.h:195
#define CHERIOT_DURING
Simple error handling macros.
Definition unwind.h:84
#define CHERIOT_HANDLER
See CHERIOT_DURING.
Definition unwind.h:97
static void on_error(auto fn, auto err)
On-error helper.
Definition unwind.h:120
static void cleanup_unwind(void)
Unwind the stack to the most recent CHERIOT_HANDLER block.
Definition unwind.h:63
static struct CleanupList ** cleanup_list_head()
Head of the cleanup list.
Definition unwind.h:39
#define CHERIOT_END_HANDLER
See CHERIOT_DURING.
Definition unwind.h:108