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 static int db_newlines; /* # lines this page */ 69 static int db_maxlines = -1; /* max lines per page */ 70 static db_page_calloutfcn_t *db_page_callout = NULL; 71 static void *db_page_callout_arg = NULL; 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 78 /* 79 * Force pending whitespace. 80 */ 81 void 82 db_force_whitespace() 83 { 84 register int last_print, next_tab; 85 86 last_print = db_last_non_space; 87 while (last_print < db_output_position) { 88 next_tab = NEXT_TAB(last_print); 89 if (next_tab <= db_output_position) { 90 while (last_print < next_tab) { /* DON'T send a tab!!! */ 91 cnputc(' '); 92 last_print++; 93 } 94 } 95 else { 96 cnputc(' '); 97 last_print++; 98 } 99 } 100 db_last_non_space = db_output_position; 101 } 102 103 /* 104 * Output character. Buffer whitespace. 105 */ 106 static void 107 db_putchar(c, arg) 108 int c; /* character to output */ 109 void * arg; 110 { 111 112 /* 113 * If not in the debugger or the user requests it, output data to 114 * both the console and the message buffer. 115 */ 116 if (!kdb_active || ddb_use_printf) { 117 printf("%c", c); 118 if (!kdb_active) 119 return; 120 if (c == '\r' || c == '\n') 121 db_check_interrupt(); 122 if (c == '\n' && db_maxlines > 0 && db_page_callout != NULL) { 123 db_newlines++; 124 if (db_newlines >= db_maxlines) { 125 db_maxlines = -1; 126 db_page_callout(db_page_callout_arg); 127 } 128 } 129 return; 130 } 131 132 /* Otherwise, output data directly to the console. */ 133 if (c > ' ' && c <= '~') { 134 /* 135 * Printing character. 136 * If we have spaces to print, print them first. 137 * Use tabs if possible. 138 */ 139 db_force_whitespace(); 140 cnputc(c); 141 db_output_position++; 142 db_last_non_space = db_output_position; 143 } 144 else if (c == '\n') { 145 /* Newline */ 146 cnputc(c); 147 db_output_position = 0; 148 db_last_non_space = 0; 149 db_check_interrupt(); 150 if (db_maxlines > 0 && db_page_callout != NULL) { 151 db_newlines++; 152 if (db_newlines >= db_maxlines) { 153 db_maxlines = -1; 154 db_page_callout(db_page_callout_arg); 155 } 156 } 157 } 158 else if (c == '\r') { 159 /* Return */ 160 cnputc(c); 161 db_output_position = 0; 162 db_last_non_space = 0; 163 db_check_interrupt(); 164 } 165 else if (c == '\t') { 166 /* assume tabs every 8 positions */ 167 db_output_position = NEXT_TAB(db_output_position); 168 } 169 else if (c == ' ') { 170 /* space */ 171 db_output_position++; 172 } 173 else if (c == '\007') { 174 /* bell */ 175 cnputc(c); 176 } 177 /* other characters are assumed non-printing */ 178 } 179 180 /* 181 * Register callout for providing a pager for output. 182 */ 183 void 184 db_setup_paging(db_page_calloutfcn_t *callout, void *arg, int maxlines) 185 { 186 187 db_page_callout = callout; 188 db_page_callout_arg = arg; 189 db_maxlines = maxlines; 190 db_newlines = 0; 191 } 192 193 /* 194 * A simple paging callout function. If the argument is not null, it 195 * points to an integer that will be set to 1 if the user asks to quit. 196 */ 197 void 198 db_simple_pager(void *arg) 199 { 200 int c; 201 202 db_printf("--More--\r"); 203 for (;;) { 204 c = cngetc(); 205 switch (c) { 206 case '\n': 207 /* Just one more line. */ 208 db_setup_paging(db_simple_pager, arg, 1); 209 return; 210 case ' ': 211 /* Another page. */ 212 db_setup_paging(db_simple_pager, arg, 213 DB_LINES_PER_PAGE); 214 return; 215 case 'q': 216 case 'Q': 217 case 'x': 218 case 'X': 219 /* Quit */ 220 if (arg != NULL) { 221 *(int *)arg = 1; 222 db_printf("\n"); 223 return; 224 } 225 #if 0 226 /* FALLTHROUGH */ 227 default: 228 cnputc('\007'); 229 #endif 230 } 231 } 232 } 233 234 /* 235 * Return output position 236 */ 237 int 238 db_print_position() 239 { 240 return (db_output_position); 241 } 242 243 /* 244 * Printing 245 */ 246 void 247 #if __STDC__ 248 db_printf(const char *fmt, ...) 249 #else 250 db_printf(fmt) 251 const char *fmt; 252 #endif 253 { 254 va_list listp; 255 256 va_start(listp, fmt); 257 kvprintf (fmt, db_putchar, NULL, db_radix, listp); 258 va_end(listp); 259 } 260 261 int db_indent; 262 263 void 264 #if __STDC__ 265 db_iprintf(const char *fmt,...) 266 #else 267 db_iprintf(fmt) 268 const char *fmt; 269 #endif 270 { 271 register int i; 272 va_list listp; 273 274 for (i = db_indent; i >= 8; i -= 8) 275 db_printf("\t"); 276 while (--i >= 0) 277 db_printf(" "); 278 va_start(listp, fmt); 279 kvprintf (fmt, db_putchar, NULL, db_radix, listp); 280 va_end(listp); 281 } 282 283 /* 284 * End line if too long. 285 */ 286 void 287 db_end_line() 288 { 289 if (db_output_position >= db_max_width) 290 db_printf("\n"); 291 } 292