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