components/python/python27/patches/14-py_db.patch
author John Beck <John.Beck@Oracle.COM>
Sat, 04 Oct 2014 14:50:43 -0700
branchs11-update
changeset 3367 ed5024e47b53
parent 896 50be262e44f7
child 3565 2d729d36ded7
permissions -rw-r--r--
PSARC 2014/183 Python 2.7.6 18251953 update Python 2.7 line to version 2.7.6 19004605 update Python 2.7 line to version 2.7.7 19308541 update Python 2.7 line to version 2.7.8 19284990 python 2.7.7 segfaults while under memory stress 17431625 64-bit python should use long rather than int for os.sysconf() return value 19164544 Python 2.7 test_tcl fails 19030238 Python 2.7 test_sysconfig fails - no module named _osx_support 19030198 Python 2.7 tests fail - import name error 19032456 more Python 2.7 tests failing with import errors 19022543 Python 2.7 test_lib2to3 fails

This patch adds Python debugger support.  It may be contributed upstream at
some point, but the suitability (or lack thereof) has not yet been determined.

--- Python-2.7.7/Makefile.pre.in.~3~	2014-06-02 10:54:32.421086337 -0700
+++ Python-2.7.7/Makefile.pre.in	2014-06-02 10:54:32.438134113 -0700
@@ -407,7 +407,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:
@@ -778,6 +778,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 $@ $(CFLAGS) $(CPPFLAGS) $(SHLIB_FLAGS) $<
+
+check_offset:  $(srcdir)/py_db/check_offsets.c
+	$(CC) -o $@ $(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)
 
 ######################################################################
 
@@ -842,7 +855,7 @@
 		$(TESTPYTHON) $(TESTPROG) $(MEMTESTOPTS)
 
 # Install everything
-install:	@FRAMEWORKINSTALLFIRST@ altinstall bininstall maninstall @FRAMEWORKINSTALLLAST@
+install:	@FRAMEWORKINSTALLFIRST@ altinstall bininstall maninstall @FRAMEWORKINSTALLLAST@ install-py_db
 
 # Install almost everything without disturbing previous versions
 altinstall:	@FRAMEWORKALTINSTALLFIRST@ altbininstall libinstall inclinstall \
--- /dev/null
+++ Python-2.7.1/py_db/check_offsets.c
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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:
+	*;
+};