blob: 9e6a56ac8434748b93ed65abad75e16701db54f4 [file] [log] [blame]
#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