diff options
Diffstat (limited to 'usr/src')
| -rw-r--r-- | usr/src/cmd/mdb/Makefile.common | 3 | ||||
| -rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb_module_load.c | 25 | ||||
| -rw-r--r-- | usr/src/cmd/mdb/common/modules/libpython2.6/libpython26.c | 461 | ||||
| -rw-r--r-- | usr/src/cmd/mdb/intel/amd64/libpython2.6/Makefile | 45 | ||||
| -rw-r--r-- | usr/src/cmd/mdb/intel/ia32/libpython2.6/Makefile | 44 | ||||
| -rw-r--r-- | usr/src/cmd/mdb/sparc/v7/libpython2.6/Makefile | 44 | ||||
| -rw-r--r-- | usr/src/cmd/mdb/sparc/v9/libpython2.6/Makefile | 45 | ||||
| -rw-r--r-- | usr/src/cmd/ptools/pstack/pstack.c | 120 | ||||
| -rw-r--r-- | usr/src/pkg/manifests/developer-debug-mdb.mf | 2 |
9 files changed, 773 insertions, 16 deletions
diff --git a/usr/src/cmd/mdb/Makefile.common b/usr/src/cmd/mdb/Makefile.common index 638bdcdb72..77411aa030 100644 --- a/usr/src/cmd/mdb/Makefile.common +++ b/usr/src/cmd/mdb/Makefile.common @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # MDB modules used for debugging user processes that every ISA's build @@ -32,6 +32,7 @@ COMMON_MODULES_PROC = \ libc \ libnvpair \ libproc \ + libpython2.6 \ libsysevent \ libtopo \ libumem \ 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 f8a3ffcd6b..83ba970eca 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_module_load.c +++ b/usr/src/cmd/mdb/common/mdb/mdb_module_load.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/param.h> #include <unistd.h> #include <strings.h> @@ -61,22 +58,22 @@ mdb_module_load(const char *name, int mode) /* * Remove any .so(.[0-9]+)? suffix */ - if ((p = strrchr(buf, '.')) != NULL) { + while ((p = strrchr(buf, '.')) != NULL) { for (q = p + 1; isdigit(*q); q++) ; if (*q == '\0') { /* found digits to remove */ *p = '\0'; - p = strrchr(buf, '.'); /* search for ".so" */ + continue; } - } - if (p != NULL) { - if (strcmp(p, ".so") == 0) + if (strcmp(p, ".so") == 0) { *p = '\0'; - } + break; + } + } fullname = name; name = buf; } @@ -97,7 +94,7 @@ mdb_module_load(const char *name, int mode) * The module path is searched in order, and for each element we * look for the following files: * - * 1. If the module name ends in ".so.[0-9]+", search for the literal + * 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. * 2. If the module name ends in ".so", search for the literal name. * 3. Search for the module name with ".so" appended. @@ -118,7 +115,7 @@ mdb_module_load(const char *name, int mode) } } - if (strisnum(p) && (p = strrchr(buf, '.')) != NULL) { + while (strisnum(p) && (p = strrchr(buf, '.')) != NULL) { *p = '\0'; /* strip trailing digits */ mdb_dprintf(MDB_DBG_MODULE, "checking for %s\n", buf); diff --git a/usr/src/cmd/mdb/common/modules/libpython2.6/libpython26.c b/usr/src/cmd/mdb/common/modules/libpython2.6/libpython26.c new file mode 100644 index 0000000000..9d4635326d --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/libpython2.6/libpython26.c @@ -0,0 +1,461 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <mdb/mdb_modapi.h> + +#include <pthread.h> +#include <stddef.h> +#include <dlfcn.h> +#include <link.h> +#include <libproc.h> + +#include <python2.6/Python.h> +#include <python2.6/frameobject.h> + +/* + * Decoding Python Stack Frames + * ============================ + * + * Python2.6 uses a variety of objects to construct its call chain. An address + * space may have one or more PyInterpreterState objects, which are the base + * object in the interpreter's state. These objects are kept in a linked list + * with a head pointer named interp_head. This makes it possible for the + * debugger to get a toehold on data structures necessary to understand the + * interpreter. Since most of these structures are linked out of the + * InterpreterState, traversals generally start here. + * + * In order to decode a frame, the debugger needs to walk from + * PyInterpreterState down to a PyCodeObject. The diagram below shows the + * the objects that must be examined in order to reach a leaf PyCodeObject. + * + * +--------------------+ next +--------------------+ next + * interp_head -> | PyInterpreterState | ----> | PyInterpreterState | ---> ... + * +--------------------+ +--------------------+ + * | | tstate_head + * | tstate_head V + * | +---------------+ frame + * V | PyThreadState | -----> ... + * +---------------+ frame +---------------+ + * | PyThreadState | ---> ... + * +---------------+ + * | next + * V + * +---------------+ frame +---------------+ f_back +---------------+ + * | PyThreadState | ------> | PyFrameObject | -----> | PyFrameObject | + * +---------------+ +---------------+ +---------------+ + * | | + * | f_code | f_code + * V V + * +--------------+ ... + * | PyCodeObject | + * +--------------+ + * co_filename | | | co_lnotab + * +-------------+ | +-------------+ + * | co_name | | + * V V V + * +----------------+ +----------------+ +----------------+ + * | PyStringObject | | PyStringObject | | PyStringObject | + * +----------------+ +----------------+ +----------------+ + * + * The interp_head pointer is a list of one or more PyInterpreterState + * objects. Each of these objects can contain one or more PyThreadState + * objects. The PyInterpreterState object keeps a pointer to the head of the + * list of PyThreadState objects as tstate_head. + * + * Each thread keeps ahold of its stack frames. The PyThreadState object + * has a pointer to the topmost PyFrameObject, kept in frame. The + * successive frames on the stack are kept linked in the PyFrameObject's + * f_back pointer, with each frame pointing to its caller. + * + * In order to decode each call frame, our code needs to look at the + * PyCodeObject for each frame. Essentially, this is the code that is + * being executed in the frame. The PyFrameObject keeps a pointer to this + * code object in f_code. In order to print meaningful debug information, + * it's necessary to extract the Python filename (co_filename), the + * function name (co_name), and the line number within the file + * (co_lnotab). The filename and function are stored as strings, but the + * line number is a mapping of bytecode offsets to line numbers. The + * description of the lnotab algorithm lives here: + * + * http://svn.python.org/projects/python/trunk/Objects/lnotab_notes.txt + * + * In order to decode the frame, the debugger needs to walk each + * InterpreterState object. For each InterpreterState, every PyThreadState + * must be traversed. The PyThreadState objects point to the + * PyFrameObjects. For every thread, we must walk the frames backwards and + * decode the strings that are in the PyCodeObjects. + */ + +/* + * The Python-dependent debugging functionality lives in its own helper + * library. The helper agent is provided by libpython2.6_db.so, which is also + * used by pstack(1) for debugging Python processes. + * + * Define needed prototypes here. + */ + +#define PYDB_VERSION 1 +typedef struct pydb_agent pydb_agent_t; +typedef struct pydb_iter pydb_iter_t; + +typedef pydb_agent_t *(*pydb_agent_create_f)(struct ps_prochandle *P, int vers); +typedef void (*pydb_agent_destroy_f)(pydb_agent_t *py); +typedef int (*pydb_get_frameinfo_f)(pydb_agent_t *py, uintptr_t frame_addr, + char *fbuf, size_t bufsz, int verbose); +typedef pydb_iter_t *(*pydb_iter_init_f)(pydb_agent_t *py, uintptr_t addr); +typedef uintptr_t (*pydb_iter_next_f)(pydb_iter_t *iter); +typedef void (*pydb_iter_fini_f)(pydb_iter_t *iter); + +static pydb_agent_create_f pydb_agent_create; +static pydb_agent_destroy_f pydb_agent_destroy; +static pydb_get_frameinfo_f pydb_get_frameinfo; +static pydb_iter_init_f pydb_frame_iter_init; +static pydb_iter_init_f pydb_interp_iter_init; +static pydb_iter_init_f pydb_thread_iter_init; +static pydb_iter_next_f pydb_iter_next; +static pydb_iter_fini_f pydb_iter_fini; + +static pydb_agent_t *pydb_hdl = NULL; +static void *pydb_dlhdl = NULL; + +/*ARGSUSED*/ +static int +py_frame(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + char buf[1024]; + int verbose = FALSE; + + if (mdb_getopts(argc, argv, + 'v', MDB_OPT_SETBITS, TRUE, &verbose, + NULL) != argc) { + return (DCMD_USAGE); + } + + if (flags & DCMD_PIPE_OUT) { + mdb_warn("py_stack cannot output into a pipe\n"); + return (DCMD_ERR); + } + + if (!(flags & DCMD_ADDRSPEC)) { + mdb_warn("no address"); + return (DCMD_USAGE); + } + + if (pydb_get_frameinfo(pydb_hdl, addr, buf, sizeof (buf), + verbose) < 0) { + mdb_warn("Unable to find frame at address %p\n", addr); + return (DCMD_ERR); + } + + mdb_printf("%s", buf); + + return (DCMD_OK); +} + +int +py_interp_walk_init(mdb_walk_state_t *wsp) +{ + pydb_iter_t *pdi; + + pdi = pydb_interp_iter_init(pydb_hdl, wsp->walk_addr); + + if (pdi == NULL) { + mdb_warn("unable to create interpreter iterator\n"); + return (DCMD_ERR); + } + + wsp->walk_data = pdi; + + return (WALK_NEXT); +} + +int +py_walk_step(mdb_walk_state_t *wsp) +{ + pydb_iter_t *pdi = wsp->walk_data; + uintptr_t addr; + int status; + + addr = pydb_iter_next(pdi); + + if (addr == NULL) { + return (WALK_DONE); + } + + status = wsp->walk_callback(addr, 0, wsp->walk_cbdata); + + return (status); +} + +void +py_walk_fini(mdb_walk_state_t *wsp) +{ + pydb_iter_t *pdi = wsp->walk_data; + pydb_iter_fini(pdi); +} + +int +py_thread_walk_init(mdb_walk_state_t *wsp) +{ + pydb_iter_t *pdi; + + pdi = pydb_thread_iter_init(pydb_hdl, wsp->walk_addr); + if (pdi == NULL) { + mdb_warn("unable to create thread iterator\n"); + return (DCMD_ERR); + } + + wsp->walk_data = pdi; + + return (WALK_NEXT); +} + +int +py_frame_walk_init(mdb_walk_state_t *wsp) +{ + pydb_iter_t *pdi; + + pdi = pydb_frame_iter_init(pydb_hdl, wsp->walk_addr); + if (pdi == NULL) { + mdb_warn("unable to create frame iterator\n"); + return (DCMD_ERR); + } + + wsp->walk_data = pdi; + + return (WALK_NEXT); +} + +/*ARGSUSED*/ +static int +python_stack(uintptr_t addr, const PyThreadState *ts, uint_t *verbose) +{ + mdb_arg_t nargv; + uint_t nargc = (verbose != NULL && *verbose) ? 1 : 0; + /* + * Pass the ThreadState to the frame walker. Have frame walker + * call frame dcmd. + */ + mdb_printf("PyThreadState: %0?p\n", addr); + + nargv.a_type = MDB_TYPE_STRING; + nargv.a_un.a_str = "-v"; + + if (mdb_pwalk_dcmd("pyframe", "pyframe", nargc, &nargv, addr) == -1) { + mdb_warn("can't walk 'pyframe'"); + return (WALK_ERR); + } + + return (WALK_NEXT); +} + +/*ARGSUSED*/ +static int +python_thread(uintptr_t addr, const PyInterpreterState *is, uint_t *verbose) +{ + /* + * Pass the InterpreterState to the threadstate walker. + */ + if (mdb_pwalk("pythread", (mdb_walk_cb_t)python_stack, verbose, + addr) == -1) { + mdb_warn("can't walk 'pythread'"); + return (WALK_ERR); + } + + return (WALK_NEXT); +} + +/*ARGSUSED*/ +static int +py_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + uint_t verbose = FALSE; + + if (mdb_getopts(argc, argv, + 'v', MDB_OPT_SETBITS, TRUE, &verbose, + NULL) != argc) + return (DCMD_USAGE); + + if (flags & DCMD_PIPE_OUT) { + mdb_warn("py_stack cannot output into a pipe\n"); + return (DCMD_ERR); + } + + if (flags & DCMD_ADDRSPEC) { + mdb_arg_t nargv; + uint_t nargc = verbose ? 1 : 0; + + nargv.a_type = MDB_TYPE_STRING; + nargv.a_un.a_str = "-v"; + + if (mdb_pwalk_dcmd("pyframe", "pyframe", nargc, &nargv, addr) + == -1) { + mdb_warn("can't walk 'pyframe'"); + return (DCMD_ERR); + } + return (DCMD_OK); + } + + if (mdb_walk("pyinterp", (mdb_walk_cb_t)python_thread, + &verbose) == -1) { + mdb_warn("can't walk 'pyinterp'"); + return (DCMD_ERR); + } + + return (DCMD_OK); +} + +static const mdb_dcmd_t dcmds[] = { + { "pystack", "[-v]", "print python stacks", py_stack }, + { "pyframe", "[-v]", "print python frames", py_frame }, + { NULL } +}; + +static const mdb_walker_t walkers[] = { + { "pyinterp", "walk python interpreter structures", + py_interp_walk_init, py_walk_step, py_walk_fini }, + { "pythread", "given an interpreter, walk the list of python threads", + py_thread_walk_init, py_walk_step, py_walk_fini }, + { "pyframe", "given a thread state, walk the list of frame objects", + py_frame_walk_init, py_walk_step, py_walk_fini }, + { NULL } +}; + +static const mdb_modinfo_t modinfo = { + MDB_API_VERSION, dcmds, walkers +}; + +/*ARGSUSED*/ +static int +python_object_iter(void *cd, const prmap_t *pmp, const char *obj) +{ + char path[PATH_MAX]; + char *name; + char *s1, *s2; + struct ps_prochandle *Pr = cd; + + name = strstr(obj, "/libpython"); + + if (name) { + (void) strcpy(path, obj); + if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) { + s1 = name; + s2 = path + (s1 - obj); + (void) strcpy(s2, "/64"); + s2 += 3; + (void) strcpy(s2, s1); + } + + s1 = strstr(obj, ".so"); + s2 = strstr(path, ".so"); + (void) strcpy(s2, "_db"); + s2 += 3; + (void) strcpy(s2, s1); + + if ((pydb_dlhdl = dlopen(path, RTLD_LAZY|RTLD_GLOBAL)) != NULL) + return (1); + } + + return (0); +} + +static int +python_db_init(void) +{ + struct ps_prochandle *Ph; + + if (mdb_get_xdata("pshandle", &Ph, sizeof (Ph)) == -1) { + mdb_warn("couldn't read pshandle xdata\n"); + dlclose(pydb_dlhdl); + pydb_dlhdl = NULL; + return (-1); + } + + (void) Pobject_iter(Ph, python_object_iter, Ph); + + pydb_agent_create = (pydb_agent_create_f) + dlsym(pydb_dlhdl, "pydb_agent_create"); + pydb_agent_destroy = (pydb_agent_destroy_f) + dlsym(pydb_dlhdl, "pydb_agent_destroy"); + pydb_get_frameinfo = (pydb_get_frameinfo_f) + dlsym(pydb_dlhdl, "pydb_get_frameinfo"); + + pydb_frame_iter_init = (pydb_iter_init_f) + dlsym(pydb_dlhdl, "pydb_frame_iter_init"); + pydb_interp_iter_init = (pydb_iter_init_f) + dlsym(pydb_dlhdl, "pydb_interp_iter_init"); + pydb_thread_iter_init = (pydb_iter_init_f) + dlsym(pydb_dlhdl, "pydb_thread_iter_init"); + pydb_iter_next = (pydb_iter_next_f)dlsym(pydb_dlhdl, "pydb_iter_next"); + pydb_iter_fini = (pydb_iter_fini_f)dlsym(pydb_dlhdl, "pydb_iter_fini"); + + + if (pydb_agent_create == NULL || pydb_agent_destroy == NULL || + pydb_get_frameinfo == NULL || pydb_frame_iter_init == NULL || + pydb_interp_iter_init == NULL || pydb_thread_iter_init == NULL || + pydb_iter_next == NULL || pydb_iter_fini == NULL) { + mdb_warn("couldn't load pydb functions"); + dlclose(pydb_dlhdl); + pydb_dlhdl = NULL; + return (-1); + } + + pydb_hdl = pydb_agent_create(Ph, PYDB_VERSION); + if (pydb_hdl == NULL) { + mdb_warn("unable to create pydb_agent"); + dlclose(pydb_dlhdl); + pydb_dlhdl = NULL; + return (-1); + } + + return (0); +} + +static void +python_db_fini(void) +{ + if (pydb_dlhdl) { + pydb_agent_destroy(pydb_hdl); + pydb_hdl = NULL; + + dlclose(pydb_dlhdl); + pydb_dlhdl = NULL; + } +} + +const mdb_modinfo_t * +_mdb_init(void) +{ + if (python_db_init() != 0) + return (NULL); + + return (&modinfo); +} + +void +_mdb_fini(void) +{ + python_db_fini(); +} diff --git a/usr/src/cmd/mdb/intel/amd64/libpython2.6/Makefile b/usr/src/cmd/mdb/intel/amd64/libpython2.6/Makefile new file mode 100644 index 0000000000..7f2e268e42 --- /dev/null +++ b/usr/src/cmd/mdb/intel/amd64/libpython2.6/Makefile @@ -0,0 +1,45 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +MODULE = libpython2.6.so +MDBTGT = proc + +MODSRCS_DIR = ../../../common/modules/libpython2.6 + +MODSRCS = libpython26.c + +include ../../../../Makefile.cmd +include ../../../../Makefile.cmd.64 +include ../../Makefile.amd64 +include ../../../Makefile.module + +dmod/$(MODULE) := LDLIBS += -lproc + +%.o: $(MODSRCS_DIR)/%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +%.ln: $(MODSRCS_DIR)/%.c + $(LINT.c) -c $< diff --git a/usr/src/cmd/mdb/intel/ia32/libpython2.6/Makefile b/usr/src/cmd/mdb/intel/ia32/libpython2.6/Makefile new file mode 100644 index 0000000000..53703a48cc --- /dev/null +++ b/usr/src/cmd/mdb/intel/ia32/libpython2.6/Makefile @@ -0,0 +1,44 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +MODULE = libpython2.6.so +MDBTGT = proc + +MODSRCS_DIR = ../../../common/modules/libpython2.6 + +MODSRCS = libpython26.c + +include ../../../../Makefile.cmd +include ../../Makefile.ia32 +include ../../../Makefile.module + +dmod/$(MODULE) := LDLIBS += -lproc + +%.o: $(MODSRCS_DIR)/%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +%.ln: $(MODSRCS_DIR)/%.c + $(LINT.c) -c $< diff --git a/usr/src/cmd/mdb/sparc/v7/libpython2.6/Makefile b/usr/src/cmd/mdb/sparc/v7/libpython2.6/Makefile new file mode 100644 index 0000000000..67fa9e938f --- /dev/null +++ b/usr/src/cmd/mdb/sparc/v7/libpython2.6/Makefile @@ -0,0 +1,44 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +MODULE = libpython2.6.so +MDBTGT = proc + +MODSRCS_DIR = ../../../common/modules/libpython2.6 + +MODSRCS = libpython26.c + +include ../../../../Makefile.cmd +include ../../Makefile.sparcv7 +include ../../../Makefile.module + +dmod/$(MODULE) := LDLIBS += -lproc + +%.o: $(MODSRCS_DIR)/%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +%.ln: $(MODSRCS_DIR)/%.c + $(LINT.c) -c $< diff --git a/usr/src/cmd/mdb/sparc/v9/libpython2.6/Makefile b/usr/src/cmd/mdb/sparc/v9/libpython2.6/Makefile new file mode 100644 index 0000000000..abccb3974c --- /dev/null +++ b/usr/src/cmd/mdb/sparc/v9/libpython2.6/Makefile @@ -0,0 +1,45 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +MODULE = libpython2.6.so +MDBTGT = proc + +MODSRCS_DIR = ../../../common/modules/libpython2.6 + +MODSRCS = libpython26.c + +include ../../../../Makefile.cmd +include ../../../../Makefile.cmd.64 +include ../../Makefile.sparcv9 +include ../../../Makefile.module + +dmod/$(MODULE) := LDLIBS += -lproc + +%.o: $(MODSRCS_DIR)/%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +%.ln: $(MODSRCS_DIR)/%.c + $(LINT.c) -c $< diff --git a/usr/src/cmd/ptools/pstack/pstack.c b/usr/src/cmd/ptools/pstack/pstack.c index 6d9ad10fa7..0515ff62d0 100644 --- a/usr/src/cmd/ptools/pstack/pstack.c +++ b/usr/src/cmd/ptools/pstack/pstack.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -101,6 +101,26 @@ static jvm_agent_t *load_libjvm(struct ps_prochandle *P); static void reset_libjvm(jvm_agent_t *); /* + * Similar to what's done for debugging java programs, here are prototypes for + * the library that allows us to debug Python programs. + */ +#define PYDB_VERSION 1 +static void *libpython; + +typedef struct pydb_agent pydb_agent_t; + +typedef pydb_agent_t *(*pydb_agent_create_f)(struct ps_prochandle *P, int vers); +typedef void (*pydb_agent_destroy_f)(pydb_agent_t *py); +typedef int (*pydb_pc_frameinfo_f)(pydb_agent_t *py, uintptr_t pc, + uintptr_t frame_addr, char *fbuf, size_t bufsz); + +static pydb_agent_create_f pydb_agent_create; +static pydb_agent_destroy_f pydb_agent_destroy; +static pydb_pc_frameinfo_f pydb_pc_frameinfo; + +static pydb_agent_t *load_libpython(struct ps_prochandle *P); +static void reset_libpython(pydb_agent_t *); +/* * Since we must maintain both a proc handle and a jvm handle, this structure * is the basic type that gets passed around. */ @@ -110,6 +130,7 @@ typedef struct pstack_handle { int ignore_frame; const char *lwps; int count; + pydb_agent_t *pydb; } pstack_handle_t; static int thr_stack(const td_thrhandle_t *, void *); @@ -261,6 +282,7 @@ main(int argc, char **argv) handle.proc = Pr; handle.jvm = load_libjvm(Pr); + handle.pydb = load_libpython(Pr); handle.lwps = lwps; handle.count = 0; @@ -270,6 +292,7 @@ main(int argc, char **argv) free_threadinfo(); reset_libjvm(handle.jvm); + reset_libpython(handle.pydb); Prelease(Pr, 0); if (handle.count == 0) @@ -559,6 +582,17 @@ print_frame(void *cd, prgregset_t gregs, uint_t argc, const long *argv) (void) printf("..."); (void) printf((start != pc) ? ") + %lx\n" : ")\n", (long)(pc - start)); + if (h->pydb != NULL && argc > 0) { + char buf_py[1024]; + int rc; + + rc = pydb_pc_frameinfo(h->pydb, pc, argv[0], buf_py, + sizeof (buf_py)); + if (rc == 0) { + (void) printf(" %s", buf_py); + } + } + /* * If the frame's pc is in the "sigh" (a.k.a. signal handler, signal * hack, or *sigh* ...) range, then we're about to cross a signal @@ -727,3 +761,87 @@ reset_libjvm(jvm_agent_t *agent) j_frame_iter = NULL; libjvm = NULL; } + +/*ARGSUSED*/ +static int +python_object_iter(void *cd, const prmap_t *pmp, const char *obj) +{ + char path[PATH_MAX]; + char *name; + char *s1, *s2; + struct ps_prochandle *Pr = cd; + + name = strstr(obj, "/libpython"); + + if (name) { + (void) strcpy(path, obj); + if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) { + s1 = name; + s2 = path + (s1 - obj); + (void) strcpy(s2, "/64"); + s2 += 3; + (void) strcpy(s2, s1); + } + + s1 = strstr(obj, ".so"); + s2 = strstr(path, ".so"); + (void) strcpy(s2, "_db"); + s2 += 3; + (void) strcpy(s2, s1); + + if ((libpython = dlopen(path, RTLD_LAZY|RTLD_GLOBAL)) != NULL) + return (1); + } + + return (0); +} + +static pydb_agent_t * +load_libpython(struct ps_prochandle *Pr) +{ + pydb_agent_t *pdb; + + (void) Pobject_iter(Pr, python_object_iter, Pr); + + if (libpython) { + pydb_agent_create = (pydb_agent_create_f) + dlsym(libpython, "pydb_agent_create"); + pydb_agent_destroy = (pydb_agent_destroy_f) + dlsym(libpython, "pydb_agent_destroy"); + pydb_pc_frameinfo = (pydb_pc_frameinfo_f) + dlsym(libpython, "pydb_pc_frameinfo"); + + if (pydb_agent_create == NULL || pydb_agent_destroy == NULL || + pydb_pc_frameinfo == NULL) { + (void) dlclose(libpython); + libpython = NULL; + return (NULL); + } + + pdb = pydb_agent_create(Pr, PYDB_VERSION); + if (pdb == NULL) { + (void) dlclose(libpython); + libpython = NULL; + return (NULL); + } + return (pdb); + } + + return (NULL); +} + +static void +reset_libpython(pydb_agent_t *pdb) +{ + if (libpython != NULL) { + if (pdb != NULL) { + pydb_agent_destroy(pdb); + } + (void) dlclose(libpython); + } + + libpython = NULL; + pydb_agent_create = NULL; + pydb_agent_destroy = NULL; + pydb_pc_frameinfo = NULL; +} diff --git a/usr/src/pkg/manifests/developer-debug-mdb.mf b/usr/src/pkg/manifests/developer-debug-mdb.mf index 016696caed..e03a1bf80a 100644 --- a/usr/src/pkg/manifests/developer-debug-mdb.mf +++ b/usr/src/pkg/manifests/developer-debug-mdb.mf @@ -393,6 +393,7 @@ file path=usr/lib/mdb/proc/$(ARCH64)/libavl.so group=sys mode=0555 file path=usr/lib/mdb/proc/$(ARCH64)/libc.so group=sys mode=0555 file path=usr/lib/mdb/proc/$(ARCH64)/libnvpair.so group=sys mode=0555 file path=usr/lib/mdb/proc/$(ARCH64)/libproc.so group=sys mode=0555 +file path=usr/lib/mdb/proc/$(ARCH64)/libpython2.6.so group=sys mode=0555 file path=usr/lib/mdb/proc/$(ARCH64)/libsysevent.so group=sys mode=0555 file path=usr/lib/mdb/proc/$(ARCH64)/libtopo.so group=sys mode=0555 file path=usr/lib/mdb/proc/$(ARCH64)/libumem.so group=sys mode=0555 @@ -404,6 +405,7 @@ file path=usr/lib/mdb/proc/libavl.so group=sys mode=0555 file path=usr/lib/mdb/proc/libc.so group=sys mode=0555 file path=usr/lib/mdb/proc/libnvpair.so group=sys mode=0555 file path=usr/lib/mdb/proc/libproc.so group=sys mode=0555 +file path=usr/lib/mdb/proc/libpython2.6.so group=sys mode=0555 file path=usr/lib/mdb/proc/libsysevent.so group=sys mode=0555 file path=usr/lib/mdb/proc/libtopo.so group=sys mode=0555 file path=usr/lib/mdb/proc/libumem.so group=sys mode=0555 |
