1 /* $OpenBSD: db_output.c,v 1.22 2004/01/03 14:08:53 espie Exp $ */
2 /* $NetBSD: db_output.c,v 1.13 1996/04/01 17:27:14 christos Exp $ */
3
4 /*
5 * Mach Operating System
6 * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
7 * All Rights Reserved.
8 *
9 * Permission to use, copy, modify and distribute this software and its
10 * documentation is hereby granted, provided that both the copyright
11 * notice and this permission notice appear in all copies of the
12 * software, derivative works or modified versions, and any portions
13 * thereof, and that both notices appear in supporting documentation.
14 *
15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 *
19 * Carnegie Mellon requests users of this software to return to
20 *
21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
22 * School of Computer Science
23 * Carnegie Mellon University
24 * Pittsburgh PA 15213-3890
25 *
26 * any improvements or extensions that they make and grant Carnegie Mellon
27 * the rights to redistribute these changes.
28 */
29
30 /*
31 * Printf and character output for debugger.
32 */
33 #include <sys/param.h>
34 #include <sys/proc.h>
35
36 #include <sys/stdarg.h>
37
38 #include <dev/cons.h>
39
40 #include <uvm/uvm_extern.h>
41
42 #include <machine/db_machdep.h>
43
44 #include <ddb/db_command.h>
45 #include <ddb/db_output.h>
46 #include <ddb/db_interface.h>
47 #include <ddb/db_sym.h>
48 #include <ddb/db_var.h>
49 #include <ddb/db_extern.h>
50
51 #include <sys/slibkern.h>
52
53 /*
54 * Character output - tracks position in line.
55 * To do this correctly, we should know how wide
56 * the output device is - then we could zero
57 * the line position when the output device wraps
58 * around to the start of the next line.
59 *
60 * Instead, we count the number of spaces printed
61 * since the last printing character so that we
62 * don't print trailing spaces. This avoids most
63 * of the wraparounds.
64 */
65
66 #ifndef DB_MAX_LINE
67 #define DB_MAX_LINE 24 /* maximum line */
68 #define DB_MAX_WIDTH 80 /* maximum width */
69 #endif /* DB_MAX_LINE */
70
71 #define DB_MIN_MAX_WIDTH 20 /* minimum max width */
72 #define DB_MIN_MAX_LINE 3 /* minimum max line */
73 #define CTRL(c) ((c) & 0xff)
74
75 int db_output_position = 0; /* output column */
76 int db_output_line = 0; /* output line number */
77 int db_last_non_space = 0; /* last non-space character */
78 int db_tab_stop_width = 8; /* how wide are tab stops? */
79 #define NEXT_TAB(i) \
80 ((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
81 int db_max_line = DB_MAX_LINE; /* output max lines */
82 int db_max_width = DB_MAX_WIDTH; /* output line width */
83 int db_radix = 16; /* output numbers radix */
84
85 #ifdef DDB
86 static void db_more(void);
87 #endif
88
89 /*
90 * Force pending whitespace.
91 */
92 void
db_force_whitespace()93 db_force_whitespace()
94 {
95 register 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 last_print++;
104 }
105 }
106 else {
107 cnputc(' ');
108 last_print++;
109 }
110 }
111 db_last_non_space = db_output_position;
112 }
113
114 #ifdef DDB
115 static void
db_more()116 db_more()
117 {
118 register char *p;
119 int quit_output = 0;
120
121 for (p = "--db_more--"; *p; p++)
122 cnputc(*p);
123 switch(cngetc()) {
124 case ' ':
125 db_output_line = 0;
126 break;
127 case 'q':
128 case CTRL('c'):
129 db_output_line = 0;
130 quit_output = 1;
131 break;
132 default:
133 db_output_line--;
134 break;
135 }
136 p = "\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b";
137 while (*p)
138 cnputc(*p++);
139 if (quit_output) {
140 db_error(0);
141 /* NOTREACHED */
142 }
143 }
144 #endif
145
146 /*
147 * Output character. Buffer whitespace.
148 */
149 void
db_putchar(c)150 db_putchar(c)
151 int c; /* character to output */
152 {
153 #ifdef DDB
154 if (db_max_line >= DB_MIN_MAX_LINE && db_output_line >= db_max_line-1)
155 db_more();
156 #endif
157 if (c > ' ' && c <= '~') {
158 /*
159 * Printing character.
160 * If we have spaces to print, print them first.
161 * Use tabs if possible.
162 */
163 db_force_whitespace();
164 cnputc(c);
165 db_output_position++;
166 if (db_max_width >= DB_MIN_MAX_WIDTH
167 && db_output_position >= db_max_width-1) {
168 /* auto new line */
169 cnputc('\n');
170 db_output_position = 0;
171 db_last_non_space = 0;
172 db_output_line++;
173 }
174 db_last_non_space = db_output_position;
175 }
176 else if (c == '\n') {
177 /* Return */
178 cnputc(c);
179 db_output_position = 0;
180 db_last_non_space = 0;
181 db_output_line++;
182 #ifdef DDB
183 db_check_interrupt();
184 #endif
185 }
186 else if (c == '\t') {
187 /* assume tabs every 8 positions */
188 db_output_position = NEXT_TAB(db_output_position);
189 }
190 else if (c == ' ') {
191 /* space */
192 db_output_position++;
193 }
194 else if (c == '\007') {
195 /* bell */
196 cnputc(c);
197 }
198 /* other characters are assumed non-printing */
199 }
200
201 /*
202 * Return output position
203 */
204 int
db_print_position()205 db_print_position()
206 {
207 return (db_output_position);
208 }
209
210 /*
211 * End line if too long.
212 */
213 void
db_end_line(space)214 db_end_line(space)
215 int space;
216 {
217 if (db_output_position >= db_max_width - space)
218 db_printf("\n");
219 }
220
221 char *
db_format(char * buf,size_t bufsize,long val,int format,int alt,int width)222 db_format(char *buf, size_t bufsize, long val, int format, int alt, int width)
223 {
224 const char *fmt;
225
226 if (format == DB_FORMAT_Z || db_radix == 16)
227 fmt = alt ? "-%#*lx" : "-%*lx";
228 else if (db_radix == 8)
229 fmt = alt ? "-%#*lo" : "-%*lo";
230 else
231 fmt = alt ? "-%#*lu" : "-%*lu";
232
233 /* The leading '-' is a nasty (and beautiful) idea from NetBSD */
234 if (val < 0 && format != DB_FORMAT_N)
235 val = -val;
236 else
237 fmt++;
238
239 snprintf(buf, bufsize, fmt, width, val);
240
241 return (buf);
242 }
243
244 void
db_stack_dump(void)245 db_stack_dump(void)
246 {
247 static int intrace;
248
249 if (intrace) {
250 printf("Faulted in traceback, aborting...\n");
251 return;
252 }
253
254 intrace = 1;
255 printf("Starting stack trace...\n");
256 db_stack_trace_print((db_expr_t)__builtin_frame_address(0), TRUE,
257 256 /* low limit */, "", printf);
258 printf("End of stack trace.\n");
259 intrace = 0;
260 }
261