CHERIoT RTOS
A compartmentalised RTOS for CHERIoT hardware
Toggle main menu visibility
Loading...
Searching...
No Matches
sdk
include
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
*/
19
struct
CleanupList
20
{
21
/// Next pointer.
22
struct
CleanupList
*
next
;
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
;
68
switcher_handler_invocation_count_reset
();
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
*/
120
static
inline
void
on_error
(
auto
fn,
auto
err)
121
{
122
CHERIOT_DURING
123
fn();
124
CHERIOT_HANDLER
125
err();
126
CHERIOT_END_HANDLER
127
}
128
129
/**
130
* On-error helper with no error handler (returns normally from forced unwind).
131
*/
132
static
inline
void
on_error
(
auto
fn)
133
{
134
on_error
(fn, []() {});
135
}
136
#endif
CleanupList
On-stack linked list of cleanup handlers.
Definition
unwind.h:20
CleanupList::next
struct CleanupList * next
Next pointer.
Definition
unwind.h:22
CleanupList::env
struct __jmp_buf env
Jump buffer to return to.
Definition
unwind.h:24
__jmp_buf
This is a minimal implementation of setjmp/longjmp.
Definition
setjmp.h:20
switcher.h
APIs for interacting with the switcher.
switcher_handler_invocation_count_reset
__cheri_libcall uint16_t switcher_handler_invocation_count_reset(void)
Resets the switcher's count of invocations.
thread.h
Functions and types used for thread management.
invocation_state_slot
static void ** invocation_state_slot(size_t index)
Compute a pointer to a Compartment-Invocation-Local Storage slot.
Definition
thread.h:195
CHERIOT_DURING
#define CHERIOT_DURING
Simple error handling macros.
Definition
unwind.h:84
CHERIOT_HANDLER
#define CHERIOT_HANDLER
See CHERIOT_DURING.
Definition
unwind.h:97
on_error
static void on_error(auto fn, auto err)
On-error helper.
Definition
unwind.h:120
cleanup_unwind
static void cleanup_unwind(void)
Unwind the stack to the most recent CHERIOT_HANDLER block.
Definition
unwind.h:63
cleanup_list_head
static struct CleanupList ** cleanup_list_head()
Head of the cleanup list.
Definition
unwind.h:39
CHERIOT_END_HANDLER
#define CHERIOT_END_HANDLER
See CHERIOT_DURING.
Definition
unwind.h:108
Generated by
1.18.0