xref: /netbsd-src/sys/arch/sparc/sparc/db_interface.c (revision 1f143d9abb3b7bd0463dc7c8e080311d3cef6fcd)
1 /*	$NetBSD: db_interface.c,v 1.98 2023/10/26 10:41:03 andvar Exp $ */
2 
3 /*
4  * Mach Operating System
5  * Copyright (c) 1991,1990 Carnegie Mellon University
6  * All Rights Reserved.
7  *
8  * Permission to use, copy, modify and distribute this software and its
9  * documentation is hereby granted, provided that both the copyright
10  * notice and this permission notice appear in all copies of the
11  * software, derivative works or modified versions, and any portions
12  * thereof, and that both notices appear in supporting documentation.
13  *
14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17  *
18  * Carnegie Mellon requests users of this software to return to
19  *
20  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
21  *  School of Computer Science
22  *  Carnegie Mellon University
23  *  Pittsburgh PA 15213-3890
24  *
25  * any improvements or extensions that they make and grant Carnegie the
26  * rights to redistribute these changes.
27  *
28  *	From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
29  */
30 
31 /*
32  * Interface to new debugger.
33  */
34 
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.98 2023/10/26 10:41:03 andvar Exp $");
37 
38 #ifdef _KERNEL_OPT
39 #include "opt_ddb.h"
40 #include "opt_kgdb.h"
41 #include "opt_multiprocessor.h"
42 #endif
43 
44 #include <sys/param.h>
45 #include <sys/proc.h>
46 #include <sys/cpu.h>
47 #include <sys/reboot.h>
48 #include <sys/systm.h>
49 #include <sys/lwp.h>
50 
51 #include <dev/cons.h>
52 
53 #include <uvm/uvm.h>
54 
55 #include <machine/db_machdep.h>
56 #include <machine/locore.h>
57 
58 #include <ddb/db_access.h>
59 #include <ddb/db_active.h>
60 #include <ddb/ddbvar.h>
61 
62 #if defined(DDB) || defined(_KMEMUSER)
63 #include <ddb/db_user.h>
64 #include <ddb/db_command.h>
65 #include <ddb/db_sym.h>
66 #include <ddb/db_variables.h>
67 #include <ddb/db_extern.h>
68 #include <ddb/db_output.h>
69 #include <ddb/db_interface.h>
70 #endif
71 #ifdef KGDB
72 #include <ddb/db_interface.h>
73 #endif
74 
75 #include <machine/instr.h>
76 #if defined(_KERNEL)
77 #include <machine/promlib.h>
78 #endif
79 #include <machine/ctlreg.h>
80 #include <machine/pmap.h>
81 
82 #if defined(_KERNEL)
83 #include <sparc/sparc/asm.h>
84 
85 #include "fb.h"
86 
87 /*
88  * Read bytes from kernel address space for debugger.
89  */
90 void
db_read_bytes(vaddr_t addr,size_t size,char * data)91 db_read_bytes(vaddr_t addr, size_t size, char *data)
92 {
93 	char	*src;
94 
95 	src = (char *)addr;
96 	while (size-- > 0)
97 		*data++ = *src++;
98 }
99 
100 /*
101  * Write bytes to kernel address space for debugger.
102  */
103 void
db_write_bytes(vaddr_t addr,size_t size,const char * data)104 db_write_bytes(vaddr_t addr, size_t size, const char *data)
105 {
106 	char	*dst;
107 
108 	dst = (char *)addr;
109 	while (size-- > 0) {
110 		if ((dst >= (char *)VM_MIN_KERNEL_ADDRESS) && (dst < etext))
111 			pmap_writetext(dst, *data);
112 		else
113 			*dst = *data;
114 		dst++, data++;
115 	}
116 
117 }
118 #endif
119 
120 #if defined(DDB)
121 
122 /*
123  * Data and functions used by DDB only.
124  */
125 
126 void
cpu_Debugger(void)127 cpu_Debugger(void)
128 {
129 	__asm("ta 0x81");
130 	sparc_noop();	/* Force this function to allocate a stack frame */
131 }
132 
133 #endif /* DDB */
134 
135 #if defined(DDB) || defined(_KMEMUSER)
136 
137 int	db_active = 0;
138 
139 #ifdef _KERNEL
140 void kdb_kbd_trap(struct trapframe *);
141 void db_prom_cmd(db_expr_t, bool, db_expr_t, const char *);
142 void db_page_cmd(db_expr_t, bool, db_expr_t, const char *);
143 void db_proc_cmd(db_expr_t, bool, db_expr_t, const char *);
144 void db_dump_pcb(db_expr_t, bool, db_expr_t, const char *);
145 #endif
146 #ifdef MULTIPROCESSOR
147 void db_cpu_cmd(db_expr_t, bool, db_expr_t, const char *);
148 void db_xcall_cmd(db_expr_t, bool, db_expr_t, const char *);
149 #endif
150 
151 #ifdef _KERNEL
152 /*
153  * Received keyboard interrupt sequence.
154  */
155 void
kdb_kbd_trap(struct trapframe * tf)156 kdb_kbd_trap(struct trapframe *tf)
157 {
158 	if (db_active == 0 && (boothowto & RB_KDB)) {
159 		printf("\n\nkernel: keyboard interrupt\n");
160 		kdb_trap(-1, tf);
161 	}
162 }
163 #endif
164 
165 /* struct cpu_info of CPU being investigated */
166 struct cpu_info *ddb_cpuinfo;
167 
168 #ifdef MULTIPROCESSOR
169 
170 #define NOCPU -1
171 
172 static int db_suspend_others(void);
173 static void db_resume_others(void);
174 void ddb_suspend(struct trapframe *);
175 
176 /* from cpu.c */
177 void mp_pause_cpus_ddb(void);
178 void mp_resume_cpus_ddb(void);
179 
180 __cpu_simple_lock_t db_lock;
181 int ddb_cpu = NOCPU;
182 
183 static int
db_suspend_others(void)184 db_suspend_others(void)
185 {
186 	int cpu_me = cpu_number();
187 	int win;
188 
189 	__cpu_simple_lock(&db_lock);
190 	if (ddb_cpu == NOCPU)
191 		ddb_cpu = cpu_me;
192 	win = (ddb_cpu == cpu_me);
193 	__cpu_simple_unlock(&db_lock);
194 
195 	if (win)
196 		mp_pause_cpus_ddb();
197 
198 	return win;
199 }
200 
201 static void
db_resume_others(void)202 db_resume_others(void)
203 {
204 
205 	mp_resume_cpus_ddb();
206 
207 	__cpu_simple_lock(&db_lock);
208 	ddb_cpu = NOCPU;
209 	__cpu_simple_unlock(&db_lock);
210 }
211 
212 void
ddb_suspend(struct trapframe * tf)213 ddb_suspend(struct trapframe *tf)
214 {
215 	volatile db_regs_t dbregs;
216 
217 	/* Initialise local dbregs storage from trap frame */
218 	dbregs.db_tf = *tf;
219 	dbregs.db_fr = *(struct frame *)tf->tf_out[6];
220 
221 	cpuinfo.ci_ddb_regs = &dbregs;
222 	while (cpuinfo.flags & CPUFLG_PAUSED) /*void*/;
223 	cpuinfo.ci_ddb_regs = NULL;
224 }
225 #endif /* MULTIPROCESSOR */
226 
227 #if defined(DDB) || defined(KGDB)
228 /*
229  *  kdb_trap - field a TRACE or BPT trap
230  */
231 int
kdb_trap(int type,struct trapframe * tf)232 kdb_trap(int type, struct trapframe *tf)
233 {
234 	db_regs_t dbregs;
235 	int s;
236 
237 #if NFB > 0
238 	fb_unblank();
239 #endif
240 
241 	switch (type) {
242 	case T_BREAKPOINT:	/* breakpoint */
243 	case -1:		/* keyboard interrupt */
244 		break;
245 	default:
246 		if (!db_onpanic && db_recover==0)
247 			return (0);
248 
249 		printf("kernel: %s trap\n", trap_type[type & 0xff]);
250 		if (db_recover != 0) {
251 			db_error("Faulted in DDB; continuing...\n");
252 			/*NOTREACHED*/
253 		}
254 	}
255 
256 #ifdef MULTIPROCESSOR
257 	if (!db_suspend_others()) {
258 		ddb_suspend(tf);
259 		return 1;
260 	}
261 #endif
262 	/* Initialise local dbregs storage from trap frame */
263 	dbregs.db_tf = *tf;
264 	dbregs.db_fr = *(struct frame *)tf->tf_out[6];
265 
266 	/* Setup current CPU & reg pointers */
267 	ddb_cpuinfo = curcpu();
268 	curcpu()->ci_ddb_regs = ddb_regp = &dbregs;
269 
270 	/* Should switch to kdb`s own stack here. */
271 
272 	s = splhigh();
273 	db_active++;
274 	cnpollc(true);
275 	db_trap(type, 0/*code*/);
276 	cnpollc(false);
277 	db_active--;
278 	splx(s);
279 
280 	/* Update trap frame from local dbregs storage */
281 	*(struct frame *)tf->tf_out[6] = dbregs.db_fr;
282 	*tf = dbregs.db_tf;
283 	curcpu()->ci_ddb_regs = ddb_regp = 0;
284 	ddb_cpuinfo = NULL;
285 
286 #ifdef MULTIPROCESSOR
287 	db_resume_others();
288 #endif
289 
290 	return (1);
291 }
292 #endif /* DDB || KGDB */
293 
294 #ifdef _KERNEL
295 void
db_proc_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)296 db_proc_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
297 {
298 	struct lwp *l;
299 	struct proc *p;
300 
301 	l = curlwp;
302 	if (have_addr)
303 		l = (struct lwp *) addr;
304 
305 	if (l == NULL) {
306 		db_printf("no current process\n");
307 		return;
308 	}
309 
310 	p = l->l_proc;
311 
312 	db_printf("LWP %p: ", l);
313 	db_printf("PID:%d.%d CPU:%d stat:%d vmspace:%p", p->p_pid,
314 	    l->l_lid, l->l_cpu->ci_cpuid, l->l_stat, p->p_vmspace);
315 	if (!P_ZOMBIE(p))
316 		db_printf(" ctx: %p cpuset %x",
317 			  p->p_vmspace->vm_map.pmap->pm_ctx,
318 			  p->p_vmspace->vm_map.pmap->pm_cpuset);
319 	db_printf("\npmap:%p wchan:%p pri:%d epri:%d\n",
320 		  p->p_vmspace->vm_map.pmap,
321 		  l->l_wchan, l->l_priority, lwp_eprio(l));
322 	db_printf("maxsaddr:%p ssiz:%d pg or %llxB\n",
323 		  p->p_vmspace->vm_maxsaddr, p->p_vmspace->vm_ssize,
324 		  (unsigned long long)ctob(p->p_vmspace->vm_ssize));
325 	db_printf("profile timer: %lld sec %ld nsec\n",
326 		  p->p_stats->p_timer[ITIMER_PROF].it_value.tv_sec,
327 		  p->p_stats->p_timer[ITIMER_PROF].it_value.tv_nsec);
328 	db_printf("pcb: %p\n", lwp_getpcb(l));
329 	return;
330 }
331 
332 void
db_dump_pcb(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)333 db_dump_pcb(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
334 {
335 	struct pcb *pcb;
336 	char bits[64];
337 	int i;
338 
339 	if (have_addr)
340 		pcb = (struct pcb *) addr;
341 	else
342 		pcb = curcpu()->curpcb;
343 
344 	snprintb(bits, sizeof(bits), PSR_BITS, pcb->pcb_psr);
345 	db_printf("pcb@%p sp:%p pc:%p psr:%s onfault:%p\nfull windows:\n",
346 		  pcb, (void *)(long)pcb->pcb_sp, (void *)(long)pcb->pcb_pc,
347 		  bits, (void *)pcb->pcb_onfault);
348 
349 	for (i=0; i<pcb->pcb_nsaved; i++) {
350 		db_printf("win %d: at %llx local, in\n", i,
351 			  (unsigned long long)pcb->pcb_rw[i+1].rw_in[6]);
352 		db_printf("%16llx %16llx %16llx %16llx\n",
353 			  (unsigned long long)pcb->pcb_rw[i].rw_local[0],
354 			  (unsigned long long)pcb->pcb_rw[i].rw_local[1],
355 			  (unsigned long long)pcb->pcb_rw[i].rw_local[2],
356 			  (unsigned long long)pcb->pcb_rw[i].rw_local[3]);
357 		db_printf("%16llx %16llx %16llx %16llx\n",
358 			  (unsigned long long)pcb->pcb_rw[i].rw_local[4],
359 			  (unsigned long long)pcb->pcb_rw[i].rw_local[5],
360 			  (unsigned long long)pcb->pcb_rw[i].rw_local[6],
361 			  (unsigned long long)pcb->pcb_rw[i].rw_local[7]);
362 		db_printf("%16llx %16llx %16llx %16llx\n",
363 			  (unsigned long long)pcb->pcb_rw[i].rw_in[0],
364 			  (unsigned long long)pcb->pcb_rw[i].rw_in[1],
365 			  (unsigned long long)pcb->pcb_rw[i].rw_in[2],
366 			  (unsigned long long)pcb->pcb_rw[i].rw_in[3]);
367 		db_printf("%16llx %16llx %16llx %16llx\n",
368 			  (unsigned long long)pcb->pcb_rw[i].rw_in[4],
369 			  (unsigned long long)pcb->pcb_rw[i].rw_in[5],
370 			  (unsigned long long)pcb->pcb_rw[i].rw_in[6],
371 			  (unsigned long long)pcb->pcb_rw[i].rw_in[7]);
372 	}
373 }
374 
375 void
db_prom_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)376 db_prom_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
377 {
378 
379 	prom_abort();
380 }
381 
382 void
db_page_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)383 db_page_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
384 {
385 
386 	if (!have_addr) {
387 		db_printf("Need paddr for page\n");
388 		return;
389 	}
390 
391 	db_printf("pa %llx pg %p\n", (unsigned long long)addr,
392 	    PHYS_TO_VM_PAGE(addr));
393 }
394 #endif /* _KERNEL */
395 
396 #if defined(MULTIPROCESSOR)
397 
398 void
db_cpu_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)399 db_cpu_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
400 {
401 	struct cpu_info *ci;
402 	if (!have_addr) {
403 		cpu_debug_dump();
404 		return;
405 	}
406 
407 	if ((addr < 0) || (addr >= sparc_ncpus)) {
408 		db_printf("%ld: CPU out of range\n", addr);
409 		return;
410 	}
411 	ci = cpus[addr];
412 	if (ci == NULL) {
413 		db_printf("CPU %ld not configured\n", addr);
414 		return;
415 	}
416 	if (ci != curcpu()) {
417 		if (!(ci->flags & CPUFLG_PAUSED)) {
418 			db_printf("CPU %ld not paused\n", addr);
419 			return;
420 		}
421 	}
422 	if (ci->ci_ddb_regs == 0) {
423 		db_printf("CPU %ld has no saved regs\n", addr);
424 		return;
425 	}
426 	db_printf("using CPU %ld", addr);
427 	ddb_regp = __UNVOLATILE(ci->ci_ddb_regs);
428 	ddb_cpuinfo = ci;
429 }
430 
431 void
db_xcall_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)432 db_xcall_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
433 {
434 	cpu_xcall_dump();
435 }
436 
437 #endif /* MULTIPROCESSOR */
438 
439 const struct db_command db_machine_command_table[] = {
440 #ifdef _KERNEL
441 	{ DDB_ADD_CMD("prom",	db_prom_cmd,	0,
442 	  "Enter the Sun PROM monitor.",NULL,NULL) },
443 	{ DDB_ADD_CMD("page",	db_page_cmd,	0,
444 	  "Display the address of a struct vm_page given a physical address",
445 	   "pa", "   pa:\tphysical address to look up") },
446 	{ DDB_ADD_CMD("proc",	db_proc_cmd,	0,
447 	  "Display some information about an LWP",
448 	  "[addr]","   addr:\tstruct lwp address (curlwp otherwise)") },
449 	{ DDB_ADD_CMD("pcb",	db_dump_pcb,	0,
450 	  "Display information about a struct pcb",
451 	  "[address]",
452 	  "   address:\tthe struct pcb to print (curpcb otherwise)") },
453 #endif
454 #ifdef MULTIPROCESSOR
455 	{ DDB_ADD_CMD("cpu",	db_cpu_cmd,	0,
456 	  "switch to another cpu's registers", "cpu-no", NULL) },
457 	{ DDB_ADD_CMD("xcall",	db_xcall_cmd,	0,
458 	  "show xcall information on all cpus", NULL, NULL) },
459 #endif
460 	{ DDB_END_CMD },
461 };
462 #endif /* DDB || _KMEMUSER */
463 
464 /*
465  * support for SOFTWARE_SSTEP:
466  * return the next pc if the given branch is taken.
467  *
468  * note: in the case of conditional branches with annul,
469  * this actually returns the next pc in the "not taken" path,
470  * but in that case next_instr_address() will return the
471  * next pc in the "taken" path.  so even tho the breakpoints
472  * are backwards, everything will still work, and the logic is
473  * much simpler this way.
474  */
475 db_addr_t
db_branch_taken(int inst,db_addr_t pc,db_regs_t * regs)476 db_branch_taken(int inst, db_addr_t pc, db_regs_t *regs)
477 {
478     union instr insn;
479     db_addr_t npc = ddb_regp->db_tf.tf_npc;
480 
481     insn.i_int = inst;
482 
483     /*
484      * if this is not an annulled conditional branch, the next pc is "npc".
485      */
486 
487     if (insn.i_any.i_op != IOP_OP2 || insn.i_branch.i_annul != 1)
488 	return npc;
489 
490     switch (insn.i_op2.i_op2) {
491       case IOP2_Bicc:
492       case IOP2_FBfcc:
493       case IOP2_BPcc:
494       case IOP2_FBPfcc:
495       case IOP2_CBccc:
496 	/* branch on some condition-code */
497 	switch (insn.i_branch.i_cond)
498 	{
499 	  case Icc_A: /* always */
500 	    return pc + ((inst << 10) >> 8);
501 
502 	  default: /* all other conditions */
503 	    return npc + 4;
504 	}
505 
506       case IOP2_BPr:
507 	/* branch on register, always conditional */
508 	return npc + 4;
509 
510       default:
511 	/* not a branch */
512 #ifdef _KERNEL
513 	panic("branch_taken() on non-branch");
514 #else
515 	printf("branch_taken() on non-branch\n");
516 	return 0;
517 #endif
518     }
519 }
520 
521 bool
db_inst_branch(int inst)522 db_inst_branch(int inst)
523 {
524     union instr insn;
525 
526     insn.i_int = inst;
527 
528     if (insn.i_any.i_op != IOP_OP2)
529 	return false;
530 
531     switch (insn.i_op2.i_op2) {
532       case IOP2_BPcc:
533       case IOP2_Bicc:
534       case IOP2_BPr:
535       case IOP2_FBPfcc:
536       case IOP2_FBfcc:
537       case IOP2_CBccc:
538 	return true;
539 
540       default:
541 	return false;
542     }
543 }
544 
545 
546 bool
db_inst_call(int inst)547 db_inst_call(int inst)
548 {
549     union instr insn;
550 
551     insn.i_int = inst;
552 
553     switch (insn.i_any.i_op) {
554       case IOP_CALL:
555 	return true;
556 
557       case IOP_reg:
558 	return (insn.i_op3.i_op3 == IOP3_JMPL) && !db_inst_return(inst);
559 
560       default:
561 	return false;
562     }
563 }
564 
565 
566 bool
db_inst_unconditional_flow_transfer(int inst)567 db_inst_unconditional_flow_transfer(int inst)
568 {
569     union instr insn;
570 
571     insn.i_int = inst;
572 
573     if (db_inst_call(inst))
574 	return true;
575 
576     if (insn.i_any.i_op != IOP_OP2)
577 	return false;
578 
579     switch (insn.i_op2.i_op2)
580     {
581       case IOP2_BPcc:
582       case IOP2_Bicc:
583       case IOP2_FBPfcc:
584       case IOP2_FBfcc:
585       case IOP2_CBccc:
586 	return insn.i_branch.i_cond == Icc_A;
587 
588       default:
589 	return false;
590     }
591 }
592 
593 
594 bool
db_inst_return(int inst)595 db_inst_return(int inst)
596 {
597 
598     return (inst == I_JMPLri(I_G0, I_O7, 8) ||		/* ret */
599 	    inst == I_JMPLri(I_G0, I_I7, 8));		/* retl */
600 }
601 
602 bool
db_inst_trap_return(int inst)603 db_inst_trap_return(int inst)
604 {
605     union instr insn;
606 
607     insn.i_int = inst;
608 
609     return (insn.i_any.i_op == IOP_reg &&
610 	    insn.i_op3.i_op3 == IOP3_RETT);
611 }
612 
613 
614 int
db_inst_load(int inst)615 db_inst_load(int inst)
616 {
617     union instr insn;
618 
619     insn.i_int = inst;
620 
621     if (insn.i_any.i_op != IOP_mem)
622 	return 0;
623 
624     switch (insn.i_op3.i_op3) {
625       case IOP3_LD:
626       case IOP3_LDUB:
627       case IOP3_LDUH:
628       case IOP3_LDD:
629       case IOP3_LDSB:
630       case IOP3_LDSH:
631       case IOP3_LDSTUB:
632       case IOP3_SWAP:
633       case IOP3_LDA:
634       case IOP3_LDUBA:
635       case IOP3_LDUHA:
636       case IOP3_LDDA:
637       case IOP3_LDSBA:
638       case IOP3_LDSHA:
639       case IOP3_LDSTUBA:
640       case IOP3_SWAPA:
641       case IOP3_LDF:
642       case IOP3_LDFSR:
643       case IOP3_LDDF:
644       case IOP3_LFC:
645       case IOP3_LDCSR:
646       case IOP3_LDDC:
647 	return 1;
648 
649       default:
650 	return 0;
651     }
652 }
653 
654 int
db_inst_store(int inst)655 db_inst_store(int inst)
656 {
657     union instr insn;
658 
659     insn.i_int = inst;
660 
661     if (insn.i_any.i_op != IOP_mem)
662 	return 0;
663 
664     switch (insn.i_op3.i_op3) {
665       case IOP3_ST:
666       case IOP3_STB:
667       case IOP3_STH:
668       case IOP3_STD:
669       case IOP3_LDSTUB:
670       case IOP3_SWAP:
671       case IOP3_STA:
672       case IOP3_STBA:
673       case IOP3_STHA:
674       case IOP3_STDA:
675       case IOP3_LDSTUBA:
676       case IOP3_SWAPA:
677       case IOP3_STF:
678       case IOP3_STFSR:
679       case IOP3_STDFQ:
680       case IOP3_STDF:
681       case IOP3_STC:
682       case IOP3_STCSR:
683       case IOP3_STDCQ:
684       case IOP3_STDC:
685 	return 1;
686 
687       default:
688 	return 0;
689     }
690 }
691