rust/cargo-c: update to 0.10.7+cargo-0.84.0
[oi-userland.git] / components / python / python37 / patches / 08-py_db.patch
blobb0dc914cde71e58c7d5314f67badff3e41abe90f
1 This patch adds Python debugger support. It may be contributed upstream at
2 some point, but the suitability (or lack thereof) has not yet been determined.
4 --- Python-3.7.5/Makefile.pre.in
5 +++ Python-3.7.5/Makefile.pre.in
6 @@ -462,7 +462,7 @@ DTRACE_DEPS = \
7 # Default target
8 all: @DEF_MAKE_ALL_RULE@
9 build_all: check-clean-src $(BUILDPYTHON) oldsharedmods sharedmods gdbhooks \
10 - Programs/_testembed python-config
11 + Programs/_testembed python-config build-py_db
13 # Check that the source is clean when building out of source.
14 check-clean-src:
15 @@ -706,6 +706,15 @@ Makefile Modules/config.c: Makefile.pre
16 @mv config.c Modules
17 @echo "The Makefile was updated, you may need to re-run make."
19 +SHLIB_FLAGS = -shared -fpic
21 +libpython$(LDVERSION)_db.so.1.0: $(srcdir)/py_db/libpython37_db.c
22 + $(CC) -o $@ $(CFLAGS) $(PY_CPPFLAGS) $(CPPFLAGS) $(SHLIB_FLAGS) $<
24 +build-py_db: libpython$(LDVERSION)_db.so.1.0
26 +install-py_db: libpython$(LDVERSION)_db.so.1.0
27 + $(INSTALL_SHARED) libpython$(LDVERSION)_db.so.1.0 $(DESTDIR)$(LIBDIR)
29 Modules/Setup: $(srcdir)/Modules/Setup.dist
30 @if test -f Modules/Setup; then \
31 @@ -1129,7 +1138,7 @@ multisslcompile: build_all
32 multissltest: build_all
33 $(RUNSHARED) ./$(BUILDPYTHON) Tools/ssl/multissltests.py
35 -install: @FRAMEWORKINSTALLFIRST@ commoninstall bininstall maninstall @FRAMEWORKINSTALLLAST@
36 +install: @FRAMEWORKINSTALLFIRST@ commoninstall bininstall maninstall install-py_db @FRAMEWORKINSTALLLAST@
37 if test "x$(ENSUREPIP)" != "xno" ; then \
38 case $(ENSUREPIP) in \
39 upgrade) ensurepip="--upgrade" ;; \
40 --- Python-3.7.5/py_db/libpython37_db.c
41 +++ Python-3.7.5/py_db/libpython37_db.c
42 @@ -0,0 +1,595 @@
43 +/*
44 + * CDDL HEADER START
45 + *
46 + * The contents of this file are subject to the terms of the
47 + * Common Development and Distribution License (the "License").
48 + * You may not use this file except in compliance with the License.
49 + *
50 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
51 + * or http://www.opensolaris.org/os/licensing.
52 + * See the License for the specific language governing permissions
53 + * and limitations under the License.
54 + *
55 + * When distributing Covered Code, include this CDDL HEADER in each
56 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
57 + * If applicable, add the following below this CDDL HEADER, with the
58 + * fields enclosed by brackets "[]" replaced with your own identifying
59 + * information: Portions Copyright [yyyy] [name of copyright owner]
60 + *
61 + * CDDL HEADER END
62 + */
63 +/*
64 + * Copyright (c) 2012, 2020, Oracle and/or its affiliates.
65 + */
67 +#include <stdio.h>
68 +#include <stdlib.h>
69 +#include <string.h>
70 +#include <errno.h>
71 +#include <gelf.h>
73 +#define Py_BUILD_CORE
75 +#include <Python.h>
76 +#include <frameobject.h>
77 +#include "internal/pystate.h"
79 +#include "libpython37_db.h"
81 +struct pydb_agent {
82 + struct ps_prochandle *pdb_ph;
83 + int pdb_vers;
84 + int pdb_is_64bit;
85 + int pdb_datamodel;
86 +};
88 +typedef uintptr_t (*pdi_next_cb_t)(pydb_iter_t *);
90 +struct pydb_iter {
91 + struct ps_prochandle *pdi_ph;
92 + uintptr_t pdi_current;
93 + pdi_next_cb_t pdi_nextf;
94 +};
96 +#define LIBPYTHON "libpython3.7m.so"
98 +#define MIN(x, y) (((x) < (y)) ? (x) : (y))
100 +/* Generic interface to helper functions */
101 +static ssize_t pydb_strobj_readdata(pydb_agent_t *py, uintptr_t addr,
102 + unsigned char *buf, size_t buf_len);
103 +static int pydb_getlno(pydb_agent_t *py, uintptr_t lnotab_addr, int firstline,
104 + int lastinst);
105 +static int pydb_frameinfo(pydb_agent_t *py, uintptr_t addr, char *funcnm,
106 + size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno);
108 +/* datamodel specific implementation of helper functions */
109 +static ssize_t pydb_strobj_readdata_native(pydb_agent_t *py, uintptr_t addr,
110 + unsigned char *buf, size_t buf_len);
111 +static int pydb_frameinfo_native(pydb_agent_t *py, uintptr_t addr, char *funcnm,
112 + size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno);
114 +static ssize_t pydb_strobj_readstr(pydb_agent_t *py, uintptr_t addr, char *buf,
115 + size_t len);
117 +/* Iterator function next routines. Plugable, configured by iterator init */
118 +static uintptr_t pydb_frame_iter_next(pydb_iter_t *iter);
119 +static uintptr_t pydb_interp_iter_next(pydb_iter_t *iter);
120 +static uintptr_t pydb_thread_iter_next(pydb_iter_t *iter);
122 +static const char *strbasename(const char *s);
124 +static const char *
125 +strbasename(const char *s)
127 + const char *p = strrchr(s, '/');
129 + if (p == NULL)
130 + return (s);
132 + return (++p);
135 +/* Agent creation / destruction routines */
137 +pydb_agent_t *
138 +pydb_agent_create(struct ps_prochandle *P, int vers)
140 + pydb_agent_t *py;
141 + int datamodel;
143 + if (vers != PYDB_VERSION) {
144 + errno = ENOTSUP;
145 + return (NULL);
148 + if (ps_pdmodel(P, &datamodel) != PS_OK) {
149 + return (NULL);
152 + py = (pydb_agent_t *)malloc(sizeof (pydb_agent_t));
153 + if (py == NULL) {
154 + return (NULL);
157 + py->pdb_ph = P;
158 + py->pdb_vers = vers;
159 + py->pdb_datamodel = datamodel;
160 + py->pdb_is_64bit = 0;
162 + return (py);
165 +void
166 +pydb_agent_destroy(pydb_agent_t *py)
168 + if (py == NULL) {
169 + return;
172 + free(py);
175 +/* Helper functions */
176 +static int
177 +pydb_getlno(pydb_agent_t *py, uintptr_t lnotab_addr, int firstline,
178 + int lastinst)
180 + unsigned char lnotab[4096];
181 + ssize_t lnotab_len;
182 + int addr, line;
183 + int i;
185 + lnotab_len = pydb_strobj_readdata(py, lnotab_addr, lnotab,
186 + sizeof (lnotab));
187 + if (lnotab_len < 0) {
188 + return (-1);
191 + /*
192 + * Python's line number algorithm is arcane. See here for details:
193 + * http://svn.python.org/projects/python/trunk/Objects/lnotab_notes.txt
194 + */
196 + line = firstline;
197 + for (addr = i = 0; i < lnotab_len; i += 2) {
198 + if (addr + lnotab[i] > lastinst) {
199 + break;
201 + addr += lnotab[i];
202 + line += lnotab[i + 1];
205 + return (line);
208 +static ssize_t
209 +pydb_asciiobj_readdata(pydb_agent_t *py, uintptr_t addr,
210 + unsigned char *buf, size_t buf_len)
212 + PyASCIIObject sobj;
213 + ssize_t obj_sz;
214 + ssize_t read_sz;
215 + psaddr_t asciiaddr;
217 + /*
218 + * PyASCIIObjects are a type of Unicode string. They are identified
219 + * as follows:
220 + * - sobj.state.compact == 1
221 + * - sobj.state.ascii == 1
222 + * - sobj.state.ready == 1
223 + * The length of the string is stored in sobj.length. The string
224 + * itself follows the PyASCIIObject.
225 + */
227 + if (ps_pread(py->pdb_ph, addr, &sobj, sizeof (PyASCIIObject))
228 + != PS_OK) {
229 + return (-1);
232 + if (!sobj.state.compact || !sobj.state.ascii || !sobj.state.ready) {
233 + return (-1);
236 + obj_sz = (ssize_t)sobj.length;
238 + read_sz = MIN(obj_sz, (ssize_t)buf_len);
239 + asciiaddr = (psaddr_t)(addr + sizeof (PyASCIIObject));
241 + if (ps_pread(py->pdb_ph, asciiaddr, buf, (size_t)read_sz) != PS_OK) {
242 + return (-1);
245 + return (read_sz);
248 +static ssize_t
249 +pydb_asciiobj_readstr(pydb_agent_t *py, uintptr_t addr, char *buf,
250 + size_t buf_len)
252 + ssize_t read_sz;
254 + read_sz = pydb_asciiobj_readdata(py, addr, (unsigned char *)buf,
255 + buf_len);
257 + if (read_sz >= 0) {
258 + if (read_sz >= buf_len) {
259 + read_sz = buf_len - 1;
262 + buf[read_sz] = '\0';
265 + return (read_sz);
268 +static ssize_t
269 +pydb_strobj_readdata(pydb_agent_t *py, uintptr_t addr,
270 + unsigned char *buf, size_t buf_len)
272 + PyBytesObject sobj;
273 + ssize_t obj_sz;
274 + ssize_t read_sz;
275 + psaddr_t straddr;
277 + /*
278 + * PyBytesObject are variable size. The size of the PyBytesObject
279 + * struct is fixed, and known at compile time; however, the size of the
280 + * associated buffer is variable. The char[1] element at the end of the
281 + * structure contains the string, and the ob_size of the PyBytesObject
282 + * indicates how much extra space was allocated to contain the string
283 + * buffer at the object's tail. Read in the fixed size portion of the
284 + * object first, and then read the contents of the data buffer into the
285 + * buffer passed by the caller.
286 + */
288 + if (ps_pread(py->pdb_ph, addr, &sobj, sizeof (PyBytesObject))
289 + != PS_OK) {
290 + return (-1);
293 + /*
294 + * If we want to emulate PyBytes_GET_SIZE() instead of just calling
295 + * Py_SIZE() directly, we need to do a ps_pread() of Py_TYPE(&sobj).
296 + * PyBytes_Check() will try to access the type structure, but the
297 + * address is not in the debugger's address space.
298 + */
299 + obj_sz = (ssize_t)Py_SIZE(&sobj);
301 + read_sz = MIN(obj_sz, (ssize_t)buf_len);
302 + straddr = (psaddr_t)(addr + offsetof(PyBytesObject, ob_sval));
304 + if (ps_pread(py->pdb_ph, straddr, buf, (size_t)read_sz) != PS_OK) {
305 + return (-1);
308 + return (read_sz);
312 + * Most Python PyBytesObject contain strings, as one would expect. However,
313 + * due to some sleazy hackery in parts of the Python code, some string objects
314 + * are used as buffers for binary data. In the general case,
315 + * pydb_strobj_readstr() should be used to read strings out of string objects.
316 + * It wraps pydb_strobj_readdata(), which should be used by callers only when
317 + * trying to retrieve binary data. (This routine does some string cleanup).
318 + */
319 +static ssize_t
320 +pydb_strobj_readstr(pydb_agent_t *py, uintptr_t addr, char *buf,
321 + size_t buf_len)
323 + ssize_t read_sz;
325 + read_sz = pydb_strobj_readdata(py, addr, (unsigned char *)buf, buf_len);
327 + if (read_sz >= 0) {
328 + if (read_sz >= buf_len) {
329 + read_sz = buf_len - 1;
332 + buf[read_sz] = '\0';
335 + return (read_sz);
339 +static int
340 +pydb_frameinfo(pydb_agent_t *py, uintptr_t addr, char *funcnm,
341 + size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno)
343 + PyFrameObject fo;
344 + PyCodeObject co;
345 + ssize_t rc;
347 + if (ps_pread(py->pdb_ph, addr, &fo, sizeof (PyFrameObject))
348 + != PS_OK) {
349 + return (-1);
352 + if (ps_pread(py->pdb_ph, (uintptr_t)fo.f_code, &co,
353 + sizeof (PyCodeObject)) != PS_OK) {
354 + return (-1);
357 + rc = pydb_asciiobj_readstr(py, (uintptr_t)co.co_name, funcnm,
358 + funcnm_sz);
359 + if (rc < 0) {
360 + return (-1);
363 + rc = pydb_asciiobj_readstr(py, (uintptr_t)co.co_filename, filenm,
364 + filenm_sz);
365 + if (rc < 0) {
366 + return (-1);
369 + *lineno = pydb_getlno(py, (uintptr_t)co.co_lnotab, co.co_firstlineno,
370 + fo.f_lasti);
371 + if (*lineno < 0) {
372 + return (-1);
375 + return (0);
378 +/* Functions that are part of the library's interface */
381 + * Given the address of a PyFrameObject, and a buffer of a known size,
382 + * fill the buffer with a description of the frame.
383 + */
384 +int
385 +pydb_get_frameinfo(pydb_agent_t *py, uintptr_t frame_addr, char *fbuf,
386 + size_t bufsz, int verbose)
388 + char funcname[1024];
389 + char filename[1024];
390 + char *fn;
391 + int lineno;
392 + int length = (py->pdb_is_64bit ? 16 : 8);
393 + int rc;
395 + rc = pydb_frameinfo(py, frame_addr, funcname, sizeof (funcname),
396 + filename, sizeof (filename), &lineno);
397 + if (rc < 0) {
398 + return (-1);
401 + if (!verbose) {
402 + fn = (char *)strbasename(filename);
403 + } else {
404 + fn = filename;
407 + (void) snprintf(fbuf, bufsz, "%0.*lx %s:%d %s()\n", length,
408 + frame_addr, fn, lineno, funcname);
410 + return (0);
414 + * Return a description about a PyFrameObject, if the object is
415 + * actually a PyFrameObject. In this case, the pc argument is checked
416 + * to make sure that it came from a function that takes a PyFrameObject
417 + * as its first (argv[0]) argument.
418 + */
419 +int
420 +pydb_pc_frameinfo(pydb_agent_t *py, uintptr_t pc, uintptr_t frame_addr,
421 + char *fbuf, size_t bufsz)
423 + char funcname[1024];
424 + char filename[1024];
425 + int lineno;
426 + int rc;
427 + ps_sym_t psym;
429 + /*
430 + * If PC doesn't match PyEval_EvalFrameEx in either libpython
431 + * or the executable, don't decode it.
432 + */
433 + if (ps_pglobal_sym(py->pdb_ph, LIBPYTHON, "PyEval_EvalFrameEx", &psym)
434 + != PS_OK) {
435 + return (-1);
438 + /* If symbol found, ensure that PC falls within PyEval_EvalFrameEx. */
439 + if (pc < psym.st_value || pc > psym.st_value + psym.st_size) {
440 + return (-1);
443 + rc = pydb_frameinfo(py, frame_addr, funcname, sizeof (funcname),
444 + filename, sizeof (filename), &lineno);
445 + if (rc < 0) {
446 + return (-1);
449 + (void) snprintf(fbuf, bufsz, "[ %s:%d (%s) ]\n", filename, lineno,
450 + funcname);
452 + return (0);
456 + * Walks the list of PyInterpreterState objects. If caller doesn't
457 + * supply address of list, this method will look it up.
458 + */
459 +pydb_iter_t *
460 +pydb_interp_iter_init(pydb_agent_t *py, uintptr_t addr)
462 + pydb_iter_t *itr;
463 + _PyRuntimeState st;
464 + uintptr_t i_addr;
465 + int rc;
467 + if (addr == 0) {
468 + rc = ps_pglobal_lookup(py->pdb_ph, LIBPYTHON, "_PyRuntime",
469 + (psaddr_t *)&addr);
470 + if (rc != PS_OK) {
471 + return (NULL);
474 + if (ps_pread(py->pdb_ph, (uintptr_t)addr, &st, sizeof (_PyRuntimeState))
475 + != PS_OK) {
476 + return (NULL);
479 + i_addr = (uintptr_t)st.interpreters.head;
481 + } else {
482 + if (ps_pread(py->pdb_ph, (uintptr_t)addr, &i_addr, sizeof (uintptr_t))
483 + != PS_OK) {
484 + return (NULL);
488 + itr = malloc(sizeof (pydb_iter_t));
489 + if (itr == NULL) {
490 + return (NULL);
493 + itr->pdi_ph = py->pdb_ph;
494 + itr->pdi_current = i_addr;
495 + itr->pdi_nextf = pydb_interp_iter_next;
497 + return (itr);
500 +static uintptr_t
501 +pydb_interp_iter_next(pydb_iter_t *iter)
503 + PyInterpreterState st;
504 + uintptr_t cur;
506 + cur = iter->pdi_current;
508 + if (cur == 0) {
509 + return (cur);
512 + if (ps_pread(iter->pdi_ph, cur, &st, sizeof (PyInterpreterState))
513 + != PS_OK) {
514 + iter->pdi_current = 0;
515 + return (0);
518 + iter->pdi_current = (uintptr_t)st.next;
520 + return (cur);
524 + * Walk a list of Python PyFrameObjects. The addr argument must be
525 + * the address of a valid PyThreadState object.
526 + */
527 +pydb_iter_t *
528 +pydb_frame_iter_init(pydb_agent_t *py, uintptr_t addr)
530 + pydb_iter_t *itr;
531 + PyThreadState ts;
533 + if (ps_pread(py->pdb_ph, (uintptr_t)addr, &ts, sizeof (PyThreadState))
534 + != PS_OK) {
535 + return (NULL);
538 + itr = malloc(sizeof (pydb_iter_t));
539 + if (itr == NULL) {
540 + return (NULL);
543 + itr->pdi_ph = py->pdb_ph;
544 + itr->pdi_current = (uintptr_t)ts.frame;
545 + itr->pdi_nextf = pydb_frame_iter_next;
547 + return (itr);
550 +static uintptr_t
551 +pydb_frame_iter_next(pydb_iter_t *iter)
553 + PyFrameObject fo;
554 + uintptr_t cur;
556 + cur = iter->pdi_current;
558 + if (cur == 0) {
559 + return (cur);
562 + if (ps_pread(iter->pdi_ph, cur, &fo, sizeof (PyFrameObject))
563 + != PS_OK) {
564 + iter->pdi_current = 0;
565 + return (0);
568 + iter->pdi_current = (uintptr_t)fo.f_back;
570 + return (cur);
574 + * Walk a list of Python PyThreadState objects. The addr argument must be
575 + * the address of a valid PyInterpreterState object.
576 + */
577 +pydb_iter_t *
578 +pydb_thread_iter_init(pydb_agent_t *py, uintptr_t addr)
580 + pydb_iter_t *itr;
581 + PyInterpreterState is;
583 + if (ps_pread(py->pdb_ph, (uintptr_t)addr, &is,
584 + sizeof (PyInterpreterState)) != PS_OK) {
585 + return (NULL);
588 + itr = malloc(sizeof (pydb_iter_t));
589 + if (itr == NULL) {
590 + return (NULL);
593 + itr->pdi_ph = py->pdb_ph;
594 + itr->pdi_current = (uintptr_t)is.tstate_head;
595 + itr->pdi_nextf = pydb_thread_iter_next;
597 + return (itr);
600 +static uintptr_t
601 +pydb_thread_iter_next(pydb_iter_t *iter)
603 + PyThreadState ts;
604 + uintptr_t cur;
606 + cur = iter->pdi_current;
608 + if (cur == 0) {
609 + return (cur);
612 + if (ps_pread(iter->pdi_ph, cur, &ts, sizeof (PyThreadState)) != PS_OK) {
613 + iter->pdi_current = 0;
614 + return (0);
617 + iter->pdi_current = (uintptr_t)ts.next;
619 + return (cur);
623 +uintptr_t
624 +pydb_iter_next(pydb_iter_t *iter)
626 + return (iter->pdi_nextf(iter));
629 +void
630 +pydb_iter_fini(pydb_iter_t *iter)
632 + if (iter == NULL) {
633 + return;
636 + free(iter);
638 --- Python-3.7.5/py_db/libpython37_db.h
639 +++ Python-3.7.5/py_db/libpython37_db.h
640 @@ -0,0 +1,73 @@
642 + * CDDL HEADER START
644 + * The contents of this file are subject to the terms of the
645 + * Common Development and Distribution License (the "License").
646 + * You may not use this file except in compliance with the License.
648 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
649 + * or http://www.opensolaris.org/os/licensing.
650 + * See the License for the specific language governing permissions
651 + * and limitations under the License.
653 + * When distributing Covered Code, include this CDDL HEADER in each
654 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
655 + * If applicable, add the following below this CDDL HEADER, with the
656 + * fields enclosed by brackets "[]" replaced with your own identifying
657 + * information: Portions Copyright [yyyy] [name of copyright owner]
659 + * CDDL HEADER END
660 + */
662 + * Copyright (c) 2012, 2020, Oracle and/or its affiliates.
663 + */
665 +#ifndef _LIBPYTHON37_DB_H
666 +#define _LIBPYTHON37_DB_H
668 +#include <proc_service.h>
670 +#ifdef __cplusplus
671 +extern "C" {
672 +#endif
674 +/* Agent is opaque to library's consumers. */
675 +typedef struct pydb_agent pydb_agent_t;
678 + * Library's debug version is 1. Changes to interface should increase this
679 + * number.
680 + */
681 +#define PYDB_VERSION 1
683 +/* Agent creation/destruction routines */
684 +extern pydb_agent_t *pydb_agent_create(struct ps_prochandle *P, int vers);
685 +extern void pydb_agent_destroy(pydb_agent_t *py);
687 +/* Used by callers that know they are looking at a PyFrameObject */
688 +extern int pydb_get_frameinfo(pydb_agent_t *py, uintptr_t frame_addr,
689 + char *fbuf, size_t bufsz, int verbose);
692 + * Used by callers that don't know if they're looking at PyFrameObject.
693 + * Checks PC for traceable functions.
694 + */
695 +extern int pydb_pc_frameinfo(pydb_agent_t *py, uintptr_t pc,
696 + uintptr_t frame_addr, char *fbuf, size_t bufsz);
698 +/* Iterator functions */
699 +typedef struct pydb_iter pydb_iter_t;
701 +extern pydb_iter_t *pydb_frame_iter_init(pydb_agent_t *py, uintptr_t addr);
702 +extern pydb_iter_t *pydb_interp_iter_init(pydb_agent_t *py,
703 + uintptr_t addr);
704 +extern pydb_iter_t *pydb_thread_iter_init(pydb_agent_t *py,
705 + uintptr_t addr);
706 +extern void pydb_iter_fini(pydb_iter_t *iter);
707 +extern uintptr_t pydb_iter_next(pydb_iter_t *iter);
709 +#ifdef __cplusplus
711 +#endif
713 +#endif /* _LIBPYTHON37_DB_H */
714 --- Python-3.7.5/py_db/mapfile-vers
715 +++ Python-3.7.5/py_db/mapfile-vers
716 @@ -0,0 +1,39 @@
718 +# CDDL HEADER START
720 +# The contents of this file are subject to the terms of the
721 +# Common Development and Distribution License (the "License").
722 +# You may not use this file except in compliance with the License.
724 +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
725 +# or http://www.opensolaris.org/os/licensing.
726 +# See the License for the specific language governing permissions
727 +# and limitations under the License.
729 +# When distributing Covered Code, include this CDDL HEADER in each
730 +# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
731 +# If applicable, add the following below this CDDL HEADER, with the
732 +# fields enclosed by brackets "[]" replaced with your own identifying
733 +# information: Portions Copyright [yyyy] [name of copyright owner]
735 +# CDDL HEADER END
739 +# Copyright (c) 2012, 2020, Oracle and/or its affiliates.
742 +SUNWprivate_1.1 {
743 + global:
744 + pydb_agent_create;
745 + pydb_agent_destroy;
746 + pydb_frame_iter_init;
747 + pydb_get_frameinfo;
748 + pydb_pc_frameinfo;
749 + pydb_interp_iter_init;
750 + pydb_thread_iter_init;
751 + pydb_iter_fini;
752 + pydb_iter_next;
753 + local:
754 + *;