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

esp_system: fix address printed by ESP_ERROR_CHECK

...to point to the calling function, not to _esp_error_check_failed.
Ivan Grokhotkov 3 лет назад
Родитель
Сommit
ca7c9947fc
2 измененных файлов с 38 добавлено и 4 удалено
  1. 23 0
      components/esp_hw_support/include/esp_cpu.h
  2. 15 4
      components/esp_system/esp_err.c

+ 23 - 0
components/esp_hw_support/include/esp_cpu.h

@@ -511,6 +511,29 @@ FORCE_INLINE_ATTR void esp_cpu_dbgr_break(void)
 #endif
 }
 
+// ---------------------- Instructions -------------------------
+
+/**
+ * @brief Given the return address, calculate the address of the preceding call instruction
+ * This is typically used to answer the question "where was the function called from?"
+ * @param return_address  The value of the return address register.
+ *                        Typically set to the value of __builtin_return_address(0).
+ * @return Address of the call instruction preceding the return address.
+ */
+FORCE_INLINE_ATTR intptr_t esp_cpu_get_call_addr(intptr_t return_address)
+{
+    /* Both Xtensa and RISC-V have 2-byte instructions, so to get this right we
+     * should decode the preceding instruction as if it is 2-byte, check if it is a call,
+     * else treat it as 3 or 4 byte one. However for the cases where this function is
+     * used, being off by one instruction is usually okay, so this is kept simple for now.
+     */
+#ifdef __XTENSA__
+    return return_address - 3;
+#else
+    return return_address - 4;
+#endif
+}
+
 /* ------------------------------------------------------ Misc ---------------------------------------------------------
  *
  * ------------------------------------------------------------------------------------------------------------------ */

+ 15 - 4
components/esp_system/esp_err.c

@@ -13,13 +13,24 @@
 
 #include "esp_rom_sys.h"
 
-static void esp_error_check_failed_print(const char *msg, esp_err_t rc, const char *file, int line, const char *function, const char *expression)
+#ifndef CONFIG_IDF_TARGET_LINUX
+    #include "esp_cpu.h"
+#else
+    /* esp_cpu.h isn't available when building for Linux */
+    static intptr_t esp_cpu_get_call_addr(intptr_t return_address)
+    {
+        /* on x86, there is no hope to get the address of the previous instruction */
+        return return_address;
+    }
+#endif
+
+static void esp_error_check_failed_print(const char *msg, esp_err_t rc, const char *file, int line, const char *function, const char *expression, intptr_t addr)
 {
     esp_rom_printf("%s failed: esp_err_t 0x%x", msg, rc);
 #ifdef CONFIG_ESP_ERR_TO_NAME_LOOKUP
     esp_rom_printf(" (%s)", esp_err_to_name(rc));
 #endif //CONFIG_ESP_ERR_TO_NAME_LOOKUP
-    esp_rom_printf(" at 0x%08x\n", (intptr_t)__builtin_return_address(0) - 3);
+    esp_rom_printf(" at 0x%08x\n", esp_cpu_get_call_addr(addr));
     if (spi_flash_cache_enabled()) { // strings may be in flash cache
         esp_rom_printf("file: \"%s\" line %d\nfunc: %s\nexpression: %s\n", file, line, function, expression);
     }
@@ -27,11 +38,11 @@ static void esp_error_check_failed_print(const char *msg, esp_err_t rc, const ch
 
 void _esp_error_check_failed_without_abort(esp_err_t rc, const char *file, int line, const char *function, const char *expression)
 {
-    esp_error_check_failed_print("ESP_ERROR_CHECK_WITHOUT_ABORT", rc, file, line, function, expression);
+    esp_error_check_failed_print("ESP_ERROR_CHECK_WITHOUT_ABORT", rc, file, line, function, expression, (intptr_t)__builtin_return_address(0));
 }
 
 void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression)
 {
-    esp_error_check_failed_print("ESP_ERROR_CHECK", rc, file, line, function, expression);
+    esp_error_check_failed_print("ESP_ERROR_CHECK", rc, file, line, function, expression, (intptr_t)__builtin_return_address(0));
     abort();
 }