backtrace.c 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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. #include <asm/stacktrace.h>
  16. static void backtrace_warning_symbol(void *data, char *msg,
  17. unsigned long symbol)
  18. {
  19. /* Ignore warnings */
  20. }
  21. static void backtrace_warning(void *data, char *msg)
  22. {
  23. /* Ignore warnings */
  24. }
  25. static int backtrace_stack(void *data, char *name)
  26. {
  27. /* Yes, we want all stacks */
  28. return 0;
  29. }
  30. static void backtrace_address(void *data, unsigned long addr, int reliable)
  31. {
  32. unsigned int *depth = data;
  33. if ((*depth)--)
  34. oprofile_add_trace(addr);
  35. }
  36. static struct stacktrace_ops backtrace_ops = {
  37. .warning = backtrace_warning,
  38. .warning_symbol = backtrace_warning_symbol,
  39. .stack = backtrace_stack,
  40. .address = backtrace_address,
  41. };
  42. struct frame_head {
  43. struct frame_head *bp;
  44. unsigned long ret;
  45. } __attribute__((packed));
  46. static struct frame_head *
  47. dump_user_backtrace(struct frame_head * head)
  48. {
  49. struct frame_head bufhead[2];
  50. /* Also check accessibility of one struct frame_head beyond */
  51. if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
  52. return NULL;
  53. if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
  54. return NULL;
  55. oprofile_add_trace(bufhead[0].ret);
  56. /* frame pointers should strictly progress back up the stack
  57. * (towards higher addresses) */
  58. if (head >= bufhead[0].bp)
  59. return NULL;
  60. return bufhead[0].bp;
  61. }
  62. void
  63. x86_backtrace(struct pt_regs * const regs, unsigned int depth)
  64. {
  65. struct frame_head *head = (struct frame_head *)frame_pointer(regs);
  66. unsigned long stack = kernel_trap_sp(regs);
  67. if (!user_mode_vm(regs)) {
  68. if (depth)
  69. dump_trace(NULL, regs, (unsigned long *)stack, 0,
  70. &backtrace_ops, &depth);
  71. return;
  72. }
  73. while (depth-- && head)
  74. head = dump_user_backtrace(head);
  75. }