unwind.h 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Most of this ideas comes from x86.
  4. *
  5. * Copyright (C) 2022 Loongson Technology Corporation Limited
  6. */
  7. #ifndef _ASM_UNWIND_H
  8. #define _ASM_UNWIND_H
  9. #include <linux/sched.h>
  10. #include <linux/ftrace.h>
  11. #include <asm/ptrace.h>
  12. #include <asm/stacktrace.h>
  13. enum unwinder_type {
  14. UNWINDER_GUESS,
  15. UNWINDER_PROLOGUE,
  16. UNWINDER_ORC,
  17. };
  18. struct unwind_state {
  19. char type; /* UNWINDER_XXX */
  20. struct stack_info stack_info;
  21. struct task_struct *task;
  22. bool first, error, reset;
  23. int graph_idx;
  24. unsigned long sp, fp, pc, ra;
  25. };
  26. bool default_next_frame(struct unwind_state *state);
  27. void unwind_start(struct unwind_state *state,
  28. struct task_struct *task, struct pt_regs *regs);
  29. bool unwind_next_frame(struct unwind_state *state);
  30. unsigned long unwind_get_return_address(struct unwind_state *state);
  31. static inline bool unwind_done(struct unwind_state *state)
  32. {
  33. return state->stack_info.type == STACK_TYPE_UNKNOWN;
  34. }
  35. static inline bool unwind_error(struct unwind_state *state)
  36. {
  37. return state->error;
  38. }
  39. #define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_regs, regs[1]))
  40. static inline unsigned long unwind_graph_addr(struct unwind_state *state,
  41. unsigned long pc, unsigned long cfa)
  42. {
  43. return ftrace_graph_ret_addr(state->task, &state->graph_idx,
  44. pc, (unsigned long *)(cfa - GRAPH_FAKE_OFFSET));
  45. }
  46. static __always_inline void __unwind_start(struct unwind_state *state,
  47. struct task_struct *task, struct pt_regs *regs)
  48. {
  49. memset(state, 0, sizeof(*state));
  50. if (regs) {
  51. state->sp = regs->regs[3];
  52. state->pc = regs->csr_era;
  53. state->ra = regs->regs[1];
  54. state->fp = regs->regs[22];
  55. } else if (task && task != current) {
  56. state->sp = thread_saved_fp(task);
  57. state->pc = thread_saved_ra(task);
  58. state->ra = 0;
  59. state->fp = 0;
  60. } else {
  61. state->sp = (unsigned long)__builtin_frame_address(0);
  62. state->pc = (unsigned long)__builtin_return_address(0);
  63. state->ra = 0;
  64. state->fp = 0;
  65. }
  66. state->task = task;
  67. get_stack_info(state->sp, state->task, &state->stack_info);
  68. state->pc = unwind_graph_addr(state, state->pc, state->sp);
  69. }
  70. static __always_inline unsigned long __unwind_get_return_address(struct unwind_state *state)
  71. {
  72. if (unwind_done(state))
  73. return 0;
  74. return __kernel_text_address(state->pc) ? state->pc : 0;
  75. }
  76. #ifdef CONFIG_UNWINDER_ORC
  77. void unwind_init(void);
  78. void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size, void *orc, size_t orc_size);
  79. #else
  80. static inline void unwind_init(void) {}
  81. static inline void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size, void *orc, size_t orc_size) {}
  82. #endif
  83. #endif /* _ASM_UNWIND_H */