xref: /onnv-gate/usr/src/cmd/mdb/common/modules/libpython2.6/libpython26.c (revision 11946:fbfb89676033)
1*11946Sjohansen@sun.com /*
2*11946Sjohansen@sun.com  * CDDL HEADER START
3*11946Sjohansen@sun.com  *
4*11946Sjohansen@sun.com  * The contents of this file are subject to the terms of the
5*11946Sjohansen@sun.com  * Common Development and Distribution License (the "License").
6*11946Sjohansen@sun.com  * You may not use this file except in compliance with the License.
7*11946Sjohansen@sun.com  *
8*11946Sjohansen@sun.com  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*11946Sjohansen@sun.com  * or http://www.opensolaris.org/os/licensing.
10*11946Sjohansen@sun.com  * See the License for the specific language governing permissions
11*11946Sjohansen@sun.com  * and limitations under the License.
12*11946Sjohansen@sun.com  *
13*11946Sjohansen@sun.com  * When distributing Covered Code, include this CDDL HEADER in each
14*11946Sjohansen@sun.com  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*11946Sjohansen@sun.com  * If applicable, add the following below this CDDL HEADER, with the
16*11946Sjohansen@sun.com  * fields enclosed by brackets "[]" replaced with your own identifying
17*11946Sjohansen@sun.com  * information: Portions Copyright [yyyy] [name of copyright owner]
18*11946Sjohansen@sun.com  *
19*11946Sjohansen@sun.com  * CDDL HEADER END
20*11946Sjohansen@sun.com  */
21*11946Sjohansen@sun.com /*
22*11946Sjohansen@sun.com  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23*11946Sjohansen@sun.com  * Use is subject to license terms.
24*11946Sjohansen@sun.com  */
25*11946Sjohansen@sun.com 
26*11946Sjohansen@sun.com #include <mdb/mdb_modapi.h>
27*11946Sjohansen@sun.com 
28*11946Sjohansen@sun.com #include <pthread.h>
29*11946Sjohansen@sun.com #include <stddef.h>
30*11946Sjohansen@sun.com #include <dlfcn.h>
31*11946Sjohansen@sun.com #include <link.h>
32*11946Sjohansen@sun.com #include <libproc.h>
33*11946Sjohansen@sun.com 
34*11946Sjohansen@sun.com #include <python2.6/Python.h>
35*11946Sjohansen@sun.com #include <python2.6/frameobject.h>
36*11946Sjohansen@sun.com 
37*11946Sjohansen@sun.com /*
38*11946Sjohansen@sun.com  * Decoding Python Stack Frames
39*11946Sjohansen@sun.com  * ============================
40*11946Sjohansen@sun.com  *
41*11946Sjohansen@sun.com  * Python2.6 uses a variety of objects to construct its call chain.  An address
42*11946Sjohansen@sun.com  * space may have one or more PyInterpreterState objects, which are the base
43*11946Sjohansen@sun.com  * object in the interpreter's state.  These objects are kept in a linked list
44*11946Sjohansen@sun.com  * with a head pointer named interp_head.  This makes it possible for the
45*11946Sjohansen@sun.com  * debugger to get a toehold on data structures necessary to understand the
46*11946Sjohansen@sun.com  * interpreter.  Since most of these structures are linked out of the
47*11946Sjohansen@sun.com  * InterpreterState, traversals generally start here.
48*11946Sjohansen@sun.com  *
49*11946Sjohansen@sun.com  * In order to decode a frame, the debugger needs to walk from
50*11946Sjohansen@sun.com  * PyInterpreterState down to a PyCodeObject.  The diagram below shows the
51*11946Sjohansen@sun.com  * the objects that must be examined in order to reach a leaf PyCodeObject.
52*11946Sjohansen@sun.com  *
53*11946Sjohansen@sun.com  *                +--------------------+ next   +--------------------+ next
54*11946Sjohansen@sun.com  * interp_head -> | PyInterpreterState | ---->  | PyInterpreterState | ---> ...
55*11946Sjohansen@sun.com  *                +--------------------+        +--------------------+
56*11946Sjohansen@sun.com  *                  |                            | tstate_head
57*11946Sjohansen@sun.com  *                  | tstate_head                V
58*11946Sjohansen@sun.com  *                  |                 +---------------+  frame
59*11946Sjohansen@sun.com  *                  V                 | PyThreadState | -----> ...
60*11946Sjohansen@sun.com  *  +---------------+  frame          +---------------+
61*11946Sjohansen@sun.com  *  | PyThreadState |  ---> ...
62*11946Sjohansen@sun.com  *  +---------------+
63*11946Sjohansen@sun.com  *          | next
64*11946Sjohansen@sun.com  *          V
65*11946Sjohansen@sun.com  *  +---------------+  frame    +---------------+ f_back +---------------+
66*11946Sjohansen@sun.com  *  | PyThreadState |  ------>  | PyFrameObject | -----> | PyFrameObject |
67*11946Sjohansen@sun.com  *  +---------------+           +---------------+        +---------------+
68*11946Sjohansen@sun.com  *                                      |                       |
69*11946Sjohansen@sun.com  *                                      | f_code                | f_code
70*11946Sjohansen@sun.com  *                                      V                       V
71*11946Sjohansen@sun.com  *                              +--------------+               ...
72*11946Sjohansen@sun.com  *                              | PyCodeObject |
73*11946Sjohansen@sun.com  *                              +--------------+
74*11946Sjohansen@sun.com  *                 co_filename   |      |     | co_lnotab
75*11946Sjohansen@sun.com  *                 +-------------+      |     +-------------+
76*11946Sjohansen@sun.com  *                 |           co_name  |                   |
77*11946Sjohansen@sun.com  *                 V                    V                   V
78*11946Sjohansen@sun.com  * +----------------+          +----------------+         +----------------+
79*11946Sjohansen@sun.com  * | PyStringObject |          | PyStringObject |         | PyStringObject |
80*11946Sjohansen@sun.com  * +----------------+          +----------------+         +----------------+
81*11946Sjohansen@sun.com  *
82*11946Sjohansen@sun.com  * The interp_head pointer is a list of one or more PyInterpreterState
83*11946Sjohansen@sun.com  * objects.  Each of these objects can contain one or more PyThreadState
84*11946Sjohansen@sun.com  * objects.  The PyInterpreterState object keeps a pointer to the head of the
85*11946Sjohansen@sun.com  * list of PyThreadState objects as tstate_head.
86*11946Sjohansen@sun.com  *
87*11946Sjohansen@sun.com  * Each thread keeps ahold of its stack frames.  The PyThreadState object
88*11946Sjohansen@sun.com  * has a pointer to the topmost PyFrameObject, kept in frame.  The
89*11946Sjohansen@sun.com  * successive frames on the stack are kept linked in the PyFrameObject's
90*11946Sjohansen@sun.com  * f_back pointer, with each frame pointing to its caller.
91*11946Sjohansen@sun.com  *
92*11946Sjohansen@sun.com  * In order to decode each call frame, our code needs to look at the
93*11946Sjohansen@sun.com  * PyCodeObject for each frame.  Essentially, this is the code that is
94*11946Sjohansen@sun.com  * being executed in the frame.  The PyFrameObject keeps a pointer to this
95*11946Sjohansen@sun.com  * code object in f_code.  In order to print meaningful debug information,
96*11946Sjohansen@sun.com  * it's necessary to extract the Python filename (co_filename), the
97*11946Sjohansen@sun.com  * function name (co_name), and the line number within the file
98*11946Sjohansen@sun.com  * (co_lnotab).  The filename and function are stored as strings, but the
99*11946Sjohansen@sun.com  * line number is a mapping of bytecode offsets to line numbers.  The
100*11946Sjohansen@sun.com  * description of the lnotab algorithm lives here:
101*11946Sjohansen@sun.com  *
102*11946Sjohansen@sun.com  * http://svn.python.org/projects/python/trunk/Objects/lnotab_notes.txt
103*11946Sjohansen@sun.com  *
104*11946Sjohansen@sun.com  * In order to decode the frame, the debugger needs to walk each
105*11946Sjohansen@sun.com  * InterpreterState object.  For each InterpreterState, every PyThreadState
106*11946Sjohansen@sun.com  * must be traversed.  The PyThreadState objects point to the
107*11946Sjohansen@sun.com  * PyFrameObjects.  For every thread, we must walk the frames backwards and
108*11946Sjohansen@sun.com  * decode the strings that are in the PyCodeObjects.
109*11946Sjohansen@sun.com  */
110*11946Sjohansen@sun.com 
111*11946Sjohansen@sun.com /*
112*11946Sjohansen@sun.com  * The Python-dependent debugging functionality lives in its own helper
113*11946Sjohansen@sun.com  * library.  The helper agent is provided by libpython2.6_db.so, which is also
114*11946Sjohansen@sun.com  * used by pstack(1) for debugging Python processes.
115*11946Sjohansen@sun.com  *
116*11946Sjohansen@sun.com  * Define needed prototypes here.
117*11946Sjohansen@sun.com  */
118*11946Sjohansen@sun.com 
119*11946Sjohansen@sun.com #define	PYDB_VERSION	1
120*11946Sjohansen@sun.com typedef struct pydb_agent pydb_agent_t;
121*11946Sjohansen@sun.com typedef struct pydb_iter pydb_iter_t;
122*11946Sjohansen@sun.com 
123*11946Sjohansen@sun.com typedef pydb_agent_t *(*pydb_agent_create_f)(struct ps_prochandle *P, int vers);
124*11946Sjohansen@sun.com typedef void (*pydb_agent_destroy_f)(pydb_agent_t *py);
125*11946Sjohansen@sun.com typedef int (*pydb_get_frameinfo_f)(pydb_agent_t *py, uintptr_t frame_addr,
126*11946Sjohansen@sun.com     char *fbuf, size_t bufsz, int verbose);
127*11946Sjohansen@sun.com typedef pydb_iter_t *(*pydb_iter_init_f)(pydb_agent_t *py, uintptr_t addr);
128*11946Sjohansen@sun.com typedef uintptr_t (*pydb_iter_next_f)(pydb_iter_t *iter);
129*11946Sjohansen@sun.com typedef void (*pydb_iter_fini_f)(pydb_iter_t *iter);
130*11946Sjohansen@sun.com 
131*11946Sjohansen@sun.com static pydb_agent_create_f pydb_agent_create;
132*11946Sjohansen@sun.com static pydb_agent_destroy_f pydb_agent_destroy;
133*11946Sjohansen@sun.com static pydb_get_frameinfo_f pydb_get_frameinfo;
134*11946Sjohansen@sun.com static pydb_iter_init_f pydb_frame_iter_init;
135*11946Sjohansen@sun.com static pydb_iter_init_f pydb_interp_iter_init;
136*11946Sjohansen@sun.com static pydb_iter_init_f pydb_thread_iter_init;
137*11946Sjohansen@sun.com static pydb_iter_next_f pydb_iter_next;
138*11946Sjohansen@sun.com static pydb_iter_fini_f pydb_iter_fini;
139*11946Sjohansen@sun.com 
140*11946Sjohansen@sun.com static pydb_agent_t *pydb_hdl = NULL;
141*11946Sjohansen@sun.com static void *pydb_dlhdl = NULL;
142*11946Sjohansen@sun.com 
143*11946Sjohansen@sun.com /*ARGSUSED*/
144*11946Sjohansen@sun.com static int
py_frame(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)145*11946Sjohansen@sun.com py_frame(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
146*11946Sjohansen@sun.com {
147*11946Sjohansen@sun.com 	char buf[1024];
148*11946Sjohansen@sun.com 	int verbose = FALSE;
149*11946Sjohansen@sun.com 
150*11946Sjohansen@sun.com 	if (mdb_getopts(argc, argv,
151*11946Sjohansen@sun.com 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
152*11946Sjohansen@sun.com 	    NULL) != argc) {
153*11946Sjohansen@sun.com 		return (DCMD_USAGE);
154*11946Sjohansen@sun.com 	}
155*11946Sjohansen@sun.com 
156*11946Sjohansen@sun.com 	if (flags & DCMD_PIPE_OUT) {
157*11946Sjohansen@sun.com 		mdb_warn("py_stack cannot output into a pipe\n");
158*11946Sjohansen@sun.com 		return (DCMD_ERR);
159*11946Sjohansen@sun.com 	}
160*11946Sjohansen@sun.com 
161*11946Sjohansen@sun.com 	if (!(flags & DCMD_ADDRSPEC)) {
162*11946Sjohansen@sun.com 		mdb_warn("no address");
163*11946Sjohansen@sun.com 		return (DCMD_USAGE);
164*11946Sjohansen@sun.com 	}
165*11946Sjohansen@sun.com 
166*11946Sjohansen@sun.com 	if (pydb_get_frameinfo(pydb_hdl, addr, buf, sizeof (buf),
167*11946Sjohansen@sun.com 	    verbose) < 0) {
168*11946Sjohansen@sun.com 		mdb_warn("Unable to find frame at address %p\n", addr);
169*11946Sjohansen@sun.com 		return (DCMD_ERR);
170*11946Sjohansen@sun.com 	}
171*11946Sjohansen@sun.com 
172*11946Sjohansen@sun.com 	mdb_printf("%s", buf);
173*11946Sjohansen@sun.com 
174*11946Sjohansen@sun.com 	return (DCMD_OK);
175*11946Sjohansen@sun.com }
176*11946Sjohansen@sun.com 
177*11946Sjohansen@sun.com int
py_interp_walk_init(mdb_walk_state_t * wsp)178*11946Sjohansen@sun.com py_interp_walk_init(mdb_walk_state_t *wsp)
179*11946Sjohansen@sun.com {
180*11946Sjohansen@sun.com 	pydb_iter_t *pdi;
181*11946Sjohansen@sun.com 
182*11946Sjohansen@sun.com 	pdi = pydb_interp_iter_init(pydb_hdl, wsp->walk_addr);
183*11946Sjohansen@sun.com 
184*11946Sjohansen@sun.com 	if (pdi == NULL) {
185*11946Sjohansen@sun.com 		mdb_warn("unable to create interpreter iterator\n");
186*11946Sjohansen@sun.com 		return (DCMD_ERR);
187*11946Sjohansen@sun.com 	}
188*11946Sjohansen@sun.com 
189*11946Sjohansen@sun.com 	wsp->walk_data = pdi;
190*11946Sjohansen@sun.com 
191*11946Sjohansen@sun.com 	return (WALK_NEXT);
192*11946Sjohansen@sun.com }
193*11946Sjohansen@sun.com 
194*11946Sjohansen@sun.com int
py_walk_step(mdb_walk_state_t * wsp)195*11946Sjohansen@sun.com py_walk_step(mdb_walk_state_t *wsp)
196*11946Sjohansen@sun.com {
197*11946Sjohansen@sun.com 	pydb_iter_t *pdi = wsp->walk_data;
198*11946Sjohansen@sun.com 	uintptr_t addr;
199*11946Sjohansen@sun.com 	int status;
200*11946Sjohansen@sun.com 
201*11946Sjohansen@sun.com 	addr = pydb_iter_next(pdi);
202*11946Sjohansen@sun.com 
203*11946Sjohansen@sun.com 	if (addr == NULL) {
204*11946Sjohansen@sun.com 		return (WALK_DONE);
205*11946Sjohansen@sun.com 	}
206*11946Sjohansen@sun.com 
207*11946Sjohansen@sun.com 	status = wsp->walk_callback(addr, 0, wsp->walk_cbdata);
208*11946Sjohansen@sun.com 
209*11946Sjohansen@sun.com 	return (status);
210*11946Sjohansen@sun.com }
211*11946Sjohansen@sun.com 
212*11946Sjohansen@sun.com void
py_walk_fini(mdb_walk_state_t * wsp)213*11946Sjohansen@sun.com py_walk_fini(mdb_walk_state_t *wsp)
214*11946Sjohansen@sun.com {
215*11946Sjohansen@sun.com 	pydb_iter_t *pdi = wsp->walk_data;
216*11946Sjohansen@sun.com 	pydb_iter_fini(pdi);
217*11946Sjohansen@sun.com }
218*11946Sjohansen@sun.com 
219*11946Sjohansen@sun.com int
py_thread_walk_init(mdb_walk_state_t * wsp)220*11946Sjohansen@sun.com py_thread_walk_init(mdb_walk_state_t *wsp)
221*11946Sjohansen@sun.com {
222*11946Sjohansen@sun.com 	pydb_iter_t *pdi;
223*11946Sjohansen@sun.com 
224*11946Sjohansen@sun.com 	pdi = pydb_thread_iter_init(pydb_hdl, wsp->walk_addr);
225*11946Sjohansen@sun.com 	if (pdi == NULL) {
226*11946Sjohansen@sun.com 		mdb_warn("unable to create thread iterator\n");
227*11946Sjohansen@sun.com 		return (DCMD_ERR);
228*11946Sjohansen@sun.com 	}
229*11946Sjohansen@sun.com 
230*11946Sjohansen@sun.com 	wsp->walk_data = pdi;
231*11946Sjohansen@sun.com 
232*11946Sjohansen@sun.com 	return (WALK_NEXT);
233*11946Sjohansen@sun.com }
234*11946Sjohansen@sun.com 
235*11946Sjohansen@sun.com int
py_frame_walk_init(mdb_walk_state_t * wsp)236*11946Sjohansen@sun.com py_frame_walk_init(mdb_walk_state_t *wsp)
237*11946Sjohansen@sun.com {
238*11946Sjohansen@sun.com 	pydb_iter_t *pdi;
239*11946Sjohansen@sun.com 
240*11946Sjohansen@sun.com 	pdi = pydb_frame_iter_init(pydb_hdl, wsp->walk_addr);
241*11946Sjohansen@sun.com 	if (pdi == NULL) {
242*11946Sjohansen@sun.com 		mdb_warn("unable to create frame iterator\n");
243*11946Sjohansen@sun.com 		return (DCMD_ERR);
244*11946Sjohansen@sun.com 	}
245*11946Sjohansen@sun.com 
246*11946Sjohansen@sun.com 	wsp->walk_data = pdi;
247*11946Sjohansen@sun.com 
248*11946Sjohansen@sun.com 	return (WALK_NEXT);
249*11946Sjohansen@sun.com }
250*11946Sjohansen@sun.com 
251*11946Sjohansen@sun.com /*ARGSUSED*/
252*11946Sjohansen@sun.com static int
python_stack(uintptr_t addr,const PyThreadState * ts,uint_t * verbose)253*11946Sjohansen@sun.com python_stack(uintptr_t addr, const PyThreadState *ts, uint_t *verbose)
254*11946Sjohansen@sun.com {
255*11946Sjohansen@sun.com 	mdb_arg_t nargv;
256*11946Sjohansen@sun.com 	uint_t nargc = (verbose != NULL && *verbose) ? 1 : 0;
257*11946Sjohansen@sun.com 	/*
258*11946Sjohansen@sun.com 	 * Pass the ThreadState to the frame walker. Have frame walker
259*11946Sjohansen@sun.com 	 * call frame dcmd.
260*11946Sjohansen@sun.com 	 */
261*11946Sjohansen@sun.com 	mdb_printf("PyThreadState: %0?p\n", addr);
262*11946Sjohansen@sun.com 
263*11946Sjohansen@sun.com 	nargv.a_type = MDB_TYPE_STRING;
264*11946Sjohansen@sun.com 	nargv.a_un.a_str = "-v";
265*11946Sjohansen@sun.com 
266*11946Sjohansen@sun.com 	if (mdb_pwalk_dcmd("pyframe", "pyframe", nargc, &nargv, addr) == -1) {
267*11946Sjohansen@sun.com 		mdb_warn("can't walk 'pyframe'");
268*11946Sjohansen@sun.com 		return (WALK_ERR);
269*11946Sjohansen@sun.com 	}
270*11946Sjohansen@sun.com 
271*11946Sjohansen@sun.com 	return (WALK_NEXT);
272*11946Sjohansen@sun.com }
273*11946Sjohansen@sun.com 
274*11946Sjohansen@sun.com /*ARGSUSED*/
275*11946Sjohansen@sun.com static int
python_thread(uintptr_t addr,const PyInterpreterState * is,uint_t * verbose)276*11946Sjohansen@sun.com python_thread(uintptr_t addr, const PyInterpreterState *is, uint_t *verbose)
277*11946Sjohansen@sun.com {
278*11946Sjohansen@sun.com 	/*
279*11946Sjohansen@sun.com 	 * Pass the InterpreterState to the threadstate walker.
280*11946Sjohansen@sun.com 	 */
281*11946Sjohansen@sun.com 	if (mdb_pwalk("pythread", (mdb_walk_cb_t)python_stack, verbose,
282*11946Sjohansen@sun.com 	    addr) == -1) {
283*11946Sjohansen@sun.com 		mdb_warn("can't walk 'pythread'");
284*11946Sjohansen@sun.com 		return (WALK_ERR);
285*11946Sjohansen@sun.com 	}
286*11946Sjohansen@sun.com 
287*11946Sjohansen@sun.com 	return (WALK_NEXT);
288*11946Sjohansen@sun.com }
289*11946Sjohansen@sun.com 
290*11946Sjohansen@sun.com /*ARGSUSED*/
291*11946Sjohansen@sun.com static int
py_stack(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)292*11946Sjohansen@sun.com py_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
293*11946Sjohansen@sun.com {
294*11946Sjohansen@sun.com 	uint_t verbose = FALSE;
295*11946Sjohansen@sun.com 
296*11946Sjohansen@sun.com 	if (mdb_getopts(argc, argv,
297*11946Sjohansen@sun.com 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
298*11946Sjohansen@sun.com 	    NULL) != argc)
299*11946Sjohansen@sun.com 		return (DCMD_USAGE);
300*11946Sjohansen@sun.com 
301*11946Sjohansen@sun.com 	if (flags & DCMD_PIPE_OUT) {
302*11946Sjohansen@sun.com 		mdb_warn("py_stack cannot output into a pipe\n");
303*11946Sjohansen@sun.com 		return (DCMD_ERR);
304*11946Sjohansen@sun.com 	}
305*11946Sjohansen@sun.com 
306*11946Sjohansen@sun.com 	if (flags & DCMD_ADDRSPEC) {
307*11946Sjohansen@sun.com 		mdb_arg_t nargv;
308*11946Sjohansen@sun.com 		uint_t nargc = verbose ? 1 : 0;
309*11946Sjohansen@sun.com 
310*11946Sjohansen@sun.com 		nargv.a_type = MDB_TYPE_STRING;
311*11946Sjohansen@sun.com 		nargv.a_un.a_str = "-v";
312*11946Sjohansen@sun.com 
313*11946Sjohansen@sun.com 		if (mdb_pwalk_dcmd("pyframe", "pyframe", nargc, &nargv, addr)
314*11946Sjohansen@sun.com 		    == -1) {
315*11946Sjohansen@sun.com 			mdb_warn("can't walk 'pyframe'");
316*11946Sjohansen@sun.com 			return (DCMD_ERR);
317*11946Sjohansen@sun.com 		}
318*11946Sjohansen@sun.com 		return (DCMD_OK);
319*11946Sjohansen@sun.com 	}
320*11946Sjohansen@sun.com 
321*11946Sjohansen@sun.com 	if (mdb_walk("pyinterp", (mdb_walk_cb_t)python_thread,
322*11946Sjohansen@sun.com 	    &verbose) == -1) {
323*11946Sjohansen@sun.com 		mdb_warn("can't walk 'pyinterp'");
324*11946Sjohansen@sun.com 		return (DCMD_ERR);
325*11946Sjohansen@sun.com 	}
326*11946Sjohansen@sun.com 
327*11946Sjohansen@sun.com 	return (DCMD_OK);
328*11946Sjohansen@sun.com }
329*11946Sjohansen@sun.com 
330*11946Sjohansen@sun.com static const mdb_dcmd_t dcmds[] = {
331*11946Sjohansen@sun.com 	{ "pystack", "[-v]", "print python stacks", py_stack },
332*11946Sjohansen@sun.com 	{ "pyframe", "[-v]", "print python frames", py_frame },
333*11946Sjohansen@sun.com 	{ NULL }
334*11946Sjohansen@sun.com };
335*11946Sjohansen@sun.com 
336*11946Sjohansen@sun.com static const mdb_walker_t walkers[] = {
337*11946Sjohansen@sun.com 	{ "pyinterp", "walk python interpreter structures",
338*11946Sjohansen@sun.com 		py_interp_walk_init, py_walk_step, py_walk_fini },
339*11946Sjohansen@sun.com 	{ "pythread", "given an interpreter, walk the list of python threads",
340*11946Sjohansen@sun.com 		py_thread_walk_init, py_walk_step, py_walk_fini },
341*11946Sjohansen@sun.com 	{ "pyframe", "given a thread state, walk the list of frame objects",
342*11946Sjohansen@sun.com 		py_frame_walk_init, py_walk_step, py_walk_fini },
343*11946Sjohansen@sun.com 	{ NULL }
344*11946Sjohansen@sun.com };
345*11946Sjohansen@sun.com 
346*11946Sjohansen@sun.com static const mdb_modinfo_t modinfo = {
347*11946Sjohansen@sun.com 	MDB_API_VERSION, dcmds, walkers
348*11946Sjohansen@sun.com };
349*11946Sjohansen@sun.com 
350*11946Sjohansen@sun.com /*ARGSUSED*/
351*11946Sjohansen@sun.com static int
python_object_iter(void * cd,const prmap_t * pmp,const char * obj)352*11946Sjohansen@sun.com python_object_iter(void *cd, const prmap_t *pmp, const char *obj)
353*11946Sjohansen@sun.com {
354*11946Sjohansen@sun.com 	char path[PATH_MAX];
355*11946Sjohansen@sun.com 	char *name;
356*11946Sjohansen@sun.com 	char *s1, *s2;
357*11946Sjohansen@sun.com 	struct ps_prochandle *Pr = cd;
358*11946Sjohansen@sun.com 
359*11946Sjohansen@sun.com 	name = strstr(obj, "/libpython");
360*11946Sjohansen@sun.com 
361*11946Sjohansen@sun.com 	if (name) {
362*11946Sjohansen@sun.com 		(void) strcpy(path, obj);
363*11946Sjohansen@sun.com 		if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) {
364*11946Sjohansen@sun.com 			s1 = name;
365*11946Sjohansen@sun.com 			s2 = path + (s1 - obj);
366*11946Sjohansen@sun.com 			(void) strcpy(s2, "/64");
367*11946Sjohansen@sun.com 			s2 += 3;
368*11946Sjohansen@sun.com 			(void) strcpy(s2, s1);
369*11946Sjohansen@sun.com 		}
370*11946Sjohansen@sun.com 
371*11946Sjohansen@sun.com 		s1 = strstr(obj, ".so");
372*11946Sjohansen@sun.com 		s2 = strstr(path, ".so");
373*11946Sjohansen@sun.com 		(void) strcpy(s2, "_db");
374*11946Sjohansen@sun.com 		s2 += 3;
375*11946Sjohansen@sun.com 		(void) strcpy(s2, s1);
376*11946Sjohansen@sun.com 
377*11946Sjohansen@sun.com 		if ((pydb_dlhdl = dlopen(path, RTLD_LAZY|RTLD_GLOBAL)) != NULL)
378*11946Sjohansen@sun.com 			return (1);
379*11946Sjohansen@sun.com 	}
380*11946Sjohansen@sun.com 
381*11946Sjohansen@sun.com 	return (0);
382*11946Sjohansen@sun.com }
383*11946Sjohansen@sun.com 
384*11946Sjohansen@sun.com static int
python_db_init(void)385*11946Sjohansen@sun.com python_db_init(void)
386*11946Sjohansen@sun.com {
387*11946Sjohansen@sun.com 	struct ps_prochandle *Ph;
388*11946Sjohansen@sun.com 
389*11946Sjohansen@sun.com 	if (mdb_get_xdata("pshandle", &Ph, sizeof (Ph)) == -1) {
390*11946Sjohansen@sun.com 		mdb_warn("couldn't read pshandle xdata\n");
391*11946Sjohansen@sun.com 		dlclose(pydb_dlhdl);
392*11946Sjohansen@sun.com 		pydb_dlhdl = NULL;
393*11946Sjohansen@sun.com 		return (-1);
394*11946Sjohansen@sun.com 	}
395*11946Sjohansen@sun.com 
396*11946Sjohansen@sun.com 	(void) Pobject_iter(Ph, python_object_iter, Ph);
397*11946Sjohansen@sun.com 
398*11946Sjohansen@sun.com 	pydb_agent_create = (pydb_agent_create_f)
399*11946Sjohansen@sun.com 	    dlsym(pydb_dlhdl, "pydb_agent_create");
400*11946Sjohansen@sun.com 	pydb_agent_destroy = (pydb_agent_destroy_f)
401*11946Sjohansen@sun.com 	    dlsym(pydb_dlhdl, "pydb_agent_destroy");
402*11946Sjohansen@sun.com 	pydb_get_frameinfo = (pydb_get_frameinfo_f)
403*11946Sjohansen@sun.com 	    dlsym(pydb_dlhdl, "pydb_get_frameinfo");
404*11946Sjohansen@sun.com 
405*11946Sjohansen@sun.com 	pydb_frame_iter_init = (pydb_iter_init_f)
406*11946Sjohansen@sun.com 	    dlsym(pydb_dlhdl, "pydb_frame_iter_init");
407*11946Sjohansen@sun.com 	pydb_interp_iter_init = (pydb_iter_init_f)
408*11946Sjohansen@sun.com 	    dlsym(pydb_dlhdl, "pydb_interp_iter_init");
409*11946Sjohansen@sun.com 	pydb_thread_iter_init = (pydb_iter_init_f)
410*11946Sjohansen@sun.com 	    dlsym(pydb_dlhdl, "pydb_thread_iter_init");
411*11946Sjohansen@sun.com 	pydb_iter_next = (pydb_iter_next_f)dlsym(pydb_dlhdl, "pydb_iter_next");
412*11946Sjohansen@sun.com 	pydb_iter_fini = (pydb_iter_fini_f)dlsym(pydb_dlhdl, "pydb_iter_fini");
413*11946Sjohansen@sun.com 
414*11946Sjohansen@sun.com 
415*11946Sjohansen@sun.com 	if (pydb_agent_create == NULL || pydb_agent_destroy == NULL ||
416*11946Sjohansen@sun.com 	    pydb_get_frameinfo == NULL || pydb_frame_iter_init == NULL ||
417*11946Sjohansen@sun.com 	    pydb_interp_iter_init == NULL || pydb_thread_iter_init == NULL ||
418*11946Sjohansen@sun.com 	    pydb_iter_next == NULL || pydb_iter_fini == NULL) {
419*11946Sjohansen@sun.com 		mdb_warn("couldn't load pydb functions");
420*11946Sjohansen@sun.com 		dlclose(pydb_dlhdl);
421*11946Sjohansen@sun.com 		pydb_dlhdl = NULL;
422*11946Sjohansen@sun.com 		return (-1);
423*11946Sjohansen@sun.com 	}
424*11946Sjohansen@sun.com 
425*11946Sjohansen@sun.com 	pydb_hdl = pydb_agent_create(Ph, PYDB_VERSION);
426*11946Sjohansen@sun.com 	if (pydb_hdl == NULL) {
427*11946Sjohansen@sun.com 		mdb_warn("unable to create pydb_agent");
428*11946Sjohansen@sun.com 		dlclose(pydb_dlhdl);
429*11946Sjohansen@sun.com 		pydb_dlhdl = NULL;
430*11946Sjohansen@sun.com 		return (-1);
431*11946Sjohansen@sun.com 	}
432*11946Sjohansen@sun.com 
433*11946Sjohansen@sun.com 	return (0);
434*11946Sjohansen@sun.com }
435*11946Sjohansen@sun.com 
436*11946Sjohansen@sun.com static void
python_db_fini(void)437*11946Sjohansen@sun.com python_db_fini(void)
438*11946Sjohansen@sun.com {
439*11946Sjohansen@sun.com 	if (pydb_dlhdl) {
440*11946Sjohansen@sun.com 		pydb_agent_destroy(pydb_hdl);
441*11946Sjohansen@sun.com 		pydb_hdl = NULL;
442*11946Sjohansen@sun.com 
443*11946Sjohansen@sun.com 		dlclose(pydb_dlhdl);
444*11946Sjohansen@sun.com 		pydb_dlhdl = NULL;
445*11946Sjohansen@sun.com 	}
446*11946Sjohansen@sun.com }
447*11946Sjohansen@sun.com 
448*11946Sjohansen@sun.com const mdb_modinfo_t *
_mdb_init(void)449*11946Sjohansen@sun.com _mdb_init(void)
450*11946Sjohansen@sun.com {
451*11946Sjohansen@sun.com 	if (python_db_init() != 0)
452*11946Sjohansen@sun.com 		return (NULL);
453*11946Sjohansen@sun.com 
454*11946Sjohansen@sun.com 	return (&modinfo);
455*11946Sjohansen@sun.com }
456*11946Sjohansen@sun.com 
457*11946Sjohansen@sun.com void
_mdb_fini(void)458*11946Sjohansen@sun.com _mdb_fini(void)
459*11946Sjohansen@sun.com {
460*11946Sjohansen@sun.com 	python_db_fini();
461*11946Sjohansen@sun.com }
462