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