summaryrefslogtreecommitdiff
path: root/usr/src/lib/libkvm/common/kvm.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libkvm/common/kvm.c')
-rw-r--r--usr/src/lib/libkvm/common/kvm.c89
1 files changed, 85 insertions, 4 deletions
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)
{