]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
8ad349bb | 2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. |
1c79356b | 3 | * |
8ad349bb | 4 | * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ |
1c79356b | 5 | * |
8ad349bb A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the | |
10 | * License may not be used to create, or enable the creation or | |
11 | * redistribution of, unlawful or unlicensed copies of an Apple operating | |
12 | * system, or to circumvent, violate, or enable the circumvention or | |
13 | * violation of, any terms of an Apple operating system software license | |
14 | * agreement. | |
15 | * | |
16 | * Please obtain a copy of the License at | |
17 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
18 | * file. | |
19 | * | |
20 | * The Original Code and all software distributed under the License are | |
21 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
22 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
23 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
24 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
25 | * Please see the License for the specific language governing rights and | |
26 | * limitations under the License. | |
27 | * | |
28 | * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ | |
1c79356b A |
29 | */ |
30 | /* | |
31 | * @OSF_COPYRIGHT@ | |
32 | */ | |
33 | /* | |
34 | * Mach Operating System | |
35 | * Copyright (c) 1991 Carnegie Mellon University | |
36 | * All Rights Reserved. | |
37 | * | |
38 | * Permission to use, copy, modify and distribute this software and its | |
39 | * documentation is hereby granted, provided that both the copyright | |
40 | * notice and this permission notice appear in all copies of the | |
41 | * software, derivative works or modified versions, and any portions | |
42 | * thereof, and that both notices appear in supporting documentation. | |
43 | * | |
44 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |
45 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
46 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
47 | * | |
48 | * Carnegie Mellon requests users of this software to return to | |
49 | * | |
50 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
51 | * School of Computer Science | |
52 | * Carnegie Mellon University | |
53 | * Pittsburgh PA 15213-3890 | |
54 | * | |
55 | * any improvements or extensions that they make and grant Carnegie Mellon | |
56 | * the rights to redistribute these changes. | |
57 | */ | |
58 | /* | |
59 | */ | |
60 | /* | |
61 | * Author: David B. Golub, Carnegie Mellon University | |
62 | * Date: 7/90 | |
63 | */ | |
64 | ||
65 | /* | |
66 | * Command dispatcher. | |
67 | */ | |
1c79356b A |
68 | #include <norma_vm.h> |
69 | #ifdef AT386 | |
70 | #include <norma_scsi.h> | |
71 | #endif /* AT386 */ | |
72 | ||
73 | #include <mach/boolean.h> | |
74 | #include <string.h> | |
75 | #include <machine/db_machdep.h> | |
76 | ||
77 | #if defined(__alpha) | |
78 | # include <kdebug.h> | |
79 | # if KDEBUG | |
80 | # include <machine/kdebug.h> | |
81 | # endif | |
82 | #endif /* defined(__alpha) */ | |
83 | ||
84 | #include <ddb/db_lex.h> | |
85 | #include <ddb/db_output.h> | |
86 | #include <ddb/db_break.h> | |
87 | #include <ddb/db_command.h> | |
88 | #include <ddb/db_cond.h> | |
89 | #include <ddb/db_examine.h> | |
90 | #include <ddb/db_expr.h> | |
91 | #include <ppc/db_low_trace.h> | |
92 | #include <ddb/db_macro.h> | |
93 | #include <ddb/db_print.h> | |
94 | #include <ddb/db_run.h> | |
95 | #include <ddb/db_task_thread.h> | |
96 | #include <ddb/db_variables.h> | |
97 | #include <ddb/db_watch.h> | |
98 | #include <ddb/db_write_cmd.h> | |
99 | #include <ddb/tr.h> | |
100 | ||
101 | #include <machine/setjmp.h> | |
102 | #include <kern/thread.h> | |
103 | ||
104 | #include <kern/misc_protos.h> | |
105 | #include <vm/vm_print.h> | |
106 | #include <ipc/ipc_print.h> | |
107 | #include <kern/kern_print.h> | |
108 | #include <machine/db_machdep.h> /* For db_stack_trace_cmd(). */ | |
109 | #include <kern/zalloc.h> /* For db_show_one_zone, db_show_all_zones. */ | |
110 | #include <kern/lock.h> /* For db_show_all_slocks(). */ | |
111 | ||
112 | #if NORMA_VM | |
113 | #include <xmm/xmm_obj.h> | |
114 | #endif /* NORMA_VM */ | |
115 | ||
116 | /* | |
117 | * Exported global variables | |
118 | */ | |
119 | boolean_t db_cmd_loop_done; | |
120 | jmp_buf_t *db_recover = 0; | |
121 | db_addr_t db_dot; | |
122 | db_addr_t db_last_addr; | |
123 | db_addr_t db_prev; | |
124 | db_addr_t db_next; | |
125 | ||
126 | /* | |
127 | * if 'ed' style: 'dot' is set at start of last item printed, | |
128 | * and '+' points to next line. | |
129 | * Otherwise: 'dot' points to next item, '..' points to last. | |
130 | */ | |
131 | boolean_t db_ed_style = TRUE; | |
132 | ||
133 | /* | |
134 | * Results of command search. | |
135 | */ | |
136 | #define CMD_UNIQUE 0 | |
137 | #define CMD_FOUND 1 | |
138 | #define CMD_NONE 2 | |
139 | #define CMD_AMBIGUOUS 3 | |
140 | #define CMD_HELP 4 | |
141 | ||
142 | /* Prototypes for functions local to this file. XXX -- should be static! | |
143 | */ | |
144 | ||
145 | void db_command( | |
146 | struct db_command **last_cmdp, /* IN_OUT */ | |
147 | db_expr_t *last_countp, /* IN_OUT */ | |
148 | char *last_modifp, /* IN_OUT */ | |
149 | struct db_command *cmd_table); | |
150 | ||
151 | void db_help_cmd(void); | |
152 | ||
153 | void db_output_prompt(void); | |
154 | ||
155 | void db_fncall(void); | |
156 | ||
157 | void db_cmd_list(struct db_command *table); | |
158 | ||
159 | int db_cmd_search( | |
160 | char * name, | |
161 | struct db_command * table, | |
162 | struct db_command ** cmdp); /* out */ | |
163 | ||
164 | void db_command_list( | |
165 | struct db_command **last_cmdp, /* IN_OUT */ | |
166 | db_expr_t *last_countp, /* IN_OUT */ | |
167 | char *last_modifp, /* IN_OUT */ | |
168 | struct db_command *cmd_table); | |
169 | ||
8ad349bb A |
170 | |
171 | ||
1c79356b A |
172 | /* |
173 | * Search for command prefix. | |
174 | */ | |
175 | int | |
176 | db_cmd_search( | |
177 | char * name, | |
178 | struct db_command * table, | |
179 | struct db_command ** cmdp) /* out */ | |
180 | { | |
181 | struct db_command *cmd; | |
182 | int result = CMD_NONE; | |
183 | ||
184 | for (cmd = table; cmd->name != 0; cmd++) { | |
185 | register char *lp; | |
186 | register char *rp; | |
187 | register int c; | |
188 | ||
189 | lp = name; | |
190 | rp = cmd->name; | |
191 | while ((c = *lp) == *rp) { | |
192 | if (c == 0) { | |
193 | /* complete match */ | |
194 | *cmdp = cmd; | |
195 | return (CMD_UNIQUE); | |
196 | } | |
197 | lp++; | |
198 | rp++; | |
199 | } | |
200 | if (c == 0) { | |
201 | /* end of name, not end of command - | |
202 | partial match */ | |
203 | if (result == CMD_FOUND) { | |
204 | result = CMD_AMBIGUOUS; | |
205 | /* but keep looking for a full match - | |
206 | this lets us match single letters */ | |
207 | } | |
208 | else { | |
209 | *cmdp = cmd; | |
210 | result = CMD_FOUND; | |
211 | } | |
212 | } | |
213 | } | |
214 | if (result == CMD_NONE) { | |
215 | /* check for 'help' */ | |
216 | if (!strncmp(name, "help", strlen(name))) | |
217 | result = CMD_HELP; | |
218 | } | |
219 | return (result); | |
220 | } | |
221 | ||
222 | void | |
223 | db_cmd_list(struct db_command *table) | |
224 | { | |
225 | register struct db_command *new; | |
226 | register struct db_command *old; | |
227 | register struct db_command *cur; | |
228 | unsigned int l; | |
229 | unsigned int len; | |
230 | ||
231 | len = 1; | |
232 | for (cur = table; cur->name != 0; cur++) | |
233 | if ((l = strlen(cur->name)) >= len) | |
234 | len = l + 1; | |
235 | ||
236 | old = (struct db_command *)0; | |
237 | for (;;) { | |
238 | new = (struct db_command *)0; | |
239 | for (cur = table; cur->name != 0; cur++) | |
240 | if ((new == (struct db_command *)0 || | |
241 | strcmp(cur->name, new->name) < 0) && | |
242 | (old == (struct db_command *)0 || | |
243 | strcmp(cur->name, old->name) > 0)) | |
244 | new = cur; | |
245 | if (new == (struct db_command *)0) | |
246 | return; | |
247 | db_reserve_output_position(len); | |
248 | db_printf("%-*s", len, new->name); | |
249 | old = new; | |
250 | } | |
251 | } | |
252 | ||
253 | void | |
254 | db_command( | |
255 | struct db_command **last_cmdp, /* IN_OUT */ | |
256 | db_expr_t *last_countp, /* IN_OUT */ | |
257 | char *last_modifp, /* IN_OUT */ | |
258 | struct db_command *cmd_table) | |
259 | { | |
260 | struct db_command *cmd; | |
261 | int t; | |
262 | char modif[TOK_STRING_SIZE]; | |
263 | char *modifp = &modif[0]; | |
264 | db_expr_t addr, count; | |
265 | boolean_t have_addr; | |
266 | int result; | |
267 | ||
268 | t = db_read_token(); | |
269 | if (t == tEOL || t == tSEMI_COLON) { | |
270 | /* empty line repeats last command, at 'next' */ | |
271 | cmd = *last_cmdp; | |
272 | count = *last_countp; | |
273 | modifp = last_modifp; | |
274 | addr = (db_expr_t)db_next; | |
275 | have_addr = FALSE; | |
276 | if (t == tSEMI_COLON) | |
277 | db_unread_token(t); | |
278 | } | |
279 | else if (t == tEXCL) { | |
280 | db_fncall(); | |
281 | return; | |
282 | } | |
283 | else if (t != tIDENT) { | |
284 | db_printf("?\n"); | |
285 | db_flush_lex(); | |
286 | return; | |
287 | } | |
288 | else { | |
289 | /* | |
290 | * Search for command | |
291 | */ | |
292 | while (cmd_table) { | |
293 | result = db_cmd_search(db_tok_string, | |
294 | cmd_table, | |
295 | &cmd); | |
296 | switch (result) { | |
297 | case CMD_NONE: | |
298 | if (db_exec_macro(db_tok_string) == 0) | |
299 | return; | |
300 | db_printf("No such command \"%s\"\n", db_tok_string); | |
301 | db_flush_lex(); | |
302 | return; | |
303 | case CMD_AMBIGUOUS: | |
304 | db_printf("Ambiguous\n"); | |
305 | db_flush_lex(); | |
306 | return; | |
307 | case CMD_HELP: | |
308 | db_cmd_list(cmd_table); | |
309 | db_flush_lex(); | |
310 | return; | |
311 | default: | |
312 | break; | |
313 | } | |
314 | if ((cmd_table = cmd->more) != 0) { | |
315 | t = db_read_token(); | |
316 | if (t != tIDENT) { | |
317 | db_cmd_list(cmd_table); | |
318 | db_flush_lex(); | |
319 | return; | |
320 | } | |
321 | } | |
322 | } | |
323 | ||
324 | if ((cmd->flag & CS_OWN) == 0) { | |
325 | /* | |
326 | * Standard syntax: | |
327 | * command [/modifier] [addr] [,count] | |
328 | */ | |
329 | t = db_read_token(); | |
330 | if (t == tSLASH) { | |
331 | t = db_read_token(); | |
332 | if (t != tIDENT) { | |
333 | db_printf("Bad modifier \"/%s\"\n", db_tok_string); | |
334 | db_flush_lex(); | |
335 | return; | |
336 | } | |
337 | strcpy(modif, db_tok_string); | |
338 | } | |
339 | else { | |
340 | db_unread_token(t); | |
341 | modif[0] = '\0'; | |
342 | } | |
343 | ||
344 | if (db_expression(&addr)) { | |
345 | db_dot = (db_addr_t) addr; | |
346 | db_last_addr = db_dot; | |
347 | have_addr = TRUE; | |
348 | } | |
349 | else { | |
350 | addr = (db_expr_t) db_dot; | |
351 | have_addr = FALSE; | |
352 | } | |
353 | t = db_read_token(); | |
354 | if (t == tCOMMA) { | |
355 | if (!db_expression(&count)) { | |
356 | db_printf("Count missing after ','\n"); | |
357 | db_flush_lex(); | |
358 | return; | |
359 | } | |
360 | } | |
361 | else { | |
362 | db_unread_token(t); | |
363 | count = -1; | |
364 | } | |
365 | } | |
366 | } | |
367 | if (cmd != 0) { | |
368 | /* | |
369 | * Execute the command. | |
370 | */ | |
371 | (*cmd->fcn)(addr, have_addr, count, modifp); | |
372 | ||
373 | if (cmd->flag & CS_SET_DOT) { | |
374 | /* | |
375 | * If command changes dot, set dot to | |
376 | * previous address displayed (if 'ed' style). | |
377 | */ | |
378 | if (db_ed_style) { | |
379 | db_dot = db_prev; | |
380 | } | |
381 | else { | |
382 | db_dot = db_next; | |
383 | } | |
384 | } | |
385 | else { | |
386 | /* | |
387 | * If command does not change dot, | |
388 | * set 'next' location to be the same. | |
389 | */ | |
390 | db_next = db_dot; | |
391 | } | |
392 | } | |
393 | *last_cmdp = cmd; | |
394 | *last_countp = count; | |
395 | strcpy(last_modifp, modifp); | |
396 | } | |
397 | ||
398 | void | |
399 | db_command_list( | |
400 | struct db_command **last_cmdp, /* IN_OUT */ | |
401 | db_expr_t *last_countp, /* IN_OUT */ | |
402 | char *last_modifp, /* IN_OUT */ | |
403 | struct db_command *cmd_table) | |
404 | { | |
405 | do { | |
406 | db_command(last_cmdp, last_countp, last_modifp, cmd_table); | |
407 | db_skip_to_eol(); | |
408 | } while (db_read_token() == tSEMI_COLON && db_cmd_loop_done == 0); | |
409 | } | |
410 | ||
411 | ||
412 | extern void db_system_stats(void); | |
413 | ||
414 | struct db_command db_show_all_cmds[] = { | |
1c79356b A |
415 | { "acts", db_show_all_acts, 0, 0 }, |
416 | { "spaces", db_show_all_spaces, 0, 0 }, | |
417 | { "tasks", db_show_all_acts, 0, 0 }, | |
418 | /* temporary alias for sanity preservation */ | |
419 | { "threads", db_show_all_acts, 0, 0 }, | |
420 | { "zones", db_show_all_zones, 0, 0 }, | |
421 | { "vmtask", db_show_all_task_vm, 0, 0 }, | |
422 | { (char *)0 } | |
423 | }; | |
424 | ||
425 | /* XXX */ | |
426 | ||
427 | extern void db_show_thread_log(void); | |
428 | extern void db_show_one_lock(lock_t*); | |
429 | extern void db_show_etap_log(db_expr_t, int, db_expr_t, char *); | |
430 | ||
431 | struct db_command db_show_cmds[] = { | |
432 | { "all", 0, 0, db_show_all_cmds }, | |
433 | { "registers", db_show_regs, 0, 0 }, | |
434 | { "variables", (db_func) db_show_variable, CS_OWN, 0 }, | |
435 | { "breaks", (db_func) db_listbreak_cmd, 0, 0 }, | |
436 | { "watches", (db_func) db_listwatch_cmd, 0, 0 }, | |
437 | { "task", db_show_one_task, 0, 0 }, | |
438 | { "act", db_show_one_act, 0, 0 }, | |
439 | { "shuttle", db_show_shuttle, 0, 0 }, | |
440 | #if 0 | |
441 | { "thread", db_show_one_thread, 0, 0 }, | |
442 | #endif | |
443 | { "vmtask", db_show_one_task_vm, 0, 0 }, | |
444 | { "macro", (db_func) db_show_macro, CS_OWN, 0 }, | |
445 | { "runq", (db_func) db_show_runq, 0, 0 }, | |
446 | { "map", (db_func) vm_map_print, 0, 0 }, | |
447 | { "object", (db_func) vm_object_print, 0, 0 }, | |
448 | { "page", (db_func) vm_page_print, 0, 0 }, | |
449 | { "copy", (db_func) vm_map_copy_print, 0, 0 }, | |
450 | { "port", (db_func) ipc_port_print, 0, 0 }, | |
451 | { "pset", (db_func) ipc_pset_print, 0, 0 }, | |
452 | { "kmsg", (db_func) ipc_kmsg_print, 0, 0 }, | |
453 | { "msg", (db_func) ipc_msg_print, 0, 0 }, | |
454 | { "ipc_port", db_show_port_id, 0, 0 }, | |
1c79356b A |
455 | #if NORMA_VM |
456 | { "xmm_obj", (db_func) xmm_obj_print, 0, 0 }, | |
457 | { "xmm_reply", (db_func) xmm_reply_print, 0, 0 }, | |
458 | #endif /* NORMA_VM */ | |
459 | #if TRACE_BUFFER | |
460 | { "tr", db_show_tr, 0, 0 }, | |
461 | #endif /* TRACE_BUFFER */ | |
462 | { "space", db_show_one_space, 0, 0 }, | |
463 | { "system", (db_func) db_system_stats, 0, 0 }, | |
464 | { "zone", db_show_one_zone, 0, 0 }, | |
91447636 A |
465 | { "lock", (db_func)db_show_one_lock, 0, 0 }, |
466 | { "mutex_lock", (db_func)db_show_one_mutex, 0, 0 }, | |
467 | { "simple_lock", (db_func)db_show_one_simple_lock, 0, 0 }, | |
1c79356b | 468 | { "thread_log", (db_func)db_show_thread_log, 0, 0 }, |
1c79356b | 469 | { "shuttle", db_show_shuttle, 0, 0 }, |
1c79356b A |
470 | { (char *)0, } |
471 | }; | |
472 | ||
1c79356b A |
473 | #define db_switch_cpu kdb_on |
474 | extern void db_switch_cpu(int); | |
1c79356b A |
475 | |
476 | struct db_command db_command_table[] = { | |
477 | #if DB_MACHINE_COMMANDS | |
478 | ||
479 | /* this must be the first entry, if it exists */ | |
480 | { "machine", 0, 0, 0 }, | |
481 | #endif | |
482 | { "print", (db_func) db_print_cmd, CS_OWN, 0 }, | |
483 | { "examine", db_examine_cmd, CS_MORE|CS_SET_DOT, 0 }, | |
484 | { "x", db_examine_cmd, CS_MORE|CS_SET_DOT, 0 }, | |
485 | { "xf", db_examine_forward, CS_SET_DOT, 0 }, | |
486 | { "xb", db_examine_backward, CS_SET_DOT, 0 }, | |
487 | { "search", (db_func) db_search_cmd, CS_OWN|CS_SET_DOT, 0 }, | |
488 | { "set", (db_func) db_set_cmd, CS_OWN, 0 }, | |
489 | { "write", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, | |
490 | { "w", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, | |
491 | { "delete", (db_func) db_delete_cmd, CS_OWN, 0 }, | |
492 | { "d", (db_func) db_delete_cmd, CS_OWN, 0 }, | |
493 | { "break", db_breakpoint_cmd, CS_MORE, 0 }, | |
494 | { "dwatch", db_deletewatch_cmd, CS_MORE, 0 }, | |
495 | { "watch", db_watchpoint_cmd, CS_MORE, 0 }, | |
496 | { "step", db_single_step_cmd, 0, 0 }, | |
497 | { "s", db_single_step_cmd, 0, 0 }, | |
498 | { "continue", db_continue_cmd, 0, 0 }, | |
499 | { "c", db_continue_cmd, 0, 0 }, | |
500 | { "gdb", db_continue_gdb, 0, 0 }, | |
501 | { "until", db_trace_until_call_cmd, 0, 0 }, | |
502 | ||
503 | /* As per request of DNoveck, CR1550, leave this disabled */ | |
504 | #if 0 /* until CR1440 is fixed, to avoid toe-stubbing */ | |
505 | { "next", db_trace_until_matching_cmd, 0, 0 }, | |
506 | #endif | |
507 | { "match", db_trace_until_matching_cmd, 0 , 0 }, | |
508 | { "trace", db_stack_trace_cmd, 0, 0 }, | |
509 | { "cond", (db_func) db_cond_cmd, CS_OWN, 0 }, | |
510 | { "call", (db_func) db_fncall, CS_OWN, 0 }, | |
511 | { "macro", (db_func) db_def_macro_cmd, CS_OWN, 0 }, | |
512 | { "dmacro", (db_func) db_del_macro_cmd, CS_OWN, 0 }, | |
513 | { "show", 0, 0, db_show_cmds }, | |
1c79356b | 514 | { "cpu", (db_func) db_switch_cpu, 0, 0 }, |
1c79356b | 515 | { "reboot", (db_func) db_reboot, 0, 0 }, |
8ad349bb | 516 | #if defined(__ppc__) |
1c79356b A |
517 | { "lt", db_low_trace, CS_MORE|CS_SET_DOT, 0 }, |
518 | { "dl", db_display_long, CS_MORE|CS_SET_DOT, 0 }, | |
55e303ae | 519 | { "dc", db_display_char, CS_MORE|CS_SET_DOT, 0 }, |
8ad349bb | 520 | { "dr", db_display_real, CS_MORE|CS_SET_DOT, 0 }, |
1c79356b A |
521 | { "dv", db_display_virtual, CS_MORE|CS_SET_DOT, 0 }, |
522 | { "dm", db_display_mappings, CS_MORE|CS_SET_DOT, 0 }, | |
55e303ae | 523 | { "dh", db_display_hash, CS_MORE|CS_SET_DOT, 0 }, |
1c79356b | 524 | { "dp", db_display_pmap, CS_MORE, 0 }, |
8ad349bb | 525 | { "di", db_display_iokit, CS_MORE, 0 }, |
1c79356b A |
526 | { "ds", db_display_save, CS_MORE|CS_SET_DOT, 0 }, |
527 | { "dx", db_display_xregs, CS_MORE|CS_SET_DOT, 0 }, | |
8ad349bb | 528 | { "dk", db_display_kmod, CS_MORE, 0 }, |
1c79356b | 529 | { "gs", db_gsnoop, CS_MORE, 0 }, |
55e303ae A |
530 | { "cm", db_check_mappings, CS_MORE, 0 }, |
531 | { "cp", db_check_pmaps, CS_MORE, 0 }, | |
1c79356b A |
532 | #endif |
533 | { (char *)0, } | |
534 | }; | |
535 | ||
536 | /* this function should be called to install the machine dependent | |
537 | commands. It should be called before the debugger is enabled */ | |
538 | void db_machine_commands_install(struct db_command *ptr) | |
539 | { | |
540 | db_command_table[0].more = ptr; | |
541 | return; | |
542 | } | |
543 | ||
544 | ||
545 | struct db_command *db_last_command = 0; | |
546 | db_expr_t db_last_count = 0; | |
547 | char db_last_modifier[TOK_STRING_SIZE] = { '\0' }; | |
548 | ||
549 | void | |
550 | db_help_cmd(void) | |
551 | { | |
552 | struct db_command *cmd = db_command_table; | |
553 | ||
554 | while (cmd->name != 0) { | |
555 | db_printf("%-12s", cmd->name); | |
556 | db_end_line(); | |
557 | cmd++; | |
558 | } | |
559 | } | |
560 | ||
561 | int (*ddb_display)(void); | |
562 | ||
563 | void | |
564 | db_command_loop(void) | |
565 | { | |
566 | jmp_buf_t db_jmpbuf; | |
567 | jmp_buf_t *prev = db_recover; | |
568 | extern int db_output_line; | |
569 | extern int db_macro_level; | |
570 | extern int db_indent; | |
571 | ||
572 | /* | |
573 | * Initialize 'prev' and 'next' to dot. | |
574 | */ | |
575 | db_prev = db_dot; | |
576 | db_next = db_dot; | |
577 | ||
578 | if (ddb_display) | |
579 | (*ddb_display)(); | |
580 | ||
581 | db_cmd_loop_done = 0; | |
582 | while (!db_cmd_loop_done) { | |
583 | (void) _setjmp(db_recover = &db_jmpbuf); | |
584 | db_macro_level = 0; | |
585 | if (db_print_position() != 0) | |
586 | db_printf("\n"); | |
587 | db_output_line = 0; | |
588 | db_indent = 0; | |
589 | db_reset_more(); | |
590 | db_output_prompt(); | |
591 | ||
592 | (void) db_read_line("!!"); | |
593 | db_command_list(&db_last_command, &db_last_count, | |
594 | db_last_modifier, db_command_table); | |
595 | } | |
596 | ||
597 | db_recover = prev; | |
598 | } | |
599 | ||
600 | boolean_t | |
601 | db_exec_cmd_nest( | |
91447636 A |
602 | const char *cmd, |
603 | int size) | |
1c79356b A |
604 | { |
605 | struct db_lex_context lex_context; | |
606 | ||
607 | db_cmd_loop_done = 0; | |
608 | if (cmd) { | |
609 | db_save_lex_context(&lex_context); | |
610 | db_switch_input(cmd, size); | |
611 | } | |
612 | db_command_list(&db_last_command, &db_last_count, | |
613 | db_last_modifier, db_command_table); | |
614 | if (cmd) | |
615 | db_restore_lex_context(&lex_context); | |
616 | return(db_cmd_loop_done == 0); | |
617 | } | |
618 | ||
619 | void | |
91447636 | 620 | db_error(const char *s) |
1c79356b A |
621 | { |
622 | extern int db_macro_level; | |
623 | ||
1c79356b A |
624 | db_macro_level = 0; |
625 | if (db_recover) { | |
626 | if (s > (char *)1) | |
627 | db_printf(s); | |
628 | db_flush_lex(); | |
629 | _longjmp(db_recover, (s == (char *)1) ? 2 : 1); | |
630 | } | |
631 | else | |
632 | { | |
633 | if (s > (char *)1) | |
634 | db_printf(s); | |
635 | panic("db_error"); | |
636 | } | |
637 | } | |
638 | ||
639 | ||
640 | /* | |
641 | * Call random function: | |
642 | * !expr(arg,arg,arg) | |
643 | */ | |
644 | void | |
645 | db_fncall(void) | |
646 | { | |
647 | db_expr_t fn_addr; | |
648 | #define MAXARGS 11 | |
55e303ae A |
649 | uint32_t args[MAXARGS]; |
650 | db_expr_t argwork; | |
1c79356b | 651 | int nargs = 0; |
55e303ae A |
652 | uint32_t retval; |
653 | uint32_t (*func)(uint32_t, ...); | |
1c79356b A |
654 | int t; |
655 | ||
656 | if (!db_expression(&fn_addr)) { | |
657 | db_printf("Bad function \"%s\"\n", db_tok_string); | |
658 | db_flush_lex(); | |
659 | return; | |
660 | } | |
55e303ae | 661 | func = (uint32_t (*) (uint32_t, ...)) fn_addr; |
1c79356b A |
662 | |
663 | t = db_read_token(); | |
664 | if (t == tLPAREN) { | |
55e303ae A |
665 | if (db_expression(&argwork)) { |
666 | args[nargs] = (uint32_t)argwork; | |
667 | nargs++; | |
668 | while ((t = db_read_token()) == tCOMMA) { | |
669 | if (nargs == MAXARGS) { | |
670 | db_printf("Too many arguments\n"); | |
671 | db_flush_lex(); | |
672 | return; | |
673 | } | |
674 | if (!db_expression(&argwork)) { | |
675 | db_printf("Argument missing\n"); | |
676 | db_flush_lex(); | |
677 | return; | |
678 | } | |
679 | args[nargs] = (uint32_t)argwork; | |
680 | nargs++; | |
681 | } | |
682 | db_unread_token(t); | |
de355530 A |
683 | } |
684 | if (db_read_token() != tRPAREN) { | |
55e303ae A |
685 | db_printf("?\n"); |
686 | db_flush_lex(); | |
687 | return; | |
1c79356b A |
688 | } |
689 | } | |
690 | while (nargs < MAXARGS) { | |
691 | args[nargs++] = 0; | |
692 | } | |
693 | ||
694 | retval = (*func)(args[0], args[1], args[2], args[3], args[4], | |
695 | args[5], args[6], args[7], args[8], args[9] ); | |
696 | db_printf(" %#n\n", retval); | |
697 | } | |
698 | ||
699 | boolean_t | |
700 | db_option( | |
91447636 A |
701 | const char *modif, |
702 | int option) | |
1c79356b A |
703 | { |
704 | register char *p; | |
705 | ||
706 | for (p = modif; *p; p++) | |
707 | if (*p == option) | |
708 | return(TRUE); | |
709 | return(FALSE); | |
710 | } |