stacktrace.c 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. #include <linux/sched.h>
  2. #include <linux/stacktrace.h>
  3. #include <linux/stacktrace.h>
  4. #include <asm/stacktrace.h>
  5. void walk_stackframe(unsigned long sp,
  6. int (*fn)(unsigned long addr, void *data),
  7. void *data)
  8. {
  9. unsigned long high = ALIGN(sp, THREAD_SIZE);
  10. for (; sp <= high - 4; sp += 4) {
  11. unsigned long addr = *(unsigned long *) sp;
  12. if (!kernel_text_address(addr))
  13. continue;
  14. if (fn(addr, data))
  15. break;
  16. }
  17. }
  18. struct stack_trace_data {
  19. struct stack_trace *trace;
  20. unsigned int no_sched_functions;
  21. unsigned int skip;
  22. };
  23. #ifdef CONFIG_STACKTRACE
  24. static int save_trace(unsigned long addr, void *d)
  25. {
  26. struct stack_trace_data *data = d;
  27. struct stack_trace *trace = data->trace;
  28. if (data->no_sched_functions && in_sched_functions(addr))
  29. return 0;
  30. if (data->skip) {
  31. data->skip--;
  32. return 0;
  33. }
  34. trace->entries[trace->nr_entries++] = addr;
  35. return trace->nr_entries >= trace->max_entries;
  36. }
  37. void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
  38. {
  39. struct stack_trace_data data;
  40. unsigned long sp;
  41. data.trace = trace;
  42. data.skip = trace->skip;
  43. if (tsk != current) {
  44. data.no_sched_functions = 1;
  45. sp = tsk->thread.ksp;
  46. } else {
  47. data.no_sched_functions = 0;
  48. sp = rdsp();
  49. }
  50. walk_stackframe(sp, save_trace, &data);
  51. if (trace->nr_entries < trace->max_entries)
  52. trace->entries[trace->nr_entries++] = ULONG_MAX;
  53. }
  54. void save_stack_trace(struct stack_trace *trace)
  55. {
  56. save_stack_trace_tsk(current, trace);
  57. }
  58. EXPORT_SYMBOL_GPL(save_stack_trace);
  59. #endif /* CONFIG_STACKTRACE */