backtrace.c 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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 *dump_user_backtrace(struct frame_head *head)
  47. {
  48. struct frame_head bufhead[2];
  49. /* Also check accessibility of one struct frame_head beyond */
  50. if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
  51. return NULL;
  52. if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
  53. return NULL;
  54. oprofile_add_trace(bufhead[0].ret);
  55. /* frame pointers should strictly progress back up the stack
  56. * (towards higher addresses) */
  57. if (head >= bufhead[0].bp)
  58. return NULL;
  59. return bufhead[0].bp;
  60. }
  61. void
  62. x86_backtrace(struct pt_regs * const regs, unsigned int depth)
  63. {
  64. struct frame_head *head = (struct frame_head *)frame_pointer(regs);
  65. if (!user_mode_vm(regs)) {
  66. unsigned long stack = kernel_stack_pointer(regs);
  67. if (depth)
  68. dump_trace(NULL, regs, (unsigned long *)stack, 0,
  69. &backtrace_ops, &depth);
  70. return;
  71. }
  72. while (depth-- && head)
  73. head = dump_user_backtrace(head);
  74. }