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 static int db_newlines; /* # lines this page */ 70 static int db_maxlines = -1; /* max lines/page when paging */ 71 static db_page_calloutfcn_t *db_page_callout = NULL; 72 static void *db_page_callout_arg = NULL; 73 static int ddb_use_printf = 0; 74 SYSCTL_INT(_debug, OID_AUTO, ddb_use_printf, CTLFLAG_RW, &ddb_use_printf, 0, 75 "use printf for all ddb output"); 76 77 static void db_putchar(int c, void *arg); 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 last_print++; 94 } 95 } 96 else { 97 cnputc(' '); 98 last_print++; 99 } 100 } 101 db_last_non_space = db_output_position; 102 } 103 104 /* 105 * Output character. Buffer whitespace. 106 */ 107 static void 108 db_putchar(c, arg) 109 int c; /* character to output */ 110 void * arg; 111 { 112 113 /* 114 * If not in the debugger or the user requests it, output data to 115 * both the console and the message buffer. 116 */ 117 if (!kdb_active || ddb_use_printf) { 118 printf("%c", c); 119 if (!kdb_active) 120 return; 121 if (c == '\r' || c == '\n') 122 db_check_interrupt(); 123 if (c == '\n' && db_maxlines > 0 && db_page_callout != NULL) { 124 db_newlines++; 125 if (db_newlines >= db_maxlines) { 126 db_maxlines = -1; 127 db_page_callout(db_page_callout_arg); 128 } 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_output_position++; 143 db_last_non_space = db_output_position; 144 } 145 else if (c == '\n') { 146 /* Newline */ 147 db_force_whitespace(); 148 cnputc(c); 149 db_output_position = 0; 150 db_last_non_space = 0; 151 db_check_interrupt(); 152 if (db_maxlines > 0 && db_page_callout != NULL) { 153 db_newlines++; 154 if (db_newlines >= db_maxlines) { 155 db_maxlines = -1; 156 db_page_callout(db_page_callout_arg); 157 } 158 } 159 } 160 else if (c == '\r') { 161 /* Return */ 162 db_force_whitespace(); 163 cnputc(c); 164 db_output_position = 0; 165 db_last_non_space = 0; 166 db_check_interrupt(); 167 } 168 else if (c == '\t') { 169 /* assume tabs every 8 positions */ 170 db_output_position = NEXT_TAB(db_output_position); 171 } 172 else if (c == ' ') { 173 /* space */ 174 db_output_position++; 175 } 176 else if (c == '\007') { 177 /* bell */ 178 cnputc(c); 179 } 180 /* other characters are assumed non-printing */ 181 } 182 183 /* 184 * Register callout for providing a pager for output. 185 */ 186 void 187 db_setup_paging(db_page_calloutfcn_t *callout, void *arg, int maxlines) 188 { 189 190 db_page_callout = callout; 191 db_page_callout_arg = arg; 192 db_maxlines = maxlines; 193 db_newlines = 0; 194 } 195 196 /* 197 * A simple paging callout function. If the argument is not null, it 198 * points to an integer that will be set to 1 if the user asks to quit. 199 */ 200 void 201 db_simple_pager(void *arg) 202 { 203 int c, done; 204 205 db_printf("--More--\r"); 206 done = 0; 207 while (!done) { 208 c = cngetc(); 209 switch (c) { 210 case 'e': 211 case 'j': 212 case '\n': 213 /* Just one more line. */ 214 db_setup_paging(db_simple_pager, arg, 1); 215 done++; 216 break; 217 case 'd': 218 /* Half a page. */ 219 db_setup_paging(db_simple_pager, arg, 220 db_lines_per_page / 2); 221 done++; 222 break; 223 case 'f': 224 case ' ': 225 /* Another page. */ 226 db_setup_paging(db_simple_pager, arg, 227 db_lines_per_page); 228 done++; 229 break; 230 case 'q': 231 case 'Q': 232 case 'x': 233 case 'X': 234 /* Quit */ 235 if (arg != NULL) { 236 *(int *)arg = 1; 237 done++; 238 break; 239 } 240 #if 0 241 /* FALLTHROUGH */ 242 default: 243 cnputc('\007'); 244 #endif 245 } 246 } 247 db_printf(" \r"); 248 } 249 250 /* 251 * Return output position 252 */ 253 int 254 db_print_position() 255 { 256 return (db_output_position); 257 } 258 259 /* 260 * Printing 261 */ 262 void 263 #if __STDC__ 264 db_printf(const char *fmt, ...) 265 #else 266 db_printf(fmt) 267 const char *fmt; 268 #endif 269 { 270 va_list listp; 271 272 va_start(listp, fmt); 273 kvprintf (fmt, db_putchar, NULL, db_radix, listp); 274 va_end(listp); 275 } 276 277 int db_indent; 278 279 void 280 #if __STDC__ 281 db_iprintf(const char *fmt,...) 282 #else 283 db_iprintf(fmt) 284 const char *fmt; 285 #endif 286 { 287 register int i; 288 va_list listp; 289 290 for (i = db_indent; i >= 8; i -= 8) 291 db_printf("\t"); 292 while (--i >= 0) 293 db_printf(" "); 294 va_start(listp, fmt); 295 kvprintf (fmt, db_putchar, NULL, db_radix, listp); 296 va_end(listp); 297 } 298 299 /* 300 * End line if too long. 301 */ 302 void 303 db_end_line() 304 { 305 if (db_output_position >= db_max_width) 306 db_printf("\n"); 307 } 308