Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[architecture] Rework assertions to make them more useful #351

Merged
merged 4 commits into from
Mar 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
salkinium marked this conversation as resolved.
Show resolved Hide resolved
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