File: | ddb/db_command.c |
Warning: | line 288, column 3 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: db_command.c,v 1.92 2021/11/16 13:53:14 bluhm Exp $ */ | |||
2 | /* $NetBSD: db_command.c,v 1.20 1996/03/30 22:30:05 christos Exp $ */ | |||
3 | ||||
4 | /* | |||
5 | * Mach Operating System | |||
6 | * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University | |||
7 | * All Rights Reserved. | |||
8 | * | |||
9 | * Permission to use, copy, modify and distribute this software and its | |||
10 | * documentation is hereby granted, provided that both the copyright | |||
11 | * notice and this permission notice appear in all copies of the | |||
12 | * software, derivative works or modified versions, and any portions | |||
13 | * thereof, and that both notices appear in supporting documentation. | |||
14 | * | |||
15 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |||
16 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |||
17 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |||
18 | * | |||
19 | * Carnegie Mellon requests users of this software to return to | |||
20 | * | |||
21 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |||
22 | * School of Computer Science | |||
23 | * Carnegie Mellon University | |||
24 | * Pittsburgh PA 15213-3890 | |||
25 | * | |||
26 | * any improvements or extensions that they make and grant Carnegie Mellon | |||
27 | * the rights to redistribute these changes. | |||
28 | */ | |||
29 | ||||
30 | /* | |||
31 | * Command dispatcher. | |||
32 | */ | |||
33 | #include <sys/param.h> | |||
34 | #include <sys/systm.h> | |||
35 | #include <sys/proc.h> | |||
36 | #include <sys/reboot.h> | |||
37 | #include <sys/extent.h> | |||
38 | #include <sys/pool.h> | |||
39 | #include <sys/msgbuf.h> | |||
40 | #include <sys/malloc.h> | |||
41 | #include <sys/mount.h> | |||
42 | ||||
43 | #include <uvm/uvm_extern.h> | |||
44 | #include <machine/db_machdep.h> /* type definitions */ | |||
45 | ||||
46 | #include <ddb/db_access.h> | |||
47 | #include <ddb/db_lex.h> | |||
48 | #include <ddb/db_output.h> | |||
49 | #include <ddb/db_command.h> | |||
50 | #include <ddb/db_break.h> | |||
51 | #include <ddb/db_watch.h> | |||
52 | #include <ddb/db_run.h> | |||
53 | #include <ddb/db_sym.h> | |||
54 | #include <ddb/db_var.h> | |||
55 | #include <ddb/db_variables.h> | |||
56 | #include <ddb/db_interface.h> | |||
57 | #include <ddb/db_extern.h> | |||
58 | ||||
59 | #include <netinet/ip_ipsp.h> | |||
60 | #include <uvm/uvm_ddb.h> | |||
61 | ||||
62 | /* | |||
63 | * Exported global variables | |||
64 | */ | |||
65 | int db_cmd_loop_done; | |||
66 | label_t *db_recover; | |||
67 | ||||
68 | /* | |||
69 | * if 'ed' style: 'dot' is set at start of last item printed, | |||
70 | * and '+' points to next line. | |||
71 | * Otherwise: 'dot' points to next item, '..' points to last. | |||
72 | */ | |||
73 | int db_ed_style = 1; | |||
74 | ||||
75 | vaddr_t db_dot; /* current location */ | |||
76 | vaddr_t db_last_addr; /* last explicit address typed */ | |||
77 | vaddr_t db_prev; /* last address examined | |||
78 | or written */ | |||
79 | vaddr_t db_next; /* next address to be examined | |||
80 | or written */ | |||
81 | ||||
82 | int db_cmd_search(char *, struct db_command *, struct db_command **); | |||
83 | void db_cmd_list(struct db_command *); | |||
84 | void db_ctf_pprint_cmd(db_expr_t, int, db_expr_t,char *); | |||
85 | void db_map_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
86 | void db_buf_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
87 | void db_malloc_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
88 | void db_mbuf_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
89 | void db_mount_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
90 | void db_show_all_mounts(db_expr_t, int, db_expr_t, char *); | |||
91 | void db_show_all_vnodes(db_expr_t, int, db_expr_t, char *); | |||
92 | void db_show_all_bufs(db_expr_t, int, db_expr_t, char *); | |||
93 | void db_show_all_tdbs(db_expr_t, int, db_expr_t, char *); | |||
94 | void db_object_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
95 | void db_page_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
96 | void db_extent_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
97 | void db_pool_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
98 | void db_proc_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
99 | void db_uvmexp_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
100 | void db_tdb_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
101 | void db_vnode_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
102 | void db_nfsreq_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
103 | void db_nfsnode_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
104 | void db_help_cmd(db_expr_t, int, db_expr_t, char *); | |||
105 | void db_fncall(db_expr_t, int, db_expr_t, char *); | |||
106 | void db_boot_sync_cmd(db_expr_t, int, db_expr_t, char *); | |||
107 | void db_boot_crash_cmd(db_expr_t, int, db_expr_t, char *); | |||
108 | void db_boot_dump_cmd(db_expr_t, int, db_expr_t, char *); | |||
109 | void db_boot_halt_cmd(db_expr_t, int, db_expr_t, char *); | |||
110 | void db_boot_reboot_cmd(db_expr_t, int, db_expr_t, char *); | |||
111 | void db_boot_poweroff_cmd(db_expr_t, int, db_expr_t, char *); | |||
112 | void db_stack_trace_cmd(db_expr_t, int, db_expr_t, char *); | |||
113 | void db_dmesg_cmd(db_expr_t, int, db_expr_t, char *); | |||
114 | void db_show_panic_cmd(db_expr_t, int, db_expr_t, char *); | |||
115 | void db_bcstats_print_cmd(db_expr_t, int, db_expr_t, char *); | |||
116 | void db_struct_offset_cmd(db_expr_t, int, db_expr_t, char *); | |||
117 | void db_ctf_show_struct(db_expr_t, int, db_expr_t, char *); | |||
118 | void db_show_regs(db_expr_t, int, db_expr_t, char *); | |||
119 | void db_write_cmd(db_expr_t, int, db_expr_t, char *); | |||
120 | void db_witness_display(db_expr_t, int, db_expr_t, char *); | |||
121 | void db_witness_list(db_expr_t, int, db_expr_t, char *); | |||
122 | void db_witness_list_all(db_expr_t, int, db_expr_t, char *); | |||
123 | ||||
124 | ||||
125 | /* | |||
126 | * Utility routine - discard tokens through end-of-line. | |||
127 | */ | |||
128 | void | |||
129 | db_skip_to_eol(void) | |||
130 | { | |||
131 | int t; | |||
132 | do { | |||
133 | t = db_read_token(); | |||
134 | } while (t != tEOL1); | |||
135 | } | |||
136 | ||||
137 | /* | |||
138 | * Results of command search. | |||
139 | */ | |||
140 | #define CMD_UNIQUE0 0 | |||
141 | #define CMD_FOUND1 1 | |||
142 | #define CMD_NONE2 2 | |||
143 | #define CMD_AMBIGUOUS3 3 | |||
144 | ||||
145 | /* | |||
146 | * Search for command prefix. | |||
147 | */ | |||
148 | int | |||
149 | db_cmd_search(char *name, struct db_command *table, struct db_command **cmdp) | |||
150 | { | |||
151 | struct db_command *cmd; | |||
152 | int result = CMD_NONE2; | |||
153 | ||||
154 | for (cmd = table; cmd->name != 0; cmd++) { | |||
155 | char *lp = name, *rp = cmd->name; | |||
156 | int c; | |||
157 | ||||
158 | while ((c = *lp) == *rp) { | |||
159 | if (c == 0) { | |||
160 | /* complete match */ | |||
161 | *cmdp = cmd; | |||
162 | return (CMD_UNIQUE0); | |||
163 | } | |||
164 | lp++; | |||
165 | rp++; | |||
166 | } | |||
167 | if (c == 0) { | |||
168 | /* end of name, not end of command - partial match */ | |||
169 | if (result == CMD_FOUND1) { | |||
170 | result = CMD_AMBIGUOUS3; | |||
171 | /* but keep looking for a full match - | |||
172 | this lets us match single letters */ | |||
173 | } else { | |||
174 | *cmdp = cmd; | |||
175 | result = CMD_FOUND1; | |||
176 | } | |||
177 | } | |||
178 | } | |||
179 | return (result); | |||
180 | } | |||
181 | ||||
182 | void | |||
183 | db_cmd_list(struct db_command *table) | |||
184 | { | |||
185 | struct db_command *cmd; | |||
186 | ||||
187 | for (cmd = table; cmd->name != 0; cmd++) { | |||
188 | db_printf("%-12s", cmd->name); | |||
189 | db_end_line(12); | |||
190 | } | |||
191 | } | |||
192 | ||||
193 | void | |||
194 | db_command(struct db_command **last_cmdp, struct db_command *cmd_table) | |||
195 | { | |||
196 | struct db_command *cmd; | |||
197 | char modif[TOK_STRING_SIZE120]; | |||
198 | db_expr_t addr, count; | |||
199 | int t, result, have_addr = 0; | |||
200 | ||||
201 | t = db_read_token(); | |||
202 | if (t == tEOL1) { | |||
203 | /* empty line repeats last command, at 'next' */ | |||
204 | cmd = *last_cmdp; | |||
205 | addr = (db_expr_t)db_next; | |||
206 | have_addr = 0; | |||
207 | count = 1; | |||
208 | modif[0] = '\0'; | |||
209 | } else if (t == tEXCL17) { | |||
210 | db_fncall(0, 0, 0, NULL((void *)0)); | |||
211 | return; | |||
212 | } else if (t != tIDENT3) { | |||
213 | db_printf("?\n"); | |||
214 | db_flush_lex(); | |||
215 | return; | |||
216 | } else { | |||
217 | /* Search for command */ | |||
218 | while (cmd_table) { | |||
219 | result = db_cmd_search(db_tok_string, | |||
220 | cmd_table, &cmd); | |||
221 | switch (result) { | |||
222 | case CMD_NONE2: | |||
223 | db_printf("No such command\n"); | |||
224 | db_flush_lex(); | |||
225 | return; | |||
226 | case CMD_AMBIGUOUS3: | |||
227 | db_printf("Ambiguous\n"); | |||
228 | db_flush_lex(); | |||
229 | return; | |||
230 | default: | |||
231 | break; | |||
232 | } | |||
233 | if ((cmd_table = cmd->more) != 0) { | |||
234 | t = db_read_token(); | |||
235 | if (t != tIDENT3) { | |||
236 | db_cmd_list(cmd_table); | |||
237 | db_flush_lex(); | |||
238 | return; | |||
239 | } | |||
240 | } | |||
241 | } | |||
242 | ||||
243 | if ((cmd->flag & CS_OWN0x1) == 0) { | |||
244 | /* | |||
245 | * Standard syntax: | |||
246 | * command [/modifier] [addr] [,count] | |||
247 | */ | |||
248 | t = db_read_token(); | |||
249 | if (t == tSLASH8) { | |||
250 | t = db_read_token(); | |||
251 | if (t != tIDENT3) { | |||
252 | db_printf("Bad modifier\n"); | |||
253 | db_flush_lex(); | |||
254 | return; | |||
255 | } | |||
256 | db_strlcpy(modif, db_tok_string, sizeof(modif)); | |||
257 | } else { | |||
258 | db_unread_token(t); | |||
259 | modif[0] = '\0'; | |||
260 | } | |||
261 | ||||
262 | if (db_expression(&addr)) { | |||
263 | db_dot = (vaddr_t) addr; | |||
264 | db_last_addr = db_dot; | |||
265 | have_addr = 1; | |||
266 | } else { | |||
267 | addr = (db_expr_t) db_dot; | |||
268 | have_addr = 0; | |||
269 | } | |||
270 | t = db_read_token(); | |||
271 | if (t == tCOMMA14) { | |||
272 | if (!db_expression(&count)) { | |||
273 | db_printf("Count missing\n"); | |||
274 | db_flush_lex(); | |||
275 | return; | |||
276 | } | |||
277 | } else { | |||
278 | db_unread_token(t); | |||
279 | count = -1; | |||
280 | } | |||
281 | if ((cmd->flag & CS_MORE0x2) == 0) | |||
282 | db_skip_to_eol(); | |||
283 | } | |||
284 | } | |||
285 | *last_cmdp = cmd; | |||
286 | if (cmd
| |||
287 | /* Execute the command. */ | |||
288 | (*cmd->fcn)(addr, have_addr, count, modif); | |||
| ||||
289 | ||||
290 | if (cmd->flag & CS_SET_DOT0x100) { | |||
291 | /* | |||
292 | * If command changes dot, set dot to | |||
293 | * previous address displayed (if 'ed' style). | |||
294 | */ | |||
295 | if (db_ed_style) | |||
296 | db_dot = db_prev; | |||
297 | else | |||
298 | db_dot = db_next; | |||
299 | } | |||
300 | } else { | |||
301 | /* | |||
302 | * If command does not change dot, | |||
303 | * set 'next' location to be the same. | |||
304 | */ | |||
305 | db_next = db_dot; | |||
306 | } | |||
307 | } | |||
308 | ||||
309 | /*ARGSUSED*/ | |||
310 | void | |||
311 | db_buf_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
312 | { | |||
313 | int full = 0; | |||
314 | ||||
315 | if (modif[0] == 'f') | |||
316 | full = 1; | |||
317 | ||||
318 | vfs_buf_print((void *) addr, full, db_printf); | |||
319 | } | |||
320 | ||||
321 | /*ARGSUSED*/ | |||
322 | void | |||
323 | db_map_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
324 | { | |||
325 | int full = 0; | |||
326 | ||||
327 | if (modif[0] == 'f') | |||
328 | full = 1; | |||
329 | ||||
330 | uvm_map_printit((struct vm_map *) addr, full, db_printf); | |||
331 | } | |||
332 | ||||
333 | /*ARGSUSED*/ | |||
334 | void | |||
335 | db_malloc_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
336 | { | |||
337 | malloc_printit(db_printf); | |||
338 | } | |||
339 | ||||
340 | /*ARGSUSED*/ | |||
341 | void | |||
342 | db_mbuf_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
343 | { | |||
344 | m_print((void *)addr, db_printf); | |||
345 | } | |||
346 | ||||
347 | /*ARGSUSED*/ | |||
348 | void | |||
349 | db_socket_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
350 | { | |||
351 | so_print((void *)addr, db_printf); | |||
352 | } | |||
353 | ||||
354 | /*ARGSUSED*/ | |||
355 | void | |||
356 | db_mount_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
357 | { | |||
358 | int full = 0; | |||
359 | ||||
360 | if (modif[0] == 'f') | |||
361 | full = 1; | |||
362 | ||||
363 | vfs_mount_print((struct mount *) addr, full, db_printf); | |||
364 | } | |||
365 | ||||
366 | void | |||
367 | db_show_all_mounts(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
368 | { | |||
369 | int full = 0; | |||
370 | struct mount *mp; | |||
371 | ||||
372 | if (modif[0] == 'f') | |||
373 | full = 1; | |||
374 | ||||
375 | TAILQ_FOREACH(mp, &mountlist, mnt_list)for((mp) = ((&mountlist)->tqh_first); (mp) != ((void * )0); (mp) = ((mp)->mnt_list.tqe_next)) { | |||
376 | db_printf("mountpoint %p\n", mp); | |||
377 | vfs_mount_print(mp, full, db_printf); | |||
378 | } | |||
379 | } | |||
380 | ||||
381 | extern struct pool vnode_pool; | |||
382 | void | |||
383 | db_show_all_vnodes(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
384 | { | |||
385 | int full = 0; | |||
386 | ||||
387 | if (modif[0] == 'f') | |||
388 | full = 1; | |||
389 | ||||
390 | pool_walk(&vnode_pool, full, db_printf, vfs_vnode_print); | |||
391 | } | |||
392 | ||||
393 | extern struct pool bufpool; | |||
394 | void | |||
395 | db_show_all_bufs(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
396 | { | |||
397 | int full = 0; | |||
398 | ||||
399 | if (modif[0] == 'f') | |||
400 | full = 1; | |||
401 | ||||
402 | pool_walk(&bufpool, full, db_printf, vfs_buf_print); | |||
403 | } | |||
404 | ||||
405 | #ifdef IPSEC1 | |||
406 | void | |||
407 | db_show_all_tdbs(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
408 | { | |||
409 | int full = 0; | |||
410 | ||||
411 | if (modif[0] == 'f') | |||
412 | full = 1; | |||
413 | ||||
414 | pool_walk(&tdb_pool, full, db_printf, tdb_printit); | |||
415 | } | |||
416 | #endif | |||
417 | ||||
418 | /*ARGSUSED*/ | |||
419 | void | |||
420 | db_object_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
421 | { | |||
422 | int full = 0; | |||
423 | ||||
424 | if (modif[0] == 'f') | |||
425 | full = 1; | |||
426 | ||||
427 | uvm_object_printit((struct uvm_object *) addr, full, db_printf); | |||
428 | } | |||
429 | ||||
430 | /*ARGSUSED*/ | |||
431 | void | |||
432 | db_page_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
433 | { | |||
434 | int full = 0; | |||
435 | ||||
436 | if (modif[0] == 'f') | |||
437 | full = 1; | |||
438 | ||||
439 | uvm_page_printit((struct vm_page *) addr, full, db_printf); | |||
440 | } | |||
441 | ||||
442 | /*ARGSUSED*/ | |||
443 | void | |||
444 | db_vnode_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
445 | { | |||
446 | int full = 0; | |||
447 | ||||
448 | if (modif[0] == 'f') | |||
449 | full = 1; | |||
450 | ||||
451 | vfs_vnode_print((void *)addr, full, db_printf); | |||
452 | } | |||
453 | ||||
454 | #ifdef NFSCLIENT1 | |||
455 | /*ARGSUSED*/ | |||
456 | void | |||
457 | db_nfsreq_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, | |||
458 | char *modif) | |||
459 | { | |||
460 | int full = 0; | |||
461 | ||||
462 | if (modif[0] == 'f') | |||
463 | full = 1; | |||
464 | ||||
465 | nfs_request_print((void *)addr, full, db_printf); | |||
466 | } | |||
467 | ||||
468 | /*ARGSUSED*/ | |||
469 | void | |||
470 | db_nfsnode_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, | |||
471 | char *modif) | |||
472 | { | |||
473 | int full = 0; | |||
474 | ||||
475 | if (modif[0] == 'f') | |||
476 | full = 1; | |||
477 | ||||
478 | nfs_node_print((void *)addr, full, db_printf); | |||
479 | } | |||
480 | #endif | |||
481 | ||||
482 | ||||
483 | /*ARGSUSED*/ | |||
484 | void | |||
485 | db_show_panic_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
486 | { | |||
487 | struct cpu_info *ci; | |||
488 | char *prefix; | |||
489 | CPU_INFO_ITERATORint cii; | |||
490 | int panicked = 0; | |||
491 | ||||
492 | CPU_INFO_FOREACH(cii, ci)for (cii = 0, ci = cpu_info_list; ci != ((void *)0); ci = ci-> ci_next) { | |||
493 | if (ci->ci_panicbuf[0] != '\0') { | |||
494 | prefix = (panicstr == ci->ci_panicbuf) ? "*" : " "; | |||
495 | db_printf("%scpu%d: %s\n", | |||
496 | prefix, CPU_INFO_UNIT(ci)((ci)->ci_dev ? (ci)->ci_dev->dv_unit : 0), ci->ci_panicbuf); | |||
497 | panicked = 1; | |||
498 | } | |||
499 | } | |||
500 | if (!panicked) | |||
501 | db_printf("the kernel did not panic\n"); /* yet */ | |||
502 | } | |||
503 | ||||
504 | /*ARGSUSED*/ | |||
505 | void | |||
506 | db_extent_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
507 | { | |||
508 | extent_print_all(); | |||
509 | } | |||
510 | ||||
511 | /*ARGSUSED*/ | |||
512 | void | |||
513 | db_pool_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
514 | { | |||
515 | pool_printit((struct pool *)addr, modif, db_printf); | |||
516 | } | |||
517 | ||||
518 | /*ARGSUSED*/ | |||
519 | void | |||
520 | db_proc_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
521 | { | |||
522 | if (!have_addr) | |||
523 | addr = (db_expr_t)curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc; | |||
524 | ||||
525 | proc_printit((struct proc *)addr, modif, db_printf); | |||
526 | } | |||
527 | ||||
528 | #ifdef IPSEC1 | |||
529 | void | |||
530 | db_tdb_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
531 | { | |||
532 | int full = 0; | |||
533 | ||||
534 | if (modif[0] == 'f') | |||
535 | full = 1; | |||
536 | ||||
537 | tdb_printit((void *)addr, full, db_printf); | |||
538 | } | |||
539 | #endif | |||
540 | ||||
541 | /*ARGSUSED*/ | |||
542 | void | |||
543 | db_uvmexp_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
544 | { | |||
545 | uvmexp_print(db_printf); | |||
546 | } | |||
547 | ||||
548 | void bcstats_print(int (*)(const char *, ...)); | |||
549 | ||||
550 | /*ARGSUSED*/ | |||
551 | void | |||
552 | db_bcstats_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
553 | { | |||
554 | bcstats_print(db_printf); | |||
555 | } | |||
556 | ||||
557 | /* | |||
558 | * 'show' commands | |||
559 | */ | |||
560 | ||||
561 | struct db_command db_show_all_cmds[] = { | |||
562 | { "procs", db_show_all_procs, 0, NULL((void *)0) }, | |||
563 | { "callout", db_show_callout, 0, NULL((void *)0) }, | |||
564 | { "pools", db_show_all_pools, 0, NULL((void *)0) }, | |||
565 | { "mounts", db_show_all_mounts, 0, NULL((void *)0) }, | |||
566 | { "vnodes", db_show_all_vnodes, 0, NULL((void *)0) }, | |||
567 | { "bufs", db_show_all_bufs, 0, NULL((void *)0) }, | |||
568 | #ifdef NFSCLIENT1 | |||
569 | { "nfsreqs", db_show_all_nfsreqs, 0, NULL((void *)0) }, | |||
570 | { "nfsnodes", db_show_all_nfsnodes, 0, NULL((void *)0) }, | |||
571 | #endif | |||
572 | #ifdef IPSEC1 | |||
573 | { "tdbs", db_show_all_tdbs, 0, NULL((void *)0) }, | |||
574 | #endif | |||
575 | #ifdef WITNESS | |||
576 | { "locks", db_witness_list_all, 0, NULL((void *)0) }, | |||
577 | #endif | |||
578 | { NULL((void *)0), NULL((void *)0), 0, NULL((void *)0) } | |||
579 | }; | |||
580 | ||||
581 | struct db_command db_show_cmds[] = { | |||
582 | { "all", NULL((void *)0), 0, db_show_all_cmds }, | |||
583 | { "bcstats", db_bcstats_print_cmd, 0, NULL((void *)0) }, | |||
584 | { "breaks", db_listbreak_cmd, 0, NULL((void *)0) }, | |||
585 | { "buf", db_buf_print_cmd, 0, NULL((void *)0) }, | |||
586 | { "extents", db_extent_print_cmd, 0, NULL((void *)0) }, | |||
587 | #ifdef WITNESS | |||
588 | { "locks", db_witness_list, 0, NULL((void *)0) }, | |||
589 | #endif | |||
590 | { "malloc", db_malloc_print_cmd, 0, NULL((void *)0) }, | |||
591 | { "map", db_map_print_cmd, 0, NULL((void *)0) }, | |||
592 | { "mbuf", db_mbuf_print_cmd, 0, NULL((void *)0) }, | |||
593 | { "mount", db_mount_print_cmd, 0, NULL((void *)0) }, | |||
594 | #ifdef NFSCLIENT1 | |||
595 | { "nfsreq", db_nfsreq_print_cmd, 0, NULL((void *)0) }, | |||
596 | { "nfsnode", db_nfsnode_print_cmd, 0, NULL((void *)0) }, | |||
597 | #endif | |||
598 | { "object", db_object_print_cmd, 0, NULL((void *)0) }, | |||
599 | { "page", db_page_print_cmd, 0, NULL((void *)0) }, | |||
600 | { "panic", db_show_panic_cmd, 0, NULL((void *)0) }, | |||
601 | { "pool", db_pool_print_cmd, 0, NULL((void *)0) }, | |||
602 | { "proc", db_proc_print_cmd, 0, NULL((void *)0) }, | |||
603 | { "registers", db_show_regs, 0, NULL((void *)0) }, | |||
604 | { "socket", db_socket_print_cmd, 0, NULL((void *)0) }, | |||
605 | { "struct", db_ctf_show_struct, CS_OWN0x1, NULL((void *)0) }, | |||
606 | #ifdef IPSEC1 | |||
607 | { "tdb", db_tdb_print_cmd, 0, NULL((void *)0) }, | |||
608 | #endif | |||
609 | { "uvmexp", db_uvmexp_print_cmd, 0, NULL((void *)0) }, | |||
610 | { "vnode", db_vnode_print_cmd, 0, NULL((void *)0) }, | |||
611 | { "watches", db_listwatch_cmd, 0, NULL((void *)0) }, | |||
612 | #ifdef WITNESS | |||
613 | { "witness", db_witness_display, 0, NULL((void *)0) }, | |||
614 | #endif | |||
615 | { NULL((void *)0), NULL((void *)0), 0, NULL((void *)0) } | |||
616 | }; | |||
617 | ||||
618 | struct db_command db_boot_cmds[] = { | |||
619 | { "sync", db_boot_sync_cmd, 0, 0 }, | |||
620 | { "crash", db_boot_crash_cmd, 0, 0 }, | |||
621 | { "dump", db_boot_dump_cmd, 0, 0 }, | |||
622 | { "halt", db_boot_halt_cmd, 0, 0 }, | |||
623 | { "reboot", db_boot_reboot_cmd, 0, 0 }, | |||
624 | { "poweroff", db_boot_poweroff_cmd, 0, 0 }, | |||
625 | { NULL((void *)0), } | |||
626 | }; | |||
627 | ||||
628 | struct db_command db_command_table[] = { | |||
629 | #ifdef DB_MACHINE_COMMANDS | |||
630 | /* this must be the first entry, if it exists */ | |||
631 | { "machine", NULL((void *)0), 0, NULL((void *)0)}, | |||
632 | #endif | |||
633 | { "kill", db_kill_cmd, 0, NULL((void *)0) }, | |||
634 | { "print", db_print_cmd, 0, NULL((void *)0) }, | |||
635 | { "p", db_print_cmd, 0, NULL((void *)0) }, | |||
636 | { "pprint", db_ctf_pprint_cmd, CS_OWN0x1, NULL((void *)0) }, | |||
637 | { "examine", db_examine_cmd, CS_SET_DOT0x100, NULL((void *)0) }, | |||
638 | { "x", db_examine_cmd, CS_SET_DOT0x100, NULL((void *)0) }, | |||
639 | { "search", db_search_cmd, CS_OWN0x1|CS_SET_DOT0x100, NULL((void *)0) }, | |||
640 | { "set", db_set_cmd, CS_OWN0x1, NULL((void *)0) }, | |||
641 | { "write", db_write_cmd, CS_MORE0x2|CS_SET_DOT0x100, NULL((void *)0) }, | |||
642 | { "w", db_write_cmd, CS_MORE0x2|CS_SET_DOT0x100, NULL((void *)0) }, | |||
643 | { "delete", db_delete_cmd, 0, NULL((void *)0) }, | |||
644 | { "d", db_delete_cmd, 0, NULL((void *)0) }, | |||
645 | { "break", db_breakpoint_cmd, 0, NULL((void *)0) }, | |||
646 | { "dwatch", db_deletewatch_cmd, 0, NULL((void *)0) }, | |||
647 | { "watch", db_watchpoint_cmd, CS_MORE0x2, NULL((void *)0) }, | |||
648 | { "step", db_single_step_cmd, 0, NULL((void *)0) }, | |||
649 | { "s", db_single_step_cmd, 0, NULL((void *)0) }, | |||
650 | { "continue", db_continue_cmd, 0, NULL((void *)0) }, | |||
651 | { "c", db_continue_cmd, 0, NULL((void *)0) }, | |||
652 | { "until", db_trace_until_call_cmd,0, NULL((void *)0) }, | |||
653 | { "next", db_trace_until_matching_cmd,0, NULL((void *)0) }, | |||
654 | { "match", db_trace_until_matching_cmd,0, NULL((void *)0) }, | |||
655 | { "trace", db_stack_trace_cmd, 0, NULL((void *)0) }, | |||
656 | { "bt", db_stack_trace_cmd, 0, NULL((void *)0) }, | |||
657 | { "call", db_fncall, CS_OWN0x1, NULL((void *)0) }, | |||
658 | { "ps", db_show_all_procs, 0, NULL((void *)0) }, | |||
659 | { "callout", db_show_callout, 0, NULL((void *)0) }, | |||
660 | { "reboot", db_boot_reboot_cmd, 0, NULL((void *)0) }, | |||
661 | { "show", NULL((void *)0), 0, db_show_cmds }, | |||
662 | { "boot", NULL((void *)0), 0, db_boot_cmds }, | |||
663 | { "help", db_help_cmd, 0, NULL((void *)0) }, | |||
664 | { "hangman", db_hangman, 0, NULL((void *)0) }, | |||
665 | { "dmesg", db_dmesg_cmd, 0, NULL((void *)0) }, | |||
666 | { NULL((void *)0), NULL((void *)0), 0, NULL((void *)0) } | |||
667 | }; | |||
668 | ||||
669 | #ifdef DB_MACHINE_COMMANDS | |||
670 | ||||
671 | /* this function should be called to install the machine dependent | |||
672 | commands. It should be called before the debugger is enabled */ | |||
673 | void | |||
674 | db_machine_commands_install(struct db_command *ptr) | |||
675 | { | |||
676 | db_command_table[0].more = ptr; | |||
677 | } | |||
678 | ||||
679 | #endif | |||
680 | ||||
681 | struct db_command *db_last_command = NULL((void *)0); | |||
682 | ||||
683 | void | |||
684 | db_help_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) | |||
685 | { | |||
686 | db_cmd_list(db_command_table); | |||
687 | } | |||
688 | ||||
689 | void | |||
690 | db_command_loop(void) | |||
691 | { | |||
692 | label_t db_jmpbuf; | |||
693 | label_t *savejmp; | |||
694 | extern int db_output_line; | |||
695 | ||||
696 | /* | |||
697 | * Initialize 'prev' and 'next' to dot. | |||
698 | */ | |||
699 | db_prev = db_dot; | |||
700 | db_next = db_dot; | |||
701 | ||||
702 | db_cmd_loop_done = 0; | |||
703 | ||||
704 | savejmp = db_recover; | |||
705 | db_recover = &db_jmpbuf; | |||
706 | (void) setjmp(&db_jmpbuf); | |||
707 | ||||
708 | while (!db_cmd_loop_done) { | |||
| ||||
709 | ||||
710 | if (db_print_position() != 0) | |||
711 | db_printf("\n"); | |||
712 | db_output_line = 0; | |||
713 | ||||
714 | #ifdef MULTIPROCESSOR1 | |||
715 | db_printf("ddb{%d}> ", CPU_INFO_UNIT(curcpu())((({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;}))->ci_dev ? (({struct cpu_info *__ci; asm volatile ("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;}))->ci_dev->dv_unit : 0)); | |||
716 | #else | |||
717 | db_printf("ddb> "); | |||
718 | #endif | |||
719 | (void) db_read_line(); | |||
720 | ||||
721 | db_command(&db_last_command, db_command_table); | |||
722 | } | |||
723 | ||||
724 | db_recover = savejmp; | |||
725 | } | |||
726 | ||||
727 | void | |||
728 | db_error(char *s) | |||
729 | { | |||
730 | if (s) | |||
731 | db_printf("%s", s); | |||
732 | db_flush_lex(); | |||
733 | if (db_recover != NULL((void *)0)) | |||
734 | longjmp(db_recover); | |||
735 | } | |||
736 | ||||
737 | ||||
738 | /* | |||
739 | * Call random function: | |||
740 | * !expr(arg,arg,arg) | |||
741 | */ | |||
742 | /*ARGSUSED*/ | |||
743 | void | |||
744 | db_fncall(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
745 | { | |||
746 | db_expr_t fn_addr; | |||
747 | #define MAXARGS11 11 | |||
748 | db_expr_t args[MAXARGS11]; | |||
749 | int nargs = 0; | |||
750 | db_expr_t retval; | |||
751 | db_expr_t (*func)(db_expr_t, ...); | |||
752 | int t; | |||
753 | char tmpfmt[28]; | |||
754 | ||||
755 | if (!db_expression(&fn_addr)) { | |||
756 | db_printf("Bad function\n"); | |||
757 | db_flush_lex(); | |||
758 | return; | |||
759 | } | |||
760 | func = (db_expr_t (*)(db_expr_t, ...)) fn_addr; | |||
761 | ||||
762 | t = db_read_token(); | |||
763 | if (t == tLPAREN10) { | |||
764 | if (db_expression(&args[0])) { | |||
765 | nargs++; | |||
766 | while ((t = db_read_token()) == tCOMMA14) { | |||
767 | if (nargs == MAXARGS11) { | |||
768 | db_printf("Too many arguments\n"); | |||
769 | db_flush_lex(); | |||
770 | return; | |||
771 | } | |||
772 | if (!db_expression(&args[nargs])) { | |||
773 | db_printf("Argument missing\n"); | |||
774 | db_flush_lex(); | |||
775 | return; | |||
776 | } | |||
777 | nargs++; | |||
778 | } | |||
779 | db_unread_token(t); | |||
780 | } | |||
781 | if (db_read_token() != tRPAREN11) { | |||
782 | db_printf("?\n"); | |||
783 | db_flush_lex(); | |||
784 | return; | |||
785 | } | |||
786 | } | |||
787 | db_skip_to_eol(); | |||
788 | ||||
789 | while (nargs < MAXARGS11) | |||
790 | args[nargs++] = 0; | |||
791 | ||||
792 | retval = (*func)(args[0], args[1], args[2], args[3], args[4], | |||
793 | args[5], args[6], args[7], args[8], args[9]); | |||
794 | db_printf("%s\n", db_format(tmpfmt, sizeof tmpfmt, retval, | |||
795 | DB_FORMAT_N3, 1, 0)); | |||
796 | } | |||
797 | ||||
798 | void | |||
799 | db_reboot(int howto) | |||
800 | { | |||
801 | spl0()spllower(0x0); | |||
802 | if (!curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc) | |||
803 | curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc = &proc0; | |||
804 | reboot(howto); | |||
805 | } | |||
806 | ||||
807 | void | |||
808 | db_boot_sync_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) | |||
809 | { | |||
810 | db_reboot(RB_AUTOBOOT0 | RB_TIMEBAD0x00800 | RB_USERREQ0x04000); | |||
811 | } | |||
812 | ||||
813 | void | |||
814 | db_boot_crash_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) | |||
815 | { | |||
816 | db_reboot(RB_NOSYNC0x00004 | RB_DUMP0x00100 | RB_TIMEBAD0x00800 | RB_USERREQ0x04000); | |||
817 | } | |||
818 | ||||
819 | void | |||
820 | db_boot_dump_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) | |||
821 | { | |||
822 | db_reboot(RB_DUMP0x00100 | RB_TIMEBAD0x00800 | RB_USERREQ0x04000); | |||
823 | } | |||
824 | ||||
825 | void | |||
826 | db_boot_halt_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) | |||
827 | { | |||
828 | db_reboot(RB_NOSYNC0x00004 | RB_HALT0x00008 | RB_TIMEBAD0x00800 | RB_USERREQ0x04000); | |||
829 | } | |||
830 | ||||
831 | void | |||
832 | db_boot_reboot_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) | |||
833 | { | |||
834 | boot(RB_RESET0x08000 | RB_AUTOBOOT0 | RB_NOSYNC0x00004 | RB_TIMEBAD0x00800 | RB_USERREQ0x04000); | |||
835 | } | |||
836 | ||||
837 | void | |||
838 | db_boot_poweroff_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) | |||
839 | { | |||
840 | db_reboot(RB_NOSYNC0x00004 | RB_HALT0x00008 | RB_POWERDOWN0x01000 | RB_TIMEBAD0x00800 | RB_USERREQ0x04000); | |||
841 | } | |||
842 | ||||
843 | void | |||
844 | db_dmesg_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif) | |||
845 | { | |||
846 | int i, off; | |||
847 | char *p; | |||
848 | ||||
849 | if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC0x063061) | |||
850 | return; | |||
851 | off = msgbufp->msg_bufx; | |||
852 | if (off > msgbufp->msg_bufs) | |||
853 | off = 0; | |||
854 | for (i = 0, p = msgbufp->msg_bufc + off; | |||
855 | i < msgbufp->msg_bufs; i++, p++) { | |||
856 | if (p >= msgbufp->msg_bufc + msgbufp->msg_bufs) | |||
857 | p = msgbufp->msg_bufc; | |||
858 | if (*p != '\0') | |||
859 | db_putchar(*p); | |||
860 | } | |||
861 | db_putchar('\n'); | |||
862 | } | |||
863 | ||||
864 | void | |||
865 | db_stack_trace_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
866 | { | |||
867 | db_stack_trace_print(addr, have_addr, count, modif, db_printf); | |||
868 | } | |||
869 | ||||
870 | void | |||
871 | db_show_regs(db_expr_t addr, int have_addr, db_expr_t count, char *modif) | |||
872 | { | |||
873 | struct db_variable *regp; | |||
874 | db_expr_t value, offset; | |||
875 | char * name; | |||
876 | char tmpfmt[28]; | |||
877 | ||||
878 | for (regp = db_regs; regp < db_eregs; regp++) { | |||
879 | db_read_variable(regp, &value); | |||
880 | db_printf("%-12s%s", regp->name, | |||
881 | db_format(tmpfmt, sizeof tmpfmt, | |||
882 | (long)value, DB_FORMAT_N3, 1, sizeof(long) * 3)); | |||
883 | db_find_xtrn_sym_and_offset((vaddr_t)value, &name, &offset)db_symbol_values(db_search_symbol((vaddr_t)value,1,&offset ),&name,((void *)0)); | |||
884 | if (name != 0 && offset <= db_maxoff && offset != value) { | |||
885 | db_printf("\t%s", name); | |||
886 | if (offset != 0) | |||
887 | db_printf("+%s", | |||
888 | db_format(tmpfmt, sizeof tmpfmt, | |||
889 | (long)offset, DB_FORMAT_R2, 1, 0)); | |||
890 | } | |||
891 | db_printf("\n"); | |||
892 | } | |||
893 | db_print_loc_and_inst(PC_REGS(&ddb_regs)((vaddr_t)(&ddb_regs)->tf_rip)); | |||
894 | } | |||
895 | ||||
896 | /* | |||
897 | * Write to file. | |||
898 | */ | |||
899 | /*ARGSUSED*/ | |||
900 | void | |||
901 | db_write_cmd(db_expr_t address, int have_addr, db_expr_t count, char *modif) | |||
902 | { | |||
903 | vaddr_t addr; | |||
904 | db_expr_t old_value; | |||
905 | db_expr_t new_value; | |||
906 | int size, wrote_one = 0; | |||
907 | char tmpfmt[28]; | |||
908 | ||||
909 | addr = (vaddr_t) address; | |||
910 | ||||
911 | switch (modif[0]) { | |||
912 | case 'b': | |||
913 | size = 1; | |||
914 | break; | |||
915 | case 'h': | |||
916 | size = 2; | |||
917 | break; | |||
918 | case 'l': | |||
919 | case '\0': | |||
920 | size = 4; | |||
921 | break; | |||
922 | #ifdef __LP64__1 | |||
923 | case 'q': | |||
924 | size = 8; | |||
925 | break; | |||
926 | #endif | |||
927 | default: | |||
928 | size = -1; | |||
929 | db_error("Unknown size\n"); | |||
930 | /*NOTREACHED*/ | |||
931 | } | |||
932 | ||||
933 | while (db_expression(&new_value)) { | |||
934 | old_value = db_get_value(addr, size, 0); | |||
935 | db_printsym(addr, DB_STGY_ANY0, db_printf); | |||
936 | db_printf("\t\t%s\t", db_format(tmpfmt, sizeof tmpfmt, | |||
937 | old_value, DB_FORMAT_N3, 0, 8)); | |||
938 | db_printf("=\t%s\n", db_format(tmpfmt, sizeof tmpfmt, | |||
939 | new_value, DB_FORMAT_N3, 0, 8)); | |||
940 | db_put_value(addr, size, new_value); | |||
941 | addr += size; | |||
942 | ||||
943 | wrote_one = 1; | |||
944 | } | |||
945 | ||||
946 | if (!wrote_one) { | |||
947 | db_error("Nothing written.\n"); | |||
948 | /*NOTREACHED*/ | |||
949 | } | |||
950 | ||||
951 | db_next = addr; | |||
952 | db_prev = addr - size; | |||
953 | ||||
954 | db_skip_to_eol(); | |||
955 | } |