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