jenkins-core-weekly: update to 2.491
[oi-userland.git] / components / python / python39 / patches / 08-py_db.patch
blobd1ec9dc6d3d4b473f96b6668b9ad0238667e87be
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.9.1/Makefile.pre.in
5 +++ Python-3.9.1/Makefile.pre.in
6 @@ -472,7 +472,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 @@ -720,6 +720,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/libpython39_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 Programs/_testembed: Programs/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) $(EXPORTSYMS)
30 $(LINKCC) $(PY_CORE_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS)
31 @@ -1239,7 +1248,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.9.18/py_db/libpython39_db.c.~1~ 2024-02-12 12:48:39.903737823 -0800
41 +++ Python-3.9.18/py_db/libpython39_db.c 2024-02-12 13:04:54.724880396 -0800
42 @@ -0,0 +1,633 @@
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/pycore_runtime.h"
78 +#include "internal/pycore_interp.h"
80 +#include "libpython39_db.h"
82 +/* Maximum number of pieces of the core eval function */
83 +#define NEVAL 2
84 +struct pydb_code_range {
85 + uintptr_t base;
86 + size_t size;
87 +};
89 +struct pydb_agent {
90 + struct ps_prochandle *pdb_ph;
91 + int pdb_vers;
92 + int pdb_is_64bit:1;
93 + int pdb_has_eval:1;
94 + int pdb_datamodel;
95 + struct pydb_code_range pdb_eval_code[NEVAL];
96 +};
98 +typedef uintptr_t (*pdi_next_cb_t)(pydb_iter_t *);
100 +struct pydb_iter {
101 + struct ps_prochandle *pdi_ph;
102 + uintptr_t pdi_current;
103 + pdi_next_cb_t pdi_nextf;
106 +#define LIBPYTHON "libpython3.9.so"
108 +#define MIN(x, y) (((x) < (y)) ? (x) : (y))
110 +/* Generic interface to helper functions */
111 +static ssize_t pydb_strobj_readdata(pydb_agent_t *py, uintptr_t addr,
112 + unsigned char *buf, size_t buf_len);
113 +static int pydb_getlno(pydb_agent_t *py, uintptr_t lnotab_addr, int firstline,
114 + int lastinst);
115 +static int pydb_frameinfo(pydb_agent_t *py, uintptr_t addr, char *funcnm,
116 + size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno);
118 +/* datamodel specific implementation of helper functions */
119 +static ssize_t pydb_strobj_readdata_native(pydb_agent_t *py, uintptr_t addr,
120 + unsigned char *buf, size_t buf_len);
121 +static int pydb_frameinfo_native(pydb_agent_t *py, uintptr_t addr, char *funcnm,
122 + size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno);
124 +static ssize_t pydb_strobj_readstr(pydb_agent_t *py, uintptr_t addr, char *buf,
125 + size_t len);
127 +/* Iterator function next routines. Plugable, configured by iterator init */
128 +static uintptr_t pydb_frame_iter_next(pydb_iter_t *iter);
129 +static uintptr_t pydb_interp_iter_next(pydb_iter_t *iter);
130 +static uintptr_t pydb_thread_iter_next(pydb_iter_t *iter);
132 +static const char *strbasename(const char *s);
134 +static const char *
135 +strbasename(const char *s)
137 + const char *p = strrchr(s, '/');
139 + if (p == NULL)
140 + return (s);
142 + return (++p);
145 +/* Agent creation / destruction routines */
147 +pydb_agent_t *
148 +pydb_agent_create(struct ps_prochandle *P, int vers)
150 + pydb_agent_t *py;
151 + int datamodel;
153 + if (vers != PYDB_VERSION) {
154 + errno = ENOTSUP;
155 + return (NULL);
158 + if (ps_pdmodel(P, &datamodel) != PS_OK) {
159 + return (NULL);
162 + py = (pydb_agent_t *)malloc(sizeof (pydb_agent_t));
163 + if (py == NULL) {
164 + return (NULL);
167 + py->pdb_ph = P;
168 + py->pdb_vers = vers;
169 + py->pdb_datamodel = datamodel;
170 + py->pdb_is_64bit = 0;
172 + return (py);
175 +void
176 +pydb_agent_destroy(pydb_agent_t *py)
178 + if (py == NULL) {
179 + return;
182 + free(py);
185 +/* Helper functions */
186 +static int
187 +pydb_getlno(pydb_agent_t *py, uintptr_t lnotab_addr, int firstline,
188 + int lastinst)
190 + unsigned char lnotab[4096];
191 + ssize_t lnotab_len;
192 + int addr, line;
193 + int i;
195 + lnotab_len = pydb_strobj_readdata(py, lnotab_addr, lnotab,
196 + sizeof (lnotab));
197 + if (lnotab_len < 0) {
198 + return (-1);
201 + /*
202 + * Python's line number algorithm is arcane. See here for details:
203 + * https://github.com/python/cpython/blob/main/Objects/lnotab_notes.txt
204 + */
206 + line = firstline;
207 + for (addr = i = 0; i < lnotab_len; i += 2) {
208 + int addr_incr = lnotab[i];
209 + int line_incr = lnotab[i+1];
211 + addr += addr_incr;
212 + if (addr > lastinst) {
213 + break;
215 + if (line_incr > 0x80) {
216 + line_incr -= 0x100;
218 + line += line_incr;
221 + return (line);
224 +static ssize_t
225 +pydb_asciiobj_readdata(pydb_agent_t *py, uintptr_t addr,
226 + unsigned char *buf, size_t buf_len)
228 + PyASCIIObject sobj;
229 + ssize_t obj_sz;
230 + ssize_t read_sz;
231 + psaddr_t asciiaddr;
233 + /*
234 + * PyASCIIObjects are a type of Unicode string. They are identified
235 + * as follows:
236 + * - sobj.state.compact == 1
237 + * - sobj.state.ascii == 1
238 + * - sobj.state.ready == 1
239 + * The length of the string is stored in sobj.length. The string
240 + * itself follows the PyASCIIObject.
241 + */
243 + if (ps_pread(py->pdb_ph, addr, &sobj, sizeof (PyASCIIObject))
244 + != PS_OK) {
245 + return (-1);
248 + if (!sobj.state.compact || !sobj.state.ascii || !sobj.state.ready) {
249 + return (-1);
252 + obj_sz = (ssize_t)sobj.length;
254 + read_sz = MIN(obj_sz, (ssize_t)buf_len);
255 + asciiaddr = (psaddr_t)(addr + sizeof (PyASCIIObject));
257 + if (ps_pread(py->pdb_ph, asciiaddr, buf, (size_t)read_sz) != PS_OK) {
258 + return (-1);
261 + return (read_sz);
264 +static ssize_t
265 +pydb_asciiobj_readstr(pydb_agent_t *py, uintptr_t addr, char *buf,
266 + size_t buf_len)
268 + ssize_t read_sz;
270 + read_sz = pydb_asciiobj_readdata(py, addr, (unsigned char *)buf,
271 + buf_len);
273 + if (read_sz >= 0) {
274 + if (read_sz >= buf_len) {
275 + read_sz = buf_len - 1;
278 + buf[read_sz] = '\0';
281 + return (read_sz);
284 +static ssize_t
285 +pydb_strobj_readdata(pydb_agent_t *py, uintptr_t addr,
286 + unsigned char *buf, size_t buf_len)
288 + PyBytesObject sobj;
289 + ssize_t obj_sz;
290 + ssize_t read_sz;
291 + psaddr_t straddr;
293 + /*
294 + * PyBytesObject are variable size. The size of the PyBytesObject
295 + * struct is fixed, and known at compile time; however, the size of the
296 + * associated buffer is variable. The char[1] element at the end of the
297 + * structure contains the string, and the ob_size of the PyBytesObject
298 + * indicates how much extra space was allocated to contain the string
299 + * buffer at the object's tail. Read in the fixed size portion of the
300 + * object first, and then read the contents of the data buffer into the
301 + * buffer passed by the caller.
302 + */
304 + if (ps_pread(py->pdb_ph, addr, &sobj, sizeof (PyBytesObject))
305 + != PS_OK) {
306 + return (-1);
309 + /*
310 + * If we want to emulate PyBytes_GET_SIZE() instead of just calling
311 + * Py_SIZE() directly, we need to do a ps_pread() of Py_TYPE(&sobj).
312 + * PyBytes_Check() will try to access the type structure, but the
313 + * address is not in the debugger's address space.
314 + */
315 + obj_sz = (ssize_t)Py_SIZE(&sobj);
317 + read_sz = MIN(obj_sz, (ssize_t)buf_len);
318 + straddr = (psaddr_t)(addr + offsetof(PyBytesObject, ob_sval));
320 + if (ps_pread(py->pdb_ph, straddr, buf, (size_t)read_sz) != PS_OK) {
321 + return (-1);
324 + return (read_sz);
328 + * Most Python PyBytesObject contain strings, as one would expect. However,
329 + * due to some sleazy hackery in parts of the Python code, some string objects
330 + * are used as buffers for binary data. In the general case,
331 + * pydb_strobj_readstr() should be used to read strings out of string objects.
332 + * It wraps pydb_strobj_readdata(), which should be used by callers only when
333 + * trying to retrieve binary data. (This routine does some string cleanup).
334 + */
335 +static ssize_t
336 +pydb_strobj_readstr(pydb_agent_t *py, uintptr_t addr, char *buf,
337 + size_t buf_len)
339 + ssize_t read_sz;
341 + read_sz = pydb_strobj_readdata(py, addr, (unsigned char *)buf, buf_len);
343 + if (read_sz >= 0) {
344 + if (read_sz >= buf_len) {
345 + read_sz = buf_len - 1;
348 + buf[read_sz] = '\0';
351 + return (read_sz);
354 +static void
355 +pydb_find_eval(pydb_agent_t *py) {
356 + ps_sym_t psym;
358 + if (ps_pglobal_sym(py->pdb_ph, LIBPYTHON, "_PyEval_EvalFrameDefault", &psym)
359 + == PS_OK) {
360 + py->pdb_eval_code[0].base = psym.st_value;
361 + py->pdb_eval_code[0].size = psym.st_size;
362 + py->pdb_has_eval = 1;
364 + if (ps_pglobal_sym(py->pdb_ph, LIBPYTHON, "_PyEval_EvalFrameDefault.cold", &psym)
365 + == PS_OK) {
366 + py->pdb_eval_code[1].base = psym.st_value;
367 + py->pdb_eval_code[1].size = psym.st_size;
368 + py->pdb_has_eval = 1;
373 +static int
374 +pydb_frameinfo(pydb_agent_t *py, uintptr_t addr, char *funcnm,
375 + size_t funcnm_sz, char *filenm, size_t filenm_sz, int *lineno)
377 + PyFrameObject fo;
378 + PyCodeObject co;
379 + ssize_t rc;
381 + if (ps_pread(py->pdb_ph, addr, &fo, sizeof (PyFrameObject))
382 + != PS_OK) {
383 + return (-1);
386 + if (ps_pread(py->pdb_ph, (uintptr_t)fo.f_code, &co,
387 + sizeof (PyCodeObject)) != PS_OK) {
388 + return (-1);
391 + rc = pydb_asciiobj_readstr(py, (uintptr_t)co.co_name, funcnm,
392 + funcnm_sz);
393 + if (rc < 0) {
394 + return (-1);
397 + rc = pydb_asciiobj_readstr(py, (uintptr_t)co.co_filename, filenm,
398 + filenm_sz);
399 + if (rc < 0) {
400 + return (-1);
403 + *lineno = pydb_getlno(py, (uintptr_t)co.co_lnotab, co.co_firstlineno,
404 + fo.f_lasti);
405 + if (*lineno < 0) {
406 + return (-1);
409 + return (0);
412 +/* Functions that are part of the library's interface */
415 + * Given the address of a PyFrameObject, and a buffer of a known size,
416 + * fill the buffer with a description of the frame.
417 + */
418 +int
419 +pydb_get_frameinfo(pydb_agent_t *py, uintptr_t frame_addr, char *fbuf,
420 + size_t bufsz, int verbose)
422 + char funcname[1024];
423 + char filename[1024];
424 + char *fn;
425 + int lineno;
426 + int length = (py->pdb_is_64bit ? 16 : 8);
427 + int rc;
429 + rc = pydb_frameinfo(py, frame_addr, funcname, sizeof (funcname),
430 + filename, sizeof (filename), &lineno);
431 + if (rc < 0) {
432 + return (-1);
435 + if (!verbose) {
436 + fn = (char *)strbasename(filename);
437 + } else {
438 + fn = filename;
441 + (void) snprintf(fbuf, bufsz, "%0.*lx %s:%d %s()\n", length,
442 + frame_addr, fn, lineno, funcname);
444 + return (0);
448 + * Return a description about a PyFrameObject, if the object is
449 + * actually a PyFrameObject. In this case, the pc argument is checked
450 + * to make sure that it came from a function that takes a PyFrameObject
451 + * as its second (argv[1]) argument.
452 + */
453 +int
454 +pydb_pc_frameinfo_argv(pydb_agent_t *py, uintptr_t pc, const long *argv,
455 + char *fbuf, size_t bufsz)
457 + char funcname[1024];
458 + char filename[1024];
459 + int lineno;
460 + int i, rc;
461 + uintptr_t frame_addr = argv[1];
463 + if (!py->pdb_has_eval) {
464 + pydb_find_eval(py);
465 + if (!py->pdb_has_eval)
466 + return (-1);
469 + /*
470 + * If the PC isn't inside one of the eval code ranges,
471 + * don't decode it.
472 + */
473 + for (i = 0; i < NEVAL; i++) {
474 + struct pydb_code_range *r = &py->pdb_eval_code[i];
476 + if (pc >= r->base && pc < (r->base + r->size)) {
478 + rc = pydb_frameinfo(py, frame_addr, funcname, sizeof (funcname),
479 + filename, sizeof (filename), &lineno);
480 + if (rc < 0) {
481 + return (-1);
484 + (void) snprintf(fbuf, bufsz, "[ %s:%d (%s) ]\n", filename, lineno,
485 + funcname);
486 + return (0);
490 + return (-1);
494 + * Walks the list of PyInterpreterState objects. If caller doesn't
495 + * supply address of list, this method will look it up.
496 + */
497 +pydb_iter_t *
498 +pydb_interp_iter_init(pydb_agent_t *py, uintptr_t addr)
500 + pydb_iter_t *itr;
501 + _PyRuntimeState st;
502 + uintptr_t i_addr;
503 + int rc;
505 + if (addr == 0) {
506 + rc = ps_pglobal_lookup(py->pdb_ph, LIBPYTHON, "_PyRuntime",
507 + (psaddr_t *)&addr);
508 + if (rc != PS_OK) {
509 + return (NULL);
512 + if (ps_pread(py->pdb_ph, (uintptr_t)addr, &st, sizeof (_PyRuntimeState))
513 + != PS_OK) {
514 + return (NULL);
517 + i_addr = (uintptr_t)st.interpreters.head;
519 + } else {
520 + if (ps_pread(py->pdb_ph, (uintptr_t)addr, &i_addr, sizeof (uintptr_t))
521 + != PS_OK) {
522 + return (NULL);
526 + itr = malloc(sizeof (pydb_iter_t));
527 + if (itr == NULL) {
528 + return (NULL);
531 + itr->pdi_ph = py->pdb_ph;
532 + itr->pdi_current = i_addr;
533 + itr->pdi_nextf = pydb_interp_iter_next;
535 + return (itr);
538 +static uintptr_t
539 +pydb_interp_iter_next(pydb_iter_t *iter)
541 + PyInterpreterState st;
542 + uintptr_t cur;
544 + cur = iter->pdi_current;
546 + if (cur == 0) {
547 + return (cur);
550 + if (ps_pread(iter->pdi_ph, cur, &st, sizeof (PyInterpreterState))
551 + != PS_OK) {
552 + iter->pdi_current = 0;
553 + return (0);
556 + iter->pdi_current = (uintptr_t)st.next;
558 + return (cur);
562 + * Walk a list of Python PyFrameObjects. The addr argument must be
563 + * the address of a valid PyThreadState object.
564 + */
565 +pydb_iter_t *
566 +pydb_frame_iter_init(pydb_agent_t *py, uintptr_t addr)
568 + pydb_iter_t *itr;
569 + PyThreadState ts;
571 + if (ps_pread(py->pdb_ph, (uintptr_t)addr, &ts, sizeof (PyThreadState))
572 + != PS_OK) {
573 + return (NULL);
576 + itr = malloc(sizeof (pydb_iter_t));
577 + if (itr == NULL) {
578 + return (NULL);
581 + itr->pdi_ph = py->pdb_ph;
582 + itr->pdi_current = (uintptr_t)ts.frame;
583 + itr->pdi_nextf = pydb_frame_iter_next;
585 + return (itr);
588 +static uintptr_t
589 +pydb_frame_iter_next(pydb_iter_t *iter)
591 + PyFrameObject fo;
592 + uintptr_t cur;
594 + cur = iter->pdi_current;
596 + if (cur == 0) {
597 + return (cur);
600 + if (ps_pread(iter->pdi_ph, cur, &fo, sizeof (PyFrameObject))
601 + != PS_OK) {
602 + iter->pdi_current = 0;
603 + return (0);
606 + iter->pdi_current = (uintptr_t)fo.f_back;
608 + return (cur);
612 + * Walk a list of Python PyThreadState objects. The addr argument must be
613 + * the address of a valid PyInterpreterState object.
614 + */
615 +pydb_iter_t *
616 +pydb_thread_iter_init(pydb_agent_t *py, uintptr_t addr)
618 + pydb_iter_t *itr;
619 + PyInterpreterState is;
621 + if (ps_pread(py->pdb_ph, (uintptr_t)addr, &is,
622 + sizeof (PyInterpreterState)) != PS_OK) {
623 + return (NULL);
626 + itr = malloc(sizeof (pydb_iter_t));
627 + if (itr == NULL) {
628 + return (NULL);
631 + itr->pdi_ph = py->pdb_ph;
632 + itr->pdi_current = (uintptr_t)is.tstate_head;
633 + itr->pdi_nextf = pydb_thread_iter_next;
635 + return (itr);
638 +static uintptr_t
639 +pydb_thread_iter_next(pydb_iter_t *iter)
641 + PyThreadState ts;
642 + uintptr_t cur;
644 + cur = iter->pdi_current;
646 + if (cur == 0) {
647 + return (cur);
650 + if (ps_pread(iter->pdi_ph, cur, &ts, sizeof (PyThreadState)) != PS_OK) {
651 + iter->pdi_current = 0;
652 + return (0);
655 + iter->pdi_current = (uintptr_t)ts.next;
657 + return (cur);
661 +uintptr_t
662 +pydb_iter_next(pydb_iter_t *iter)
664 + return (iter->pdi_nextf(iter));
667 +void
668 +pydb_iter_fini(pydb_iter_t *iter)
670 + if (iter == NULL) {
671 + return;
674 + free(iter);
676 --- Python-3.9.18/py_db/libpython39_db.h.~1~ 2024-02-12 12:48:39.904029254 -0800
677 +++ Python-3.9.18/py_db/libpython39_db.h 2024-02-12 13:04:59.939924305 -0800
678 @@ -0,0 +1,73 @@
680 + * CDDL HEADER START
682 + * The contents of this file are subject to the terms of the
683 + * Common Development and Distribution License (the "License").
684 + * You may not use this file except in compliance with the License.
686 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
687 + * or http://www.opensolaris.org/os/licensing.
688 + * See the License for the specific language governing permissions
689 + * and limitations under the License.
691 + * When distributing Covered Code, include this CDDL HEADER in each
692 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
693 + * If applicable, add the following below this CDDL HEADER, with the
694 + * fields enclosed by brackets "[]" replaced with your own identifying
695 + * information: Portions Copyright [yyyy] [name of copyright owner]
697 + * CDDL HEADER END
698 + */
700 + * Copyright (c) 2012, 2020, Oracle and/or its affiliates.
701 + */
703 +#ifndef _LIBPYTHON39_DB_H
704 +#define _LIBPYTHON39_DB_H
706 +#include <proc_service.h>
708 +#ifdef __cplusplus
709 +extern "C" {
710 +#endif
712 +/* Agent is opaque to library's consumers. */
713 +typedef struct pydb_agent pydb_agent_t;
716 + * Library's debug version is 1. Changes to interface should increase this
717 + * number.
718 + */
719 +#define PYDB_VERSION 1
721 +/* Agent creation/destruction routines */
722 +extern pydb_agent_t *pydb_agent_create(struct ps_prochandle *P, int vers);
723 +extern void pydb_agent_destroy(pydb_agent_t *py);
725 +/* Used by callers that know they are looking at a PyFrameObject */
726 +extern int pydb_get_frameinfo(pydb_agent_t *py, uintptr_t frame_addr,
727 + char *fbuf, size_t bufsz, int verbose);
730 + * Used by callers that don't know if they're looking at PyFrameObject.
731 + * Checks PC for traceable functions.
732 + */
733 +extern int pydb_pc_frameinfo_argv(pydb_agent_t *py, uintptr_t pc,
734 + const long *argv, char *fbuf, size_t bufsz);
736 +/* Iterator functions */
737 +typedef struct pydb_iter pydb_iter_t;
739 +extern pydb_iter_t *pydb_frame_iter_init(pydb_agent_t *py, uintptr_t addr);
740 +extern pydb_iter_t *pydb_interp_iter_init(pydb_agent_t *py,
741 + uintptr_t addr);
742 +extern pydb_iter_t *pydb_thread_iter_init(pydb_agent_t *py,
743 + uintptr_t addr);
744 +extern void pydb_iter_fini(pydb_iter_t *iter);
745 +extern uintptr_t pydb_iter_next(pydb_iter_t *iter);
747 +#ifdef __cplusplus
749 +#endif
751 +#endif /* _LIBPYTHON39_DB_H */
752 --- Python-3.9.1/py_db/mapfile-vers
753 +++ Python-3.9.1/py_db/mapfile-vers
754 @@ -0,0 +1,39 @@
756 +# CDDL HEADER START
758 +# The contents of this file are subject to the terms of the
759 +# Common Development and Distribution License (the "License").
760 +# You may not use this file except in compliance with the License.
762 +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
763 +# or http://www.opensolaris.org/os/licensing.
764 +# See the License for the specific language governing permissions
765 +# and limitations under the License.
767 +# When distributing Covered Code, include this CDDL HEADER in each
768 +# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
769 +# If applicable, add the following below this CDDL HEADER, with the
770 +# fields enclosed by brackets "[]" replaced with your own identifying
771 +# information: Portions Copyright [yyyy] [name of copyright owner]
773 +# CDDL HEADER END
777 +# Copyright (c) 2012, 2020, Oracle and/or its affiliates.
780 +SUNWprivate_1.1 {
781 + global:
782 + pydb_agent_create;
783 + pydb_agent_destroy;
784 + pydb_frame_iter_init;
785 + pydb_get_frameinfo;
786 + pydb_pc_frameinfo_argv;
787 + pydb_interp_iter_init;
788 + pydb_thread_iter_init;
789 + pydb_iter_fini;
790 + pydb_iter_next;
791 + local:
792 + *;