xref: /openbsd/sys/arch/sh/sh/db_interface.c (revision 949c1c4e)
1 /*	$OpenBSD: db_interface.c,v 1.16 2024/11/07 16:02:29 miod Exp $	*/
2 /*	$NetBSD: db_interface.c,v 1.37 2006/09/06 00:11:49 uwe Exp $	*/
3 
4 /*-
5  * Copyright (C) 2002 UCHIYAMA Yasushi.  All rights reserved.
6  * Copyright (c) 2000 Tsubai Masanari.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/proc.h>
34 #include <sys/user.h>
35 
36 #include <uvm/uvm_extern.h>
37 
38 #include <dev/cons.h>
39 
40 #include <machine/db_machdep.h>
41 #include <ddb/db_run.h>
42 #include <ddb/db_sym.h>
43 
44 #include <sh/ubcreg.h>
45 
46 db_regs_t ddb_regs;		/* register state */
47 
48 
49 #include <sh/cache.h>
50 #include <sh/cache_sh3.h>
51 #include <sh/cache_sh4.h>
52 #include <sh/mmu.h>
53 #include <sh/mmu_sh3.h>
54 #include <sh/mmu_sh4.h>
55 
56 #include <ddb/db_command.h>
57 #include <ddb/db_extern.h>
58 #include <ddb/db_output.h>
59 #include <ddb/db_var.h>
60 
61 void kdb_printtrap(u_int, int);
62 
63 void db_tlbdump_cmd(db_expr_t, int, db_expr_t, char *);
64 void __db_tlbdump_page_size_sh4(uint32_t);
65 void __db_tlbdump_pfn(uint32_t);
66 void db_cachedump_cmd(db_expr_t, int, db_expr_t, char *);
67 
68 void __db_cachedump_sh3(vaddr_t);
69 void __db_cachedump_sh4(vaddr_t);
70 
71 void db_stackcheck_cmd(db_expr_t, int, db_expr_t, char *);
72 void db_frame_cmd(db_expr_t, int, db_expr_t, char *);
73 void __db_print_symbol(db_expr_t);
74 char *__db_procname_by_asid(int);
75 
76 const struct db_command db_machine_command_table[] = {
77 	{ "tlb",	db_tlbdump_cmd,		0,	NULL },
78 	{ "cache",	db_cachedump_cmd,	0,	NULL },
79 	{ "frame",	db_frame_cmd,		0,	NULL },
80 #ifdef KSTACK_DEBUG
81 	{ "stack",	db_stackcheck_cmd,	0,	NULL },
82 #endif
83 	{ NULL }
84 };
85 
86 void
db_machine_init(void)87 db_machine_init(void)
88 {
89 }
90 
91 void
kdb_printtrap(u_int type,int code)92 kdb_printtrap(u_int type, int code)
93 {
94 	int i;
95 	i = type >> 5;
96 
97 	db_printf("%s mode trap: ", type & 1 ? "user" : "kernel");
98 	if (i >= exp_types)
99 		db_printf("type 0x%03x", type & ~1);
100 	else
101 		db_printf("%s", exp_type[i]);
102 
103 	db_printf(" code = 0x%x\n", code);
104 }
105 
106 int
db_ktrap(int type,int code,db_regs_t * regs)107 db_ktrap(int type, int code, db_regs_t *regs)
108 {
109 	extern label_t *db_recover;
110 	int s;
111 
112 	switch (type) {
113 	case EXPEVT_TRAPA:	/* trapa instruction */
114 	case EXPEVT_BREAK:	/* UBC */
115 	case -1:		/* keyboard interrupt */
116 		break;
117 	default:
118 		if (!db_panic && db_recover == NULL)
119 			return 0;
120 
121 		kdb_printtrap(type, code);
122 		if (db_recover != NULL) {
123 			db_error("Faulted in DDB; continuing...\n");
124 			/*NOTREACHED*/
125 		}
126 	}
127 
128 	/* XXX Should switch to kdb's own stack here. */
129 
130 	ddb_regs = *regs;
131 
132 	s = splhigh();
133 	db_active++;
134 	cnpollc(1);
135 	db_trap(type, code);
136 	cnpollc(0);
137 	db_active--;
138 	splx(s);
139 
140 	*regs = ddb_regs;
141 
142 	return 1;
143 }
144 
145 void
db_enter(void)146 db_enter(void)
147 {
148 	__asm volatile("trapa %0" :: "i"(_SH_TRA_BREAK));
149 }
150 
151 #define	M_BSR	0xf000
152 #define	I_BSR	0xb000
153 #define	M_BSRF	0xf0ff
154 #define	I_BSRF	0x0003
155 #define	M_JSR	0xf0ff
156 #define	I_JSR	0x400b
157 #define	M_RTS	0xffff
158 #define	I_RTS	0x000b
159 #define	M_RTE	0xffff
160 #define	I_RTE	0x002b
161 
162 int
inst_call(int inst)163 inst_call(int inst)
164 {
165 #if _BYTE_ORDER == BIG_ENDIAN
166 	inst >>= 16;
167 #endif
168 	return (inst & M_BSR) == I_BSR || (inst & M_BSRF) == I_BSRF ||
169 	       (inst & M_JSR) == I_JSR;
170 }
171 
172 int
inst_return(int inst)173 inst_return(int inst)
174 {
175 #if _BYTE_ORDER == BIG_ENDIAN
176 	inst >>= 16;
177 #endif
178 	return (inst & M_RTS) == I_RTS;
179 }
180 
181 int
inst_trap_return(int inst)182 inst_trap_return(int inst)
183 {
184 #if _BYTE_ORDER == BIG_ENDIAN
185 	inst >>= 16;
186 #endif
187 	return (inst & M_RTE) == I_RTE;
188 }
189 
190 void
db_set_single_step(db_regs_t * regs)191 db_set_single_step(db_regs_t *regs)
192 {
193 
194 	_reg_write_2(SH_(BBRA), 0);		/* disable break */
195 	_reg_write_4(SH_(BARA), 0);		/* break address */
196 	_reg_write_1(SH_(BASRA), 0);		/* break ASID */
197 	_reg_write_1(SH_(BAMRA), 0x07);		/* break always */
198 	_reg_write_2(SH_(BRCR),  0x400);	/* break after each execution */
199 
200 	regs->tf_ubc = 0x0014;	/* will be written to BBRA */
201 }
202 
203 void
db_clear_single_step(db_regs_t * regs)204 db_clear_single_step(db_regs_t *regs)
205 {
206 
207 	regs->tf_ubc = 0;
208 }
209 
210 #define	ON(x, c)	((x) & (c) ? '|' : '.')
211 
212 /*
213  * MMU
214  */
215 void
db_tlbdump_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)216 db_tlbdump_cmd(db_expr_t addr, int have_addr, db_expr_t count,
217     char *modif)
218 {
219 	static const char *pr[] = { "_r", "_w", "rr", "ww" };
220 	static const char title[] =
221 	    "   VPN      ASID    PFN  AREA VDCGWtPR  SZ";
222 	static const char title2[] =
223 	    "          U/K                       U/K";
224 	uint32_t r, e;
225 	int i;
226 #ifdef SH3
227 	if (CPU_IS_SH3) {
228 		/* MMU configuration. */
229 		r = _reg_read_4(SH3_MMUCR);
230 		db_printf("%s-mode, %s virtual storage mode\n",
231 		    r & SH3_MMUCR_IX
232 		    ? "ASID + VPN" : "VPN only",
233 		    r & SH3_MMUCR_SV ? "single" : "multiple");
234 		i = _reg_read_4(SH3_PTEH) & SH3_PTEH_ASID_MASK;
235 		db_printf("ASID=%d (%s)", i, __db_procname_by_asid(i));
236 
237 		db_printf("---TLB DUMP---\n%s\n%s\n", title, title2);
238 		for (i = 0; i < SH3_MMU_WAY; i++) {
239 			db_printf(" [way %d]\n", i);
240 			for (e = 0; e < SH3_MMU_ENTRY; e++) {
241 				uint32_t a;
242 				/* address/data array common offset. */
243 				a = (e << SH3_MMU_VPN_SHIFT) |
244 				    (i << SH3_MMU_WAY_SHIFT);
245 
246 				r = _reg_read_4(SH3_MMUAA | a);
247 				if (r == 0) {
248 					db_printf("---------- - --- ----------"
249 					    " - ----x --  --\n");
250 				} else {
251 					vaddr_t va;
252 					int asid;
253 					asid = r & SH3_MMUAA_D_ASID_MASK;
254 					r &= SH3_MMUAA_D_VPN_MASK_1K;
255 					va = r | (e << SH3_MMU_VPN_SHIFT);
256 					db_printf("0x%08lx %c %3d", va,
257 					    (int)va < 0 ? 'K' : 'U', asid);
258 
259 					r = _reg_read_4(SH3_MMUDA | a);
260 					__db_tlbdump_pfn(r);
261 
262 					db_printf(" %c%c%c%cx %s %2dK\n",
263 					    ON(r, SH3_MMUDA_D_V),
264 					    ON(r, SH3_MMUDA_D_D),
265 					    ON(r, SH3_MMUDA_D_C),
266 					    ON(r, SH3_MMUDA_D_SH),
267 					    pr[(r & SH3_MMUDA_D_PR_MASK) >>
268 						SH3_MMUDA_D_PR_SHIFT],
269 					    r & SH3_MMUDA_D_SZ ? 4 : 1);
270 				}
271 			}
272 		}
273 	}
274 #endif /* SH3 */
275 #ifdef SH4
276 	if (CPU_IS_SH4) {
277 		/* MMU configuration */
278 		r = _reg_read_4(SH4_MMUCR);
279 		db_printf("%s virtual storage mode, SQ access: (kernel%s)\n",
280 		    r & SH3_MMUCR_SV ? "single" : "multiple",
281 		    r & SH4_MMUCR_SQMD ? "" : "/user");
282 		db_printf("random counter limit=%d\n",
283 		    (r & SH4_MMUCR_URB_MASK) >> SH4_MMUCR_URB_SHIFT);
284 
285 		i = _reg_read_4(SH4_PTEH) & SH4_PTEH_ASID_MASK;
286 		db_printf("ASID=%d (%s)", i, __db_procname_by_asid(i));
287 
288 		/* Dump ITLB */
289 		db_printf("---ITLB DUMP ---\n%s TC SA\n%s\n", title, title2);
290 		for (i = 0; i < 4; i++) {
291 			e = i << SH4_ITLB_E_SHIFT;
292 
293 			r = _reg_read_4(SH4_ITLB_AA | e);
294 			db_printf("0x%08x   %3d",
295 			    r & SH4_ITLB_AA_VPN_MASK,
296 			    r & SH4_ITLB_AA_ASID_MASK);
297 
298 			r = _reg_read_4(SH4_ITLB_DA1 | e);
299 			__db_tlbdump_pfn(r);
300 			db_printf(" %c_%c%c_ %s ",
301 			    ON(r, SH4_ITLB_DA1_V),
302 			    ON(r, SH4_ITLB_DA1_C),
303 			    ON(r, SH4_ITLB_DA1_SH),
304 			    pr[(r & SH4_ITLB_DA1_PR) >>
305 				SH4_UTLB_DA1_PR_SHIFT]);
306 			__db_tlbdump_page_size_sh4(r);
307 
308 #if 0 /* XXX: causes weird effects on landisk */
309 			r = _reg_read_4(SH4_ITLB_DA2 | e);
310 			db_printf(" %c  %d\n",
311 			    ON(r, SH4_ITLB_DA2_TC),
312 			    r & SH4_ITLB_DA2_SA_MASK);
313 #else
314 			db_printf("\n");
315 #endif
316 		}
317 
318 		/* Dump UTLB */
319 		db_printf("---UTLB DUMP---\n%s TC SA\n%s\n", title, title2);
320 		for (i = 0; i < 64; i++) {
321 			e = i << SH4_UTLB_E_SHIFT;
322 
323 			r = _reg_read_4(SH4_UTLB_AA | e);
324 			db_printf("0x%08x   %3d",
325 			    r & SH4_UTLB_AA_VPN_MASK,
326 			    r & SH4_UTLB_AA_ASID_MASK);
327 
328 			r = _reg_read_4(SH4_UTLB_DA1 | e);
329 			__db_tlbdump_pfn(r);
330 			db_printf(" %c%c%c%c%c %s ",
331 			    ON(r, SH4_UTLB_DA1_V),
332 			    ON(r, SH4_UTLB_DA1_D),
333 			    ON(r, SH4_UTLB_DA1_C),
334 			    ON(r, SH4_UTLB_DA1_SH),
335 			    ON(r, SH4_UTLB_DA1_WT),
336 			    pr[(r & SH4_UTLB_DA1_PR_MASK) >>
337 				SH4_UTLB_DA1_PR_SHIFT]
338 			    );
339 			__db_tlbdump_page_size_sh4(r);
340 
341 #if 0 /* XXX: causes weird effects on landisk */
342 			r = _reg_read_4(SH4_UTLB_DA2 | e);
343 			db_printf(" %c  %d\n",
344 			    ON(r, SH4_UTLB_DA2_TC),
345 			    r & SH4_UTLB_DA2_SA_MASK);
346 #else
347 			db_printf("\n");
348 #endif
349 		}
350 	}
351 #endif /* SH4 */
352 }
353 
354 void
__db_tlbdump_pfn(uint32_t r)355 __db_tlbdump_pfn(uint32_t r)
356 {
357 	uint32_t pa = (r & SH3_MMUDA_D_PPN_MASK);
358 
359 	db_printf(" 0x%08x %d", pa, (pa >> 26) & 7);
360 }
361 
362 char *
__db_procname_by_asid(int asid)363 __db_procname_by_asid(int asid)
364 {
365 	static char notfound[] = "---";
366 	struct process *pr;
367 
368 	LIST_FOREACH(pr, &allprocess, ps_list) {
369 		if (pr->ps_vmspace->vm_map.pmap->pm_asid == asid)
370 			return (pr->ps_comm);
371 	}
372 
373 	return (notfound);
374 }
375 
376 #ifdef SH4
377 void
__db_tlbdump_page_size_sh4(uint32_t r)378 __db_tlbdump_page_size_sh4(uint32_t r)
379 {
380 	switch (r & SH4_PTEL_SZ_MASK) {
381 	case SH4_PTEL_SZ_1K:
382 		db_printf(" 1K");
383 		break;
384 	case SH4_PTEL_SZ_4K:
385 		db_printf(" 4K");
386 		break;
387 	case SH4_PTEL_SZ_64K:
388 		db_printf("64K");
389 		break;
390 	case SH4_PTEL_SZ_1M:
391 		db_printf(" 1M");
392 		break;
393 	}
394 }
395 #endif /* SH4 */
396 
397 /*
398  * CACHE
399  */
400 void
db_cachedump_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)401 db_cachedump_cmd(db_expr_t addr, int have_addr, db_expr_t count,
402     char *modif)
403 {
404 #ifdef SH3
405 	if (CPU_IS_SH3)
406 		__db_cachedump_sh3(have_addr ? addr : 0);
407 #endif
408 #ifdef SH4
409 	if (CPU_IS_SH4)
410 		__db_cachedump_sh4(have_addr ? addr : 0);
411 #endif
412 }
413 
414 #ifdef SH3
415 void
__db_cachedump_sh3(vaddr_t va_start)416 __db_cachedump_sh3(vaddr_t va_start)
417 {
418 	uint32_t r;
419 	vaddr_t va, va_end, cca;
420 	int entry, way;
421 
422 	RUN_P2;
423 	/* disable cache */
424 	_reg_write_4(SH3_CCR,
425 	    _reg_read_4(SH3_CCR) & ~SH3_CCR_CE);
426 
427 	if (va_start) {
428 		va = va_start & ~(sh_cache_line_size - 1);
429 		va_end = va + sh_cache_line_size;
430 	} else {
431 		va = 0;
432 		va_end = sh_cache_way_size;
433 	}
434 
435 	db_printf("%d-way, way-size=%dB, way-shift=%d, entry-mask=%08x, "
436 	    "line-size=%dB \n", sh_cache_ways, sh_cache_way_size,
437 	    sh_cache_way_shift, sh_cache_entry_mask, sh_cache_line_size);
438 	db_printf("Entry  Way 0  UV   Way 1  UV   Way 2  UV   Way 3  UV\n");
439 	for (; va < va_end; va += sh_cache_line_size) {
440 		entry = va & sh_cache_entry_mask;
441 		cca = SH3_CCA | entry;
442 		db_printf(" %3d ", entry >> CCA_ENTRY_SHIFT);
443 		for (way = 0; way < sh_cache_ways; way++) {
444 			r = _reg_read_4(cca | (way << sh_cache_way_shift));
445 			db_printf("%08x %c%c ", r & CCA_TAGADDR_MASK,
446 			    ON(r, CCA_U), ON(r, CCA_V));
447 		}
448 		db_printf("\n");
449 	}
450 
451 	/* enable cache */
452 	_reg_bset_4(SH3_CCR, SH3_CCR_CE);
453 	sh_icache_sync_all();
454 
455 	RUN_P1;
456 }
457 #endif /* SH3 */
458 
459 #ifdef SH4
460 void
__db_cachedump_sh4(vaddr_t va)461 __db_cachedump_sh4(vaddr_t va)
462 {
463 	uint32_t r, e;
464 	int i, istart, iend;
465 
466 	RUN_P2; /* must access from P2 */
467 
468 	/* disable I/D-cache */
469 	_reg_write_4(SH4_CCR,
470 	    _reg_read_4(SH4_CCR) & ~(SH4_CCR_ICE | SH4_CCR_OCE));
471 
472 	if (va) {
473 		istart = ((va & CCIA_ENTRY_MASK) >> CCIA_ENTRY_SHIFT) & ~3;
474 		iend = istart + 4;
475 	} else {
476 		istart = 0;
477 		iend = SH4_ICACHE_SIZE / SH4_CACHE_LINESZ;
478 	}
479 
480 	db_printf("[I-cache]\n");
481 	db_printf("  Entry             V           V           V           V\n");
482 	for (i = istart; i < iend; i++) {
483 		if ((i & 3) == 0)
484 			db_printf("\n[%3d-%3d] ", i, i + 3);
485 		r = _reg_read_4(SH4_CCIA | (i << CCIA_ENTRY_SHIFT));
486 		db_printf("%08x _%c ", r & CCIA_TAGADDR_MASK, ON(r, CCIA_V));
487 	}
488 
489 	db_printf("\n[D-cache]\n");
490 	db_printf("  Entry            UV          UV          UV          UV\n");
491 	for (i = istart; i < iend; i++) {
492 		if ((i & 3) == 0)
493 			db_printf("\n[%3d-%3d] ", i, i + 3);
494 		e = (i << CCDA_ENTRY_SHIFT);
495 		r = _reg_read_4(SH4_CCDA | e);
496 		db_printf("%08x %c%c ", r & CCDA_TAGADDR_MASK, ON(r, CCDA_U),
497 		    ON(r, CCDA_V));
498 
499 	}
500 	db_printf("\n");
501 
502 	_reg_write_4(SH4_CCR,
503 	    _reg_read_4(SH4_CCR) | SH4_CCR_ICE | SH4_CCR_OCE);
504 	sh_icache_sync_all();
505 
506 	RUN_P1;
507 }
508 #endif /* SH4 */
509 
510 #undef ON
511 
512 void
db_frame_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)513 db_frame_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
514 {
515 	struct switchframe *sf = &curpcb->pcb_sf;
516 	struct trapframe *tf, *tftop;
517 
518 	/* Print switch frame */
519 	db_printf("[switch frame]\n");
520 
521 #define	SF(x)	db_printf("sf_" #x "\t\t0x%08x\t", sf->sf_ ## x);	\
522 		__db_print_symbol(sf->sf_ ## x)
523 
524 	SF(sr);
525 	SF(r15);
526 	SF(r14);
527 	SF(r13);
528 	SF(r12);
529 	SF(r11);
530 	SF(r10);
531 	SF(r9);
532 	SF(r8);
533 	SF(pr);
534 	db_printf("sf_r6_bank\t0x%08x\n", sf->sf_r6_bank);
535 	db_printf("sf_r7_bank\t0x%08x\n", sf->sf_r7_bank);
536 
537 
538 	/* Print trap frame stack */
539 	db_printf("[trap frame]\n");
540 
541 	__asm("stc r6_bank, %0" : "=r"(tf));
542 	tftop = (struct trapframe *)((vaddr_t)curpcb + PAGE_SIZE);
543 
544 	for (; tf != tftop; tf++) {
545 		db_printf("-- %p-%p --\n", tf, tf + 1);
546 		db_printf("tf_expevt\t0x%08x\n", tf->tf_expevt);
547 
548 #define	TF(x)	db_printf("tf_" #x "\t\t0x%08x\t", tf->tf_ ## x);	\
549 		__db_print_symbol(tf->tf_ ## x)
550 
551 		TF(ubc);
552 		TF(spc);
553 		TF(ssr);
554 		TF(gbr);
555 		TF(macl);
556 		TF(mach);
557 		TF(pr);
558 		TF(r13);
559 		TF(r12);
560 		TF(r11);
561 		TF(r10);
562 		TF(r9);
563 		TF(r8);
564 		TF(r7);
565 		TF(r6);
566 		TF(r5);
567 		TF(r4);
568 		TF(r3);
569 		TF(r2);
570 		TF(r1);
571 		TF(r0);
572 		TF(r15);
573 		TF(r14);
574 	}
575 #undef	SF
576 #undef	TF
577 }
578 
579 void
__db_print_symbol(db_expr_t value)580 __db_print_symbol(db_expr_t value)
581 {
582 	const char *name;
583 	db_expr_t offset;
584 
585 	db_find_sym_and_offset((vaddr_t)value, &name, &offset);
586 	if (name != NULL && offset <= db_maxoff && offset != value)
587 		db_printsym(value, DB_STGY_ANY, db_printf);
588 
589 	db_printf("\n");
590 }
591 
592 #ifdef KSTACK_DEBUG
593 /*
594  * Stack overflow check
595  */
596 void
db_stackcheck_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)597 db_stackcheck_cmd(db_expr_t addr, int have_addr, db_expr_t count,
598 		  char *modif)
599 {
600 	struct proc *p;
601 	struct user *u;
602 	struct pcb *pcb;
603 	uint32_t *t32;
604 	uint8_t *t8;
605 	int i, j;
606 
607 #define	MAX_STACK	(USPACE - PAGE_SIZE)
608 #define	MAX_FRAME	(PAGE_SIZE - sizeof(struct user))
609 
610 	db_printf("stack max: %d byte, frame max %d byte,"
611 	    " sizeof(struct trapframe) %d byte\n", MAX_STACK, MAX_FRAME,
612 	    sizeof(struct trapframe));
613 	db_printf("   PID.LID    "
614 		  "stack top    max used    frame top     max used"
615 		  "  nest\n");
616 
617 	LIST_FOREACH(p, &allproc, p_list) {
618 		u = p->p_addr;
619 		pcb = &u->u_pcb;
620 		/* stack */
621 		t32 = (uint32_t *)(pcb->pcb_sf.sf_r7_bank - MAX_STACK);
622 		for (i = 0; *t32++ == 0xa5a5a5a5; i++)
623 			continue;
624 		i = MAX_STACK - i * sizeof(int);
625 
626 		/* frame */
627 		t8 = (uint8_t *)((vaddr_t)pcb + PAGE_SIZE - MAX_FRAME);
628 		for (j = 0; *t8++ == 0x5a; j++)
629 			continue;
630 		j = MAX_FRAME - j;
631 
632 		db_printf("%6d 0x%08x %6d (%3d%%) 0x%08lx %6d (%3d%%) %d %s\n",
633 		    p->p_lid,
634 		    pcb->pcb_sf.sf_r7_bank, i, i * 100 / MAX_STACK,
635 		    (vaddr_t)pcb + PAGE_SIZE, j, j * 100 / MAX_FRAME,
636 		    j / sizeof(struct trapframe),
637 		    p->p_p->ps_comm);
638 	}
639 #undef	MAX_STACK
640 #undef	MAX_FRAME
641 }
642 #endif /* KSTACK_DEBUG */
643