summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@joyent.com>2013-06-29 00:24:10 +0000
committerRobert Mustacchi <rm@joyent.com>2013-07-09 20:47:14 +0000
commit4086e8503f4d11488be081f225425cb573afd15e (patch)
tree6f8602a65d19c7f6cd09b8e60a847a9ef24cd6ba
parent3811d9e101a450ba1ee0fb54bc73c428f8f0f766 (diff)
downloadillumos-joyent-4086e8503f4d11488be081f225425cb573afd15e.tar.gz
OS-2356 mdb should support embedded dmods in core dumps
Reviewed by: Dave Pacheco <dap@joyent.com>
-rw-r--r--usr/src/cmd/mdb/Makefile.mdb1
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_module.h5
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_module_dump.c64
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_module_load.c176
4 files changed, 234 insertions, 12 deletions
diff --git a/usr/src/cmd/mdb/Makefile.mdb b/usr/src/cmd/mdb/Makefile.mdb
index 9d1d7b4d6c..91c043c29c 100644
--- a/usr/src/cmd/mdb/Makefile.mdb
+++ b/usr/src/cmd/mdb/Makefile.mdb
@@ -67,6 +67,7 @@ SRCS += \
mdb_memio.c \
mdb_modapi.c \
mdb_module.c \
+ mdb_module_dump.c \
mdb_module_load.c \
mdb_nm.c \
mdb_nv.c \
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_module.h b/usr/src/cmd/mdb/common/mdb/mdb_module.h
index 04cb3d1cee..1624d44785 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_module.h
+++ b/usr/src/cmd/mdb/common/mdb/mdb_module.h
@@ -22,13 +22,11 @@
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright (c) 2012 by Delphix. All rights reserved.
- * Copyright (c) 2012 Joyent, Inc. All rights reserved.
*/
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
- * Copyright (c) 2012 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
*/
#ifndef _MDB_MODULE_H
@@ -112,6 +110,7 @@ extern int mdb_module_remove_walker(mdb_module_t *, const char *);
extern int mdb_module_create(const char *, const char *, int, mdb_module_t **);
extern int mdb_module_validate_name(const char *, const char **);
+extern int mdb_module_dumpfd(int, uintptr_t, uintptr_t);
#endif /* _MDB */
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_module_dump.c b/usr/src/cmd/mdb/common/mdb/mdb_module_dump.c
new file mode 100644
index 0000000000..6694c94b83
--- /dev/null
+++ b/usr/src/cmd/mdb/common/mdb/mdb_module_dump.c
@@ -0,0 +1,64 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Dump a region of memory from a target and dump it to a temporary file. This
+ * only makes sense for mdb, not for kmdb.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libproc.h>
+#include <sys/sysmacros.h>
+#include <errno.h>
+#include <strings.h>
+
+#include <mdb/mdb_module.h>
+#include <mdb/mdb.h>
+
+int
+mdb_module_dumpfd(int fd, uintptr_t tgtaddr, size_t tgtsize)
+{
+#ifdef _KMDB
+ return (-1);
+#endif
+ int toread, towrite, ret;
+ char buf[1024];
+
+ while (tgtsize > 0) {
+ toread = MIN(sizeof (buf), tgtsize);
+ towrite = mdb_vread(buf, toread, tgtaddr);
+ if (towrite < 0) {
+ mdb_printf("failed to read dmod from target");
+ return (-1);
+ }
+ tgtsize -= towrite;
+ tgtaddr += towrite;
+ do {
+ ret = write(fd, buf, towrite);
+ if (ret > 0)
+ towrite -= ret;
+ } while (ret < towrite && errno == EINTR);
+
+ if (ret < 0) {
+ mdb_printf("failed to write to temporary dmod "
+ "file: %s\n", strerror(errno));
+ return (-1);
+ }
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_module_load.c b/usr/src/cmd/mdb/common/mdb/mdb_module_load.c
index 811af3dd47..5eb4570f00 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_module_load.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_module_load.c
@@ -22,11 +22,12 @@
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
- * Copyright (c) 2012 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
*/
#include <sys/param.h>
#include <unistd.h>
+#include <stdlib.h>
#include <strings.h>
#include <dlfcn.h>
#include <ctype.h>
@@ -41,6 +42,149 @@
#include <mdb/mdb_frame.h>
#include <mdb/mdb.h>
+typedef struct mdb_modload_data {
+ int mld_first;
+ int mld_mode;
+} mdb_modload_data_t;
+
+#ifndef _KMDB
+static int
+mdb_module_load_targmod(const char *name, char *buf, size_t buflen,
+ uintptr_t targaddr, uintptr_t targsize)
+{
+ int fd, ret;
+ char *template = "/tmp/.mdb_mod_%s.pid%d.XXXXXX";
+
+ (void) mdb_iob_snprintf(buf, buflen, template, name, getpid());
+ fd = mkstemp(buf);
+ if (fd == -1) {
+ mdb_printf("failed to create temporary file "
+ "for dmod %s: %s\n", buf,
+ strerror(errno));
+ return (-1);
+ }
+ ret = mdb_module_dumpfd(fd, targaddr, targsize);
+ (void) close(fd);
+ if (ret != 0)
+ (void) unlink(buf);
+
+ return (ret);
+}
+
+static int
+mdb_module_load_fromtarg(const char *mname, char *pathbuf, size_t buflen)
+{
+ char buf[256], name[256];
+ char *p;
+ GElf_Sym sym;
+
+ if (mdb.m_target == NULL)
+ return (1);
+
+ /*
+ * See mdb_module_load() for details about the symbol names we test for
+ * here.
+ */
+ (void) strlcpy(name, mname, sizeof (name));
+ if ((p = strrchr(name, '.')) != NULL && *++p != '\0') {
+ if (strisnum(p) || strcmp(p, "so") == 0) {
+ (void) mdb_iob_snprintf(buf, sizeof (buf),
+ "mdb_%s_start", name);
+ if (mdb_lookup_by_name(buf, &sym) == 0)
+ goto found;
+ }
+
+ while (strisnum(p) && (p = strrchr(name, '.')) != NULL) {
+ *p = '\0'; /* strip trailing digits */
+ (void) mdb_iob_snprintf(buf, sizeof (buf),
+ "mdb_%s_start", name);
+ if (mdb_lookup_by_name(buf, &sym) == 0)
+ goto found;
+ }
+ }
+
+ (void) mdb_iob_snprintf(buf, sizeof (buf), "mdb_%s.so_start",
+ mname);
+ if (mdb_lookup_by_name(buf, &sym) == 0)
+ goto found;
+
+ return (1);
+
+found:
+ return (mdb_module_load_targmod(mname, pathbuf, buflen,
+ sym.st_value, sym.st_size));
+}
+
+typedef struct mdb_autoload_arg {
+ int ma_found;
+ mdb_modload_data_t *ma_mld;
+} mdb_autoload_arg_t;
+
+/*
+ * A valid key that we care about will look like: mdb_<module>_start. The module
+ * name will end up being everything inbetween.
+ */
+static int
+mdb_module_autoload_cb(mdb_symbol_t *sym, void *arg)
+{
+ static const char *lead = "mdb_", *end = "_start";
+ static int llen = 4, elen = 6;
+ char *errstr;
+ char buf[256], createbuf[256];
+ int len = strlen(sym->sym_name);
+ mdb_autoload_arg_t *map = arg;
+ int ret;
+
+ if (len < llen + elen + 1)
+ return (0);
+
+ if (strncmp(lead, sym->sym_name, strlen(lead)) != 0)
+ return (0);
+
+ if (strcmp(end, sym->sym_name + len - elen) != 0)
+ return (0);
+
+ (void) strlcpy(buf, sym->sym_name + llen, sizeof (buf));
+ buf[len - llen - elen] = '\0';
+
+ if (!mdb_module_validate_name(buf, (const char **)&errstr))
+ return (0);
+
+ ret = mdb_module_load_targmod(buf, createbuf, sizeof (createbuf),
+ sym->sym_sym->st_value, sym->sym_sym->st_size);
+ if (ret != 0) {
+ mdb_printf("failed to load module %s from target\n", buf);
+ return (0);
+ }
+ ret = mdb_module_create(buf, createbuf, map->ma_mld->mld_mode, NULL);
+ if (ret == 0) {
+ map->ma_found++;
+ if (mdb.m_term != NULL) {
+ if (map->ma_mld->mld_first == TRUE) {
+ mdb_iob_puts(mdb.m_out, "Loading modules: [");
+ map->ma_mld->mld_first = FALSE;
+ }
+ mdb_iob_printf(mdb.m_out, " %s", buf);
+ mdb_iob_flush(mdb.m_out);
+ }
+ }
+ (void) unlink(createbuf);
+
+ return (0);
+}
+
+static int
+mdb_module_autoload_targ(const char *mname, mdb_modload_data_t *mlp)
+{
+ mdb_autoload_arg_t ma;
+ ma.ma_found = 0;
+ ma.ma_mld = mlp;
+ mdb_symbol_iter(mname, MDB_SYMTAB,
+ MDB_BIND_ANY | MDB_TYPE_OBJECT, mdb_module_autoload_cb, &ma);
+ return (ma.ma_found);
+}
+#endif /* _KMDB */
+
int
mdb_module_load(const char *name, int mode)
{
@@ -92,9 +236,10 @@ mdb_module_load(const char *name, int mode)
}
/*
- * If a simple name is specified, search for it in the module path.
- * The module path is searched in order, and for each element we
- * look for the following files:
+ * If a simple name is specified, search of a symbol called
+ * mdb_<module>_start in the target itself. If that fails, search the
+ * module apth in order, and for each element look for the following
+ * files:
*
* 1. If the module name ends in ".so(.[0-9]+)?", search for the literal
* name and then search for the name without the [0-9]+ suffix.
@@ -104,6 +249,20 @@ mdb_module_load(const char *name, int mode)
* Once a matching file is detected, we attempt to load that module
* and do not resume our search in the case of an error.
*/
+
+#ifndef _KMDB
+ /* Search the target */
+ i = mdb_module_load_fromtarg(name, buf, sizeof (buf));
+ if (i == -1)
+ goto err;
+ if (i == 0) {
+ i = mdb_module_create(name, buf, mode, NULL);
+ (void) unlink(buf);
+ return (i);
+ }
+#endif /* _KMDB */
+
+ /* Start searching the module path */
for (i = 0; mdb.m_lpath[i] != NULL; i++) {
if ((p = strrchr(name, '.')) != NULL && *++p != '\0') {
if (strisnum(p) || strcmp(p, "so") == 0) {
@@ -143,17 +302,16 @@ err:
return (-1);
}
-typedef struct mdb_modload_data {
- int mld_first;
- int mld_mode;
-} mdb_modload_data_t;
-
/*ARGSUSED*/
static int
module_load(void *fp, const mdb_map_t *map, const char *fullname)
{
+ int ret = 0;
mdb_modload_data_t *mld = fp;
const char *name = strbasename(fullname);
+#ifndef _KMDB
+ (void) mdb_module_autoload_targ(name, mld);
+#endif /* ! _KMDB */
if (mdb_module_load(name, mld->mld_mode) == 0 && mdb.m_term != NULL) {
if (mld->mld_first == TRUE) {