esp_err: Use separate code path for ESP_ERROR_CHECK assertion

* Minimum code size overhead
* Makes function safe to use when flash cache is disabled

Builds on #339 https://github.com/espressif/esp-idf/pull/339
This commit is contained in:
Angus Gratton 2017-03-02 17:22:22 +11:00
parent 50f414f54c
commit 8ab96b13af
4 changed files with 53 additions and 14 deletions

View file

@ -11,10 +11,10 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#ifndef __ESP_ERR_H__ #pragma once
#define __ESP_ERR_H__
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <assert.h> #include <assert.h>
#ifdef __cplusplus #ifdef __cplusplus
@ -40,22 +40,38 @@ typedef int32_t esp_err_t;
#define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */ #define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */
void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression) __attribute__((noreturn));
#ifndef __ASSERT_FUNC
/* This won't happen on IDF, which defines __ASSERT_FUNC in assert.h, but it does happen when building on the host which
uses /usr/include/assert.h or equivalent.
*/
#ifdef __ASSERT_FUNCTION
#define __ASSERT_FUNC __ASSERT_FUNCTION /* used in glibc assert.h */
#else
#define __ASSERT_FUNC "??"
#endif
#endif
/** /**
* Macro which can be used to check the error code, * Macro which can be used to check the error code,
* and terminate the program in case the code is not ESP_OK. * and terminate the program in case the code is not ESP_OK.
* Prints the failed statement to serial output. * Prints the error code, error location, and the failed statement to serial output.
* *
* Note: this macro is not safe to use if flash cache * Disabled if assertions are disabled.
* may be disabled.
*/ */
#ifdef NDEBUG #ifdef NDEBUG
#define ESP_ERROR_CHECK(x) #define ESP_ERROR_CHECK(x) do { (x); } while (0)
#else #else
#define ESP_ERROR_CHECK(x) do { esp_err_t rc = (x); if (rc != ESP_OK) { ESP_LOGE("err", "esp_err_t = %d", rc); assert(0 && #x);} } while(0); #define ESP_ERROR_CHECK(x) do { \
esp_err_t rc = (x); \
if (rc != ESP_OK) { \
_esp_error_check_failed(rc, __FILE__, __LINE__, \
__ASSERT_FUNC, #x); \
} \
} while(0);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __ESP_ERR_H__ */

View file

@ -34,6 +34,7 @@
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_core_dump.h" #include "esp_core_dump.h"
#include "esp_spi_flash.h"
/* /*
Panic handlers; these get called when an unhandled exception occurs or the assembly-level Panic handlers; these get called when an unhandled exception occurs or the assembly-level
@ -107,11 +108,8 @@ void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, s
static bool abort_called; static bool abort_called;
void abort() static __attribute__((noreturn)) inline void invoke_abort()
{ {
#if !CONFIG_ESP32_PANIC_SILENT_REBOOT
ets_printf("abort() was called at PC 0x%08x\n", (intptr_t)__builtin_return_address(0) - 3);
#endif
abort_called = true; abort_called = true;
while(1) { while(1) {
__asm__ ("break 0,0"); __asm__ ("break 0,0");
@ -119,6 +117,14 @@ void abort()
} }
} }
void abort()
{
#if !CONFIG_ESP32_PANIC_SILENT_REBOOT
ets_printf("abort() was called at PC 0x%08x\n", (intptr_t)__builtin_return_address(0) - 3);
#endif
invoke_abort();
}
static const char *edesc[] = { static const char *edesc[] = {
"IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError", "IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError",
@ -441,4 +447,11 @@ void esp_clear_watchpoint(int no)
} }
} }
void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression)
{
ets_printf("ESP_ERROR_CHECK failed: esp_err_t 0x%x at 0x%08x\n", rc, (intptr_t)__builtin_return_address(0) - 3);
if (spi_flash_cache_enabled()) { // strings may be in flash cache
ets_printf("file: \"%s\" line %d\nfunc: %s\nexpression: %s\n", file, line, function, expression);
}
invoke_abort();
}

View file

@ -2,6 +2,7 @@ TEST_PROGRAM=test_nvs
all: $(TEST_PROGRAM) all: $(TEST_PROGRAM)
SOURCE_FILES = \ SOURCE_FILES = \
esp_error_check_stub.cpp \
$(addprefix ../src/, \ $(addprefix ../src/, \
nvs_types.cpp \ nvs_types.cpp \
nvs_api.cpp \ nvs_api.cpp \

View file

@ -0,0 +1,9 @@
#include "catch.hpp"
#include "esp_err.h"
void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression)
{
printf("ESP_ERROR_CHECK failed: esp_err_t 0x%x at %p\n", rc, __builtin_return_address(0));
printf("file: \"%s\" line %d\nfunc: %s\nexpression: %s\n", file, line, function, expression);
abort();
}