1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) |
4 | */ |
5 | |
6 | #include <linux/ptrace.h> |
7 | #include <linux/module.h> |
8 | #include <linux/mm.h> |
9 | #include <linux/fs.h> |
10 | #include <linux/kdev_t.h> |
11 | #include <linux/proc_fs.h> |
12 | #include <linux/file.h> |
13 | #include <linux/sched/mm.h> |
14 | #include <linux/sched/debug.h> |
15 | |
16 | #include <asm/arcregs.h> |
17 | #include <asm/irqflags.h> |
18 | |
19 | #define ARC_PATH_MAX 256 |
20 | |
21 | static noinline void print_regs_scratch(struct pt_regs *regs) |
22 | { |
23 | pr_cont("BTA: 0x%08lx\n SP: 0x%08lx FP: 0x%08lx BLK: %pS\n" , |
24 | regs->bta, regs->sp, regs->fp, (void *)regs->blink); |
25 | pr_cont("LPS: 0x%08lx\tLPE: 0x%08lx\tLPC: 0x%08lx\n" , |
26 | regs->lp_start, regs->lp_end, regs->lp_count); |
27 | |
28 | pr_info("r00: 0x%08lx\tr01: 0x%08lx\tr02: 0x%08lx\n" \ |
29 | "r03: 0x%08lx\tr04: 0x%08lx\tr05: 0x%08lx\n" \ |
30 | "r06: 0x%08lx\tr07: 0x%08lx\tr08: 0x%08lx\n" \ |
31 | "r09: 0x%08lx\tr10: 0x%08lx\tr11: 0x%08lx\n" \ |
32 | "r12: 0x%08lx\t" , |
33 | regs->r0, regs->r1, regs->r2, |
34 | regs->r3, regs->r4, regs->r5, |
35 | regs->r6, regs->r7, regs->r8, |
36 | regs->r9, regs->r10, regs->r11, |
37 | regs->r12); |
38 | } |
39 | |
40 | static void print_regs_callee(struct callee_regs *regs) |
41 | { |
42 | pr_cont("r13: 0x%08lx\tr14: 0x%08lx\n" \ |
43 | "r15: 0x%08lx\tr16: 0x%08lx\tr17: 0x%08lx\n" \ |
44 | "r18: 0x%08lx\tr19: 0x%08lx\tr20: 0x%08lx\n" \ |
45 | "r21: 0x%08lx\tr22: 0x%08lx\tr23: 0x%08lx\n" \ |
46 | "r24: 0x%08lx\tr25: 0x%08lx\n" , |
47 | regs->r13, regs->r14, |
48 | regs->r15, regs->r16, regs->r17, |
49 | regs->r18, regs->r19, regs->r20, |
50 | regs->r21, regs->r22, regs->r23, |
51 | regs->r24, regs->r25); |
52 | } |
53 | |
54 | static void print_task_path_n_nm(struct task_struct *tsk) |
55 | { |
56 | char *path_nm = NULL; |
57 | struct mm_struct *mm; |
58 | struct file *exe_file; |
59 | char buf[ARC_PATH_MAX]; |
60 | |
61 | mm = get_task_mm(task: tsk); |
62 | if (!mm) |
63 | goto done; |
64 | |
65 | exe_file = get_mm_exe_file(mm); |
66 | mmput(mm); |
67 | |
68 | if (exe_file) { |
69 | path_nm = file_path(exe_file, buf, ARC_PATH_MAX-1); |
70 | fput(exe_file); |
71 | } |
72 | |
73 | done: |
74 | pr_info("Path: %s\n" , !IS_ERR(path_nm) ? path_nm : "?" ); |
75 | } |
76 | |
77 | static void show_faulting_vma(unsigned long address) |
78 | { |
79 | struct vm_area_struct *vma; |
80 | struct mm_struct *active_mm = current->active_mm; |
81 | |
82 | /* can't use print_vma_addr() yet as it doesn't check for |
83 | * non-inclusive vma |
84 | */ |
85 | mmap_read_lock(mm: active_mm); |
86 | vma = vma_lookup(mm: active_mm, addr: address); |
87 | |
88 | /* Lookup the vma at the address and report if the container VMA is not |
89 | * found |
90 | */ |
91 | if (vma) { |
92 | char buf[ARC_PATH_MAX]; |
93 | char *nm = "anon" ; |
94 | |
95 | if (vma->vm_file) { |
96 | /* XXX: can we use %pD below and get rid of buf? */ |
97 | nm = d_path(file_user_path(f: vma->vm_file), buf, |
98 | ARC_PATH_MAX-1); |
99 | if (IS_ERR(ptr: nm)) |
100 | nm = "?" ; |
101 | } |
102 | pr_info(" @off 0x%lx in [%s] VMA: 0x%08lx to 0x%08lx\n" , |
103 | vma->vm_start < TASK_UNMAPPED_BASE ? |
104 | address : address - vma->vm_start, |
105 | nm, vma->vm_start, vma->vm_end); |
106 | } else |
107 | pr_info(" @No matching VMA found\n" ); |
108 | |
109 | mmap_read_unlock(mm: active_mm); |
110 | } |
111 | |
112 | static void show_ecr_verbose(struct pt_regs *regs) |
113 | { |
114 | unsigned int vec, cause_code; |
115 | unsigned long address; |
116 | |
117 | /* For Data fault, this is data address not instruction addr */ |
118 | address = current->thread.fault_address; |
119 | |
120 | vec = regs->ecr.vec; |
121 | cause_code = regs->ecr.cause; |
122 | |
123 | /* For DTLB Miss or ProtV, display the memory involved too */ |
124 | if (vec == ECR_V_DTLB_MISS) { |
125 | pr_cont("Invalid %s @ 0x%08lx by insn @ %pS\n" , |
126 | (cause_code == 0x01) ? "Read" : |
127 | ((cause_code == 0x02) ? "Write" : "EX" ), |
128 | address, (void *)regs->ret); |
129 | } else if (vec == ECR_V_ITLB_MISS) { |
130 | pr_cont("Insn could not be fetched\n" ); |
131 | } else if (vec == ECR_V_MACH_CHK) { |
132 | pr_cont("Machine Check (%s)\n" , (cause_code == 0x0) ? |
133 | "Double Fault" : "Other Fatal Err" ); |
134 | |
135 | } else if (vec == ECR_V_PROTV) { |
136 | if (cause_code == ECR_C_PROTV_INST_FETCH) |
137 | pr_cont("Execute from Non-exec Page\n" ); |
138 | else if (cause_code == ECR_C_PROTV_MISALIG_DATA && |
139 | IS_ENABLED(CONFIG_ISA_ARCOMPACT)) |
140 | pr_cont("Misaligned r/w from 0x%08lx\n" , address); |
141 | else |
142 | pr_cont("%s access not allowed on page\n" , |
143 | (cause_code == 0x01) ? "Read" : |
144 | ((cause_code == 0x02) ? "Write" : "EX" )); |
145 | } else if (vec == ECR_V_INSN_ERR) { |
146 | pr_cont("Illegal Insn\n" ); |
147 | #ifdef CONFIG_ISA_ARCV2 |
148 | } else if (vec == ECR_V_MEM_ERR) { |
149 | if (cause_code == 0x00) |
150 | pr_cont("Bus Error from Insn Mem\n" ); |
151 | else if (cause_code == 0x10) |
152 | pr_cont("Bus Error from Data Mem\n" ); |
153 | else |
154 | pr_cont("Bus Error, check PRM\n" ); |
155 | } else if (vec == ECR_V_MISALIGN) { |
156 | pr_cont("Misaligned r/w from 0x%08lx\n" , address); |
157 | #endif |
158 | } else if (vec == ECR_V_TRAP) { |
159 | if (regs->ecr.param == 5) |
160 | pr_cont("gcc generated __builtin_trap\n" ); |
161 | } else { |
162 | pr_cont("Check Programmer's Manual\n" ); |
163 | } |
164 | } |
165 | |
166 | /************************************************************************ |
167 | * API called by rest of kernel |
168 | ***********************************************************************/ |
169 | |
170 | void show_regs(struct pt_regs *regs) |
171 | { |
172 | struct task_struct *tsk = current; |
173 | struct callee_regs *cregs = (struct callee_regs *)tsk->thread.callee_reg; |
174 | |
175 | /* |
176 | * generic code calls us with preemption disabled, but some calls |
177 | * here could sleep, so re-enable to avoid lockdep splat |
178 | */ |
179 | preempt_enable(); |
180 | |
181 | print_task_path_n_nm(tsk); |
182 | show_regs_print_info(KERN_INFO); |
183 | |
184 | show_ecr_verbose(regs); |
185 | |
186 | if (user_mode(regs)) |
187 | show_faulting_vma(address: regs->ret); /* faulting code, not data */ |
188 | |
189 | pr_info("ECR: 0x%08lx EFA: 0x%08lx ERET: 0x%08lx\n" , |
190 | regs->ecr.full, current->thread.fault_address, regs->ret); |
191 | |
192 | pr_info("STAT32: 0x%08lx" , regs->status32); |
193 | |
194 | #define STS_BIT(r, bit) r->status32 & STATUS_##bit##_MASK ? #bit" " : "" |
195 | |
196 | #ifdef CONFIG_ISA_ARCOMPACT |
197 | pr_cont(" [%2s%2s%2s%2s%2s%2s%2s]" , |
198 | (regs->status32 & STATUS_U_MASK) ? "U " : "K " , |
199 | STS_BIT(regs, DE), STS_BIT(regs, AE), |
200 | STS_BIT(regs, A2), STS_BIT(regs, A1), |
201 | STS_BIT(regs, E2), STS_BIT(regs, E1)); |
202 | #else |
203 | pr_cont(" [%2s%2s%2s%2s] " , |
204 | STS_BIT(regs, IE), |
205 | (regs->status32 & STATUS_U_MASK) ? "U " : "K " , |
206 | STS_BIT(regs, DE), STS_BIT(regs, AE)); |
207 | #endif |
208 | |
209 | print_regs_scratch(regs); |
210 | if (cregs) |
211 | print_regs_callee(regs: cregs); |
212 | |
213 | preempt_disable(); |
214 | } |
215 | |
216 | void show_kernel_fault_diag(const char *str, struct pt_regs *regs, |
217 | unsigned long address) |
218 | { |
219 | current->thread.fault_address = address; |
220 | |
221 | /* Show fault description */ |
222 | pr_info("\n%s\n" , str); |
223 | |
224 | /* Caller and Callee regs */ |
225 | show_regs(regs); |
226 | |
227 | /* Show stack trace if this Fatality happened in kernel mode */ |
228 | if (!user_mode(regs)) |
229 | show_stacktrace(current, regs, KERN_DEFAULT); |
230 | } |
231 | |