FreeBSD/Linux Kernel Cross Reference
sys/ddb/db_output.c
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: releng/9.2/sys/ddb/db_output.c 207922 2010-05-11 17:01:14Z attilio $");
37
38 #include "opt_ddb.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/cons.h>
43 #include <sys/kdb.h>
44 #include <sys/kernel.h>
45 #include <sys/sysctl.h>
46
47 #include <machine/stdarg.h>
48
49 #include <ddb/ddb.h>
50 #include <ddb/db_output.h>
51
52 struct dbputchar_arg {
53 size_t da_nbufr;
54 size_t da_remain;
55 char *da_pbufr;
56 char *da_pnext;
57 };
58
59 /*
60 * Character output - tracks position in line.
61 * To do this correctly, we should know how wide
62 * the output device is - then we could zero
63 * the line position when the output device wraps
64 * around to the start of the next line.
65 *
66 * Instead, we count the number of spaces printed
67 * since the last printing character so that we
68 * don't print trailing spaces. This avoids most
69 * of the wraparounds.
70 */
71 static int db_output_position = 0; /* output column */
72 static int db_last_non_space = 0; /* last non-space character */
73 db_expr_t db_tab_stop_width = 8; /* how wide are tab stops? */
74 #define NEXT_TAB(i) \
75 ((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
76 db_expr_t db_max_width = 79; /* output line width */
77 db_expr_t db_lines_per_page = 20; /* lines per page */
78 volatile int db_pager_quit; /* user requested quit */
79 static int db_newlines; /* # lines this page */
80 static int db_maxlines; /* max lines/page when paging */
81 static int ddb_use_printf = 0;
82 SYSCTL_INT(_debug, OID_AUTO, ddb_use_printf, CTLFLAG_RW, &ddb_use_printf, 0,
83 "use printf for all ddb output");
84
85 static void db_putc(int c);
86 static void db_puts(const char *str);
87 static void db_putchar(int c, void *arg);
88 static void db_pager(void);
89
90 /*
91 * Force pending whitespace.
92 */
93 void
94 db_force_whitespace()
95 {
96 register int last_print, next_tab;
97
98 last_print = db_last_non_space;
99 while (last_print < db_output_position) {
100 next_tab = NEXT_TAB(last_print);
101 if (next_tab <= db_output_position) {
102 while (last_print < next_tab) { /* DON'T send a tab!!! */
103 cnputc(' ');
104 db_capture_writech(' ');
105 last_print++;
106 }
107 }
108 else {
109 cnputc(' ');
110 db_capture_writech(' ');
111 last_print++;
112 }
113 }
114 db_last_non_space = db_output_position;
115 }
116
117 /*
118 * Output character. Buffer whitespace.
119 */
120 static void
121 db_putchar(int c, void *arg)
122 {
123 struct dbputchar_arg *dap = arg;
124
125 if (dap->da_pbufr == NULL) {
126
127 /* No bufferized output is provided. */
128 db_putc(c);
129 } else {
130
131 *dap->da_pnext++ = c;
132 dap->da_remain--;
133
134 /* Leave always the buffer 0 terminated. */
135 *dap->da_pnext = '\0';
136
137 /* Check if the buffer needs to be flushed. */
138 if (dap->da_remain < 2 || c == '\n') {
139 db_puts(dap->da_pbufr);
140 dap->da_pnext = dap->da_pbufr;
141 dap->da_remain = dap->da_nbufr;
142 *dap->da_pnext = '\0';
143 }
144 }
145 }
146
147 static void
148 db_putc(int c)
149 {
150
151 /*
152 * If not in the debugger or the user requests it, output data to
153 * both the console and the message buffer.
154 */
155 if (!kdb_active || ddb_use_printf) {
156 printf("%c", c);
157 if (!kdb_active)
158 return;
159 if (c == '\r' || c == '\n')
160 db_check_interrupt();
161 if (c == '\n' && db_maxlines > 0) {
162 db_newlines++;
163 if (db_newlines >= db_maxlines)
164 db_pager();
165 }
166 return;
167 }
168
169 /* Otherwise, output data directly to the console. */
170 if (c > ' ' && c <= '~') {
171 /*
172 * Printing character.
173 * If we have spaces to print, print them first.
174 * Use tabs if possible.
175 */
176 db_force_whitespace();
177 cnputc(c);
178 db_capture_writech(c);
179 db_output_position++;
180 db_last_non_space = db_output_position;
181 }
182 else if (c == '\n') {
183 /* Newline */
184 cnputc(c);
185 db_capture_writech(c);
186 db_output_position = 0;
187 db_last_non_space = 0;
188 db_check_interrupt();
189 if (db_maxlines > 0) {
190 db_newlines++;
191 if (db_newlines >= db_maxlines)
192 db_pager();
193 }
194 }
195 else if (c == '\r') {
196 /* Return */
197 cnputc(c);
198 db_capture_writech(c);
199 db_output_position = 0;
200 db_last_non_space = 0;
201 db_check_interrupt();
202 }
203 else if (c == '\t') {
204 /* assume tabs every 8 positions */
205 db_output_position = NEXT_TAB(db_output_position);
206 }
207 else if (c == ' ') {
208 /* space */
209 db_output_position++;
210 }
211 else if (c == '\007') {
212 /* bell */
213 cnputc(c);
214 /* No need to beep in a log: db_capture_writech(c); */
215 }
216 /* other characters are assumed non-printing */
217 }
218
219 static void
220 db_puts(const char *str)
221 {
222 int i;
223
224 for (i = 0; str[i] != '\0'; i++)
225 db_putc(str[i]);
226 }
227
228 /*
229 * Turn on the pager.
230 */
231 void
232 db_enable_pager(void)
233 {
234 if (db_maxlines == 0) {
235 db_maxlines = db_lines_per_page;
236 db_newlines = 0;
237 db_pager_quit = 0;
238 }
239 }
240
241 /*
242 * Turn off the pager.
243 */
244 void
245 db_disable_pager(void)
246 {
247 db_maxlines = 0;
248 }
249
250 /*
251 * A simple paging callout function. It supports several simple more(1)-like
252 * commands as well as a quit command that sets db_pager_quit which db
253 * commands can poll to see if they should terminate early.
254 */
255 void
256 db_pager(void)
257 {
258 int c, done;
259
260 db_capture_enterpager();
261 db_printf("--More--\r");
262 done = 0;
263 while (!done) {
264 c = cngetc();
265 switch (c) {
266 case 'e':
267 case 'j':
268 case '\n':
269 /* Just one more line. */
270 db_maxlines = 1;
271 done++;
272 break;
273 case 'd':
274 /* Half a page. */
275 db_maxlines = db_lines_per_page / 2;
276 done++;
277 break;
278 case 'f':
279 case ' ':
280 /* Another page. */
281 db_maxlines = db_lines_per_page;
282 done++;
283 break;
284 case 'q':
285 case 'Q':
286 case 'x':
287 case 'X':
288 /* Quit */
289 db_maxlines = 0;
290 db_pager_quit = 1;
291 done++;
292 break;
293 #if 0
294 /* FALLTHROUGH */
295 default:
296 cnputc('\007');
297 #endif
298 }
299 }
300 db_printf(" ");
301 db_force_whitespace();
302 db_printf("\r");
303 db_newlines = 0;
304 db_capture_exitpager();
305 }
306
307 /*
308 * Return output position
309 */
310 int
311 db_print_position()
312 {
313 return (db_output_position);
314 }
315
316 /*
317 * Printing
318 */
319 int
320 db_printf(const char *fmt, ...)
321 {
322 #ifdef DDB_BUFR_SIZE
323 char bufr[DDB_BUFR_SIZE];
324 #endif
325 struct dbputchar_arg dca;
326 va_list listp;
327 int retval;
328
329 #ifdef DDB_BUFR_SIZE
330 dca.da_pbufr = bufr;
331 dca.da_pnext = dca.da_pbufr;
332 dca.da_nbufr = sizeof(bufr);
333 dca.da_remain = sizeof(bufr);
334 *dca.da_pnext = '\0';
335 #else
336 dca.da_pbufr = NULL;
337 #endif
338
339 va_start(listp, fmt);
340 retval = kvprintf (fmt, db_putchar, &dca, db_radix, listp);
341 va_end(listp);
342
343 #ifdef DDB_BUFR_SIZE
344 if (*dca.da_pbufr != '\0')
345 db_puts(dca.da_pbufr);
346 #endif
347 return (retval);
348 }
349
350 int db_indent;
351
352 void
353 db_iprintf(const char *fmt,...)
354 {
355 #ifdef DDB_BUFR_SIZE
356 char bufr[DDB_BUFR_SIZE];
357 #endif
358 struct dbputchar_arg dca;
359 register int i;
360 va_list listp;
361
362 for (i = db_indent; i >= 8; i -= 8)
363 db_printf("\t");
364 while (--i >= 0)
365 db_printf(" ");
366
367 #ifdef DDB_BUFR_SIZE
368 dca.da_pbufr = bufr;
369 dca.da_pnext = dca.da_pbufr;
370 dca.da_nbufr = sizeof(bufr);
371 dca.da_remain = sizeof(bufr);
372 *dca.da_pnext = '\0';
373 #else
374 dca.da_pbufr = NULL;
375 #endif
376
377 va_start(listp, fmt);
378 kvprintf (fmt, db_putchar, &dca, db_radix, listp);
379 va_end(listp);
380
381 #ifdef DDB_BUFR_SIZE
382 if (*dca.da_pbufr != '\0')
383 db_puts(dca.da_pbufr);
384 #endif
385 }
386
387 /*
388 * End line if too long.
389 */
390 void
391 db_end_line(int field_width)
392 {
393 if (db_output_position + field_width > db_max_width)
394 db_printf("\n");
395 }
Cache object: 2aff8c5a09a1e3436b2919497273308c
|