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 if (db_page_callout == NULL || callout == NULL || arg == 191 db_page_callout_arg) { 192 db_page_callout = callout; 193 db_page_callout_arg = arg; 194 db_maxlines = maxlines; 195 db_newlines = 0; 196 } 197 } 198 199 /* 200 * A simple paging callout function. If the argument is not null, it 201 * points to an integer that will be set to 1 if the user asks to quit. 202 */ 203 void 204 db_simple_pager(void *arg) 205 { 206 int c, done; 207 208 db_printf("--More--\r"); 209 done = 0; 210 while (!done) { 211 c = cngetc(); 212 switch (c) { 213 case 'e': 214 case 'j': 215 case '\n': 216 /* Just one more line. */ 217 db_setup_paging(db_simple_pager, arg, 1); 218 done++; 219 break; 220 case 'd': 221 /* Half a page. */ 222 db_setup_paging(db_simple_pager, arg, 223 db_lines_per_page / 2); 224 done++; 225 break; 226 case 'f': 227 case ' ': 228 /* Another page. */ 229 db_setup_paging(db_simple_pager, arg, 230 db_lines_per_page); 231 done++; 232 break; 233 case 'q': 234 case 'Q': 235 case 'x': 236 case 'X': 237 /* Quit */ 238 if (arg != NULL) { 239 *(int *)arg = 1; 240 done++; 241 break; 242 } 243 #if 0 244 /* FALLTHROUGH */ 245 default: 246 cnputc('\007'); 247 #endif 248 } 249 } 250 db_printf(" \r"); 251 } 252 253 /* 254 * Return output position 255 */ 256 int 257 db_print_position() 258 { 259 return (db_output_position); 260 } 261 262 /* 263 * Printing 264 */ 265 void 266 #if __STDC__ 267 db_printf(const char *fmt, ...) 268 #else 269 db_printf(fmt) 270 const char *fmt; 271 #endif 272 { 273 va_list listp; 274 275 va_start(listp, fmt); 276 kvprintf (fmt, db_putchar, NULL, db_radix, listp); 277 va_end(listp); 278 } 279 280 int db_indent; 281 282 void 283 #if __STDC__ 284 db_iprintf(const char *fmt,...) 285 #else 286 db_iprintf(fmt) 287 const char *fmt; 288 #endif 289 { 290 register int i; 291 va_list listp; 292 293 for (i = db_indent; i >= 8; i -= 8) 294 db_printf("\t"); 295 while (--i >= 0) 296 db_printf(" "); 297 va_start(listp, fmt); 298 kvprintf (fmt, db_putchar, NULL, db_radix, listp); 299 va_end(listp); 300 } 301 302 /* 303 * End line if too long. 304 */ 305 void 306 db_end_line() 307 { 308 if (db_output_position >= db_max_width) 309 db_printf("\n"); 310 } 311