1a9643ea8Slogwang /*-
2*22ce4affSfengbojiang * SPDX-License-Identifier: MIT-CMU
3*22ce4affSfengbojiang *
4a9643ea8Slogwang * Mach Operating System
5a9643ea8Slogwang * Copyright (c) 1991,1990 Carnegie Mellon University
6a9643ea8Slogwang * All Rights Reserved.
7a9643ea8Slogwang *
8a9643ea8Slogwang * Permission to use, copy, modify and distribute this software and its
9a9643ea8Slogwang * documentation is hereby granted, provided that both the copyright
10a9643ea8Slogwang * notice and this permission notice appear in all copies of the
11a9643ea8Slogwang * software, derivative works or modified versions, and any portions
12a9643ea8Slogwang * thereof, and that both notices appear in supporting documentation.
13a9643ea8Slogwang *
14a9643ea8Slogwang * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
15a9643ea8Slogwang * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16a9643ea8Slogwang * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17a9643ea8Slogwang *
18a9643ea8Slogwang * Carnegie Mellon requests users of this software to return to
19a9643ea8Slogwang *
20a9643ea8Slogwang * Software Distribution Coordinator or [email protected]
21a9643ea8Slogwang * School of Computer Science
22a9643ea8Slogwang * Carnegie Mellon University
23a9643ea8Slogwang * Pittsburgh PA 15213-3890
24a9643ea8Slogwang *
25a9643ea8Slogwang * any improvements or extensions that they make and grant Carnegie the
26a9643ea8Slogwang * rights to redistribute these changes.
27a9643ea8Slogwang */
28a9643ea8Slogwang /*
29a9643ea8Slogwang * Author: David B. Golub, Carnegie Mellon University
30a9643ea8Slogwang * Date: 7/90
31a9643ea8Slogwang */
32a9643ea8Slogwang /*
33a9643ea8Slogwang * Command dispatcher.
34a9643ea8Slogwang */
35a9643ea8Slogwang
36a9643ea8Slogwang #include <sys/cdefs.h>
37a9643ea8Slogwang __FBSDID("$FreeBSD$");
38a9643ea8Slogwang
39a9643ea8Slogwang #include <sys/param.h>
40*22ce4affSfengbojiang #include <sys/eventhandler.h>
41a9643ea8Slogwang #include <sys/linker_set.h>
42a9643ea8Slogwang #include <sys/lock.h>
43a9643ea8Slogwang #include <sys/kdb.h>
44a9643ea8Slogwang #include <sys/mutex.h>
45a9643ea8Slogwang #include <sys/proc.h>
46a9643ea8Slogwang #include <sys/reboot.h>
47a9643ea8Slogwang #include <sys/signalvar.h>
48a9643ea8Slogwang #include <sys/systm.h>
49a9643ea8Slogwang #include <sys/cons.h>
50a9643ea8Slogwang #include <sys/conf.h>
51a9643ea8Slogwang #include <sys/watchdog.h>
52a9643ea8Slogwang #include <sys/kernel.h>
53a9643ea8Slogwang
54a9643ea8Slogwang #include <ddb/ddb.h>
55a9643ea8Slogwang #include <ddb/db_command.h>
56a9643ea8Slogwang #include <ddb/db_lex.h>
57a9643ea8Slogwang #include <ddb/db_output.h>
58a9643ea8Slogwang
59a9643ea8Slogwang #include <machine/cpu.h>
60a9643ea8Slogwang #include <machine/setjmp.h>
61a9643ea8Slogwang
62a9643ea8Slogwang /*
63a9643ea8Slogwang * Exported global variables
64a9643ea8Slogwang */
65*22ce4affSfengbojiang int db_cmd_loop_done;
66a9643ea8Slogwang db_addr_t db_dot;
67a9643ea8Slogwang db_addr_t db_last_addr;
68a9643ea8Slogwang db_addr_t db_prev;
69a9643ea8Slogwang db_addr_t db_next;
70a9643ea8Slogwang
71a9643ea8Slogwang static db_cmdfcn_t db_dump;
72a9643ea8Slogwang static db_cmdfcn_t db_fncall;
73a9643ea8Slogwang static db_cmdfcn_t db_gdb;
74a9643ea8Slogwang static db_cmdfcn_t db_halt;
75a9643ea8Slogwang static db_cmdfcn_t db_kill;
76a9643ea8Slogwang static db_cmdfcn_t db_reset;
77a9643ea8Slogwang static db_cmdfcn_t db_stack_trace;
78*22ce4affSfengbojiang static db_cmdfcn_t db_stack_trace_active;
79a9643ea8Slogwang static db_cmdfcn_t db_stack_trace_all;
80a9643ea8Slogwang static db_cmdfcn_t db_watchdog;
81a9643ea8Slogwang
82a9643ea8Slogwang /*
83a9643ea8Slogwang * 'show' commands
84a9643ea8Slogwang */
85a9643ea8Slogwang
86*22ce4affSfengbojiang static struct command db_show_active_cmds[] = {
87*22ce4affSfengbojiang { "trace", db_stack_trace_active, 0, NULL },
88*22ce4affSfengbojiang };
89*22ce4affSfengbojiang struct command_table db_show_active_table =
90*22ce4affSfengbojiang LIST_HEAD_INITIALIZER(db_show_active_table);
91*22ce4affSfengbojiang
92a9643ea8Slogwang static struct command db_show_all_cmds[] = {
93a9643ea8Slogwang { "trace", db_stack_trace_all, 0, NULL },
94a9643ea8Slogwang };
95a9643ea8Slogwang struct command_table db_show_all_table =
96a9643ea8Slogwang LIST_HEAD_INITIALIZER(db_show_all_table);
97a9643ea8Slogwang
98a9643ea8Slogwang static struct command db_show_cmds[] = {
99*22ce4affSfengbojiang { "active", 0, 0, &db_show_active_table },
100a9643ea8Slogwang { "all", 0, 0, &db_show_all_table },
101a9643ea8Slogwang { "registers", db_show_regs, 0, NULL },
102a9643ea8Slogwang { "breaks", db_listbreak_cmd, 0, NULL },
103a9643ea8Slogwang { "threads", db_show_threads, 0, NULL },
104a9643ea8Slogwang };
105a9643ea8Slogwang struct command_table db_show_table = LIST_HEAD_INITIALIZER(db_show_table);
106a9643ea8Slogwang
107a9643ea8Slogwang static struct command db_cmds[] = {
108a9643ea8Slogwang { "print", db_print_cmd, 0, NULL },
109a9643ea8Slogwang { "p", db_print_cmd, 0, NULL },
110a9643ea8Slogwang { "examine", db_examine_cmd, CS_SET_DOT, NULL },
111a9643ea8Slogwang { "x", db_examine_cmd, CS_SET_DOT, NULL },
112a9643ea8Slogwang { "search", db_search_cmd, CS_OWN|CS_SET_DOT, NULL },
113a9643ea8Slogwang { "set", db_set_cmd, CS_OWN, NULL },
114a9643ea8Slogwang { "write", db_write_cmd, CS_MORE|CS_SET_DOT, NULL },
115a9643ea8Slogwang { "w", db_write_cmd, CS_MORE|CS_SET_DOT, NULL },
116a9643ea8Slogwang { "delete", db_delete_cmd, 0, NULL },
117a9643ea8Slogwang { "d", db_delete_cmd, 0, NULL },
118a9643ea8Slogwang { "dump", db_dump, 0, NULL },
119a9643ea8Slogwang { "break", db_breakpoint_cmd, 0, NULL },
120a9643ea8Slogwang { "b", db_breakpoint_cmd, 0, NULL },
121a9643ea8Slogwang { "dwatch", db_deletewatch_cmd, 0, NULL },
122a9643ea8Slogwang { "watch", db_watchpoint_cmd, CS_MORE,NULL },
123a9643ea8Slogwang { "dhwatch", db_deletehwatch_cmd, 0, NULL },
124a9643ea8Slogwang { "hwatch", db_hwatchpoint_cmd, 0, NULL },
125a9643ea8Slogwang { "step", db_single_step_cmd, 0, NULL },
126a9643ea8Slogwang { "s", db_single_step_cmd, 0, NULL },
127a9643ea8Slogwang { "continue", db_continue_cmd, 0, NULL },
128a9643ea8Slogwang { "c", db_continue_cmd, 0, NULL },
129a9643ea8Slogwang { "until", db_trace_until_call_cmd,0, NULL },
130a9643ea8Slogwang { "next", db_trace_until_matching_cmd,0, NULL },
131a9643ea8Slogwang { "match", db_trace_until_matching_cmd,0, NULL },
132a9643ea8Slogwang { "trace", db_stack_trace, CS_OWN, NULL },
133a9643ea8Slogwang { "t", db_stack_trace, CS_OWN, NULL },
134*22ce4affSfengbojiang /* XXX alias for active trace */
135*22ce4affSfengbojiang { "acttrace", db_stack_trace_active, 0, NULL },
136a9643ea8Slogwang /* XXX alias for all trace */
137a9643ea8Slogwang { "alltrace", db_stack_trace_all, 0, NULL },
138a9643ea8Slogwang { "where", db_stack_trace, CS_OWN, NULL },
139a9643ea8Slogwang { "bt", db_stack_trace, CS_OWN, NULL },
140a9643ea8Slogwang { "call", db_fncall, CS_OWN, NULL },
141a9643ea8Slogwang { "show", 0, 0, &db_show_table },
142a9643ea8Slogwang { "ps", db_ps, 0, NULL },
143a9643ea8Slogwang { "gdb", db_gdb, 0, NULL },
144a9643ea8Slogwang { "halt", db_halt, 0, NULL },
145a9643ea8Slogwang { "reboot", db_reset, 0, NULL },
146a9643ea8Slogwang { "reset", db_reset, 0, NULL },
147a9643ea8Slogwang { "kill", db_kill, CS_OWN, NULL },
148a9643ea8Slogwang { "watchdog", db_watchdog, CS_OWN, NULL },
149*22ce4affSfengbojiang { "thread", db_set_thread, 0, NULL },
150a9643ea8Slogwang { "run", db_run_cmd, CS_OWN, NULL },
151a9643ea8Slogwang { "script", db_script_cmd, CS_OWN, NULL },
152a9643ea8Slogwang { "scripts", db_scripts_cmd, 0, NULL },
153a9643ea8Slogwang { "unscript", db_unscript_cmd, CS_OWN, NULL },
154a9643ea8Slogwang { "capture", db_capture_cmd, CS_OWN, NULL },
155a9643ea8Slogwang { "textdump", db_textdump_cmd, CS_OWN, NULL },
156a9643ea8Slogwang { "findstack", db_findstack_cmd, 0, NULL },
157a9643ea8Slogwang };
158a9643ea8Slogwang struct command_table db_cmd_table = LIST_HEAD_INITIALIZER(db_cmd_table);
159a9643ea8Slogwang
160a9643ea8Slogwang static struct command *db_last_command = NULL;
161a9643ea8Slogwang
162a9643ea8Slogwang /*
163a9643ea8Slogwang * if 'ed' style: 'dot' is set at start of last item printed,
164a9643ea8Slogwang * and '+' points to next line.
165a9643ea8Slogwang * Otherwise: 'dot' points to next item, '..' points to last.
166a9643ea8Slogwang */
167a9643ea8Slogwang static bool db_ed_style = true;
168a9643ea8Slogwang
169a9643ea8Slogwang /*
170a9643ea8Slogwang * Utility routine - discard tokens through end-of-line.
171a9643ea8Slogwang */
172a9643ea8Slogwang void
db_skip_to_eol(void)173a9643ea8Slogwang db_skip_to_eol(void)
174a9643ea8Slogwang {
175a9643ea8Slogwang int t;
176a9643ea8Slogwang do {
177a9643ea8Slogwang t = db_read_token();
178a9643ea8Slogwang } while (t != tEOL);
179a9643ea8Slogwang }
180a9643ea8Slogwang
181a9643ea8Slogwang /*
182a9643ea8Slogwang * Results of command search.
183a9643ea8Slogwang */
184a9643ea8Slogwang #define CMD_UNIQUE 0
185a9643ea8Slogwang #define CMD_FOUND 1
186a9643ea8Slogwang #define CMD_NONE 2
187a9643ea8Slogwang #define CMD_AMBIGUOUS 3
188a9643ea8Slogwang #define CMD_HELP 4
189a9643ea8Slogwang
190a9643ea8Slogwang static void db_cmd_match(char *name, struct command *cmd,
191a9643ea8Slogwang struct command **cmdp, int *resultp);
192a9643ea8Slogwang static void db_cmd_list(struct command_table *table);
193a9643ea8Slogwang static int db_cmd_search(char *name, struct command_table *table,
194a9643ea8Slogwang struct command **cmdp);
195a9643ea8Slogwang static void db_command(struct command **last_cmdp,
196a9643ea8Slogwang struct command_table *cmd_table, int dopager);
197a9643ea8Slogwang
198a9643ea8Slogwang /*
199a9643ea8Slogwang * Initialize the command lists from the static tables.
200a9643ea8Slogwang */
201a9643ea8Slogwang void
db_command_init(void)202a9643ea8Slogwang db_command_init(void)
203a9643ea8Slogwang {
204a9643ea8Slogwang #define N(a) (sizeof(a) / sizeof(a[0]))
205a9643ea8Slogwang int i;
206a9643ea8Slogwang
207a9643ea8Slogwang for (i = 0; i < N(db_cmds); i++)
208a9643ea8Slogwang db_command_register(&db_cmd_table, &db_cmds[i]);
209a9643ea8Slogwang for (i = 0; i < N(db_show_cmds); i++)
210a9643ea8Slogwang db_command_register(&db_show_table, &db_show_cmds[i]);
211*22ce4affSfengbojiang for (i = 0; i < N(db_show_active_cmds); i++)
212*22ce4affSfengbojiang db_command_register(&db_show_active_table,
213*22ce4affSfengbojiang &db_show_active_cmds[i]);
214a9643ea8Slogwang for (i = 0; i < N(db_show_all_cmds); i++)
215a9643ea8Slogwang db_command_register(&db_show_all_table, &db_show_all_cmds[i]);
216a9643ea8Slogwang #undef N
217a9643ea8Slogwang }
218a9643ea8Slogwang
219a9643ea8Slogwang /*
220a9643ea8Slogwang * Register a command.
221a9643ea8Slogwang */
222a9643ea8Slogwang void
db_command_register(struct command_table * list,struct command * cmd)223a9643ea8Slogwang db_command_register(struct command_table *list, struct command *cmd)
224a9643ea8Slogwang {
225a9643ea8Slogwang struct command *c, *last;
226a9643ea8Slogwang
227a9643ea8Slogwang last = NULL;
228a9643ea8Slogwang LIST_FOREACH(c, list, next) {
229a9643ea8Slogwang int n = strcmp(cmd->name, c->name);
230a9643ea8Slogwang
231a9643ea8Slogwang /* Check that the command is not already present. */
232a9643ea8Slogwang if (n == 0) {
233a9643ea8Slogwang printf("%s: Warning, the command \"%s\" already exists;"
234a9643ea8Slogwang " ignoring request\n", __func__, cmd->name);
235a9643ea8Slogwang return;
236a9643ea8Slogwang }
237a9643ea8Slogwang if (n < 0) {
238a9643ea8Slogwang /* NB: keep list sorted lexicographically */
239a9643ea8Slogwang LIST_INSERT_BEFORE(c, cmd, next);
240a9643ea8Slogwang return;
241a9643ea8Slogwang }
242a9643ea8Slogwang last = c;
243a9643ea8Slogwang }
244a9643ea8Slogwang if (last == NULL)
245a9643ea8Slogwang LIST_INSERT_HEAD(list, cmd, next);
246a9643ea8Slogwang else
247a9643ea8Slogwang LIST_INSERT_AFTER(last, cmd, next);
248a9643ea8Slogwang }
249a9643ea8Slogwang
250a9643ea8Slogwang /*
251a9643ea8Slogwang * Remove a command previously registered with db_command_register.
252a9643ea8Slogwang */
253a9643ea8Slogwang void
db_command_unregister(struct command_table * list,struct command * cmd)254a9643ea8Slogwang db_command_unregister(struct command_table *list, struct command *cmd)
255a9643ea8Slogwang {
256a9643ea8Slogwang struct command *c;
257a9643ea8Slogwang
258a9643ea8Slogwang LIST_FOREACH(c, list, next) {
259a9643ea8Slogwang if (cmd == c) {
260a9643ea8Slogwang LIST_REMOVE(cmd, next);
261a9643ea8Slogwang return;
262a9643ea8Slogwang }
263a9643ea8Slogwang }
264a9643ea8Slogwang /* NB: intentionally quiet */
265a9643ea8Slogwang }
266a9643ea8Slogwang
267a9643ea8Slogwang /*
268a9643ea8Slogwang * Helper function to match a single command.
269a9643ea8Slogwang */
270a9643ea8Slogwang static void
db_cmd_match(char * name,struct command * cmd,struct command ** cmdp,int * resultp)271a9643ea8Slogwang db_cmd_match(char *name, struct command *cmd, struct command **cmdp,
272a9643ea8Slogwang int *resultp)
273a9643ea8Slogwang {
274a9643ea8Slogwang char *lp, *rp;
275a9643ea8Slogwang int c;
276a9643ea8Slogwang
277a9643ea8Slogwang lp = name;
278a9643ea8Slogwang rp = cmd->name;
279a9643ea8Slogwang while ((c = *lp) == *rp) {
280a9643ea8Slogwang if (c == 0) {
281a9643ea8Slogwang /* complete match */
282a9643ea8Slogwang *cmdp = cmd;
283a9643ea8Slogwang *resultp = CMD_UNIQUE;
284a9643ea8Slogwang return;
285a9643ea8Slogwang }
286a9643ea8Slogwang lp++;
287a9643ea8Slogwang rp++;
288a9643ea8Slogwang }
289a9643ea8Slogwang if (c == 0) {
290a9643ea8Slogwang /* end of name, not end of command -
291a9643ea8Slogwang partial match */
292a9643ea8Slogwang if (*resultp == CMD_FOUND) {
293a9643ea8Slogwang *resultp = CMD_AMBIGUOUS;
294a9643ea8Slogwang /* but keep looking for a full match -
295a9643ea8Slogwang this lets us match single letters */
296a9643ea8Slogwang } else {
297a9643ea8Slogwang *cmdp = cmd;
298a9643ea8Slogwang *resultp = CMD_FOUND;
299a9643ea8Slogwang }
300a9643ea8Slogwang }
301a9643ea8Slogwang }
302a9643ea8Slogwang
303a9643ea8Slogwang /*
304a9643ea8Slogwang * Search for command prefix.
305a9643ea8Slogwang */
306a9643ea8Slogwang static int
db_cmd_search(char * name,struct command_table * table,struct command ** cmdp)307a9643ea8Slogwang db_cmd_search(char *name, struct command_table *table, struct command **cmdp)
308a9643ea8Slogwang {
309a9643ea8Slogwang struct command *cmd;
310a9643ea8Slogwang int result = CMD_NONE;
311a9643ea8Slogwang
312a9643ea8Slogwang LIST_FOREACH(cmd, table, next) {
313a9643ea8Slogwang db_cmd_match(name,cmd,cmdp,&result);
314a9643ea8Slogwang if (result == CMD_UNIQUE)
315a9643ea8Slogwang break;
316a9643ea8Slogwang }
317a9643ea8Slogwang
318a9643ea8Slogwang if (result == CMD_NONE) {
319a9643ea8Slogwang /* check for 'help' */
320a9643ea8Slogwang if (name[0] == 'h' && name[1] == 'e'
321a9643ea8Slogwang && name[2] == 'l' && name[3] == 'p')
322a9643ea8Slogwang result = CMD_HELP;
323a9643ea8Slogwang }
324a9643ea8Slogwang return (result);
325a9643ea8Slogwang }
326a9643ea8Slogwang
327a9643ea8Slogwang static void
db_cmd_list(struct command_table * table)328a9643ea8Slogwang db_cmd_list(struct command_table *table)
329a9643ea8Slogwang {
330a9643ea8Slogwang struct command *cmd;
331*22ce4affSfengbojiang int have_subcommands;
332a9643ea8Slogwang
333*22ce4affSfengbojiang have_subcommands = 0;
334a9643ea8Slogwang LIST_FOREACH(cmd, table, next) {
335*22ce4affSfengbojiang if (cmd->more != NULL)
336*22ce4affSfengbojiang have_subcommands++;
337a9643ea8Slogwang db_printf("%-16s", cmd->name);
338a9643ea8Slogwang db_end_line(16);
339a9643ea8Slogwang }
340*22ce4affSfengbojiang
341*22ce4affSfengbojiang if (have_subcommands > 0) {
342*22ce4affSfengbojiang db_printf("\nThe following have subcommands; append \"help\" "
343*22ce4affSfengbojiang "to list (e.g. \"show help\"):\n");
344*22ce4affSfengbojiang LIST_FOREACH(cmd, table, next) {
345*22ce4affSfengbojiang if (cmd->more == NULL)
346*22ce4affSfengbojiang continue;
347*22ce4affSfengbojiang db_printf("%-16s", cmd->name);
348*22ce4affSfengbojiang db_end_line(16);
349*22ce4affSfengbojiang }
350*22ce4affSfengbojiang }
351a9643ea8Slogwang }
352a9643ea8Slogwang
353a9643ea8Slogwang static void
db_command(struct command ** last_cmdp,struct command_table * cmd_table,int dopager)354a9643ea8Slogwang db_command(struct command **last_cmdp, struct command_table *cmd_table,
355a9643ea8Slogwang int dopager)
356a9643ea8Slogwang {
357a9643ea8Slogwang struct command *cmd = NULL;
358a9643ea8Slogwang int t;
359a9643ea8Slogwang char modif[TOK_STRING_SIZE];
360a9643ea8Slogwang db_expr_t addr, count;
361a9643ea8Slogwang bool have_addr = false;
362a9643ea8Slogwang int result;
363a9643ea8Slogwang
364a9643ea8Slogwang t = db_read_token();
365a9643ea8Slogwang if (t == tEOL) {
366a9643ea8Slogwang /* empty line repeats last command, at 'next' */
367a9643ea8Slogwang cmd = *last_cmdp;
368a9643ea8Slogwang addr = (db_expr_t)db_next;
369a9643ea8Slogwang have_addr = false;
370a9643ea8Slogwang count = 1;
371a9643ea8Slogwang modif[0] = '\0';
372a9643ea8Slogwang }
373a9643ea8Slogwang else if (t == tEXCL) {
374a9643ea8Slogwang db_fncall((db_expr_t)0, (bool)false, (db_expr_t)0, (char *)0);
375a9643ea8Slogwang return;
376a9643ea8Slogwang }
377a9643ea8Slogwang else if (t != tIDENT) {
378*22ce4affSfengbojiang db_printf("Unrecognized input; use \"help\" "
379*22ce4affSfengbojiang "to list available commands\n");
380a9643ea8Slogwang db_flush_lex();
381a9643ea8Slogwang return;
382a9643ea8Slogwang }
383a9643ea8Slogwang else {
384a9643ea8Slogwang /*
385a9643ea8Slogwang * Search for command
386a9643ea8Slogwang */
387a9643ea8Slogwang while (cmd_table) {
388a9643ea8Slogwang result = db_cmd_search(db_tok_string,
389a9643ea8Slogwang cmd_table,
390a9643ea8Slogwang &cmd);
391a9643ea8Slogwang switch (result) {
392a9643ea8Slogwang case CMD_NONE:
393*22ce4affSfengbojiang db_printf("No such command; use \"help\" "
394*22ce4affSfengbojiang "to list available commands\n");
395a9643ea8Slogwang db_flush_lex();
396a9643ea8Slogwang return;
397a9643ea8Slogwang case CMD_AMBIGUOUS:
398a9643ea8Slogwang db_printf("Ambiguous\n");
399a9643ea8Slogwang db_flush_lex();
400a9643ea8Slogwang return;
401a9643ea8Slogwang case CMD_HELP:
402*22ce4affSfengbojiang if (cmd_table == &db_cmd_table) {
403*22ce4affSfengbojiang db_printf("This is ddb(4), the kernel debugger; "
404*22ce4affSfengbojiang "see https://man.FreeBSD.org/ddb/4 for help.\n");
405*22ce4affSfengbojiang db_printf("Use \"bt\" for backtrace, \"dump\" for "
406*22ce4affSfengbojiang "kernel core dump, \"reset\" to reboot.\n");
407*22ce4affSfengbojiang db_printf("Available commands:\n");
408*22ce4affSfengbojiang }
409a9643ea8Slogwang db_cmd_list(cmd_table);
410a9643ea8Slogwang db_flush_lex();
411a9643ea8Slogwang return;
412a9643ea8Slogwang default:
413a9643ea8Slogwang break;
414a9643ea8Slogwang }
415a9643ea8Slogwang if ((cmd_table = cmd->more) != NULL) {
416a9643ea8Slogwang t = db_read_token();
417a9643ea8Slogwang if (t != tIDENT) {
418*22ce4affSfengbojiang db_printf("Subcommand required; "
419*22ce4affSfengbojiang "available subcommands:\n");
420a9643ea8Slogwang db_cmd_list(cmd_table);
421a9643ea8Slogwang db_flush_lex();
422a9643ea8Slogwang return;
423a9643ea8Slogwang }
424a9643ea8Slogwang }
425a9643ea8Slogwang }
426a9643ea8Slogwang
427a9643ea8Slogwang if ((cmd->flag & CS_OWN) == 0) {
428a9643ea8Slogwang /*
429a9643ea8Slogwang * Standard syntax:
430a9643ea8Slogwang * command [/modifier] [addr] [,count]
431a9643ea8Slogwang */
432a9643ea8Slogwang t = db_read_token();
433a9643ea8Slogwang if (t == tSLASH) {
434a9643ea8Slogwang t = db_read_token();
435a9643ea8Slogwang if (t != tIDENT) {
436a9643ea8Slogwang db_printf("Bad modifier\n");
437a9643ea8Slogwang db_flush_lex();
438a9643ea8Slogwang return;
439a9643ea8Slogwang }
440a9643ea8Slogwang db_strcpy(modif, db_tok_string);
441a9643ea8Slogwang }
442a9643ea8Slogwang else {
443a9643ea8Slogwang db_unread_token(t);
444a9643ea8Slogwang modif[0] = '\0';
445a9643ea8Slogwang }
446a9643ea8Slogwang
447a9643ea8Slogwang if (db_expression(&addr)) {
448a9643ea8Slogwang db_dot = (db_addr_t) addr;
449a9643ea8Slogwang db_last_addr = db_dot;
450a9643ea8Slogwang have_addr = true;
451a9643ea8Slogwang }
452a9643ea8Slogwang else {
453a9643ea8Slogwang addr = (db_expr_t) db_dot;
454a9643ea8Slogwang have_addr = false;
455a9643ea8Slogwang }
456a9643ea8Slogwang t = db_read_token();
457a9643ea8Slogwang if (t == tCOMMA) {
458a9643ea8Slogwang if (!db_expression(&count)) {
459a9643ea8Slogwang db_printf("Count missing\n");
460a9643ea8Slogwang db_flush_lex();
461a9643ea8Slogwang return;
462a9643ea8Slogwang }
463a9643ea8Slogwang }
464a9643ea8Slogwang else {
465a9643ea8Slogwang db_unread_token(t);
466a9643ea8Slogwang count = -1;
467a9643ea8Slogwang }
468a9643ea8Slogwang if ((cmd->flag & CS_MORE) == 0) {
469a9643ea8Slogwang db_skip_to_eol();
470a9643ea8Slogwang }
471a9643ea8Slogwang }
472a9643ea8Slogwang }
473a9643ea8Slogwang *last_cmdp = cmd;
474a9643ea8Slogwang if (cmd != NULL) {
475a9643ea8Slogwang /*
476a9643ea8Slogwang * Execute the command.
477a9643ea8Slogwang */
478a9643ea8Slogwang if (dopager)
479a9643ea8Slogwang db_enable_pager();
480a9643ea8Slogwang else
481a9643ea8Slogwang db_disable_pager();
482a9643ea8Slogwang (*cmd->fcn)(addr, have_addr, count, modif);
483a9643ea8Slogwang if (dopager)
484a9643ea8Slogwang db_disable_pager();
485a9643ea8Slogwang
486a9643ea8Slogwang if (cmd->flag & CS_SET_DOT) {
487a9643ea8Slogwang /*
488a9643ea8Slogwang * If command changes dot, set dot to
489a9643ea8Slogwang * previous address displayed (if 'ed' style).
490a9643ea8Slogwang */
491a9643ea8Slogwang if (db_ed_style) {
492a9643ea8Slogwang db_dot = db_prev;
493a9643ea8Slogwang }
494a9643ea8Slogwang else {
495a9643ea8Slogwang db_dot = db_next;
496a9643ea8Slogwang }
497a9643ea8Slogwang }
498a9643ea8Slogwang else {
499a9643ea8Slogwang /*
500a9643ea8Slogwang * If command does not change dot,
501a9643ea8Slogwang * set 'next' location to be the same.
502a9643ea8Slogwang */
503a9643ea8Slogwang db_next = db_dot;
504a9643ea8Slogwang }
505a9643ea8Slogwang }
506a9643ea8Slogwang }
507a9643ea8Slogwang
508a9643ea8Slogwang /*
509a9643ea8Slogwang * At least one non-optional command must be implemented using
510a9643ea8Slogwang * DB_COMMAND() so that db_cmd_set gets created. Here is one.
511a9643ea8Slogwang */
DB_COMMAND(panic,db_panic)512a9643ea8Slogwang DB_COMMAND(panic, db_panic)
513a9643ea8Slogwang {
514a9643ea8Slogwang db_disable_pager();
515a9643ea8Slogwang panic("from debugger");
516a9643ea8Slogwang }
517a9643ea8Slogwang
518a9643ea8Slogwang void
db_command_loop(void)519a9643ea8Slogwang db_command_loop(void)
520a9643ea8Slogwang {
521a9643ea8Slogwang /*
522a9643ea8Slogwang * Initialize 'prev' and 'next' to dot.
523a9643ea8Slogwang */
524a9643ea8Slogwang db_prev = db_dot;
525a9643ea8Slogwang db_next = db_dot;
526a9643ea8Slogwang
527a9643ea8Slogwang db_cmd_loop_done = 0;
528a9643ea8Slogwang while (!db_cmd_loop_done) {
529a9643ea8Slogwang if (db_print_position() != 0)
530a9643ea8Slogwang db_printf("\n");
531a9643ea8Slogwang
532a9643ea8Slogwang db_printf("db> ");
533a9643ea8Slogwang (void) db_read_line();
534a9643ea8Slogwang
535a9643ea8Slogwang db_command(&db_last_command, &db_cmd_table, /* dopager */ 1);
536a9643ea8Slogwang }
537a9643ea8Slogwang }
538a9643ea8Slogwang
539a9643ea8Slogwang /*
540a9643ea8Slogwang * Execute a command on behalf of a script. The caller is responsible for
541a9643ea8Slogwang * making sure that the command string is < DB_MAXLINE or it will be
542a9643ea8Slogwang * truncated.
543a9643ea8Slogwang *
544a9643ea8Slogwang * XXXRW: Runs by injecting faked input into DDB input stream; it would be
545a9643ea8Slogwang * nicer to use an alternative approach that didn't mess with the previous
546a9643ea8Slogwang * command buffer.
547a9643ea8Slogwang */
548a9643ea8Slogwang void
db_command_script(const char * command)549a9643ea8Slogwang db_command_script(const char *command)
550a9643ea8Slogwang {
551a9643ea8Slogwang db_prev = db_next = db_dot;
552a9643ea8Slogwang db_inject_line(command);
553a9643ea8Slogwang db_command(&db_last_command, &db_cmd_table, /* dopager */ 0);
554a9643ea8Slogwang }
555a9643ea8Slogwang
556a9643ea8Slogwang void
db_error(const char * s)557a9643ea8Slogwang db_error(const char *s)
558a9643ea8Slogwang {
559a9643ea8Slogwang if (s)
560a9643ea8Slogwang db_printf("%s", s);
561a9643ea8Slogwang db_flush_lex();
562*22ce4affSfengbojiang kdb_reenter_silent();
563a9643ea8Slogwang }
564a9643ea8Slogwang
565a9643ea8Slogwang static void
db_dump(db_expr_t dummy,bool dummy2,db_expr_t dummy3,char * dummy4)566a9643ea8Slogwang db_dump(db_expr_t dummy, bool dummy2, db_expr_t dummy3, char *dummy4)
567a9643ea8Slogwang {
568a9643ea8Slogwang int error;
569a9643ea8Slogwang
570a9643ea8Slogwang if (textdump_pending) {
571a9643ea8Slogwang db_printf("textdump_pending set.\n"
572a9643ea8Slogwang "run \"textdump unset\" first or \"textdump dump\" for a textdump.\n");
573a9643ea8Slogwang return;
574a9643ea8Slogwang }
575a9643ea8Slogwang error = doadump(false);
576a9643ea8Slogwang if (error) {
577a9643ea8Slogwang db_printf("Cannot dump: ");
578a9643ea8Slogwang switch (error) {
579a9643ea8Slogwang case EBUSY:
580a9643ea8Slogwang db_printf("debugger got invoked while dumping.\n");
581a9643ea8Slogwang break;
582a9643ea8Slogwang case ENXIO:
583a9643ea8Slogwang db_printf("no dump device specified.\n");
584a9643ea8Slogwang break;
585a9643ea8Slogwang default:
586a9643ea8Slogwang db_printf("unknown error (error=%d).\n", error);
587a9643ea8Slogwang break;
588a9643ea8Slogwang }
589a9643ea8Slogwang }
590a9643ea8Slogwang }
591a9643ea8Slogwang
592a9643ea8Slogwang /*
593a9643ea8Slogwang * Call random function:
594a9643ea8Slogwang * !expr(arg,arg,arg)
595a9643ea8Slogwang */
596a9643ea8Slogwang
597a9643ea8Slogwang /* The generic implementation supports a maximum of 10 arguments. */
598a9643ea8Slogwang typedef db_expr_t __db_f(db_expr_t, db_expr_t, db_expr_t, db_expr_t,
599a9643ea8Slogwang db_expr_t, db_expr_t, db_expr_t, db_expr_t, db_expr_t, db_expr_t);
600a9643ea8Slogwang
601a9643ea8Slogwang static __inline int
db_fncall_generic(db_expr_t addr,db_expr_t * rv,int nargs,db_expr_t args[])602a9643ea8Slogwang db_fncall_generic(db_expr_t addr, db_expr_t *rv, int nargs, db_expr_t args[])
603a9643ea8Slogwang {
604a9643ea8Slogwang __db_f *f = (__db_f *)addr;
605a9643ea8Slogwang
606a9643ea8Slogwang if (nargs > 10) {
607a9643ea8Slogwang db_printf("Too many arguments (max 10)\n");
608a9643ea8Slogwang return (0);
609a9643ea8Slogwang }
610a9643ea8Slogwang *rv = (*f)(args[0], args[1], args[2], args[3], args[4], args[5],
611a9643ea8Slogwang args[6], args[7], args[8], args[9]);
612a9643ea8Slogwang return (1);
613a9643ea8Slogwang }
614a9643ea8Slogwang
615a9643ea8Slogwang static void
db_fncall(db_expr_t dummy1,bool dummy2,db_expr_t dummy3,char * dummy4)616a9643ea8Slogwang db_fncall(db_expr_t dummy1, bool dummy2, db_expr_t dummy3, char *dummy4)
617a9643ea8Slogwang {
618a9643ea8Slogwang db_expr_t fn_addr;
619a9643ea8Slogwang db_expr_t args[DB_MAXARGS];
620a9643ea8Slogwang int nargs = 0;
621a9643ea8Slogwang db_expr_t retval;
622a9643ea8Slogwang int t;
623a9643ea8Slogwang
624a9643ea8Slogwang if (!db_expression(&fn_addr)) {
625a9643ea8Slogwang db_printf("Bad function\n");
626a9643ea8Slogwang db_flush_lex();
627a9643ea8Slogwang return;
628a9643ea8Slogwang }
629a9643ea8Slogwang
630a9643ea8Slogwang t = db_read_token();
631a9643ea8Slogwang if (t == tLPAREN) {
632a9643ea8Slogwang if (db_expression(&args[0])) {
633a9643ea8Slogwang nargs++;
634a9643ea8Slogwang while ((t = db_read_token()) == tCOMMA) {
635a9643ea8Slogwang if (nargs == DB_MAXARGS) {
636a9643ea8Slogwang db_printf("Too many arguments (max %d)\n", DB_MAXARGS);
637a9643ea8Slogwang db_flush_lex();
638a9643ea8Slogwang return;
639a9643ea8Slogwang }
640a9643ea8Slogwang if (!db_expression(&args[nargs])) {
641a9643ea8Slogwang db_printf("Argument missing\n");
642a9643ea8Slogwang db_flush_lex();
643a9643ea8Slogwang return;
644a9643ea8Slogwang }
645a9643ea8Slogwang nargs++;
646a9643ea8Slogwang }
647a9643ea8Slogwang db_unread_token(t);
648a9643ea8Slogwang }
649a9643ea8Slogwang if (db_read_token() != tRPAREN) {
650*22ce4affSfengbojiang db_printf("Mismatched parens\n");
651a9643ea8Slogwang db_flush_lex();
652a9643ea8Slogwang return;
653a9643ea8Slogwang }
654a9643ea8Slogwang }
655a9643ea8Slogwang db_skip_to_eol();
656a9643ea8Slogwang db_disable_pager();
657a9643ea8Slogwang
658a9643ea8Slogwang if (DB_CALL(fn_addr, &retval, nargs, args))
659a9643ea8Slogwang db_printf("= %#lr\n", (long)retval);
660a9643ea8Slogwang }
661a9643ea8Slogwang
662a9643ea8Slogwang static void
db_halt(db_expr_t dummy,bool dummy2,db_expr_t dummy3,char * dummy4)663a9643ea8Slogwang db_halt(db_expr_t dummy, bool dummy2, db_expr_t dummy3, char *dummy4)
664a9643ea8Slogwang {
665a9643ea8Slogwang
666a9643ea8Slogwang cpu_halt();
667a9643ea8Slogwang }
668a9643ea8Slogwang
669a9643ea8Slogwang static void
db_kill(db_expr_t dummy1,bool dummy2,db_expr_t dummy3,char * dummy4)670a9643ea8Slogwang db_kill(db_expr_t dummy1, bool dummy2, db_expr_t dummy3, char *dummy4)
671a9643ea8Slogwang {
672a9643ea8Slogwang db_expr_t old_radix, pid, sig;
673a9643ea8Slogwang struct proc *p;
674a9643ea8Slogwang
675a9643ea8Slogwang #define DB_ERROR(f) do { db_printf f; db_flush_lex(); goto out; } while (0)
676a9643ea8Slogwang
677a9643ea8Slogwang /*
678a9643ea8Slogwang * PIDs and signal numbers are typically represented in base
679a9643ea8Slogwang * 10, so make that the default here. It can, of course, be
680a9643ea8Slogwang * overridden by specifying a prefix.
681a9643ea8Slogwang */
682a9643ea8Slogwang old_radix = db_radix;
683a9643ea8Slogwang db_radix = 10;
684a9643ea8Slogwang /* Retrieve arguments. */
685a9643ea8Slogwang if (!db_expression(&sig))
686a9643ea8Slogwang DB_ERROR(("Missing signal number\n"));
687a9643ea8Slogwang if (!db_expression(&pid))
688a9643ea8Slogwang DB_ERROR(("Missing process ID\n"));
689a9643ea8Slogwang db_skip_to_eol();
690a9643ea8Slogwang if (!_SIG_VALID(sig))
691a9643ea8Slogwang DB_ERROR(("Signal number out of range\n"));
692a9643ea8Slogwang
693a9643ea8Slogwang /*
694a9643ea8Slogwang * Find the process in question. allproc_lock is not needed
695a9643ea8Slogwang * since we're in DDB.
696a9643ea8Slogwang */
697a9643ea8Slogwang /* sx_slock(&allproc_lock); */
698a9643ea8Slogwang FOREACH_PROC_IN_SYSTEM(p)
699a9643ea8Slogwang if (p->p_pid == pid)
700a9643ea8Slogwang break;
701a9643ea8Slogwang /* sx_sunlock(&allproc_lock); */
702a9643ea8Slogwang if (p == NULL)
703a9643ea8Slogwang DB_ERROR(("Can't find process with pid %ld\n", (long) pid));
704a9643ea8Slogwang
705a9643ea8Slogwang /* If it's already locked, bail; otherwise, do the deed. */
706a9643ea8Slogwang if (PROC_TRYLOCK(p) == 0)
707a9643ea8Slogwang DB_ERROR(("Can't lock process with pid %ld\n", (long) pid));
708a9643ea8Slogwang else {
709a9643ea8Slogwang pksignal(p, sig, NULL);
710a9643ea8Slogwang PROC_UNLOCK(p);
711a9643ea8Slogwang }
712a9643ea8Slogwang
713a9643ea8Slogwang out:
714a9643ea8Slogwang db_radix = old_radix;
715a9643ea8Slogwang #undef DB_ERROR
716a9643ea8Slogwang }
717a9643ea8Slogwang
718a9643ea8Slogwang /*
719a9643ea8Slogwang * Reboot. In case there is an additional argument, take it as delay in
720a9643ea8Slogwang * seconds. Default to 15s if we cannot parse it and make sure we will
721a9643ea8Slogwang * never wait longer than 1 week. Some code is similar to
722a9643ea8Slogwang * kern_shutdown.c:shutdown_panic().
723a9643ea8Slogwang */
724a9643ea8Slogwang #ifndef DB_RESET_MAXDELAY
725a9643ea8Slogwang #define DB_RESET_MAXDELAY (3600 * 24 * 7)
726a9643ea8Slogwang #endif
727a9643ea8Slogwang
728a9643ea8Slogwang static void
db_reset(db_expr_t addr,bool have_addr,db_expr_t count __unused,char * modif __unused)729a9643ea8Slogwang db_reset(db_expr_t addr, bool have_addr, db_expr_t count __unused,
730a9643ea8Slogwang char *modif __unused)
731a9643ea8Slogwang {
732a9643ea8Slogwang int delay, loop;
733a9643ea8Slogwang
734a9643ea8Slogwang if (have_addr) {
735a9643ea8Slogwang delay = (int)db_hex2dec(addr);
736a9643ea8Slogwang
737a9643ea8Slogwang /* If we parse to fail, use 15s. */
738a9643ea8Slogwang if (delay == -1)
739a9643ea8Slogwang delay = 15;
740a9643ea8Slogwang
741a9643ea8Slogwang /* Cap at one week. */
742a9643ea8Slogwang if ((uintmax_t)delay > (uintmax_t)DB_RESET_MAXDELAY)
743a9643ea8Slogwang delay = DB_RESET_MAXDELAY;
744a9643ea8Slogwang
745a9643ea8Slogwang db_printf("Automatic reboot in %d seconds - "
746a9643ea8Slogwang "press a key on the console to abort\n", delay);
747a9643ea8Slogwang for (loop = delay * 10; loop > 0; --loop) {
748a9643ea8Slogwang DELAY(1000 * 100); /* 1/10th second */
749a9643ea8Slogwang /* Did user type a key? */
750a9643ea8Slogwang if (cncheckc() != -1)
751a9643ea8Slogwang return;
752a9643ea8Slogwang }
753a9643ea8Slogwang }
754a9643ea8Slogwang
755a9643ea8Slogwang cpu_reset();
756a9643ea8Slogwang }
757a9643ea8Slogwang
758a9643ea8Slogwang static void
db_watchdog(db_expr_t dummy1,bool dummy2,db_expr_t dummy3,char * dummy4)759a9643ea8Slogwang db_watchdog(db_expr_t dummy1, bool dummy2, db_expr_t dummy3, char *dummy4)
760a9643ea8Slogwang {
761a9643ea8Slogwang db_expr_t old_radix, tout;
762a9643ea8Slogwang int err, i;
763a9643ea8Slogwang
764a9643ea8Slogwang old_radix = db_radix;
765a9643ea8Slogwang db_radix = 10;
766a9643ea8Slogwang err = db_expression(&tout);
767a9643ea8Slogwang db_skip_to_eol();
768a9643ea8Slogwang db_radix = old_radix;
769a9643ea8Slogwang
770a9643ea8Slogwang /* If no argument is provided the watchdog will just be disabled. */
771a9643ea8Slogwang if (err == 0) {
772a9643ea8Slogwang db_printf("No argument provided, disabling watchdog\n");
773a9643ea8Slogwang tout = 0;
774a9643ea8Slogwang } else if ((tout & WD_INTERVAL) == WD_TO_NEVER) {
775a9643ea8Slogwang db_error("Out of range watchdog interval\n");
776a9643ea8Slogwang return;
777a9643ea8Slogwang }
778a9643ea8Slogwang EVENTHANDLER_INVOKE(watchdog_list, tout, &i);
779a9643ea8Slogwang }
780a9643ea8Slogwang
781a9643ea8Slogwang static void
db_gdb(db_expr_t dummy1,bool dummy2,db_expr_t dummy3,char * dummy4)782a9643ea8Slogwang db_gdb(db_expr_t dummy1, bool dummy2, db_expr_t dummy3, char *dummy4)
783a9643ea8Slogwang {
784a9643ea8Slogwang
785a9643ea8Slogwang if (kdb_dbbe_select("gdb") != 0) {
786a9643ea8Slogwang db_printf("The remote GDB backend could not be selected.\n");
787a9643ea8Slogwang return;
788a9643ea8Slogwang }
789a9643ea8Slogwang /*
790a9643ea8Slogwang * Mark that we are done in the debugger. kdb_trap()
791a9643ea8Slogwang * should re-enter with the new backend.
792a9643ea8Slogwang */
793a9643ea8Slogwang db_cmd_loop_done = 1;
794a9643ea8Slogwang db_printf("(ctrl-c will return control to ddb)\n");
795a9643ea8Slogwang }
796a9643ea8Slogwang
797a9643ea8Slogwang static void
db_stack_trace(db_expr_t tid,bool hastid,db_expr_t count,char * modif)798a9643ea8Slogwang db_stack_trace(db_expr_t tid, bool hastid, db_expr_t count, char *modif)
799a9643ea8Slogwang {
800a9643ea8Slogwang struct thread *td;
801a9643ea8Slogwang db_expr_t radix;
802a9643ea8Slogwang pid_t pid;
803a9643ea8Slogwang int t;
804a9643ea8Slogwang
805a9643ea8Slogwang /*
806a9643ea8Slogwang * We parse our own arguments. We don't like the default radix.
807a9643ea8Slogwang */
808a9643ea8Slogwang radix = db_radix;
809a9643ea8Slogwang db_radix = 10;
810a9643ea8Slogwang hastid = db_expression(&tid);
811a9643ea8Slogwang t = db_read_token();
812a9643ea8Slogwang if (t == tCOMMA) {
813a9643ea8Slogwang if (!db_expression(&count)) {
814a9643ea8Slogwang db_printf("Count missing\n");
815a9643ea8Slogwang db_flush_lex();
816*22ce4affSfengbojiang db_radix = radix;
817a9643ea8Slogwang return;
818a9643ea8Slogwang }
819a9643ea8Slogwang } else {
820a9643ea8Slogwang db_unread_token(t);
821a9643ea8Slogwang count = -1;
822a9643ea8Slogwang }
823a9643ea8Slogwang db_skip_to_eol();
824a9643ea8Slogwang db_radix = radix;
825a9643ea8Slogwang
826a9643ea8Slogwang if (hastid) {
827a9643ea8Slogwang td = kdb_thr_lookup((lwpid_t)tid);
828a9643ea8Slogwang if (td == NULL)
829a9643ea8Slogwang td = kdb_thr_from_pid((pid_t)tid);
830a9643ea8Slogwang if (td == NULL) {
831a9643ea8Slogwang db_printf("Thread %d not found\n", (int)tid);
832a9643ea8Slogwang return;
833a9643ea8Slogwang }
834a9643ea8Slogwang } else
835a9643ea8Slogwang td = kdb_thread;
836a9643ea8Slogwang if (td->td_proc != NULL)
837a9643ea8Slogwang pid = td->td_proc->p_pid;
838a9643ea8Slogwang else
839a9643ea8Slogwang pid = -1;
840a9643ea8Slogwang db_printf("Tracing pid %d tid %ld td %p\n", pid, (long)td->td_tid, td);
841*22ce4affSfengbojiang if (td->td_proc != NULL && (td->td_proc->p_flag & P_INMEM) == 0)
842*22ce4affSfengbojiang db_printf("--- swapped out\n");
843*22ce4affSfengbojiang else
844a9643ea8Slogwang db_trace_thread(td, count);
845a9643ea8Slogwang }
846a9643ea8Slogwang
847a9643ea8Slogwang static void
_db_stack_trace_all(bool active_only)848*22ce4affSfengbojiang _db_stack_trace_all(bool active_only)
849*22ce4affSfengbojiang {
850*22ce4affSfengbojiang struct thread *td;
851*22ce4affSfengbojiang jmp_buf jb;
852*22ce4affSfengbojiang void *prev_jb;
853*22ce4affSfengbojiang
854*22ce4affSfengbojiang for (td = kdb_thr_first(); td != NULL; td = kdb_thr_next(td)) {
855*22ce4affSfengbojiang prev_jb = kdb_jmpbuf(jb);
856*22ce4affSfengbojiang if (setjmp(jb) == 0) {
857*22ce4affSfengbojiang if (td->td_state == TDS_RUNNING)
858*22ce4affSfengbojiang db_printf("\nTracing command %s pid %d"
859*22ce4affSfengbojiang " tid %ld td %p (CPU %d)\n",
860*22ce4affSfengbojiang td->td_proc->p_comm, td->td_proc->p_pid,
861*22ce4affSfengbojiang (long)td->td_tid, td, td->td_oncpu);
862*22ce4affSfengbojiang else if (active_only)
863*22ce4affSfengbojiang continue;
864*22ce4affSfengbojiang else
865*22ce4affSfengbojiang db_printf("\nTracing command %s pid %d"
866*22ce4affSfengbojiang " tid %ld td %p\n", td->td_proc->p_comm,
867*22ce4affSfengbojiang td->td_proc->p_pid, (long)td->td_tid, td);
868*22ce4affSfengbojiang if (td->td_proc->p_flag & P_INMEM)
869*22ce4affSfengbojiang db_trace_thread(td, -1);
870*22ce4affSfengbojiang else
871*22ce4affSfengbojiang db_printf("--- swapped out\n");
872*22ce4affSfengbojiang if (db_pager_quit) {
873*22ce4affSfengbojiang kdb_jmpbuf(prev_jb);
874*22ce4affSfengbojiang return;
875*22ce4affSfengbojiang }
876*22ce4affSfengbojiang }
877*22ce4affSfengbojiang kdb_jmpbuf(prev_jb);
878*22ce4affSfengbojiang }
879*22ce4affSfengbojiang }
880*22ce4affSfengbojiang
881*22ce4affSfengbojiang static void
db_stack_trace_active(db_expr_t dummy,bool dummy2,db_expr_t dummy3,char * dummy4)882*22ce4affSfengbojiang db_stack_trace_active(db_expr_t dummy, bool dummy2, db_expr_t dummy3,
883*22ce4affSfengbojiang char *dummy4)
884*22ce4affSfengbojiang {
885*22ce4affSfengbojiang
886*22ce4affSfengbojiang _db_stack_trace_all(true);
887*22ce4affSfengbojiang }
888*22ce4affSfengbojiang
889*22ce4affSfengbojiang static void
db_stack_trace_all(db_expr_t dummy,bool dummy2,db_expr_t dummy3,char * dummy4)890a9643ea8Slogwang db_stack_trace_all(db_expr_t dummy, bool dummy2, db_expr_t dummy3,
891a9643ea8Slogwang char *dummy4)
892a9643ea8Slogwang {
893a9643ea8Slogwang
894*22ce4affSfengbojiang _db_stack_trace_all(false);
895a9643ea8Slogwang }
896a9643ea8Slogwang
897a9643ea8Slogwang /*
898a9643ea8Slogwang * Take the parsed expression value from the command line that was parsed
899a9643ea8Slogwang * as a hexadecimal value and convert it as if the expression was parsed
900a9643ea8Slogwang * as a decimal value. Returns -1 if the expression was not a valid
901a9643ea8Slogwang * decimal value.
902a9643ea8Slogwang */
903a9643ea8Slogwang db_expr_t
db_hex2dec(db_expr_t expr)904a9643ea8Slogwang db_hex2dec(db_expr_t expr)
905a9643ea8Slogwang {
906a9643ea8Slogwang uintptr_t x, y;
907a9643ea8Slogwang db_expr_t val;
908a9643ea8Slogwang
909a9643ea8Slogwang y = 1;
910a9643ea8Slogwang val = 0;
911a9643ea8Slogwang x = expr;
912a9643ea8Slogwang while (x != 0) {
913a9643ea8Slogwang if (x % 16 > 9)
914a9643ea8Slogwang return (-1);
915a9643ea8Slogwang val += (x % 16) * (y);
916a9643ea8Slogwang x >>= 4;
917a9643ea8Slogwang y *= 10;
918a9643ea8Slogwang }
919a9643ea8Slogwang return (val);
920a9643ea8Slogwang }
921