1 /* $NetBSD: crash.c,v 1.1 2009/03/07 22:08:08 ad Exp $ */
4 * Copyright (c) 2009 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: crash.c,v 1.1 2009/03/07 22:08:08 ad Exp $");
39 #include <sys/fcntl.h>
41 #include <sys/ioctl.h>
43 #include <machine/frame.h>
58 #define MAXSTAB (16 * 1024 * 1024)
68 static struct nlist nl
[] = {
70 { .n_name
= "_osrelease" },
72 { .n_name
= "_panicstr" },
77 db_vprintf(const char *fmt
, va_list ap
)
82 c
= vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
83 for (b
= 0; b
< c
; b
++) {
89 db_printf(const char *fmt
, ...)
99 db_write_bytes(db_addr_t addr
, size_t size
, const char *str
)
102 if ((size_t)kvm_write(kd
, addr
, str
, size
) != size
) {
103 warnx("kvm_write(%p, %zd): %s", (void *)addr
, size
,
110 db_read_bytes(db_addr_t addr
, size_t size
, char *str
)
113 if ((size_t)kvm_read(kd
, addr
, str
, size
) != size
) {
114 warnx("kvm_read(%p, %zd): %s", (void *)addr
, size
,
131 return calloc(1, sz
);
135 db_free(void *p
, size_t sz
)
145 db_printf("This command can only be used in-kernel.\n");
149 db_breakpoint_cmd(db_expr_t addr
, bool have_addr
, db_expr_t count
,
157 db_continue_cmd(db_expr_t addr
, bool have_addr
, db_expr_t count
,
161 db_cmd_loop_done
= true;
165 db_delete_cmd(db_expr_t addr
, bool have_addr
, db_expr_t count
,
173 db_deletewatch_cmd(db_expr_t addr
, bool have_addr
, db_expr_t count
,
182 db_trace_until_matching_cmd(db_expr_t addr
, bool have_addr
, db_expr_t count
,
191 db_single_step_cmd(db_expr_t addr
, bool have_addr
, db_expr_t count
,
200 db_trace_until_call_cmd(db_expr_t addr
, bool have_addr
, db_expr_t count
,
209 db_watchpoint_cmd(db_expr_t addr
, bool have_addr
, db_expr_t count
,
217 db_readline(char *lstart
, int lsize
)
223 db_force_whitespace();
225 /* Close any open pipe. */
232 /* Read next command. */
233 el
= el_gets(elptr
, &cnt
);
239 /* Save to history, and copy to caller's buffer. */
240 history(hist
, &he
, H_ENTER
, el
);
241 strlcpy(lstart
, el
, lsize
);
246 if (cnt
> 0 && lstart
[cnt
- 1] == '\n') {
247 lstart
[cnt
- 1] = '\0';
250 /* Need to open a pipe? If not, return now. */
251 pcmd
= strchr(lstart
, '|');
253 return strlen(lstart
);
256 /* Open a pipe to specified command, redirect output. */
257 assert(ofp
== stdout
);
258 for (*pcmd
++ = '\0'; isspace((int)*pcmd
); pcmd
++) {
262 ofp
= popen(pcmd
, "w");
264 warn("opening pipe for command `%s'", pcmd
);
267 return strlen(lstart
);
271 db_check_interrupt(void)
280 fprintf(stderr
, "cngetc\n");
296 "usage: %s [options]\n\n"
297 "-M mem\tspecify memory file\n"
298 "-N nlist\tspecify name list file (default /dev/ksyms)\n",
311 main(int argc
, char **argv
)
313 const char *nlistf
, *memf
;
322 nlistf
= _PATH_KSYMS
;
329 while ((ch
= getopt(argc
, argv
, "M:N:")) != -1) {
345 * Print a list of images, and allow user to select.
350 * Open the images (crash dump and symbol table).
352 kd
= kvm_open(nlistf
, memf
, NULL
, O_RDONLY
, getprogname());
356 fd
= open(nlistf
, O_RDONLY
);
358 err(EXIT_FAILURE
, "open(%s)", nlistf
);
360 if (fstat(fd
, &sb
) < 0) {
361 err(EXIT_FAILURE
, "stat(%s)", nlistf
);
363 if ((sb
.st_mode
& S_IFMT
) != S_IFREG
) { /* XXX ksyms */
367 err(EXIT_FAILURE
, "malloc(%zd)", sz
);
369 sz
= read(fd
, elf
, sz
);
370 if ((ssize_t
)sz
< 0) {
371 err(EXIT_FAILURE
, "read(%s)", nlistf
);
374 errx(EXIT_FAILURE
, "symbol table > %d bytes",
379 elf
= mmap(NULL
, sz
, PROT_READ
, MAP_FILE
, fd
, 0);
380 if (elf
== MAP_FAILED
) {
381 err(EXIT_FAILURE
, "mmap(%s)", nlistf
);
386 * Print kernel & crash versions.
388 if (kvm_nlist(kd
, nl
) == -1) {
389 errx(EXIT_FAILURE
, "kvm_nlist: %s", kvm_geterr(kd
));
391 if ((size_t)kvm_read(kd
, nl
[X_OSRELEASE
].n_value
, imgrelease
,
392 sizeof(imgrelease
)) != sizeof(imgrelease
)) {
393 errx(EXIT_FAILURE
, "cannot read osrelease: %s",
396 printf("Crash version %s, image version %s.\n", osrelease
, imgrelease
);
397 if (strcmp(osrelease
, imgrelease
) != 0) {
398 printf("WARNING: versions differ, you may not be able to "
399 "examine this image.\n");
403 * Print the panic string, if any.
405 if ((size_t)kvm_read(kd
, nl
[X_PANICSTR
].n_value
, &panicstr
,
406 sizeof(panicstr
)) != sizeof(panicstr
)) {
407 errx(EXIT_FAILURE
, "cannot read panicstr: %s",
410 if (strcmp(memf
, _PATH_MEM
) == 0) {
411 printf("Output from a running system is unreliable.\n");
412 } else if (panicstr
== 0) {
413 printf("System does not appear to have panicked.\n");
415 printf("System panicked: ");
417 if ((size_t)kvm_read(kd
, panicstr
, &c
, sizeof(c
)) !=
419 errx(EXIT_FAILURE
, "cannot read *panicstr: %s",
432 * Initialize line editing.
434 hist
= history_init();
435 history(hist
, &he
, H_SETSIZE
, 100);
436 elptr
= el_init(getprogname(), stdin
, stdout
, stderr
);
437 el_set(elptr
, EL_EDITOR
, "emacs");
438 el_set(elptr
, EL_SIGNAL
, 1);
439 el_set(elptr
, EL_HIST
, history
, hist
);
440 el_set(elptr
, EL_PROMPT
, prompt
);
441 el_source(elptr
, NULL
);
446 if (ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &ws
) != -1) {
447 db_max_width
= ws
.ws_col
;
450 ddb_init(sz
, elf
, (char *)elf
+ sz
);