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