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