1dd3cb568SWarner Losh /*-
2796df753SPedro F. Giffuni * SPDX-License-Identifier: MIT-CMU
3796df753SPedro F. Giffuni *
45b81b6b3SRodney W. Grimes * Mach Operating System
55b81b6b3SRodney W. Grimes * Copyright (c) 1991,1990 Carnegie Mellon University
65b81b6b3SRodney W. Grimes * All Rights Reserved.
75b81b6b3SRodney W. Grimes *
85b81b6b3SRodney W. Grimes * Permission to use, copy, modify and distribute this software and its
95b81b6b3SRodney W. Grimes * documentation is hereby granted, provided that both the copyright
105b81b6b3SRodney W. Grimes * notice and this permission notice appear in all copies of the
115b81b6b3SRodney W. Grimes * software, derivative works or modified versions, and any portions
125b81b6b3SRodney W. Grimes * thereof, and that both notices appear in supporting documentation.
135b81b6b3SRodney W. Grimes *
145b81b6b3SRodney W. Grimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
155b81b6b3SRodney W. Grimes * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
165b81b6b3SRodney W. Grimes * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
175b81b6b3SRodney W. Grimes *
185b81b6b3SRodney W. Grimes * Carnegie Mellon requests users of this software to return to
195b81b6b3SRodney W. Grimes *
205b81b6b3SRodney W. Grimes * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
215b81b6b3SRodney W. Grimes * School of Computer Science
225b81b6b3SRodney W. Grimes * Carnegie Mellon University
235b81b6b3SRodney W. Grimes * Pittsburgh PA 15213-3890
245b81b6b3SRodney W. Grimes *
255b81b6b3SRodney W. Grimes * any improvements or extensions that they make and grant Carnegie the
265b81b6b3SRodney W. Grimes * rights to redistribute these changes.
275b81b6b3SRodney W. Grimes */
285b81b6b3SRodney W. Grimes /*
295b81b6b3SRodney W. Grimes * Author: David B. Golub, Carnegie Mellon University
305b81b6b3SRodney W. Grimes * Date: 7/90
315b81b6b3SRodney W. Grimes */
325b81b6b3SRodney W. Grimes
335b81b6b3SRodney W. Grimes /*
345b81b6b3SRodney W. Grimes * Printf and character output for debugger.
355b81b6b3SRodney W. Grimes */
365b81b6b3SRodney W. Grimes
37753960f7SDavid E. O'Brien #include <sys/cdefs.h>
38e23851c6SAttilio Rao #include "opt_ddb.h"
39e23851c6SAttilio Rao
40f540b106SGarrett Wollman #include <sys/param.h>
41f540b106SGarrett Wollman #include <sys/systm.h>
42ce9edcf5SPoul-Henning Kamp #include <sys/cons.h>
4337224cd3SMarcel Moolenaar #include <sys/kdb.h>
445de6c5b5SNate Lawson #include <sys/kernel.h>
455de6c5b5SNate Lawson #include <sys/sysctl.h>
465ccbc3ccSBruce Evans
47f540b106SGarrett Wollman #include <machine/stdarg.h>
485ccbc3ccSBruce Evans
49f540b106SGarrett Wollman #include <ddb/ddb.h>
50058284fcSBruce Evans #include <ddb/db_output.h>
515b81b6b3SRodney W. Grimes
5251b93e47SAttilio Rao struct dbputchar_arg {
5351b93e47SAttilio Rao size_t da_nbufr;
5451b93e47SAttilio Rao size_t da_remain;
5551b93e47SAttilio Rao char *da_pbufr;
5651b93e47SAttilio Rao char *da_pnext;
5751b93e47SAttilio Rao };
5851b93e47SAttilio Rao
595b81b6b3SRodney W. Grimes /*
605b81b6b3SRodney W. Grimes * Character output - tracks position in line.
615b81b6b3SRodney W. Grimes * To do this correctly, we should know how wide
625b81b6b3SRodney W. Grimes * the output device is - then we could zero
635b81b6b3SRodney W. Grimes * the line position when the output device wraps
645b81b6b3SRodney W. Grimes * around to the start of the next line.
655b81b6b3SRodney W. Grimes *
665b81b6b3SRodney W. Grimes * Instead, we count the number of spaces printed
675b81b6b3SRodney W. Grimes * since the last printing character so that we
685b81b6b3SRodney W. Grimes * don't print trailing spaces. This avoids most
695b81b6b3SRodney W. Grimes * of the wraparounds.
705b81b6b3SRodney W. Grimes */
71f73a856dSPoul-Henning Kamp static int db_output_position = 0; /* output column */
72f73a856dSPoul-Henning Kamp static int db_last_non_space = 0; /* last non-space character */
733da6ef3cSBruce Evans db_expr_t db_tab_stop_width = 8; /* how wide are tab stops? */
744ed3c0e7SPedro F. Giffuni #define NEXT_TAB(i) rounddown((i) + db_tab_stop_width, db_tab_stop_width)
753da6ef3cSBruce Evans db_expr_t db_max_width = 79; /* output line width */
76d39d4a6eSJohn Baldwin db_expr_t db_lines_per_page = 20; /* lines per page */
7719e9205aSJohn Baldwin volatile int db_pager_quit; /* user requested quit */
781e16f609SJohn Baldwin static int db_newlines; /* # lines this page */
7919e9205aSJohn Baldwin static int db_maxlines; /* max lines/page when paging */
805de6c5b5SNate Lawson static int ddb_use_printf = 0;
815de6c5b5SNate Lawson SYSCTL_INT(_debug, OID_AUTO, ddb_use_printf, CTLFLAG_RW, &ddb_use_printf, 0,
825de6c5b5SNate Lawson "use printf for all ddb output");
835b81b6b3SRodney W. Grimes
8451b93e47SAttilio Rao static void db_putc(int c);
8551b93e47SAttilio Rao static void db_puts(const char *str);
8614e10f99SAlfred Perlstein static void db_putchar(int c, void *arg);
8719e9205aSJohn Baldwin static void db_pager(void);
886ddbf1e2SGary Palmer
895b81b6b3SRodney W. Grimes /*
905b81b6b3SRodney W. Grimes * Force pending whitespace.
915b81b6b3SRodney W. Grimes */
925b81b6b3SRodney W. Grimes void
db_force_whitespace(void)93a41dd031SPedro F. Giffuni db_force_whitespace(void)
945b81b6b3SRodney W. Grimes {
953e85b721SEd Maste int last_print, next_tab;
965b81b6b3SRodney W. Grimes
975b81b6b3SRodney W. Grimes last_print = db_last_non_space;
985b81b6b3SRodney W. Grimes while (last_print < db_output_position) {
995b81b6b3SRodney W. Grimes next_tab = NEXT_TAB(last_print);
1005b81b6b3SRodney W. Grimes if (next_tab <= db_output_position) {
1015b81b6b3SRodney W. Grimes while (last_print < next_tab) { /* DON'T send a tab!!! */
1025b81b6b3SRodney W. Grimes cnputc(' ');
103086fec57SRobert Watson db_capture_writech(' ');
1045b81b6b3SRodney W. Grimes last_print++;
1055b81b6b3SRodney W. Grimes }
1065b81b6b3SRodney W. Grimes }
1075b81b6b3SRodney W. Grimes else {
1085b81b6b3SRodney W. Grimes cnputc(' ');
109086fec57SRobert Watson db_capture_writech(' ');
1105b81b6b3SRodney W. Grimes last_print++;
1115b81b6b3SRodney W. Grimes }
1125b81b6b3SRodney W. Grimes }
1135b81b6b3SRodney W. Grimes db_last_non_space = db_output_position;
1145b81b6b3SRodney W. Grimes }
1155b81b6b3SRodney W. Grimes
1165b81b6b3SRodney W. Grimes /*
1175b81b6b3SRodney W. Grimes * Output character. Buffer whitespace.
1185b81b6b3SRodney W. Grimes */
1196ddbf1e2SGary Palmer static void
db_putchar(int c,void * arg)12051b93e47SAttilio Rao db_putchar(int c, void *arg)
12151b93e47SAttilio Rao {
12251b93e47SAttilio Rao struct dbputchar_arg *dap = arg;
12351b93e47SAttilio Rao
12451b93e47SAttilio Rao if (dap->da_pbufr == NULL) {
12551b93e47SAttilio Rao /* No bufferized output is provided. */
12651b93e47SAttilio Rao db_putc(c);
12751b93e47SAttilio Rao } else {
12851b93e47SAttilio Rao *dap->da_pnext++ = c;
12951b93e47SAttilio Rao dap->da_remain--;
13051b93e47SAttilio Rao
13151b93e47SAttilio Rao /* Leave always the buffer 0 terminated. */
13251b93e47SAttilio Rao *dap->da_pnext = '\0';
13351b93e47SAttilio Rao
13451b93e47SAttilio Rao /* Check if the buffer needs to be flushed. */
13551b93e47SAttilio Rao if (dap->da_remain < 2 || c == '\n') {
13651b93e47SAttilio Rao db_puts(dap->da_pbufr);
13751b93e47SAttilio Rao dap->da_pnext = dap->da_pbufr;
13851b93e47SAttilio Rao dap->da_remain = dap->da_nbufr;
13951b93e47SAttilio Rao *dap->da_pnext = '\0';
14051b93e47SAttilio Rao }
14151b93e47SAttilio Rao }
14251b93e47SAttilio Rao }
14351b93e47SAttilio Rao
14451b93e47SAttilio Rao static void
db_putc(int c)14551b93e47SAttilio Rao db_putc(int c)
1465b81b6b3SRodney W. Grimes {
1471e16f609SJohn Baldwin
1485de6c5b5SNate Lawson /*
1495de6c5b5SNate Lawson * If not in the debugger or the user requests it, output data to
1505de6c5b5SNate Lawson * both the console and the message buffer.
1515de6c5b5SNate Lawson */
15237224cd3SMarcel Moolenaar if (!kdb_active || ddb_use_printf) {
1535de6c5b5SNate Lawson printf("%c", c);
15437224cd3SMarcel Moolenaar if (!kdb_active)
1555de6c5b5SNate Lawson return;
1565de6c5b5SNate Lawson if (c == '\r' || c == '\n')
1575de6c5b5SNate Lawson db_check_interrupt();
15819e9205aSJohn Baldwin if (c == '\n' && db_maxlines > 0) {
1595de6c5b5SNate Lawson db_newlines++;
16019e9205aSJohn Baldwin if (db_newlines >= db_maxlines)
16119e9205aSJohn Baldwin db_pager();
1625de6c5b5SNate Lawson }
1635de6c5b5SNate Lawson return;
1645de6c5b5SNate Lawson }
1655de6c5b5SNate Lawson
1665de6c5b5SNate Lawson /* Otherwise, output data directly to the console. */
1675b81b6b3SRodney W. Grimes if (c > ' ' && c <= '~') {
1685b81b6b3SRodney W. Grimes /*
1695b81b6b3SRodney W. Grimes * Printing character.
1705b81b6b3SRodney W. Grimes * If we have spaces to print, print them first.
1715b81b6b3SRodney W. Grimes * Use tabs if possible.
1725b81b6b3SRodney W. Grimes */
1735b81b6b3SRodney W. Grimes db_force_whitespace();
1745b81b6b3SRodney W. Grimes cnputc(c);
175086fec57SRobert Watson db_capture_writech(c);
1765b81b6b3SRodney W. Grimes db_output_position++;
1775b81b6b3SRodney W. Grimes db_last_non_space = db_output_position;
1785b81b6b3SRodney W. Grimes }
1795b81b6b3SRodney W. Grimes else if (c == '\n') {
1808a129caeSDavid Greenman /* Newline */
1818a129caeSDavid Greenman cnputc(c);
182086fec57SRobert Watson db_capture_writech(c);
1838a129caeSDavid Greenman db_output_position = 0;
1848a129caeSDavid Greenman db_last_non_space = 0;
1858a129caeSDavid Greenman db_check_interrupt();
18619e9205aSJohn Baldwin if (db_maxlines > 0) {
1871e16f609SJohn Baldwin db_newlines++;
18819e9205aSJohn Baldwin if (db_newlines >= db_maxlines)
18919e9205aSJohn Baldwin db_pager();
1901e16f609SJohn Baldwin }
1918a129caeSDavid Greenman }
1928a129caeSDavid Greenman else if (c == '\r') {
1935b81b6b3SRodney W. Grimes /* Return */
1945b81b6b3SRodney W. Grimes cnputc(c);
195086fec57SRobert Watson db_capture_writech(c);
1965b81b6b3SRodney W. Grimes db_output_position = 0;
1975b81b6b3SRodney W. Grimes db_last_non_space = 0;
1985b81b6b3SRodney W. Grimes db_check_interrupt();
1995b81b6b3SRodney W. Grimes }
2005b81b6b3SRodney W. Grimes else if (c == '\t') {
2015b81b6b3SRodney W. Grimes /* assume tabs every 8 positions */
2025b81b6b3SRodney W. Grimes db_output_position = NEXT_TAB(db_output_position);
2035b81b6b3SRodney W. Grimes }
2045b81b6b3SRodney W. Grimes else if (c == ' ') {
2055b81b6b3SRodney W. Grimes /* space */
2065b81b6b3SRodney W. Grimes db_output_position++;
2075b81b6b3SRodney W. Grimes }
2085b81b6b3SRodney W. Grimes else if (c == '\007') {
2095b81b6b3SRodney W. Grimes /* bell */
2105b81b6b3SRodney W. Grimes cnputc(c);
211086fec57SRobert Watson /* No need to beep in a log: db_capture_writech(c); */
2125b81b6b3SRodney W. Grimes }
2135b81b6b3SRodney W. Grimes /* other characters are assumed non-printing */
2145b81b6b3SRodney W. Grimes }
2155b81b6b3SRodney W. Grimes
21651b93e47SAttilio Rao static void
db_puts(const char * str)21751b93e47SAttilio Rao db_puts(const char *str)
21851b93e47SAttilio Rao {
21951b93e47SAttilio Rao int i;
22051b93e47SAttilio Rao
22151b93e47SAttilio Rao for (i = 0; str[i] != '\0'; i++)
22251b93e47SAttilio Rao db_putc(str[i]);
22351b93e47SAttilio Rao }
22451b93e47SAttilio Rao
2255b81b6b3SRodney W. Grimes /*
22619e9205aSJohn Baldwin * Turn on the pager.
2271e16f609SJohn Baldwin */
2281e16f609SJohn Baldwin void
db_enable_pager(void)22919e9205aSJohn Baldwin db_enable_pager(void)
2301e16f609SJohn Baldwin {
23119e9205aSJohn Baldwin if (db_maxlines == 0) {
23219e9205aSJohn Baldwin db_maxlines = db_lines_per_page;
2331e16f609SJohn Baldwin db_newlines = 0;
23419e9205aSJohn Baldwin db_pager_quit = 0;
2351e16f609SJohn Baldwin }
236da927f93SOlivier Houchard }
2371e16f609SJohn Baldwin
2381e16f609SJohn Baldwin /*
23919e9205aSJohn Baldwin * Turn off the pager.
2401e16f609SJohn Baldwin */
2411e16f609SJohn Baldwin void
db_disable_pager(void)24219e9205aSJohn Baldwin db_disable_pager(void)
24319e9205aSJohn Baldwin {
24419e9205aSJohn Baldwin db_maxlines = 0;
24519e9205aSJohn Baldwin }
24619e9205aSJohn Baldwin
24719e9205aSJohn Baldwin /*
24819e9205aSJohn Baldwin * A simple paging callout function. It supports several simple more(1)-like
24919e9205aSJohn Baldwin * commands as well as a quit command that sets db_pager_quit which db
25019e9205aSJohn Baldwin * commands can poll to see if they should terminate early.
25119e9205aSJohn Baldwin */
25219e9205aSJohn Baldwin void
db_pager(void)25319e9205aSJohn Baldwin db_pager(void)
2541e16f609SJohn Baldwin {
255d39d4a6eSJohn Baldwin int c, done;
2561e16f609SJohn Baldwin
257086fec57SRobert Watson db_capture_enterpager();
2581e16f609SJohn Baldwin db_printf("--More--\r");
259d39d4a6eSJohn Baldwin done = 0;
260d39d4a6eSJohn Baldwin while (!done) {
261*3e5e9939SRyan Libby c = db_getc();
2621e16f609SJohn Baldwin switch (c) {
263d39d4a6eSJohn Baldwin case 'e':
264d39d4a6eSJohn Baldwin case 'j':
2651e16f609SJohn Baldwin case '\n':
2661e16f609SJohn Baldwin /* Just one more line. */
26719e9205aSJohn Baldwin db_maxlines = 1;
268d39d4a6eSJohn Baldwin done++;
269d39d4a6eSJohn Baldwin break;
270d39d4a6eSJohn Baldwin case 'd':
271d39d4a6eSJohn Baldwin /* Half a page. */
27219e9205aSJohn Baldwin db_maxlines = db_lines_per_page / 2;
273d39d4a6eSJohn Baldwin done++;
274d39d4a6eSJohn Baldwin break;
275d39d4a6eSJohn Baldwin case 'f':
2761e16f609SJohn Baldwin case ' ':
2771e16f609SJohn Baldwin /* Another page. */
27819e9205aSJohn Baldwin db_maxlines = db_lines_per_page;
279d39d4a6eSJohn Baldwin done++;
280d39d4a6eSJohn Baldwin break;
2811e16f609SJohn Baldwin case 'q':
2821e16f609SJohn Baldwin case 'Q':
2831e16f609SJohn Baldwin case 'x':
2841e16f609SJohn Baldwin case 'X':
2851e16f609SJohn Baldwin /* Quit */
28619e9205aSJohn Baldwin db_maxlines = 0;
28719e9205aSJohn Baldwin db_pager_quit = 1;
288d39d4a6eSJohn Baldwin done++;
289d39d4a6eSJohn Baldwin break;
2901e16f609SJohn Baldwin #if 0
2911e16f609SJohn Baldwin /* FALLTHROUGH */
2921e16f609SJohn Baldwin default:
2931e16f609SJohn Baldwin cnputc('\007');
2941e16f609SJohn Baldwin #endif
2951e16f609SJohn Baldwin }
2961e16f609SJohn Baldwin }
297c7eeb59dSBruce Evans db_printf(" ");
298c7eeb59dSBruce Evans db_force_whitespace();
299d39d4a6eSJohn Baldwin db_printf("\r");
30019e9205aSJohn Baldwin db_newlines = 0;
301086fec57SRobert Watson db_capture_exitpager();
3021e16f609SJohn Baldwin }
3031e16f609SJohn Baldwin
3041e16f609SJohn Baldwin /*
3055b81b6b3SRodney W. Grimes * Return output position
3065b81b6b3SRodney W. Grimes */
3075b81b6b3SRodney W. Grimes int
db_print_position(void)308a41dd031SPedro F. Giffuni db_print_position(void)
3095b81b6b3SRodney W. Grimes {
3105b81b6b3SRodney W. Grimes return (db_output_position);
3115b81b6b3SRodney W. Grimes }
3125b81b6b3SRodney W. Grimes
3135b81b6b3SRodney W. Grimes /*
3145b81b6b3SRodney W. Grimes * Printing
3155b81b6b3SRodney W. Grimes */
3163caaaae0SAttilio Rao int
db_printf(const char * fmt,...)317381fe1aaSGarrett Wollman db_printf(const char *fmt, ...)
3185b81b6b3SRodney W. Grimes {
31951b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE
32051b93e47SAttilio Rao char bufr[DDB_BUFR_SIZE];
32151b93e47SAttilio Rao #endif
32251b93e47SAttilio Rao struct dbputchar_arg dca;
3235b81b6b3SRodney W. Grimes va_list listp;
3243caaaae0SAttilio Rao int retval;
325c7c34a24SBruce Evans
32651b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE
32751b93e47SAttilio Rao dca.da_pbufr = bufr;
32851b93e47SAttilio Rao dca.da_pnext = dca.da_pbufr;
32951b93e47SAttilio Rao dca.da_nbufr = sizeof(bufr);
33051b93e47SAttilio Rao dca.da_remain = sizeof(bufr);
33151b93e47SAttilio Rao *dca.da_pnext = '\0';
33251b93e47SAttilio Rao #else
33351b93e47SAttilio Rao dca.da_pbufr = NULL;
33451b93e47SAttilio Rao #endif
33551b93e47SAttilio Rao
336c7c34a24SBruce Evans va_start(listp, fmt);
3373caaaae0SAttilio Rao retval = kvprintf (fmt, db_putchar, &dca, db_radix, listp);
338c7c34a24SBruce Evans va_end(listp);
33951b93e47SAttilio Rao
34051b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE
34151b93e47SAttilio Rao if (*dca.da_pbufr != '\0')
34251b93e47SAttilio Rao db_puts(dca.da_pbufr);
34351b93e47SAttilio Rao #endif
3443caaaae0SAttilio Rao return (retval);
345c7c34a24SBruce Evans }
346c7c34a24SBruce Evans
347c7c34a24SBruce Evans int db_indent;
348c7c34a24SBruce Evans
349c7c34a24SBruce Evans void
db_iprintf(const char * fmt,...)350c7c34a24SBruce Evans db_iprintf(const char *fmt,...)
351c7c34a24SBruce Evans {
35251b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE
35351b93e47SAttilio Rao char bufr[DDB_BUFR_SIZE];
35451b93e47SAttilio Rao #endif
35551b93e47SAttilio Rao struct dbputchar_arg dca;
3563e85b721SEd Maste int i;
357c7c34a24SBruce Evans va_list listp;
358c7c34a24SBruce Evans
359c7c34a24SBruce Evans for (i = db_indent; i >= 8; i -= 8)
360c7c34a24SBruce Evans db_printf("\t");
361c7c34a24SBruce Evans while (--i >= 0)
362c7c34a24SBruce Evans db_printf(" ");
36351b93e47SAttilio Rao
36451b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE
36551b93e47SAttilio Rao dca.da_pbufr = bufr;
36651b93e47SAttilio Rao dca.da_pnext = dca.da_pbufr;
36751b93e47SAttilio Rao dca.da_nbufr = sizeof(bufr);
36851b93e47SAttilio Rao dca.da_remain = sizeof(bufr);
36951b93e47SAttilio Rao *dca.da_pnext = '\0';
37051b93e47SAttilio Rao #else
37151b93e47SAttilio Rao dca.da_pbufr = NULL;
37251b93e47SAttilio Rao #endif
37351b93e47SAttilio Rao
3745b81b6b3SRodney W. Grimes va_start(listp, fmt);
37551b93e47SAttilio Rao kvprintf (fmt, db_putchar, &dca, db_radix, listp);
3765b81b6b3SRodney W. Grimes va_end(listp);
37751b93e47SAttilio Rao
37851b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE
37951b93e47SAttilio Rao if (*dca.da_pbufr != '\0')
38051b93e47SAttilio Rao db_puts(dca.da_pbufr);
38151b93e47SAttilio Rao #endif
3825b81b6b3SRodney W. Grimes }
3835b81b6b3SRodney W. Grimes
3845b81b6b3SRodney W. Grimes /*
385572de915SRodney W. Grimes * End line if too long.
386572de915SRodney W. Grimes */
387572de915SRodney W. Grimes void
db_end_line(int field_width)3882481da74SBruce Evans db_end_line(int field_width)
389572de915SRodney W. Grimes {
3902481da74SBruce Evans if (db_output_position + field_width > db_max_width)
391572de915SRodney W. Grimes db_printf("\n");
392572de915SRodney W. Grimes }
393