// 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
#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__ */
#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
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");
}
}
+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",
}
}
-
+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();
+}
--- /dev/null
+#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();
+}