FreeBSD/Linux Kernel Cross Reference
sys/ddb/db_examine.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1992,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 "AS IS"
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 Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: db_examine.c,v $
29 * Revision 2.13 93/05/17 10:26:31 rvb
30 * Type casts, etc to quiet gcc 2.3.3 warnings
31 *
32 * Revision 2.12 93/03/09 17:55:55 danner
33 * Added ',' format to examine command.
34 * [93/02/25 jfriedl]
35 *
36 * Revision 2.11 93/01/14 17:24:52 danner
37 * 64bit cleanup.
38 * [92/12/10 16:16:01 af]
39 *
40 * Revision 2.10 92/08/03 17:30:58 jfriedl
41 * removed silly prototypes
42 * [92/08/02 jfriedl]
43 *
44 * Revision 2.9 92/05/21 17:06:44 jfriedl
45 * Added void type to functions that needed it.
46 * Added init to 'size' in db_search_cmd(). Removed unused variables.
47 * Other cleanup to quiet gcc warnings.
48 * [92/05/16 jfriedl]
49 *
50 * Revision 2.8 92/05/04 11:23:59 danner
51 * x/u now examines current user space. x/t still examines user
52 * space of the the specified thread. x/tu is redundant.
53 * To examine an value as unsigned decimal, use x/U.
54 * [92/04/18 danner]
55 *
56 * Revision 2.7 91/10/09 15:59:28 af
57 * Supported non current task space data examination and search.
58 * Added 'm' format and db_xcdump to print with hex and characters.
59 * Added db_examine_{forward, backward}.
60 * Changed db_print_cmd to support variable number of parameters
61 * including string constant.
62 * Included "db_access.h".
63 * [91/08/29 tak]
64 *
65 * Revision 2.6 91/08/28 11:11:01 jsb
66 * Added 'A' flag to examine: just like 'a' (address), but prints addr
67 * as a procedure type, thus printing file/line info if available.
68 * Useful when called as 'x/Ai'.
69 * [91/08/13 18:14:55 jsb]
70 *
71 * Revision 2.5 91/05/14 15:33:31 mrt
72 * Correcting copyright
73 *
74 * Revision 2.4 91/02/05 17:06:20 mrt
75 * Changed to new Mach copyright
76 * [91/01/31 16:17:37 mrt]
77 *
78 * Revision 2.3 90/11/07 16:49:23 rpd
79 * Added db_search_cmd, db_search.
80 * [90/11/06 rpd]
81 *
82 * Revision 2.2 90/08/27 21:50:38 dbg
83 * Add 'r', 'z' to print and examine formats.
84 * Change calling sequence of db_disasm.
85 * db_examine sets db_prev and db_next instead of explicitly
86 * advancing dot.
87 * [90/08/20 dbg]
88 * Reflected changes in db_printsym()'s calling seq.
89 * [90/08/20 af]
90 * Reduce lint.
91 * [90/08/07 dbg]
92 * Created.
93 * [90/07/25 dbg]
94 *
95 */
96 /*
97 * Author: David B. Golub, Carnegie Mellon University
98 * Date: 7/90
99 */
100 #include <mach/boolean.h>
101 #include <machine/db_machdep.h>
102
103 #include <ddb/db_access.h>
104 #include <ddb/db_lex.h>
105 #include <ddb/db_output.h>
106 #include <ddb/db_command.h>
107 #include <ddb/db_sym.h>
108 #include <ddb/db_task_thread.h>
109 #include <kern/thread.h>
110 #include <kern/task.h>
111 #include <mach/vm_param.h>
112
113 #define db_thread_to_task(thread) ((thread)? thread->task: TASK_NULL)
114
115 char db_examine_format[TOK_STRING_SIZE] = "x";
116 int db_examine_count = 1;
117 db_addr_t db_examine_prev_addr = 0;
118 thread_t db_examine_thread = THREAD_NULL;
119
120 extern db_addr_t db_disasm(db_addr_t pc, boolean_t altform, task_t task);
121 /* instruction disassembler */
122
123 void db_examine();/*forwards*/
124 void db_strcpy();
125
126 /*
127 * Examine (print) data.
128 */
129 /*ARGSUSED*/
130 void
131 db_examine_cmd(addr, have_addr, count, modif)
132 db_expr_t addr;
133 int have_addr;
134 db_expr_t count;
135 char * modif;
136 {
137 thread_t thread;
138 boolean_t db_option();
139
140 if (modif[0] != '\0')
141 db_strcpy(db_examine_format, modif);
142
143 if (count == -1)
144 count = 1;
145 db_examine_count = count;
146 if (db_option(modif, 't'))
147 {
148 if (!db_get_next_thread(&thread, 0))
149 return;
150 }
151 else
152 if (db_option(modif,'u'))
153 thread = current_thread();
154 else
155 thread = THREAD_NULL;
156
157 db_examine_thread = thread;
158 db_examine((db_addr_t) addr, db_examine_format, count,
159 db_thread_to_task(thread));
160 }
161
162 /* ARGSUSED */
163 void
164 db_examine_forward(addr, have_addr, count, modif)
165 db_expr_t addr;
166 int have_addr;
167 db_expr_t count;
168 char * modif;
169 {
170 db_examine(db_next, db_examine_format, db_examine_count,
171 db_thread_to_task(db_examine_thread));
172 }
173
174 /* ARGSUSED */
175 void
176 db_examine_backward(addr, have_addr, count, modif)
177 db_expr_t addr;
178 int have_addr;
179 db_expr_t count;
180 char * modif;
181 {
182
183 db_examine(db_examine_prev_addr - (db_next - db_examine_prev_addr),
184 db_examine_format, db_examine_count,
185 db_thread_to_task(db_examine_thread));
186 }
187
188 void
189 db_examine(addr, fmt, count, task)
190 register
191 db_addr_t addr;
192 char * fmt; /* format string */
193 int count; /* repeat count */
194 task_t task;
195 {
196 int c;
197 db_expr_t value;
198 int size; /* in bytes */
199 int width;
200 char * fp;
201
202 db_examine_prev_addr = addr;
203 while (--count >= 0) {
204 fp = fmt;
205 size = sizeof(int);
206 width = 4*size;
207 while ((c = *fp++) != 0) {
208 switch (c) {
209 case 'b':
210 size = sizeof(char);
211 width = 4*size;
212 break;
213 case 'h':
214 size = sizeof(short);
215 width = 4*size;
216 break;
217 case 'l':
218 size = sizeof(long);
219 width = 4*size;
220 break;
221 case 'a': /* address */
222 case 'A': /* function address */
223 /* always forces a new line */
224 if (db_print_position() != 0)
225 db_printf("\n");
226 db_prev = addr;
227 db_task_printsym(addr,
228 (c == 'a')?DB_STGY_ANY:DB_STGY_PROC,
229 task);
230 db_printf(":\t");
231 break;
232 case 'm':
233 db_next = db_xcdump(addr, size, count+1, task);
234 return;
235 default:
236 if (db_print_position() == 0) {
237 /* If we hit a new symbol, print it */
238 char * name;
239 db_addr_t off;
240
241 db_find_task_sym_and_offset(addr,&name,&off,task);
242 if (off == 0)
243 db_printf("%s:\t", name);
244 else
245 db_printf("\t\t");
246
247 db_prev = addr;
248 }
249
250 switch (c) {
251 case ',': /* skip one unit w/o printing */
252 addr += size;
253 break;
254
255 case 'r': /* signed, current radix */
256 value = db_get_task_value(addr,size,TRUE,task);
257 addr += size;
258 db_printf("%-*R", width, value);
259 break;
260 case 'x': /* unsigned hex */
261 value = db_get_task_value(addr,size,FALSE,task);
262 addr += size;
263 db_printf("%-*X", width, value);
264 break;
265 case 'z': /* signed hex */
266 value = db_get_task_value(addr,size,TRUE,task);
267 addr += size;
268 db_printf("%-*Z", width, value);
269 break;
270 case 'd': /* signed decimal */
271 value = db_get_task_value(addr,size,TRUE,task);
272 addr += size;
273 db_printf("%-*D", width, value);
274 break;
275 case 'U': /* unsigned decimal */
276 value = db_get_task_value(addr,size,FALSE,task);
277 addr += size;
278 db_printf("%-*U", width, value);
279 break;
280 case 'o': /* unsigned octal */
281 value = db_get_task_value(addr,size,FALSE,task);
282 addr += size;
283 db_printf("%-*O", width, value);
284 break;
285 case 'c': /* character */
286 value = db_get_task_value(addr,1,FALSE,task);
287 addr += 1;
288 if (value >= ' ' && value <= '~')
289 db_printf("%c", value);
290 else
291 db_printf("\\%03o", value);
292 break;
293 case 's': /* null-terminated string */
294 for (;;) {
295 value = db_get_task_value(addr,1,FALSE,task);
296 addr += 1;
297 if (value == 0)
298 break;
299 if (value >= ' ' && value <= '~')
300 db_printf("%c", value);
301 else
302 db_printf("\\%03o", value);
303 }
304 break;
305 case 'i': /* instruction */
306 addr = db_disasm(addr, FALSE, task);
307 break;
308 case 'I': /* instruction, alternate form */
309 addr = db_disasm(addr, TRUE, task);
310 break;
311 default:
312 break;
313 }
314 if (db_print_position() != 0)
315 db_end_line();
316 break;
317 }
318 }
319 }
320 db_next = addr;
321 }
322
323 /*
324 * Print value.
325 */
326 char db_print_format = 'x';
327
328 /*ARGSUSED*/
329 void
330 db_print_cmd()
331 {
332 db_expr_t value;
333 int t;
334 task_t task = TASK_NULL;
335
336 if ((t = db_read_token()) == tSLASH) {
337 if (db_read_token() != tIDENT) {
338 db_printf("Bad modifier \"/%s\"\n", db_tok_string);
339 db_error(0);
340 /* NOTREACHED */
341 }
342 if (db_tok_string[0])
343 db_print_format = db_tok_string[0];
344 if (db_option(db_tok_string, 't') && db_default_thread)
345 task = db_default_thread->task;
346 } else
347 db_unread_token(t);
348
349 for ( ; ; ) {
350 t = db_read_token();
351 if (t == tSTRING) {
352 db_printf("%s", db_tok_string);
353 continue;
354 }
355 db_unread_token(t);
356 if (!db_expression(&value))
357 break;
358 switch (db_print_format) {
359 case 'a':
360 db_task_printsym((db_addr_t)value, DB_STGY_ANY, task);
361 break;
362 case 'r':
363 db_printf("%*r", 3+2*sizeof(db_expr_t), value);
364 break;
365 case 'x':
366 db_printf("%*x", 2*sizeof(db_expr_t), value);
367 break;
368 case 'z':
369 db_printf("%*z", 2*sizeof(db_expr_t), value);
370 break;
371 case 'd':
372 db_printf("%*d", 3+2*sizeof(db_expr_t), value);
373 break;
374 case 'u':
375 db_printf("%*u", 3+2*sizeof(db_expr_t), value);
376 break;
377 case 'o':
378 db_printf("%o", 4*sizeof(db_expr_t), value);
379 break;
380 case 'c':
381 value = value & 0xFF;
382 if (value >= ' ' && value <= '~')
383 db_printf("%c", value);
384 else
385 db_printf("\\%03o", value);
386 break;
387 default:
388 db_printf("Unknown format %c\n", db_print_format);
389 db_print_format = 'x';
390 db_error(0);
391 }
392 }
393 }
394
395 void
396 db_print_loc_and_inst(loc, task)
397 db_addr_t loc;
398 task_t task;
399 {
400 db_task_printsym(loc, DB_STGY_PROC, task);
401 db_printf(":\t");
402 (void) db_disasm(loc, TRUE, task);
403 }
404
405 void
406 db_strcpy(dst, src)
407 register char *dst;
408 register char *src;
409 {
410 while (*dst++ = *src++)
411 ;
412 }
413
414 void db_search(); /*forward*/
415 /*
416 * Search for a value in memory.
417 * Syntax: search [/bhl] addr value [mask] [,count] [thread]
418 */
419 void
420 db_search_cmd()
421 {
422 int t;
423 db_addr_t addr;
424 int size = 0;
425 db_expr_t value;
426 db_expr_t mask;
427 db_addr_t count;
428 thread_t thread;
429 boolean_t thread_flag = FALSE;
430 register char *p;
431
432 t = db_read_token();
433 if (t == tSLASH) {
434 t = db_read_token();
435 if (t != tIDENT) {
436 bad_modifier:
437 db_printf("Bad modifier \"/%s\"\n", db_tok_string);
438 db_flush_lex();
439 return;
440 }
441
442 for (p = db_tok_string; *p; p++) {
443 switch(*p) {
444 case 'b':
445 size = sizeof(char);
446 break;
447 case 'h':
448 size = sizeof(short);
449 break;
450 case 'l':
451 size = sizeof(long);
452 break;
453 case 't':
454 thread_flag = TRUE;
455 break;
456 default:
457 goto bad_modifier;
458 }
459 }
460 } else {
461 db_unread_token(t);
462 size = sizeof(int);
463 }
464
465 if (!db_expression(&addr)) {
466 db_printf("Address missing\n");
467 db_flush_lex();
468 return;
469 }
470
471 if (!db_expression(&value)) {
472 db_printf("Value missing\n");
473 db_flush_lex();
474 return;
475 }
476
477 if (!db_expression(&mask))
478 mask = ~0;
479
480 t = db_read_token();
481 if (t == tCOMMA) {
482 if (!db_expression(&count)) {
483 db_printf("Count missing\n");
484 db_flush_lex();
485 return;
486 }
487 } else {
488 db_unread_token(t);
489 count = -1; /* effectively forever */
490 }
491 if (thread_flag) {
492 if (!db_get_next_thread(&thread, 0))
493 return;
494 } else
495 thread = THREAD_NULL;
496
497 db_search(addr, size, value, mask, count, db_thread_to_task(thread));
498 }
499
500 void
501 db_search(addr, size, value, mask, count, task)
502 register
503 db_addr_t addr;
504 int size;
505 db_expr_t value;
506 db_expr_t mask;
507 unsigned int count;
508 task_t task;
509 {
510 while (count-- != 0) {
511 db_prev = addr;
512 if ((db_get_task_value(addr,size,FALSE,task) & mask) == value)
513 break;
514 addr += size;
515 }
516 db_next = addr;
517 }
518
519 #define DB_XCDUMP_NC 16
520
521 int
522 db_xcdump(addr, size, count, task)
523 db_addr_t addr;
524 int size;
525 int count;
526 task_t task;
527 {
528 register i, n;
529 db_expr_t value;
530 int bcount;
531 db_addr_t off;
532 char *name;
533 char data[DB_XCDUMP_NC];
534
535 db_find_task_sym_and_offset(addr, &name, &off, task);
536 for (n = count*size; n > 0; n -= bcount) {
537 db_prev = addr;
538 if (off == 0) {
539 db_printf("%s:\n", name);
540 off = -1;
541 }
542 db_printf("%0*X:%s", 2*sizeof(db_addr_t), addr,
543 (size != 1)? " ": "");
544 bcount = ((n > DB_XCDUMP_NC)? DB_XCDUMP_NC: n);
545 if (trunc_page(addr) != trunc_page(addr+bcount-1)) {
546 db_addr_t next_page_addr = trunc_page(addr+bcount-1);
547 if (!DB_CHECK_ACCESS(next_page_addr, sizeof(int), task))
548 bcount = next_page_addr - addr;
549 }
550 db_read_bytes((char *)addr, bcount, data, task);
551 for (i = 0; i < bcount && off != 0; i += size) {
552 if (i % 4 == 0)
553 db_printf(" ");
554 value = db_get_task_value(addr, size, FALSE, task);
555 db_printf("%0*x ", size*2, value);
556 addr += size;
557 db_find_task_sym_and_offset(addr, &name, &off, task);
558 }
559 db_printf("%*s",
560 ((DB_XCDUMP_NC-i)/size)*(size*2+1)+(DB_XCDUMP_NC-i)/4,
561 "");
562 bcount = i;
563 db_printf("%s*", (size != 1)? " ": "");
564 for (i = 0; i < bcount; i++) {
565 value = data[i];
566 db_printf("%c", (value >= ' ' && value <= '~')? value: '.');
567 }
568 db_printf("*\n");
569 }
570 return(addr);
571 }
Cache object: 878a149e21fc4d79373719885a1016ab
|