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