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

LEDGER_ASSERT improvments and CX_ASSERT addition #504

Merged
merged 5 commits into from
Jan 24, 2024
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
10 changes: 10 additions & 0 deletions include/cx_errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#pragma once

#include <stdint.h>
#include "ledger_assert.h"

/**
* Checks the error code of a function.
Expand All @@ -32,6 +33,15 @@
} \
} while (0)

/**
* Checks the error code of a function and assert in case of error.
*/
#define CX_ASSERT(call) \
do { \
cx_err_t _assert_err = call; \
LEDGER_ASSERT(!_assert_err, "err 0x%X <%s>", _assert_err, #call); \
} while (0)

/** Success. */
#define CX_OK 0x00000000

Expand Down
249 changes: 92 additions & 157 deletions include/ledger_assert.h
Original file line number Diff line number Diff line change
@@ -1,160 +1,95 @@
#pragma once

#include <stdbool.h>

#ifdef HAVE_PRINTF
void assert_print_failed(void);
#endif

#ifdef LEDGER_ASSERT_CONFIG_FILE_INFO
#define LEDGER_ASSERT_CONFIG_MESSAGE_INFO 1
#define LEDGER_ASSERT_CONFIG_LR_AND_PC_INFO 1
#endif

#ifdef LEDGER_ASSERT_CONFIG_MESSAGE_INFO
#define LEDGER_ASSERT_CONFIG_LR_AND_PC_INFO 1
#endif

#if defined(LEDGER_ASSERT_CONFIG_LR_AND_PC_INFO) && defined(HAVE_LEDGER_ASSERT_DISPLAY)
#define LR_AND_PC_SIZE 30
void assert_display_lr_and_pc(int lr, int pc);
#define ASSERT_DISPLAY_LR_AND_PC(lr, pc) assert_display_lr_and_pc(lr, pc)
#else
#define LR_AND_PC_SIZE 0
#define ASSERT_DISPLAY_LR_AND_PC(lr, pc) \
do { \
} while (0)
#endif

#if defined(LEDGER_ASSERT_CONFIG_MESSAGE_INFO) && defined(HAVE_LEDGER_ASSERT_DISPLAY)
#define MESSAGE_SIZE 20
void assert_display_message(const char *message);
#define ASSERT_DISPLAY_MESSAGE(message) assert_display_message(message)
#else
#define MESSAGE_SIZE 0
#define ASSERT_DISPLAY_MESSAGE(message) \
do { \
} while (0)
#endif

#if defined(LEDGER_ASSERT_CONFIG_FILE_INFO) && defined(HAVE_LEDGER_ASSERT_DISPLAY)
#define FILE_SIZE 50
void assert_display_file_info(const char *file, unsigned int line);
#define ASSERT_DISPLAY_FILE_INFO(file, line) assert_display_file_info(file, line)
#else
#define FILE_SIZE 0
#define ASSERT_DISPLAY_FILE_INFO(file, line) \
do { \
} while (0)
#endif

#ifdef HAVE_LEDGER_ASSERT_DISPLAY
#define ASSERT_BUFFER_LEN LR_AND_PC_SIZE + MESSAGE_SIZE + FILE_SIZE
void __attribute__((noreturn)) assert_display_exit(void);

#define LEDGER_ASSERT_EXIT() assert_display_exit()
#else
void assert_exit(bool confirm);
#define LEDGER_ASSERT_EXIT() assert_exit(true)
#endif

#if defined(LEDGER_ASSERT_CONFIG_LR_AND_PC_INFO) && defined(HAVE_PRINTF)
void assert_print_lr_and_pc(int lr, int pc);
#define ASSERT_PRINT_LR_AND_PC(lr, pc) assert_print_lr_and_pc(lr, pc)
#else
#define ASSERT_PRINT_LR_AND_PC(lr, pc) \
do { \
} while (0)
#endif

#if defined(LEDGER_ASSERT_CONFIG_MESSAGE_INFO) && defined(HAVE_PRINTF)
void assert_print_message(const char *message);
#define ASSERT_PRINT_MESSAGE(message) assert_print_message(message)
#else
#define ASSERT_PRINT_MESSAGE(message) \
do { \
} while (0)
#endif

#if defined(LEDGER_ASSERT_CONFIG_FILE_INFO) && defined(HAVE_PRINTF)
void assert_print_file_info(const char *file, int line);
#define ASSERT_PRINT_FILE_INFO(file, line) assert_print_file_info(file, line)
#else
#define ASSERT_PRINT_FILE_INFO(file, line) \
do { \
} while (0)
#endif

#ifdef LEDGER_ASSERT_CONFIG_LR_AND_PC_INFO
#define LEDGER_ASSERT_LR_AND_PC() \
do { \
int _lr_address = 0; \
int _pc_address = 0; \
\
__asm volatile("mov %0, lr" : "=r"(_lr_address)); \
__asm volatile("mov %0, pc" : "=r"(_pc_address)); \
ASSERT_PRINT_LR_AND_PC(_lr_address, _pc_address); \
ASSERT_DISPLAY_LR_AND_PC(_lr_address, _pc_address); \
} while (0)
#elif defined(HAVE_PRINTF)
#define LEDGER_ASSERT_LR_AND_PC() assert_print_failed()
#else
#define LEDGER_ASSERT_LR_AND_PC() \
do { \
} while (0)
#endif

#ifdef LEDGER_ASSERT_CONFIG_MESSAGE_INFO
#define LEDGER_ASSERT_MESSAGE(message) \
do { \
ASSERT_PRINT_MESSAGE(message); \
ASSERT_DISPLAY_MESSAGE(message); \
} while (0)
#else
#define LEDGER_ASSERT_MESSAGE(message) \
do { \
} while (0)
#endif

#ifdef LEDGER_ASSERT_CONFIG_FILE_INFO
#define LEDGER_ASSERT_FILE_INFO() \
do { \
ASSERT_PRINT_FILE_INFO(__FILE__, __LINE__); \
ASSERT_DISPLAY_FILE_INFO(__FILE__, __LINE__); \
} while (0)
#else
#define LEDGER_ASSERT_FILE_INFO() \
do { \
} while (0)
#endif

#define LEDGER_ASSERT(test, message) \
do { \
if (!(test)) { \
LEDGER_ASSERT_LR_AND_PC(); \
LEDGER_ASSERT_MESSAGE(message); \
LEDGER_ASSERT_FILE_INFO(); \
LEDGER_ASSERT_EXIT(); \
} \
} while (0)

#if defined(HAVE_DEBUG_THROWS) && defined(HAVE_PRINTF)
void throw_print_lr(int e, int lr);
#define THROW_PRINT_LR(e, lr_val) throw_print_lr(e, lr_val)
#else
#define THROW_PRINT_LR(e, lr_val) \
do { \
} while (0)
#endif

#if defined(HAVE_DEBUG_THROWS)
void __attribute__((noreturn)) assert_display_exit(void);
void throw_display_lr(int e, int lr);
#define DEBUG_THROW(e) \
do { \
unsigned int lr_val; \
__asm volatile("mov %0, lr" : "=r"(lr_val)); \
throw_display_lr(e, lr_val); \
THROW_PRINT_LR(e, lr_val); \
#include "ledger_assert_internals.h"

/*****************
* LEDGER_ASSERT *
****************/

/**
* LEDGER_ASSERT - exit the app if assertion is false.
*
* Description:
* This is a C macro that can be used similarly of the libc `assert` macro.
* Therefore, it can help programmers find bugs in their programs, or handle
* exceptional cases via a crash that will produce limited debugging output.
*
*
* Important note:
* Note that contrary to the libc `assert`, the `LEDGER_ASSERT` macro will
* still end the app execution even if build with DEBUG=0 or NDEBUG.
* However, there are configurations explained below that shall be used to
* reduce the code size impact of the `LEDGER_ASSERT` macro to the bare minimum.
*
*
* Examples of usage:
*
* 1/ Simple example always raising with simple message:
* - `LEDGER_ASSERT(false, "Always assert");`
*
* 2/ More complex examples:
* - `LEDGER_ASSERT(len <= sizeof(buf), "Len too long");`
* - `LEDGER_ASSERT(check_value(value) == 0, "check_value failed");`
*
* 3/ Examples showcasing advance message format:
* - `LEDGER_ASSERT(len <= sizeof(buf), "Len too long %d <= %d", len, sizeof(buf));`
* - `int err = check_value(value); LEDGER_ASSERT(err == 0, "check_value failed (%d)", err);`
*
*
* Configuration:
*
* I/ Type of info to expose in PRINTF and screen if enabled.
*
* There are 4 types of information that can be displayed:
*
* 1/ A simple info displaying "LEDGER_ASSERT FAILED"
* => This is always enabled
*
* 2/ An info containing the PC and LR of the instruction that failed.
* This can be used to locate the failing code and flow using the following
* command: `arm-none-eabi-addr2line --exe bin/app.elf -pf 0xC0DE586B`
* => This is enabled when `LEDGER_ASSERT_CONFIG_LR_AND_PC_INFO` is defined.
*
* 3/ An info displaying the `LEDGER_ASSERT` message passed as parameter.
* => This is enabled when `LEDGER_ASSERT_CONFIG_MESSAGE_INFO` is defined.
*
* 4/ An info displaying the file and line position of the failing
* `LEDGER_ASSERT`.
* => This is enabled when `LEDGER_ASSERT_CONFIG_FILE_INFO` is defined.
*
* By default, when an info level X is enabled, all info level below are enabled.
*
* When using `Makefile.standard_app` and building with `DEBUG=1` all info are
* enabled.
*
* Note that enabling these info increase the app code size and is only
* recommended to ease the debugging.
*
*
* II/ Display info on device screen.
*
* Control whether or not a specific screen displaying assert info is shown
* to the app user before exiting the app due to an assert failure.
*
* To enable it, add `DEFINES+=HAVE_LEDGER_ASSERT_DISPLAY` in your app Makefile.
*
* This is enabled by default when using `Makefile.standard_app` and building
* with `DEBUG=1`. It can still be disabled with using
* `DISABLE_DEBUG_LEDGER_ASSERT=1`.
*
* Note that this is increasing the app code size and exposes a non-user
* friendly screen in case of assert. therefore this should not be enabled in
* app release build but only kept for debug purposes.
*
*/
#define LEDGER_ASSERT(test, format, ...) \
do { \
if (!(test)) { \
LEDGER_ASSERT_LR_AND_PC_PREAMBLE(); \
PRINTF("LEDGER_ASSERT FAILED\n"); \
LEDGER_ASSERT_MESSAGE(format, ##__VA_ARGS__); \
LEDGER_ASSERT_FILE_INFO(); \
LEDGER_ASSERT_LR_AND_PC(); \
LEDGER_ASSERT_EXIT(); \
} \
} while (0)
#endif
Loading
Loading