]> granicus.if.org Git - esp-idf/commitdiff
esp_err: Use separate code path for ESP_ERROR_CHECK assertion
authorAngus Gratton <angus@espressif.com>
Thu, 2 Mar 2017 06:22:22 +0000 (17:22 +1100)
committerAngus Gratton <angus@espressif.com>
Fri, 17 Mar 2017 10:14:17 +0000 (18:14 +0800)
* 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

components/esp32/include/esp_err.h
components/esp32/panic.c
components/nvs_flash/test_nvs_host/Makefile
components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp [new file with mode: 0644]

index fe8c004face18dc20e11cdce89b25bf55f40b778..c7beafd37563b08c7291ede1dd85d0bac1e0a9d7 100644 (file)
 // 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.
-#ifndef __ESP_ERR_H__
-#define __ESP_ERR_H__
+#pragma once
 
 #include <stdint.h>
+#include <stdio.h>
 #include <assert.h>
 
 #ifdef __cplusplus
@@ -40,22 +40,38 @@ typedef int32_t esp_err_t;
 
 #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,
  * 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
- * may be disabled.
+ * Disabled if assertions are disabled.
  */
 #ifdef NDEBUG
-#define ESP_ERROR_CHECK(x)
+#define ESP_ERROR_CHECK(x) do { (x); } while (0)
 #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
 
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* __ESP_ERR_H__ */
index 4f0497d6ea19ff0912be526283b2691ba00550f1..cd426344e1b75241f60e527fee7fb97c5db28d90 100644 (file)
@@ -34,6 +34,7 @@
 #include "esp_attr.h"
 #include "esp_err.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
@@ -107,11 +108,8 @@ void  __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, s
 
 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;
     while(1) {
         __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[] = {
     "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();
+}
index 6006213961b93e0a2a5f2714cd11a96da3067469..133762992d7ac685ac4d911061335a7869f99646 100644 (file)
@@ -2,6 +2,7 @@ TEST_PROGRAM=test_nvs
 all: $(TEST_PROGRAM)
 
 SOURCE_FILES = \
+       esp_error_check_stub.cpp \
        $(addprefix ../src/, \
                nvs_types.cpp \
                nvs_api.cpp \
diff --git a/components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp b/components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp
new file mode 100644 (file)
index 0000000..9cff4af
--- /dev/null
@@ -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();
+}