|  | #pragma once | 
|  | #include <cdefs.h> | 
|  | #include <setjmp.h> | 
|  | #include <switcher.h> | 
|  |  | 
|  | /** | 
|  | * On-stack linked list of cleanup handlers. | 
|  | */ | 
|  | struct CleanupList | 
|  | { | 
|  | /// Next pointer. | 
|  | struct CleanupList *next; | 
|  | /// Jump buffer to return to. | 
|  | struct __jmp_buf env; | 
|  | }; | 
|  |  | 
|  | #include <unwind-assembly.h> | 
|  |  | 
|  | /** | 
|  | * Head of the cleanup list. | 
|  | * | 
|  | * This is stored in the space that the switcher reserves at the top of the | 
|  | * stack.  The stack is zeroed on entry to a compartment and so this will be | 
|  | * null until explicitly written to. | 
|  | */ | 
|  | __always_inline static inline struct CleanupList **cleanup_list_head() | 
|  | { | 
|  | void     *csp = __builtin_cheri_stack_get(); | 
|  | ptraddr_t top = __builtin_cheri_top_get(csp); | 
|  | csp           = __builtin_cheri_address_set( | 
|  | csp, top - INVOCATION_LOCAL_UNWIND_LIST_OFFSET); | 
|  | return (struct CleanupList **)csp; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Unwind the stack to the most recent `CHERIOT_HANDLER` block. | 
|  | */ | 
|  | __always_inline static inline void cleanup_unwind(void) | 
|  | { | 
|  | struct CleanupList **__head = cleanup_list_head(); | 
|  | struct CleanupList  *__top  = *__head; | 
|  | *__head                     = __top->next; | 
|  | switcher_handler_invocation_count_reset(); | 
|  | longjmp(&__top->env, 1); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Simple error handling macros.  These are modelled on the OpenStep exception | 
|  | * macros and are similarly built on top of `setjmp`.  Code between | 
|  | * `CHERIOT_DURING` and `CHERIOT_HANDLER` corresponds to a `try` block.  Code | 
|  | * between `CHERIOT_HANDLER` and `CHERIOT_END_HANDLER` corresponds to a `catch` | 
|  | * block, though no exception value is actually thrown. | 
|  | * | 
|  | * Any automatic-storage values accessed in both blocks must be declared | 
|  | * `volatile`. | 
|  | */ | 
|  | #define CHERIOT_DURING                                                         \ | 
|  | {                                                                          \ | 
|  | struct CleanupList   cleanupListEntry;                                 \ | 
|  | struct CleanupList **__head = cleanup_list_head();                     \ | 
|  | cleanupListEntry.next       = *__head;                                 \ | 
|  | *__head                     = &cleanupListEntry;                       \ | 
|  | if (setjmp(&cleanupListEntry.env) == 0)                                \ | 
|  | { | 
|  | /// See CHERIOT_DURING. | 
|  | #define CHERIOT_HANDLER                                                        \ | 
|  | *__head = cleanupListEntry.next;                                           \ | 
|  | }                                                                          \ | 
|  | else                                                                       \ | 
|  | {                                                                          \ | 
|  | *__head = cleanupListEntry.next; | 
|  |  | 
|  | /// See CHERIOT_DURING. | 
|  | #define CHERIOT_END_HANDLER                                                    \ | 
|  | }                                                                          \ | 
|  | } | 
|  |  | 
|  | #ifdef __cplusplus | 
|  |  | 
|  | /** | 
|  | * On-error helper.  Invokes `fn` and, if `cleanup_unwind` is called, invokes | 
|  | * `err`.  Destructors in between `fn` and the frame that calls | 
|  | * `cleanup_unwind` are not called, but this function returns normally and so | 
|  | * destructors of objects above this on the stack will be called normally. | 
|  | */ | 
|  | static inline void on_error(auto fn, auto err) | 
|  | { | 
|  | CHERIOT_DURING | 
|  | fn(); | 
|  | CHERIOT_HANDLER | 
|  | err(); | 
|  | CHERIOT_END_HANDLER | 
|  | } | 
|  |  | 
|  | /** | 
|  | * On-error helper with no error handler (returns normally from forced unwind). | 
|  | */ | 
|  | static inline void on_error(auto fn) | 
|  | { | 
|  | on_error(fn, []() {}); | 
|  | } | 
|  | #endif |