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