7#include <compartment.h>
9#include <platform-uart.hh>
37 concept IsBool = std::is_same_v<T, bool>;
52 std::is_pointer_v<T> && !std::is_same_v<T, const char *>;
60 std::convertible_to<T, ptraddr_t> && !
IsEnum<T>;
79 virtual void write(
const char *) = 0;
83 virtual void write(std::string_view) = 0;
87 virtual void write(uint32_t) = 0;
91 virtual void write(int32_t) = 0;
95 virtual void write(uint64_t) = 0;
99 virtual void write(int64_t) = 0;
123 requires(std::integral<T>)
125 if constexpr (
sizeof(T) <= 4)
127 write(
static_cast<uint32_t
>(x));
131 write(
static_cast<uint64_t
>(x));
139 requires(std::integral<T>)
141 if constexpr (
sizeof(T) <= 4)
144 static_cast<int32_t
>(
static_cast<std::make_unsigned_t<T>
>(x)));
149 static_cast<int64_t
>(
static_cast<std::make_unsigned_t<T>
>(x)));
162 writer.write(magic_enum::enum_name<T>(
static_cast<T
>(value)));
164 writer.write(
static_cast<uint32_t
>(value));
191 return {
static_cast<uintptr_t
>(value),
192 DebugFormatArgumentKind::DebugFormatArgumentBool};
204 return {
static_cast<uintptr_t
>(value),
205 DebugFormatArgumentKind::DebugFormatArgumentCharacter};
217 return {
static_cast<uintptr_t
>(value),
218 DebugFormatArgumentKind::DebugFormatArgumentUnsignedNumber32};
230 return {
static_cast<uintptr_t
>(value),
231 DebugFormatArgumentKind::DebugFormatArgumentUnsignedNumber32};
243 return {
static_cast<uintptr_t
>(value),
244 DebugFormatArgumentKind::DebugFormatArgumentUnsignedNumber32};
260 uintptr_t fudgedValue;
261 memcpy(&fudgedValue, &value,
sizeof(fudgedValue));
263 DebugFormatArgumentKind::DebugFormatArgumentUnsignedNumber64};
275 return {
static_cast<uintptr_t
>(value),
276 DebugFormatArgumentKind::DebugFormatArgumentSignedNumber32};
288 return {
static_cast<uintptr_t
>(value),
289 DebugFormatArgumentKind::DebugFormatArgumentSignedNumber32};
301 return {
static_cast<uintptr_t
>(value),
302 DebugFormatArgumentKind::DebugFormatArgumentSignedNumber32};
318 static_assert(
sizeof(uintptr_t) ==
sizeof(uint64_t));
319 uintptr_t fudgedValue;
320 memcpy(&fudgedValue, &value,
sizeof(fudgedValue));
322 DebugFormatArgumentKind::DebugFormatArgumentSignedNumber64};
331 uintptr_t fudgedValue = 0;
332 memcpy(&fudgedValue, &value,
sizeof(value));
333 return {fudgedValue, DebugFormatArgumentKind::DebugFormatArgumentFloat};
342 uintptr_t fudgedValue = 0;
343 memcpy(&fudgedValue, &value,
sizeof(value));
345 DebugFormatArgumentKind::DebugFormatArgumentDouble};
357 return {
reinterpret_cast<uintptr_t
>(value),
358 DebugFormatArgumentKind::DebugFormatArgumentCString};
372 construct(std::string_view &value)
374 return {
reinterpret_cast<uintptr_t
>(&value),
375 DebugFormatArgumentKind::DebugFormatArgumentStringView};
398template<DebugConcepts::IsEnum T>
403#ifdef CHERIOT_AVOID_CAPRELOCS
404 return {
static_cast<uintptr_t
>(value),
405 DebugFormatArgumentKind::DebugFormatArgumentUnsignedNumber32};
407 return {
static_cast<uintptr_t
>(value),
422 static_assert(
sizeof(v) ==
sizeof(value));
423 memcpy(&v, &value,
sizeof(v));
424 return {v,
reinterpret_cast<uintptr_t
>(&print)};
428 static void print(uintptr_t value,
DebugWriter &writer)
430 TimeoutArgument t(0ULL);
431 static_assert(
sizeof(t) ==
sizeof(value));
432 memcpy(&t, &value,
sizeof(t));
435 writer.
write(
"{ elapsed: ");
436 writer.
write(t.relativeTimeout->elapsed);
437 writer.
write(
", remaining: ");
438 writer.
write(t.relativeTimeout->remaining);
443 writer.
write(t.absoluteTimeout);
444 writer.
write(
" cycles");
458 return {
static_cast<uintptr_t
>(value.
as_raw()),
459 DebugFormatArgumentKind::DebugFormatArgumentPermissionSet};
471 return {0, DebugFormatArgumentKind::DebugFormatArgumentPointer};
478template<DebugConcepts::IsPo
interButNotCString T>
483 return {
reinterpret_cast<uintptr_t
>(
484 reinterpret_cast<const volatile void *
>(value)),
485 DebugFormatArgumentKind::DebugFormatArgumentPointer};
493template<
typename T,
bool Sealed>
499 return {
reinterpret_cast<uintptr_t
>(
500 static_cast<const volatile void *
>(value)),
501 DebugFormatArgumentKind::DebugFormatArgumentPointer};
509template<DebugConcepts::IsConvertibleToAddress T>
514 return {
static_cast<uintptr_t
>(value),
516 DebugFormatArgumentKind::DebugFormatArgumentUnsignedNumber32};
526 auto &&argumentTuple)
530 std::remove_cvref_t<decltype(std::get<I>(argumentTuple))>>{}
531 .construct(std::get<I>(argumentTuple));
542template<
typename... Args>
543__always_inline
inline void
546 if constexpr (
sizeof...(Args) > 0)
549 std::forward_as_tuple(args...));
563 size_t messageCount);
565__cheri_libcall
void debug_report_failure(
const char *kind,
567 const char *function,
571 size_t argumentCount);
588 std::copy_n(str, N,
value);
594 constexpr operator const char *()
const
617 const char *fileName,
618 const char *functionName)
619 : lineNumber(lineNumber),
620 columnNumber(columnNumber),
622 functionName(functionName)
631 int columnNumber = __builtin_COLUMN(),
632 const char *fileName = __builtin_FILE(),
633 const char *functionName = __builtin_FUNCTION()) noexcept
635 return {lineNumber, columnNumber, fileName, functionName};
639 [[nodiscard]] __always_inline
constexpr int line() const noexcept
644 [[nodiscard]] __always_inline
constexpr int column() const noexcept
649 [[nodiscard]] __always_inline
constexpr const char *
655 [[nodiscard]] __always_inline
constexpr const char *
667 const char *fileName;
669 const char *functionName;
743 return static_cast<int>(Level) <=>
static_cast<int>(Threshold);
795 template<DebugLevel Level = DebugLevel::Information>
796 static void log(
const char *fmt,
auto... args)
800 "None is valid only as a threshold, not as a reporting level");
801 if constexpr (Level >= Threshold)
803 asm volatile(
"" :::
"memory");
804 const char *context = Context;
807 if constexpr (
sizeof...(args) == 0)
816 context, fmt, arguments,
sizeof...(args));
818 asm volatile(
"" :::
"memory");
822 template<DebugLevel Level = DebugLevel::Information>
823 static __always_inline
void
824 log_if(
bool condition,
const char *fmt,
auto... args)
828 "None is valid only as a threshold, not as a reporting level");
829 if constexpr (Level >= Threshold)
840 static __always_inline
void
841 log_if(Condition condition,
const char *fmt,
auto... args)
845 "None is valid only as a threshold, not as a reporting level");
846 if constexpr (Level >= Threshold)
863 template<
typename... Args>
866 const char *function,
874 const char *context = Context;
875 debug_report_failure(
876 kind, file, function,
line, fmt, arguments,
sizeof...(Args));
889 template<
typename... Args>
901 if (__predict_false(!condition))
903 if constexpr (VerboseInvariants)
910 std::forward<Args>(args)...);
926 template<
typename... Args>
940 if constexpr (EnableAssertions)
942 if (__predict_false(!condition))
949 std::forward<Args>(args)...);
972 if constexpr (EnableAssertions)
974 if (__predict_false(!condition()))
981 std::forward<Args>(args)...);
992 template<
typename T,
typename... Ts>
1001 template<
typename T,
typename... Args>
1002 __always_inline
static void
1005 std::tuple<Args...> args = std::make_tuple(),
1009 [&](Args... iargs) {
1011 condition, fmt, std::forward<Args>(iargs)..., loc);
1020 template<
typename... Ts>
1027 template<
typename... Ts>
1036 template<
typename T,
typename... Args>
1037 __always_inline
static void
1040 std::tuple<Args...> args = std::make_tuple(),
1044 [&](Args... iargs) {
1046 condition, fmt, std::forward<Args>(iargs)..., loc);
1052 enum class StackCheckMode
1102 template<StackCheckMode Mode,
size_t Expected, DebugContext Fn>
1109 static inline size_t stackUsage = Expected;
1122 if constexpr (Mode != StackCheckMode::Disabled)
1127 size_t used = highest - lowest;
1129 bool tripped =
false;
1130 if constexpr ((Mode == StackCheckMode::LoggingMonotonic) ||
1131 (Mode == StackCheckMode::AssertingMonotonic))
1133 if (used > stackUsage)
1139 else if constexpr ((Mode == StackCheckMode::Logging) ||
1140 (Mode == StackCheckMode::Asserting))
1142 if (used > Expected)
1146 if (used > stackUsage)
1155 "Stack used: {} bytes (max {})", used, stackUsage);
1156 if constexpr ((Mode == StackCheckMode::Asserting) ||
1157 (Mode == StackCheckMode::AssertingMonotonic))
C++ helpers for operating on capabilities.
Helper class for accessing capability properties on pointers.
ptraddr_t top() const
Returns the address of the top of this capability.
Class encapsulating a set of permissions.
constexpr uint32_t as_raw() const
Returns the raw permission mask as an integer containing a bitfield of permissions.
Assert(auto, const char *, Ts &&...) -> Assert< Ts... >
Deduction guide, allows Assert to be used as if it were a function with a lambda argument.
static void invariant(T condition, const char *fmt, std::tuple< Args... > args=std::make_tuple(), SourceLocation loc=SourceLocation::current())
Overt wrapper function around Invariant.
static void report_failure(const char *kind, const char *file, const char *function, int line, const char *fmt, Args... args)
Helper to report failure.
Invariant(T, const char *, Ts &&...) -> Invariant< Ts... >
Deduction guide, allows Invariant to be used as if it were a function.
Assert(bool, const char *, Ts &&...) -> Assert< Ts... >
Deduction guide, allows Assert to be used as if it were a function.
static void assertion(T condition, const char *fmt, std::tuple< Args... > args=std::make_tuple(), SourceLocation loc=SourceLocation::current())
Overt wrapper function around Assert.
static void log(const char *fmt, auto... args)
Log a message.
~StackUsageCheck()
Destructor, runs at the end of the function to print the message.
StackUsageCheck()=default
Default constructor, does nothing.
Helper concept for matching booleans.
Helper concept for things that can be converted to addresses but are not enumerations.
Helper concept for matching enumerations.
Helper for identifying pointers that are (probably) not C strings.
Concept for something that can be lazily called to produce a bool.
void(*)(uintptr_t, DebugWriter &) DebugCallback
Callback for custom types in debug output.
__cheri_libcall void debug_log_message_write(const char *context, const char *format, DebugFormatArgument *messages, size_t messageCount)
Library function that writes a debug message.
void make_debug_arguments_list(DebugFormatArgument *arguments, Args &...args)
Convert args into a type-erased array of DebugFormatArguments in arguments.
void debug_enum_helper(uintptr_t value, DebugWriter &writer)
Helper function for writing enumerations.
void map_debug_argument(DebugFormatArgument *arguments, auto &&argumentTuple)
Recursive helper that maps from a tuple representing the arguments into a type-erased array.
Concepts used for matching types in the debug code.
consteval std::strong_ordering operator<=>(const DebugLevel Level, const DebugLevel Threshold)
Comparison operator to determine whether a provided debug level is above the threshold at which it sh...
@ Warning
This is probably wrong but the component issuing the warning can recover.
@ Critical
Something is completely broken.
@ None
No debugging information should be reported.
@ Error
This is definitely wrong and may cause problems but the rest of the system is not impacted.
@ Information
This is informative and may be helpful for debugging.
Abstract class for writing debug output.
virtual void write(int32_t)=0
Write a 32-bit signed integer.
virtual void write(float)=0
Write a single-precision floating-point value.
virtual void write(std::string_view)=0
Write a string view.
void write_decimal(T x)
Write an integer as decimal.
virtual void write(char)=0
Write a single character.
virtual void write(uint32_t)=0
Write a 32-bit unsigned integer.
virtual void write_hex_byte(uint8_t)=0
Write a single byte as hex with no leading 0x.
virtual void write(int64_t)=0
Write a 64-bit signed integer.
virtual void write(double)=0
Write a double-precision floating-point value.
virtual void write(uint64_t)=0
Write a 64-bit unsigned integer.
void write_hex(T x)
Write an integer as hex.
virtual void write(const char *)=0
Write a C string.
Function-like class for assertions that is expected to be used via the deduction guide as:
Assert(T condition, const char *fmt, Args... args, SourceLocation loc=SourceLocation::current())
Constructor, performs the assertion check.
Assert(T &&condition, const char *fmt, Args... args, SourceLocation loc=SourceLocation::current())
Constructor, performs an assertion check.
Function-like class for invariants that is expected to be used via the deduction guide as:
Invariant(bool condition, const char *fmt, Args... args, SourceLocation loc=SourceLocation::current())
Constructor, performs the invariant check.
char value[N]
The captured string.
constexpr DebugContext(const char(&str)[N])
Constructor, captures the string argument.
consteval DebugLevelTemplateArgument(DebugLevel level)
Construct from a DebugLevel, captures the argument.
consteval DebugLevelTemplateArgument(bool enabled)
Construct from a boolean, enables all debug reporting for true.
const DebugLevel Value
The DebugLevel that this encapsulates.
Our libc++ does not currently provide source_location, but our clang provides the necessary builtins ...
constexpr int column() const noexcept
Returns the column number for this source location.
constexpr const char * function_name() const noexcept
Returns the function name for this source location.
constexpr int line() const noexcept
Returns the line number for this source location.
constexpr const char * file_name() const noexcept
Returns the file name for this source location.
static constexpr SourceLocation current(int lineNumber=__builtin_LINE(), int columnNumber=__builtin_COLUMN(), const char *fileName=__builtin_FILE(), const char *functionName=__builtin_FUNCTION()) noexcept
Construct a source location for the caller.
constexpr SourceLocation(int lineNumber, int columnNumber, const char *fileName, const char *functionName)
Explicitly construct a source location.
APIs for interacting with the switcher.
__cheri_libcall ptraddr_t stack_lowest_used_address(void)
Returns the lowest address that has been stored to on the stack in this compartment invocation.
This file contains the types used for timeouts across scheduler APIs.