main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /*
  2. * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #define _POSIX_C_SOURCE 200809L
  7. #define _DEFAULT_SOURCE
  8. #include <stdio.h>
  9. #include <signal.h>
  10. #include <string.h>
  11. #include <unistd.h>
  12. #include <stdlib.h>
  13. #include <stdbool.h>
  14. #include <assert.h>
  15. #include <ucontext.h>
  16. #include "esp_private/eh_frame_parser.h"
  17. #include "libunwind.h"
  18. /**
  19. * @brief Index of x86 registers in `greg_t` structure.
  20. */
  21. #define REG_EDI 4
  22. #define REG_ESI 5
  23. #define REG_EBP 6
  24. #define REG_ESP 7
  25. #define REG_EBX 8
  26. #define REG_EDX 9
  27. #define REG_ECX 10
  28. #define REG_EAX 11
  29. #define REG_EIP 14
  30. /**
  31. * @brief Number of functions in the funs structure described below.
  32. */
  33. #define FUNCTIONS_COUNT ((sizeof(funs)/sizeof(*funs)))
  34. /**
  35. * @brief Number which will determine the depth of the call stack.
  36. * Check `main()` for more information.
  37. */
  38. #define NUMBER_TO_TEST (4)
  39. /**
  40. * @brief Number of iteration for function `esp_eh_frame_generated_step`.
  41. */
  42. #define NUMBER_OF_ITERATION (2 * NUMBER_TO_TEST + 2 + 1)
  43. /**
  44. * @brief Macro for testing calls to libunwind when UNW_ESUCCESS must be returned.
  45. */
  46. #define UNW_CHECK(call) do { if ((err = (call)) != UNW_ESUCCESS) { \
  47. printf("\e[31m\e[1mLibunwind error code %d on line %d\e[0m\r\n", err, __LINE__); \
  48. exit(1); \
  49. } \
  50. } while(0)
  51. /**
  52. * @brief Macro for testing if the given condition is true. To be used with libunwind when
  53. * the result is not necessarily UNW_ESUCCESS.
  54. */
  55. #define UNW_CHECK_TRUE(cond) do { \
  56. if (!(cond)) { \
  57. printf("\e[31m\e[1mLibunwind error on line %d\e[0m\r\n", __LINE__); \
  58. exit(1); \
  59. } \
  60. } while(0)
  61. /**
  62. * @brief Macro for checking if a PC returned by libunwind is part of the given function
  63. */
  64. #define UNW_CHECK_PC(pc, funname) do { \
  65. if (!is_pc_in_function((pc), (funname))) { \
  66. printf("\e[31m\e[1mPC %04lx should have been of function %s\e[0m\r\n", (pc), (funname)); \
  67. exit(1); \
  68. } \
  69. } while (0)
  70. /**
  71. * @brief Define a simple linked list type and initialize one.
  72. */
  73. struct list_t {
  74. uint32_t value;
  75. struct list_t *next;
  76. };
  77. static struct list_t head = { 0 };
  78. /**
  79. * Few recursive functions to make the the call stack a bit more complex than a
  80. * single function call would give.
  81. */
  82. bool is_odd(uint32_t n);
  83. bool is_even(uint32_t n);
  84. void browse_list(struct list_t* l);
  85. int analyse_callstack();
  86. int inner_function1(void);
  87. int inner_function2(void);
  88. void test1(void);
  89. /**
  90. * @brief Structure defining a function of our program.
  91. * This will be used to translate the backtrace.
  92. */
  93. struct functions_info {
  94. const char* name;
  95. uintptr_t start;
  96. uintptr_t end; /* will be filled at runtime */
  97. };
  98. /**
  99. * @brief Structure storing the information about the
  100. * function that will be part of the backtrace.
  101. */
  102. struct functions_info funs[] = {
  103. {
  104. .name = "browse_list",
  105. .start = (uintptr_t) &browse_list,
  106. .end = 0
  107. },
  108. {
  109. .name = "is_odd",
  110. .start = (uintptr_t) &is_odd,
  111. .end = 0
  112. },
  113. {
  114. .name = "is_even",
  115. .start = (uintptr_t) &is_even,
  116. .end = 0
  117. },
  118. {
  119. .name = "analyse_callstack",
  120. .start = (uintptr_t) &analyse_callstack,
  121. .end = 0
  122. },
  123. {
  124. .name = "inner_function1",
  125. .start = (uintptr_t) &inner_function1,
  126. .end = 0
  127. },
  128. {
  129. .name = "inner_function2",
  130. .start = (uintptr_t) &inner_function2,
  131. .end = 0
  132. },
  133. {
  134. .name = "test1",
  135. .start = (uintptr_t) &test1,
  136. .end = 0
  137. },
  138. };
  139. /**
  140. * @brief Test whether the address passed as PC is part of the function which
  141. * name is `function_name`. The global array `funs` is used.
  142. *
  143. * @param pc Program counter to test. (address in the program)
  144. * @param function_name Function name to check the address of.
  145. *
  146. * @return true if PC is in the function called `function_name`, false else.
  147. */
  148. bool is_pc_in_function(const uint32_t pc, const char* function_name)
  149. {
  150. for (uint32_t i = 0; i < FUNCTIONS_COUNT; i++) {
  151. const struct functions_info current_fun = funs[i];
  152. if (strcmp(current_fun.name, function_name) == 0) {
  153. return current_fun.start <= pc && pc <= current_fun.end;
  154. }
  155. }
  156. /* Function not found. */
  157. return false;
  158. }
  159. /**
  160. * @brief Number of times `esp_eh_frame_generated_step` is called.
  161. */
  162. static uint32_t iteration = 1;
  163. /**
  164. * @brief Override the default function called when a backtrace step is
  165. * generated.
  166. */
  167. void esp_eh_frame_generated_step(uint32_t pc, uint32_t sp) {
  168. /* The first PCs in the backtrace are calls to `browse_list()` + 2.
  169. * This is due to the fact that the list contains all the numbers
  170. * between NUMBER_TO_TEST to 0 included. Moreover, another call
  171. * is made when we meet the NULL pointer. */
  172. if (iteration > 0 && iteration <= (NUMBER_TO_TEST + 2)) {
  173. assert(is_pc_in_function(pc, "browse_list"));
  174. } else {
  175. /**
  176. * The backtrace should be:
  177. * - in is_odd when iteration is even.
  178. * - in is_even when iteration is odd.
  179. *
  180. * The backtrace finishes when the iteration reaches the end of
  181. * browse_list (NUMBER_TO_TEST + 2 iterations), is_even
  182. * (NUMBER_TO_TEST/2 calls) and is_odd (NUMBER_TO_TEST/2 calls) calls.
  183. */
  184. if (iteration >= NUMBER_OF_ITERATION)
  185. return;
  186. else if (iteration % 2 == 0)
  187. assert(is_pc_in_function(pc, "is_odd"));
  188. else
  189. assert(is_pc_in_function(pc, "is_even"));
  190. }
  191. /* Number of times this function has been entered. */
  192. iteration++;
  193. }
  194. /**
  195. * @brief Handler called when SIGSEV signal is sent to the program.
  196. *
  197. * @param signal Signal received by the program. Shall be SIGSEGV.
  198. * @param info Structure containing info about the error itself. Ignored.
  199. * @param ucontext Context of the program when the error occurred. This
  200. * is used to retrieve the CPU registers value.
  201. */
  202. void signal_handler(int signal, siginfo_t *info, void *ucontext) {
  203. /* Setup the execution frame as expected by the eh_frame_parser.
  204. * Indeed, the registers index defined in ucontext.h are NOT the same
  205. * the registers index DWARF is expecting. */
  206. ucontext_t* context = (ucontext_t*) ucontext;
  207. greg_t *gregset = context->uc_mcontext.gregs;
  208. x86ExcFrame frame = {
  209. .eax = gregset[REG_EAX],
  210. .ecx = gregset[REG_ECX],
  211. .edx = gregset[REG_EDX],
  212. .ebx = gregset[REG_EBX],
  213. .esp = gregset[REG_ESP],
  214. .ebp = gregset[REG_EBP],
  215. .esi = gregset[REG_ESI],
  216. .edi = gregset[REG_EDI],
  217. .eip = gregset[REG_EIP]
  218. };
  219. /* The following function will use panic_print_str and panic_print_hex
  220. * function to output the data.
  221. * Instead of replacing stdout file descriptor with a pipe, we can simply
  222. * replace these functions to store the data instead of printing them.
  223. */
  224. esp_eh_frame_print_backtrace(&frame);
  225. /* No assert has been triggered, the backtrace succeeded if the number of
  226. * iterations of function `esp_eh_frame_generated_step` is correct. */
  227. if (iteration == NUMBER_OF_ITERATION) {
  228. printf("\e[32m\e[1mAll tests passed \e[0m\r\n");
  229. } else {
  230. printf("\e[31m\e[1mWrong length of backtrace (%d iteration, expected %d) \e[0m\r\n",
  231. iteration, NUMBER_OF_ITERATION);
  232. exit(1);
  233. }
  234. /* Everything went fine, exit normally. */
  235. exit(0);
  236. }
  237. /**
  238. * @brief Browse the list passed as an argument.
  239. * The following function will trigger a SIGSEV signal on purpose, in order to
  240. * generate the backtrace.
  241. *
  242. * @param l List to browse.
  243. */
  244. void browse_list(struct list_t* l) {
  245. browse_list(l->next);
  246. }
  247. /**
  248. * @brief Add a number to the global list `head`.
  249. *
  250. * @param n Number to add in the list.
  251. */
  252. void add_number_to_list(uint32_t n) {
  253. struct list_t* l = malloc(sizeof(struct list_t));
  254. l->value = n;
  255. l->next = head.next;
  256. head.next = l;
  257. }
  258. /**
  259. * @brief Test if the number passed is even.
  260. * This function will fail, on purpose.
  261. *
  262. * @param n Number to test.
  263. *
  264. * @return true if even, false else.
  265. */
  266. bool is_even(uint32_t n) {
  267. add_number_to_list(n);
  268. if (n == 0) {
  269. browse_list(head.next);
  270. return true;
  271. }
  272. return is_odd(n - 1);
  273. }
  274. /**
  275. * @brief Test if the number passed is odd.
  276. * This function will fail, on purpose.
  277. *
  278. * @param n Number to test.
  279. *
  280. * @return true if odd, false else.
  281. */
  282. bool is_odd(uint32_t n) {
  283. add_number_to_list(n);
  284. if (n == 0) {
  285. browse_list(head.next);
  286. return false;
  287. }
  288. return is_even(n - 1);
  289. }
  290. /**
  291. * @brief Initialize the global `funs` array.
  292. */
  293. static inline void initialize_functions_info(void)
  294. {
  295. for (uint32_t i = 0; i < FUNCTIONS_COUNT; i++) {
  296. /* Each of the functions defined in this structure finishes
  297. * with the following instructions:
  298. * leave (0xc9)
  299. * ret (0xc3)
  300. * or
  301. * pop ebp (0x5d)
  302. * ret (0xc3)
  303. * Thus, we will look for these instructions. */
  304. uint8_t* instructions = (uint8_t*) funs[i].start;
  305. while ((instructions[0] != 0xc9 || instructions[1] != 0xc3) &&
  306. (instructions[0] != 0x5d || instructions[1] != 0xc3) )
  307. instructions++;
  308. instructions += 1;
  309. funs[i].end = (uintptr_t) instructions;
  310. }
  311. }
  312. /**
  313. * Test the eh_frame_parser for backtracing
  314. */
  315. void test2(void) {
  316. /* Initialize the structure holding information about the signal to override. */
  317. struct sigaction sig = {
  318. .sa_mask = 0,
  319. .sa_flags = SA_SIGINFO,
  320. .sa_restorer = NULL,
  321. .sa_sigaction = signal_handler
  322. };
  323. /* Override default SIGSEV signal callback. */
  324. int res = sigaction(SIGSEGV, &sig, NULL);
  325. if (res) {
  326. perror("Could not override SIGSEV signal");
  327. exit(1);
  328. }
  329. /* Trigger the segmentation fault with a complex backtrace. */
  330. is_even(NUMBER_TO_TEST);
  331. }
  332. /**
  333. * Test the libunwind implementation in ESP-IDF
  334. * Let's create some nested function calls to make unwinding more interesting.
  335. * Important: the stack must still be alive when analyzing it, thus it must be done
  336. * within the nested functions.
  337. */
  338. int analyse_callstack() {
  339. unw_context_t ucp = { 0 };
  340. unw_cursor_t cur = { 0 };
  341. unw_word_t pc = 0;
  342. int err = UNW_ESUCCESS;
  343. UNW_CHECK(unw_getcontext(&ucp));
  344. UNW_CHECK(unw_init_local(&cur, &ucp));
  345. UNW_CHECK(unw_get_reg(&cur, UNW_X86_EIP, &pc));
  346. /* This PC must be inside analyse_callstack */
  347. UNW_CHECK_PC(pc, "analyse_callstack");
  348. /* unw_step returns a positive value on success */
  349. UNW_CHECK_TRUE(unw_step(&cur) > 0);
  350. UNW_CHECK(unw_get_reg(&cur, UNW_X86_EIP, &pc));
  351. UNW_CHECK_PC(pc, "inner_function2");
  352. UNW_CHECK_TRUE(unw_step(&cur) > 0);
  353. UNW_CHECK(unw_get_reg(&cur, UNW_X86_EIP, &pc));
  354. UNW_CHECK_PC(pc, "inner_function1");
  355. /* unw_step returns if the frame is last one */
  356. UNW_CHECK_TRUE(unw_step(&cur) >= 0);
  357. UNW_CHECK(unw_get_reg(&cur, UNW_X86_EIP, &pc));
  358. UNW_CHECK_PC(pc, "test1");
  359. return UNW_ESUCCESS;
  360. }
  361. int __attribute__((noinline)) inner_function2(void) {
  362. return analyse_callstack();
  363. }
  364. int __attribute__((noinline)) inner_function1(void) {
  365. return inner_function2();
  366. }
  367. void __attribute__((noinline)) test1() {
  368. (void) inner_function1();
  369. }
  370. /**
  371. * Call the previous tests within the main. If the first test fails, it will exit by itself.
  372. */
  373. int main(int argc, char** argv)
  374. {
  375. initialize_functions_info();
  376. test1();
  377. test2();
  378. return 0;
  379. }