stacktrace.c 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. #include <linux/sched.h>
  2. #include <linux/stacktrace.h>
  3. #include "stacktrace.h"
  4. int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high,
  5. int (*fn)(struct stackframe *, void *), void *data)
  6. {
  7. struct stackframe *frame;
  8. do {
  9. /*
  10. * Check current frame pointer is within bounds
  11. */
  12. if ((fp - 12) < low || fp + 4 >= high)
  13. break;
  14. frame = (struct stackframe *)(fp - 12);
  15. if (fn(frame, data))
  16. break;
  17. /*
  18. * Update the low bound - the next frame must always
  19. * be at a higher address than the current frame.
  20. */
  21. low = fp + 4;
  22. fp = frame->fp;
  23. } while (fp);
  24. return 0;
  25. }
  26. #ifdef CONFIG_STACKTRACE
  27. struct stack_trace_data {
  28. struct stack_trace *trace;
  29. unsigned int skip;
  30. };
  31. static int save_trace(struct stackframe *frame, void *d)
  32. {
  33. struct stack_trace_data *data = d;
  34. struct stack_trace *trace = data->trace;
  35. if (data->skip) {
  36. data->skip--;
  37. return 0;
  38. }
  39. trace->entries[trace->nr_entries++] = frame->lr;
  40. return trace->nr_entries >= trace->max_entries;
  41. }
  42. void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
  43. {
  44. struct stack_trace_data data;
  45. unsigned long fp, base;
  46. data.trace = trace;
  47. data.skip = trace->skip;
  48. if (task) {
  49. base = (unsigned long)task_stack_page(task);
  50. fp = 0; /* FIXME */
  51. } else {
  52. base = (unsigned long)task_stack_page(current);
  53. asm("mov %0, fp" : "=r" (fp));
  54. }
  55. walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data);
  56. }
  57. #endif