backtrace.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*
  2. * SH specific backtracing code for oprofile
  3. *
  4. * Copyright 2007 STMicroelectronics Ltd.
  5. *
  6. * Author: Dave Peverley <dpeverley@mpc-data.co.uk>
  7. *
  8. * Based on ARM oprofile backtrace code by Richard Purdie and in turn, i386
  9. * oprofile backtrace code by John Levon, David Smith
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License version 2 as
  13. * published by the Free Software Foundation.
  14. *
  15. */
  16. #include <linux/oprofile.h>
  17. #include <linux/sched.h>
  18. #include <linux/kallsyms.h>
  19. #include <linux/mm.h>
  20. #include <asm/ptrace.h>
  21. #include <asm/uaccess.h>
  22. #include <asm/sections.h>
  23. /* Limit to stop backtracing too far. */
  24. static int backtrace_limit = 20;
  25. static unsigned long *
  26. user_backtrace(unsigned long *stackaddr, struct pt_regs *regs)
  27. {
  28. unsigned long buf_stack;
  29. /* Also check accessibility of address */
  30. if (!access_ok(VERIFY_READ, stackaddr, sizeof(unsigned long)))
  31. return NULL;
  32. if (__copy_from_user_inatomic(&buf_stack, stackaddr, sizeof(unsigned long)))
  33. return NULL;
  34. /* Quick paranoia check */
  35. if (buf_stack & 3)
  36. return NULL;
  37. oprofile_add_trace(buf_stack);
  38. stackaddr++;
  39. return stackaddr;
  40. }
  41. /*
  42. * | | /\ Higher addresses
  43. * | |
  44. * --------------- stack base (address of current_thread_info)
  45. * | thread info |
  46. * . .
  47. * | stack |
  48. * --------------- saved regs->regs[15] value if valid
  49. * . .
  50. * --------------- struct pt_regs stored on stack (struct pt_regs *)
  51. * | |
  52. * . .
  53. * | |
  54. * --------------- ???
  55. * | |
  56. * | | \/ Lower addresses
  57. *
  58. * Thus, &pt_regs <-> stack base restricts the valid(ish) fp values
  59. */
  60. static int valid_kernel_stack(unsigned long *stackaddr, struct pt_regs *regs)
  61. {
  62. unsigned long stack = (unsigned long)regs;
  63. unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
  64. return ((unsigned long)stackaddr > stack) && ((unsigned long)stackaddr < stack_base);
  65. }
  66. static unsigned long *
  67. kernel_backtrace(unsigned long *stackaddr, struct pt_regs *regs)
  68. {
  69. unsigned long addr;
  70. /*
  71. * If not a valid kernel address, keep going till we find one
  72. * or the SP stops being a valid address.
  73. */
  74. do {
  75. addr = *stackaddr++;
  76. oprofile_add_trace(addr);
  77. } while (valid_kernel_stack(stackaddr, regs));
  78. return stackaddr;
  79. }
  80. void sh_backtrace(struct pt_regs * const regs, unsigned int depth)
  81. {
  82. unsigned long *stackaddr;
  83. /*
  84. * Paranoia - clip max depth as we could get lost in the weeds.
  85. */
  86. if (depth > backtrace_limit)
  87. depth = backtrace_limit;
  88. stackaddr = (unsigned long *)regs->regs[15];
  89. if (!user_mode(regs)) {
  90. while (depth-- && valid_kernel_stack(stackaddr, regs))
  91. stackaddr = kernel_backtrace(stackaddr, regs);
  92. return;
  93. }
  94. while (depth-- && (stackaddr != NULL))
  95. stackaddr = user_backtrace(stackaddr, regs);
  96. }