libunwind.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*
  2. * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #pragma once
  7. #include "sdkconfig.h"
  8. #include <stddef.h>
  9. #include <stdint.h>
  10. #if CONFIG_IDF_TARGET_ARCH_RISCV
  11. #include "libunwind-riscv.h"
  12. #elif CONFIG_IDF_TARGET_X86
  13. #include "libunwind-x86.h"
  14. #else
  15. /* This header must be a standalone one, so, it shall not trigger an error when
  16. * pre-processed without including any of the architecture header above.
  17. * The implementation can trigger a compile error if UNW_UNKNOWN_TARGET
  18. * macro is defined. */
  19. #define UNW_UNKNOWN_TARGET 1
  20. typedef void* ExecutionFrame;
  21. #endif
  22. #ifdef __cplusplus
  23. extern "C" {
  24. #endif
  25. /* Error codes returned by the functions defined below */
  26. #define UNW_ESUCCESS 0
  27. #define UNW_EUNSPEC 1 /* General failure */
  28. #define UNW_EBADREG 3 /* Register given is wrong */
  29. #define UNW_ESTOPUNWIND 5
  30. #define UNW_EINVAL 8 /* Bad parameter or unimplemented operation */
  31. #define UNW_EBADVERSION 9
  32. #define UNW_ENOINFO 10
  33. /* A libunwind context is the equivalent of an ESP-IDF ExecutionFrame */
  34. typedef ExecutionFrame unw_context_t;
  35. /* A register number is an unsigned word in our case */
  36. typedef uint32_t unw_regnum_t;
  37. /* In our current implementation, a cursor is the same as a context */
  38. typedef unw_context_t unw_cursor_t;
  39. /* long should represent the size of a CPU register */
  40. typedef unsigned long unw_word_t;
  41. /* At the moment, we don't support the operations using the following types,
  42. * so just set them to void* */
  43. typedef void* unw_addr_space_t;
  44. typedef void* unw_fpreg_t;
  45. /**
  46. * @brief Get the current CPU context.
  47. *
  48. * @param[out] ctx Pointer to `unw_context_t` structure. It must not be NULL
  49. * as it will be filled with the CPU registers value
  50. *
  51. * @return UNW_ESUCCESS on success, -UNW_EUNSPEC if ctx is NULL
  52. *
  53. * @note This function MUST be inlined. Marking it as "static inline" or
  54. * __attribute__((always_inline)) does not guarantee that it will inlined by
  55. * the compiler for all the architectures. Thus, define this function as a macro.
  56. * @note If the caller of this function returns, all the pointers, contexts, cursors
  57. * generated out of the initial returned context shall be considered invalid and
  58. * thus, must **not** be used.
  59. */
  60. #define unw_getcontext(ctx) ({ int retval; \
  61. if (ctx == NULL) { \
  62. retval = -UNW_EUNSPEC; \
  63. } else { \
  64. UNW_GET_CONTEXT(ctx); \
  65. retval = UNW_ESUCCESS; \
  66. } \
  67. retval; \
  68. })
  69. /**
  70. * @brief Initialize a cursor on a local context. Multiple cursor can be initialized on
  71. * a given CPU context, they can then be manipulated independently.
  72. *
  73. * @param[out] c Pointer on cursor to be returned. Must not be NULL
  74. * @param[in] ctx Pointer on the context returned by the function `unw_getcontext`
  75. *
  76. * @return UNW_ESUCCESS on success, -UNW_EUNSPEC if one of the parameter is NULL.
  77. */
  78. int unw_init_local(unw_cursor_t* c, unw_context_t* ctx);
  79. /**
  80. * @brief Perform a step "up" on the given cursor. After calling this function, the
  81. * cursor will point to the caller's CPU context. Thus, it is then possible
  82. * to retrieve the caller's address by getting the PC register out of the cursor.
  83. * Check `unw_get_reg` function for this.
  84. *
  85. * @param[in] cp Current cursor
  86. *
  87. * @returns 0 if the previous frame was the last one
  88. * @returns Positive value on success
  89. * @returns -UNW_EBADVERSION if the DWARF information's version is not compatible with the eh_frame_parser implementation
  90. * @returns -UNW_ENOINFO if the caller information are not present in the binary. (if the caller is in ROM for example)
  91. * @returns -UNW_ESTOPUNWIND if unwinding is terminated
  92. */
  93. int unw_step(unw_cursor_t* cp);
  94. /**
  95. * @brief Get the value of a CPU register from a given cursor.
  96. *
  97. * @param[in] cp Pointer to the cursor
  98. * @param reg Register number to retrieve the value of
  99. * @param[out] valp Pointer that will be filled with the register value
  100. *
  101. * @returns UNW_ESUCCESS on success
  102. * @returns -UNW_EUNSPEC if any pointer passed is NULL
  103. * @returns -UNW_EBADREG if the register number is invalid
  104. */
  105. int unw_get_reg(unw_cursor_t* cp, unw_regnum_t reg, unw_word_t* valp);
  106. /**
  107. * @brief Set the value of a CPU register in a given cursor.
  108. *
  109. * @param[in]cp Pointer to the cursor
  110. * @param reg Register number to set the value of
  111. * @param val New register value
  112. *
  113. * @returns UNW_ESUCCESS on success
  114. * @returns -UNW_EUNSPEC if the pointer passed is NULL
  115. * @returns -UNW_EBADREG if the register number is invalid
  116. */
  117. int unw_set_reg(unw_cursor_t* cp, unw_regnum_t reg, unw_word_t val);
  118. #ifdef __cplusplus
  119. }
  120. #endif