Skip to content

Commit

Permalink
[assert] Rework assertion implementation
Browse files Browse the repository at this point in the history
This breaking change allows for better fine-tuning of assertions, add a lot of
documentation and better debug options.
  • Loading branch information
salkinium committed Mar 19, 2020
2 parents 2318f39 + c35d52c commit 23ec952
Show file tree
Hide file tree
Showing 79 changed files with 994 additions and 845 deletions.
62 changes: 27 additions & 35 deletions examples/avr/assert/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,23 @@

#include <modm/board.hpp>
#include <modm/architecture/interface/assert.hpp>
#include <avr/pgmspace.h>

using modm::accessor::asFlash;

// Flash support on avr-gcc is so horribly broken.
#define IFS(s) asFlash(PSTR(s))

#define MODM_CAN_MODULE_NAME "can"
#define MODM_IOBUFFER_MODULE_NAME "iobuffer"
#define MODM_UART_MODULE_NAME "uart"

extern "C" void
modm_abandon(const char * module,
const char * location,
const char * failure,
uintptr_t context)
modm_abandon(const modm::AssertionInfo &info)
{
serialStream << IFS("Assertion '")
<< asFlash(module) << '.'
<< asFlash(location) << '.'
<< asFlash(failure)
<< IFS("' @ ") << (void *) context
<< IFS(" failed! Abandoning.") << modm::endl;
serialStream << IFS("Assertion '") << asFlash(info.name) << '\'';
if (info.context != uintptr_t(-1))
serialStream << IFS(" @ ") << (void *)info.context << IFS(" (") << (uint32_t)info.context << IFS(")");
#if MODM_ASSERTION_INFO_HAS_DESCRIPTION
serialStream << IFS(" failed!\n ") << asFlash(info.description) << IFS("\nAbandoning...\n");
#else
serialStream << IFS(" failed!\nAbandoning...\n");
#endif

Leds::setOutput();
while (true) {
Expand All @@ -44,57 +38,55 @@ modm_abandon(const char * module,
}
}


static modm::Abandonment
test_assertion_handler(const char * module,
const char * /* location */,
const char * /* failure */,
uintptr_t /* context */)
test_assertion_handler(const modm::AssertionInfo &info)
{
serialStream << IFS("#1: '") << asFlash(module) << IFS("'!") << modm::endl;
serialStream << IFS("#1: '") << asFlash(info.name) << IFS("'!") << modm::endl;
// The strings are located in FLASH!!!
if (strcmp_P(module, PSTR(MODM_IOBUFFER_MODULE_NAME)) == 0)
if (strncmp_P("io.", info.name, 3) == 0) {
serialStream << IFS("Ignoring assertion!") << modm::endl;
return modm::Abandonment::Ignore;
}
return modm::Abandonment::DontCare;
}
MODM_ASSERTION_HANDLER(test_assertion_handler);

static modm::Abandonment
test_assertion_handler2(const char * /* module */,
const char * location,
const char * /* failure */,
uintptr_t /* context */)
test_assertion_handler2(const modm::AssertionInfo &info)
{
serialStream << IFS("#2: '") << asFlash(location) << IFS("'!") << modm::endl;
serialStream << IFS("#2: '") << asFlash(info.name) << IFS("'!") << modm::endl;
return modm::Abandonment::DontCare;
}
MODM_ASSERTION_HANDLER(test_assertion_handler2);

static modm::Abandonment
test_assertion_handler3(const char * /* module */,
const char * /* location */,
const char * failure,
uintptr_t /* context */)
test_assertion_handler3(const modm::AssertionInfo &info)
{
serialStream << IFS("#3: '") << asFlash(failure) << IFS("'!") << modm::endl;
serialStream << IFS("#3: '") << asFlash(info.name) << IFS("'!") << modm::endl;
return modm::Abandonment::DontCare;
}
MODM_ASSERTION_HANDLER(test_assertion_handler3);


// ----------------------------------------------------------------------------
int main()
{
Board::initialize();
Leds::setOutput();
serialStream << IFS("Starting test...\n");

modm_assert(true, MODM_CAN_MODULE_NAME, "init", "timeout");
// only fails for debug builds, but is ignored anyways
modm_assert_continue_fail(false, "io.tx",
"The IO transmit buffer is full!");

modm_assert_debug(false, MODM_IOBUFFER_MODULE_NAME, "tx", "full");
modm_assert_continue_fail_debug(false, "uart.init", "UART init failed!");

modm_assert(false, MODM_UART_MODULE_NAME, "init", "mode");
modm_assert(false, "can.init", "CAN init timed out!");

while (true)
{
Led3::toggle();
LedD13::toggle();
modm::delayMilliseconds(500);
}
}
2 changes: 1 addition & 1 deletion examples/avr/assert/project.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<library>
<extends>modm:al-avreb-can</extends>
<extends>modm:arduino-nano</extends>
<options>
<option name="modm:build:build.path">../../../build/avr/assert</option>
</options>
Expand Down
28 changes: 16 additions & 12 deletions examples/linux/assert/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,36 @@

#include <modm/platform.hpp>
#include <modm/architecture/interface/assert.hpp>

#define MODM_CAN_MODULE_NAME "can"
#define MODM_IOBUFFER_MODULE_NAME "iobuffer"
#define MODM_UART_MODULE_NAME "uart"
#include <modm/debug.hpp>

static modm::Abandonment
test_assertion_handler(const char * module,
const char * /* location */,
const char * /* failure */,
uintptr_t /* context */)
test_assertion_handler(const modm::AssertionInfo &info)
{
if (strcmp(module, MODM_IOBUFFER_MODULE_NAME) == 0)
if (strncmp(info.name, "io.", 3) == 0) {
MODM_LOG_WARNING << "Ignoring all 'io.*' assertions!" << modm::endl;
return modm::Abandonment::Ignore;
}
return modm::Abandonment::DontCare;
}
MODM_ASSERTION_HANDLER(test_assertion_handler);

static modm::Abandonment
log_assertion_handler(const modm::AssertionInfo &info)
{
MODM_LOG_DEBUG.printf("Assertion '%s' failed!\n", info.name);
return modm::Abandonment::DontCare;
}
MODM_ASSERTION_HANDLER_DEBUG(log_assertion_handler);

// ----------------------------------------------------------------------------
int
main()
{
modm_assert(true, MODM_CAN_MODULE_NAME, "init", "timeout");
modm_assert_continue_fail_debug(false, "io.tx", "IO transmit buffer is full!");

modm_assert_debug(false, MODM_IOBUFFER_MODULE_NAME, "tx", "full");
modm_assert_continue_fail_debug(false, "uart.init", "UART init failed!");

modm_assert(false, MODM_UART_MODULE_NAME, "init", "mode");
modm_assert(false, "can.init", "CAN init timed out!");

return 0;
}
1 change: 1 addition & 0 deletions examples/linux/assert/project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
</options>
<modules>
<module>modm:platform:core</module>
<module>modm:architecture:assert</module>
<module>modm:debug</module>
<module>modm:build:scons</module>
<module>modm:build:cmake</module>
Expand Down
40 changes: 21 additions & 19 deletions examples/stm32f469_discovery/assert/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,32 @@
// ----------------------------------------------------------------------------

#include <modm/board.hpp>
#include <modm/architecture/interface/assert.hpp>
#include <string>

using namespace std::string_literals;
using namespace Board;

static modm::Abandonment
test_assertion_handler(const char * module,
const char * /* location */,
const char * /* failure */,
uintptr_t /* context */)
test_assertion_handler(const modm::AssertionInfo &info)
{
if (not strcmp(module, "iobuffer")) {
MODM_LOG_ERROR << "Ignoring iobuffer full!" << modm::endl;
if (not strncmp(info.name, "io.", 3)) {
MODM_LOG_ERROR << "Ignoring all io.* assertions!" << modm::endl;
return modm::Abandonment::Ignore;
}
return modm::Abandonment::DontCare;
}
MODM_ASSERTION_HANDLER(test_assertion_handler);

static modm::Abandonment
core_assertion_handler(const char * module,
const char * /* location */,
const char * failure,
uintptr_t context)
core_assertion_handler(const modm::AssertionInfo &info)
{
if (not memcmp(module, "core\0nvic\0undefined", 19)) {
MODM_LOG_ERROR.printf("Ignoring undefined IRQ handler %d!\n", context);
if (info.name == "nvic.undef"s) {
MODM_LOG_ERROR.printf("Ignoring undefined IRQ handler %d!\n", info.context);
return modm::Abandonment::Ignore;
}
if (not memcmp(module, "core\0heap", 9)) {
MODM_LOG_ERROR.printf("Ignoring 'core.heap.%s' of size 0x%x!\n", failure, context);
if ((info.name == "new"s) or (info.name == "malloc"s)) {
MODM_LOG_ERROR.printf("Ignoring '%s' of size 0x%x!\n", info.name, info.context);
return modm::Abandonment::Ignore;
}
return modm::Abandonment::DontCare;
Expand All @@ -51,10 +48,12 @@ int
main()
{
Board::initialize();
MODM_LOG_INFO << "\n=== RESTART ===\n" << modm::flush;

// trigger an IRQ with undefined handler
NVIC_EnableIRQ(RTC_Alarm_IRQn);
NVIC_SetPendingIRQ(RTC_Alarm_IRQn);
NVIC_EnableIRQ(OTG_FS_WKUP_IRQn);
NVIC_SetPendingIRQ(OTG_FS_WKUP_IRQn);


// trigger an out of memory
// we definitely don't have 32MB RAM on this board
Expand All @@ -68,13 +67,16 @@ main()

// does not fail, should not be optimized away
volatile bool true_condition = true;
modm_assert(true_condition, "can", "init", "timeout");
modm_assert(true_condition, "can.init",
"Can::init() function has timed out!");

// only fails for debug builds, but is ignored anyways
modm_assert_debug(false, "iobuffer", "tx", "full");
modm_assert_continue_fail_debug(false, "io.tx",
"The IO transmit buffer is full!");

MODM_LOG_ERROR << modm::flush;
// "accidentally" return from main, without even returning properly!
// This should be caught by the debug assert core.main.exit!
// This should be caught by the debug assert main.exit!
// while (true)
// {};
// return 0;
Expand Down
2 changes: 1 addition & 1 deletion ext/aws/FreeRTOSConfig.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ modm_extern_c uint32_t _ZN4modm5clock4fcpuE;
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE

/* Define to trap errors during development. */
#define configASSERT( x ) { modm_assert((x), "freertos", __FILE__, MODM_STRINGIFY(__LINE__)); }
#define configASSERT( x ) { modm_assert((x), "freertos.assert", __FILE__, MODM_STRINGIFY(__LINE__)); }

/* FreeRTOS MPU specific definitions. */
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0
Expand Down
2 changes: 1 addition & 1 deletion ext/aws/modm_port.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ extern "C" void vApplicationStackOverflowHook(TaskHandle_t, const char *);

void vApplicationStackOverflowHook(TaskHandle_t /*pxTask*/, const char *pcTaskName)
{
modm_assert(false, "freertos", "stack", "overflow", pcTaskName);
modm_assert(false, "freertos.stack", "FreeRTOS detected a stack overflow!", pcTaskName);
}
2 changes: 1 addition & 1 deletion ext/gcc/assert.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
%% if options["assert_on_exception"]
#include <modm/architecture/interface/assert.hpp>

#define __modm_stdcpp_failure(failure) modm_assert(false, "stdc++", "stdc++", failure);__builtin_abort();
#define __modm_stdcpp_failure(failure) modm_assert(false, "c++." failure, "C++ Exception 'std::" failure "' was raised!");
%% else
#define __modm_stdcpp_failure(failure) __builtin_abort();
%% endif
Expand Down
4 changes: 2 additions & 2 deletions ext/gcc/cabi_cortex.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
extern void _exit(int);
void _exit(int status)
{
modm_assert(false, "libc", "libc", "exit", status);
__builtin_trap();
modm_assert(false, "libc.exit",
"The libc exit(status) function was called!", status);
}
8 changes: 4 additions & 4 deletions ext/gcc/cxxabi.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ extern "C"
{

void __cxa_pure_virtual()
{ modm_assert_debug(0, "cxa", "virtual", "pure"); __builtin_trap(); }
{ modm_assert(0, "virt.pure", "A pure virtual function was called!"); }
void __cxa_deleted_virtual()
{ modm_assert_debug(0, "cxa", "virtual", "deleted"); __builtin_trap(); }
{ modm_assert(0, "virt.del", "A deleted virtual function was called!"); }

void* __dso_handle = (void*) &__dso_handle;
%% if core.startswith("avr")
Expand Down Expand Up @@ -52,8 +52,8 @@ extern "C" int __cxa_guard_acquire(int *guard)
std::atomic_int *atomic_guard = reinterpret_cast<std::atomic_int *>(guard);
if (atomic_guard->exchange(INITIALIZING) == INITIALIZING)
{
modm_assert_debug(0, "cxa", "guard", "recursion", guard);
return 0;
modm_assert(0, "stat.rec",
"Recursive initialization of a function static!", guard);
}
return 1;
}
Expand Down
25 changes: 13 additions & 12 deletions ext/gcc/newdelete_avr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,37 @@
#include <modm/architecture/interface/assert.hpp>
#include <modm/platform/core/ram.hpp>

void *
operator new(size_t size)
static inline void *
modm_new(size_t size)
{
void * ptr = modm::platform::allocateMemory(size);
modm_assert(ptr, "core", "heap", "new", size);
modm_assert_continue_fail(ptr, "new",
"C++ new() operator failed to allocate!", size);
return ptr;
}

void *
operator new(size_t size)
{
return modm_new(size);
}

void *
operator new[](size_t size)
{
void * ptr = modm::platform::allocateMemory(size);
modm_assert(ptr, "core", "heap", "new", size);
return ptr;
return modm_new(size);
}

void *
operator new(size_t size, modm::MemoryTraits)
{
void * ptr = modm::platform::allocateMemory(size);
modm_assert(ptr, "core", "heap", "new", size);
return ptr;
return modm_new(size);
}

void *
operator new[](size_t size, modm::MemoryTraits)
{
void * ptr = modm::platform::allocateMemory(size);
modm_assert(ptr, "core", "heap", "new", size);
return ptr;
return modm_new(size);
}

void*
Expand Down
Loading

0 comments on commit 23ec952

Please sign in to comment.