diff --git a/Makefile.standard_app b/Makefile.standard_app index 461f3f08f..29cd89b8d 100644 --- a/Makefile.standard_app +++ b/Makefile.standard_app @@ -56,6 +56,13 @@ ifneq ($(DEBUG), 0) else DEFINES += PRINTF=mcu_usb_printf endif + ifneq ($(DISABLE_DEBUG_LEDGER_ASSERT), 1) + DEFINES += HAVE_LEDGER_ASSERT_DISPLAY + DEFINES += LEDGER_ASSERT_CONFIG_FILE_INFO + endif + ifneq ($(DISABLE_DEBUG_THROW), 1) + DEFINES += HAVE_DEBUG_THROWS + endif else DEFINES += PRINTF\(...\)= endif diff --git a/include/ledger_assert.h b/include/ledger_assert.h new file mode 100644 index 000000000..15387e5c4 --- /dev/null +++ b/include/ledger_assert.h @@ -0,0 +1,156 @@ +#pragma once + +#include + +#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() PRINTF("LEDGER_ASSERT FAILED\n") +#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); \ + } while (0) +#endif diff --git a/include/os.h b/include/os.h index 0a6ae4d9d..27633c383 100644 --- a/include/os.h +++ b/include/os.h @@ -131,6 +131,10 @@ int snprintf(char *str, size_t str_size, const char *format, ...); #endif // APPLE #endif // HAVE_SPRINTF +#ifndef HAVE_BOLOS +int compute_address_location(int address); +#endif + // syscall test // SYSCALL void dummy_1(unsigned int* p PLENGTH(2+len+15+ len + 16 + sizeof(io_send_t) + 1 ), // unsigned int len); diff --git a/lib_standard_app/debug.c b/lib_standard_app/debug.c deleted file mode 100644 index ea1a396cb..000000000 --- a/lib_standard_app/debug.c +++ /dev/null @@ -1,71 +0,0 @@ -/***************************************************************************** - * (c) 2020 Ledger SAS. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *****************************************************************************/ - -#include // uint*_t -#include // memset, explicit_bzero - -#include "os.h" -#include "io.h" - -#ifdef HAVE_NBGL -#include "nbgl_use_case.h" -#endif - -#ifdef HAVE_DEBUG_THROWS -static char errordata[20]; - -WEAK void app_throw_info(unsigned int exception, unsigned int lr_val) -{ - snprintf(errordata, sizeof(errordata), "n%d, LR=0x%08X", exception, lr_val); -} - -static void review_choice(bool confirm) -{ - UNUSED(confirm); - os_sched_exit(-1); -} - -#ifdef HAVE_BAGL -UX_STEP_CB(ux_error, - bnnn_paging, - review_choice(true), - { - .title = "App error", - .text = errordata, - }); -UX_FLOW(ux_error_flow, &ux_error); -#endif - -WEAK void __attribute__((noreturn)) debug_display_throw_error(int exception) -{ - UNUSED(exception); - -#ifdef HAVE_BAGL - ux_flow_init(0, ux_error_flow, NULL); -#endif - -#ifdef HAVE_NBGL - nbgl_useCaseChoice( - &C_round_warning_64px, "App error", errordata, "Exit app", "Exit app", review_choice); -#endif - - // Block until the user approve and the app is quit - while (1) { - io_seproxyhal_io_heartbeat(); - } -} - -#endif diff --git a/lib_standard_app/debug.h b/lib_standard_app/debug.h deleted file mode 100644 index 0987417fc..000000000 --- a/lib_standard_app/debug.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -WEAK void __attribute__((noreturn)) debug_display_throw_error(int exception); diff --git a/lib_standard_app/main.c b/lib_standard_app/main.c index 80cf336c7..e82647eac 100644 --- a/lib_standard_app/main.c +++ b/lib_standard_app/main.c @@ -19,7 +19,7 @@ #include "os.h" #include "io.h" -#include "debug.h" +#include "ledger_assert.h" #ifdef HAVE_SWAP #include "swap.h" @@ -72,8 +72,6 @@ static void standalone_app_main(void) } CATCH_OTHER(e) { - PRINTF("Exiting following exception: %d\n", e); - #ifdef HAVE_DEBUG_THROWS // Disable USB and BLE, the app have crashed and is going to be exited // This is necessary to avoid device freeze while displaying throw error @@ -90,7 +88,9 @@ static void standalone_app_main(void) BLE_power(0, NULL); #endif // Display crash info on screen for debug purpose - debug_display_throw_error(e); + assert_display_exit(); +#else + PRINTF("Exiting following exception: 0x%04X\n", e); #endif } FINALLY {} @@ -141,7 +141,7 @@ static void library_app_main(libargs_t *args) } CATCH_OTHER(e) { - PRINTF("Exiting following exception: %d\n", e); + PRINTF("Exiting following exception: 0x%04X\n", e); } FINALLY { diff --git a/src/ledger_assert.c b/src/ledger_assert.c new file mode 100644 index 000000000..baea1f46f --- /dev/null +++ b/src/ledger_assert.c @@ -0,0 +1,145 @@ +/******************************************************************************* + * (c) 2023 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ + +#include + +#include "ledger_assert.h" +#include "os.h" +#include "ux.h" +#include "os_io_seproxyhal.h" + +#ifdef HAVE_NBGL +#include "nbgl_use_case.h" +#endif + +#ifndef ASSERT_BUFFER_LEN +#define ASSERT_BUFFER_LEN 24 +#endif + +#if defined(HAVE_LEDGER_ASSERT_DISPLAY) || defined(HAVE_DEBUG_THROWS) +static char assert_buffer[ASSERT_BUFFER_LEN]; +#endif + +#if defined(HAVE_LEDGER_ASSERT_DISPLAY) && defined(LEDGER_ASSERT_CONFIG_LR_AND_PC_INFO) +void assert_display_lr_and_pc(int lr, int pc) +{ + char buff[LR_AND_PC_SIZE]; + + lr = compute_address_location(lr); + pc = compute_address_location(pc); + snprintf(buff, LR_AND_PC_SIZE, "LR=0x%08X\n PC=0x%08X\n", lr, pc); + strncat(assert_buffer, buff, LR_AND_PC_SIZE); +} +#endif + +#if defined(HAVE_LEDGER_ASSERT_DISPLAY) && defined(LEDGER_ASSERT_CONFIG_MESSAGE_INFO) +void assert_display_message(const char *message) +{ + char buff[MESSAGE_SIZE]; + + snprintf(buff, MESSAGE_SIZE, "%s\n", message); + strncat(assert_buffer, buff, MESSAGE_SIZE); +} +#endif + +#if defined(HAVE_LEDGER_ASSERT_DISPLAY) && defined(LEDGER_ASSERT_CONFIG_FILE_INFO) +void assert_display_file_info(const char *file, unsigned int line) +{ + char buff[FILE_SIZE]; + + snprintf(buff, FILE_SIZE, "%s::%d\n", file, line); + strncat(assert_buffer, buff, FILE_SIZE); +} +#endif + +#if defined(HAVE_PRINTF) && defined(LEDGER_ASSERT_CONFIG_LR_AND_PC_INFO) +void assert_print_lr_and_pc(int lr, int pc) +{ + lr = compute_address_location(lr); + pc = compute_address_location(pc); + PRINTF("LEDGER_ASSERT FAILED\n"); + PRINTF("=> LR: 0x%08X \n", lr); + PRINTF("=> PC: 0x%08X \n", pc); +} +#endif + +#if defined(HAVE_PRINTF) && defined(LEDGER_ASSERT_CONFIG_FILE_INFO) +void assert_print_file_info(const char *file, int line) +{ + PRINTF("%s::%d \n", file, line); +} +#endif + +#if defined(HAVE_PRINTF) && defined(LEDGER_ASSERT_CONFIG_MESSAGE_INFO) +void assert_print_message(const char *message) +{ + if (message) { + PRINTF("%s\n", message); + } +} +#endif + +#if defined(HAVE_DEBUG_THROWS) +void throw_display_lr(int e, int lr) +{ + lr = compute_address_location(lr); + snprintf(assert_buffer, ASSERT_BUFFER_LEN, "e=0x%04X\n LR=0x%08X\n", e, lr); +} +#endif + +#if defined(HAVE_PRINTF) && defined(HAVE_DEBUG_THROWS) +void throw_print_lr(int e, int lr) +{ + lr = compute_address_location(lr); + PRINTF("exception[0x%04X]: LR=0x%08X\n", e, lr); +} +#endif + +void assert_exit(bool confirm) +{ + UNUSED(confirm); + os_sched_exit(-1); +} + +#if defined(HAVE_LEDGER_ASSERT_DISPLAY) || defined(HAVE_DEBUG_THROWS) +#ifdef HAVE_BAGL +UX_STEP_CB(ux_error, + bnnn_paging, + assert_exit(true), + { + .title = "App error", + .text = assert_buffer, + }); +UX_FLOW(ux_error_flow, &ux_error); +#endif + +void __attribute__((noreturn)) assert_display_exit(void) +{ +#ifdef HAVE_BAGL + ux_flow_init(0, ux_error_flow, NULL); +#endif + +#ifdef HAVE_NBGL + nbgl_useCaseChoice( + &C_round_warning_64px, "App error", assert_buffer, "Exit app", "Exit app", assert_exit); +#endif + + // Block until the user approve and the app is quit + while (1) { + io_seproxyhal_io_heartbeat(); + } +} +#endif diff --git a/src/os.c b/src/os.c index 232b82375..a88e3001d 100644 --- a/src/os.c +++ b/src/os.c @@ -85,30 +85,28 @@ char os_secure_memcmp(const void *src1, const void *src2, size_t length) } #ifndef HAVE_BOLOS -#define MAIN_LINKER_SCRIPT_LOCATION 0xC0DE0000 +#include "ledger_assert.h" int main(void); -// This function can be used to declare a callback to THROW in the application -__attribute((weak)) void app_throw_info(unsigned int exception, unsigned int lr_val) +#define MAIN_LINKER_SCRIPT_LOCATION 0xC0DE0000 +int compute_address_location(int address) { - UNUSED(exception); - UNUSED(lr_val); + // Compute location before relocation (sort of anti PIC) + return address - (unsigned int) main + MAIN_LINKER_SCRIPT_LOCATION; } void os_longjmp(unsigned int exception) { - unsigned int lr_val; +#ifdef HAVE_DEBUG_THROWS + // Send to the app the info of exception and LR for debug purpose + DEBUG_THROW(exception); +#elif defined(HAVE_PRINTF) + int lr_val; __asm volatile("mov %0, lr" : "=r"(lr_val)); + lr_val = compute_address_location(lr_val); - // Compute location before relocation (sort of anti PIC) - lr_val = lr_val - (unsigned int) main + MAIN_LINKER_SCRIPT_LOCATION; - -#ifdef HAVE_PRINTF - PRINTF("exception[%d]: LR=0x%08X\n", exception, lr_val); -#endif // HAVE_PRINTF - - // Send to the app the info of exception and LR for debug purpose - app_throw_info(exception, lr_val); + PRINTF("exception[0x%04X]: LR=0x%08X\n", exception, lr_val); +#endif longjmp(try_context_get()->jmp_buf, exception); }