ftrace.c 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2022 Loongson Technology Corporation Limited
  4. */
  5. #include <linux/init.h>
  6. #include <linux/ftrace.h>
  7. #include <linux/syscalls.h>
  8. #include <linux/uaccess.h>
  9. #include <asm/asm.h>
  10. #include <asm/asm-offsets.h>
  11. #include <asm/cacheflush.h>
  12. #include <asm/inst.h>
  13. #include <asm/loongarch.h>
  14. #include <asm/syscall.h>
  15. #include <asm-generic/sections.h>
  16. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  17. /*
  18. * As `call _mcount` follows LoongArch psABI, ra-saved operation and
  19. * stack operation can be found before this insn.
  20. */
  21. static int ftrace_get_parent_ra_addr(unsigned long insn_addr, int *ra_off)
  22. {
  23. int limit = 32;
  24. union loongarch_instruction *insn;
  25. insn = (union loongarch_instruction *)insn_addr;
  26. do {
  27. insn--;
  28. limit--;
  29. if (is_ra_save_ins(insn))
  30. *ra_off = -((1 << 12) - insn->reg2i12_format.immediate);
  31. } while (!is_stack_alloc_ins(insn) && limit);
  32. if (!limit)
  33. return -EINVAL;
  34. return 0;
  35. }
  36. void prepare_ftrace_return(unsigned long self_addr,
  37. unsigned long callsite_sp, unsigned long old)
  38. {
  39. int ra_off;
  40. unsigned long return_hooker = (unsigned long)&return_to_handler;
  41. if (unlikely(ftrace_graph_is_dead()))
  42. return;
  43. if (unlikely(atomic_read(&current->tracing_graph_pause)))
  44. return;
  45. if (ftrace_get_parent_ra_addr(self_addr, &ra_off))
  46. goto out;
  47. if (!function_graph_enter(old, self_addr, 0, NULL))
  48. *(unsigned long *)(callsite_sp + ra_off) = return_hooker;
  49. return;
  50. out:
  51. ftrace_graph_stop();
  52. WARN_ON(1);
  53. }
  54. #endif /* CONFIG_FUNCTION_GRAPH_TRACER */