1dd3cb568SWarner Losh /*- 2*796df753SPedro F. Giffuni * SPDX-License-Identifier: MIT-CMU 3*796df753SPedro 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 12851b93e47SAttilio Rao /* No bufferized output is provided. */ 12951b93e47SAttilio Rao db_putc(c); 13051b93e47SAttilio Rao } else { 13151b93e47SAttilio Rao 13251b93e47SAttilio Rao *dap->da_pnext++ = c; 13351b93e47SAttilio Rao dap->da_remain--; 13451b93e47SAttilio Rao 13551b93e47SAttilio Rao /* Leave always the buffer 0 terminated. */ 13651b93e47SAttilio Rao *dap->da_pnext = '\0'; 13751b93e47SAttilio Rao 13851b93e47SAttilio Rao /* Check if the buffer needs to be flushed. */ 13951b93e47SAttilio Rao if (dap->da_remain < 2 || c == '\n') { 14051b93e47SAttilio Rao db_puts(dap->da_pbufr); 14151b93e47SAttilio Rao dap->da_pnext = dap->da_pbufr; 14251b93e47SAttilio Rao dap->da_remain = dap->da_nbufr; 14351b93e47SAttilio Rao *dap->da_pnext = '\0'; 14451b93e47SAttilio Rao } 14551b93e47SAttilio Rao } 14651b93e47SAttilio Rao } 14751b93e47SAttilio Rao 14851b93e47SAttilio Rao static void 14951b93e47SAttilio Rao db_putc(int c) 1505b81b6b3SRodney W. Grimes { 1511e16f609SJohn Baldwin 1525de6c5b5SNate Lawson /* 1535de6c5b5SNate Lawson * If not in the debugger or the user requests it, output data to 1545de6c5b5SNate Lawson * both the console and the message buffer. 1555de6c5b5SNate Lawson */ 15637224cd3SMarcel Moolenaar if (!kdb_active || ddb_use_printf) { 1575de6c5b5SNate Lawson printf("%c", c); 15837224cd3SMarcel Moolenaar if (!kdb_active) 1595de6c5b5SNate Lawson return; 1605de6c5b5SNate Lawson if (c == '\r' || c == '\n') 1615de6c5b5SNate Lawson db_check_interrupt(); 16219e9205aSJohn Baldwin if (c == '\n' && db_maxlines > 0) { 1635de6c5b5SNate Lawson db_newlines++; 16419e9205aSJohn Baldwin if (db_newlines >= db_maxlines) 16519e9205aSJohn Baldwin db_pager(); 1665de6c5b5SNate Lawson } 1675de6c5b5SNate Lawson return; 1685de6c5b5SNate Lawson } 1695de6c5b5SNate Lawson 1705de6c5b5SNate Lawson /* Otherwise, output data directly to the console. */ 1715b81b6b3SRodney W. Grimes if (c > ' ' && c <= '~') { 1725b81b6b3SRodney W. Grimes /* 1735b81b6b3SRodney W. Grimes * Printing character. 1745b81b6b3SRodney W. Grimes * If we have spaces to print, print them first. 1755b81b6b3SRodney W. Grimes * Use tabs if possible. 1765b81b6b3SRodney W. Grimes */ 1775b81b6b3SRodney W. Grimes db_force_whitespace(); 1785b81b6b3SRodney W. Grimes cnputc(c); 179086fec57SRobert Watson db_capture_writech(c); 1805b81b6b3SRodney W. Grimes db_output_position++; 1815b81b6b3SRodney W. Grimes db_last_non_space = db_output_position; 1825b81b6b3SRodney W. Grimes } 1835b81b6b3SRodney W. Grimes else if (c == '\n') { 1848a129caeSDavid Greenman /* Newline */ 1858a129caeSDavid Greenman cnputc(c); 186086fec57SRobert Watson db_capture_writech(c); 1878a129caeSDavid Greenman db_output_position = 0; 1888a129caeSDavid Greenman db_last_non_space = 0; 1898a129caeSDavid Greenman db_check_interrupt(); 19019e9205aSJohn Baldwin if (db_maxlines > 0) { 1911e16f609SJohn Baldwin db_newlines++; 19219e9205aSJohn Baldwin if (db_newlines >= db_maxlines) 19319e9205aSJohn Baldwin db_pager(); 1941e16f609SJohn Baldwin } 1958a129caeSDavid Greenman } 1968a129caeSDavid Greenman else if (c == '\r') { 1975b81b6b3SRodney W. Grimes /* Return */ 1985b81b6b3SRodney W. Grimes cnputc(c); 199086fec57SRobert Watson db_capture_writech(c); 2005b81b6b3SRodney W. Grimes db_output_position = 0; 2015b81b6b3SRodney W. Grimes db_last_non_space = 0; 2025b81b6b3SRodney W. Grimes db_check_interrupt(); 2035b81b6b3SRodney W. Grimes } 2045b81b6b3SRodney W. Grimes else if (c == '\t') { 2055b81b6b3SRodney W. Grimes /* assume tabs every 8 positions */ 2065b81b6b3SRodney W. Grimes db_output_position = NEXT_TAB(db_output_position); 2075b81b6b3SRodney W. Grimes } 2085b81b6b3SRodney W. Grimes else if (c == ' ') { 2095b81b6b3SRodney W. Grimes /* space */ 2105b81b6b3SRodney W. Grimes db_output_position++; 2115b81b6b3SRodney W. Grimes } 2125b81b6b3SRodney W. Grimes else if (c == '\007') { 2135b81b6b3SRodney W. Grimes /* bell */ 2145b81b6b3SRodney W. Grimes cnputc(c); 215086fec57SRobert Watson /* No need to beep in a log: db_capture_writech(c); */ 2165b81b6b3SRodney W. Grimes } 2175b81b6b3SRodney W. Grimes /* other characters are assumed non-printing */ 2185b81b6b3SRodney W. Grimes } 2195b81b6b3SRodney W. Grimes 22051b93e47SAttilio Rao static void 22151b93e47SAttilio Rao db_puts(const char *str) 22251b93e47SAttilio Rao { 22351b93e47SAttilio Rao int i; 22451b93e47SAttilio Rao 22551b93e47SAttilio Rao for (i = 0; str[i] != '\0'; i++) 22651b93e47SAttilio Rao db_putc(str[i]); 22751b93e47SAttilio Rao } 22851b93e47SAttilio Rao 2295b81b6b3SRodney W. Grimes /* 23019e9205aSJohn Baldwin * Turn on the pager. 2311e16f609SJohn Baldwin */ 2321e16f609SJohn Baldwin void 23319e9205aSJohn Baldwin db_enable_pager(void) 2341e16f609SJohn Baldwin { 23519e9205aSJohn Baldwin if (db_maxlines == 0) { 23619e9205aSJohn Baldwin db_maxlines = db_lines_per_page; 2371e16f609SJohn Baldwin db_newlines = 0; 23819e9205aSJohn Baldwin db_pager_quit = 0; 2391e16f609SJohn Baldwin } 240da927f93SOlivier Houchard } 2411e16f609SJohn Baldwin 2421e16f609SJohn Baldwin /* 24319e9205aSJohn Baldwin * Turn off the pager. 2441e16f609SJohn Baldwin */ 2451e16f609SJohn Baldwin void 24619e9205aSJohn Baldwin db_disable_pager(void) 24719e9205aSJohn Baldwin { 24819e9205aSJohn Baldwin db_maxlines = 0; 24919e9205aSJohn Baldwin } 25019e9205aSJohn Baldwin 25119e9205aSJohn Baldwin /* 25219e9205aSJohn Baldwin * A simple paging callout function. It supports several simple more(1)-like 25319e9205aSJohn Baldwin * commands as well as a quit command that sets db_pager_quit which db 25419e9205aSJohn Baldwin * commands can poll to see if they should terminate early. 25519e9205aSJohn Baldwin */ 25619e9205aSJohn Baldwin void 25719e9205aSJohn Baldwin db_pager(void) 2581e16f609SJohn Baldwin { 259d39d4a6eSJohn Baldwin int c, done; 2601e16f609SJohn Baldwin 261086fec57SRobert Watson db_capture_enterpager(); 2621e16f609SJohn Baldwin db_printf("--More--\r"); 263d39d4a6eSJohn Baldwin done = 0; 264d39d4a6eSJohn Baldwin while (!done) { 2651e16f609SJohn Baldwin c = cngetc(); 2661e16f609SJohn Baldwin switch (c) { 267d39d4a6eSJohn Baldwin case 'e': 268d39d4a6eSJohn Baldwin case 'j': 2691e16f609SJohn Baldwin case '\n': 2701e16f609SJohn Baldwin /* Just one more line. */ 27119e9205aSJohn Baldwin db_maxlines = 1; 272d39d4a6eSJohn Baldwin done++; 273d39d4a6eSJohn Baldwin break; 274d39d4a6eSJohn Baldwin case 'd': 275d39d4a6eSJohn Baldwin /* Half a page. */ 27619e9205aSJohn Baldwin db_maxlines = db_lines_per_page / 2; 277d39d4a6eSJohn Baldwin done++; 278d39d4a6eSJohn Baldwin break; 279d39d4a6eSJohn Baldwin case 'f': 2801e16f609SJohn Baldwin case ' ': 2811e16f609SJohn Baldwin /* Another page. */ 28219e9205aSJohn Baldwin db_maxlines = db_lines_per_page; 283d39d4a6eSJohn Baldwin done++; 284d39d4a6eSJohn Baldwin break; 2851e16f609SJohn Baldwin case 'q': 2861e16f609SJohn Baldwin case 'Q': 2871e16f609SJohn Baldwin case 'x': 2881e16f609SJohn Baldwin case 'X': 2891e16f609SJohn Baldwin /* Quit */ 29019e9205aSJohn Baldwin db_maxlines = 0; 29119e9205aSJohn Baldwin db_pager_quit = 1; 292d39d4a6eSJohn Baldwin done++; 293d39d4a6eSJohn Baldwin break; 2941e16f609SJohn Baldwin #if 0 2951e16f609SJohn Baldwin /* FALLTHROUGH */ 2961e16f609SJohn Baldwin default: 2971e16f609SJohn Baldwin cnputc('\007'); 2981e16f609SJohn Baldwin #endif 2991e16f609SJohn Baldwin } 3001e16f609SJohn Baldwin } 301c7eeb59dSBruce Evans db_printf(" "); 302c7eeb59dSBruce Evans db_force_whitespace(); 303d39d4a6eSJohn Baldwin db_printf("\r"); 30419e9205aSJohn Baldwin db_newlines = 0; 305086fec57SRobert Watson db_capture_exitpager(); 3061e16f609SJohn Baldwin } 3071e16f609SJohn Baldwin 3081e16f609SJohn Baldwin /* 3095b81b6b3SRodney W. Grimes * Return output position 3105b81b6b3SRodney W. Grimes */ 3115b81b6b3SRodney W. Grimes int 312a41dd031SPedro F. Giffuni db_print_position(void) 3135b81b6b3SRodney W. Grimes { 3145b81b6b3SRodney W. Grimes return (db_output_position); 3155b81b6b3SRodney W. Grimes } 3165b81b6b3SRodney W. Grimes 3175b81b6b3SRodney W. Grimes /* 3185b81b6b3SRodney W. Grimes * Printing 3195b81b6b3SRodney W. Grimes */ 3203caaaae0SAttilio Rao int 321381fe1aaSGarrett Wollman db_printf(const char *fmt, ...) 3225b81b6b3SRodney W. Grimes { 32351b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE 32451b93e47SAttilio Rao char bufr[DDB_BUFR_SIZE]; 32551b93e47SAttilio Rao #endif 32651b93e47SAttilio Rao struct dbputchar_arg dca; 3275b81b6b3SRodney W. Grimes va_list listp; 3283caaaae0SAttilio Rao int retval; 329c7c34a24SBruce Evans 33051b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE 33151b93e47SAttilio Rao dca.da_pbufr = bufr; 33251b93e47SAttilio Rao dca.da_pnext = dca.da_pbufr; 33351b93e47SAttilio Rao dca.da_nbufr = sizeof(bufr); 33451b93e47SAttilio Rao dca.da_remain = sizeof(bufr); 33551b93e47SAttilio Rao *dca.da_pnext = '\0'; 33651b93e47SAttilio Rao #else 33751b93e47SAttilio Rao dca.da_pbufr = NULL; 33851b93e47SAttilio Rao #endif 33951b93e47SAttilio Rao 340c7c34a24SBruce Evans va_start(listp, fmt); 3413caaaae0SAttilio Rao retval = kvprintf (fmt, db_putchar, &dca, db_radix, listp); 342c7c34a24SBruce Evans va_end(listp); 34351b93e47SAttilio Rao 34451b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE 34551b93e47SAttilio Rao if (*dca.da_pbufr != '\0') 34651b93e47SAttilio Rao db_puts(dca.da_pbufr); 34751b93e47SAttilio Rao #endif 3483caaaae0SAttilio Rao return (retval); 349c7c34a24SBruce Evans } 350c7c34a24SBruce Evans 351c7c34a24SBruce Evans int db_indent; 352c7c34a24SBruce Evans 353c7c34a24SBruce Evans void 354c7c34a24SBruce Evans db_iprintf(const char *fmt,...) 355c7c34a24SBruce Evans { 35651b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE 35751b93e47SAttilio Rao char bufr[DDB_BUFR_SIZE]; 35851b93e47SAttilio Rao #endif 35951b93e47SAttilio Rao struct dbputchar_arg dca; 3603e85b721SEd Maste int i; 361c7c34a24SBruce Evans va_list listp; 362c7c34a24SBruce Evans 363c7c34a24SBruce Evans for (i = db_indent; i >= 8; i -= 8) 364c7c34a24SBruce Evans db_printf("\t"); 365c7c34a24SBruce Evans while (--i >= 0) 366c7c34a24SBruce Evans db_printf(" "); 36751b93e47SAttilio Rao 36851b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE 36951b93e47SAttilio Rao dca.da_pbufr = bufr; 37051b93e47SAttilio Rao dca.da_pnext = dca.da_pbufr; 37151b93e47SAttilio Rao dca.da_nbufr = sizeof(bufr); 37251b93e47SAttilio Rao dca.da_remain = sizeof(bufr); 37351b93e47SAttilio Rao *dca.da_pnext = '\0'; 37451b93e47SAttilio Rao #else 37551b93e47SAttilio Rao dca.da_pbufr = NULL; 37651b93e47SAttilio Rao #endif 37751b93e47SAttilio Rao 3785b81b6b3SRodney W. Grimes va_start(listp, fmt); 37951b93e47SAttilio Rao kvprintf (fmt, db_putchar, &dca, db_radix, listp); 3805b81b6b3SRodney W. Grimes va_end(listp); 38151b93e47SAttilio Rao 38251b93e47SAttilio Rao #ifdef DDB_BUFR_SIZE 38351b93e47SAttilio Rao if (*dca.da_pbufr != '\0') 38451b93e47SAttilio Rao db_puts(dca.da_pbufr); 38551b93e47SAttilio Rao #endif 3865b81b6b3SRodney W. Grimes } 3875b81b6b3SRodney W. Grimes 3885b81b6b3SRodney W. Grimes /* 389572de915SRodney W. Grimes * End line if too long. 390572de915SRodney W. Grimes */ 391572de915SRodney W. Grimes void 3922481da74SBruce Evans db_end_line(int field_width) 393572de915SRodney W. Grimes { 3942481da74SBruce Evans if (db_output_position + field_width > db_max_width) 395572de915SRodney W. Grimes db_printf("\n"); 396572de915SRodney W. Grimes } 397