7155369 mdb should work with python 2.7 bits
authorRich Burridge <rich.burridge@oracle.com>
Thu, 28 Jun 2012 12:59:05 -0700
changeset 896 50be262e44f7
parent 895 179839d37cb0
child 897 f239fb8865f3
7155369 mdb should work with python 2.7 bits
components/python/python27/Makefile
components/python/python27/patches/14-py_db.patch
components/python/python27/python-27-tests.p5m
components/python/python27/python-27.p5m
--- a/components/python/python27/Makefile	Thu Jun 28 03:21:11 2012 -0400
+++ b/components/python/python27/Makefile	Thu Jun 28 12:59:05 2012 -0700
@@ -43,8 +43,17 @@
 COMPONENT_PREP_ACTION = \
 	(cd $(@D) ; autoheader ; autoconf)
 
+# we don't want to leak $(CC_BITS) into BASECFLAGS as it causes problems with
+# python-config
+CC +=	$(CFLAGS)
+
+C99MODE=
+CPPFLAGS +=	-IPython
+
 # to find the ncurses headers
 CPPFLAGS +=	-I/usr/include/ncurses
+# enable large files how they did in JDS
+CPPFLAGS +=	-D_LARGEFILE64_SOURCE
 
 # libffi for _ctypes
 CPPFLAGS +=	$(shell pkg-config --cflags-only-I libffi)
@@ -89,8 +98,8 @@
 CONFIGURE_OPTIONS  +=		ac_cv_opt_olimit_ok=no
 CONFIGURE_OPTIONS  +=		ac_cv_olimit_ok=no
 CONFIGURE_OPTIONS  +=		CPPFLAGS="$(CPPFLAGS)"
-CONFIGURE_OPTIONS  +=		BASECFLAGS="$(CFLAGS)"
 CONFIGURE_OPTIONS  +=		LDFLAGS="$(LDFLAGS)"
+CONFIGURE_OPTIONS  +=		CFLAGS="$(CFLAGS)"
 CONFIGURE_OPTIONS  +=		DFLAGS="-$(BITS)"
 CONFIGURE_OPTIONS  +=		XPROFILE_DIR="$(XPROFILE_DIR)"
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/python/python27/patches/14-py_db.patch	Thu Jun 28 12:59:05 2012 -0700
@@ -0,0 +1,1041 @@
+diff --git Python-2.7.1/Makefile.pre.in.orig Python-2.7.1/Makefile.pre.in
+--- Python-2.7.1/Makefile.pre.in.orig   Sun Feb 13 19:37:16 2011
++++ Python-2.7.1/Makefile.pre.in        Sun Feb 13 20:55:04 2011
[email protected]@ -364,7 +364,7 @@
+ 
+ # Default target
+ all:		build_all
+-build_all:	$(BUILDPYTHON) oldsharedmods sharedmods gdbhooks
++build_all:	$(BUILDPYTHON) oldsharedmods sharedmods gdbhooks build-py_db
+ 
+ # Compile a binary with gcc profile guided optimization.
+ profile-opt:
[email protected]@ -709,6 +709,19 @@
+ 
+ $(LIBRARY_OBJS) $(MODOBJS) Modules/python.o: $(PYTHON_HEADERS)
+ 
++SHLIB_FLAGS = -shared -fpic
++
++libpython2.7_db.so.1.0:        $(srcdir)/py_db/libpython27_db.c
++	$(CC) -o [email protected] $(CFLAGS) $(CPPFLAGS) $(SHLIB_FLAGS) $<
++
++check_offset:  $(srcdir)/py_db/check_offsets.c
++	$(CC) -o [email protected] $(CFLAGS) $(CPPFLAGS) $<
++
++build-py_db:   libpython2.7_db.so.1.0 check_offset
++
++install-py_db: libpython2.7_db.so.1.0 check_offset
++	$(INSTALL_SHARED) libpython2.7_db.so.1.0 $(DESTDIR)$(LIBDIR)
++	$(INSTALL_PROGRAM) check_offset $(DESTDIR)$(BINDIR)
+ 
+ ######################################################################
+ 
[email protected]@ -773,7 +786,7 @@
+ 		$(TESTPYTHON) $(TESTPROG) $(MEMTESTOPTS)
+ 
+ # Install everything
+-install:	@[email protected] altinstall bininstall maninstall @[email protected]
++install:	@[email protected] altinstall bininstall maninstall @[email protected] install-py_db
+ 
+ # Install almost everything without disturbing previous versions
+ altinstall:	@[email protected] altbininstall libinstall inclinstall libainstall \
+
+diff --git Python-2.7.1/py_db/check_offsets.c Python-2.7.1/py_db/check_offsets.c
+new file mode 100644
+--- /dev/null
++++ Python-2.7.1/py_db/check_offsets.c
[email protected]@ -0,0 +1,87 @@
++/*
++ * 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 (c) 2012, Oracle and/or its affiliates. All rights reserved.
++ */
++
++#include <stdio.h>
++
++#include <Python.h>
++#include <frameobject.h>
++
++#include "libpython27_db_32.h"
++
++#if 0
++#define	offsetof(s, m)	((size_t)(&(((s *)0)->m)))
++#endif
++
++int
++main(void)
++{
++/*
++ * PyCodeObject co_name
++ * PyCodeObject co_filename
++ * PyCodeObject co_lnotab
++ * PyFrameObject f_back
++ * PyFrameObject f_code
++ * PyFrameObject f_lasti
++ * PyInterpreterState next
++ * PyInterpreterState tstate_head
++ * PyStringObject ob_sval
++ * PyStringObject ob_size
++ * PyThreadState frame
++ * PyThreadState next
++ */
++
++	printf("struct member: native 32\n");
++	printf("PyCodeObject co_name: %d %d\n", offsetof(PyCodeObject, co_name),
++	    offsetof(PyCodeObject32, co_name));
++	printf("PyCodeObject co_filename: %d %d\n", offsetof(PyCodeObject,
++	    co_filename), offsetof(PyCodeObject32, co_filename));
++	printf("PyCodeObject co_lnotab: %d %d\n", offsetof(PyCodeObject,
++	    co_lnotab), offsetof(PyCodeObject32, co_lnotab));
++	printf("PyFrameObject f_back: %d %d\n", offsetof(PyFrameObject, f_back),
++	    offsetof(PyFrameObject32, f_back));
++	printf("PyFrameObject f_code: %d %d\n", offsetof(PyFrameObject, f_code),
++	    offsetof(PyFrameObject32, f_code));
++	printf("PyFrameObject f_lasti: %d %d\n", offsetof(PyFrameObject,
++	    f_lasti), offsetof(PyFrameObject32, f_lasti));
++	printf("PyInterpreterState next: %d %d\n", offsetof(PyInterpreterState,
++	    next), offsetof(PyInterpreterState32, next));
++	printf("PyInterpreterState tstate_head: %d %d\n",
++	    offsetof(PyInterpreterState, tstate_head),
++	    offsetof(PyInterpreterState32, tstate_head));
++	printf("PyStringObject ob_sval: %d %d\n", offsetof(PyStringObject,
++	    ob_sval), offsetof(PyStringObject32, ob_sval));
++	printf("PyStringObject ob_size: %d %d\n", offsetof(PyStringObject,
++	    ob_size), offsetof(PyStringObject32, ob_size));
++	printf("PyThreadState frame: %d %d\n", offsetof(PyThreadState, frame),
++	    offsetof(PyThreadState32, frame));
++	printf("PyThreadState next: %d %d\n", offsetof(PyThreadState, next),
++	    offsetof(PyThreadState32, next));
++
++	printf("\nObject sizes\n");
++	printf("PyObject: %d %d\n", sizeof (PyObject), sizeof (PyObject32));
++	printf("PyVarObject: %d %d\n", sizeof (PyVarObject),
++	    sizeof (PyVarObject32));
++
++	return (0);
++}
+diff --git Python-2.7.1/py_db/libpython27_db.c Python-2.7.1/py_db/libpython27_db.c
+new file mode 100644
+--- /dev/null
++++ Python-2.7.1/py_db/libpython27_db.c
[email protected]@ -0,0 +1,654 @@
++/*
++ * 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 (c) 2012, Oracle and/or its affiliates. All rights reserved.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <gelf.h>
++
++#include <Python.h>
++#include <frameobject.h>
++
++#include "libpython27_db.h"
++#if defined(_LP64)
++#include "libpython27_db_32.h"
++#endif /* _LP64 */
++
++/*
++ * Because MDB always runs the debugger in the same datamodel as the target,
++ * only functions that are used by the procfs part of this interface (or shared
++ * between the two) are written as 64->32 aware.
++ */
++typedef struct pydb_arch_ops {
++	ssize_t	(*strobj_readdata)(pydb_agent_t *, uintptr_t, unsigned char *,
++	    size_t);
++	int	(*frameinfo)(pydb_agent_t *, uintptr_t, char *,
++	    size_t, char *, size_t, int *);
++} pydb_arch_ops_t;
++
++struct pydb_agent {
++	struct ps_prochandle *pdb_ph;
++	int pdb_vers;
++	int pdb_is_64bit;
++	int pdb_datamodel;
++	const pydb_arch_ops_t *pdb_ops;
++};
++
++typedef uintptr_t (*pdi_next_cb_t)(pydb_iter_t *);
++
++struct pydb_iter {
++	struct ps_prochandle *pdi_ph;
++	uintptr_t pdi_current;
++	pdi_next_cb_t pdi_nextf;
++};
++
++#define	LIBPYTHON	"libpython2.7.so"
++
++#define	MIN(x, y)	(((x) < (y)) ? (x) : (y))
++
++/* Generic interface to helper functions */
++static ssize_t pydb_strobj_readdata(pydb_agent_t *py, uintptr_t addr,
++    unsigned char *buf, size_t buf_len);
++static int pydb_getlno(pydb_agent_t *py, uintptr_t lnotab_addr, int firstline,
++    int lastinst);
++static int pydb_frameinfo(pydb_agent_t *py, uintptr_t addr, char *funcnm,
++    size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno);
++
++/* datamodel specific implementation of helper functions */
++static ssize_t pydb_strobj_readdata_native(pydb_agent_t *py, uintptr_t addr,
++    unsigned char *buf, size_t buf_len);
++static int pydb_frameinfo_native(pydb_agent_t *py, uintptr_t addr, char *funcnm,
++    size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno);
++
++#if defined (_LP64)
++static ssize_t pydb_strobj_readdata_32(pydb_agent_t *py, uintptr_t addr,
++    unsigned char *buf, size_t buf_len);
++static int pydb_frameinfo_32(pydb_agent_t *py, uintptr_t addr, char *funcnm,
++    size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno);
++#endif /* _LP64 */
++
++static ssize_t pydb_strobj_readstr(pydb_agent_t *py, uintptr_t addr, char *buf,
++    size_t len);
++
++/* Iterator function next routines.  Plugable, configured by iterator init */
++static uintptr_t pydb_frame_iter_next(pydb_iter_t *iter);
++static uintptr_t pydb_interp_iter_next(pydb_iter_t *iter);
++static uintptr_t pydb_thread_iter_next(pydb_iter_t *iter);
++
++static const char *strbasename(const char *s);
++
++static const pydb_arch_ops_t arch_ops_native = {
++	.frameinfo = pydb_frameinfo_native,
++	.strobj_readdata = pydb_strobj_readdata_native,
++};
++
++#if defined (_LP64)
++static const pydb_arch_ops_t arch_ops_32 = {
++	.frameinfo = pydb_frameinfo_32,
++	.strobj_readdata = pydb_strobj_readdata_32,
++};
++#endif /* _LP64 */
++
++static const char *
++strbasename(const char *s)
++{
++	const char *p = strrchr(s, '/');
++
++	if (p == NULL)
++		return (s);
++
++	return (++p);
++}
++
++/* Agent creation / destruction routines */
++
++pydb_agent_t *
++pydb_agent_create(struct ps_prochandle *P, int vers)
++{
++	pydb_agent_t *py;
++	int datamodel;
++
++	if (vers != PYDB_VERSION) {
++		errno = ENOTSUP;
++		return (NULL);
++	}
++
++	if (ps_pdmodel(P, &datamodel) != PS_OK) {
++		return (NULL);
++	}
++
++	py = (pydb_agent_t *)malloc(sizeof (pydb_agent_t));
++	if (py == NULL) {
++		return (NULL);
++	}
++
++	py->pdb_ph = P;
++	py->pdb_vers = vers;
++	py->pdb_datamodel = datamodel;
++	py->pdb_is_64bit = 0;
++	py->pdb_ops = &arch_ops_native;
++
++#if defined (_LP64)
++	py->pdb_is_64bit = (datamodel == PR_MODEL_LP64);
++	if (!py->pdb_is_64bit) {
++		py->pdb_ops = &arch_ops_32;
++	}
++#endif /* _LP64 */
++
++	return (py);
++}
++
++void
++pydb_agent_destroy(pydb_agent_t *py)
++{
++	if (py == NULL) {
++		return;
++	}
++
++	free(py);
++}
++
++/* Helper functions */
++static int
++pydb_getlno(pydb_agent_t *py, uintptr_t lnotab_addr, int firstline,
++    int lastinst)
++{
++	unsigned char lnotab[4096];
++	ssize_t lnotab_len;
++	int addr, line;
++	int i;
++
++	lnotab_len = pydb_strobj_readdata(py, lnotab_addr, lnotab,
++	    sizeof (lnotab));
++	if (lnotab_len < 0) {
++		return (-1);
++	}
++
++	/*
++	 * Python's line number algorithm is arcane. See here for details:
++	 * http://svn.python.org/projects/python/trunk/Objects/lnotab_notes.txt
++	 */
++
++	line = firstline;
++	for (addr = i = 0; i < lnotab_len; i += 2) {
++		if (addr + lnotab[i] > lastinst) {
++			break;
++		}
++		addr += lnotab[i];
++		line += lnotab[i + 1];
++	}
++
++	return (line);
++}
++
++static ssize_t
++pydb_strobj_readdata(pydb_agent_t *py, uintptr_t addr, unsigned char *buf,
++    size_t buf_len)
++{
++	return (py->pdb_ops->strobj_readdata(py, addr, buf, buf_len));
++}
++
++static ssize_t
++pydb_strobj_readdata_native(pydb_agent_t *py, uintptr_t addr,
++    unsigned char *buf, size_t buf_len)
++{
++	PyStringObject sobj;
++	ssize_t obj_sz;
++	ssize_t read_sz;
++	psaddr_t straddr;
++
++	/*
++	 * PyStringObjects are variable size.  The size of the PyStringObject
++	 * struct is fixed, and known at compile time; however, the size of the
++	 * associated buffer is variable.  The char[1] element at the end of the
++	 * structure contains the string, and the ob_size of the PyStringObject
++	 * indicates how much extra space was allocated to contain the string
++	 * buffer at the object's tail.  Read in the fixed size portion of the
++	 * object first, and then read the contents of the data buffer into the
++	 * buffer passed by the caller.
++	 */
++
++	if (ps_pread(py->pdb_ph, addr, &sobj, sizeof (PyStringObject))
++	    != PS_OK) {
++		return (-1);
++	}
++
++	obj_sz = (ssize_t)PyString_GET_SIZE(&sobj);
++
++	read_sz = MIN(obj_sz, (ssize_t)buf_len);
++	straddr = (psaddr_t)(addr + offsetof(PyStringObject, ob_sval));
++
++	if (ps_pread(py->pdb_ph, straddr, buf, (size_t)read_sz) != PS_OK) {
++		return (-1);
++	}
++
++	return (read_sz);
++}
++
++#if defined(_LP64)
++static ssize_t
++pydb_strobj_readdata_32(pydb_agent_t *py, uintptr_t addr,
++    unsigned char *buf, size_t buf_len)
++{
++	PyStringObject32 sobj;
++	ssize_t obj_sz;
++	ssize_t read_sz;
++	psaddr_t straddr;
++
++	/*
++	 * PyStringObjects are variable size.  The size of the PyStringObject
++	 * struct is fixed, and known at compile time; however, the size of the
++	 * associated buffer is variable.  The char[1] element at the end of the
++	 * structure contains the string, and the ob_size of the PyStringObject
++	 * indicates how much extra space was allocated to contain the string
++	 * buffer at the object's tail.  Read in the fixed size portion of the
++	 * object first, and then read the contents of the data buffer into the
++	 * buffer passed by the caller.
++	 */
++
++	if (ps_pread(py->pdb_ph, addr, &sobj, sizeof (PyStringObject32))
++	    != PS_OK) {
++		return (-1);
++	}
++
++	obj_sz = (ssize_t)PyString_GET_SIZE32(&sobj);
++
++	read_sz = MIN(obj_sz, (ssize_t)buf_len);
++	straddr = (psaddr_t)(addr + offsetof(PyStringObject32, ob_sval));
++
++	if (ps_pread(py->pdb_ph, straddr, buf, (size_t)read_sz) != PS_OK) {
++		return (-1);
++	}
++
++	return (read_sz);
++}
++#endif /* _LP64 */
++
++/*
++ * Most Python PyStringObjects contain strings, as one would expect.  However,
++ * due to some sleazy hackery in parts of the Python code, some string objects
++ * are used as buffers for binary data.  In the general case,
++ * pydb_strobj_readstr() should be used to read strings out of string objects.
++ * It wraps pydb_strobj_readdata(), which should be used by callers only when
++ * trying to retrieve binary data.  (This routine does some string cleanup).
++ */
++static ssize_t
++pydb_strobj_readstr(pydb_agent_t *py, uintptr_t addr, char *buf,
++    size_t buf_len)
++{
++	ssize_t read_sz;
++
++	read_sz = pydb_strobj_readdata(py, addr, (unsigned char *)buf, buf_len);
++
++	if (read_sz >= 0) {
++		if (read_sz >= buf_len) {
++			read_sz = buf_len - 1;
++		}
++
++		buf[read_sz] = '\0';
++	}
++
++	return (read_sz);
++}
++
++
++static int
++pydb_frameinfo(pydb_agent_t *py, uintptr_t addr, char *funcnm,
++    size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno)
++{
++	return (py->pdb_ops->frameinfo(py, addr, funcnm, funcnm_sz,
++	    filenm, filenm_sz, lineno));
++}
++
++static int
++pydb_frameinfo_native(pydb_agent_t *py, uintptr_t addr, char *funcnm,
++    size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno)
++{
++	PyFrameObject fo;
++	PyCodeObject co;
++	ssize_t rc;
++
++	if (ps_pread(py->pdb_ph, addr, &fo, sizeof (PyFrameObject))
++	    != PS_OK) {
++		return (-1);
++	}
++
++	if (ps_pread(py->pdb_ph, (uintptr_t)fo.f_code, &co,
++	    sizeof (PyCodeObject)) != PS_OK) {
++		return (-1);
++	}
++
++	rc = pydb_strobj_readstr(py, (uintptr_t)co.co_name, funcnm, funcnm_sz);
++	if (rc < 0) {
++		return (-1);
++	}
++
++	rc = pydb_strobj_readstr(py, (uintptr_t)co.co_filename, filenm,
++	    filenm_sz);
++	if (rc < 0) {
++		return (-1);
++	}
++
++	*lineno = pydb_getlno(py, (uintptr_t)co.co_lnotab, co.co_firstlineno,
++	    fo.f_lasti);
++	if (*lineno < 0) {
++		return (-1);
++	}
++
++	return (0);
++}
++
++#if defined (_LP64)
++static int
++pydb_frameinfo_32(pydb_agent_t *py, uintptr_t addr, char *funcnm,
++    size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno)
++{
++	PyFrameObject32 fo;
++	PyCodeObject32 co;
++	ssize_t rc;
++
++	if (ps_pread(py->pdb_ph, addr, &fo, sizeof (PyFrameObject32))
++	    != PS_OK) {
++		return (-1);
++	}
++
++	if (ps_pread(py->pdb_ph, (uintptr_t)fo.f_code, &co,
++	    sizeof (PyCodeObject32)) != PS_OK) {
++		return (-1);
++	}
++
++	rc = pydb_strobj_readstr(py, (uintptr_t)co.co_name, funcnm, funcnm_sz);
++	if (rc < 0) {
++		return (-1);
++	}
++
++	rc = pydb_strobj_readstr(py, (uintptr_t)co.co_filename, filenm,
++	    filenm_sz);
++	if (rc < 0) {
++		return (-1);
++	}
++
++	*lineno = pydb_getlno(py, (uintptr_t)co.co_lnotab, co.co_firstlineno,
++	    fo.f_lasti);
++	if (*lineno < 0) {
++		return (-1);
++	}
++
++	return (0);
++}
++
++#endif /* _LP64 */
++
++/* Functions that are part of the library's interface */
++
++/*
++ * Given the address of a PyFrameObject, and a buffer of a known size,
++ * fill the buffer with a description of the frame.
++ */
++int
++pydb_get_frameinfo(pydb_agent_t *py, uintptr_t frame_addr, char *fbuf,
++    size_t bufsz, int verbose)
++{
++	char funcname[1024];
++	char filename[1024];
++	char *fn;
++	int lineno;
++	int length = (py->pdb_is_64bit ? 16 : 8);
++	int rc;
++
++	rc = pydb_frameinfo(py, frame_addr, funcname, sizeof (funcname),
++	    filename, sizeof (filename), &lineno);
++	if (rc < 0) {
++		return (-1);
++	}
++
++	if (!verbose) {
++		fn = (char *)strbasename(filename);
++	} else {
++		fn = filename;
++	}
++
++	(void) snprintf(fbuf, bufsz, "%0.*lx %s:%d %s()\n", length,
++	    frame_addr, fn, lineno, funcname);
++
++	return (0);
++}
++
++/*
++ * Return a description about a PyFrameObject, if the object is
++ * actually a PyFrameObject.  In this case, the pc argument is checked
++ * to make sure that it came from a function that takes a PyFrameObject
++ * as its first (argv[0]) argument.
++ */
++int
++pydb_pc_frameinfo(pydb_agent_t *py, uintptr_t pc, uintptr_t frame_addr,
++    char *fbuf, size_t bufsz)
++{
++	char funcname[1024];
++	char filename[1024];
++	int lineno;
++	int rc;
++	ps_sym_t psym;
++
++	/*
++	 * If PC doesn't match PyEval_EvalFrameEx in either libpython
++	 * or the executable, don't decode it.
++	 */
++	if (ps_pglobal_sym(py->pdb_ph, LIBPYTHON, "PyEval_EvalFrameEx", &psym)
++	    != PS_OK) {
++		return (-1);
++	}
++
++	/* If symbol found, ensure that PC falls within PyEval_EvalFrameEx. */
++	if (pc < psym.st_value || pc > psym.st_value + psym.st_size) {
++		return (-1);
++	}
++
++	rc = pydb_frameinfo(py, frame_addr, funcname, sizeof (funcname),
++	    filename, sizeof (filename), &lineno);
++	if (rc < 0) {
++		return (-1);
++	}
++
++	(void) snprintf(fbuf, bufsz, "[ %s:%d (%s) ]\n", filename, lineno,
++	    funcname);
++
++	return (0);
++}
++
++/*
++ * Walks the list of PyInterpreterState objects.  If caller doesn't
++ * supply address of list, this method will look it up.
++ */
++pydb_iter_t *
++pydb_interp_iter_init(pydb_agent_t *py, uintptr_t addr)
++{
++	pydb_iter_t *itr;
++	uintptr_t i_addr;
++	int rc;
++
++	if (addr == 0) {
++		rc = ps_pglobal_lookup(py->pdb_ph, LIBPYTHON, "interp_head",
++		    (psaddr_t *)&addr);
++		if (rc != PS_OK) {
++			return (NULL);
++		}
++	}
++
++	if (ps_pread(py->pdb_ph, (uintptr_t)addr, &i_addr, sizeof (uintptr_t))
++	    != PS_OK) {
++		return (NULL);
++	}
++
++	itr = malloc(sizeof (pydb_iter_t));
++	if (itr == NULL) {
++		return (NULL);
++	}
++
++	itr->pdi_ph = py->pdb_ph;
++	itr->pdi_current = i_addr;
++	itr->pdi_nextf = pydb_interp_iter_next;
++
++	return (itr);
++}
++
++static uintptr_t
++pydb_interp_iter_next(pydb_iter_t *iter)
++{
++	PyInterpreterState st;
++	uintptr_t cur;
++
++	cur = iter->pdi_current;
++
++	if (cur == 0) {
++		return (cur);
++	}
++
++	if (ps_pread(iter->pdi_ph, cur, &st, sizeof (PyInterpreterState))
++	    != PS_OK) {
++		iter->pdi_current = 0;
++		return (0);
++	}
++
++	iter->pdi_current = (uintptr_t)st.next;
++
++	return (cur);
++}
++
++/*
++ * Walk a list of Python PyFrameObjects.  The addr argument must be
++ * the address of a valid PyThreadState object.
++ */
++pydb_iter_t *
++pydb_frame_iter_init(pydb_agent_t *py, uintptr_t addr)
++{
++	pydb_iter_t *itr;
++	PyThreadState ts;
++
++	if (ps_pread(py->pdb_ph, (uintptr_t)addr, &ts, sizeof (PyThreadState))
++	    != PS_OK) {
++		return (NULL);
++	}
++
++	itr = malloc(sizeof (pydb_iter_t));
++	if (itr == NULL) {
++		return (NULL);
++	}
++
++	itr->pdi_ph = py->pdb_ph;
++	itr->pdi_current = (uintptr_t)ts.frame;
++	itr->pdi_nextf = pydb_frame_iter_next;
++
++	return (itr);
++}
++
++static uintptr_t
++pydb_frame_iter_next(pydb_iter_t *iter)
++{
++	PyFrameObject fo;
++	uintptr_t cur;
++
++	cur = iter->pdi_current;
++
++	if (cur == 0) {
++		return (cur);
++	}
++
++	if (ps_pread(iter->pdi_ph, cur, &fo, sizeof (PyFrameObject))
++	    != PS_OK) {
++		iter->pdi_current = 0;
++		return (0);
++	}
++
++	iter->pdi_current = (uintptr_t)fo.f_back;
++
++	return (cur);
++}
++
++/*
++ * Walk a list of Python PyThreadState objects.  The addr argument must be
++ * the address of a valid PyInterpreterState object.
++ */
++pydb_iter_t *
++pydb_thread_iter_init(pydb_agent_t *py, uintptr_t addr)
++{
++	pydb_iter_t *itr;
++	PyInterpreterState is;
++
++	if (ps_pread(py->pdb_ph, (uintptr_t)addr, &is,
++	    sizeof (PyInterpreterState)) != PS_OK) {
++		return (NULL);
++	}
++
++	itr = malloc(sizeof (pydb_iter_t));
++	if (itr == NULL) {
++		return (NULL);
++	}
++
++	itr->pdi_ph = py->pdb_ph;
++	itr->pdi_current = (uintptr_t)is.tstate_head;
++	itr->pdi_nextf = pydb_thread_iter_next;
++
++	return (itr);
++}
++
++static uintptr_t
++pydb_thread_iter_next(pydb_iter_t *iter)
++{
++	PyThreadState ts;
++	uintptr_t cur;
++
++	cur = iter->pdi_current;
++
++	if (cur == 0) {
++		return (cur);
++	}
++
++	if (ps_pread(iter->pdi_ph, cur, &ts, sizeof (PyThreadState)) != PS_OK) {
++		iter->pdi_current = 0;
++		return (0);
++	}
++
++	iter->pdi_current = (uintptr_t)ts.next;
++
++	return (cur);
++}
++
++
++uintptr_t
++pydb_iter_next(pydb_iter_t *iter)
++{
++	return (iter->pdi_nextf(iter));
++}
++
++void
++pydb_iter_fini(pydb_iter_t *iter)
++{
++	if (iter == NULL) {
++		return;
++	}
++
++	free(iter);
++}
+diff --git Python-2.7.1/py_db/libpython27_db.h Python-2.7.1/py_db/libpython27_db.h
+new file mode 100644
+--- /dev/null
++++ Python-2.7.1/py_db/libpython27_db.h
[email protected]@ -0,0 +1,73 @@
++/*
++ * 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 (c) 2012, Oracle and/or its affiliates. All rights reserved.
++ */
++
++#ifndef	_LIBPYTHON27_DB_H
++#define	_LIBPYTHON27_DB_H
++
++#include <proc_service.h>
++
++#ifdef	__cplusplus
++extern "C" {
++#endif
++
++/* Agent is opaque to library's consumers.  */
++typedef struct pydb_agent pydb_agent_t;
++
++/*
++ * Library's debug version is 1.  Changes to interface should increase this
++ * number.
++ */
++#define	PYDB_VERSION	1
++
++/* Agent creation/destruction routines */
++extern	pydb_agent_t	*pydb_agent_create(struct ps_prochandle *P, int vers);
++extern	void		pydb_agent_destroy(pydb_agent_t *py);
++
++/* Used by callers that know they are looking at a PyFrameObject */
++extern	int	pydb_get_frameinfo(pydb_agent_t *py, uintptr_t frame_addr,
++    char *fbuf, size_t bufsz, int verbose);
++
++/*
++ * Used by callers that don't know if they're looking at PyFrameObject.
++ * Checks PC for traceable functions.
++ */
++extern	int	pydb_pc_frameinfo(pydb_agent_t *py, uintptr_t pc,
++    uintptr_t frame_addr, char *fbuf, size_t bufsz);
++
++/* Iterator functions */
++typedef struct pydb_iter pydb_iter_t;
++
++extern	pydb_iter_t	*pydb_frame_iter_init(pydb_agent_t *py, uintptr_t addr);
++extern	pydb_iter_t	*pydb_interp_iter_init(pydb_agent_t *py,
++    uintptr_t addr);
++extern	pydb_iter_t	*pydb_thread_iter_init(pydb_agent_t *py,
++    uintptr_t addr);
++extern	void		pydb_iter_fini(pydb_iter_t *iter);
++extern	uintptr_t	pydb_iter_next(pydb_iter_t *iter);
++
++#ifdef	__cplusplus
++}
++#endif
++
++#endif	/* _LIBPYTHON27_DB_H */
+diff --git Python-2.7.1/py_db/libpython27_db_32.h Python-2.7.1/py_db/libpython27_db_32.h
+new file mode 100644
+--- /dev/null
++++ Python-2.7.1/py_db/libpython27_db_32.h
[email protected]@ -0,0 +1,121 @@
++/*
++ * 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 (c) 2012, Oracle and/or its affiliates. All rights reserved.
++ */
++
++#ifndef	_LIBPYTHON27_DB_32_H
++#define	_LIBPYTHON27_DB_32_H
++
++#ifdef	__cplusplus
++extern "C" {
++#endif
++
++#include <sys/types.h>
++
++/*
++ * Define 32-bit Python data structures for use by the 64-bit debugger.  This
++ * is so that a 64-bit debugger may properly examine a 32-bit process.
++ *
++ * In many cases, the debug library is only concerned with a few fields in the
++ * Python structure.  In that case, the other ancillary fields are elided.
++ */
++
++typedef uint32_t uintptr32_t;
++typedef int32_t Py_ssize32_t;
++
++typedef struct _is32 {
++	uintptr32_t	next;
++	uintptr32_t	tstate_head;
++} PyInterpreterState32;
++
++typedef struct _ts32 {
++	uintptr32_t	next;
++	uintptr32_t	interp;
++	uintptr32_t	frame;
++} PyThreadState32;
++
++#define	PyObject_HEAD32			\
++	Py_ssize32_t	ob_refcnt;	\
++	uintptr32_t	ob_type;
++
++#define	PyObject_VAR_HEAD32		\
++	PyObject_HEAD32			\
++	Py_ssize32_t	ob_size;
++
++typedef struct {
++	PyObject_HEAD32
++} PyObject32;
++
++typedef struct {
++	PyObject_VAR_HEAD32
++} PyVarObject32;
++
++typedef struct {
++	PyObject_VAR_HEAD32
++	int32_t		ob_shash;
++	int		ob_sstate;
++	char		ob_sval[1];
++} PyStringObject32;
++
++#define	Py_SIZE32(ob)			(((PyVarObject32*)(ob))->ob_size)
++#define	PyString_GET_SIZE32(op)		Py_SIZE32(op)
++#define	PyString_AS_STRING32(op)	(((PyStringObject32 *)(op))->ob_sval)
++
++typedef struct {
++	PyObject_VAR_HEAD32
++	uintptr32_t	f_back;
++	uintptr32_t	f_code;
++	uintptr32_t	f_builtins;
++	uintptr32_t	f_globals;
++	uintptr32_t	f_locals;
++	uintptr32_t	f_valuestack;
++	uintptr32_t	f_stacktop;
++	uintptr32_t	f_trace;
++	uintptr32_t	f_exc_typpe, f_exc_value, f_exc_traceback;
++	uintptr32_t	f_tstate;
++	int		f_lasti;
++	int		f_lineno;
++} PyFrameObject32;
++
++typedef struct {
++	PyObject_HEAD32
++	int		co_argcount;
++	int		co_nlocals;
++	int		co_stacksize;
++	int		co_flags;
++	uintptr32_t	co_code;
++	uintptr32_t	co_consts;
++	uintptr32_t	co_names;
++	uintptr32_t	co_varnames;
++	uintptr32_t	co_freevars;
++	uintptr32_t	co_cellvars;
++	uintptr32_t	co_filename;
++	uintptr32_t	co_name;
++	int		co_firstlineno;
++	uintptr32_t	co_lnotab;
++} PyCodeObject32;
++
++#ifdef	__cplusplus
++}
++#endif
++
++#endif	/* _LIBPYTHON27_DB_32_H */
+diff --git Python-2.7.1/py_db/mapfile-vers Python-2.7.1/py_db/mapfile-vers
+new file mode 100644
+--- /dev/null
++++ Python-2.7.1/py_db/mapfile-vers
[email protected]@ -0,0 +1,39 @@
++#
++# 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 (c) 2012, Oracle and/or its affiliates. All rights reserved.
++#
++
++SUNWprivate_1.1 {
++    global:
++	pydb_agent_create;
++	pydb_agent_destroy;
++	pydb_frame_iter_init;
++	pydb_get_frameinfo;
++	pydb_pc_frameinfo;
++	pydb_interp_iter_init;
++	pydb_thread_iter_init;
++	pydb_iter_fini;
++	pydb_iter_next;
++    local:
++	*;
++};
--- a/components/python/python27/python-27-tests.p5m	Thu Jun 28 03:21:11 2012 -0400
+++ b/components/python/python27/python-27-tests.p5m	Thu Jun 28 12:59:05 2012 -0700
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 
 # python doesn't generate .pyc version of these test files.
@@ -342,6 +342,10 @@
 file path=usr/lib/python2.7/test/badsyntax_nocaret.py
 file path=usr/lib/python2.7/test/buffer_tests.py
 file path=usr/lib/python2.7/test/cfgparser.1
+file usr/bin/check_offset \
+    path=usr/lib/python2.7/test/check_offset mode=0555
+file usr/bin/$(MACH64)/check_offset \
+    path=usr/lib/python2.7/test/check_offset64 mode=0555
 file path=usr/lib/python2.7/test/check_soundcard.vbs
 file path=usr/lib/python2.7/test/cjkencodings/big5-utf8.txt
 file path=usr/lib/python2.7/test/cjkencodings/big5.txt
--- a/components/python/python27/python-27.p5m	Thu Jun 28 03:21:11 2012 -0400
+++ b/components/python/python27/python-27.p5m	Thu Jun 28 12:59:05 2012 -0700
@@ -203,6 +203,7 @@
 file path=usr/include/python2.7/warnings.h
 file path=usr/include/python2.7/weakrefobject.h
 file path=usr/lib/$(MACH64)/libpython2.7.so.1.0
+file path=usr/lib/$(MACH64)/libpython2.7_db.so.1.0
 file $(MACH64)/llib-lpython27.ln path=usr/lib/$(MACH64)/llib-lpython2.7.ln
 file path=usr/lib/$(MACH64)/pkgconfig/python-2.7.pc
 #file path=usr/lib/$(MACH64)/python2.7/config/Makefile
@@ -215,6 +216,7 @@
 #file path=usr/lib/$(MACH64)/python2.7/config/makesetup mode=0555
 #file path=usr/lib/$(MACH64)/python2.7/config/python.o
 file path=usr/lib/libpython2.7.so.1.0
+file path=usr/lib/libpython2.7_db.so.1.0
 file llib-lpython27 path=usr/lib/llib-lpython2.7
 file $(MACH32)/llib-lpython27.ln path=usr/lib/llib-lpython2.7.ln
 file path=usr/lib/pkgconfig/python-2.7.pc
@@ -1058,7 +1060,9 @@
 link path=usr/bin/$(MACH64)/python2.7 target=isapython2.7
 link path=usr/bin/python2.7 target=$(MACH32)/isapython2.7
 link path=usr/lib/$(MACH64)/libpython2.7.so target=libpython2.7.so.1.0
+link path=usr/lib/$(MACH64)/libpython2.7_db.so target=libpython2.7_db.so.1.0
 link path=usr/lib/libpython2.7.so target=libpython2.7.so.1.0
+link path=usr/lib/libpython2.7_db.so target=libpython2.7_db.so.1.0
 
 link path=usr/bin/2to3 target=2to3-2.7 mediator=python mediator-version=2.7 \
     pkg.linted.pkglint.dupaction010.1=true