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