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