backtrace.c 1.9 KB

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