]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/ddb/db_output.c
Merge branch 'releng/11.3' into releng-CDN/11.3
[FreeBSD/FreeBSD.git] / 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$");
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 }