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> 38753960f7SDavid E. O'Brien __FBSDID("$FreeBSD$"); 39753960f7SDavid E. O'Brien 40e23851c6SAttilio Rao #include "opt_ddb.h" 41e23851c6SAttilio Rao 42f540b106SGarrett Wollman #include <sys/param.h> 43f540b106SGarrett Wollman #include <sys/systm.h> 44ce9edcf5SPoul-Henning Kamp #include <sys/cons.h> 4537224cd3SMarcel Moolenaar #include <sys/kdb.h> 465de6c5b5SNate Lawson #include <sys/kernel.h> 475de6c5b5SNate Lawson #include <sys/sysctl.h> 485ccbc3ccSBruce Evans 49f540b106SGarrett Wollman #include <machine/stdarg.h> 505ccbc3ccSBruce Evans 51f540b106SGarrett Wollman #include <ddb/ddb.h> 52058284fcSBruce Evans #include <ddb/db_output.h> 535b81b6b3SRodney W. Grimes 5451b93e47SAttilio Rao struct dbputchar_arg { 5551b93e47SAttilio Rao size_t da_nbufr; 5651b93e47SAttilio Rao size_t da_remain; 5751b93e47SAttilio Rao char *da_pbufr; 5851b93e47SAttilio Rao char *da_pnext; 5951b93e47SAttilio Rao }; 6051b93e47SAttilio Rao 615b81b6b3SRodney W. Grimes /* 625b81b6b3SRodney W. Grimes * Character output - tracks position in line. 635b81b6b3SRodney W. Grimes * To do this correctly, we should know how wide 645b81b6b3SRodney W. Grimes * the output device is - then we could zero 655b81b6b3SRodney W. Grimes * the line position when the output device wraps 665b81b6b3SRodney W. Grimes * around to the start of the next line. 675b81b6b3SRodney W. Grimes * 685b81b6b3SRodney W. Grimes * Instead, we count the number of spaces printed 695b81b6b3SRodney W. Grimes * since the last printing character so that we 705b81b6b3SRodney W. Grimes * don't print trailing spaces. This avoids most 715b81b6b3SRodney W. Grimes * of the wraparounds. 725b81b6b3SRodney W. Grimes */ 73f73a856dSPoul-Henning Kamp static int db_output_position = 0; /* output column */ 74f73a856dSPoul-Henning Kamp static int db_last_non_space = 0; /* last non-space character */ 753da6ef3cSBruce Evans db_expr_t db_tab_stop_width = 8; /* how wide are tab stops? */ 764ed3c0e7SPedro F. Giffuni #define NEXT_TAB(i) rounddown((i) + db_tab_stop_width, db_tab_stop_width) 773da6ef3cSBruce Evans db_expr_t db_max_width = 79; /* output line width */ 78d39d4a6eSJohn Baldwin db_expr_t db_lines_per_page = 20; /* lines per page */ 7919e9205aSJohn Baldwin volatile int db_pager_quit; /* user requested quit */ 801e16f609SJohn Baldwin static int db_newlines; /* # lines this page */ 8119e9205aSJohn Baldwin static int db_maxlines; /* max lines/page when paging */ 825de6c5b5SNate Lawson static int ddb_use_printf = 0; 835de6c5b5SNate Lawson SYSCTL_INT(_debug, OID_AUTO, ddb_use_printf, CTLFLAG_RW, &ddb_use_printf, 0, 845de6c5b5SNate Lawson "use printf for all ddb output"); 855b81b6b3SRodney W. Grimes 8651b93e47SAttilio Rao static void db_putc(int c); 8751b93e47SAttilio Rao static void db_puts(const char *str); 8814e10f99SAlfred Perlstein static void db_putchar(int c, void *arg); 8919e9205aSJohn Baldwin static void db_pager(void); 906ddbf1e2SGary Palmer 915b81b6b3SRodney W. Grimes /* 925b81b6b3SRodney W. Grimes * Force pending whitespace. 935b81b6b3SRodney W. Grimes */ 945b81b6b3SRodney W. Grimes void 95a41dd031SPedro F. Giffuni db_force_whitespace(void) 965b81b6b3SRodney W. Grimes { 973e85b721SEd Maste int last_print, next_tab; 985b81b6b3SRodney W. Grimes 995b81b6b3SRodney W. Grimes last_print = db_last_non_space; 1005b81b6b3SRodney W. Grimes while (last_print < db_output_position) { 1015b81b6b3SRodney W. Grimes next_tab = NEXT_TAB(last_print); 1025b81b6b3SRodney W. Grimes if (next_tab <= db_output_position) { 1035b81b6b3SRodney W. Grimes while (last_print < next_tab) { /* DON'T send a tab!!! */ 1045b81b6b3SRodney W. Grimes cnputc(' '); 105086fec57SRobert Watson db_capture_writech(' '); 1065b81b6b3SRodney W. Grimes last_print++; 1075b81b6b3SRodney W. Grimes } 1085b81b6b3SRodney W. Grimes } 1095b81b6b3SRodney W. Grimes else { 1105b81b6b3SRodney W. Grimes cnputc(' '); 111086fec57SRobert Watson db_capture_writech(' '); 1125b81b6b3SRodney W. Grimes last_print++; 1135b81b6b3SRodney W. Grimes } 1145b81b6b3SRodney W. Grimes } 1155b81b6b3SRodney W. Grimes db_last_non_space = db_output_position; 1165b81b6b3SRodney W. Grimes } 1175b81b6b3SRodney W. Grimes 1185b81b6b3SRodney W. Grimes /* 1195b81b6b3SRodney W. Grimes * Output character. Buffer whitespace. 1205b81b6b3SRodney W. Grimes */ 1216ddbf1e2SGary Palmer static void 12251b93e47SAttilio Rao db_putchar(int c, void *arg) 12351b93e47SAttilio Rao { 12451b93e47SAttilio Rao struct dbputchar_arg *dap = arg; 12551b93e47SAttilio Rao 12651b93e47SAttilio Rao if (dap->da_pbufr == NULL) { 12751b93e47SAttilio Rao /* No bufferized output is provided. */ 12851b93e47SAttilio Rao db_putc(c); 12951b93e47SAttilio Rao } else { 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) { 263*3e5e9939SRyan Libby c = db_getc(); 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; 3583e85b721SEd 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