1dd3cb568SWarner Losh /*- 25b81b6b3SRodney W. Grimes * Mach Operating System 35b81b6b3SRodney W. Grimes * Copyright (c) 1991,1990 Carnegie Mellon University 45b81b6b3SRodney W. Grimes * All Rights Reserved. 55b81b6b3SRodney W. Grimes * 65b81b6b3SRodney W. Grimes * Permission to use, copy, modify and distribute this software and its 75b81b6b3SRodney W. Grimes * documentation is hereby granted, provided that both the copyright 85b81b6b3SRodney W. Grimes * notice and this permission notice appear in all copies of the 95b81b6b3SRodney W. Grimes * software, derivative works or modified versions, and any portions 105b81b6b3SRodney W. Grimes * thereof, and that both notices appear in supporting documentation. 115b81b6b3SRodney W. Grimes * 125b81b6b3SRodney W. Grimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 135b81b6b3SRodney W. Grimes * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 145b81b6b3SRodney W. Grimes * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 155b81b6b3SRodney W. Grimes * 165b81b6b3SRodney W. Grimes * Carnegie Mellon requests users of this software to return to 175b81b6b3SRodney W. Grimes * 185b81b6b3SRodney W. Grimes * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 195b81b6b3SRodney W. Grimes * School of Computer Science 205b81b6b3SRodney W. Grimes * Carnegie Mellon University 215b81b6b3SRodney W. Grimes * Pittsburgh PA 15213-3890 225b81b6b3SRodney W. Grimes * 235b81b6b3SRodney W. Grimes * any improvements or extensions that they make and grant Carnegie the 245b81b6b3SRodney W. Grimes * rights to redistribute these changes. 255b81b6b3SRodney W. Grimes */ 265b81b6b3SRodney W. Grimes /* 275b81b6b3SRodney W. Grimes * Author: David B. Golub, Carnegie Mellon University 285b81b6b3SRodney W. Grimes * Date: 7/90 295b81b6b3SRodney W. Grimes */ 305b81b6b3SRodney W. Grimes 315b81b6b3SRodney W. Grimes /* 325b81b6b3SRodney W. Grimes * Printf and character output for debugger. 335b81b6b3SRodney W. Grimes */ 345b81b6b3SRodney W. Grimes 35753960f7SDavid E. O'Brien #include <sys/cdefs.h> 36753960f7SDavid E. O'Brien __FBSDID("$FreeBSD$"); 37753960f7SDavid E. O'Brien 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 93a41dd031SPedro F. Giffuni db_force_whitespace(void) 945b81b6b3SRodney W. Grimes { 95*3e85b721SEd 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 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 12651b93e47SAttilio Rao /* No bufferized output is provided. */ 12751b93e47SAttilio Rao db_putc(c); 12851b93e47SAttilio Rao } else { 12951b93e47SAttilio Rao 13051b93e47SAttilio Rao *dap->da_pnext++ = c; 13151b93e47SAttilio Rao dap->da_remain--; 13251b93e47SAttilio Rao 13351b93e47SAttilio Rao /* Leave always the buffer 0 terminated. */ 13451b93e47SAttilio Rao *dap->da_pnext = '\0'; 13551b93e47SAttilio Rao 13651b93e47SAttilio Rao /* Check if the buffer needs to be flushed. */ 13751b93e47SAttilio Rao if (dap->da_remain < 2 || c == '\n') { 13851b93e47SAttilio Rao db_puts(dap->da_pbufr); 13951b93e47SAttilio Rao dap->da_pnext = dap->da_pbufr; 14051b93e47SAttilio Rao dap->da_remain = dap->da_nbufr; 14151b93e47SAttilio Rao *dap->da_pnext = '\0'; 14251b93e47SAttilio Rao } 14351b93e47SAttilio Rao } 14451b93e47SAttilio Rao } 14551b93e47SAttilio Rao 14651b93e47SAttilio Rao static void 14751b93e47SAttilio Rao db_putc(int c) 1485b81b6b3SRodney W. Grimes { 1491e16f609SJohn Baldwin 1505de6c5b5SNate Lawson /* 1515de6c5b5SNate Lawson * If not in the debugger or the user requests it, output data to 1525de6c5b5SNate Lawson * both the console and the message buffer. 1535de6c5b5SNate Lawson */ 15437224cd3SMarcel Moolenaar if (!kdb_active || ddb_use_printf) { 1555de6c5b5SNate Lawson printf("%c", c); 15637224cd3SMarcel Moolenaar if (!kdb_active) 1575de6c5b5SNate Lawson return; 1585de6c5b5SNate Lawson if (c == '\r' || c == '\n') 1595de6c5b5SNate Lawson db_check_interrupt(); 16019e9205aSJohn Baldwin if (c == '\n' && db_maxlines > 0) { 1615de6c5b5SNate Lawson db_newlines++; 16219e9205aSJohn Baldwin if (db_newlines >= db_maxlines) 16319e9205aSJohn Baldwin db_pager(); 1645de6c5b5SNate Lawson } 1655de6c5b5SNate Lawson return; 1665de6c5b5SNate Lawson } 1675de6c5b5SNate Lawson 1685de6c5b5SNate Lawson /* Otherwise, output data directly to the console. */ 1695b81b6b3SRodney W. Grimes if (c > ' ' && c <= '~') { 1705b81b6b3SRodney W. Grimes /* 1715b81b6b3SRodney W. Grimes * Printing character. 1725b81b6b3SRodney W. Grimes * If we have spaces to print, print them first. 1735b81b6b3SRodney W. Grimes * Use tabs if possible. 1745b81b6b3SRodney W. Grimes */ 1755b81b6b3SRodney W. Grimes db_force_whitespace(); 1765b81b6b3SRodney W. Grimes cnputc(c); 177086fec57SRobert Watson db_capture_writech(c); 1785b81b6b3SRodney W. Grimes db_output_position++; 1795b81b6b3SRodney W. Grimes db_last_non_space = db_output_position; 1805b81b6b3SRodney W. Grimes } 1815b81b6b3SRodney W. Grimes else if (c == '\n') { 1828a129caeSDavid Greenman /* Newline */ 1838a129caeSDavid Greenman cnputc(c); 184086fec57SRobert Watson db_capture_writech(c); 1858a129caeSDavid Greenman db_output_position = 0; 1868a129caeSDavid Greenman db_last_non_space = 0; 1878a129caeSDavid Greenman db_check_interrupt(); 18819e9205aSJohn Baldwin if (db_maxlines > 0) { 1891e16f609SJohn Baldwin db_newlines++; 19019e9205aSJohn Baldwin if (db_newlines >= db_maxlines) 19119e9205aSJohn Baldwin db_pager(); 1921e16f609SJohn Baldwin } 1938a129caeSDavid Greenman } 1948a129caeSDavid Greenman else if (c == '\r') { 1955b81b6b3SRodney W. Grimes /* Return */ 1965b81b6b3SRodney W. Grimes cnputc(c); 197086fec57SRobert Watson db_capture_writech(c); 1985b81b6b3SRodney W. Grimes db_output_position = 0; 1995b81b6b3SRodney W. Grimes db_last_non_space = 0; 2005b81b6b3SRodney W. Grimes db_check_interrupt(); 2015b81b6b3SRodney W. Grimes } 2025b81b6b3SRodney W. Grimes else if (c == '\t') { 2035b81b6b3SRodney W. Grimes /* assume tabs every 8 positions */ 2045b81b6b3SRodney W. Grimes db_output_position = NEXT_TAB(db_output_position); 2055b81b6b3SRodney W. Grimes } 2065b81b6b3SRodney W. Grimes else if (c == ' ') { 2075b81b6b3SRodney W. Grimes /* space */ 2085b81b6b3SRodney W. Grimes db_output_position++; 2095b81b6b3SRodney W. Grimes } 2105b81b6b3SRodney W. Grimes else if (c == '\007') { 2115b81b6b3SRodney W. Grimes /* bell */ 2125b81b6b3SRodney W. Grimes cnputc(c); 213086fec57SRobert Watson /* No need to beep in a log: db_capture_writech(c); */ 2145b81b6b3SRodney W. Grimes } 2155b81b6b3SRodney W. Grimes /* other characters are assumed non-printing */ 2165b81b6b3SRodney W. Grimes } 2175b81b6b3SRodney W. Grimes 21851b93e47SAttilio Rao static void 21951b93e47SAttilio Rao db_puts(const char *str) 22051b93e47SAttilio Rao { 22151b93e47SAttilio Rao int i; 22251b93e47SAttilio Rao 22351b93e47SAttilio Rao for (i = 0; str[i] != '\0'; i++) 22451b93e47SAttilio Rao db_putc(str[i]); 22551b93e47SAttilio Rao } 22651b93e47SAttilio Rao 2275b81b6b3SRodney W. Grimes /* 22819e9205aSJohn Baldwin * Turn on the pager. 2291e16f609SJohn Baldwin */ 2301e16f609SJohn Baldwin void 23119e9205aSJohn Baldwin db_enable_pager(void) 2321e16f609SJohn Baldwin { 23319e9205aSJohn Baldwin if (db_maxlines == 0) { 23419e9205aSJohn Baldwin db_maxlines = db_lines_per_page; 2351e16f609SJohn Baldwin db_newlines = 0; 23619e9205aSJohn Baldwin db_pager_quit = 0; 2371e16f609SJohn Baldwin } 238da927f93SOlivier Houchard } 2391e16f609SJohn Baldwin 2401e16f609SJohn Baldwin /* 24119e9205aSJohn Baldwin * Turn off the pager. 2421e16f609SJohn Baldwin */ 2431e16f609SJohn Baldwin void 24419e9205aSJohn Baldwin db_disable_pager(void) 24519e9205aSJohn Baldwin { 24619e9205aSJohn Baldwin db_maxlines = 0; 24719e9205aSJohn Baldwin } 24819e9205aSJohn Baldwin 24919e9205aSJohn Baldwin /* 25019e9205aSJohn Baldwin * A simple paging callout function. It supports several simple more(1)-like 25119e9205aSJohn Baldwin * commands as well as a quit command that sets db_pager_quit which db 25219e9205aSJohn Baldwin * commands can poll to see if they should terminate early. 25319e9205aSJohn Baldwin */ 25419e9205aSJohn Baldwin void 25519e9205aSJohn Baldwin db_pager(void) 2561e16f609SJohn Baldwin { 257d39d4a6eSJohn Baldwin int c, done; 2581e16f609SJohn Baldwin 259086fec57SRobert Watson db_capture_enterpager(); 2601e16f609SJohn Baldwin db_printf("--More--\r"); 261d39d4a6eSJohn Baldwin done = 0; 262d39d4a6eSJohn Baldwin while (!done) { 2631e16f609SJohn Baldwin c = cngetc(); 2641e16f609SJohn Baldwin switch (c) { 265d39d4a6eSJohn Baldwin case 'e': 266d39d4a6eSJohn Baldwin case 'j': 2671e16f609SJohn Baldwin case '\n': 2681e16f609SJohn Baldwin /* Just one more line. */ 26919e9205aSJohn Baldwin db_maxlines = 1; 270d39d4a6eSJohn Baldwin done++; 271d39d4a6eSJohn Baldwin break; 272d39d4a6eSJohn Baldwin case 'd': 273d39d4a6eSJohn Baldwin /* Half a page. */ 27419e9205aSJohn Baldwin db_maxlines = db_lines_per_page / 2; 275d39d4a6eSJohn Baldwin done++; 276d39d4a6eSJohn Baldwin break; 277d39d4a6eSJohn Baldwin case 'f': 2781e16f609SJohn Baldwin case ' ': 2791e16f609SJohn Baldwin /* Another page. */ 28019e9205aSJohn Baldwin db_maxlines = db_lines_per_page; 281d39d4a6eSJohn Baldwin done++; 282d39d4a6eSJohn Baldwin break; 2831e16f609SJohn Baldwin case 'q': 2841e16f609SJohn Baldwin case 'Q': 2851e16f609SJohn Baldwin case 'x': 2861e16f609SJohn Baldwin case 'X': 2871e16f609SJohn Baldwin /* Quit */ 28819e9205aSJohn Baldwin db_maxlines = 0; 28919e9205aSJohn Baldwin db_pager_quit = 1; 290d39d4a6eSJohn Baldwin done++; 291d39d4a6eSJohn Baldwin break; 2921e16f609SJohn Baldwin #if 0 2931e16f609SJohn Baldwin /* FALLTHROUGH */ 2941e16f609SJohn Baldwin default: 2951e16f609SJohn Baldwin cnputc('\007'); 2961e16f609SJohn Baldwin #endif 2971e16f609SJohn Baldwin } 2981e16f609SJohn Baldwin } 299c7eeb59dSBruce Evans db_printf(" "); 300c7eeb59dSBruce Evans db_force_whitespace(); 301d39d4a6eSJohn Baldwin db_printf("\r"); 30219e9205aSJohn Baldwin db_newlines = 0; 303086fec57SRobert Watson db_capture_exitpager(); 3041e16f609SJohn Baldwin } 3051e16f609SJohn Baldwin 3061e16f609SJohn Baldwin /* 3075b81b6b3SRodney W. Grimes * Return output position 3085b81b6b3SRodney W. Grimes */ 3095b81b6b3SRodney W. Grimes int 310a41dd031SPedro F. Giffuni db_print_position(void) 3115b81b6b3SRodney W. Grimes { 3125b81b6b3SRodney W. Grimes return (db_output_position); 3135b81b6b3SRodney W. Grimes } 3145b81b6b3SRodney W. Grimes 3155b81b6b3SRodney W. Grimes /* 3165b81b6b3SRodney W. Grimes * Printing 3175b81b6b3SRodney W. Grimes */ 3183caaaae0SAttilio Rao int 319381fe1aaSGarrett Wollman db_printf(const char *fmt, ...) 3205b81b6b3SRodney W. Grimes { 32151b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE 32251b93e47SAttilio Rao char bufr[DDB_BUFR_SIZE]; 32351b93e47SAttilio Rao #endif 32451b93e47SAttilio Rao struct dbputchar_arg dca; 3255b81b6b3SRodney W. Grimes va_list listp; 3263caaaae0SAttilio Rao int retval; 327c7c34a24SBruce Evans 32851b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE 32951b93e47SAttilio Rao dca.da_pbufr = bufr; 33051b93e47SAttilio Rao dca.da_pnext = dca.da_pbufr; 33151b93e47SAttilio Rao dca.da_nbufr = sizeof(bufr); 33251b93e47SAttilio Rao dca.da_remain = sizeof(bufr); 33351b93e47SAttilio Rao *dca.da_pnext = '\0'; 33451b93e47SAttilio Rao #else 33551b93e47SAttilio Rao dca.da_pbufr = NULL; 33651b93e47SAttilio Rao #endif 33751b93e47SAttilio Rao 338c7c34a24SBruce Evans va_start(listp, fmt); 3393caaaae0SAttilio Rao retval = kvprintf (fmt, db_putchar, &dca, db_radix, listp); 340c7c34a24SBruce Evans va_end(listp); 34151b93e47SAttilio Rao 34251b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE 34351b93e47SAttilio Rao if (*dca.da_pbufr != '\0') 34451b93e47SAttilio Rao db_puts(dca.da_pbufr); 34551b93e47SAttilio Rao #endif 3463caaaae0SAttilio Rao return (retval); 347c7c34a24SBruce Evans } 348c7c34a24SBruce Evans 349c7c34a24SBruce Evans int db_indent; 350c7c34a24SBruce Evans 351c7c34a24SBruce Evans void 352c7c34a24SBruce Evans db_iprintf(const char *fmt,...) 353c7c34a24SBruce Evans { 35451b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE 35551b93e47SAttilio Rao char bufr[DDB_BUFR_SIZE]; 35651b93e47SAttilio Rao #endif 35751b93e47SAttilio Rao struct dbputchar_arg dca; 358*3e85b721SEd Maste int i; 359c7c34a24SBruce Evans va_list listp; 360c7c34a24SBruce Evans 361c7c34a24SBruce Evans for (i = db_indent; i >= 8; i -= 8) 362c7c34a24SBruce Evans db_printf("\t"); 363c7c34a24SBruce Evans while (--i >= 0) 364c7c34a24SBruce Evans db_printf(" "); 36551b93e47SAttilio Rao 36651b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE 36751b93e47SAttilio Rao dca.da_pbufr = bufr; 36851b93e47SAttilio Rao dca.da_pnext = dca.da_pbufr; 36951b93e47SAttilio Rao dca.da_nbufr = sizeof(bufr); 37051b93e47SAttilio Rao dca.da_remain = sizeof(bufr); 37151b93e47SAttilio Rao *dca.da_pnext = '\0'; 37251b93e47SAttilio Rao #else 37351b93e47SAttilio Rao dca.da_pbufr = NULL; 37451b93e47SAttilio Rao #endif 37551b93e47SAttilio Rao 3765b81b6b3SRodney W. Grimes va_start(listp, fmt); 37751b93e47SAttilio Rao kvprintf (fmt, db_putchar, &dca, db_radix, listp); 3785b81b6b3SRodney W. Grimes va_end(listp); 37951b93e47SAttilio Rao 38051b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE 38151b93e47SAttilio Rao if (*dca.da_pbufr != '\0') 38251b93e47SAttilio Rao db_puts(dca.da_pbufr); 38351b93e47SAttilio Rao #endif 3845b81b6b3SRodney W. Grimes } 3855b81b6b3SRodney W. Grimes 3865b81b6b3SRodney W. Grimes /* 387572de915SRodney W. Grimes * End line if too long. 388572de915SRodney W. Grimes */ 389572de915SRodney W. Grimes void 3902481da74SBruce Evans db_end_line(int field_width) 391572de915SRodney W. Grimes { 3922481da74SBruce Evans if (db_output_position + field_width > db_max_width) 393572de915SRodney W. Grimes db_printf("\n"); 394572de915SRodney W. Grimes } 395