0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <linux/ptrace.h>
0025 #include <linux/export.h>
0026 #include <linux/stacktrace.h>
0027 #include <linux/kallsyms.h>
0028 #include <linux/sched/debug.h>
0029
0030 #include <asm/arcregs.h>
0031 #include <asm/unwind.h>
0032 #include <asm/switch_to.h>
0033
0034
0035
0036
0037
0038
0039 #ifdef CONFIG_ARC_DW2_UNWIND
0040
0041 static int
0042 seed_unwind_frame_info(struct task_struct *tsk, struct pt_regs *regs,
0043 struct unwind_frame_info *frame_info)
0044 {
0045 if (regs) {
0046
0047
0048
0049
0050 frame_info->task = tsk;
0051
0052 frame_info->regs.r27 = regs->fp;
0053 frame_info->regs.r28 = regs->sp;
0054 frame_info->regs.r31 = regs->blink;
0055 frame_info->regs.r63 = regs->ret;
0056 frame_info->call_frame = 0;
0057 } else if (tsk == NULL || tsk == current) {
0058
0059
0060
0061
0062 unsigned long fp, sp, blink, ret;
0063 frame_info->task = current;
0064
0065 __asm__ __volatile__(
0066 "mov %0,r27\n\t"
0067 "mov %1,r28\n\t"
0068 "mov %2,r31\n\t"
0069 "mov %3,r63\n\t"
0070 : "=r"(fp), "=r"(sp), "=r"(blink), "=r"(ret)
0071 );
0072
0073 frame_info->regs.r27 = fp;
0074 frame_info->regs.r28 = sp;
0075 frame_info->regs.r31 = blink;
0076 frame_info->regs.r63 = ret;
0077 frame_info->call_frame = 0;
0078 } else {
0079
0080
0081
0082
0083
0084
0085
0086 if (task_is_running(tsk))
0087 return -1;
0088
0089 frame_info->task = tsk;
0090
0091 frame_info->regs.r27 = TSK_K_FP(tsk);
0092 frame_info->regs.r28 = TSK_K_ESP(tsk);
0093 frame_info->regs.r31 = TSK_K_BLINK(tsk);
0094 frame_info->regs.r63 = (unsigned int)__switch_to;
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105 frame_info->regs.r27 = 0;
0106 frame_info->regs.r28 += 60;
0107 frame_info->call_frame = 0;
0108
0109 }
0110 return 0;
0111 }
0112
0113 #endif
0114
0115 notrace noinline unsigned int
0116 arc_unwind_core(struct task_struct *tsk, struct pt_regs *regs,
0117 int (*consumer_fn) (unsigned int, void *), void *arg)
0118 {
0119 #ifdef CONFIG_ARC_DW2_UNWIND
0120 int ret = 0, cnt = 0;
0121 unsigned int address;
0122 struct unwind_frame_info frame_info;
0123
0124 if (seed_unwind_frame_info(tsk, regs, &frame_info))
0125 return 0;
0126
0127 while (1) {
0128 address = UNW_PC(&frame_info);
0129
0130 if (!address || !__kernel_text_address(address))
0131 break;
0132
0133 if (consumer_fn(address, arg) == -1)
0134 break;
0135
0136 ret = arc_unwind(&frame_info);
0137 if (ret)
0138 break;
0139
0140 frame_info.regs.r63 = frame_info.regs.r31;
0141
0142 if (cnt++ > 128) {
0143 printk("unwinder looping too long, aborting !\n");
0144 return 0;
0145 }
0146 }
0147
0148 return address;
0149 #else
0150
0151
0152
0153
0154
0155 pr_warn_once("CONFIG_ARC_DW2_UNWIND needs to be enabled\n");
0156 return 0;
0157
0158 #endif
0159 }
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172 static int __print_sym(unsigned int address, void *arg)
0173 {
0174 const char *loglvl = arg;
0175
0176 printk("%s %pS\n", loglvl, (void *)address);
0177 return 0;
0178 }
0179
0180 #ifdef CONFIG_STACKTRACE
0181
0182
0183
0184
0185 static int __collect_all(unsigned int address, void *arg)
0186 {
0187 struct stack_trace *trace = arg;
0188
0189 if (trace->skip > 0)
0190 trace->skip--;
0191 else
0192 trace->entries[trace->nr_entries++] = address;
0193
0194 if (trace->nr_entries >= trace->max_entries)
0195 return -1;
0196
0197 return 0;
0198 }
0199
0200 static int __collect_all_but_sched(unsigned int address, void *arg)
0201 {
0202 struct stack_trace *trace = arg;
0203
0204 if (in_sched_functions(address))
0205 return 0;
0206
0207 if (trace->skip > 0)
0208 trace->skip--;
0209 else
0210 trace->entries[trace->nr_entries++] = address;
0211
0212 if (trace->nr_entries >= trace->max_entries)
0213 return -1;
0214
0215 return 0;
0216 }
0217
0218 #endif
0219
0220 static int __get_first_nonsched(unsigned int address, void *unused)
0221 {
0222 if (in_sched_functions(address))
0223 return 0;
0224
0225 return -1;
0226 }
0227
0228
0229
0230
0231
0232
0233 noinline void show_stacktrace(struct task_struct *tsk, struct pt_regs *regs,
0234 const char *loglvl)
0235 {
0236 printk("%s\nStack Trace:\n", loglvl);
0237 arc_unwind_core(tsk, regs, __print_sym, (void *)loglvl);
0238 }
0239 EXPORT_SYMBOL(show_stacktrace);
0240
0241
0242 void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
0243 {
0244 show_stacktrace(tsk, NULL, loglvl);
0245 }
0246
0247
0248
0249
0250
0251 unsigned int __get_wchan(struct task_struct *tsk)
0252 {
0253 return arc_unwind_core(tsk, NULL, __get_first_nonsched, NULL);
0254 }
0255
0256 #ifdef CONFIG_STACKTRACE
0257
0258
0259
0260
0261
0262 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
0263 {
0264
0265 arc_unwind_core(tsk, NULL, __collect_all_but_sched, trace);
0266 }
0267
0268 void save_stack_trace(struct stack_trace *trace)
0269 {
0270
0271 arc_unwind_core(NULL, NULL, __collect_all, trace);
0272 }
0273 EXPORT_SYMBOL_GPL(save_stack_trace);
0274 #endif