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