backtrace.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  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. struct frame_head {
  15. struct frame_head * ebp;
  16. unsigned long ret;
  17. } __attribute__((packed));
  18. static struct frame_head *
  19. dump_backtrace(struct frame_head * head)
  20. {
  21. oprofile_add_trace(head->ret);
  22. /* frame pointers should strictly progress back up the stack
  23. * (towards higher addresses) */
  24. if (head >= head->ebp)
  25. return NULL;
  26. return head->ebp;
  27. }
  28. /* check that the page(s) containing the frame head are present */
  29. static int pages_present(struct frame_head * head)
  30. {
  31. struct mm_struct * mm = current->mm;
  32. /* FIXME: only necessary once per page */
  33. if (!check_user_page_readable(mm, (unsigned long)head))
  34. return 0;
  35. return check_user_page_readable(mm, (unsigned long)(head + 1));
  36. }
  37. /*
  38. * | | /\ Higher addresses
  39. * | |
  40. * --------------- stack base (address of current_thread_info)
  41. * | thread info |
  42. * . .
  43. * | stack |
  44. * --------------- saved regs->ebp value if valid (frame_head address)
  45. * . .
  46. * --------------- struct pt_regs stored on stack (struct pt_regs *)
  47. * | |
  48. * . .
  49. * | |
  50. * --------------- %esp
  51. * | |
  52. * | | \/ Lower addresses
  53. *
  54. * Thus, &pt_regs <-> stack base restricts the valid(ish) ebp values
  55. */
  56. #ifdef CONFIG_FRAME_POINTER
  57. static int valid_kernel_stack(struct frame_head * head, struct pt_regs * regs)
  58. {
  59. unsigned long headaddr = (unsigned long)head;
  60. unsigned long stack = (unsigned long)regs;
  61. unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
  62. return headaddr > stack && headaddr < stack_base;
  63. }
  64. #else
  65. /* without fp, it's just junk */
  66. static int valid_kernel_stack(struct frame_head * head, struct pt_regs * regs)
  67. {
  68. return 0;
  69. }
  70. #endif
  71. void
  72. x86_backtrace(struct pt_regs * const regs, unsigned int depth)
  73. {
  74. struct frame_head *head;
  75. #ifdef CONFIG_X86_64
  76. head = (struct frame_head *)regs->rbp;
  77. #else
  78. head = (struct frame_head *)regs->ebp;
  79. #endif
  80. if (!user_mode_vm(regs)) {
  81. while (depth-- && valid_kernel_stack(head, regs))
  82. head = dump_backtrace(head);
  83. return;
  84. }
  85. #ifdef CONFIG_SMP
  86. if (!spin_trylock(&current->mm->page_table_lock))
  87. return;
  88. #endif
  89. while (depth-- && head && pages_present(head))
  90. head = dump_backtrace(head);
  91. #ifdef CONFIG_SMP
  92. spin_unlock(&current->mm->page_table_lock);
  93. #endif
  94. }