]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/sparc64/sparc64/db_trace.c
Merge ACPICA 20180105.
[FreeBSD/FreeBSD.git] / sys / sparc64 / sparc64 / db_trace.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2001 Jake Burkholder.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kdb.h>
35 #include <sys/proc.h>
36 #include <sys/stack.h>
37 #include <sys/sysent.h>
38
39 #include <vm/vm.h>
40 #include <vm/vm_page.h>
41 #include <vm/vm_map.h>
42
43 #include <machine/cpu.h>
44 #include <machine/pcb.h>
45 #include <machine/stack.h>
46 #include <machine/trap.h>
47 #include <machine/vmparam.h>
48
49 #include <ddb/ddb.h>
50 #include <ddb/db_access.h>
51 #include <ddb/db_sym.h>
52 #include <ddb/db_variables.h>
53 #include <ddb/db_watch.h>
54
55 static db_varfcn_t db_frame;
56
57 #define DB_OFFSET(x)    (db_expr_t *)offsetof(struct trapframe, x)
58 struct  db_variable db_regs[] = {
59         { "g0",         DB_OFFSET(tf_global[0]),        db_frame },
60         { "g1",         DB_OFFSET(tf_global[1]),        db_frame },
61         { "g2",         DB_OFFSET(tf_global[2]),        db_frame },
62         { "g3",         DB_OFFSET(tf_global[3]),        db_frame },
63         { "g4",         DB_OFFSET(tf_global[4]),        db_frame },
64         { "g5",         DB_OFFSET(tf_global[5]),        db_frame },
65         { "g6",         DB_OFFSET(tf_global[6]),        db_frame },
66         { "g7",         DB_OFFSET(tf_global[7]),        db_frame },
67         { "i0",         DB_OFFSET(tf_out[0]),           db_frame },
68         { "i1",         DB_OFFSET(tf_out[1]),           db_frame },
69         { "i2",         DB_OFFSET(tf_out[2]),           db_frame },
70         { "i3",         DB_OFFSET(tf_out[3]),           db_frame },
71         { "i4",         DB_OFFSET(tf_out[4]),           db_frame },
72         { "i5",         DB_OFFSET(tf_out[5]),           db_frame },
73         { "i6",         DB_OFFSET(tf_out[6]),           db_frame },
74         { "i7",         DB_OFFSET(tf_out[7]),           db_frame },
75         { "tnpc",       DB_OFFSET(tf_tnpc),             db_frame },
76         { "tpc",        DB_OFFSET(tf_tpc),              db_frame },
77         { "tstate",     DB_OFFSET(tf_tstate),           db_frame },
78 };
79 struct db_variable *db_eregs = db_regs + nitems(db_regs);
80
81 static int
82 db_frame(struct db_variable *vp, db_expr_t *valuep, int op)
83 {
84         uint64_t *reg;
85
86         if (kdb_frame == NULL)
87                 return (0);
88         reg = (uint64_t*)((uintptr_t)kdb_frame + (uintptr_t)vp->valuep);
89         if (op == DB_VAR_GET)
90                 *valuep = *reg;
91         else
92                 *reg = *valuep;
93         return (1);
94 }
95
96 /*
97  * User stack trace (debugging aid).
98  */
99 static void
100 db_utrace(struct thread *td, struct trapframe *tf, int count)
101 {
102         struct pcb *pcb;
103         db_addr_t sp, rsp, o7, pc;
104         int i, found;
105
106         pcb = td->td_pcb;
107         sp = db_get_value((db_addr_t)&tf->tf_sp, sizeof(tf->tf_sp), FALSE);
108         o7 = db_get_value((db_addr_t)&tf->tf_out[7], sizeof(tf->tf_out[7]),
109             FALSE);
110         pc = db_get_value((db_addr_t)&tf->tf_tpc, sizeof(tf->tf_tpc), FALSE);
111         db_printf("user trace: trap %%o7=%#lx\n", o7);
112         while (count-- && sp != 0 && !db_pager_quit) {
113                 db_printf("pc %#lx, sp %#lx\n", pc, sp);
114                 /* First, check whether the frame is in the pcb. */
115                 found = 0;
116                 for (i = 0; i < pcb->pcb_nsaved; i++) {
117                         if (pcb->pcb_rwsp[i] == sp) {
118                                 found = 1;
119                                 sp = pcb->pcb_rw[i].rw_in[6];
120                                 pc = pcb->pcb_rw[i].rw_in[7];
121                                 break;
122                         }
123                 }
124                 if (!found) {
125                         rsp = sp + SPOFF;
126                         sp = 0;
127                         if (copyin((void *)(rsp + offsetof(struct frame, fr_fp)),
128                             &sp, sizeof(sp)) != 0 ||
129                             copyin((void *)(rsp + offsetof(struct frame, fr_pc)),
130                             &pc, sizeof(pc)) != 0)
131                                 break;
132                 }
133         }
134         db_printf("done\n");
135 }
136
137 static int
138 db_print_trap(struct thread *td, struct trapframe *tf, int count)
139 {
140         struct proc *p;
141         const char *symname;
142         c_db_sym_t sym;
143         db_expr_t diff;
144         db_addr_t func;
145         db_addr_t tpc;
146         u_long type;
147         u_long sfar;
148         u_long sfsr;
149         u_long tar;
150         u_long level;
151         u_long pil;
152         u_long code;
153         u_long o7;
154         int user;
155
156         p = td->td_proc;
157         type = db_get_value((db_addr_t)&tf->tf_type,
158             sizeof(tf->tf_type), FALSE);
159         db_printf("-- %s", trap_msg[type & ~T_KERNEL]);
160         switch (type & ~T_KERNEL) {
161         case T_DATA_PROTECTION:
162                 tar = (u_long)db_get_value((db_addr_t)&tf->tf_tar,
163                     sizeof(tf->tf_tar), FALSE);
164                 db_printf(" tar=%#lx", tar);
165                 /* fall through */
166         case T_DATA_EXCEPTION:
167         case T_INSTRUCTION_EXCEPTION:
168         case T_MEM_ADDRESS_NOT_ALIGNED:
169                 sfar = (u_long)db_get_value((db_addr_t)&tf->tf_sfar,
170                     sizeof(tf->tf_sfar), FALSE);
171                 sfsr = (u_long)db_get_value((db_addr_t)&tf->tf_sfsr,
172                     sizeof(tf->tf_sfsr), FALSE);
173                 db_printf(" sfar=%#lx sfsr=%#lx", sfar, sfsr);
174                 break;
175         case T_DATA_MISS:
176         case T_INSTRUCTION_MISS:
177                 tar = (u_long)db_get_value((db_addr_t)&tf->tf_tar,
178                     sizeof(tf->tf_tar), FALSE);
179                 db_printf(" tar=%#lx", tar);
180                 break;
181         case T_SYSCALL:
182                 code = db_get_value((db_addr_t)&tf->tf_global[1],
183                     sizeof(tf->tf_global[1]), FALSE);
184                 db_printf(" (%ld", code);
185                 if (code >= 0 && code < p->p_sysent->sv_size) {
186                         func = (db_addr_t)p->p_sysent->sv_table[code].sy_call;
187                         sym = db_search_symbol(func, DB_STGY_ANY, &diff);
188                         if (sym != DB_SYM_NULL && diff == 0) {
189                                 db_symbol_values(sym, &symname, NULL);
190                                 db_printf(", %s, %s", p->p_sysent->sv_name,
191                                     symname);
192                         }
193                         db_printf(")");
194                 }
195                 break;
196         case T_INTERRUPT:
197                 level = (u_long)db_get_value((db_addr_t)&tf->tf_level,
198                     sizeof(tf->tf_level), FALSE);
199                 pil = (u_long)db_get_value((db_addr_t)&tf->tf_pil,
200                     sizeof(tf->tf_pil), FALSE);
201                 db_printf(" level=%#lx pil=%#lx", level, pil);
202                 break;
203         default:
204                 break;
205         }
206         o7 = (u_long)db_get_value((db_addr_t)&tf->tf_out[7],
207             sizeof(tf->tf_out[7]), FALSE);
208         db_printf(" %%o7=%#lx --\n", o7);
209         user = (type & T_KERNEL) == 0;
210         if (user) {
211                 tpc = db_get_value((db_addr_t)&tf->tf_tpc,
212                     sizeof(tf->tf_tpc), FALSE);
213                 db_printf("userland() at ");
214                 db_printsym(tpc, DB_STGY_PROC);
215                 db_printf("\n");
216                 db_utrace(td, tf, count);
217         }
218         return (user);
219 }
220
221 static int
222 db_backtrace(struct thread *td, struct frame *fp, int count)
223 {
224         struct trapframe *tf;
225         const char *name;
226         c_db_sym_t sym;
227         db_expr_t offset;
228         db_expr_t value;
229         db_addr_t npc;
230         db_addr_t pc;
231         int trap;
232         int user;
233
234         if (count == -1)
235                 count = 1024;
236
237         trap = 0;
238         user = 0;
239         npc = 0;
240         while (count-- && !user && !db_pager_quit) {
241                 pc = (db_addr_t)db_get_value((db_addr_t)&fp->fr_pc,
242                     sizeof(fp->fr_pc), FALSE);
243                 if (trap) {
244                         pc = npc;
245                         trap = 0;
246                 }
247                 if (!INKERNEL((vm_offset_t)pc))
248                         break;
249                 sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
250                 if (sym == C_DB_SYM_NULL) {
251                         value = 0;
252                         name = NULL;
253                 } else
254                         db_symbol_values(sym, &name, &value);
255                 if (name == NULL)
256                         name = "(null)";
257                 fp = (struct frame *)(db_get_value((db_addr_t)&fp->fr_fp,
258                    sizeof(fp->fr_fp), FALSE) + SPOFF);
259                 if ((value > (u_long)tl_trap_begin &&
260                     value < (u_long)tl_trap_end) ||
261                     (value > (u_long)tl_text_begin &&
262                     value < (u_long)tl_text_end)) {
263                         tf = (struct trapframe *)(fp + 1);
264                         npc = db_get_value((db_addr_t)&tf->tf_tpc,
265                             sizeof(tf->tf_tpc), FALSE);
266                         user = db_print_trap(td, tf, count);
267                         trap = 1;
268                 } else {
269                         db_printf("%s() at ", name);
270                         db_printsym(pc, DB_STGY_PROC);
271                         db_printf("\n");
272                 }
273         }
274         return (0);
275 }
276
277 void
278 db_trace_self(void)
279 {
280
281         db_backtrace(curthread,
282             (struct frame *)__builtin_frame_address(1), -1);
283 }
284
285 int
286 db_trace_thread(struct thread *td, int count)
287 {
288         struct pcb *ctx;
289
290         ctx = kdb_thr_ctx(td);
291         return (db_backtrace(td,
292             (struct frame *)(ctx->pcb_sp + SPOFF), count));
293 }