diff options
author | Robert Mustacchi <rm@joyent.com> | 2013-06-29 00:24:10 +0000 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2013-07-09 20:47:14 +0000 |
commit | 4086e8503f4d11488be081f225425cb573afd15e (patch) | |
tree | 6f8602a65d19c7f6cd09b8e60a847a9ef24cd6ba | |
parent | 3811d9e101a450ba1ee0fb54bc73c428f8f0f766 (diff) | |
download | illumos-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.mdb | 1 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb_module.h | 5 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb_module_dump.c | 64 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb_module_load.c | 176 |
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) { |