diff options
author | Bryan Cantrill <bryan@joyent.com> | 2013-05-09 18:56:46 +0000 |
---|---|---|
committer | Bryan Cantrill <bryan@joyent.com> | 2013-05-09 18:56:46 +0000 |
commit | e083a554cd81f87a93a0b654bcbe3ffa29437ef2 (patch) | |
tree | ea4e01ab226b18c9c955f985fafdd639df591568 | |
parent | 43840e901cacf50a9bb41148069e34ca307524e8 (diff) | |
download | illumos-joyent-e083a554cd81f87a93a0b654bcbe3ffa29437ef2.tar.gz |
OS-2190 libkvm/mdb should be able to extract symbols from crash dump
Reviewed by: Keith Wesolowski <keith.wesolowski@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
-rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb_kb_kvm.c | 7 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb_kvm.c | 17 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb_main.c | 35 | ||||
-rw-r--r-- | usr/src/lib/libkvm/common/kvm.c | 89 | ||||
-rw-r--r-- | usr/src/lib/libkvm/common/mapfile-vers | 2 | ||||
-rw-r--r-- | usr/src/lib/libkvm/kvm.h | 7 |
6 files changed, 142 insertions, 15 deletions
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_kb_kvm.c b/usr/src/cmd/mdb/common/mdb/mdb_kb_kvm.c index d3cac91c5c..48b6e1ec93 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_kb_kvm.c +++ b/usr/src/cmd/mdb/common/mdb/mdb_kb_kvm.c @@ -23,7 +23,9 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ /* * The default KVM backend, which simply calls directly into libkvm for all @@ -39,9 +41,10 @@ /*ARGSUSED*/ static mdb_io_t * -libkvm_sym_io(void *kvm, const char *symfile) +libkvm_sym_io(void *kvm, const char *ignored) { mdb_io_t *io; + const char *symfile = kvm_namelist(kvm); if ((io = mdb_fdio_create_path(NULL, symfile, O_RDONLY, 0)) == NULL) mdb_warn("failed to open %s", symfile); diff --git a/usr/src/cmd/mdb/common/mdb/mdb_kvm.c b/usr/src/cmd/mdb/common/mdb/mdb_kvm.c index 4b368e357b..8e96c04350 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_kvm.c +++ b/usr/src/cmd/mdb/common/mdb/mdb_kvm.c @@ -23,6 +23,10 @@ */ /* + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ + +/* * Libkvm Kernel Target * * The libkvm kernel target provides access to both crash dumps and live @@ -1571,10 +1575,23 @@ err: } int +mdb_kvm_is_dump(mdb_io_t *io) +{ + dumphdr_t h; + + (void) IOP_SEEK(io, (off64_t)0L, SEEK_SET); + + return (IOP_READ(io, &h, sizeof (dumphdr_t)) == sizeof (dumphdr_t) && + h.dump_magic == DUMP_MAGIC); +} + +int mdb_kvm_is_compressed_dump(mdb_io_t *io) { dumphdr_t h; + (void) IOP_SEEK(io, (off64_t)0L, SEEK_SET); + return (IOP_READ(io, &h, sizeof (dumphdr_t)) == sizeof (dumphdr_t) && h.dump_magic == DUMP_MAGIC && (h.dump_flags & DF_COMPRESSED) != 0); diff --git a/usr/src/cmd/mdb/common/mdb/mdb_main.c b/usr/src/cmd/mdb/common/mdb/mdb_main.c index 4ca42e83cb..90e048bb82 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_main.c +++ b/usr/src/cmd/mdb/common/mdb/mdb_main.c @@ -24,6 +24,10 @@ * Copyright 2012, Josef 'Jeff' Sipek <jeffpc@31bits.net>. All rights reserved. */ +/* + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ + #include <sys/types.h> #include <sys/mman.h> #include <sys/priocntl.h> @@ -405,8 +409,9 @@ int main(int argc, char *argv[], char *envp[]) { extern int mdb_kvm_is_compressed_dump(mdb_io_t *); + extern int mdb_kvm_is_dump(mdb_io_t *); mdb_tgt_ctor_f *tgt_ctor = NULL; - const char **tgt_argv = alloca(argc * sizeof (char *)); + const char **tgt_argv = alloca((argc + 2) * sizeof (char *)); int tgt_argc = 0; mdb_tgt_t *tgt; @@ -834,8 +839,8 @@ main(int argc, char *argv[], char *envp[]) size_t len = strlen(tgt_argv[0]) + 8; const char *object = tgt_argv[0]; - tgt_argv[0] = mdb_alloc(len, UM_SLEEP); - tgt_argv[1] = mdb_alloc(len, UM_SLEEP); + tgt_argv[0] = alloca(len); + tgt_argv[1] = alloca(len); (void) strcpy((char *)tgt_argv[0], "unix."); (void) strcat((char *)tgt_argv[0], object); @@ -843,6 +848,14 @@ main(int argc, char *argv[], char *envp[]) (void) strcat((char *)tgt_argv[1], object); if (access(tgt_argv[0], F_OK) == -1 && + access(tgt_argv[1], F_OK) != -1) { + /* + * If we have a vmcore but not a unix file, + * set the symbol table to be the vmcore to + * force libkvm to extract it out of the dump. + */ + tgt_argv[0] = tgt_argv[1]; + } else if (access(tgt_argv[0], F_OK) == -1 && access(tgt_argv[1], F_OK) == -1) { (void) strcpy((char *)tgt_argv[1], "vmdump."); (void) strcat((char *)tgt_argv[1], object); @@ -866,17 +879,25 @@ main(int argc, char *argv[], char *envp[]) O_RDONLY, 0)) == NULL) die("failed to open %s", tgt_argv[0]); - /* - * Check for a single vmdump.N compressed dump file, - * and give a helpful message. - */ if (tgt_argc == 1) { if (mdb_kvm_is_compressed_dump(io)) { + /* + * We have a single vmdump.N compressed dump + * file; give a helpful message. + */ mdb_iob_printf(mdb.m_err, "cannot open compressed dump; " "decompress using savecore -f %s\n", tgt_argv[0]); terminate(0); + } else if (mdb_kvm_is_dump(io)) { + /* + * We have an uncompressed dump as our only + * argument; specify the dump as the symbol + * table to force libkvm to dig it out of the + * dump. + */ + tgt_argv[tgt_argc++] = tgt_argv[0]; } } diff --git a/usr/src/lib/libkvm/common/kvm.c b/usr/src/lib/libkvm/common/kvm.c index d3a5dbd81c..c71c4db31b 100644 --- a/usr/src/lib/libkvm/common/kvm.c +++ b/usr/src/lib/libkvm/common/kvm.c @@ -24,7 +24,9 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ #include <kvm.h> #include <stdio.h> @@ -34,6 +36,7 @@ #include <limits.h> #include <fcntl.h> #include <strings.h> +#include <errno.h> #include <sys/mem.h> #include <sys/stat.h> #include <sys/mman.h> @@ -55,12 +58,15 @@ struct _kvmd { proc_t *kvm_practive; pid_t kvm_pid; char kvm_namelist[MAXNAMELEN + 1]; + boolean_t kvm_namelist_core; proc_t kvm_proc; }; #define PREAD (ssize_t (*)(int, void *, size_t, offset_t))pread64 #define PWRITE (ssize_t (*)(int, void *, size_t, offset_t))pwrite64 +static int kvm_nlist_core(kvm_t *kd, struct nlist nl[], const char *err); + static kvm_t * fail(kvm_t *kd, const char *err, const char *message, ...) { @@ -164,9 +170,15 @@ kvm_open(const char *namelist, const char *corefile, const char *swapfile, (void) strncpy(kd->kvm_namelist, namelist, MAXNAMELEN); - if (kvm_nlist(kd, nl) == -1) - return (fail(kd, err, "%s is not a %d-bit kernel namelist", - namelist, DUMP_WORDSIZE)); + if (kvm_nlist(kd, nl) == -1) { + if (kd->kvm_corefd == -1) { + return (fail(kd, err, "%s is not a %d-bit " + "kernel namelist", namelist, DUMP_WORDSIZE)); + } + + if (kvm_nlist_core(kd, nl, err) == -1) + return (NULL); /* fail() already called */ + } kd->kvm_kas = (struct as *)nl[0].n_value; kd->kvm_practive = (proc_t *)nl[1].n_value; @@ -186,16 +198,85 @@ kvm_close(kvm_t *kd) (void) close(kd->kvm_kmemfd); if (kd->kvm_memfd != -1) (void) close(kd->kvm_memfd); + if (kd->kvm_namelist_core) + (void) unlink(kd->kvm_namelist); free(kd); return (0); } +const char * +kvm_namelist(kvm_t *kd) +{ + return (kd->kvm_namelist); +} + int kvm_nlist(kvm_t *kd, struct nlist nl[]) { return (nlist(kd->kvm_namelist, nl)); } +/* + * If we don't have a name list, try to dig it out of the kernel crash dump. + * (The symbols have been present in the dump, uncompressed, for nearly a + * decade as of this writing -- and it is frankly surprising that the archaic + * notion of a disjoint symbol table managed to survive that change.) + */ +static int +kvm_nlist_core(kvm_t *kd, struct nlist nl[], const char *err) +{ + dumphdr_t *dump = &kd->kvm_dump; + char *msg = "couldn't extract symbols from dump"; + char *template = "/tmp/.libkvm.kvm_nlist_core.pid%d.XXXXXX"; + int fd, rval; + + if (dump->dump_ksyms_size != dump->dump_ksyms_csize) { + (void) fail(kd, err, "%s: kernel symbols are compressed", msg); + return (-1); + } + + if (dump->dump_ksyms + dump->dump_ksyms_size > kd->kvm_coremapsize) { + (void) fail(kd, err, "%s: kernel symbols not mapped", msg); + return (-1); + } + + /* + * Beause this temporary file may be left as a turd if the caller + * does not properly call kvm_close(), we make sure that it clearly + * indicates its origins. + */ + (void) snprintf(kd->kvm_namelist, MAXNAMELEN, template, getpid()); + + if ((fd = mkstemp(kd->kvm_namelist)) == -1) { + (void) fail(kd, err, "%s: couldn't create temporary " + "symbols file: %s", msg, strerror(errno)); + return (-1); + } + + kd->kvm_namelist_core = B_TRUE; + + do { + rval = write(fd, (caddr_t)((uintptr_t)kd->kvm_core + + (uintptr_t)dump->dump_ksyms), dump->dump_ksyms_size); + } while (rval < dump->dump_ksyms_size && errno == EINTR); + + if (rval < dump->dump_ksyms_size) { + (void) fail(kd, err, "%s: couldn't write to temporary " + "symbols file: %s", msg, strerror(errno)); + (void) close(fd); + return (-1); + } + + (void) close(fd); + + if (kvm_nlist(kd, nl) == -1) { + (void) fail(kd, err, "%s: symbols not valid", msg); + return (-1); + } + + return (0); +} + static offset_t kvm_lookup(kvm_t *kd, struct as *as, uint64_t addr) { diff --git a/usr/src/lib/libkvm/common/mapfile-vers b/usr/src/lib/libkvm/common/mapfile-vers index 34ccee8093..091c1cbd08 100644 --- a/usr/src/lib/libkvm/common/mapfile-vers +++ b/usr/src/lib/libkvm/common/mapfile-vers @@ -20,6 +20,7 @@ # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, Joyent, Inc. All rights reserved. # # @@ -60,6 +61,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { global: kvm_aread; kvm_awrite; + kvm_namelist; kvm_physaddr; kvm_pread; kvm_pwrite; diff --git a/usr/src/lib/libkvm/kvm.h b/usr/src/lib/libkvm/kvm.h index ec2bd2a7c2..348b0c2e38 100644 --- a/usr/src/lib/libkvm/kvm.h +++ b/usr/src/lib/libkvm/kvm.h @@ -24,11 +24,13 @@ * All rights reserved. */ +/* + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ + #ifndef _KVM_H #define _KVM_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <nlist.h> #include <sys/user.h> @@ -67,6 +69,7 @@ extern proc_t *kvm_nextproc(kvm_t *); extern int kvm_setproc(kvm_t *); extern user_t *kvm_getu(kvm_t *, struct proc *); extern int kvm_getcmd(kvm_t *, proc_t *, user_t *, char ***, char ***); +extern const char *kvm_namelist(kvm_t *); #else |