main.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. // Copyright 2020 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @file DWARF Exception Frames parser header
  16. *
  17. * This file describes the frame types for x86, required for
  18. * parsing `eh_frame` and `eh_frame_hdr`.
  19. */
  20. #define _POSIX_C_SOURCE 200809L
  21. #define _DEFAULT_SOURCE
  22. #include <stdio.h>
  23. #include <signal.h>
  24. #include <string.h>
  25. #include <unistd.h>
  26. #include <stdlib.h>
  27. #include <stdbool.h>
  28. #include <assert.h>
  29. #include <ucontext.h>
  30. #include "../include/eh_frame_parser.h"
  31. #include "eh_frame_parser_impl.h"
  32. /**
  33. * @brief Index of x86 registers in `greg_t` structure.
  34. */
  35. #define REG_EDI 4
  36. #define REG_ESI 5
  37. #define REG_EBP 6
  38. #define REG_ESP 7
  39. #define REG_EBX 8
  40. #define REG_EDX 9
  41. #define REG_ECX 10
  42. #define REG_EAX 11
  43. #define REG_EIP 14
  44. /**
  45. * @brief Number of functions in the funs structure described below.
  46. */
  47. #define FUNCTIONS_COUNT ((sizeof(funs)/sizeof(*funs)))
  48. /**
  49. * @brief Number which will determine the depth of the call stack.
  50. * Check `main()` for more information.
  51. */
  52. #define NUMBER_TO_TEST (4)
  53. /**
  54. * @brief Number of iteration for function `esp_eh_frame_generated_step`.
  55. */
  56. #define NUMBER_OF_ITERATION (2 * NUMBER_TO_TEST + 2 + 1)
  57. /**
  58. * @brief Define a simple linked list type and initialize one.
  59. */
  60. struct list_t {
  61. uint32_t value;
  62. struct list_t *next;
  63. };
  64. static struct list_t head = { 0 };
  65. /**
  66. * Few recursive functions to make the the call stack a bit more complex than a
  67. * single function call would give.
  68. */
  69. bool is_odd(uint32_t n);
  70. bool is_even(uint32_t n);
  71. void browse_list(struct list_t* l);
  72. /**
  73. * @brief Structure defining a function of our program.
  74. * This will be used to translate the backtrace.
  75. */
  76. struct functions_info {
  77. const char* name;
  78. uintptr_t start;
  79. uintptr_t end; /* will be filled at runtime */
  80. };
  81. /**
  82. * @brief Structure storing the information about the
  83. * function that will be part of the backtrace.
  84. */
  85. struct functions_info funs[] = {
  86. {
  87. .name = "browse_list",
  88. .start = (uintptr_t) &browse_list,
  89. .end = 0
  90. },
  91. {
  92. .name = "is_odd",
  93. .start = (uintptr_t) &is_odd,
  94. .end = 0
  95. },
  96. {
  97. .name = "is_even",
  98. .start = (uintptr_t) &is_even,
  99. .end = 0
  100. }
  101. };
  102. /**
  103. * @brief Test whether the address passed as PC is part of the function which
  104. * name is `function_name`. The global array `funs` is used.
  105. *
  106. * @param pc Program counter to test. (address in the program)
  107. * @param function_name Function name to check the address of.
  108. *
  109. * @return true if PC is in the function called `function_name`, false else.
  110. */
  111. bool is_pc_in_function(const uint32_t pc, const char* function_name)
  112. {
  113. for (uint32_t i = 0; i < FUNCTIONS_COUNT; i++) {
  114. const struct functions_info current_fun = funs[i];
  115. if (strcmp(current_fun.name, function_name) == 0) {
  116. return current_fun.start <= pc && pc <= current_fun.end;
  117. }
  118. }
  119. /* Function not found. */
  120. return false;
  121. }
  122. /**
  123. * @brief Number of times `esp_eh_frame_generated_step` is called.
  124. */
  125. static uint32_t iteration = 1;
  126. /**
  127. * @brief Override the default function called when a backtrace step is
  128. * generated.
  129. */
  130. void esp_eh_frame_generated_step(uint32_t pc, uint32_t sp) {
  131. /* The first PCs in the backtrace are calls to `browse_list()` + 2.
  132. * This is due to the fact that the list contains all the numbers
  133. * between NUMBER_TO_TEST to 0 included. Moreover, another call
  134. * is made when we meet the NULL pointer. */
  135. if (iteration > 0 && iteration <= (NUMBER_TO_TEST + 2)) {
  136. assert(is_pc_in_function(pc, "browse_list"));
  137. } else {
  138. /**
  139. * The backtrace should be:
  140. * - in is_odd when iteration is even.
  141. * - in is_even when iteration is odd.
  142. *
  143. * The backtrace finishes when the iteration reaches the end of
  144. * browse_list (NUMBER_TO_TEST + 2 iterations), is_even
  145. * (NUMBER_TO_TEST/2 calls) and is_odd (NUMBER_TO_TEST/2 calls) calls.
  146. */
  147. if (iteration >= NUMBER_OF_ITERATION)
  148. return;
  149. else if (iteration % 2 == 0)
  150. assert(is_pc_in_function(pc, "is_odd"));
  151. else
  152. assert(is_pc_in_function(pc, "is_even"));
  153. }
  154. /* Number of times this function has been entered. */
  155. iteration++;
  156. }
  157. /**
  158. * @brief Handler called when SIGSEV signal is sent to the program.
  159. *
  160. * @param signal Signal received byt the program. Shall be SIGSEGV.
  161. * @param info Structure containing info about the error itself. Ignored.
  162. * @param ucontext Context of the program when the error occurred. This
  163. * is used to retrieve the CPU registers value.
  164. */
  165. void signal_handler(int signal, siginfo_t *info, void *ucontext) {
  166. /* Setup the execution frame as expected by the eh_frame_parser.
  167. * Indeed, the registers index defined in ucontext.h are NOT the same
  168. * the registers index DWARF is expecting. */
  169. ucontext_t* context = (ucontext_t*) ucontext;
  170. greg_t *gregset = context->uc_mcontext.gregs;
  171. x86ExcFrame frame = {
  172. .eax = gregset[REG_EAX],
  173. .ecx = gregset[REG_ECX],
  174. .edx = gregset[REG_EDX],
  175. .ebx = gregset[REG_EBX],
  176. .esp = gregset[REG_ESP],
  177. .ebp = gregset[REG_EBP],
  178. .esi = gregset[REG_ESI],
  179. .edi = gregset[REG_EDI],
  180. .eip = gregset[REG_EIP]
  181. };
  182. /* The following function will use panic_print_str and panic_print_hex
  183. * function to output the data.
  184. * Instead of replacing stdout file descriptor with a pipe, we can simply
  185. * replace these functions to store the data instead of printing them.
  186. */
  187. esp_eh_frame_print_backtrace(&frame);
  188. /* No assert has been triggered, the backtrace succeeded if the number of
  189. * iterations of function `esp_eh_frame_generated_step` is correct. */
  190. if (iteration == NUMBER_OF_ITERATION) {
  191. printf("\e[32m\e[1mAll tests passed \e[0m\r\n");
  192. } else {
  193. printf("\e[31m\e[1mWrong length of backtrace (%d iteration, expected %d) \e[0m\r\n",
  194. iteration, NUMBER_OF_ITERATION);
  195. exit(1);
  196. }
  197. /* Everything went fine, exit normally. */
  198. exit(0);
  199. }
  200. /**
  201. * @brief Browse the list passed as an argument.
  202. * The following function will trigger a SIGSEV signal on purpose, in order to
  203. * generate the backtrace.
  204. *
  205. * @param l List to browse.
  206. */
  207. void browse_list(struct list_t* l) {
  208. browse_list(l->next);
  209. }
  210. /**
  211. * @brief Add a number to the global list `head`.
  212. *
  213. * @param n Number to add in the list.
  214. */
  215. void add_number_to_list(uint32_t n) {
  216. struct list_t* l = malloc(sizeof(struct list_t));
  217. l->value = n;
  218. l->next = head.next;
  219. head.next = l;
  220. }
  221. /**
  222. * @brief Test if the number passed is even.
  223. * This function will fail, on purpose.
  224. *
  225. * @param n Number to test.
  226. *
  227. * @return true if even, false else.
  228. */
  229. bool is_even(uint32_t n) {
  230. add_number_to_list(n);
  231. if (n == 0) {
  232. browse_list(head.next);
  233. return true;
  234. }
  235. return is_odd(n - 1);
  236. }
  237. /**
  238. * @brief Test if the number passed is odd.
  239. * This function will fail, on purpose.
  240. *
  241. * @param n Number to test.
  242. *
  243. * @return true if odd, false else.
  244. */
  245. bool is_odd(uint32_t n) {
  246. add_number_to_list(n);
  247. if (n == 0) {
  248. browse_list(head.next);
  249. return false;
  250. }
  251. return is_even(n - 1);
  252. }
  253. /**
  254. * @brief Initiliaze the global `funs` array.
  255. */
  256. static inline void initialize_functions_info(void)
  257. {
  258. for (uint32_t i = 0; i < FUNCTIONS_COUNT; i++) {
  259. /* Each of the functions defined in this structure finishes
  260. * with the following instructions:
  261. * leave (0xc9)
  262. * ret (0xc3)
  263. * Thus, we will look for these instructions. */
  264. uint8_t* instructions = (uint8_t*) funs[i].start;
  265. while (instructions[0] != 0xc9 || instructions[1] != 0xc3)
  266. instructions++;
  267. instructions += 1;
  268. funs[i].end = (uintptr_t) instructions;
  269. }
  270. }
  271. /**
  272. * Call the previous functions to create a complex call stack and fail.
  273. */
  274. int main (int argc, char** argv)
  275. {
  276. /* Initialize the structure holding information about the signal to override. */
  277. struct sigaction sig = {
  278. .sa_mask = 0,
  279. .sa_flags = SA_SIGINFO,
  280. .sa_restorer = NULL,
  281. .sa_sigaction = signal_handler
  282. };
  283. /* Look for the functions end functions. */
  284. initialize_functions_info();
  285. /* Override default SIGSEV signal callback. */
  286. int res = sigaction(SIGSEGV, &sig, NULL);
  287. if (res) {
  288. perror("Could not override SIGSEV signal");
  289. return 1;
  290. }
  291. /* Trigger the segmentation fault with a complex backtrace. */
  292. is_even(NUMBER_TO_TEST);
  293. return 0;
  294. }