1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | #if MACH_KDB1 |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | #include <string.h> |
38 | #include <mach/boolean.h> |
39 | #include <machine/db_machdep.h> |
40 | |
41 | #include <ddb/db_lex.h> |
42 | #include <ddb/db_output.h> |
43 | #include <ddb/db_command.h> |
44 | #include <ddb/db_task_thread.h> |
45 | #include <ddb/db_macro.h> |
46 | #include <ddb/db_expr.h> |
47 | #include <ddb/db_examine.h> |
48 | #include <ddb/db_print.h> |
49 | #include <ddb/db_break.h> |
50 | #include <ddb/db_watch.h> |
51 | #include <ddb/db_variables.h> |
52 | #include <ddb/db_write_cmd.h> |
53 | #include <ddb/db_run.h> |
54 | #include <ddb/db_cond.h> |
55 | |
56 | #include <machine/setjmp.h> |
57 | #include <machine/db_interface.h> |
58 | #include <kern/debug.h> |
59 | #include <kern/thread.h> |
60 | #include <ipc/ipc_pset.h> /* 4proto */ |
61 | #include <ipc/ipc_port.h> /* 4proto */ |
62 | |
63 | #include <vm/vm_print.h> |
64 | #include <ipc/ipc_print.h> |
65 | #include <kern/lock.h> |
66 | |
67 | |
68 | |
69 | |
70 | boolean_t db_cmd_loop_done; |
71 | jmp_buf_t *db_recover = 0; |
72 | db_addr_t db_dot; |
73 | db_addr_t db_last_addr; |
74 | db_addr_t db_prev; |
75 | db_addr_t db_next; |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | boolean_t db_ed_style = TRUE((boolean_t) 1); |
83 | |
84 | |
85 | |
86 | |
87 | #define CMD_UNIQUE0 0 |
88 | #define CMD_FOUND1 1 |
89 | #define CMD_NONE2 2 |
90 | #define CMD_AMBIGUOUS3 3 |
91 | #define CMD_HELP4 4 |
92 | |
93 | |
94 | |
95 | |
96 | int |
97 | db_cmd_search(name, table, cmdp) |
98 | const char * name; |
99 | const struct db_command *table; |
100 | const struct db_command **cmdp; |
101 | { |
102 | const struct db_command *cmd; |
103 | int result = CMD_NONE2; |
104 | |
105 | for (cmd = table; cmd->name != 0; cmd++) { |
106 | const char *lp; |
107 | char *rp; |
108 | int c; |
109 | |
110 | lp = name; |
111 | rp = cmd->name; |
112 | while ((c = *lp) == *rp) { |
113 | if (c == 0) { |
114 | |
115 | *cmdp = cmd; |
116 | return (CMD_UNIQUE0); |
117 | } |
118 | lp++; |
119 | rp++; |
120 | } |
121 | if (c == 0) { |
122 | |
123 | |
124 | if (result == CMD_FOUND1) { |
125 | result = CMD_AMBIGUOUS3; |
126 | |
127 | |
128 | } |
129 | else { |
130 | *cmdp = cmd; |
131 | result = CMD_FOUND1; |
132 | } |
133 | } |
134 | } |
135 | if (result == CMD_NONE2) { |
136 | |
137 | if (!strncmp(name, "help", strlen(name))) |
138 | result = CMD_HELP4; |
139 | } |
140 | return (result); |
141 | } |
142 | |
143 | void |
144 | db_cmd_list(table) |
145 | const struct db_command *table; |
146 | { |
147 | const struct db_command *cmd; |
148 | |
149 | for (cmd = table; cmd->name != 0; cmd++) { |
150 | db_printf("%-12s", cmd->name); |
151 | db_end_line(); |
152 | } |
153 | } |
154 | |
155 | void |
156 | db_command( |
157 | struct db_command **last_cmdp, |
158 | struct db_command *cmd_table) |
159 | { |
160 | struct db_command *cmd; |
161 | int t; |
162 | char modif[TOK_STRING_SIZE64]; |
163 | db_expr_t addr, count; |
| 5 | | Variable 'addr' declared without an initial value | |
|
164 | boolean_t have_addr = FALSE((boolean_t) 0); |
165 | int result; |
166 | |
167 | t = db_read_token(); |
168 | if (t == tEOL1 || t == tSEMI_COLON21) { |
| 6 | | Assuming 't' is not equal to 1 | |
|
| 7 | | Assuming 't' is not equal to 21 | |
|
| |
169 | |
170 | cmd = *last_cmdp; |
171 | addr = (db_expr_t)db_next; |
172 | have_addr = FALSE((boolean_t) 0); |
173 | count = 1; |
174 | modif[0] = '\0'; |
175 | if (t == tSEMI_COLON21) |
176 | db_unread_token(t); |
177 | } |
178 | else if (t == tEXCL17) { |
| 9 | | Assuming 't' is not equal to 17 | |
|
| |
179 | db_fncall(); |
180 | return; |
181 | } |
182 | else if (t != tIDENT3) { |
| 11 | | Assuming 't' is equal to 3 | |
|
| |
183 | db_printf("?\n"); |
184 | db_flush_lex(); |
185 | return; |
186 | } |
187 | else { |
188 | |
189 | |
190 | |
191 | while (cmd_table) { |
| 13 | | Loop condition is true. Entering loop body | |
|
| 17 | | Loop condition is false. Execution continues on line 223 | |
|
192 | result = db_cmd_search(db_tok_string, |
193 | cmd_table, |
194 | &cmd); |
195 | switch (result) { |
| 14 | | Control jumps to the 'default' case at line 210 | |
|
196 | case CMD_NONE2: |
197 | if (db_exec_macro(db_tok_string) == 0) |
198 | return; |
199 | db_printf("No such command \"%s\"\n", db_tok_string); |
200 | db_flush_lex(); |
201 | return; |
202 | case CMD_AMBIGUOUS3: |
203 | db_printf("Ambiguous\n"); |
204 | db_flush_lex(); |
205 | return; |
206 | case CMD_HELP4: |
207 | db_cmd_list(cmd_table); |
208 | db_flush_lex(); |
209 | return; |
210 | default: |
211 | break; |
| 15 | | Execution continues on line 213 | |
|
212 | } |
213 | if ((cmd_table = cmd->more) != 0) { |
| |
214 | t = db_read_token(); |
215 | if (t != tIDENT3) { |
216 | db_cmd_list(cmd_table); |
217 | db_flush_lex(); |
218 | return; |
219 | } |
220 | } |
221 | } |
222 | |
223 | if ((cmd->flag & CS_OWN0x1) == 0) { |
| |
224 | |
225 | |
226 | |
227 | |
228 | t = db_read_token(); |
229 | if (t == tSLASH8) { |
230 | t = db_read_token(); |
231 | if (t != tIDENT3) { |
232 | db_printf("Bad modifier \"/%s\"\n", db_tok_string); |
233 | db_flush_lex(); |
234 | return; |
235 | } |
236 | db_strcpy(modif, db_tok_string); |
237 | } |
238 | else { |
239 | db_unread_token(t); |
240 | modif[0] = '\0'; |
241 | } |
242 | |
243 | if (db_expression(&addr)) { |
244 | db_dot = (db_addr_t) addr; |
245 | db_last_addr = db_dot; |
246 | have_addr = TRUE((boolean_t) 1); |
247 | } |
248 | else { |
249 | addr = (db_expr_t) db_dot; |
250 | have_addr = FALSE((boolean_t) 0); |
251 | } |
252 | t = db_read_token(); |
253 | if (t == tCOMMA14) { |
254 | if (!db_expression(&count)) { |
255 | db_printf("Count missing after ','\n"); |
256 | db_flush_lex(); |
257 | return; |
258 | } |
259 | } |
260 | else { |
261 | db_unread_token(t); |
262 | count = -1; |
263 | } |
264 | } |
265 | } |
266 | *last_cmdp = cmd; |
267 | if (cmd != 0) { |
| |
268 | |
269 | |
270 | |
271 | (*cmd->fcn)(addr, have_addr, count, modif); |
| 20 | | Function call argument is an uninitialized value |
|
272 | |
273 | if (cmd->flag & CS_SET_DOT0x100) { |
274 | |
275 | |
276 | |
277 | |
278 | if (db_ed_style) { |
279 | db_dot = db_prev; |
280 | } |
281 | else { |
282 | db_dot = db_next; |
283 | } |
284 | } |
285 | else { |
286 | |
287 | |
288 | |
289 | |
290 | db_next = db_dot; |
291 | } |
292 | } |
293 | } |
294 | |
295 | void |
296 | db_command_list( |
297 | struct db_command **last_cmdp, |
298 | struct db_command *cmd_table) |
299 | { |
300 | do { |
301 | db_command(last_cmdp, cmd_table); |
| |
302 | db_skip_to_eol(); |
303 | } while (db_read_token() == tSEMI_COLON21 && db_cmd_loop_done == FALSE((boolean_t) 0)); |
304 | } |
305 | |
306 | struct db_command db_show_all_cmds[] = { |
307 | { "tasks", db_show_all_tasks, 0, 0 }, |
308 | { "threads", db_show_all_threads, 0, 0 }, |
309 | { "slocks", db_show_all_slocks, 0, 0 }, |
310 | { (char *)0 } |
311 | }; |
312 | |
313 | struct db_command db_show_cmds[] = { |
314 | { "all", 0, 0, db_show_all_cmds }, |
315 | { "registers", db_show_regs, 0, 0 }, |
316 | { "breaks", db_listbreak_cmd, 0, 0 }, |
317 | { "watches", db_listwatch_cmd, 0, 0 }, |
318 | { "thread", db_show_one_thread, 0, 0 }, |
319 | { "task", db_show_one_task, 0, 0 }, |
320 | { "macro", db_show_macro, CS_OWN0x1, 0 }, |
321 | { "map", vm_map_print, 0, 0 }, |
322 | { "object", vm_object_print, 0, 0 }, |
323 | { "page", vm_page_print, 0, 0 }, |
324 | { "copy", vm_map_copy_print, 0, 0 }, |
325 | { "port", ipc_port_print, 0, 0 }, |
326 | { "pset", ipc_pset_print, 0, 0 }, |
327 | { "kmsg", ipc_kmsg_print, 0, 0 }, |
328 | { "msg", ipc_msg_print, 0, 0 }, |
329 | { "ipc_port", db_show_port_id, 0, 0 }, |
330 | { (char *)0, } |
331 | }; |
332 | |
333 | struct db_command db_command_table[] = { |
334 | #ifdef DB_MACHINE_COMMANDS |
335 | |
336 | { "machine", 0, 0, 0}, |
337 | #endif |
338 | { "print", db_print_cmd, CS_OWN0x1, 0 }, |
339 | { "examine", db_examine_cmd, CS_MORE0x2|CS_SET_DOT0x100, 0 }, |
340 | { "x", db_examine_cmd, CS_MORE0x2|CS_SET_DOT0x100, 0 }, |
341 | { "xf", db_examine_forward, CS_SET_DOT0x100, 0 }, |
342 | { "xb", db_examine_backward, CS_SET_DOT0x100, 0 }, |
343 | { "search", db_search_cmd, CS_OWN0x1|CS_SET_DOT0x100, 0 }, |
344 | { "set", db_set_cmd, CS_OWN0x1, 0 }, |
345 | { "write", db_write_cmd, CS_MORE0x2|CS_SET_DOT0x100, 0 }, |
346 | { "w", db_write_cmd, CS_MORE0x2|CS_SET_DOT0x100, 0 }, |
347 | { "delete", db_delete_cmd, CS_OWN0x1, 0 }, |
348 | { "d", db_delete_cmd, CS_OWN0x1, 0 }, |
349 | { "break", db_breakpoint_cmd, CS_MORE0x2, 0 }, |
350 | { "dwatch", db_deletewatch_cmd, CS_MORE0x2, 0 }, |
351 | { "watch", db_watchpoint_cmd, CS_MORE0x2, 0 }, |
352 | { "step", db_single_step_cmd, 0, 0 }, |
353 | { "s", db_single_step_cmd, 0, 0 }, |
354 | { "continue", db_continue_cmd, 0, 0 }, |
355 | { "c", db_continue_cmd, 0, 0 }, |
356 | { "until", db_trace_until_call_cmd,0, 0 }, |
357 | { "next", db_trace_until_matching_cmd,0, 0 }, |
358 | { "match", db_trace_until_matching_cmd,0, 0 }, |
359 | { "trace", db_stack_trace_cmd, 0, 0 }, |
360 | { "cond", db_cond_cmd, CS_OWN0x1, 0 }, |
361 | { "call", db_fncall, CS_OWN0x1, 0 }, |
362 | { "macro", db_def_macro_cmd, CS_OWN0x1, 0 }, |
363 | { "dmacro", db_del_macro_cmd, CS_OWN0x1, 0 }, |
364 | { "show", 0, 0, db_show_cmds }, |
365 | { "reset", db_reset_cpu, 0, 0 }, |
366 | { "reboot", db_reset_cpu, 0, 0 }, |
367 | { "halt", db_halt_cpu, 0, 0 }, |
368 | { (char *)0, } |
369 | }; |
370 | |
371 | #ifdef DB_MACHINE_COMMANDS |
372 | |
373 | |
374 | |
375 | void db_machine_commands_install(struct db_command *ptr) |
376 | { |
377 | db_command_table[0].more = ptr; |
378 | return; |
379 | } |
380 | |
381 | #endif /* DB_MACHINE_COMMANDS */ |
382 | |
383 | |
384 | struct db_command *db_last_command = 0; |
385 | |
386 | void |
387 | db_help_cmd(void) |
388 | { |
389 | struct db_command *cmd = db_command_table; |
390 | |
391 | while (cmd->name != 0) { |
392 | db_printf("%-12s", cmd->name); |
393 | db_end_line(); |
394 | cmd++; |
395 | } |
396 | } |
397 | |
398 | void |
399 | db_command_loop(void) |
400 | { |
401 | jmp_buf_t db_jmpbuf; |
402 | jmp_buf_t *prev = db_recover; |
403 | extern int db_output_line; |
404 | extern int db_macro_level; |
405 | |
406 | |
407 | |
408 | |
409 | db_prev = db_dot; |
410 | db_next = db_dot; |
411 | |
412 | db_cmd_loop_done = FALSE((boolean_t) 0); |
413 | while (!db_cmd_loop_done) { |
414 | (void) _setjmp(db_recover = &db_jmpbuf); |
415 | db_macro_level = 0; |
416 | if (db_print_position() != 0) |
417 | db_printf("\n"); |
418 | db_output_line = 0; |
419 | db_printf("db%s", (db_default_thread)? "t": ""); |
420 | #if NCPUS1 > 1 |
421 | db_printf("{%d}", cpu_number()(0)); |
422 | #endif |
423 | db_printf("> "); |
424 | |
425 | (void) db_read_line("!!"); |
426 | db_command_list(&db_last_command, db_command_table); |
427 | } |
428 | |
429 | db_recover = prev; |
430 | } |
431 | |
432 | boolean_t |
433 | db_exec_cmd_nest( |
434 | char *cmd, |
435 | int size) |
436 | { |
437 | struct db_lex_context lex_context; |
438 | |
439 | db_cmd_loop_done = FALSE((boolean_t) 0); |
440 | if (cmd) { |
| |
| |
441 | db_save_lex_context(&lex_context); |
442 | db_switch_input(cmd, size ); |
443 | } |
444 | db_command_list(&db_last_command, db_command_table); |
| 3 | | Calling 'db_command_list' | |
|
445 | if (cmd) |
446 | db_restore_lex_context(&lex_context); |
447 | return(db_cmd_loop_done == FALSE((boolean_t) 0)); |
448 | } |
449 | |
450 | void db_error(s) |
451 | const char *s; |
452 | { |
453 | extern int db_macro_level; |
454 | |
455 | db_macro_level = 0; |
456 | if (db_recover) { |
457 | if (s) |
458 | db_printf(s); |
459 | db_flush_lex(); |
460 | _longjmp(db_recover, 1); |
461 | } |
462 | else |
463 | { |
464 | if (s) |
465 | db_printf(s); |
466 | panic("db_error"); |
467 | } |
468 | } |
469 | |
470 | |
471 | |
472 | |
473 | |
474 | void |
475 | db_fncall(void) |
476 | { |
477 | db_expr_t fn_addr; |
478 | #define MAXARGS11 11 |
479 | db_expr_t args[MAXARGS11]; |
480 | int nargs = 0; |
481 | db_expr_t retval; |
482 | db_expr_t (*func)(); |
483 | int t; |
484 | |
485 | if (!db_expression(&fn_addr)) { |
486 | db_printf("Bad function \"%s\"\n", db_tok_string); |
487 | db_flush_lex(); |
488 | return; |
489 | } |
490 | func = (db_expr_t (*) ()) fn_addr; |
491 | |
492 | t = db_read_token(); |
493 | if (t == tLPAREN10) { |
494 | if (db_expression(&args[0])) { |
495 | nargs++; |
496 | while ((t = db_read_token()) == tCOMMA14) { |
497 | if (nargs == MAXARGS11) { |
498 | db_printf("Too many arguments\n"); |
499 | db_flush_lex(); |
500 | return; |
501 | } |
502 | if (!db_expression(&args[nargs])) { |
503 | db_printf("Argument missing\n"); |
504 | db_flush_lex(); |
505 | return; |
506 | } |
507 | nargs++; |
508 | } |
509 | db_unread_token(t); |
510 | } |
511 | if (db_read_token() != tRPAREN11) { |
512 | db_printf("?\n"); |
513 | db_flush_lex(); |
514 | return; |
515 | } |
516 | } |
517 | while (nargs < MAXARGS11) { |
518 | args[nargs++] = 0; |
519 | } |
520 | |
521 | retval = (*func)(args[0], args[1], args[2], args[3], args[4], |
522 | args[5], args[6], args[7], args[8], args[9] ); |
523 | db_printf(" %#N\n", retval); |
524 | } |
525 | |
526 | boolean_t __attribute__ ((pure)) |
527 | db_option(modif, option) |
528 | const char *modif; |
529 | int option; |
530 | { |
531 | const char *p; |
532 | |
533 | for (p = modif; *p; p++) |
534 | if (*p == option) |
535 | return(TRUE((boolean_t) 1)); |
536 | return(FALSE((boolean_t) 0)); |
537 | } |
538 | |
539 | #endif /* MACH_KDB */ |