unwind_guess.c 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2022 Loongson Technology Corporation Limited
  4. */
  5. #include <linux/kernel.h>
  6. #include <asm/unwind.h>
  7. unsigned long unwind_get_return_address(struct unwind_state *state)
  8. {
  9. if (unwind_done(state))
  10. return 0;
  11. else if (state->first)
  12. return state->pc;
  13. return *(unsigned long *)(state->sp);
  14. }
  15. EXPORT_SYMBOL_GPL(unwind_get_return_address);
  16. void unwind_start(struct unwind_state *state, struct task_struct *task,
  17. struct pt_regs *regs)
  18. {
  19. memset(state, 0, sizeof(*state));
  20. if (regs) {
  21. state->sp = regs->regs[3];
  22. state->pc = regs->csr_era;
  23. } else if (task && task != current) {
  24. state->sp = thread_saved_fp(task);
  25. state->pc = thread_saved_ra(task);
  26. } else {
  27. state->sp = (unsigned long)__builtin_frame_address(0);
  28. state->pc = (unsigned long)__builtin_return_address(0);
  29. }
  30. state->task = task;
  31. state->first = true;
  32. get_stack_info(state->sp, state->task, &state->stack_info);
  33. if (!unwind_done(state) && !__kernel_text_address(state->pc))
  34. unwind_next_frame(state);
  35. }
  36. EXPORT_SYMBOL_GPL(unwind_start);
  37. bool unwind_next_frame(struct unwind_state *state)
  38. {
  39. struct stack_info *info = &state->stack_info;
  40. unsigned long addr;
  41. if (unwind_done(state))
  42. return false;
  43. if (state->first)
  44. state->first = false;
  45. do {
  46. for (state->sp += sizeof(unsigned long);
  47. state->sp < info->end;
  48. state->sp += sizeof(unsigned long)) {
  49. addr = *(unsigned long *)(state->sp);
  50. if (__kernel_text_address(addr))
  51. return true;
  52. }
  53. state->sp = info->next_sp;
  54. } while (!get_stack_info(state->sp, state->task, info));
  55. return false;
  56. }
  57. EXPORT_SYMBOL_GPL(unwind_next_frame);