unwind.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. /*
  2. * Copyright (c) 2022 Agustina Arzille.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <stdio.h>
  18. #include <kern/symbol.h>
  19. #include <kern/thread.h>
  20. #include <kern/unwind.h>
  21. #include <machine/cpu.h>
  22. #include <machine/pmap.h>
  23. // Miscelaneous constants used by the DWARF unwinder.
  24. #define DW_EH_PE_absptr 0x00
  25. #define DW_EH_PE_signed 0x09
  26. #define DW_EH_PE_pcrel 0x10
  27. #define DW_EH_PE_aligned 0x50
  28. #define DW_EH_PE_indirect 0x80
  29. #define DW_EH_PE_omit 0xff
  30. // Encoding types for DWARF.
  31. enum
  32. {
  33. DW_EH_PE_uleb128 = 0x01,
  34. DW_EH_PE_udata2,
  35. DW_EH_PE_udata4,
  36. DW_EH_PE_udata8,
  37. DW_EH_PE_sleb128 = DW_EH_PE_uleb128 | DW_EH_PE_signed,
  38. DW_EH_PE_sdata2,
  39. DW_EH_PE_sdata4,
  40. DW_EH_PE_sdata8
  41. };
  42. // Register save states.
  43. enum
  44. {
  45. DW_RULE_SAME,
  46. DW_RULE_UNDEF,
  47. DW_RULE_OFFSET,
  48. DW_RULE_REG,
  49. };
  50. // DWARF opcodes.
  51. #define DW_CFA_nop 0x00
  52. #define DW_CFA_set_loc 0x01
  53. #define DW_CFA_advance_loc1 0x02
  54. #define DW_CFA_advance_loc2 0x03
  55. #define DW_CFA_advance_loc4 0x04
  56. #define DW_CFA_offset_extended 0x05
  57. #define DW_CFA_undefined 0x07
  58. #define DW_CFA_same_value 0x08
  59. #define DW_CFA_register 0x09
  60. #define DW_CFA_remember_state 0x0a
  61. #define DW_CFA_restore_state 0x0b
  62. #define DW_CFA_def_cfa 0x0c
  63. #define DW_CFA_def_cfa_register 0x0d
  64. #define DW_CFA_def_cfa_offset 0x0e
  65. #define DW_CFA_offset_extended_sf 0x11
  66. #define DW_CFA_def_cfa_sf 0x12
  67. #define DW_CFA_def_cfa_offset_sf 0x13
  68. #define DW_CFA_val_offset 0x14
  69. #define DW_CFA_val_offset_sf 0x15
  70. #define DW_CFA_GNU_args_size 0x2e
  71. #define DW_CFA_advance_loc 0x40
  72. #define DW_CFA_offset 0x80
  73. #define DW_CFA_restore 0xc0
  74. #define UNW_SP_REGISTER __builtin_dwarf_sp_column ()
  75. #define UNW_RA(x) __builtin_extract_return_addr ((void *)(x))
  76. const struct unw_globals *volatile unw_globals_ptr __weak;
  77. /*
  78. * A register save state can be defined in terms of:
  79. * - Another register.
  80. * - An offset within the CFA.
  81. * - An arbitrary expression (Not yet supported).
  82. */
  83. struct unw_frame_regs
  84. {
  85. uint8_t rules[CPU_UNWIND_REGISTERS];
  86. union
  87. {
  88. uint16_t reg;
  89. int16_t off;
  90. } values[CPU_UNWIND_REGISTERS];
  91. struct
  92. {
  93. int rule;
  94. uint16_t reg;
  95. int16_t off;
  96. } cfa;
  97. };
  98. struct unw_cursor
  99. {
  100. struct unw_mcontext *mctx;
  101. struct unw_frame_regs cols;
  102. };
  103. static void
  104. unw_cursor_clear (struct unw_cursor *cursor)
  105. {
  106. memset (&cursor->cols, 0, sizeof (cursor->cols));
  107. }
  108. static void
  109. unw_cursor_init_mctx (struct unw_cursor *cursor, struct unw_mcontext *mctx)
  110. {
  111. unw_cursor_clear (cursor);
  112. cursor->mctx = mctx;
  113. }
  114. static const struct unw_fde*
  115. unw_fde_lookup (uintptr_t pc, const struct unw_globals *globals)
  116. {
  117. if (pc < globals->base_addr)
  118. return (NULL);
  119. uint32_t base = (uint32_t)(pc - globals->base_addr);
  120. const struct unw_fde *fdes = globals->fdes;
  121. // Binary search over the FDE's.
  122. for (uint32_t n = globals->nr_fdes; n > 0; )
  123. {
  124. _Auto fde = &fdes[n / 2];
  125. if (base < fde->base_off)
  126. n /= 2;
  127. else if (base > fde->base_off + fde->addr_range)
  128. {
  129. fdes = fde + 1;
  130. n -= n / 2 + 1;
  131. }
  132. else
  133. return (fde);
  134. }
  135. return (NULL);
  136. }
  137. static uintptr_t
  138. unw_read_uleb (const unsigned char **ptr)
  139. {
  140. // Read an unsigned LEB-128 value and update the source pointer.
  141. const unsigned char *p = *ptr;
  142. for (uintptr_t ret = 0, shift = 0 ; ; shift += 7)
  143. {
  144. uintptr_t byte = *p++;
  145. ret |= (byte & 0x7f) << shift;
  146. if (!(byte & 0x80))
  147. {
  148. *ptr = p;
  149. return (ret);
  150. }
  151. }
  152. }
  153. static intptr_t
  154. unw_read_sleb (const unsigned char **ptr)
  155. {
  156. // Read a signed LEB-128 value and update the source pointer.
  157. intptr_t ret = 0;
  158. uint32_t shift = 0, byte;
  159. const unsigned char *p = *ptr;
  160. do
  161. {
  162. byte = *p++;
  163. ret |= ((uintptr_t)byte & 0x7f) << shift;
  164. shift += 7;
  165. }
  166. while (byte & 0x80);
  167. if (shift < 8 * sizeof (ret) && (byte & 0x40))
  168. ret |= -(((uintptr_t)1) << shift);
  169. *ptr = p;
  170. return (ret);
  171. }
  172. static int
  173. unw_read_safe (uintptr_t addr, uintptr_t *out)
  174. {
  175. if (addr < PMAP_START_KERNEL_ADDRESS ||
  176. addr > PMAP_END_KERNEL_ADDRESS)
  177. return (-EFAULT);
  178. *out = *(uintptr_t *)addr;
  179. return (0);
  180. }
  181. static int
  182. unw_read_encptr (uint8_t enc, const unsigned char **ptr,
  183. uintptr_t pc, uintptr_t *out)
  184. {
  185. const unsigned char *p = *ptr;
  186. if (enc == DW_EH_PE_omit)
  187. {
  188. *out = 0;
  189. return (0);
  190. }
  191. else if (enc == DW_EH_PE_aligned)
  192. {
  193. size_t size = sizeof (uintptr_t) - 1;
  194. p = (const unsigned char *)(((uintptr_t)p + size) & ~size);
  195. if (unw_read_safe ((uintptr_t)p, out) != 0)
  196. return (-EFAULT);
  197. *ptr = p + sizeof (uintptr_t);
  198. return (0);
  199. }
  200. uintptr_t base;
  201. switch (enc & 0x70)
  202. {
  203. case DW_EH_PE_absptr:
  204. base = 0;
  205. break;
  206. case DW_EH_PE_pcrel:
  207. base = pc;
  208. break;
  209. default:
  210. return (-EINVAL);
  211. }
  212. if ((enc & 0x7) == 0)
  213. #ifdef __LP64__
  214. enc |= DW_EH_PE_udata8;
  215. #else
  216. enc |= DW_EH_PE_udata4;
  217. #endif
  218. uintptr_t ret;
  219. switch (enc & 0xf)
  220. {
  221. case DW_EH_PE_uleb128:
  222. ret = base + unw_read_uleb (&p);
  223. break;
  224. case DW_EH_PE_sleb128:
  225. ret = base + unw_read_sleb (&p);
  226. break;
  227. #define UNW_UDATA(type, enc_val) \
  228. case DW_EH_PE_##enc_val: \
  229. { \
  230. type tmp; \
  231. for (size_t i = 0; i < sizeof (tmp); ++i) \
  232. ((unsigned char *)&tmp)[i] = p[i]; \
  233. p += sizeof (tmp); \
  234. ret = base + tmp; \
  235. } \
  236. break
  237. UNW_UDATA (uint16_t, udata2);
  238. UNW_UDATA (int16_t, sdata2);
  239. UNW_UDATA (uint32_t, udata4);
  240. UNW_UDATA (int32_t, sdata4);
  241. UNW_UDATA (uint64_t, udata8);
  242. UNW_UDATA (int64_t, sdata8);
  243. #undef UNW_UDATA
  244. default:
  245. return (-EINVAL);
  246. }
  247. if ((enc & DW_EH_PE_indirect) &&
  248. unw_read_safe (ret, &ret) != 0)
  249. return (-EFAULT);
  250. *ptr = p;
  251. *out = ret;
  252. return (0);
  253. }
  254. static int
  255. unw_cursor_set_column (struct unw_cursor *cursor, size_t column,
  256. int rule, uintptr_t val)
  257. {
  258. if (column >= ARRAY_SIZE (cursor->cols.rules))
  259. return (-EFAULT);
  260. cursor->cols.rules[column] = rule;
  261. cursor->cols.values[column].reg = val;
  262. return (0);
  263. }
  264. static uintptr_t
  265. unw_cursor_pc (const struct unw_cursor *cursor)
  266. {
  267. return (cursor->mctx->regs[CPU_UNWIND_PC_REG]);
  268. }
  269. static void
  270. unw_cursor_set_pc (struct unw_cursor *cursor, uintptr_t pc)
  271. {
  272. cursor->mctx->regs[CPU_UNWIND_PC_REG] = pc;
  273. }
  274. static void
  275. unw_cursor_set_sp (struct unw_cursor *cursor, uintptr_t sp)
  276. {
  277. cursor->mctx->regs[UNW_SP_REGISTER] = sp;
  278. }
  279. #define UNW_CURSOR_SET_COLUMN(cursor, column, rule, val) \
  280. do \
  281. { \
  282. int error_ = unw_cursor_set_column (cursor, column, rule, \
  283. (uintptr_t)(val)); \
  284. if (error_) \
  285. return (error_); \
  286. } \
  287. while (0)
  288. static int
  289. unw_run_dw (struct unw_cursor *cursor, const struct unw_cie *cie,
  290. const unsigned char *ops, uintptr_t pc)
  291. {
  292. struct unw_frame_regs free_regs[4];
  293. uint32_t free_idx = 0;
  294. intptr_t sarg;
  295. uintptr_t regno, arg = unw_read_uleb (&ops);
  296. _Auto ops_end = ops + arg;
  297. while (pc < unw_cursor_pc (cursor) && ops < ops_end)
  298. {
  299. uint8_t operand = 0, op = *ops++;
  300. if (op & 0xc0)
  301. {
  302. operand = op & 0x3f;
  303. op &= ~0x3f;
  304. }
  305. switch (op)
  306. {
  307. case DW_CFA_set_loc:
  308. if (unw_read_encptr (cie->code_enc, &ops, pc, &pc) < 0)
  309. return (-1);
  310. break;
  311. case DW_CFA_advance_loc:
  312. pc += operand * cie->code_align;
  313. break;
  314. case DW_CFA_advance_loc1:
  315. pc += (*ops++) * cie->code_align;
  316. break;
  317. case DW_CFA_advance_loc2:
  318. {
  319. uint16_t off;
  320. memcpy (&off, ops, sizeof (off));
  321. ops += sizeof (off);
  322. pc += off * cie->code_align;
  323. break;
  324. }
  325. case DW_CFA_advance_loc4:
  326. {
  327. uint32_t off;
  328. memcpy (&off, ops, sizeof (off));
  329. ops += sizeof (off);
  330. pc += off * cie->code_align;
  331. break;
  332. }
  333. case DW_CFA_def_cfa:
  334. cursor->cols.cfa.reg = unw_read_uleb (&ops);
  335. cursor->cols.cfa.off = unw_read_uleb (&ops);
  336. cursor->cols.cfa.rule = DW_RULE_REG;
  337. break;
  338. case DW_CFA_def_cfa_sf:
  339. cursor->cols.cfa.reg = unw_read_uleb (&ops);
  340. cursor->cols.cfa.off = unw_read_sleb (&ops) * cie->data_align;
  341. cursor->cols.cfa.rule = DW_RULE_REG;
  342. break;
  343. case DW_CFA_def_cfa_offset:
  344. cursor->cols.cfa.off = unw_read_uleb (&ops);
  345. break;
  346. case DW_CFA_def_cfa_register:
  347. cursor->cols.cfa.reg = unw_read_uleb (&ops);
  348. cursor->cols.cfa.rule = DW_RULE_REG;
  349. break;
  350. case DW_CFA_offset:
  351. arg = unw_read_uleb (&ops);
  352. unw_cursor_set_column (cursor, operand, DW_RULE_OFFSET,
  353. arg * cie->data_align);
  354. break;
  355. case DW_CFA_offset_extended:
  356. regno = unw_read_uleb (&ops);
  357. arg = unw_read_uleb (&ops);
  358. unw_cursor_set_column (cursor, regno, DW_RULE_OFFSET,
  359. arg * cie->data_align);
  360. break;
  361. case DW_CFA_offset_extended_sf:
  362. regno = unw_read_uleb (&ops);
  363. sarg = unw_read_sleb (&ops);
  364. unw_cursor_set_column (cursor, regno, DW_RULE_OFFSET,
  365. sarg * cie->data_align);
  366. break;
  367. case DW_CFA_undefined:
  368. case DW_CFA_same_value:
  369. regno = unw_read_uleb (&ops);
  370. unw_cursor_set_column (cursor, regno, op == DW_CFA_undefined ?
  371. DW_RULE_UNDEF : DW_RULE_SAME, 0);
  372. break;
  373. case DW_CFA_register:
  374. regno = unw_read_uleb (&ops);
  375. arg = unw_read_uleb (&ops);
  376. unw_cursor_set_column (cursor, regno, DW_RULE_REG, arg);
  377. break;
  378. case DW_CFA_nop:
  379. break;
  380. case DW_CFA_GNU_args_size:
  381. (void)unw_read_uleb (&ops);
  382. break;
  383. case DW_CFA_remember_state:
  384. if (free_idx >= ARRAY_SIZE (free_regs))
  385. return (-ENOMEM);
  386. free_regs[free_idx++] = cursor->cols;
  387. break;
  388. case DW_CFA_restore_state:
  389. if (! free_idx)
  390. return (-EINVAL);
  391. cursor->cols = free_regs[--free_idx];
  392. break;
  393. case DW_CFA_restore:
  394. if (operand >= ARRAY_SIZE (cursor->cols.rules))
  395. return (-EFAULT);
  396. cursor->cols.rules[operand] = DW_RULE_SAME;
  397. break;
  398. default:
  399. return (-EINVAL);
  400. }
  401. }
  402. return (0);
  403. }
  404. static int
  405. unw_apply_regs (struct unw_cursor *cursor, const struct unw_cie *cie)
  406. {
  407. _Auto cols = &cursor->cols;
  408. // Compute the CFA first, as further expressions may depend on it.
  409. if (cols->cfa.reg >= ARRAY_SIZE (cursor->mctx->regs))
  410. return (-EFAULT);
  411. else if (cols->cfa.rule != DW_RULE_REG)
  412. return (-EINVAL);
  413. uintptr_t *regs = cursor->mctx->regs,
  414. cfa = regs[cols->cfa.reg] + cols->cfa.off;
  415. for (size_t i = 0; i < ARRAY_SIZE (cols->rules); ++i)
  416. switch (cols->rules[i])
  417. {
  418. case DW_RULE_UNDEF:
  419. case DW_RULE_SAME:
  420. break;
  421. case DW_RULE_OFFSET:
  422. if (unw_read_safe (cfa + cols->values[i].off, &regs[i]) != 0)
  423. return (-EFAULT);
  424. break;
  425. case DW_RULE_REG:
  426. {
  427. _Auto rx = cols->values[i].reg;
  428. if (unlikely (rx >= ARRAY_SIZE (cursor->mctx->regs)) ||
  429. unw_read_safe (regs[rx], &regs[i]) != 0)
  430. return (-EFAULT);
  431. break;
  432. }
  433. default:
  434. return (-EINVAL);
  435. }
  436. if (cie->ret_addr >= ARRAY_SIZE (cols->rules))
  437. return (-EINVAL);
  438. else if (cols->rules[cie->ret_addr] == DW_RULE_UNDEF)
  439. {
  440. unw_cursor_set_pc (cursor, 0);
  441. return (0);
  442. }
  443. void *pc = UNW_RA (regs[cie->ret_addr]);
  444. unw_cursor_set_pc (cursor, (uintptr_t)pc);
  445. unw_cursor_set_sp (cursor, cfa);
  446. return (pc != 0);
  447. }
  448. static int
  449. unw_cursor_step (struct unw_cursor *cursor)
  450. {
  451. _Auto gd = unw_globals_ptr;
  452. _Auto fde = unw_fde_lookup (unw_cursor_pc (cursor) - 1, gd);
  453. if (! fde)
  454. return (-1);
  455. uintptr_t initial_loc = fde->base_off + gd->base_addr;
  456. _Auto cie = &gd->cies[fde->idxs & 0xff];
  457. // Run the CIE initialization ops.
  458. int rv = unw_run_dw (cursor, cie, gd->ops + cie->ops_idx, initial_loc);
  459. if (rv < 0)
  460. return (rv);
  461. // Run the FDE ops to unwind the stack.
  462. rv = unw_run_dw (cursor, cie, gd->ops + (fde->idxs >> 8), initial_loc);
  463. if (rv == 0)
  464. // If successful, set the registers to their new values.
  465. rv = unw_apply_regs (cursor, cie);
  466. // Clear the cursor for the next run.
  467. unw_cursor_clear (cursor);
  468. return (rv);
  469. }
  470. int
  471. unw_backtrace (struct unw_mcontext *mctx,
  472. int (*fn) (struct unw_mcontext *, void *), void *arg)
  473. {
  474. struct unw_cursor cursor;
  475. if (! mctx)
  476. {
  477. mctx = alloca (sizeof (*mctx));
  478. cpu_unw_mctx_save (mctx->regs);
  479. }
  480. unw_cursor_init_mctx (&cursor, mctx);
  481. while (1)
  482. {
  483. int error = fn (cursor.mctx, arg);
  484. if (error)
  485. return (error);
  486. else if (unw_cursor_step (&cursor) <= 0)
  487. return (0);
  488. }
  489. }
  490. static int
  491. unw_show_stacktrace (struct unw_mcontext *mctx, void *arg)
  492. {
  493. uintptr_t pc = mctx->regs[CPU_UNWIND_PC_REG];
  494. const struct symbol *sym = symbol_lookup (pc);
  495. uint32_t index = (*(uint32_t *)arg)++;
  496. if (! sym)
  497. printf ("#%02u [%#010lx]\n", index, pc);
  498. else
  499. printf ("#%02u [%#010lx] %s+%#lx/%#lx\n", index, pc,
  500. sym->name, pc - sym->addr, sym->size);
  501. return (0);
  502. }
  503. void
  504. unw_stacktrace (struct unw_mcontext *mctx)
  505. {
  506. uint32_t index = 0;
  507. unw_backtrace (mctx, unw_show_stacktrace, &index);
  508. }
  509. int
  510. (unw_fixup_save) (struct unw_fixup_t *fx, void *frame)
  511. {
  512. fx->sp = (uintptr_t)__builtin_dwarf_cfa ();
  513. fx->bp = (uintptr_t)frame;
  514. fx->pc = (uintptr_t)UNW_RA (__builtin_return_address (0));
  515. struct thread *self = thread_self ();
  516. fx->prev = &self->fixup;
  517. fx->next = *fx->prev;
  518. self->fixup = fx;
  519. return (0);
  520. }
  521. #define unw_cursor_frame(cursor) ((cursor)->mctx->regs[CPU_UNWIND_FRAME_REG])
  522. static int
  523. unw_fixup_step_until (struct unw_fixup_t *fixup, struct unw_cursor *cursor)
  524. {
  525. while (1)
  526. {
  527. if (unw_cursor_frame (cursor) == fixup->bp)
  528. return (0);
  529. else if (unw_cursor_step (cursor) <= 0)
  530. return (-1);
  531. }
  532. }
  533. void
  534. unw_fixup_restore (struct unw_fixup_t *fixup,
  535. struct unw_mcontext *mctx, int retval)
  536. {
  537. struct unw_cursor cursor;
  538. unw_cursor_init_mctx (&cursor, mctx);
  539. if (unw_fixup_step_until (fixup, &cursor) < 0)
  540. return;
  541. unw_cursor_set_pc (&cursor, fixup->pc);
  542. unw_cursor_set_sp (&cursor, fixup->sp);
  543. cpu_unw_mctx_set_frame (cursor.mctx->regs, retval);
  544. __builtin_unreachable ();
  545. }
  546. void
  547. unw_fixup_jmp (struct unw_fixup_t *fixup, int retval)
  548. {
  549. __builtin_unwind_init ();
  550. struct unw_cursor cursor;
  551. struct unw_mcontext mctx;
  552. cpu_unw_mctx_save (mctx.regs);
  553. unw_cursor_init_mctx (&cursor, &mctx);
  554. if (unw_fixup_step_until (fixup, &cursor) == 0)
  555. {
  556. unw_cursor_set_sp (&cursor, fixup->sp);
  557. unw_cursor_set_pc (&cursor, fixup->pc);
  558. cpu_unw_mctx_jmp (cursor.mctx->regs, retval);
  559. }
  560. __builtin_unreachable ();
  561. }