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