| #pragma once | |
| #include <__debug.h> | |
| #include <__macro_map.h> | |
| #ifndef __cplusplus | |
| /** | |
| * Helper macro to convert the type of an argument to the corresponding | |
| * `DebugFormatArgument` value. | |
| * | |
| * Should not be used directly. | |
| */ | |
| # define CHERIOT_DEBUG_MAP_ARGUMENT(x) \ | |
| { \ | |
| (uintptr_t)(x), _Generic((x), \ | |
| _Bool: DebugFormatArgumentBool, \ | |
| char: DebugFormatArgumentCharacter, \ | |
| short: DebugFormatArgumentSignedNumber32, \ | |
| unsigned short: DebugFormatArgumentUnsignedNumber32, \ | |
| int: DebugFormatArgumentSignedNumber32, \ | |
| unsigned int: DebugFormatArgumentUnsignedNumber32, \ | |
| signed long long: DebugFormatArgumentSignedNumber64, \ | |
| unsigned long long: DebugFormatArgumentUnsignedNumber64, \ | |
| char *: DebugFormatArgumentCString, \ | |
| default: DebugFormatArgumentPointer) \ | |
| } | |
| /** | |
| * Helper to map a list of arguments to an initialiser for a | |
| * `DebugFormatArgument` array. | |
| * | |
| * Should not be used directly. | |
| */ | |
| # define CHERIOT_DEBUG_MAP_ARGUMENTS(...) \ | |
| CHERIOT_MAP_LIST(CHERIOT_DEBUG_MAP_ARGUMENT, __VA_ARGS__) | |
| /** | |
| * Macro that logs a message. The `context` argument is a string that is | |
| * printed in magenta at the start of the line, followed by the format string. | |
| * Each format argument is referenced with {} in the format string and is | |
| * inserted in the output with the default rendering for that type. | |
| */ | |
| # define CHERIOT_DEBUG_LOG(context, msg, ...) \ | |
| do \ | |
| { \ | |
| struct DebugFormatArgument args[] = { \ | |
| __VA_OPT__(CHERIOT_DEBUG_MAP_ARGUMENTS(__VA_ARGS__))}; \ | |
| debug_log_message_write( \ | |
| context, \ | |
| msg, \ | |
| args, \ | |
| 0 __VA_OPT__(+(sizeof(args) / sizeof(args[0])))); \ | |
| } while (0) | |
| /** | |
| * Assert that `condition` is true, printing a message and aborting the | |
| * compartment invocation if not. | |
| */ | |
| # define CHERIOT_INVARIANT(condition, msg, ...) \ | |
| do \ | |
| { \ | |
| if (!(condition)) \ | |
| { \ | |
| struct DebugFormatArgument args[] = { \ | |
| __VA_OPT__(CHERIOT_DEBUG_MAP_ARGUMENTS(__VA_ARGS__))}; \ | |
| debug_report_failure( \ | |
| "Invariant", \ | |
| __FILE__, \ | |
| __func__, \ | |
| __LINE__, \ | |
| msg, \ | |
| args, \ | |
| 0 __VA_OPT__(+(sizeof(args) / sizeof(args[0])))); \ | |
| __builtin_trap(); \ | |
| } \ | |
| } while (0) | |
| #else | |
| # include <debug.hh> | |
| namespace | |
| { | |
| template<typename... Args> | |
| __always_inline void | |
| cheriot_debug_log(const char *context, const char *msg, Args... args) | |
| { | |
| DebugFormatArgument arguments[sizeof...(Args)]; | |
| make_debug_arguments_list(arguments, args...); | |
| debug_log_message_write(context, msg, arguments, sizeof...(Args)); | |
| } | |
| template<typename... Args> | |
| __always_inline void cheriot_invariant(bool condition, | |
| const char *file, | |
| const char *function, | |
| int line, | |
| const char *msg, | |
| Args... args) | |
| { | |
| if (!condition) | |
| { | |
| DebugFormatArgument arguments[sizeof...(Args)]; | |
| make_debug_arguments_list(arguments, args...); | |
| debug_report_failure("Invariant", | |
| file, | |
| function, | |
| line, | |
| msg, | |
| arguments, | |
| sizeof...(Args)); | |
| } | |
| } | |
| } // namespace | |
| /** | |
| * C++ version of `CHERIOT_DEBUG_LOG`. This uses the C++ helpers and so will | |
| * pretty-print a richer set of types than the C version. | |
| */ | |
| # define CHERIOT_DEBUG_LOG(context, msg, ...) \ | |
| do \ | |
| { \ | |
| cheriot_debug_log(context, msg __VA_OPT__(, ) __VA_ARGS__); \ | |
| } while (0) | |
| /** | |
| * C++ version of `CHERIOT_INVARIANT`. This uses the C++ helpers and so will | |
| * pretty-print a richer set of types than the C version. | |
| */ | |
| # define CHERIOT_INVARIANT(condition, msg, ...) \ | |
| do \ | |
| { \ | |
| cheriot_invariant(condition, \ | |
| __FILE__, \ | |
| __func__, \ | |
| __LINE__, \ | |
| msg __VA_OPT__(, ) __VA_ARGS__); \ | |
| } while (0) | |
| #endif |