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