stacktrace.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*
  2. * arch/xtensa/kernel/stacktrace.c
  3. *
  4. * This file is subject to the terms and conditions of the GNU General Public
  5. * License. See the file "COPYING" in the main directory of this archive
  6. * for more details.
  7. *
  8. * Copyright (C) 2001 - 2013 Tensilica Inc.
  9. */
  10. #include <linux/export.h>
  11. #include <linux/sched.h>
  12. #include <linux/stacktrace.h>
  13. #include <asm/stacktrace.h>
  14. #include <asm/traps.h>
  15. void walk_stackframe(unsigned long *sp,
  16. int (*fn)(struct stackframe *frame, void *data),
  17. void *data)
  18. {
  19. unsigned long a0, a1;
  20. unsigned long sp_end;
  21. a1 = (unsigned long)sp;
  22. sp_end = ALIGN(a1, THREAD_SIZE);
  23. spill_registers();
  24. while (a1 < sp_end) {
  25. struct stackframe frame;
  26. sp = (unsigned long *)a1;
  27. a0 = *(sp - 4);
  28. a1 = *(sp - 3);
  29. if (a1 <= (unsigned long)sp)
  30. break;
  31. frame.pc = MAKE_PC_FROM_RA(a0, a1);
  32. frame.sp = a1;
  33. if (fn(&frame, data))
  34. return;
  35. }
  36. }
  37. #ifdef CONFIG_STACKTRACE
  38. struct stack_trace_data {
  39. struct stack_trace *trace;
  40. unsigned skip;
  41. };
  42. static int stack_trace_cb(struct stackframe *frame, void *data)
  43. {
  44. struct stack_trace_data *trace_data = data;
  45. struct stack_trace *trace = trace_data->trace;
  46. if (trace_data->skip) {
  47. --trace_data->skip;
  48. return 0;
  49. }
  50. if (!kernel_text_address(frame->pc))
  51. return 0;
  52. trace->entries[trace->nr_entries++] = frame->pc;
  53. return trace->nr_entries >= trace->max_entries;
  54. }
  55. void save_stack_trace_tsk(struct task_struct *task, struct stack_trace *trace)
  56. {
  57. struct stack_trace_data trace_data = {
  58. .trace = trace,
  59. .skip = trace->skip,
  60. };
  61. walk_stackframe(stack_pointer(task), stack_trace_cb, &trace_data);
  62. }
  63. EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
  64. void save_stack_trace(struct stack_trace *trace)
  65. {
  66. save_stack_trace_tsk(current, trace);
  67. }
  68. EXPORT_SYMBOL_GPL(save_stack_trace);
  69. #endif
  70. #ifdef CONFIG_FRAME_POINTER
  71. struct return_addr_data {
  72. unsigned long addr;
  73. unsigned skip;
  74. };
  75. static int return_address_cb(struct stackframe *frame, void *data)
  76. {
  77. struct return_addr_data *r = data;
  78. if (r->skip) {
  79. --r->skip;
  80. return 0;
  81. }
  82. if (!kernel_text_address(frame->pc))
  83. return 0;
  84. r->addr = frame->pc;
  85. return 1;
  86. }
  87. unsigned long return_address(unsigned level)
  88. {
  89. struct return_addr_data r = {
  90. .skip = level + 1,
  91. };
  92. walk_stackframe(stack_pointer(NULL), return_address_cb, &r);
  93. return r.addr;
  94. }
  95. EXPORT_SYMBOL(return_address);
  96. #endif