backtrace.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /**
  2. * @file backtrace.c
  3. *
  4. * @remark Copyright 2002 OProfile authors
  5. * @remark Read the file COPYING
  6. *
  7. * @author John Levon
  8. * @author David Smith
  9. */
  10. #include <linux/oprofile.h>
  11. #include <linux/sched.h>
  12. #include <linux/mm.h>
  13. #include <asm/ptrace.h>
  14. #include <asm/uaccess.h>
  15. struct frame_head {
  16. struct frame_head * ebp;
  17. unsigned long ret;
  18. } __attribute__((packed));
  19. static struct frame_head *
  20. dump_backtrace(struct frame_head * head)
  21. {
  22. struct frame_head bufhead[2];
  23. /* Also check accessibility of one struct frame_head beyond */
  24. if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
  25. return NULL;
  26. if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
  27. return NULL;
  28. oprofile_add_trace(bufhead[0].ret);
  29. /* frame pointers should strictly progress back up the stack
  30. * (towards higher addresses) */
  31. if (head >= bufhead[0].ebp)
  32. return NULL;
  33. return bufhead[0].ebp;
  34. }
  35. /*
  36. * | | /\ Higher addresses
  37. * | |
  38. * --------------- stack base (address of current_thread_info)
  39. * | thread info |
  40. * . .
  41. * | stack |
  42. * --------------- saved regs->ebp value if valid (frame_head address)
  43. * . .
  44. * --------------- struct pt_regs stored on stack (struct pt_regs *)
  45. * | |
  46. * . .
  47. * | |
  48. * --------------- %esp
  49. * | |
  50. * | | \/ Lower addresses
  51. *
  52. * Thus, &pt_regs <-> stack base restricts the valid(ish) ebp values
  53. */
  54. #ifdef CONFIG_FRAME_POINTER
  55. static int valid_kernel_stack(struct frame_head * head, struct pt_regs * regs)
  56. {
  57. unsigned long headaddr = (unsigned long)head;
  58. unsigned long stack = (unsigned long)regs;
  59. unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
  60. return headaddr > stack && headaddr < stack_base;
  61. }
  62. #else
  63. /* without fp, it's just junk */
  64. static int valid_kernel_stack(struct frame_head * head, struct pt_regs * regs)
  65. {
  66. return 0;
  67. }
  68. #endif
  69. void
  70. x86_backtrace(struct pt_regs * const regs, unsigned int depth)
  71. {
  72. struct frame_head *head;
  73. #ifdef CONFIG_X86_64
  74. head = (struct frame_head *)regs->rbp;
  75. #else
  76. head = (struct frame_head *)regs->ebp;
  77. #endif
  78. if (!user_mode_vm(regs)) {
  79. while (depth-- && valid_kernel_stack(head, regs))
  80. head = dump_backtrace(head);
  81. return;
  82. }
  83. while (depth-- && head)
  84. head = dump_backtrace(head);
  85. }