xref: /openbsd-src/sys/ddb/db_output.c (revision fb6263ddf34d243da9639bd6bfea2aaa57ced563)
1*fb6263ddSbluhm /*	$OpenBSD: db_output.c,v 1.37 2021/06/10 12:33:48 bluhm Exp $	*/
2d724e01aSderaadt /*	$NetBSD: db_output.c,v 1.13 1996/04/01 17:27:14 christos Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*
5df930be7Sderaadt  * Mach Operating System
6b2471a9dSmickey  * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
7df930be7Sderaadt  * All Rights Reserved.
8df930be7Sderaadt  *
9df930be7Sderaadt  * Permission to use, copy, modify and distribute this software and its
10df930be7Sderaadt  * documentation is hereby granted, provided that both the copyright
11df930be7Sderaadt  * notice and this permission notice appear in all copies of the
12df930be7Sderaadt  * software, derivative works or modified versions, and any portions
13df930be7Sderaadt  * thereof, and that both notices appear in supporting documentation.
14df930be7Sderaadt  *
15b2471a9dSmickey  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16df930be7Sderaadt  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17df930be7Sderaadt  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18df930be7Sderaadt  *
19df930be7Sderaadt  * Carnegie Mellon requests users of this software to return to
20df930be7Sderaadt  *
21df930be7Sderaadt  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22df930be7Sderaadt  *  School of Computer Science
23df930be7Sderaadt  *  Carnegie Mellon University
24df930be7Sderaadt  *  Pittsburgh PA 15213-3890
25df930be7Sderaadt  *
26b2471a9dSmickey  * any improvements or extensions that they make and grant Carnegie Mellon
27b2471a9dSmickey  * the rights to redistribute these changes.
28df930be7Sderaadt  */
29df930be7Sderaadt 
30df930be7Sderaadt /*
31df930be7Sderaadt  * Printf and character output for debugger.
32df930be7Sderaadt  */
33df930be7Sderaadt #include <sys/param.h>
34*fb6263ddSbluhm #include <sys/atomic.h>
357034f964Sespie #include <sys/stdarg.h>
36f3278312Smiod #include <sys/systm.h>
37c59fd4deSvisa #include <sys/stacktrace.h>
38df930be7Sderaadt 
393ed44a89Smickey #include <dev/cons.h>
403ed44a89Smickey 
413ed44a89Smickey #include <machine/db_machdep.h>
423ed44a89Smickey 
433ed44a89Smickey #include <ddb/db_command.h>
443ed44a89Smickey #include <ddb/db_output.h>
45bfc40b23Svisa #include <ddb/db_access.h>
463ed44a89Smickey #include <ddb/db_interface.h>
473ed44a89Smickey #include <ddb/db_sym.h>
489f62b74aSniklas #include <ddb/db_var.h>
493ed44a89Smickey 
50df930be7Sderaadt /*
51df930be7Sderaadt  *	Character output - tracks position in line.
52df930be7Sderaadt  *	To do this correctly, we should know how wide
53df930be7Sderaadt  *	the output device is - then we could zero
54df930be7Sderaadt  *	the line position when the output device wraps
55df930be7Sderaadt  *	around to the start of the next line.
56df930be7Sderaadt  *
57df930be7Sderaadt  *	Instead, we count the number of spaces printed
58df930be7Sderaadt  *	since the last printing character so that we
59df930be7Sderaadt  *	don't print trailing spaces.  This avoids most
60df930be7Sderaadt  *	of the wraparounds.
61df930be7Sderaadt  */
62df930be7Sderaadt 
63df930be7Sderaadt #ifndef	DB_MAX_LINE
64df930be7Sderaadt #define	DB_MAX_LINE		24	/* maximum line */
65df930be7Sderaadt #define DB_MAX_WIDTH		80	/* maximum width */
66d1dc9c34Sespie #endif	/* DB_MAX_LINE */
67df930be7Sderaadt 
68df930be7Sderaadt #define DB_MIN_MAX_WIDTH	20	/* minimum max width */
69df930be7Sderaadt #define DB_MIN_MAX_LINE		3	/* minimum max line */
70df930be7Sderaadt #define CTRL(c)			((c) & 0xff)
71df930be7Sderaadt 
72df930be7Sderaadt int	db_output_position = 0;		/* output column */
73df930be7Sderaadt int	db_output_line = 0;		/* output line number */
74df930be7Sderaadt int	db_last_non_space = 0;		/* last non-space character */
75df930be7Sderaadt int	db_tab_stop_width = 8;		/* how wide are tab stops? */
76df930be7Sderaadt #define	NEXT_TAB(i) \
77df930be7Sderaadt 	((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
78df930be7Sderaadt int	db_max_line = DB_MAX_LINE;	/* output max lines */
79df930be7Sderaadt int	db_max_width = DB_MAX_WIDTH;	/* output line width */
808d885340Smickey int	db_radix = 16;			/* output numbers radix */
81df930be7Sderaadt 
82c4071fd1Smillert static void db_more(void);
83df930be7Sderaadt 
84df930be7Sderaadt /*
85df930be7Sderaadt  * Force pending whitespace.
86df930be7Sderaadt  */
87df930be7Sderaadt void
db_force_whitespace(void)886ecb06d0Sjsg db_force_whitespace(void)
89df930be7Sderaadt {
906ecb06d0Sjsg 	int last_print, next_tab;
91df930be7Sderaadt 
92df930be7Sderaadt 	last_print = db_last_non_space;
93df930be7Sderaadt 	while (last_print < db_output_position) {
94df930be7Sderaadt 		next_tab = NEXT_TAB(last_print);
95df930be7Sderaadt 		if (next_tab <= db_output_position) {
96df930be7Sderaadt 			while (last_print < next_tab) { /* DON'T send a tab!!! */
97df930be7Sderaadt 				cnputc(' ');
98df930be7Sderaadt 				last_print++;
99df930be7Sderaadt 			}
1005abbae66Sderaadt 		} else {
101df930be7Sderaadt 			cnputc(' ');
102df930be7Sderaadt 			last_print++;
103df930be7Sderaadt 		}
104df930be7Sderaadt 	}
105df930be7Sderaadt 	db_last_non_space = db_output_position;
106df930be7Sderaadt }
107df930be7Sderaadt 
108df930be7Sderaadt static void
db_more(void)1096ecb06d0Sjsg db_more(void)
110df930be7Sderaadt {
1116ecb06d0Sjsg 	char *p;
112df930be7Sderaadt 	int quit_output = 0;
113df930be7Sderaadt 
114df930be7Sderaadt 	for (p = "--db_more--"; *p; p++)
115df930be7Sderaadt 		cnputc(*p);
116df930be7Sderaadt 	switch(cngetc()) {
117df930be7Sderaadt 	case ' ':
118df930be7Sderaadt 		db_output_line = 0;
119df930be7Sderaadt 		break;
120df930be7Sderaadt 	case 'q':
121df930be7Sderaadt 	case CTRL('c'):
122df930be7Sderaadt 		db_output_line = 0;
123df930be7Sderaadt 		quit_output = 1;
124df930be7Sderaadt 		break;
125df930be7Sderaadt 	default:
126df930be7Sderaadt 		db_output_line--;
127df930be7Sderaadt 		break;
128df930be7Sderaadt 	}
129df930be7Sderaadt 	p = "\b\b\b\b\b\b\b\b\b\b\b           \b\b\b\b\b\b\b\b\b\b\b";
130df930be7Sderaadt 	while (*p)
131df930be7Sderaadt 		cnputc(*p++);
132df930be7Sderaadt 	if (quit_output) {
133df930be7Sderaadt 		db_error(0);
134df930be7Sderaadt 		/* NOTREACHED */
135df930be7Sderaadt 	}
136df930be7Sderaadt }
137df930be7Sderaadt 
138df930be7Sderaadt /*
139df930be7Sderaadt  * Output character.  Buffer whitespace.
140df930be7Sderaadt  */
1413ed44a89Smickey void
db_putchar(int c)1426ecb06d0Sjsg db_putchar(int c)
143df930be7Sderaadt {
144df930be7Sderaadt 	if (db_max_line >= DB_MIN_MAX_LINE && db_output_line >= db_max_line-1)
145df930be7Sderaadt 		db_more();
146fd94ba3eSmiod 
147df930be7Sderaadt 	if (c > ' ' && c <= '~') {
148df930be7Sderaadt 		/*
149df930be7Sderaadt 		 * Printing character.
150df930be7Sderaadt 		 * If we have spaces to print, print them first.
151df930be7Sderaadt 		 * Use tabs if possible.
152df930be7Sderaadt 		 */
153df930be7Sderaadt 		db_force_whitespace();
154df930be7Sderaadt 		cnputc(c);
155df930be7Sderaadt 		db_output_position++;
1565abbae66Sderaadt 		if (db_max_width >= DB_MIN_MAX_WIDTH &&
1575abbae66Sderaadt 		    db_output_position >= db_max_width-1) {
158df930be7Sderaadt 			/* auto new line */
159df930be7Sderaadt 			cnputc('\n');
160df930be7Sderaadt 			db_output_position = 0;
161df930be7Sderaadt 			db_last_non_space = 0;
162df930be7Sderaadt 			db_output_line++;
163df930be7Sderaadt 		}
164df930be7Sderaadt 		db_last_non_space = db_output_position;
1655abbae66Sderaadt 	} else if (c == '\n') {
166df930be7Sderaadt 		/* Return */
167df930be7Sderaadt 		cnputc(c);
168df930be7Sderaadt 		db_output_position = 0;
169df930be7Sderaadt 		db_last_non_space = 0;
170df930be7Sderaadt 		db_output_line++;
1715abbae66Sderaadt 	} else if (c == '\t') {
172df930be7Sderaadt 		/* assume tabs every 8 positions */
173df930be7Sderaadt 		db_output_position = NEXT_TAB(db_output_position);
1745abbae66Sderaadt 	} else if (c == ' ') {
175df930be7Sderaadt 		/* space */
176df930be7Sderaadt 		db_output_position++;
1775abbae66Sderaadt 	} else if (c == '\007') {
178df930be7Sderaadt 		/* bell */
179df930be7Sderaadt 		cnputc(c);
180df930be7Sderaadt 	}
181df930be7Sderaadt 	/* other characters are assumed non-printing */
182df930be7Sderaadt }
183df930be7Sderaadt 
184df930be7Sderaadt /*
185df930be7Sderaadt  * Return output position
186df930be7Sderaadt  */
187df930be7Sderaadt int
db_print_position(void)1886ecb06d0Sjsg db_print_position(void)
189df930be7Sderaadt {
190df930be7Sderaadt 	return (db_output_position);
191df930be7Sderaadt }
192df930be7Sderaadt 
193df930be7Sderaadt /*
194df930be7Sderaadt  * End line if too long.
195df930be7Sderaadt  */
196df930be7Sderaadt void
db_end_line(int space)1976ecb06d0Sjsg db_end_line(int space)
198df930be7Sderaadt {
1999c690e8cSniklas 	if (db_output_position >= db_max_width - space)
200df930be7Sderaadt 		db_printf("\n");
201df930be7Sderaadt }
2024414dc2eSart 
2034414dc2eSart char *
db_format(char * buf,size_t bufsize,long val,int format,int alt,int width)2044414dc2eSart db_format(char *buf, size_t bufsize, long val, int format, int alt, int width)
2054414dc2eSart {
2064414dc2eSart 	const char *fmt;
2074414dc2eSart 
2084414dc2eSart 	if (format == DB_FORMAT_Z || db_radix == 16)
2094414dc2eSart 		fmt = alt ? "-%#*lx" : "-%*lx";
2104414dc2eSart 	else if (db_radix == 8)
2114414dc2eSart 		fmt = alt ? "-%#*lo" : "-%*lo";
2124414dc2eSart 	else
2134414dc2eSart 		fmt = alt ? "-%#*lu" : "-%*lu";
2144414dc2eSart 
2154414dc2eSart 	/* The leading '-' is a nasty (and beautiful) idea from NetBSD */
2164414dc2eSart 	if (val < 0 && format != DB_FORMAT_N)
2174414dc2eSart 		val = -val;
2184414dc2eSart 	else
2194414dc2eSart 		fmt++;
2204414dc2eSart 
2214414dc2eSart 	snprintf(buf, bufsize, fmt, width, val);
2224414dc2eSart 	return (buf);
2234414dc2eSart }
224a5243c05Sart 
225a5243c05Sart void
db_stack_dump(void)226a5243c05Sart db_stack_dump(void)
227a5243c05Sart {
228*fb6263ddSbluhm 	static struct cpu_info *intrace = NULL;
229*fb6263ddSbluhm 	struct cpu_info *tracing, *ci = curcpu();
230a5243c05Sart 
231*fb6263ddSbluhm 	tracing = atomic_cas_ptr(&intrace, NULL, ci);
232*fb6263ddSbluhm 	if (tracing != NULL) {
233*fb6263ddSbluhm 		if (tracing == ci)
234a5243c05Sart 			printf("Faulted in traceback, aborting...\n");
235*fb6263ddSbluhm 		else
236*fb6263ddSbluhm 			printf("Parallel traceback, suppressed...\n");
237a5243c05Sart 		return;
238a5243c05Sart 	}
239a5243c05Sart 
240a5243c05Sart 	printf("Starting stack trace...\n");
2418383b4f2Smpi 	db_stack_trace_print((db_expr_t)__builtin_frame_address(0), 1,
242bf5c753aSart 	    256 /* low limit */, "", printf);
243a5243c05Sart 	printf("End of stack trace.\n");
244*fb6263ddSbluhm 	membar_producer();
245*fb6263ddSbluhm 	intrace = NULL;
246a5243c05Sart }
247bfc40b23Svisa 
248bfc40b23Svisa void
stacktrace_print(struct stacktrace * st,int (* pr)(const char *,...))249c59fd4deSvisa stacktrace_print(struct stacktrace *st, int (*pr)(const char *, ...))
250bfc40b23Svisa {
251bfc40b23Svisa 	unsigned int i;
252bfc40b23Svisa 
253bfc40b23Svisa 	for (i = 0; i < st->st_count; i++) {
254e2fb33a4Svisa 		(*pr)("#%-2u ", i);
255e2fb33a4Svisa 		db_printsym(st->st_pc[i], DB_STGY_PROC, pr);
256e2fb33a4Svisa 		(*pr)("\n");
257bfc40b23Svisa 	}
258e2fb33a4Svisa 	if (st->st_count == 0)
259e2fb33a4Svisa 		(*pr)("<empty stack trace>\n");
260bfc40b23Svisa }
261e63dfe66Sjcs 
262e63dfe66Sjcs void
db_resize(int cols,int rows)263e63dfe66Sjcs db_resize(int cols, int rows)
264e63dfe66Sjcs {
265e63dfe66Sjcs 	db_max_width = cols;
266e63dfe66Sjcs 	db_max_line = rows;
267e63dfe66Sjcs }
268