From 41973b761e368a0efd5e413fe2236b3cbf91d0d3 Mon Sep 17 00:00:00 2001 From: Sachin Parekh Date: Wed, 26 May 2021 18:48:57 +0530 Subject: [PATCH] newlib: Override __assert and __assert_func Default assert implementation calls fiprintf, which tries to acquire a lock and fails if it is executing in critical section or ISR --- .../esp32s2/ld/esp32s2.rom.newlib-funcs.ld | 4 +- components/newlib/CMakeLists.txt | 6 +- components/newlib/assert.c | 97 +++++++++++++++++++ components/newlib/component.mk | 4 +- components/newlib/newlib.lf | 1 + components/newlib/platform_include/assert.h | 12 ++- 6 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 components/newlib/assert.c diff --git a/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-funcs.ld b/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-funcs.ld index c859f655b4..fc976bbbaf 100644 --- a/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-funcs.ld +++ b/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-funcs.ld @@ -10,8 +10,8 @@ abs = 0x40000618; __ascii_mbtowc = 0x40007a04; __ascii_wctomb = 0x400018d0; -__assert = 0x4001a430; -__assert_func = 0x4001a408; +PROVIDE ( __assert = 0x4001a430 ); +PROVIDE ( __assert_func = 0x4001a408 ); bzero = 0x400078c8; _cleanup_r = 0x4001a480; creat = 0x4000788c; diff --git a/components/newlib/CMakeLists.txt b/components/newlib/CMakeLists.txt index 4fa4856879..5e837b6cd8 100644 --- a/components/newlib/CMakeLists.txt +++ b/components/newlib/CMakeLists.txt @@ -6,6 +6,7 @@ endif() set(srcs "abort.c" + "assert.c" "heap.c" "locks.c" "poll.c" @@ -28,7 +29,7 @@ list(APPEND ldfragments "newlib.lf" "system_libs.lf") idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" PRIV_INCLUDE_DIRS priv_include - PRIV_REQUIRES soc + PRIV_REQUIRES soc spi_flash LDFRAGMENTS "${ldfragments}") # Toolchain libraries require code defined in this component @@ -37,11 +38,12 @@ target_link_libraries(${COMPONENT_LIB} INTERFACE c m gcc "$ +#include +#include "esp_system.h" +#include "esp_spi_flash.h" +#include "soc/soc_memory_layout.h" + +#define ASSERT_STR "assert failed: " +#define CACHE_DISABLED_STR "" + +#if __XTENSA__ +#define INST_LEN 3 +#elif __riscv +#define INST_LEN 4 +#endif + +static inline void ra_to_str(char *addr) +{ + addr[0] = '0'; + addr[1] = 'x'; + itoa((uint32_t)(__builtin_return_address(0) - INST_LEN), addr + 2, 16); +} + +/* Overriding assert function so that whenever assert is called from critical section, + * it does not lead to a crash of its own. + */ +void __attribute__((noreturn)) __assert_func(const char *file, int line, const char *func, const char *expr) +{ +#if CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT + char buff[sizeof(ASSERT_STR) + 11 + 1] = ASSERT_STR; + + ra_to_str(&buff[sizeof(ASSERT_STR) - 1]); + + esp_system_abort(buff); +#else + char addr[11] = { 0 }; + char buff[200]; + char lbuf[5]; + uint32_t rem_len = sizeof(buff) - 1; + uint32_t off = 0; + + itoa(line, lbuf, 10); + + if (!spi_flash_cache_enabled()) { + if (esp_ptr_in_drom(file)) { + file = CACHE_DISABLED_STR; + } + + if (esp_ptr_in_drom(func)) { + ra_to_str(addr); + func = addr; + } + + if (esp_ptr_in_drom(expr)) { + expr = CACHE_DISABLED_STR; + } + } + + const char *str[] = {ASSERT_STR, func ? func : "\b", " ", file, ":", lbuf, " (", expr, ")"}; + + for (int i = 0; i < sizeof(str) / sizeof(str[0]); i++) { + uint32_t len = strlen(str[i]); + uint32_t cpy_len = MIN(len, rem_len); + memcpy(buff + off, str[i], cpy_len); + rem_len -= cpy_len; + off += cpy_len; + if (rem_len == 0) { + break; + } + } + buff[off] = '\0'; + esp_system_abort(buff); +#endif /* CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT */ +} + +void __attribute__((noreturn)) __assert(const char *file, int line, const char *failedexpr) +{ + __assert_func(file, line, NULL, failedexpr); +} + +/* No-op function, used to force linker to include these changes */ +void newlib_include_assert_impl(void) +{ +} diff --git a/components/newlib/component.mk b/components/newlib/component.mk index 3841d7b8e6..f633905a67 100644 --- a/components/newlib/component.mk +++ b/components/newlib/component.mk @@ -15,10 +15,12 @@ endif COMPONENT_PRIV_INCLUDEDIRS := priv_include COMPONENT_SRCDIRS := . port -# Forces the linker to include heap, syscalls, and pthread from this component, +# Forces the linker to include heap, syscalls, pthread, and assert from this component, # instead of the implementations provided by newlib. COMPONENT_ADD_LDFLAGS += -u newlib_include_heap_impl COMPONENT_ADD_LDFLAGS += -u newlib_include_syscalls_impl +COMPONENT_ADD_LDFLAGS += -u newlib_include_pthread_impl +COMPONENT_ADD_LDFLAGS += -u newlib_include_assert_impl COMPONENT_ADD_LDFRAGMENTS += newlib.lf system_libs.lf diff --git a/components/newlib/newlib.lf b/components/newlib/newlib.lf index 3d9a0ed14d..d92c04fb0f 100644 --- a/components/newlib/newlib.lf +++ b/components/newlib/newlib.lf @@ -3,4 +3,5 @@ archive: libnewlib.a entries: heap (noflash) abort (noflash) + assert (noflash) stdatomic (noflash) diff --git a/components/newlib/platform_include/assert.h b/components/newlib/platform_include/assert.h index 8522286148..39db39a6f0 100644 --- a/components/newlib/platform_include/assert.h +++ b/components/newlib/platform_include/assert.h @@ -19,6 +19,7 @@ #pragma once #include #include +#include #include_next @@ -31,16 +32,21 @@ */ #undef assert +/* __FILENAME__ points to the file name instead of path + filename + * e.g __FILE__ points to "/apps/test.c" where as __FILENAME__ points to "test.c" + */ +#define __FILENAME__ (__builtin_strrchr( "/" __FILE__, '/') + 1) + #if defined(NDEBUG) -# define assert(__e) ((void)(__e)) +#define assert(__e) ((void)(__e)) #elif CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT -#define assert(__e) __builtin_expect(!!(__e), 1) ? (void)0 : abort() +#define assert(__e) (__builtin_expect(!!(__e), 1) ? (void)0 : __assert_func(NULL, 0, NULL, NULL)) #else // !CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT -#define assert(__e) (__builtin_expect(!!(__e), 1) ? (void)0 : __assert_func (__FILE__, __LINE__, \ +#define assert(__e) (__builtin_expect(!!(__e), 1) ? (void)0 : __assert_func (__FILENAME__, __LINE__, \ __ASSERT_FUNC, #__e)) #endif