2 * SPDX-License-Identifier: MIT-CMU
4 * Mach Operating System
5 * Copyright (c) 1991,1990 Carnegie Mellon University
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.
14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 * Carnegie Mellon requests users of this software to return to
20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
25 * any improvements or extensions that they make and grant Carnegie the
26 * rights to redistribute these changes.
29 * Author: David B. Golub, Carnegie Mellon University
34 * Printf and character output for debugger.
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
42 #include <sys/param.h>
43 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/sysctl.h>
49 #include <machine/stdarg.h>
52 #include <ddb/db_output.h>
54 struct dbputchar_arg {
62 * Character output - tracks position in line.
63 * To do this correctly, we should know how wide
64 * the output device is - then we could zero
65 * the line position when the output device wraps
66 * around to the start of the next line.
68 * Instead, we count the number of spaces printed
69 * since the last printing character so that we
70 * don't print trailing spaces. This avoids most
73 static int db_output_position = 0; /* output column */
74 static int db_last_non_space = 0; /* last non-space character */
75 db_expr_t db_tab_stop_width = 8; /* how wide are tab stops? */
76 #define NEXT_TAB(i) rounddown((i) + db_tab_stop_width, db_tab_stop_width)
77 db_expr_t db_max_width = 79; /* output line width */
78 db_expr_t db_lines_per_page = 20; /* lines per page */
79 volatile int db_pager_quit; /* user requested quit */
80 static int db_newlines; /* # lines this page */
81 static int db_maxlines; /* max lines/page when paging */
82 static int ddb_use_printf = 0;
83 SYSCTL_INT(_debug, OID_AUTO, ddb_use_printf, CTLFLAG_RW, &ddb_use_printf, 0,
84 "use printf for all ddb output");
86 static void db_putc(int c);
87 static void db_puts(const char *str);
88 static void db_putchar(int c, void *arg);
89 static void db_pager(void);
92 * Force pending whitespace.
95 db_force_whitespace(void)
97 int last_print, next_tab;
99 last_print = db_last_non_space;
100 while (last_print < db_output_position) {
101 next_tab = NEXT_TAB(last_print);
102 if (next_tab <= db_output_position) {
103 while (last_print < next_tab) { /* DON'T send a tab!!! */
105 db_capture_writech(' ');
111 db_capture_writech(' ');
115 db_last_non_space = db_output_position;
119 * Output character. Buffer whitespace.
122 db_putchar(int c, void *arg)
124 struct dbputchar_arg *dap = arg;
126 if (dap->da_pbufr == NULL) {
127 /* No bufferized output is provided. */
130 *dap->da_pnext++ = c;
133 /* Leave always the buffer 0 terminated. */
134 *dap->da_pnext = '\0';
136 /* Check if the buffer needs to be flushed. */
137 if (dap->da_remain < 2 || c == '\n') {
138 db_puts(dap->da_pbufr);
139 dap->da_pnext = dap->da_pbufr;
140 dap->da_remain = dap->da_nbufr;
141 *dap->da_pnext = '\0';
151 * If not in the debugger or the user requests it, output data to
152 * both the console and the message buffer.
154 if (!kdb_active || ddb_use_printf) {
158 if (c == '\r' || c == '\n')
159 db_check_interrupt();
160 if (c == '\n' && db_maxlines > 0) {
162 if (db_newlines >= db_maxlines)
168 /* Otherwise, output data directly to the console. */
169 if (c > ' ' && c <= '~') {
171 * Printing character.
172 * If we have spaces to print, print them first.
173 * Use tabs if possible.
175 db_force_whitespace();
177 db_capture_writech(c);
178 db_output_position++;
179 db_last_non_space = db_output_position;
181 else if (c == '\n') {
184 db_capture_writech(c);
185 db_output_position = 0;
186 db_last_non_space = 0;
187 db_check_interrupt();
188 if (db_maxlines > 0) {
190 if (db_newlines >= db_maxlines)
194 else if (c == '\r') {
197 db_capture_writech(c);
198 db_output_position = 0;
199 db_last_non_space = 0;
200 db_check_interrupt();
202 else if (c == '\t') {
203 /* assume tabs every 8 positions */
204 db_output_position = NEXT_TAB(db_output_position);
208 db_output_position++;
210 else if (c == '\007') {
213 /* No need to beep in a log: db_capture_writech(c); */
215 /* other characters are assumed non-printing */
219 db_puts(const char *str)
223 for (i = 0; str[i] != '\0'; i++)
231 db_enable_pager(void)
233 if (db_maxlines == 0) {
234 db_maxlines = db_lines_per_page;
241 * Turn off the pager.
244 db_disable_pager(void)
250 * A simple paging callout function. It supports several simple more(1)-like
251 * commands as well as a quit command that sets db_pager_quit which db
252 * commands can poll to see if they should terminate early.
259 db_capture_enterpager();
260 db_printf("--More--\r");
268 /* Just one more line. */
274 db_maxlines = db_lines_per_page / 2;
280 db_maxlines = db_lines_per_page;
300 db_force_whitespace();
303 db_capture_exitpager();
307 * Return output position
310 db_print_position(void)
312 return (db_output_position);
319 db_printf(const char *fmt, ...)
322 char bufr[DDB_BUFR_SIZE];
324 struct dbputchar_arg dca;
330 dca.da_pnext = dca.da_pbufr;
331 dca.da_nbufr = sizeof(bufr);
332 dca.da_remain = sizeof(bufr);
333 *dca.da_pnext = '\0';
338 va_start(listp, fmt);
339 retval = kvprintf (fmt, db_putchar, &dca, db_radix, listp);
343 if (*dca.da_pbufr != '\0')
344 db_puts(dca.da_pbufr);
352 db_iprintf(const char *fmt,...)
355 char bufr[DDB_BUFR_SIZE];
357 struct dbputchar_arg dca;
361 for (i = db_indent; i >= 8; i -= 8)
368 dca.da_pnext = dca.da_pbufr;
369 dca.da_nbufr = sizeof(bufr);
370 dca.da_remain = sizeof(bufr);
371 *dca.da_pnext = '\0';
376 va_start(listp, fmt);
377 kvprintf (fmt, db_putchar, &dca, db_radix, listp);
381 if (*dca.da_pbufr != '\0')
382 db_puts(dca.da_pbufr);
387 * End line if too long.
390 db_end_line(int field_width)
392 if (db_output_position + field_width > db_max_width)