db_command.c revision 1.125 1 1.125 cegger /* $NetBSD: db_command.c,v 1.125 2008/12/07 00:51:15 cegger Exp $ */
2 1.64 simonb /*
3 1.1 cgd * Mach Operating System
4 1.1 cgd * Copyright (c) 1991,1990 Carnegie Mellon University
5 1.1 cgd * All Rights Reserved.
6 1.64 simonb *
7 1.1 cgd * Permission to use, copy, modify and distribute this software and its
8 1.1 cgd * documentation is hereby granted, provided that both the copyright
9 1.1 cgd * notice and this permission notice appear in all copies of the
10 1.1 cgd * software, derivative works or modified versions, and any portions
11 1.1 cgd * thereof, and that both notices appear in supporting documentation.
12 1.64 simonb *
13 1.30 pk * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
14 1.1 cgd * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
15 1.1 cgd * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
16 1.64 simonb *
17 1.1 cgd * Carnegie Mellon requests users of this software to return to
18 1.64 simonb *
19 1.1 cgd * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
20 1.1 cgd * School of Computer Science
21 1.1 cgd * Carnegie Mellon University
22 1.1 cgd * Pittsburgh PA 15213-3890
23 1.64 simonb *
24 1.1 cgd * any improvements or extensions that they make and grant Carnegie the
25 1.1 cgd * rights to redistribute these changes.
26 1.1 cgd */
27 1.98 martin /*
28 1.98 martin * Copyright (c) 1996, 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
29 1.98 martin * All rights reserved.
30 1.98 martin *
31 1.98 martin * This code is derived from software contributed to The NetBSD Foundation
32 1.98 martin * by Adam Hamsik.
33 1.98 martin *
34 1.98 martin * Redistribution and use in source and binary forms, with or without
35 1.98 martin * modification, are permitted provided that the following conditions
36 1.98 martin * are met:
37 1.98 martin * 1. Redistributions of source code must retain the above copyright
38 1.98 martin * notice, this list of conditions and the following disclaimer.
39 1.98 martin * 2. Redistributions in binary form must reproduce the above copyright
40 1.98 martin * notice, this list of conditions and the following disclaimer in the
41 1.98 martin * documentation and/or other materials provided with the distribution.
42 1.98 martin *
43 1.98 martin * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
44 1.98 martin * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
45 1.98 martin * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
46 1.98 martin * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
47 1.98 martin * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
48 1.98 martin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
49 1.98 martin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
50 1.98 martin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
51 1.98 martin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
52 1.98 martin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
53 1.98 martin * POSSIBILITY OF SUCH DAMAGE.
54 1.98 martin */
55 1.25 mrg
56 1.63 lukem /*
57 1.63 lukem * Command dispatcher.
58 1.63 lukem */
59 1.63 lukem
60 1.63 lukem #include <sys/cdefs.h>
61 1.125 cegger __KERNEL_RCSID(0, "$NetBSD: db_command.c,v 1.125 2008/12/07 00:51:15 cegger Exp $");
62 1.63 lukem
63 1.121 ad #include "opt_aio.h"
64 1.27 tron #include "opt_ddb.h"
65 1.69 briggs #include "opt_kgdb.h"
66 1.40 jhawk #include "opt_inet.h"
67 1.118 skrll #include "opt_uvmhist.h"
68 1.80 yamt #include "opt_ddbparam.h"
69 1.5 mycroft
70 1.7 mycroft #include <sys/param.h>
71 1.18 christos #include <sys/systm.h>
72 1.23 scottr #include <sys/reboot.h>
73 1.65 simonb #include <sys/device.h>
74 1.112 yamt #include <sys/lwp.h>
75 1.65 simonb #include <sys/malloc.h>
76 1.83 yamt #include <sys/mbuf.h>
77 1.65 simonb #include <sys/namei.h>
78 1.65 simonb #include <sys/pool.h>
79 1.7 mycroft #include <sys/proc.h>
80 1.36 chs #include <sys/vnode.h>
81 1.112 yamt #include <sys/vmem.h>
82 1.92 ad #include <sys/lockdebug.h>
83 1.92 ad #include <sys/sleepq.h>
84 1.109 ad #include <sys/cpu.h>
85 1.122 pooka #include <sys/buf.h>
86 1.123 ad #include <sys/module.h>
87 1.15 gwr
88 1.98 martin /*include queue macros*/
89 1.98 martin #include <sys/queue.h>
90 1.98 martin
91 1.1 cgd #include <machine/db_machdep.h> /* type definitions */
92 1.1 cgd
93 1.58 mrg #if defined(_KERNEL_OPT)
94 1.34 sommerfe #include "opt_multiprocessor.h"
95 1.34 sommerfe #endif
96 1.34 sommerfe
97 1.1 cgd #include <ddb/db_lex.h>
98 1.1 cgd #include <ddb/db_output.h>
99 1.10 pk #include <ddb/db_command.h>
100 1.16 christos #include <ddb/db_break.h>
101 1.16 christos #include <ddb/db_watch.h>
102 1.16 christos #include <ddb/db_run.h>
103 1.16 christos #include <ddb/db_variables.h>
104 1.16 christos #include <ddb/db_interface.h>
105 1.16 christos #include <ddb/db_sym.h>
106 1.16 christos #include <ddb/db_extern.h>
107 1.1 cgd
108 1.24 mrg #include <uvm/uvm_extern.h>
109 1.26 jonathan #include <uvm/uvm_ddb.h>
110 1.24 mrg
111 1.46 jhawk #include "arp.h"
112 1.46 jhawk
113 1.1 cgd /*
114 1.64 simonb * Results of command search.
115 1.64 simonb */
116 1.64 simonb #define CMD_UNIQUE 0
117 1.64 simonb #define CMD_FOUND 1
118 1.64 simonb #define CMD_NONE 2
119 1.64 simonb #define CMD_AMBIGUOUS 3
120 1.98 martin
121 1.64 simonb /*
122 1.1 cgd * Exported global variables
123 1.1 cgd */
124 1.93 thorpej bool db_cmd_loop_done;
125 1.17 gwr label_t *db_recover;
126 1.64 simonb db_addr_t db_dot;
127 1.64 simonb db_addr_t db_last_addr;
128 1.64 simonb db_addr_t db_prev;
129 1.64 simonb db_addr_t db_next;
130 1.1 cgd
131 1.98 martin
132 1.98 martin /*
133 1.98 martin New DDB api for adding and removing commands uses three lists, because
134 1.98 martin we use two types of commands
135 1.98 martin a) standard commands without subcommands -> reboot
136 1.98 martin b) show commands which are subcommands of show command -> show aio_jobs
137 1.98 martin c) if defined machine specific commands
138 1.116 blymn
139 1.98 martin ddb_add_cmd, ddb_rem_cmd use type (DDB_SHOW_CMD||DDB_BASE_CMD)argument to
140 1.98 martin add them to representativ lists.
141 1.98 martin */
142 1.98 martin
143 1.103 martin static const struct db_command db_command_table[];
144 1.103 martin static const struct db_command db_show_cmds[];
145 1.103 martin #ifdef DB_MACHINE_COMMANDS
146 1.103 martin static const struct db_command db_machine_command_table[];
147 1.103 martin #endif
148 1.103 martin
149 1.105 martin /* the global queue of all command tables */
150 1.105 martin TAILQ_HEAD(db_cmd_tbl_en_head, db_cmd_tbl_en);
151 1.105 martin
152 1.105 martin /* TAILQ entry used to register command tables */
153 1.105 martin struct db_cmd_tbl_en {
154 1.105 martin const struct db_command *db_cmd; /* cmd table */
155 1.105 martin TAILQ_ENTRY(db_cmd_tbl_en) db_cmd_next;
156 1.105 martin };
157 1.105 martin
158 1.103 martin /* head of base commands list */
159 1.98 martin static struct db_cmd_tbl_en_head db_base_cmd_list =
160 1.98 martin TAILQ_HEAD_INITIALIZER(db_base_cmd_list);
161 1.103 martin static struct db_cmd_tbl_en db_base_cmd_builtins =
162 1.103 martin { .db_cmd = db_command_table };
163 1.98 martin
164 1.103 martin /* head of show commands list */
165 1.98 martin static struct db_cmd_tbl_en_head db_show_cmd_list =
166 1.98 martin TAILQ_HEAD_INITIALIZER(db_show_cmd_list);
167 1.103 martin static struct db_cmd_tbl_en db_show_cmd_builtins =
168 1.103 martin { .db_cmd = db_show_cmds };
169 1.98 martin
170 1.103 martin /* head of machine commands list */
171 1.98 martin static struct db_cmd_tbl_en_head db_mach_cmd_list =
172 1.98 martin TAILQ_HEAD_INITIALIZER(db_mach_cmd_list);
173 1.103 martin #ifdef DB_MACHINE_COMMANDS
174 1.103 martin static struct db_cmd_tbl_en db_mach_cmd_builtins =
175 1.103 martin { .db_cmd = db_machine_command_table };
176 1.98 martin #endif
177 1.98 martin
178 1.1 cgd /*
179 1.1 cgd * if 'ed' style: 'dot' is set at start of last item printed,
180 1.1 cgd * and '+' points to next line.
181 1.1 cgd * Otherwise: 'dot' points to next item, '..' points to last.
182 1.1 cgd */
183 1.95 thorpej static bool db_ed_style = true;
184 1.64 simonb
185 1.104 martin static void db_init_commands(void);
186 1.103 martin static int db_register_tbl_entry(uint8_t type,
187 1.103 martin struct db_cmd_tbl_en *list_ent);
188 1.98 martin static void db_cmd_list(const struct db_cmd_tbl_en_head *);
189 1.98 martin static int db_cmd_search(const char *, const struct db_command *,
190 1.98 martin const struct db_command **);
191 1.98 martin static void db_command(const struct db_command **);
192 1.94 matt static void db_buf_print_cmd(db_expr_t, bool, db_expr_t, const char *);
193 1.94 matt static void db_event_print_cmd(db_expr_t, bool, db_expr_t, const char *);
194 1.94 matt static void db_fncall(db_expr_t, bool, db_expr_t, const char *);
195 1.98 martin static int db_get_list_type(const char *);
196 1.98 martin static void db_help_print_cmd(db_expr_t, bool, db_expr_t, const char *);
197 1.98 martin static void db_lock_print_cmd(db_expr_t, bool, db_expr_t, const char *);
198 1.98 martin static void db_mount_print_cmd(db_expr_t, bool, db_expr_t, const char *);
199 1.98 martin static void db_mbuf_print_cmd(db_expr_t, bool, db_expr_t, const char *);
200 1.94 matt static void db_malloc_print_cmd(db_expr_t, bool, db_expr_t, const char *);
201 1.94 matt static void db_map_print_cmd(db_expr_t, bool, db_expr_t, const char *);
202 1.98 martin static void db_namecache_print_cmd(db_expr_t, bool, db_expr_t,
203 1.98 martin const char *);
204 1.94 matt static void db_object_print_cmd(db_expr_t, bool, db_expr_t, const char *);
205 1.94 matt static void db_page_print_cmd(db_expr_t, bool, db_expr_t, const char *);
206 1.94 matt static void db_show_all_pages(db_expr_t, bool, db_expr_t, const char *);
207 1.94 matt static void db_pool_print_cmd(db_expr_t, bool, db_expr_t, const char *);
208 1.94 matt static void db_reboot_cmd(db_expr_t, bool, db_expr_t, const char *);
209 1.94 matt static void db_sifting_cmd(db_expr_t, bool, db_expr_t, const char *);
210 1.94 matt static void db_stack_trace_cmd(db_expr_t, bool, db_expr_t, const char *);
211 1.94 matt static void db_sync_cmd(db_expr_t, bool, db_expr_t, const char *);
212 1.112 yamt static void db_whatis_cmd(db_expr_t, bool, db_expr_t, const char *);
213 1.94 matt static void db_uvmexp_print_cmd(db_expr_t, bool, db_expr_t, const char *);
214 1.118 skrll #ifdef UVMHIST
215 1.118 skrll static void db_uvmhist_print_cmd(db_expr_t, bool, db_expr_t, const char *);
216 1.118 skrll #endif
217 1.94 matt static void db_vnode_print_cmd(db_expr_t, bool, db_expr_t, const char *);
218 1.125 cegger static void db_vmem_print_cmd(db_expr_t, bool, db_expr_t, const char *);
219 1.125 cegger static void db_show_all_vmems(db_expr_t, bool, db_expr_t, const char *);
220 1.64 simonb
221 1.64 simonb static const struct db_command db_show_cmds[] = {
222 1.98 martin /*added from all sub cmds*/
223 1.98 martin { DDB_ADD_CMD("callout", db_show_callout,
224 1.98 martin 0 ,"List all used callout functions.",NULL,NULL) },
225 1.98 martin { DDB_ADD_CMD("pages", db_show_all_pages,
226 1.98 martin 0 ,"List all used memory pages.",NULL,NULL) },
227 1.98 martin { DDB_ADD_CMD("procs", db_show_all_procs,
228 1.98 martin 0 ,"List all processes.",NULL,NULL) },
229 1.98 martin { DDB_ADD_CMD("pools", db_show_all_pools,
230 1.98 martin 0 ,"Show all poolS",NULL,NULL) },
231 1.121 ad #ifdef AIO
232 1.98 martin /*added from all sub cmds*/
233 1.98 martin { DDB_ADD_CMD("aio_jobs", db_show_aio_jobs, 0,
234 1.98 martin "Show aio jobs",NULL,NULL) },
235 1.121 ad #endif
236 1.98 martin { DDB_ADD_CMD("all", NULL,
237 1.98 martin CS_COMPAT, NULL,NULL,NULL) },
238 1.64 simonb #if defined(INET) && (NARP > 0)
239 1.98 martin { DDB_ADD_CMD("arptab", db_show_arptab, 0,NULL,NULL,NULL) },
240 1.64 simonb #endif
241 1.98 martin { DDB_ADD_CMD("breaks", db_listbreak_cmd, 0,
242 1.98 martin "Display all breaks.",NULL,NULL) },
243 1.98 martin { DDB_ADD_CMD("buf", db_buf_print_cmd, 0,
244 1.98 martin "Print the struct buf at address.", "[/f] address",NULL) },
245 1.98 martin { DDB_ADD_CMD("event", db_event_print_cmd, 0,
246 1.98 martin "Print all the non-zero evcnt(9) event counters.", "[/f]",NULL) },
247 1.117 blymn { DDB_ADD_CMD("files", db_show_files_cmd, 0,
248 1.117 blymn "Print the files open by process at address",
249 1.117 blymn "[/f] address", NULL) },
250 1.98 martin { DDB_ADD_CMD("lock", db_lock_print_cmd, 0,NULL,NULL,NULL) },
251 1.98 martin { DDB_ADD_CMD("malloc", db_malloc_print_cmd,0,NULL,NULL,NULL) },
252 1.98 martin { DDB_ADD_CMD("map", db_map_print_cmd, 0,
253 1.98 martin "Print the vm_map at address.", "[/f] address",NULL) },
254 1.123 ad { DDB_ADD_CMD("module", db_show_module_cmd, 0,
255 1.123 ad "Print kernel modules", NULL, NULL) },
256 1.98 martin { DDB_ADD_CMD("mount", db_mount_print_cmd, 0,
257 1.98 martin "Print the mount structure at address.", "[/f] address",NULL) },
258 1.119 rmind { DDB_ADD_CMD("mqueue", db_show_mqueue_cmd, 0,
259 1.119 rmind "Print the message queues", NULL, NULL) },
260 1.98 martin { DDB_ADD_CMD("mbuf", db_mbuf_print_cmd, 0,NULL,NULL,
261 1.98 martin "-c prints all mbuf chains") },
262 1.98 martin { DDB_ADD_CMD("ncache", db_namecache_print_cmd, 0,
263 1.98 martin "Dump the namecache list.", "address",NULL) },
264 1.98 martin { DDB_ADD_CMD("object", db_object_print_cmd, 0,
265 1.98 martin "Print the vm_object at address.", "[/f] address",NULL) },
266 1.98 martin { DDB_ADD_CMD("page", db_page_print_cmd, 0,
267 1.98 martin "Print the vm_page at address.", "[/f] address",NULL) },
268 1.98 martin { DDB_ADD_CMD("pool", db_pool_print_cmd, 0,
269 1.98 martin "Print the pool at address.", "[/clp] address",NULL) },
270 1.98 martin { DDB_ADD_CMD("registers", db_show_regs, 0,
271 1.98 martin "Display the register set.", "[/u]",NULL) },
272 1.98 martin { DDB_ADD_CMD("sched_qs", db_show_sched_qs, 0,
273 1.98 martin "Print the state of the scheduler's run queues.",
274 1.98 martin NULL,NULL) },
275 1.98 martin { DDB_ADD_CMD("uvmexp", db_uvmexp_print_cmd, 0,
276 1.98 martin "Print a selection of UVM counters and statistics.",
277 1.98 martin NULL,NULL) },
278 1.118 skrll #ifdef UVMHIST
279 1.118 skrll { DDB_ADD_CMD("uvmhist", db_uvmhist_print_cmd, 0,
280 1.118 skrll "Print the UVM history logs.",
281 1.118 skrll NULL,NULL) },
282 1.118 skrll #endif
283 1.98 martin { DDB_ADD_CMD("vnode", db_vnode_print_cmd, 0,
284 1.98 martin "Print the vnode at address.", "[/f] address",NULL) },
285 1.125 cegger { DDB_ADD_CMD("vmem", db_vmem_print_cmd, 0,
286 1.125 cegger "Print the vmem usage.", "[/a] address", NULL) },
287 1.125 cegger { DDB_ADD_CMD("vmems", db_show_all_vmems, 0,
288 1.125 cegger "Show all vmems.", NULL, NULL) },
289 1.98 martin { DDB_ADD_CMD("watches", db_listwatch_cmd, 0,
290 1.98 martin "Display all watchpoints.", NULL,NULL) },
291 1.98 martin { DDB_ADD_CMD(NULL, NULL, 0,NULL,NULL,NULL) }
292 1.64 simonb };
293 1.64 simonb
294 1.77 yamt /* arch/<arch>/<arch>/db_interface.c */
295 1.77 yamt #ifdef DB_MACHINE_COMMANDS
296 1.77 yamt extern const struct db_command db_machine_command_table[];
297 1.77 yamt #endif
298 1.77 yamt
299 1.64 simonb static const struct db_command db_command_table[] = {
300 1.98 martin { DDB_ADD_CMD("b", db_breakpoint_cmd, 0,
301 1.98 martin "Set a breakpoint at address", "[/u] address[,count].",NULL) },
302 1.98 martin { DDB_ADD_CMD("break", db_breakpoint_cmd, 0,
303 1.98 martin "Set a breakpoint at address", "[/u] address[,count].",NULL) },
304 1.98 martin { DDB_ADD_CMD("bt", db_stack_trace_cmd, 0,
305 1.98 martin "Show backtrace.", "See help trace.",NULL) },
306 1.98 martin { DDB_ADD_CMD("c", db_continue_cmd, 0,
307 1.98 martin "Continue execution.", "[/c]",NULL) },
308 1.98 martin { DDB_ADD_CMD("call", db_fncall, CS_OWN,
309 1.98 martin "Call the function", "address[(expression[,...])]",NULL) },
310 1.98 martin { DDB_ADD_CMD("callout", db_show_callout, 0, NULL,
311 1.98 martin NULL,NULL ) },
312 1.98 martin { DDB_ADD_CMD("continue", db_continue_cmd, 0,
313 1.98 martin "Continue execution.", "[/c]",NULL) },
314 1.98 martin { DDB_ADD_CMD("d", db_delete_cmd, 0,
315 1.98 martin "Delete a breakpoint.", "address | #number",NULL) },
316 1.98 martin { DDB_ADD_CMD("delete", db_delete_cmd, 0,
317 1.98 martin "Delete a breakpoint.", "address | #number",NULL) },
318 1.98 martin { DDB_ADD_CMD("dmesg", db_dmesg, 0,
319 1.98 martin "Show kernel message buffer.", "[count]",NULL) },
320 1.98 martin { DDB_ADD_CMD("dwatch", db_deletewatch_cmd, 0,
321 1.98 martin "Delete the watchpoint.", "address",NULL) },
322 1.98 martin { DDB_ADD_CMD("examine", db_examine_cmd, CS_SET_DOT,
323 1.98 martin "Display the address locations.",
324 1.98 martin "[/modifier] address[,count]",NULL) },
325 1.98 martin { DDB_ADD_CMD("help", db_help_print_cmd, CS_OWN|CS_NOREPEAT,
326 1.98 martin "Display help about commands",
327 1.98 martin "Use other commands as arguments.",NULL) },
328 1.98 martin { DDB_ADD_CMD("kill", db_kill_proc, CS_OWN,
329 1.98 martin "Send a signal to the process","pid[,signal_number]",
330 1.98 martin " pid:\t\t\tthe process id (may need 0t prefix for decimal)\n"
331 1.98 martin " signal_number:\tthe signal to send") },
332 1.69 briggs #ifdef KGDB
333 1.99 martin { DDB_ADD_CMD("kgdb", db_kgdb_cmd, 0, NULL,NULL,NULL) },
334 1.69 briggs #endif
335 1.98 martin { DDB_ADD_CMD("machine",NULL,CS_MACH,
336 1.98 martin "Architecture specific functions.",NULL,NULL) },
337 1.98 martin { DDB_ADD_CMD("match", db_trace_until_matching_cmd,0,
338 1.98 martin "Stop at the matching return instruction.","See help next",NULL) },
339 1.98 martin { DDB_ADD_CMD("next", db_trace_until_matching_cmd,0,
340 1.98 martin "Stop at the matching return instruction.","[/p]",NULL) },
341 1.98 martin { DDB_ADD_CMD("p", db_print_cmd, 0,
342 1.98 martin "Print address according to the format.",
343 1.98 martin "[/axzodurc] address [address ...]",NULL) },
344 1.98 martin { DDB_ADD_CMD("print", db_print_cmd, 0,
345 1.98 martin "Print address according to the format.",
346 1.98 martin "[/axzodurc] address [address ...]",NULL) },
347 1.98 martin { DDB_ADD_CMD("ps", db_show_all_procs, 0,
348 1.98 martin "Print all processes.","See show all procs",NULL) },
349 1.98 martin { DDB_ADD_CMD("reboot", db_reboot_cmd, CS_OWN,
350 1.98 martin "Reboot","0x1 RB_ASKNAME, 0x2 RB_SINGLE, 0x4 RB_NOSYNC, 0x8 RB_HALT,"
351 1.98 martin "0x40 RB_KDB, 0x100 RB_DUMP, 0x808 RB_POWERDOWN",NULL) },
352 1.98 martin { DDB_ADD_CMD("s", db_single_step_cmd, 0,
353 1.98 martin "Single-step count times.","[/p] [,count]",NULL) },
354 1.98 martin { DDB_ADD_CMD("search", db_search_cmd, CS_OWN|CS_SET_DOT,
355 1.98 martin "Search memory from address for value.",
356 1.98 martin "[/bhl] address value [mask] [,count]",NULL) },
357 1.98 martin { DDB_ADD_CMD("set", db_set_cmd, CS_OWN,
358 1.98 martin "Set the named variable","$variable [=] expression",NULL) },
359 1.107 martin { DDB_ADD_CMD("show", NULL, CS_SHOW,
360 1.98 martin "Show kernel stats.", NULL,NULL) },
361 1.98 martin { DDB_ADD_CMD("sifting", db_sifting_cmd, CS_OWN,
362 1.98 martin "Search the symbol tables ","[/F] string",NULL) },
363 1.98 martin { DDB_ADD_CMD("step", db_single_step_cmd, 0,
364 1.98 martin "Single-step count times.","[/p] [,count]",NULL) },
365 1.98 martin { DDB_ADD_CMD("sync", db_sync_cmd, CS_OWN,
366 1.98 martin "Force a crash dump, and then reboot.",NULL,NULL) },
367 1.98 martin { DDB_ADD_CMD("trace", db_stack_trace_cmd, 0,
368 1.98 martin "Stack trace from frame-address.",
369 1.98 martin "[/u[l]] [frame-address][,count]",NULL) },
370 1.98 martin { DDB_ADD_CMD("until", db_trace_until_call_cmd,0,
371 1.98 martin "Stop at the next call or return instruction.","[/p]",NULL) },
372 1.98 martin { DDB_ADD_CMD("w", db_write_cmd, CS_MORE|CS_SET_DOT,
373 1.114 uwe "Write the expressions at succeeding locations.",
374 1.114 uwe "[/bhl] address expression [expression ...]",NULL) },
375 1.98 martin { DDB_ADD_CMD("watch", db_watchpoint_cmd, CS_MORE,
376 1.98 martin "Set a watchpoint for a region. ","address[,size]",NULL) },
377 1.112 yamt { DDB_ADD_CMD("whatis", db_whatis_cmd, 0,
378 1.112 yamt "Describe what an address is", "address", NULL) },
379 1.98 martin { DDB_ADD_CMD("write", db_write_cmd, CS_MORE|CS_SET_DOT,
380 1.98 martin "Write the expressions at succeeding locations.",
381 1.98 martin "[/bhl] address expression [expression ...]",NULL) },
382 1.98 martin { DDB_ADD_CMD("x", db_examine_cmd, CS_SET_DOT,
383 1.98 martin "Display the address locations.",
384 1.98 martin "[/modifier] address[,count]",NULL) },
385 1.98 martin { DDB_ADD_CMD(NULL, NULL, 0, NULL, NULL, NULL) }
386 1.64 simonb };
387 1.64 simonb
388 1.64 simonb static const struct db_command *db_last_command = NULL;
389 1.80 yamt #if defined(DDB_COMMANDONENTER)
390 1.81 yamt char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = ___STRING(DDB_COMMANDONENTER);
391 1.81 yamt #else /* defined(DDB_COMMANDONENTER) */
392 1.81 yamt char db_cmd_on_enter[DB_LINE_MAXLEN + 1] = "";
393 1.80 yamt #endif /* defined(DDB_COMMANDONENTER) */
394 1.80 yamt #define DB_LINE_SEP ';'
395 1.1 cgd
396 1.1 cgd /*
397 1.1 cgd * Utility routine - discard tokens through end-of-line.
398 1.1 cgd */
399 1.1 cgd void
400 1.64 simonb db_skip_to_eol(void)
401 1.1 cgd {
402 1.64 simonb int t;
403 1.64 simonb
404 1.1 cgd do {
405 1.64 simonb t = db_read_token();
406 1.1 cgd } while (t != tEOL);
407 1.1 cgd }
408 1.1 cgd
409 1.64 simonb void
410 1.89 uwe db_error(const char *s)
411 1.64 simonb {
412 1.64 simonb
413 1.64 simonb if (s)
414 1.64 simonb db_printf("%s", s);
415 1.64 simonb db_flush_lex();
416 1.64 simonb longjmp(db_recover);
417 1.64 simonb }
418 1.64 simonb
419 1.98 martin /*Execute commandlist after ddb start
420 1.98 martin *This function goes through the command list created from commands and ';'
421 1.98 martin */
422 1.98 martin
423 1.81 yamt static void
424 1.81 yamt db_execute_commandlist(const char *cmdlist)
425 1.81 yamt {
426 1.81 yamt const char *cmd = cmdlist;
427 1.81 yamt const struct db_command *dummy = NULL;
428 1.81 yamt
429 1.81 yamt while (*cmd != '\0') {
430 1.81 yamt const char *ep = cmd;
431 1.81 yamt
432 1.81 yamt while (*ep != '\0' && *ep != DB_LINE_SEP) {
433 1.81 yamt ep++;
434 1.81 yamt }
435 1.81 yamt db_set_line(cmd, ep);
436 1.98 martin db_command(&dummy);
437 1.81 yamt cmd = ep;
438 1.81 yamt if (*cmd == DB_LINE_SEP) {
439 1.81 yamt cmd++;
440 1.81 yamt }
441 1.81 yamt }
442 1.81 yamt }
443 1.81 yamt
444 1.98 martin /*Initialize ddb command tables*/
445 1.102 martin void
446 1.98 martin db_init_commands(void)
447 1.98 martin {
448 1.101 martin static bool done = false;
449 1.98 martin
450 1.101 martin if (done) return;
451 1.101 martin done = true;
452 1.98 martin
453 1.103 martin /* register command tables */
454 1.103 martin (void)db_register_tbl_entry(DDB_BASE_CMD, &db_base_cmd_builtins);
455 1.98 martin #ifdef DB_MACHINE_COMMANDS
456 1.103 martin (void)db_register_tbl_entry(DDB_MACH_CMD, &db_mach_cmd_builtins);
457 1.98 martin #endif
458 1.103 martin (void)db_register_tbl_entry(DDB_SHOW_CMD, &db_show_cmd_builtins);
459 1.98 martin }
460 1.98 martin
461 1.98 martin
462 1.98 martin /*
463 1.98 martin * Add command table to the specified list
464 1.98 martin * Arg:
465 1.98 martin * int type specifies type of command table DDB_SHOW_CMD|DDB_BASE_CMD|DDB_MAC_CMD
466 1.98 martin * *cmd_tbl poiter to static allocated db_command table
467 1.98 martin *
468 1.98 martin *Command table must be NULL terminated array of struct db_command
469 1.98 martin */
470 1.98 martin int
471 1.98 martin db_register_tbl(uint8_t type, const struct db_command *cmd_tbl)
472 1.98 martin {
473 1.98 martin struct db_cmd_tbl_en *list_ent;
474 1.103 martin
475 1.103 martin if (cmd_tbl->name == 0)
476 1.103 martin /* empty list - ignore */
477 1.103 martin return 0;
478 1.103 martin
479 1.105 martin /* force builtin commands to be registered first */
480 1.105 martin db_init_commands();
481 1.105 martin
482 1.105 martin /* now create a list entry for this table */
483 1.103 martin list_ent = malloc(sizeof(struct db_cmd_tbl_en), M_TEMP, M_ZERO);
484 1.103 martin if (list_ent == NULL)
485 1.103 martin return ENOMEM;
486 1.105 martin list_ent->db_cmd=cmd_tbl;
487 1.103 martin
488 1.105 martin /* and register it */
489 1.103 martin return db_register_tbl_entry(type, list_ent);
490 1.103 martin }
491 1.103 martin
492 1.103 martin static int
493 1.103 martin db_register_tbl_entry(uint8_t type, struct db_cmd_tbl_en *list_ent)
494 1.103 martin {
495 1.98 martin struct db_cmd_tbl_en_head *list;
496 1.98 martin
497 1.103 martin switch(type) {
498 1.103 martin case DDB_BASE_CMD:
499 1.103 martin list = &db_base_cmd_list;
500 1.103 martin break;
501 1.103 martin case DDB_SHOW_CMD:
502 1.103 martin list = &db_show_cmd_list;
503 1.103 martin break;
504 1.103 martin case DDB_MACH_CMD:
505 1.103 martin list = &db_mach_cmd_list;
506 1.103 martin break;
507 1.103 martin default:
508 1.103 martin return ENOENT;
509 1.98 martin }
510 1.103 martin
511 1.105 martin TAILQ_INSERT_TAIL(list, list_ent, db_cmd_next);
512 1.103 martin
513 1.98 martin return 0;
514 1.98 martin }
515 1.103 martin
516 1.98 martin /*
517 1.103 martin * Remove command table specified with db_cmd address == cmd_tbl
518 1.98 martin */
519 1.98 martin int
520 1.98 martin db_unregister_tbl(uint8_t type,const struct db_command *cmd_tbl)
521 1.98 martin {
522 1.98 martin struct db_cmd_tbl_en *list_ent;
523 1.98 martin struct db_cmd_tbl_en_head *list;
524 1.98 martin
525 1.103 martin /* find list on which the entry should live */
526 1.103 martin switch (type) {
527 1.98 martin case DDB_BASE_CMD:
528 1.98 martin list=&db_base_cmd_list;
529 1.98 martin break;
530 1.98 martin case DDB_SHOW_CMD:
531 1.98 martin list=&db_show_cmd_list;
532 1.98 martin break;
533 1.98 martin case DDB_MACH_CMD:
534 1.98 martin list=&db_mach_cmd_list;
535 1.98 martin break;
536 1.98 martin default:
537 1.103 martin return EINVAL;
538 1.98 martin }
539 1.103 martin
540 1.103 martin TAILQ_FOREACH (list_ent,list,db_cmd_next) {
541 1.98 martin if (list_ent->db_cmd == cmd_tbl){
542 1.98 martin TAILQ_REMOVE(list,
543 1.98 martin list_ent,db_cmd_next);
544 1.98 martin free(list_ent,M_TEMP);
545 1.105 martin return 0;
546 1.98 martin }
547 1.103 martin }
548 1.105 martin return ENOENT;
549 1.116 blymn }
550 1.103 martin
551 1.98 martin /*This function is called from machine trap code.*/
552 1.64 simonb void
553 1.64 simonb db_command_loop(void)
554 1.64 simonb {
555 1.116 blymn
556 1.64 simonb label_t db_jmpbuf;
557 1.64 simonb label_t *savejmp;
558 1.64 simonb
559 1.64 simonb /*
560 1.64 simonb * Initialize 'prev' and 'next' to dot.
561 1.64 simonb */
562 1.64 simonb db_prev = db_dot;
563 1.64 simonb db_next = db_dot;
564 1.64 simonb
565 1.102 martin db_cmd_loop_done = false;
566 1.64 simonb
567 1.101 martin /*Init default command tables add machine, base,
568 1.101 martin show command tables to the list*/
569 1.102 martin db_init_commands();
570 1.101 martin
571 1.98 martin /*save context for return from ddb*/
572 1.64 simonb savejmp = db_recover;
573 1.64 simonb db_recover = &db_jmpbuf;
574 1.64 simonb (void) setjmp(&db_jmpbuf);
575 1.64 simonb
576 1.98 martin /*Execute default ddb start commands*/
577 1.81 yamt db_execute_commandlist(db_cmd_on_enter);
578 1.80 yamt
579 1.106 martin (void) setjmp(&db_jmpbuf);
580 1.64 simonb while (!db_cmd_loop_done) {
581 1.64 simonb if (db_print_position() != 0)
582 1.64 simonb db_printf("\n");
583 1.64 simonb db_output_line = 0;
584 1.64 simonb
585 1.64 simonb
586 1.64 simonb #ifdef MULTIPROCESSOR
587 1.64 simonb db_printf("db{%ld}> ", (long)cpu_number());
588 1.64 simonb #else
589 1.64 simonb db_printf("db> ");
590 1.64 simonb #endif
591 1.64 simonb (void) db_read_line();
592 1.64 simonb
593 1.98 martin db_command(&db_last_command);
594 1.64 simonb }
595 1.64 simonb
596 1.64 simonb db_recover = savejmp;
597 1.64 simonb }
598 1.1 cgd
599 1.1 cgd /*
600 1.98 martin * Search for command table for command prefix
601 1.108 uwe * ret: CMD_UNIQUE -> completely matches command
602 1.108 uwe * CMD_FOUND -> matches prefix of single command
603 1.108 uwe * CMD_AMBIGIOUS -> matches prefix of more than one command
604 1.108 uwe * CMD_NONE -> command not found
605 1.1 cgd */
606 1.64 simonb static int
607 1.98 martin db_cmd_search(const char *name,const struct db_command *table,
608 1.64 simonb const struct db_command **cmdp)
609 1.1 cgd {
610 1.116 blymn
611 1.53 jdolecek const struct db_command *cmd;
612 1.108 uwe int result;
613 1.1 cgd
614 1.108 uwe result = CMD_NONE;
615 1.110 martin *cmdp = NULL;
616 1.1 cgd for (cmd = table; cmd->name != 0; cmd++) {
617 1.64 simonb const char *lp;
618 1.64 simonb const char *rp;
619 1.64 simonb
620 1.64 simonb lp = name;
621 1.64 simonb rp = cmd->name;
622 1.108 uwe while (*lp != '\0' && *lp == *rp) {
623 1.107 martin rp++;
624 1.64 simonb lp++;
625 1.64 simonb }
626 1.108 uwe
627 1.108 uwe if (*lp != '\0') /* mismatch or extra chars in name */
628 1.108 uwe continue;
629 1.108 uwe
630 1.108 uwe if (*rp == '\0') { /* complete match */
631 1.107 martin *cmdp = cmd;
632 1.107 martin return (CMD_UNIQUE);
633 1.107 martin }
634 1.108 uwe
635 1.108 uwe /* prefix match: end of name, not end of command */
636 1.108 uwe if (result == CMD_NONE) {
637 1.108 uwe result = CMD_FOUND;
638 1.108 uwe *cmdp = cmd;
639 1.108 uwe }
640 1.108 uwe else if (result == CMD_FOUND) {
641 1.108 uwe result = CMD_AMBIGUOUS;
642 1.108 uwe *cmdp = NULL;
643 1.1 cgd }
644 1.1 cgd }
645 1.108 uwe
646 1.1 cgd return (result);
647 1.1 cgd }
648 1.1 cgd
649 1.98 martin /*
650 1.98 martin *List commands to the console.
651 1.98 martin */
652 1.64 simonb static void
653 1.98 martin db_cmd_list(const struct db_cmd_tbl_en_head *list)
654 1.1 cgd {
655 1.98 martin
656 1.98 martin struct db_cmd_tbl_en *list_ent;
657 1.98 martin const struct db_command *table;
658 1.105 martin size_t i, j, w, columns, lines, numcmds, width=0;
659 1.53 jdolecek const char *p;
660 1.1 cgd
661 1.105 martin TAILQ_FOREACH(list_ent,list,db_cmd_next) {
662 1.105 martin table = list_ent->db_cmd;
663 1.105 martin for (i = 0; table[i].name != NULL; i++) {
664 1.98 martin w = strlen(table[i].name);
665 1.98 martin if (w > width)
666 1.98 martin width = w;
667 1.98 martin }
668 1.32 lukem }
669 1.98 martin
670 1.32 lukem width = DB_NEXT_TAB(width);
671 1.32 lukem
672 1.32 lukem columns = db_max_width / width;
673 1.32 lukem if (columns == 0)
674 1.32 lukem columns = 1;
675 1.98 martin
676 1.105 martin TAILQ_FOREACH(list_ent,list,db_cmd_next) {
677 1.105 martin table = list_ent->db_cmd;
678 1.98 martin
679 1.105 martin for (numcmds = 0; table[numcmds].name != NULL; numcmds++)
680 1.105 martin ;
681 1.105 martin lines = (numcmds + columns - 1) / columns;
682 1.116 blymn
683 1.98 martin for (i = 0; i < lines; i++) {
684 1.98 martin for (j = 0; j < columns; j++) {
685 1.98 martin p = table[j * lines + i].name;
686 1.98 martin if (p)
687 1.98 martin db_printf("%s", p);
688 1.105 martin if (j * lines + i + lines >= numcmds) {
689 1.98 martin db_putchar('\n');
690 1.98 martin break;
691 1.98 martin }
692 1.98 martin if (p) {
693 1.98 martin w = strlen(p);
694 1.98 martin while (w < width) {
695 1.98 martin w = DB_NEXT_TAB(w);
696 1.98 martin db_putchar('\t');
697 1.98 martin }
698 1.98 martin }
699 1.98 martin }
700 1.98 martin }
701 1.98 martin }
702 1.98 martin return;
703 1.98 martin }
704 1.98 martin
705 1.98 martin /*
706 1.98 martin *Returns type of list for command with name *name.
707 1.98 martin */
708 1.98 martin static int
709 1.98 martin db_get_list_type(const char *name)
710 1.98 martin {
711 1.98 martin
712 1.98 martin const struct db_command *cmd;
713 1.98 martin struct db_cmd_tbl_en *list_ent;
714 1.98 martin int error,ret=-1;
715 1.98 martin
716 1.105 martin /* search for the command name */
717 1.105 martin TAILQ_FOREACH(list_ent,&db_base_cmd_list,db_cmd_next) {
718 1.105 martin /*
719 1.105 martin * cmd_search returns CMD_UNIQUE, CMD_FOUND ...
720 1.105 martin * CMD_UNIQUE when name was completly matched to cmd->name
721 1.105 martin * CMD_FOUND when name was only partially matched to cmd->name
722 1.105 martin * CMD_NONE command not found in a list
723 1.105 martin * CMD_AMBIGIOUS ->more partialy matches
724 1.98 martin */
725 1.98 martin
726 1.105 martin error = db_cmd_search(name, list_ent->db_cmd, &cmd);
727 1.105 martin
728 1.105 martin if (error == CMD_UNIQUE) {
729 1.105 martin /* exact match found */
730 1.105 martin if (cmd->flag == CS_SHOW) {
731 1.105 martin ret = DDB_SHOW_CMD;
732 1.32 lukem break;
733 1.32 lukem }
734 1.105 martin if (cmd->flag == CS_MACH) {
735 1.105 martin ret = DDB_MACH_CMD;
736 1.98 martin break;
737 1.98 martin } else {
738 1.105 martin ret = DDB_BASE_CMD;
739 1.98 martin break;
740 1.32 lukem }
741 1.105 martin
742 1.111 martin } else if (error == CMD_FOUND) {
743 1.105 martin /*
744 1.105 martin * partial match, search will continue, but
745 1.105 martin * note current result in case we won't
746 1.105 martin * find anything better.
747 1.105 martin */
748 1.98 martin if (cmd->flag == CS_SHOW)
749 1.105 martin ret = DDB_SHOW_CMD;
750 1.111 martin else if (cmd->flag == CS_MACH)
751 1.105 martin ret = DDB_MACH_CMD;
752 1.98 martin else
753 1.105 martin ret = DDB_BASE_CMD;
754 1.32 lukem }
755 1.1 cgd }
756 1.102 martin
757 1.105 martin return ret;
758 1.1 cgd }
759 1.1 cgd
760 1.98 martin /*
761 1.98 martin *Parse command line and execute apropriate function.
762 1.98 martin */
763 1.64 simonb static void
764 1.98 martin db_command(const struct db_command **last_cmdp)
765 1.1 cgd {
766 1.98 martin const struct db_command *command;
767 1.98 martin struct db_cmd_tbl_en *list_ent;
768 1.98 martin struct db_cmd_tbl_en_head *list;
769 1.116 blymn
770 1.1 cgd int t;
771 1.98 martin int result;
772 1.116 blymn
773 1.1 cgd char modif[TOK_STRING_SIZE];
774 1.1 cgd db_expr_t addr, count;
775 1.95 thorpej bool have_addr = false;
776 1.98 martin
777 1.87 he static db_expr_t last_count = 0;
778 1.116 blymn
779 1.98 martin command = NULL; /* XXX gcc */
780 1.86 mrg
781 1.1 cgd t = db_read_token();
782 1.38 jhawk if ((t == tEOL) || (t == tCOMMA)) {
783 1.1 cgd /*
784 1.64 simonb * An empty line repeats last command, at 'next'.
785 1.64 simonb * Only a count repeats the last command with the new count.
786 1.64 simonb */
787 1.98 martin command = *last_cmdp;
788 1.98 martin
789 1.98 martin if (!command)
790 1.98 martin return;
791 1.98 martin
792 1.64 simonb addr = (db_expr_t)db_next;
793 1.64 simonb if (t == tCOMMA) {
794 1.64 simonb if (!db_expression(&count)) {
795 1.64 simonb db_printf("Count missing\n");
796 1.64 simonb db_flush_lex();
797 1.64 simonb return;
798 1.64 simonb }
799 1.64 simonb } else
800 1.64 simonb count = last_count;
801 1.95 thorpej have_addr = false;
802 1.64 simonb modif[0] = '\0';
803 1.64 simonb db_skip_to_eol();
804 1.98 martin
805 1.64 simonb } else if (t == tEXCL) {
806 1.64 simonb db_fncall(0, 0, 0, NULL);
807 1.64 simonb return;
808 1.98 martin
809 1.64 simonb } else if (t != tIDENT) {
810 1.64 simonb db_printf("?\n");
811 1.64 simonb db_flush_lex();
812 1.64 simonb return;
813 1.98 martin
814 1.64 simonb } else {
815 1.98 martin
816 1.98 martin switch(db_get_list_type(db_tok_string)) {
817 1.98 martin
818 1.98 martin case DDB_BASE_CMD:
819 1.107 martin list = &db_base_cmd_list;
820 1.98 martin break;
821 1.107 martin
822 1.98 martin case DDB_SHOW_CMD:
823 1.107 martin list = &db_show_cmd_list;
824 1.98 martin /* need to read show subcommand if show command list
825 1.98 martin is used. */
826 1.107 martin t = db_read_token();
827 1.98 martin
828 1.98 martin if (t != tIDENT) {
829 1.98 martin /* if only show command is executed, print
830 1.98 martin all subcommands */
831 1.116 blymn db_cmd_list(list);
832 1.64 simonb db_flush_lex();
833 1.64 simonb return;
834 1.98 martin }
835 1.98 martin break;
836 1.98 martin case DDB_MACH_CMD:
837 1.107 martin list = &db_mach_cmd_list;
838 1.98 martin /* need to read machine subcommand if
839 1.98 martin machine level 2 command list is used. */
840 1.98 martin t = db_read_token();
841 1.98 martin
842 1.98 martin if (t != tIDENT) {
843 1.98 martin /* if only show command is executed, print
844 1.98 martin all subcommands */
845 1.98 martin db_cmd_list(list);
846 1.64 simonb db_flush_lex();
847 1.64 simonb return;
848 1.116 blymn }
849 1.98 martin break;
850 1.98 martin default:
851 1.98 martin db_printf("No such command\n");
852 1.116 blymn db_flush_lex();
853 1.98 martin return;
854 1.98 martin }
855 1.98 martin
856 1.98 martin COMPAT_RET:
857 1.107 martin TAILQ_FOREACH(list_ent, list, db_cmd_next) {
858 1.98 martin result = db_cmd_search(db_tok_string, list_ent->db_cmd,
859 1.98 martin &command);
860 1.98 martin
861 1.98 martin /* after CMD_UNIQUE in cmd_list only a single command
862 1.98 martin name is possible */
863 1.98 martin if (result == CMD_UNIQUE)
864 1.64 simonb break;
865 1.98 martin
866 1.98 martin }
867 1.101 martin
868 1.118 skrll /* check compatibility flag */
869 1.101 martin if (command && command->flag & CS_COMPAT){
870 1.98 martin t = db_read_token();
871 1.98 martin if (t != tIDENT) {
872 1.98 martin db_cmd_list(list);
873 1.64 simonb db_flush_lex();
874 1.64 simonb return;
875 1.64 simonb }
876 1.1 cgd
877 1.98 martin /* support only level 2 commands here */
878 1.98 martin goto COMPAT_RET;
879 1.101 martin }
880 1.101 martin
881 1.101 martin if (!command) {
882 1.101 martin db_printf("No such command\n");
883 1.101 martin db_flush_lex();
884 1.101 martin return;
885 1.101 martin }
886 1.98 martin
887 1.98 martin if ((command->flag & CS_OWN) == 0) {
888 1.98 martin
889 1.64 simonb /*
890 1.64 simonb * Standard syntax:
891 1.64 simonb * command [/modifier] [addr] [,count]
892 1.64 simonb */
893 1.98 martin t = db_read_token(); /* get modifier */
894 1.116 blymn if (t == tSLASH) {
895 1.64 simonb t = db_read_token();
896 1.64 simonb if (t != tIDENT) {
897 1.64 simonb db_printf("Bad modifier\n");
898 1.64 simonb db_flush_lex();
899 1.64 simonb return;
900 1.64 simonb }
901 1.98 martin /* save modifier */
902 1.71 itojun strlcpy(modif, db_tok_string, sizeof(modif));
903 1.116 blymn
904 1.64 simonb } else {
905 1.64 simonb db_unread_token(t);
906 1.64 simonb modif[0] = '\0';
907 1.64 simonb }
908 1.64 simonb
909 1.98 martin if (db_expression(&addr)) { /*get address*/
910 1.64 simonb db_dot = (db_addr_t) addr;
911 1.64 simonb db_last_addr = db_dot;
912 1.95 thorpej have_addr = true;
913 1.64 simonb } else {
914 1.64 simonb addr = (db_expr_t) db_dot;
915 1.95 thorpej have_addr = false;
916 1.64 simonb }
917 1.98 martin
918 1.64 simonb t = db_read_token();
919 1.98 martin if (t == tCOMMA) { /*Get count*/
920 1.64 simonb if (!db_expression(&count)) {
921 1.64 simonb db_printf("Count missing\n");
922 1.64 simonb db_flush_lex();
923 1.64 simonb return;
924 1.64 simonb }
925 1.116 blymn } else {
926 1.64 simonb db_unread_token(t);
927 1.64 simonb count = -1;
928 1.64 simonb }
929 1.98 martin if ((command->flag & CS_MORE) == 0) {
930 1.64 simonb db_skip_to_eol();
931 1.64 simonb }
932 1.1 cgd }
933 1.1 cgd }
934 1.98 martin
935 1.98 martin if (command->flag & CS_NOREPEAT) {
936 1.98 martin *last_cmdp = NULL;
937 1.98 martin last_count = 0;
938 1.98 martin } else {
939 1.98 martin *last_cmdp = command;
940 1.98 martin last_count = count;
941 1.98 martin }
942 1.98 martin
943 1.98 martin if (command != NULL) {
944 1.1 cgd /*
945 1.64 simonb * Execute the command.
946 1.1 cgd */
947 1.107 martin if (command->fcn != NULL)
948 1.107 martin (*command->fcn)(addr, have_addr, count, modif);
949 1.64 simonb
950 1.98 martin if (command->flag & CS_SET_DOT) {
951 1.64 simonb /*
952 1.64 simonb * If command changes dot, set dot to
953 1.64 simonb * previous address displayed (if 'ed' style).
954 1.64 simonb */
955 1.64 simonb if (db_ed_style)
956 1.64 simonb db_dot = db_prev;
957 1.64 simonb else
958 1.64 simonb db_dot = db_next;
959 1.64 simonb } else {
960 1.64 simonb /*
961 1.64 simonb * If command does not change dot,
962 1.64 simonb * set 'next' location to be the same.
963 1.64 simonb */
964 1.64 simonb db_next = db_dot;
965 1.1 cgd }
966 1.1 cgd }
967 1.1 cgd }
968 1.1 cgd
969 1.98 martin /*
970 1.98 martin * Print help for commands
971 1.98 martin */
972 1.98 martin static void
973 1.98 martin db_help_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
974 1.98 martin const char *modif)
975 1.98 martin {
976 1.116 blymn
977 1.98 martin const struct db_cmd_tbl_en_head *list;
978 1.98 martin const struct db_cmd_tbl_en *list_ent;
979 1.110 martin const struct db_command *help = NULL;
980 1.98 martin int t, result;
981 1.116 blymn
982 1.98 martin t = db_read_token();
983 1.98 martin /* is there another command after the "help"? */
984 1.98 martin if (t == tIDENT){
985 1.98 martin
986 1.110 martin switch(db_get_list_type(db_tok_string)) {
987 1.98 martin
988 1.98 martin case DDB_BASE_CMD:
989 1.98 martin list=&db_base_cmd_list;
990 1.98 martin break;
991 1.98 martin case DDB_SHOW_CMD:
992 1.98 martin list=&db_show_cmd_list;
993 1.98 martin /* read the show subcommand */
994 1.116 blymn t = db_read_token();
995 1.98 martin
996 1.98 martin if (t != tIDENT) {
997 1.98 martin /* no subcommand, print the list */
998 1.98 martin db_cmd_list(list);
999 1.98 martin db_flush_lex();
1000 1.98 martin return;
1001 1.116 blymn }
1002 1.116 blymn
1003 1.98 martin break;
1004 1.98 martin case DDB_MACH_CMD:
1005 1.98 martin list=&db_mach_cmd_list;
1006 1.98 martin /* read machine subcommand */
1007 1.116 blymn t = db_read_token();
1008 1.98 martin
1009 1.98 martin if (t != tIDENT) {
1010 1.98 martin /* no subcommand - just print the list */
1011 1.98 martin db_cmd_list(list);
1012 1.98 martin db_flush_lex();
1013 1.98 martin return;
1014 1.98 martin }
1015 1.98 martin break;
1016 1.103 martin
1017 1.98 martin default:
1018 1.98 martin db_printf("No such command\n");
1019 1.98 martin db_flush_lex();
1020 1.98 martin return;
1021 1.98 martin }
1022 1.116 blymn COMPAT_RET:
1023 1.98 martin TAILQ_FOREACH(list_ent,list,db_cmd_next){
1024 1.98 martin result = db_cmd_search(db_tok_string, list_ent->db_cmd,
1025 1.98 martin &help);
1026 1.98 martin /* after CMD_UNIQUE only a single command
1027 1.98 martin name is possible */
1028 1.98 martin if (result == CMD_UNIQUE)
1029 1.98 martin break;
1030 1.98 martin }
1031 1.98 martin #ifdef DDB_VERBOSE_HELP
1032 1.98 martin /*print help*/
1033 1.98 martin
1034 1.98 martin db_printf("Command: %s\n",help->name);
1035 1.98 martin
1036 1.98 martin if (help->cmd_descr != NULL)
1037 1.98 martin db_printf(" Description: %s\n",help->cmd_descr);
1038 1.116 blymn
1039 1.98 martin if (help->cmd_arg != NULL)
1040 1.98 martin db_printf(" Arguments: %s\n",help->cmd_arg);
1041 1.98 martin
1042 1.98 martin if (help->cmd_arg_help != NULL)
1043 1.98 martin db_printf(" Arguments description:\n%s\n",
1044 1.98 martin help->cmd_arg_help);
1045 1.98 martin
1046 1.98 martin if ((help->cmd_arg == NULL) && (help->cmd_descr == NULL))
1047 1.98 martin db_printf("%s Doesn't have any help message included.\n",
1048 1.98 martin help->name);
1049 1.98 martin #endif
1050 1.98 martin /* check compatibility flag */
1051 1.98 martin /*
1052 1.98 martin * The "show all" command table has been merged with the
1053 1.98 martin * "show" command table - but we want to keep the old UI
1054 1.98 martin * available. So if we find a CS_COMPAT entry, we read
1055 1.98 martin * the next token and try again.
1056 1.98 martin */
1057 1.98 martin if (help->flag == CS_COMPAT){
1058 1.98 martin t = db_read_token();
1059 1.98 martin
1060 1.98 martin if (t != tIDENT){
1061 1.98 martin db_cmd_list(list);
1062 1.98 martin db_flush_lex();
1063 1.98 martin return;
1064 1.98 martin }
1065 1.98 martin
1066 1.98 martin goto COMPAT_RET;
1067 1.98 martin /* support only level 2 commands here */
1068 1.98 martin } else {
1069 1.98 martin db_skip_to_eol();
1070 1.98 martin }
1071 1.116 blymn
1072 1.98 martin } else /* t != tIDENT */
1073 1.98 martin /* print base commands */
1074 1.98 martin db_cmd_list(&db_base_cmd_list);
1075 1.116 blymn
1076 1.98 martin return;
1077 1.98 martin }
1078 1.110 martin
1079 1.4 brezak /*ARGSUSED*/
1080 1.64 simonb static void
1081 1.94 matt db_map_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
1082 1.90 christos const char *modif)
1083 1.64 simonb {
1084 1.95 thorpej bool full = false;
1085 1.64 simonb
1086 1.64 simonb if (modif[0] == 'f')
1087 1.95 thorpej full = true;
1088 1.60 matt
1089 1.95 thorpej if (have_addr == false)
1090 1.120 rmind addr = (db_expr_t)(uintptr_t) kernel_map;
1091 1.4 brezak
1092 1.120 rmind uvm_map_printit((struct vm_map *)(uintptr_t) addr, full, db_printf);
1093 1.4 brezak }
1094 1.4 brezak
1095 1.4 brezak /*ARGSUSED*/
1096 1.64 simonb static void
1097 1.94 matt db_malloc_print_cmd(db_expr_t addr, bool have_addr,
1098 1.91 christos db_expr_t count, const char *modif)
1099 1.62 thorpej {
1100 1.64 simonb
1101 1.62 thorpej #ifdef MALLOC_DEBUG
1102 1.62 thorpej if (!have_addr)
1103 1.62 thorpej addr = 0;
1104 1.62 thorpej
1105 1.62 thorpej debug_malloc_printit(db_printf, (vaddr_t) addr);
1106 1.62 thorpej #else
1107 1.62 thorpej db_printf("The kernel is not built with the MALLOC_DEBUG option.\n");
1108 1.62 thorpej #endif /* MALLOC_DEBUG */
1109 1.62 thorpej }
1110 1.62 thorpej
1111 1.62 thorpej /*ARGSUSED*/
1112 1.64 simonb static void
1113 1.94 matt db_object_print_cmd(db_expr_t addr, bool have_addr,
1114 1.91 christos db_expr_t count, const char *modif)
1115 1.64 simonb {
1116 1.95 thorpej bool full = false;
1117 1.64 simonb
1118 1.64 simonb if (modif[0] == 'f')
1119 1.95 thorpej full = true;
1120 1.4 brezak
1121 1.120 rmind uvm_object_printit((struct uvm_object *)(uintptr_t) addr, full,
1122 1.66 scw db_printf);
1123 1.24 mrg }
1124 1.24 mrg
1125 1.24 mrg /*ARGSUSED*/
1126 1.64 simonb static void
1127 1.94 matt db_page_print_cmd(db_expr_t addr, bool have_addr,
1128 1.91 christos db_expr_t count, const char *modif)
1129 1.64 simonb {
1130 1.95 thorpej bool full = false;
1131 1.64 simonb
1132 1.64 simonb if (modif[0] == 'f')
1133 1.95 thorpej full = true;
1134 1.24 mrg
1135 1.120 rmind uvm_page_printit((struct vm_page *)(uintptr_t) addr, full, db_printf);
1136 1.36 chs }
1137 1.36 chs
1138 1.36 chs /*ARGSUSED*/
1139 1.64 simonb static void
1140 1.94 matt db_show_all_pages(db_expr_t addr, bool have_addr,
1141 1.91 christos db_expr_t count, const char *modif)
1142 1.84 bjh21 {
1143 1.84 bjh21
1144 1.84 bjh21 uvm_page_printall(db_printf);
1145 1.84 bjh21 }
1146 1.84 bjh21
1147 1.84 bjh21 /*ARGSUSED*/
1148 1.84 bjh21 static void
1149 1.94 matt db_buf_print_cmd(db_expr_t addr, bool have_addr,
1150 1.91 christos db_expr_t count, const char *modif)
1151 1.36 chs {
1152 1.95 thorpej bool full = false;
1153 1.64 simonb
1154 1.36 chs if (modif[0] == 'f')
1155 1.95 thorpej full = true;
1156 1.36 chs
1157 1.120 rmind vfs_buf_print((struct buf *)(uintptr_t) addr, full, db_printf);
1158 1.65 simonb }
1159 1.65 simonb
1160 1.65 simonb /*ARGSUSED*/
1161 1.65 simonb static void
1162 1.94 matt db_event_print_cmd(db_expr_t addr, bool have_addr,
1163 1.91 christos db_expr_t count, const char *modif)
1164 1.65 simonb {
1165 1.95 thorpej bool full = false;
1166 1.65 simonb
1167 1.65 simonb if (modif[0] == 'f')
1168 1.95 thorpej full = true;
1169 1.65 simonb
1170 1.65 simonb event_print(full, db_printf);
1171 1.36 chs }
1172 1.36 chs
1173 1.36 chs /*ARGSUSED*/
1174 1.64 simonb static void
1175 1.94 matt db_vnode_print_cmd(db_expr_t addr, bool have_addr,
1176 1.91 christos db_expr_t count, const char *modif)
1177 1.36 chs {
1178 1.95 thorpej bool full = false;
1179 1.64 simonb
1180 1.36 chs if (modif[0] == 'f')
1181 1.95 thorpej full = true;
1182 1.36 chs
1183 1.120 rmind vfs_vnode_print((struct vnode *)(uintptr_t) addr, full, db_printf);
1184 1.74 dbj }
1185 1.74 dbj
1186 1.125 cegger /*ARGSUSED*/
1187 1.125 cegger static void
1188 1.125 cegger db_vmem_print_cmd(db_expr_t addr, bool have_addr,
1189 1.125 cegger db_expr_t count, const char *modif)
1190 1.125 cegger {
1191 1.125 cegger vmem_print((uintptr_t) addr, modif, db_printf);
1192 1.125 cegger }
1193 1.125 cegger
1194 1.125 cegger /*ARGSUSED*/
1195 1.125 cegger static void
1196 1.125 cegger db_show_all_vmems(db_expr_t addr, bool have_addr,
1197 1.125 cegger db_expr_t count, const char *modif)
1198 1.125 cegger {
1199 1.125 cegger vmem_print((uintptr_t)addr, "a", db_printf);
1200 1.125 cegger }
1201 1.125 cegger
1202 1.74 dbj static void
1203 1.94 matt db_mount_print_cmd(db_expr_t addr, bool have_addr,
1204 1.91 christos db_expr_t count, const char *modif)
1205 1.74 dbj {
1206 1.95 thorpej bool full = false;
1207 1.74 dbj
1208 1.74 dbj if (modif[0] == 'f')
1209 1.95 thorpej full = true;
1210 1.74 dbj
1211 1.120 rmind vfs_mount_print((struct mount *)(uintptr_t) addr, full, db_printf);
1212 1.4 brezak }
1213 1.4 brezak
1214 1.31 thorpej /*ARGSUSED*/
1215 1.64 simonb static void
1216 1.94 matt db_mbuf_print_cmd(db_expr_t addr, bool have_addr,
1217 1.91 christos db_expr_t count, const char *modif)
1218 1.83 yamt {
1219 1.83 yamt
1220 1.120 rmind m_print((const struct mbuf *)(uintptr_t) addr, modif, db_printf);
1221 1.83 yamt }
1222 1.83 yamt
1223 1.83 yamt /*ARGSUSED*/
1224 1.83 yamt static void
1225 1.94 matt db_pool_print_cmd(db_expr_t addr, bool have_addr,
1226 1.91 christos db_expr_t count, const char *modif)
1227 1.31 thorpej {
1228 1.64 simonb
1229 1.120 rmind pool_printit((struct pool *)(uintptr_t) addr, modif, db_printf);
1230 1.51 chs }
1231 1.31 thorpej
1232 1.51 chs /*ARGSUSED*/
1233 1.64 simonb static void
1234 1.94 matt db_namecache_print_cmd(db_expr_t addr, bool have_addr,
1235 1.91 christos db_expr_t count, const char *modif)
1236 1.51 chs {
1237 1.64 simonb
1238 1.120 rmind namecache_print((struct vnode *)(uintptr_t) addr, db_printf);
1239 1.51 chs }
1240 1.51 chs
1241 1.51 chs /*ARGSUSED*/
1242 1.64 simonb static void
1243 1.94 matt db_uvmexp_print_cmd(db_expr_t addr, bool have_addr,
1244 1.91 christos db_expr_t count, const char *modif)
1245 1.51 chs {
1246 1.64 simonb
1247 1.51 chs uvmexp_print(db_printf);
1248 1.31 thorpej }
1249 1.31 thorpej
1250 1.118 skrll #ifdef UVMHIST
1251 1.118 skrll /*ARGSUSED*/
1252 1.118 skrll static void
1253 1.118 skrll db_uvmhist_print_cmd(db_expr_t addr, bool have_addr,
1254 1.118 skrll db_expr_t count, const char *modif)
1255 1.118 skrll {
1256 1.118 skrll
1257 1.118 skrll uvmhist_print(db_printf);
1258 1.118 skrll }
1259 1.118 skrll #endif
1260 1.118 skrll
1261 1.92 ad /*ARGSUSED*/
1262 1.92 ad static void
1263 1.94 matt db_lock_print_cmd(db_expr_t addr, bool have_addr,
1264 1.92 ad db_expr_t count, const char *modif)
1265 1.92 ad {
1266 1.92 ad
1267 1.124 nakayama lockdebug_lock_print((void *)(uintptr_t)addr, db_printf);
1268 1.92 ad }
1269 1.92 ad
1270 1.1 cgd /*
1271 1.1 cgd * Call random function:
1272 1.1 cgd * !expr(arg,arg,arg)
1273 1.1 cgd */
1274 1.16 christos /*ARGSUSED*/
1275 1.64 simonb static void
1276 1.94 matt db_fncall(db_expr_t addr, bool have_addr,
1277 1.91 christos db_expr_t count, const char *modif)
1278 1.1 cgd {
1279 1.1 cgd db_expr_t fn_addr;
1280 1.1 cgd #define MAXARGS 11
1281 1.1 cgd db_expr_t args[MAXARGS];
1282 1.1 cgd int nargs = 0;
1283 1.1 cgd db_expr_t retval;
1284 1.64 simonb db_expr_t (*func)(db_expr_t, ...);
1285 1.1 cgd int t;
1286 1.1 cgd
1287 1.1 cgd if (!db_expression(&fn_addr)) {
1288 1.64 simonb db_printf("Bad function\n");
1289 1.64 simonb db_flush_lex();
1290 1.64 simonb return;
1291 1.1 cgd }
1292 1.120 rmind func = (db_expr_t (*)(db_expr_t, ...))(uintptr_t) fn_addr;
1293 1.1 cgd
1294 1.1 cgd t = db_read_token();
1295 1.1 cgd if (t == tLPAREN) {
1296 1.64 simonb if (db_expression(&args[0])) {
1297 1.64 simonb nargs++;
1298 1.64 simonb while ((t = db_read_token()) == tCOMMA) {
1299 1.64 simonb if (nargs == MAXARGS) {
1300 1.64 simonb db_printf("Too many arguments\n");
1301 1.64 simonb db_flush_lex();
1302 1.64 simonb return;
1303 1.64 simonb }
1304 1.64 simonb if (!db_expression(&args[nargs])) {
1305 1.64 simonb db_printf("Argument missing\n");
1306 1.64 simonb db_flush_lex();
1307 1.64 simonb return;
1308 1.64 simonb }
1309 1.64 simonb nargs++;
1310 1.64 simonb }
1311 1.64 simonb db_unread_token(t);
1312 1.64 simonb }
1313 1.64 simonb if (db_read_token() != tRPAREN) {
1314 1.64 simonb db_printf("?\n");
1315 1.1 cgd db_flush_lex();
1316 1.1 cgd return;
1317 1.1 cgd }
1318 1.1 cgd }
1319 1.1 cgd db_skip_to_eol();
1320 1.1 cgd
1321 1.1 cgd while (nargs < MAXARGS) {
1322 1.64 simonb args[nargs++] = 0;
1323 1.1 cgd }
1324 1.1 cgd
1325 1.1 cgd retval = (*func)(args[0], args[1], args[2], args[3], args[4],
1326 1.20 christos args[5], args[6], args[7], args[8], args[9]);
1327 1.45 jhawk db_printf("%s\n", db_num_to_str(retval));
1328 1.23 scottr }
1329 1.23 scottr
1330 1.64 simonb static void
1331 1.94 matt db_reboot_cmd(db_expr_t addr, bool have_addr,
1332 1.91 christos db_expr_t count, const char *modif)
1333 1.23 scottr {
1334 1.23 scottr db_expr_t bootflags;
1335 1.23 scottr
1336 1.23 scottr /* Flags, default to RB_AUTOBOOT */
1337 1.23 scottr if (!db_expression(&bootflags))
1338 1.23 scottr bootflags = (db_expr_t)RB_AUTOBOOT;
1339 1.23 scottr if (db_read_token() != tEOL) {
1340 1.64 simonb db_error("?\n");
1341 1.64 simonb /*NOTREACHED*/
1342 1.23 scottr }
1343 1.47 sommerfe /*
1344 1.47 sommerfe * We are leaving DDB, never to return upward.
1345 1.47 sommerfe * Clear db_recover so that we can debug faults in functions
1346 1.47 sommerfe * called from cpu_reboot.
1347 1.47 sommerfe */
1348 1.47 sommerfe db_recover = 0;
1349 1.23 scottr cpu_reboot((int)bootflags, NULL);
1350 1.41 jhawk }
1351 1.41 jhawk
1352 1.64 simonb static void
1353 1.94 matt db_sifting_cmd(db_expr_t addr, bool have_addr,
1354 1.91 christos db_expr_t count, const char *modif)
1355 1.41 jhawk {
1356 1.41 jhawk int mode, t;
1357 1.41 jhawk
1358 1.41 jhawk t = db_read_token();
1359 1.41 jhawk if (t == tSLASH) {
1360 1.41 jhawk t = db_read_token();
1361 1.41 jhawk if (t != tIDENT) {
1362 1.41 jhawk bad_modifier:
1363 1.41 jhawk db_printf("Bad modifier\n");
1364 1.41 jhawk db_flush_lex();
1365 1.41 jhawk return;
1366 1.41 jhawk }
1367 1.41 jhawk if (!strcmp(db_tok_string, "F"))
1368 1.41 jhawk mode = 'F';
1369 1.41 jhawk else
1370 1.41 jhawk goto bad_modifier;
1371 1.41 jhawk t = db_read_token();
1372 1.41 jhawk } else
1373 1.41 jhawk mode = 0;
1374 1.41 jhawk
1375 1.51 chs if (t == tIDENT)
1376 1.41 jhawk db_sifting(db_tok_string, mode);
1377 1.41 jhawk else {
1378 1.41 jhawk db_printf("Bad argument (non-string)\n");
1379 1.41 jhawk db_flush_lex();
1380 1.41 jhawk }
1381 1.43 jhawk }
1382 1.43 jhawk
1383 1.64 simonb static void
1384 1.94 matt db_stack_trace_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
1385 1.43 jhawk {
1386 1.79 drochner register const char *cp = modif;
1387 1.70 atatat register char c;
1388 1.70 atatat void (*pr)(const char *, ...);
1389 1.70 atatat
1390 1.70 atatat pr = db_printf;
1391 1.70 atatat while ((c = *cp++) != 0)
1392 1.70 atatat if (c == 'l')
1393 1.70 atatat pr = printf;
1394 1.64 simonb
1395 1.43 jhawk if (count == -1)
1396 1.43 jhawk count = 65535;
1397 1.43 jhawk
1398 1.70 atatat db_stack_trace_print(addr, have_addr, count, modif, pr);
1399 1.32 lukem }
1400 1.32 lukem
1401 1.64 simonb static void
1402 1.94 matt db_sync_cmd(db_expr_t addr, bool have_addr,
1403 1.91 christos db_expr_t count, const char *modif)
1404 1.32 lukem {
1405 1.64 simonb
1406 1.47 sommerfe /*
1407 1.47 sommerfe * We are leaving DDB, never to return upward.
1408 1.47 sommerfe * Clear db_recover so that we can debug faults in functions
1409 1.47 sommerfe * called from cpu_reboot.
1410 1.47 sommerfe */
1411 1.47 sommerfe db_recover = 0;
1412 1.113 martin panicstr = "dump forced via kernel debugger";
1413 1.32 lukem cpu_reboot(RB_DUMP, NULL);
1414 1.1 cgd }
1415 1.112 yamt
1416 1.112 yamt /*
1417 1.112 yamt * Describe what an address is
1418 1.112 yamt */
1419 1.112 yamt void
1420 1.112 yamt db_whatis_cmd(db_expr_t address, bool have_addr,
1421 1.112 yamt db_expr_t count, const char *modif)
1422 1.112 yamt {
1423 1.112 yamt const uintptr_t addr = (uintptr_t)address;
1424 1.112 yamt
1425 1.112 yamt lwp_whatis(addr, db_printf);
1426 1.112 yamt pool_whatis(addr, db_printf);
1427 1.112 yamt vmem_whatis(addr, db_printf);
1428 1.112 yamt uvm_whatis(addr, db_printf);
1429 1.123 ad module_whatis(addr, db_printf);
1430 1.112 yamt }
1431