Просмотр исходного кода

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
Angus Gratton 9 лет назад
Родитель
Сommit
d6f183fbb9

+ 25 - 9
components/esp32/include/esp_err.h

@@ -11,10 +11,10 @@
 // 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__ */

+ 18 - 5
components/esp32/panic.c

@@ -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();
+}

+ 1 - 0
components/nvs_flash/test_nvs_host/Makefile

@@ -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 \

+ 9 - 0
components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp

@@ -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();
+}