unwind.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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. * Generic runtime stack unwinding.
  18. */
  19. #ifndef KERN_UNWIND_H
  20. #define KERN_UNWIND_H
  21. #include <stdint.h>
  22. #include <stdnoreturn.h>
  23. #include <kern/macros.h>
  24. #include <machine/cpu.h>
  25. #define __unwind __section (".unwind")
  26. // Common information element.
  27. struct unw_cie
  28. {
  29. uintptr_t code_align;
  30. uintptr_t ret_addr;
  31. intptr_t data_align;
  32. uint8_t code_enc;
  33. uint16_t ops_idx;
  34. };
  35. // Frame descriptor element.
  36. struct unw_fde
  37. {
  38. uint32_t base_off; // Difference relative to the base address.
  39. uint32_t addr_range; // Range in bytes for this FDE.
  40. uint32_t idxs; // CIE index (low 16 bits) and opcode index (high 16 bits).
  41. };
  42. // DWARF global data - Exported by the unwind table generator.
  43. struct unw_globals
  44. {
  45. uint32_t nr_fdes;
  46. const struct unw_fde *fdes;
  47. const struct unw_cie *cies;
  48. const unsigned char *ops;
  49. uintptr_t base_addr;
  50. };
  51. // Machine context used for unwinding and stack tracing.
  52. struct unw_mcontext
  53. {
  54. uintptr_t regs[CPU_UNWIND_REGISTERS];
  55. };
  56. // Saved information needed for fixups.
  57. struct unw_fixup_t
  58. {
  59. uintptr_t sp;
  60. uintptr_t bp;
  61. uintptr_t pc;
  62. struct unw_fixup_t *next;
  63. struct unw_fixup_t **prev;
  64. };
  65. int unw_fixup_save (struct unw_fixup_t *fixup, void *frame)
  66. __attribute__ ((returns_twice));
  67. // Save the calling environemt in FIXUP. Always returns zero.
  68. #define unw_fixup_save(fx) \
  69. (unw_fixup_save) ((fx), __builtin_frame_address (0))
  70. /*
  71. * Restore the environment saved in FIXUP, starting the unwind process
  72. * from CTX. Makes the 'unw_fixup_save' return RETVAL.
  73. */
  74. void unw_fixup_restore (struct unw_fixup_t *fixup,
  75. struct unw_mcontext *ctx, int retval);
  76. /*
  77. * Same as above, only this function uses the current machine context
  78. * instead of a user-provided one, and doesn't handle failures in
  79. * the unwind process.
  80. */
  81. noreturn void unw_fixup_jmp (struct unw_fixup_t *fixup, int retval);
  82. /*
  83. * Perform a traceback, starting from the passed machine context (or the
  84. * current one, if null), applying the function with the registers and
  85. * argument. If a non-zero value is returned, the traceback stops immediately.
  86. */
  87. int unw_backtrace (struct unw_mcontext *initial,
  88. int (*fn) (struct unw_mcontext *, void *), void *arg);
  89. /*
  90. * Print the stack trace originating in the provided context, if provided,
  91. * otherwise, use the current one.
  92. */
  93. void unw_stacktrace (struct unw_mcontext *initial);
  94. // Fixup guard.
  95. static inline void
  96. unw_fixup_fini (void *p)
  97. {
  98. struct unw_fixup_t *fx = p;
  99. *fx->prev = fx->next;
  100. }
  101. #define unw_fixup unw_fixup_t CLEANUP (unw_fixup_fini)
  102. #endif