1 /*- 2 * Mach Operating System 3 * Copyright (c) 1991,1990 Carnegie Mellon University 4 * All Rights Reserved. 5 * 6 * Permission to use, copy, modify and distribute this software and its 7 * documentation is hereby granted, provided that both the copyright 8 * notice and this permission notice appear in all copies of the 9 * software, derivative works or modified versions, and any portions 10 * thereof, and that both notices appear in supporting documentation. 11 * 12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15 * 16 * Carnegie Mellon requests users of this software to return to 17 * 18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 19 * School of Computer Science 20 * Carnegie Mellon University 21 * Pittsburgh PA 15213-3890 22 * 23 * any improvements or extensions that they make and grant Carnegie the 24 * rights to redistribute these changes. 25 */ 26 /* 27 * Author: David B. Golub, Carnegie Mellon University 28 * Date: 7/90 29 */ 30 31 /* 32 * Printf and character output for debugger. 33 */ 34 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/cons.h> 41 #include <sys/kdb.h> 42 #include <sys/kernel.h> 43 #include <sys/sysctl.h> 44 45 #include <machine/stdarg.h> 46 47 #include <ddb/ddb.h> 48 #include <ddb/db_output.h> 49 50 /* 51 * Character output - tracks position in line. 52 * To do this correctly, we should know how wide 53 * the output device is - then we could zero 54 * the line position when the output device wraps 55 * around to the start of the next line. 56 * 57 * Instead, we count the number of spaces printed 58 * since the last printing character so that we 59 * don't print trailing spaces. This avoids most 60 * of the wraparounds. 61 */ 62 static int db_output_position = 0; /* output column */ 63 static int db_last_non_space = 0; /* last non-space character */ 64 db_expr_t db_tab_stop_width = 8; /* how wide are tab stops? */ 65 #define NEXT_TAB(i) \ 66 ((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width) 67 db_expr_t db_max_width = 79; /* output line width */ 68 db_expr_t db_lines_per_page = 20; /* lines per page */ 69 volatile int db_pager_quit; /* user requested quit */ 70 static int db_newlines; /* # lines this page */ 71 static int db_maxlines; /* max lines/page when paging */ 72 static int ddb_use_printf = 0; 73 SYSCTL_INT(_debug, OID_AUTO, ddb_use_printf, CTLFLAG_RW, &ddb_use_printf, 0, 74 "use printf for all ddb output"); 75 76 static void db_putchar(int c, void *arg); 77 static void db_pager(void); 78 79 /* 80 * Force pending whitespace. 81 */ 82 void 83 db_force_whitespace() 84 { 85 register int last_print, next_tab; 86 87 last_print = db_last_non_space; 88 while (last_print < db_output_position) { 89 next_tab = NEXT_TAB(last_print); 90 if (next_tab <= db_output_position) { 91 while (last_print < next_tab) { /* DON'T send a tab!!! */ 92 cnputc(' '); 93 db_capture_writech(' '); 94 last_print++; 95 } 96 } 97 else { 98 cnputc(' '); 99 db_capture_writech(' '); 100 last_print++; 101 } 102 } 103 db_last_non_space = db_output_position; 104 } 105 106 /* 107 * Output character. Buffer whitespace. 108 */ 109 static void 110 db_putchar(c, arg) 111 int c; /* character to output */ 112 void * arg; 113 { 114 115 /* 116 * If not in the debugger or the user requests it, output data to 117 * both the console and the message buffer. 118 */ 119 if (!kdb_active || ddb_use_printf) { 120 printf("%c", c); 121 if (!kdb_active) 122 return; 123 if (c == '\r' || c == '\n') 124 db_check_interrupt(); 125 if (c == '\n' && db_maxlines > 0) { 126 db_newlines++; 127 if (db_newlines >= db_maxlines) 128 db_pager(); 129 } 130 return; 131 } 132 133 /* Otherwise, output data directly to the console. */ 134 if (c > ' ' && c <= '~') { 135 /* 136 * Printing character. 137 * If we have spaces to print, print them first. 138 * Use tabs if possible. 139 */ 140 db_force_whitespace(); 141 cnputc(c); 142 db_capture_writech(c); 143 db_output_position++; 144 db_last_non_space = db_output_position; 145 } 146 else if (c == '\n') { 147 /* Newline */ 148 cnputc(c); 149 db_capture_writech(c); 150 db_output_position = 0; 151 db_last_non_space = 0; 152 db_check_interrupt(); 153 if (db_maxlines > 0) { 154 db_newlines++; 155 if (db_newlines >= db_maxlines) 156 db_pager(); 157 } 158 } 159 else if (c == '\r') { 160 /* Return */ 161 cnputc(c); 162 db_capture_writech(c); 163 db_output_position = 0; 164 db_last_non_space = 0; 165 db_check_interrupt(); 166 } 167 else if (c == '\t') { 168 /* assume tabs every 8 positions */ 169 db_output_position = NEXT_TAB(db_output_position); 170 } 171 else if (c == ' ') { 172 /* space */ 173 db_output_position++; 174 } 175 else if (c == '\007') { 176 /* bell */ 177 cnputc(c); 178 /* No need to beep in a log: db_capture_writech(c); */ 179 } 180 /* other characters are assumed non-printing */ 181 } 182 183 /* 184 * Turn on the pager. 185 */ 186 void 187 db_enable_pager(void) 188 { 189 if (db_maxlines == 0) { 190 db_maxlines = db_lines_per_page; 191 db_newlines = 0; 192 db_pager_quit = 0; 193 } 194 } 195 196 /* 197 * Turn off the pager. 198 */ 199 void 200 db_disable_pager(void) 201 { 202 db_maxlines = 0; 203 } 204 205 /* 206 * A simple paging callout function. It supports several simple more(1)-like 207 * commands as well as a quit command that sets db_pager_quit which db 208 * commands can poll to see if they should terminate early. 209 */ 210 void 211 db_pager(void) 212 { 213 int c, done; 214 215 db_capture_enterpager(); 216 db_printf("--More--\r"); 217 done = 0; 218 while (!done) { 219 c = cngetc(); 220 switch (c) { 221 case 'e': 222 case 'j': 223 case '\n': 224 /* Just one more line. */ 225 db_maxlines = 1; 226 done++; 227 break; 228 case 'd': 229 /* Half a page. */ 230 db_maxlines = db_lines_per_page / 2; 231 done++; 232 break; 233 case 'f': 234 case ' ': 235 /* Another page. */ 236 db_maxlines = db_lines_per_page; 237 done++; 238 break; 239 case 'q': 240 case 'Q': 241 case 'x': 242 case 'X': 243 /* Quit */ 244 db_maxlines = 0; 245 db_pager_quit = 1; 246 done++; 247 break; 248 #if 0 249 /* FALLTHROUGH */ 250 default: 251 cnputc('\007'); 252 #endif 253 } 254 } 255 db_printf(" "); 256 db_force_whitespace(); 257 db_printf("\r"); 258 db_newlines = 0; 259 db_capture_exitpager(); 260 } 261 262 /* 263 * Return output position 264 */ 265 int 266 db_print_position() 267 { 268 return (db_output_position); 269 } 270 271 /* 272 * Printing 273 */ 274 void 275 #if __STDC__ 276 db_printf(const char *fmt, ...) 277 #else 278 db_printf(fmt) 279 const char *fmt; 280 #endif 281 { 282 va_list listp; 283 284 va_start(listp, fmt); 285 kvprintf (fmt, db_putchar, NULL, db_radix, listp); 286 va_end(listp); 287 } 288 289 int db_indent; 290 291 void 292 #if __STDC__ 293 db_iprintf(const char *fmt,...) 294 #else 295 db_iprintf(fmt) 296 const char *fmt; 297 #endif 298 { 299 register int i; 300 va_list listp; 301 302 for (i = db_indent; i >= 8; i -= 8) 303 db_printf("\t"); 304 while (--i >= 0) 305 db_printf(" "); 306 va_start(listp, fmt); 307 kvprintf (fmt, db_putchar, NULL, db_radix, listp); 308 va_end(listp); 309 } 310 311 /* 312 * End line if too long. 313 */ 314 void 315 db_end_line(int field_width) 316 { 317 if (db_output_position + field_width > db_max_width) 318 db_printf("\n"); 319 } 320