]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/ddb/db_command.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / sys / ddb / db_command.c
1 /*-
2  * Mach Operating System
3  * Copyright (c) 1991,1990 Carnegie Mellon University
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify and distribute this software and its
7  * documentation is hereby granted, provided that both the copyright
8  * notice and this permission notice appear in all copies of the
9  * software, derivative works or modified versions, and any portions
10  * thereof, and that both notices appear in supporting documentation.
11  *
12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15  *
16  * Carnegie Mellon requests users of this software to return to
17  *
18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19  *  School of Computer Science
20  *  Carnegie Mellon University
21  *  Pittsburgh PA 15213-3890
22  *
23  * any improvements or extensions that they make and grant Carnegie the
24  * rights to redistribute these changes.
25  */
26 /*
27  *      Author: David B. Golub, Carnegie Mellon University
28  *      Date:   7/90
29  */
30 /*
31  * Command dispatcher.
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/param.h>
38 #include <sys/linker_set.h>
39 #include <sys/lock.h>
40 #include <sys/kdb.h>
41 #include <sys/mutex.h>
42 #include <sys/proc.h>
43 #include <sys/reboot.h>
44 #include <sys/signalvar.h>
45 #include <sys/systm.h>
46 #include <sys/cons.h>
47 #include <sys/watchdog.h>
48
49 #include <ddb/ddb.h>
50 #include <ddb/db_command.h>
51 #include <ddb/db_lex.h>
52 #include <ddb/db_output.h>
53
54 #include <machine/cpu.h>
55 #include <machine/setjmp.h>
56
57 /*
58  * Exported global variables
59  */
60 boolean_t       db_cmd_loop_done;
61 db_addr_t       db_dot;
62 db_addr_t       db_last_addr;
63 db_addr_t       db_prev;
64 db_addr_t       db_next;
65
66 SET_DECLARE(db_cmd_set, struct command);
67 SET_DECLARE(db_show_cmd_set, struct command);
68
69 static db_cmdfcn_t      db_fncall;
70 static db_cmdfcn_t      db_gdb;
71 static db_cmdfcn_t      db_halt;
72 static db_cmdfcn_t      db_kill;
73 static db_cmdfcn_t      db_reset;
74 static db_cmdfcn_t      db_stack_trace;
75 static db_cmdfcn_t      db_stack_trace_all;
76 static db_cmdfcn_t      db_watchdog;
77
78 /*
79  * 'show' commands
80  */
81
82 static struct command db_show_all_cmds[] = {
83         { "procs",      db_ps,                  0,      0 },
84         { (char *)0 }
85 };
86
87 static struct command db_show_cmds[] = {
88         { "all",        0,                      0,      db_show_all_cmds },
89         { "registers",  db_show_regs,           0,      0 },
90         { "breaks",     db_listbreak_cmd,       0,      0 },
91         { "threads",    db_show_threads,        0,      0 },
92         { (char *)0, }
93 };
94
95 static struct command db_command_table[] = {
96         { "print",      db_print_cmd,           0,      0 },
97         { "p",          db_print_cmd,           0,      0 },
98         { "examine",    db_examine_cmd,         CS_SET_DOT, 0 },
99         { "x",          db_examine_cmd,         CS_SET_DOT, 0 },
100         { "search",     db_search_cmd,          CS_OWN|CS_SET_DOT, 0 },
101         { "set",        db_set_cmd,             CS_OWN, 0 },
102         { "write",      db_write_cmd,           CS_MORE|CS_SET_DOT, 0 },
103         { "w",          db_write_cmd,           CS_MORE|CS_SET_DOT, 0 },
104         { "delete",     db_delete_cmd,          0,      0 },
105         { "d",          db_delete_cmd,          0,      0 },
106         { "break",      db_breakpoint_cmd,      0,      0 },
107         { "dwatch",     db_deletewatch_cmd,     0,      0 },
108         { "watch",      db_watchpoint_cmd,      CS_MORE,0 },
109         { "dhwatch",    db_deletehwatch_cmd,    0,      0 },
110         { "hwatch",     db_hwatchpoint_cmd,     0,      0 },
111         { "step",       db_single_step_cmd,     0,      0 },
112         { "s",          db_single_step_cmd,     0,      0 },
113         { "continue",   db_continue_cmd,        0,      0 },
114         { "c",          db_continue_cmd,        0,      0 },
115         { "until",      db_trace_until_call_cmd,0,      0 },
116         { "next",       db_trace_until_matching_cmd,0,  0 },
117         { "match",      db_trace_until_matching_cmd,0,  0 },
118         { "trace",      db_stack_trace,         CS_OWN, 0 },
119         { "alltrace",   db_stack_trace_all,     0,      0 },
120         { "where",      db_stack_trace,         CS_OWN, 0 },
121         { "bt",         db_stack_trace,         CS_OWN, 0 },
122         { "call",       db_fncall,              CS_OWN, 0 },
123         { "show",       0,                      0,      db_show_cmds },
124         { "ps",         db_ps,                  0,      0 },
125         { "gdb",        db_gdb,                 0,      0 },
126         { "halt",       db_halt,                0,      0 },
127         { "reboot",     db_reset,               0,      0 },
128         { "reset",      db_reset,               0,      0 },
129         { "kill",       db_kill,                CS_OWN, 0 },
130         { "watchdog",   db_watchdog,            0,      0 },
131         { "thread",     db_set_thread,          CS_OWN, 0 },
132         { (char *)0, }
133 };
134
135 static struct command   *db_last_command = 0;
136
137
138 /*
139  * if 'ed' style: 'dot' is set at start of last item printed,
140  * and '+' points to next line.
141  * Otherwise: 'dot' points to next item, '..' points to last.
142  */
143 static boolean_t        db_ed_style = TRUE;
144
145 /*
146  * Utility routine - discard tokens through end-of-line.
147  */
148 void
149 db_skip_to_eol()
150 {
151         int     t;
152         do {
153             t = db_read_token();
154         } while (t != tEOL);
155 }
156
157 /*
158  * Results of command search.
159  */
160 #define CMD_UNIQUE      0
161 #define CMD_FOUND       1
162 #define CMD_NONE        2
163 #define CMD_AMBIGUOUS   3
164 #define CMD_HELP        4
165
166 static void     db_cmd_list(struct command *table, struct command **aux_tablep,
167                     struct command **aux_tablep_end);
168 static int      db_cmd_search(char *name, struct command *table,
169                     struct command **aux_tablep,
170                     struct command **aux_tablep_end, struct command **cmdp);
171 static void     db_command(struct command **last_cmdp,
172                     struct command *cmd_table, struct command **aux_cmd_tablep,
173                     struct command **aux_cmd_tablep_end);
174
175 /*
176  * Search for command prefix.
177  */
178 static int
179 db_cmd_search(name, table, aux_tablep, aux_tablep_end, cmdp)
180         char *          name;
181         struct command  *table;
182         struct command  **aux_tablep;
183         struct command  **aux_tablep_end;
184         struct command  **cmdp; /* out */
185 {
186         struct command  *cmd;
187         struct command  **aux_cmdp;
188         int             result = CMD_NONE;
189
190         for (cmd = table; cmd->name != 0; cmd++) {
191             register char *lp;
192             register char *rp;
193             register int  c;
194
195             lp = name;
196             rp = cmd->name;
197             while ((c = *lp) == *rp) {
198                 if (c == 0) {
199                     /* complete match */
200                     *cmdp = cmd;
201                     return (CMD_UNIQUE);
202                 }
203                 lp++;
204                 rp++;
205             }
206             if (c == 0) {
207                 /* end of name, not end of command -
208                    partial match */
209                 if (result == CMD_FOUND) {
210                     result = CMD_AMBIGUOUS;
211                     /* but keep looking for a full match -
212                        this lets us match single letters */
213                 }
214                 else {
215                     *cmdp = cmd;
216                     result = CMD_FOUND;
217                 }
218             }
219         }
220         if (result == CMD_NONE && aux_tablep != 0)
221             /* XXX repeat too much code. */
222             for (aux_cmdp = aux_tablep; aux_cmdp < aux_tablep_end; aux_cmdp++) {
223                 register char *lp;
224                 register char *rp;
225                 register int  c;
226
227                 lp = name;
228                 rp = (*aux_cmdp)->name;
229                 while ((c = *lp) == *rp) {
230                     if (c == 0) {
231                         /* complete match */
232                         *cmdp = *aux_cmdp;
233                         return (CMD_UNIQUE);
234                     }
235                     lp++;
236                     rp++;
237                 }
238                 if (c == 0) {
239                     /* end of name, not end of command -
240                        partial match */
241                     if (result == CMD_FOUND) {
242                         result = CMD_AMBIGUOUS;
243                         /* but keep looking for a full match -
244                            this lets us match single letters */
245                     }
246                     else {
247                         *cmdp = *aux_cmdp;
248                         result = CMD_FOUND;
249                     }
250                 }
251             }
252         if (result == CMD_NONE) {
253             /* check for 'help' */
254                 if (name[0] == 'h' && name[1] == 'e'
255                     && name[2] == 'l' && name[3] == 'p')
256                         result = CMD_HELP;
257         }
258         return (result);
259 }
260
261 static void
262 db_cmd_list(table, aux_tablep, aux_tablep_end)
263         struct command *table;
264         struct command **aux_tablep;
265         struct command **aux_tablep_end;
266 {
267         register struct command *cmd;
268         register struct command **aux_cmdp;
269
270         for (cmd = table; cmd->name != 0; cmd++) {
271             db_printf("%-12s", cmd->name);
272             db_end_line();
273         }
274         if (aux_tablep == 0)
275             return;
276         for (aux_cmdp = aux_tablep; aux_cmdp < aux_tablep_end; aux_cmdp++) {
277             db_printf("%-12s", (*aux_cmdp)->name);
278             db_end_line();
279         }
280 }
281
282 static void
283 db_command(last_cmdp, cmd_table, aux_cmd_tablep, aux_cmd_tablep_end)
284         struct command  **last_cmdp;    /* IN_OUT */
285         struct command  *cmd_table;
286         struct command  **aux_cmd_tablep;
287         struct command  **aux_cmd_tablep_end;
288 {
289         struct command  *cmd;
290         int             t;
291         char            modif[TOK_STRING_SIZE];
292         db_expr_t       addr, count;
293         boolean_t       have_addr = FALSE;
294         int             result;
295
296         t = db_read_token();
297         if (t == tEOL) {
298             /* empty line repeats last command, at 'next' */
299             cmd = *last_cmdp;
300             addr = (db_expr_t)db_next;
301             have_addr = FALSE;
302             count = 1;
303             modif[0] = '\0';
304         }
305         else if (t == tEXCL) {
306             db_fncall((db_expr_t)0, (boolean_t)0, (db_expr_t)0, (char *)0);
307             return;
308         }
309         else if (t != tIDENT) {
310             db_printf("?\n");
311             db_flush_lex();
312             return;
313         }
314         else {
315             /*
316              * Search for command
317              */
318             while (cmd_table) {
319                 result = db_cmd_search(db_tok_string,
320                                        cmd_table,
321                                        aux_cmd_tablep,
322                                        aux_cmd_tablep_end,
323                                        &cmd);
324                 switch (result) {
325                     case CMD_NONE:
326                         db_printf("No such command\n");
327                         db_flush_lex();
328                         return;
329                     case CMD_AMBIGUOUS:
330                         db_printf("Ambiguous\n");
331                         db_flush_lex();
332                         return;
333                     case CMD_HELP:
334                         db_cmd_list(cmd_table, aux_cmd_tablep, aux_cmd_tablep_end);
335                         db_flush_lex();
336                         return;
337                     default:
338                         break;
339                 }
340                 if ((cmd_table = cmd->more) != 0) {
341                     /* XXX usually no more aux's. */
342                     aux_cmd_tablep = 0;
343                     if (cmd_table == db_show_cmds) {
344                         aux_cmd_tablep = SET_BEGIN(db_show_cmd_set);
345                         aux_cmd_tablep_end = SET_LIMIT(db_show_cmd_set);
346                     }
347
348                     t = db_read_token();
349                     if (t != tIDENT) {
350                         db_cmd_list(cmd_table, aux_cmd_tablep, aux_cmd_tablep_end);
351                         db_flush_lex();
352                         return;
353                     }
354                 }
355             }
356
357             if ((cmd->flag & CS_OWN) == 0) {
358                 /*
359                  * Standard syntax:
360                  * command [/modifier] [addr] [,count]
361                  */
362                 t = db_read_token();
363                 if (t == tSLASH) {
364                     t = db_read_token();
365                     if (t != tIDENT) {
366                         db_printf("Bad modifier\n");
367                         db_flush_lex();
368                         return;
369                     }
370                     db_strcpy(modif, db_tok_string);
371                 }
372                 else {
373                     db_unread_token(t);
374                     modif[0] = '\0';
375                 }
376
377                 if (db_expression(&addr)) {
378                     db_dot = (db_addr_t) addr;
379                     db_last_addr = db_dot;
380                     have_addr = TRUE;
381                 }
382                 else {
383                     addr = (db_expr_t) db_dot;
384                     have_addr = FALSE;
385                 }
386                 t = db_read_token();
387                 if (t == tCOMMA) {
388                     if (!db_expression(&count)) {
389                         db_printf("Count missing\n");
390                         db_flush_lex();
391                         return;
392                     }
393                 }
394                 else {
395                     db_unread_token(t);
396                     count = -1;
397                 }
398                 if ((cmd->flag & CS_MORE) == 0) {
399                     db_skip_to_eol();
400                 }
401             }
402         }
403         *last_cmdp = cmd;
404         if (cmd != 0) {
405             /*
406              * Execute the command.
407              */
408             (*cmd->fcn)(addr, have_addr, count, modif);
409             db_setup_paging(NULL, NULL, -1);
410
411             if (cmd->flag & CS_SET_DOT) {
412                 /*
413                  * If command changes dot, set dot to
414                  * previous address displayed (if 'ed' style).
415                  */
416                 if (db_ed_style) {
417                     db_dot = db_prev;
418                 }
419                 else {
420                     db_dot = db_next;
421                 }
422             }
423             else {
424                 /*
425                  * If command does not change dot,
426                  * set 'next' location to be the same.
427                  */
428                 db_next = db_dot;
429             }
430         }
431 }
432
433 /*
434  * At least one non-optional command must be implemented using
435  * DB_COMMAND() so that db_cmd_set gets created.  Here is one.
436  */
437 DB_COMMAND(panic, db_panic)
438 {
439         panic("from debugger");
440 }
441
442 void
443 db_command_loop()
444 {
445         /*
446          * Initialize 'prev' and 'next' to dot.
447          */
448         db_prev = db_dot;
449         db_next = db_dot;
450
451         db_cmd_loop_done = 0;
452         while (!db_cmd_loop_done) {
453             if (db_print_position() != 0)
454                 db_printf("\n");
455
456             db_printf("db> ");
457             (void) db_read_line();
458
459             db_command(&db_last_command, db_command_table,
460                        SET_BEGIN(db_cmd_set), SET_LIMIT(db_cmd_set));
461         }
462 }
463
464 void
465 db_error(s)
466         const char *s;
467 {
468         if (s)
469             db_printf("%s", s);
470         db_flush_lex();
471         kdb_reenter();
472 }
473
474
475 /*
476  * Call random function:
477  * !expr(arg,arg,arg)
478  */
479
480 /* The generic implementation supports a maximum of 10 arguments. */
481 typedef db_expr_t __db_f(db_expr_t, db_expr_t, db_expr_t, db_expr_t,
482     db_expr_t, db_expr_t, db_expr_t, db_expr_t, db_expr_t, db_expr_t);
483
484 static __inline int
485 db_fncall_generic(db_expr_t addr, db_expr_t *rv, int nargs, db_expr_t args[])
486 {
487         __db_f *f = (__db_f *)addr;
488
489         if (nargs > 10) {
490                 db_printf("Too many arguments (max 10)\n");
491                 return (0);
492         }
493         *rv = (*f)(args[0], args[1], args[2], args[3], args[4], args[5],
494             args[6], args[7], args[8], args[9]);
495         return (1);
496 }
497
498 static void
499 db_fncall(dummy1, dummy2, dummy3, dummy4)
500         db_expr_t       dummy1;
501         boolean_t       dummy2;
502         db_expr_t       dummy3;
503         char *          dummy4;
504 {
505         db_expr_t       fn_addr;
506         db_expr_t       args[DB_MAXARGS];
507         int             nargs = 0;
508         db_expr_t       retval;
509         int             t;
510
511         if (!db_expression(&fn_addr)) {
512             db_printf("Bad function\n");
513             db_flush_lex();
514             return;
515         }
516
517         t = db_read_token();
518         if (t == tLPAREN) {
519             if (db_expression(&args[0])) {
520                 nargs++;
521                 while ((t = db_read_token()) == tCOMMA) {
522                     if (nargs == DB_MAXARGS) {
523                         db_printf("Too many arguments (max %d)\n", DB_MAXARGS);
524                         db_flush_lex();
525                         return;
526                     }
527                     if (!db_expression(&args[nargs])) {
528                         db_printf("Argument missing\n");
529                         db_flush_lex();
530                         return;
531                     }
532                     nargs++;
533                 }
534                 db_unread_token(t);
535             }
536             if (db_read_token() != tRPAREN) {
537                 db_printf("?\n");
538                 db_flush_lex();
539                 return;
540             }
541         }
542         db_skip_to_eol();
543
544         if (DB_CALL(fn_addr, &retval, nargs, args))
545                 db_printf("= %#lr\n", (long)retval);
546 }
547
548 static void
549 db_halt(db_expr_t dummy, boolean_t dummy2, db_expr_t dummy3, char *dummy4)
550 {
551
552         cpu_halt();
553 }
554
555 static void
556 db_kill(dummy1, dummy2, dummy3, dummy4)
557         db_expr_t       dummy1;
558         boolean_t       dummy2;
559         db_expr_t       dummy3;
560         char *          dummy4;
561 {
562         db_expr_t old_radix, pid, sig;
563         struct proc *p;
564
565 #define DB_ERROR(f)     do { db_printf f; db_flush_lex(); goto out; } while (0)
566
567         /*
568          * PIDs and signal numbers are typically represented in base
569          * 10, so make that the default here.  It can, of course, be
570          * overridden by specifying a prefix.
571          */
572         old_radix = db_radix;
573         db_radix = 10;
574         /* Retrieve arguments. */
575         if (!db_expression(&sig))
576                 DB_ERROR(("Missing signal number\n"));
577         if (!db_expression(&pid))
578                 DB_ERROR(("Missing process ID\n"));
579         db_skip_to_eol();
580         if (sig < 1 || sig > _SIG_MAXSIG)
581                 DB_ERROR(("Signal number out of range\n"));
582
583         /*
584          * Find the process in question.  allproc_lock is not needed
585          * since we're in DDB.
586          */
587         /* sx_slock(&allproc_lock); */
588         LIST_FOREACH(p, &allproc, p_list)
589             if (p->p_pid == pid)
590                     break;
591         /* sx_sunlock(&allproc_lock); */
592         if (p == NULL)
593                 DB_ERROR(("Can't find process with pid %ld\n", (long) pid));
594
595         /* If it's already locked, bail; otherwise, do the deed. */
596         if (PROC_TRYLOCK(p) == 0)
597                 DB_ERROR(("Can't lock process with pid %ld\n", (long) pid));
598         else {
599                 psignal(p, sig);
600                 PROC_UNLOCK(p);
601         }
602
603 out:
604         db_radix = old_radix;
605 #undef DB_ERROR
606 }
607
608 static void
609 db_reset(dummy1, dummy2, dummy3, dummy4)
610         db_expr_t       dummy1;
611         boolean_t       dummy2;
612         db_expr_t       dummy3;
613         char *          dummy4;
614 {
615
616         cpu_reset();
617 }
618
619 static void
620 db_watchdog(dummy1, dummy2, dummy3, dummy4)
621         db_expr_t       dummy1;
622         boolean_t       dummy2;
623         db_expr_t       dummy3;
624         char *          dummy4;
625 {
626         int i;
627
628         /*
629          * XXX: It might make sense to be able to set the watchdog to a
630          * XXX: timeout here so that failure or hang as a result of subsequent
631          * XXX: ddb commands could be recovered by a reset.
632          */
633
634         EVENTHANDLER_INVOKE(watchdog_list, 0, &i);
635 }
636
637 static void
638 db_gdb(db_expr_t dummy1, boolean_t dummy2, db_expr_t dummy3, char *dummy4)
639 {
640
641         if (kdb_dbbe_select("gdb") != 0)
642                 db_printf("The remote GDB backend could not be selected.\n");
643         else
644                 db_printf("Step to enter the remote GDB backend.\n");
645 }
646
647 static void
648 db_stack_trace(db_expr_t tid, boolean_t hastid, db_expr_t count, char *modif)
649 {
650         struct thread *td;
651         db_expr_t radix;
652         pid_t pid;
653         int t;
654
655         /*
656          * We parse our own arguments. We don't like the default radix.
657          */
658         radix = db_radix;
659         db_radix = 10;
660         hastid = db_expression(&tid);
661         t = db_read_token();
662         if (t == tCOMMA) {
663                 if (!db_expression(&count)) {
664                         db_printf("Count missing\n");
665                         db_flush_lex();
666                         return;
667                 }
668         } else {
669                 db_unread_token(t);
670                 count = -1;
671         }
672         db_skip_to_eol();
673         db_radix = radix;
674
675         if (hastid) {
676                 td = kdb_thr_lookup((lwpid_t)tid);
677                 if (td == NULL)
678                         td = kdb_thr_from_pid((pid_t)tid);
679                 if (td == NULL) {
680                         db_printf("Thread %d not found\n", (int)tid);
681                         return;
682                 }
683         } else
684                 td = kdb_thread;
685         if (td->td_proc != NULL)
686                 pid = td->td_proc->p_pid;
687         else
688                 pid = -1;
689         db_printf("Tracing pid %d tid %ld td %p\n", pid, (long)td->td_tid, td);
690         db_trace_thread(td, count);
691 }
692
693 static void
694 db_stack_trace_all(db_expr_t dummy, boolean_t dummy2, db_expr_t dummy3,
695     char *dummy4)
696 {
697         struct proc *p;
698         struct thread *td;
699
700         for (p = LIST_FIRST(&allproc); p != NULL; p = LIST_NEXT(p, p_list)) {
701                 FOREACH_THREAD_IN_PROC(p, td) {
702                         db_printf("\nTracing command %s pid %d tid %ld td %p\n",
703                             p->p_comm, p->p_pid, (long)td->td_tid, td);
704                         db_trace_thread(td, -1);
705                 }
706         }
707 }