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 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 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 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 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 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 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 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 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 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 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 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