]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/db_command.c
xnu-1228.tar.gz
[apple/xnu.git] / osfmk / ddb / db_command.c
1 /*
2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
57 */
58 /*
59 * Author: David B. Golub, Carnegie Mellon University
60 * Date: 7/90
61 */
62
63 /*
64 * Command dispatcher.
65 */
66 #include <norma_vm.h>
67 #ifdef AT386
68 #include <norma_scsi.h>
69 #endif /* AT386 */
70
71 #include <mach/boolean.h>
72 #include <string.h>
73 #include <machine/db_machdep.h>
74
75 #if defined(__alpha)
76 # include <kdebug.h>
77 # if KDEBUG
78 # include <machine/kdebug.h>
79 # endif
80 #endif /* defined(__alpha) */
81
82 #include <ddb/db_lex.h>
83 #include <ddb/db_output.h>
84 #include <ddb/db_break.h>
85 #include <ddb/db_command.h>
86 #include <ddb/db_cond.h>
87 #include <ddb/db_examine.h>
88 #include <ddb/db_expr.h>
89 #if defined(__ppc__)
90 #include <ppc/db_low_trace.h>
91 #endif
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_fncall(void);
154
155 void db_cmd_list(struct db_command *table);
156
157 int db_cmd_search(
158 char * name,
159 struct db_command * table,
160 struct db_command ** cmdp); /* out */
161
162 void db_command_list(
163 struct db_command **last_cmdp, /* IN_OUT */
164 db_expr_t *last_countp, /* IN_OUT */
165 char *last_modifp, /* IN_OUT */
166 struct db_command *cmd_table);
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 const 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 struct db_command *new;
222 struct db_command *old;
223 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 strncmp(cur->name, new->name, strlen(cur->name)) < 0) &&
238 (old == (struct db_command *)0 ||
239 strncmp(cur->name, old->name, strlen(cur->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 = FALSE;
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 strlcpy(modif, db_tok_string, TOK_STRING_SIZE);
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 strlcpy(last_modifp, modifp, TOK_STRING_SIZE);
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 {
412 .name = "acts",
413 .fcn = db_show_all_acts,
414 },
415 {
416 .name = "spaces",
417 .fcn = db_show_all_spaces,
418 },
419 {
420 .name = "tasks",
421 .fcn = db_show_all_acts,
422 },
423 /* temporary alias for sanity preservation */
424 {
425 .name ="threads",
426 db_show_all_acts,
427 },
428 {
429 .name = "zones",
430 .fcn = db_show_all_zones,
431 },
432 {
433 .name = "vmtask",
434 .fcn = db_show_all_task_vm,
435 },
436 {
437 .name = (const char *)NULL,
438 },
439 };
440
441 /* XXX */
442
443 extern void db_show_thread_log(void);
444 extern void db_show_etap_log(db_expr_t, int, db_expr_t, char *);
445
446 struct db_command db_show_cmds[] = {
447 {
448 .name = "all",
449 .more = db_show_all_cmds
450 },
451 {
452 .name = "registers",
453 .fcn = db_show_regs,
454 },
455 {
456 .name = "variables",
457 .fcn = db_show_variable,
458 .flag = CS_OWN,
459 },
460 {
461 .name = "breaks",
462 .fcn = db_listbreak_cmd,
463 },
464 {
465 .name = "watches",
466 .fcn = db_listwatch_cmd,
467 },
468 {
469 .name = "task",
470 .fcn = db_show_one_task,
471 },
472 {
473 .name = "act",
474 .fcn = db_show_one_act,
475 },
476 {
477 .name = "shuttle",
478 .fcn = db_show_shuttle,
479 },
480 #if 0
481 {
482 .name = "thread",
483 .fcn = db_show_one_thread,
484 },
485 #endif
486 {
487 .name = "vmtask",
488 .fcn = db_show_one_task_vm,
489 },
490 {
491 .name = "macro",
492 .fcn = (db_func)db_show_macro,
493 .flag = CS_OWN,
494 },
495 {
496 .name = "runq",
497 .fcn = (db_func)db_show_runq,
498 },
499 {
500 .name = "map",
501 .fcn = (db_func)vm_map_print,
502 },
503 {
504 .name = "object",
505 .fcn = vm_object_print,
506 },
507 {
508 .name = "page",
509 .fcn = (db_func)vm_page_print,
510 },
511 {
512 .name = "copy",
513 .fcn = (db_func)vm_map_copy_print,
514 },
515 {
516 .name = "port",
517 .fcn = (db_func)ipc_port_print,
518 },
519 {
520 .name = "pset",
521 .fcn = (db_func)ipc_pset_print,
522 },
523 {
524 .name = "kmsg",
525 .fcn = (db_func)ipc_kmsg_print,
526 },
527 {
528 .name = "msg",
529 .fcn = (db_func)ipc_msg_print,
530 },
531 {
532 .name = "ipc_port",
533 .fcn = db_show_port_id,
534 },
535 #if NORMA_VM
536 {
537 .name = "xmm_obj",
538 .fcn = (db_func)xmm_obj_print,
539 },
540 {
541 .name = "xmm_reply",
542 .fcn = (db_func)xmm_reply_print,
543 },
544 #endif /* NORMA_VM */
545 #if TRACE_BUFFER
546 {
547 .name = "tr",
548 .fcn = db_show_tr,
549 },
550 #endif /* TRACE_BUFFER */
551 {
552 .name = "space",
553 .fcn = db_show_one_space,
554 },
555 {
556 .name = "system",
557 .fcn = (db_func)db_system_stats,
558 },
559 {
560 .name = "zone",
561 .fcn = db_show_one_zone,
562 },
563 {
564 .name = "lock",
565 .fcn = (db_func)db_show_one_lock,
566 },
567 {
568 .name = "mutex_lock",
569 .fcn = (db_func)db_show_one_mutex,
570 },
571 {
572 .name = "simple_lock",
573 .fcn = (db_func)db_show_one_simple_lock,
574 },
575 {
576 .name = "thread_log",
577 (db_func)db_show_thread_log,
578 },
579 {
580 .name = "shuttle",
581 .fcn = db_show_shuttle,
582 },
583 {
584 .name = (const char *)NULL,
585 },
586 };
587
588 #define db_switch_cpu kdb_on
589
590 struct db_command db_command_table[] = {
591 #if DB_MACHINE_COMMANDS
592 /* this must be the first entry, if it exists */
593 {
594 .name = "machine",
595 },
596 #endif /* DB_MACHINE_COMMANDS */
597 {
598 .name = "print",
599 .fcn = (db_func)db_print_cmd,
600 .flag = CS_OWN,
601 },
602 {
603 .name = "examine",
604 .fcn = db_examine_cmd,
605 .flag = CS_MORE|CS_SET_DOT,
606 },
607 {
608 .name = "x",
609 .fcn = db_examine_cmd,
610 .flag = CS_MORE|CS_SET_DOT,
611 },
612 {
613 .name = "xf",
614 .fcn = db_examine_forward,
615 .flag = CS_SET_DOT,
616 },
617 {
618 .name = "xb",
619 .fcn = db_examine_backward,
620 .flag = CS_SET_DOT,
621 },
622 {
623 .name = "search",
624 .fcn = (db_func)db_search_cmd,
625 .flag = CS_OWN|CS_SET_DOT,
626 },
627 {
628 .name = "set",
629 .fcn = (db_func)db_set_cmd,
630 .flag = CS_OWN,
631 },
632 {
633 .name = "write",
634 .fcn = db_write_cmd,
635 .flag = CS_MORE|CS_SET_DOT,
636 },
637 {
638 .name = "w",
639 .fcn = db_write_cmd,
640 .flag = CS_MORE|CS_SET_DOT,
641 },
642 {
643 .name = "delete",
644 .fcn = (db_func)db_delete_cmd,
645 .flag = CS_OWN,
646 },
647 {
648 .name = "d",
649 .fcn = (db_func)db_delete_cmd,
650 .flag = CS_OWN,
651 },
652 {
653 .name = "break",
654 .fcn = db_breakpoint_cmd,
655 .flag = CS_MORE,
656 },
657 {
658 .name = "dwatch",
659 .fcn = db_deletewatch_cmd,
660 .flag = CS_MORE,
661 },
662 {
663 .name = "watch",
664 .fcn = db_watchpoint_cmd,
665 .flag = CS_MORE,
666 },
667 {
668 .name = "step",
669 .fcn = db_single_step_cmd,
670 },
671 {
672 .name = "s",
673 .fcn = db_single_step_cmd,
674 },
675 {
676 .name = "continue",
677 .fcn = db_continue_cmd,
678 },
679 {
680 .name = "c",
681 .fcn = db_continue_cmd,
682 },
683 {
684 .name = "gdb",
685 .fcn = db_continue_gdb,
686 },
687 {
688 .name = "until",
689 .fcn = db_trace_until_call_cmd,
690 },
691
692 /* As per request of DNoveck, CR1550, leave this disabled */
693 #if 0 /* until CR1440 is fixed, to avoid toe-stubbing */
694 {
695 .name = "next",
696 .fcn = db_trace_until_matching_cmd,
697 },
698 #endif
699 {
700 .name = "match",
701 .fcn = db_trace_until_matching_cmd,
702 },
703 {
704 .name = "trace",
705 .fcn = db_stack_trace_cmd,
706 },
707 {
708 .name = "cond",
709 .fcn = (db_func)db_cond_cmd,
710 .flag = CS_OWN,
711 },
712 {
713 .name = "call",
714 .fcn = (db_func)db_fncall,
715 .flag = CS_OWN,
716 },
717 {
718 .name = "macro",
719 .fcn = (db_func)db_def_macro_cmd,
720 .flag = CS_OWN,
721 },
722 {
723 .name = "dmacro",
724 .fcn = (db_func)db_del_macro_cmd,
725 .flag = CS_OWN,
726 },
727 {
728 .name = "show",
729 .more = db_show_cmds
730 },
731 {
732 .name = "cpu",
733 .fcn = (db_func)db_switch_cpu,
734 },
735 {
736 .name = "dr",
737 .fcn = db_display_real,
738 .flag = CS_MORE|CS_SET_DOT,
739 },
740 {
741 .name = "di",
742 .fcn = db_display_iokit,
743 .flag = CS_MORE,
744 },
745 {
746 .name = "dk",
747 .fcn = db_display_kmod,
748 .flag = CS_MORE,
749 },
750
751 {
752 .name = "reboot",
753 (db_func)db_reboot,
754 },
755 #if !defined(__ppc__)
756 {
757 .name = "ms",
758 .fcn = db_msr,
759 .flag = CS_MORE,
760 },
761 {
762 .name = "cp",
763 .fcn = db_cpuid,
764 .flag = CS_MORE,
765 },
766 {
767 .name = "da",
768 .fcn = db_apic,
769 .flag = CS_MORE,
770 },
771 {
772 .name = "hp",
773 .fcn = db_hpet,
774 .flag = CS_MORE,
775 },
776 #endif /* !__ppc__ */
777 #if defined(__ppc__)
778 {
779 .name = "lt",
780 .fcn = db_low_trace,
781 .flag = CS_MORE|CS_SET_DOT,
782 },
783 {
784 .name = "dl",
785 .fcn = db_display_long,
786 .flag = CS_MORE|CS_SET_DOT,
787 },
788 {
789 .name = "dc",
790 .fcn = db_display_char,
791 .flag = CS_MORE|CS_SET_DOT,
792 },
793 {
794 .name = "dv",
795 .fcn = db_display_virtual,
796 .flag = CS_MORE|CS_SET_DOT,
797 },
798 {
799 .name = "dm",
800 .fcn = db_display_mappings,
801 .flag = CS_MORE|CS_SET_DOT,
802 },
803 {
804 .name = "dh",
805 .fcn = db_display_hash,
806 .flag = CS_MORE|CS_SET_DOT,
807 },
808 {
809 .name = "dp",
810 .fcn = db_display_pmap,
811 .flag = CS_MORE,
812 },
813 {
814 .name = "ds",
815 .fcn = db_display_save,
816 .flag = CS_MORE|CS_SET_DOT,
817 },
818 {
819 .name = "dx",
820 .fcn = db_display_xregs,
821 .flag = CS_MORE|CS_SET_DOT,
822 },
823 {
824 .name = "gs",
825 .fcn = db_gsnoop,
826 .flag = CS_MORE,
827 },
828 {
829 .name = "cm",
830 .fcn = db_check_mappings,
831 .flag = CS_MORE,
832 },
833 {
834 .name = "cp",
835 .fcn = db_check_pmaps,
836 .flag = CS_MORE,
837 },
838 #endif /* __ppc__ */
839 {
840 .name = (const char *)NULL,
841 },
842 };
843
844 /* this function should be called to install the machine dependent
845 commands. It should be called before the debugger is enabled */
846 void db_machine_commands_install(struct db_command *ptr)
847 {
848 db_command_table[0].more = ptr;
849 return;
850 }
851
852
853 struct db_command *db_last_command = 0;
854 db_expr_t db_last_count = 0;
855 char db_last_modifier[TOK_STRING_SIZE] = { '\0' };
856
857 void
858 db_help_cmd(void)
859 {
860 struct db_command *cmd = db_command_table;
861
862 while (cmd->name != 0) {
863 db_printf("%-12s", cmd->name);
864 db_end_line();
865 cmd++;
866 }
867 }
868
869 int (*ddb_display)(void);
870
871 extern int db_output_line;
872 extern int db_macro_level;
873
874 void
875 db_command_loop(void)
876 {
877 jmp_buf_t db_jmpbuf;
878 jmp_buf_t *prev = db_recover;
879
880 /*
881 * Initialize 'prev' and 'next' to dot.
882 */
883 db_prev = db_dot;
884 db_next = db_dot;
885
886 if (ddb_display)
887 (*ddb_display)();
888
889 db_cmd_loop_done = 0;
890 while (!db_cmd_loop_done) {
891 (void) _setjmp(db_recover = &db_jmpbuf);
892 db_macro_level = 0;
893 if (db_print_position() != 0)
894 db_printf("\n");
895 db_output_line = 0;
896 db_indent = 0;
897 db_reset_more();
898 db_output_prompt();
899
900 (void) db_read_line("!!");
901 db_command_list(&db_last_command, &db_last_count,
902 db_last_modifier, db_command_table);
903 }
904
905 db_recover = prev;
906 }
907
908 boolean_t
909 db_exec_cmd_nest(
910 const char *cmd,
911 int size)
912 {
913 struct db_lex_context lex_context;
914
915 db_cmd_loop_done = 0;
916 if (cmd) {
917 db_save_lex_context(&lex_context);
918 db_switch_input(cmd, size);
919 }
920 db_command_list(&db_last_command, &db_last_count,
921 db_last_modifier, db_command_table);
922 if (cmd)
923 db_restore_lex_context(&lex_context);
924 return(db_cmd_loop_done == 0);
925 }
926
927 void
928 db_error(const char *s)
929 {
930 db_macro_level = 0;
931 if (db_recover) {
932 if (s > (char *)1)
933 db_printf(s);
934 db_flush_lex();
935 _longjmp(db_recover, (s == (char *)1) ? 2 : 1);
936 }
937 else
938 {
939 if (s > (char *)1)
940 db_printf(s);
941 panic("db_error");
942 }
943 }
944
945
946 /*
947 * Call random function:
948 * !expr(arg,arg,arg)
949 */
950 void
951 db_fncall(void)
952 {
953 db_expr_t fn_addr;
954 #define MAXARGS 11
955 uint32_t args[MAXARGS];
956 db_expr_t argwork;
957 int nargs = 0;
958 uint32_t retval;
959 uint32_t (*func)(uint32_t, ...);
960 int t;
961
962 if (!db_expression(&fn_addr)) {
963 db_printf("Bad function \"%s\"\n", db_tok_string);
964 db_flush_lex();
965 return;
966 }
967 func = (uint32_t (*) (uint32_t, ...))(unsigned long)fn_addr;
968
969 t = db_read_token();
970 if (t == tLPAREN) {
971 if (db_expression(&argwork)) {
972 args[nargs] = (uint32_t)argwork;
973 nargs++;
974 while ((t = db_read_token()) == tCOMMA) {
975 if (nargs == MAXARGS) {
976 db_printf("Too many arguments\n");
977 db_flush_lex();
978 return;
979 }
980 if (!db_expression(&argwork)) {
981 db_printf("Argument missing\n");
982 db_flush_lex();
983 return;
984 }
985 args[nargs] = (uint32_t)argwork;
986 nargs++;
987 }
988 db_unread_token(t);
989 }
990 if (db_read_token() != tRPAREN) {
991 db_printf("?\n");
992 db_flush_lex();
993 return;
994 }
995 }
996 while (nargs < MAXARGS) {
997 args[nargs++] = 0;
998 }
999
1000 retval = (*func)(args[0], args[1], args[2], args[3], args[4],
1001 args[5], args[6], args[7], args[8], args[9] );
1002 db_printf(" %#n\n", retval);
1003 }
1004
1005 boolean_t
1006 db_option(
1007 const char *modif,
1008 int option)
1009 {
1010 const char *p;
1011
1012 for (p = modif; *p; p++)
1013 if (*p == option)
1014 return(TRUE);
1015 return(FALSE);
1016 }