1+ /* This code was taken from https://github.com/GoogleCloudPlatform/cloud-profiler-python/blob/main/googlecloudprofiler/src/populate_frames.cc */
2+
3+ #include "populate_frames.h"
4+
5+ #include <Python.h>
6+
7+
8+ // 0x030B0000 is 3.11.
9+ #define PY_311 0x030B0000
10+ #if PY_VERSION_HEX >= PY_311
11+
12+ /**
13+ * The PyFrameObject structure members have been removed from the public C API
14+ * in 3.11:
15+ https://docs.python.org/3/whatsnew/3.11.html#pyframeobject-3-11-hiding.
16+ *
17+ * Instead, getters are provided which participate in reference counting; since
18+ * this code runs as part of the SIGPROF handler, it cannot modify Python
19+ * objects (including their refcounts) and the getters can't be used. Instead,
20+ * we expose the internal _PyInterpreterFrame and use that directly.
21+ *
22+ */
23+
24+ #define Py_BUILD_CORE
25+ #include "internal/pycore_frame.h"
26+ #undef Py_BUILD_CORE
27+
28+ // Modified from
29+ // https://github.com/python/cpython/blob/v3.11.4/Python/pystate.c#L1278-L1285
30+ _PyInterpreterFrame * unsafe_PyThreadState_GetInterpreterFrame (
31+ PyThreadState * tstate ) {
32+ assert (tstate != NULL );
33+ _PyInterpreterFrame * f = tstate -> cframe -> current_frame ;
34+ while (f && _PyFrame_IsIncomplete (f )) {
35+ f = f -> previous ;
36+ }
37+ if (f == NULL ) {
38+ return NULL ;
39+ }
40+ return f ;
41+ }
42+
43+ // Modified from
44+ // https://github.com/python/cpython/blob/v3.11.4/Objects/frameobject.c#L1310-L1315
45+ // with refcounting removed
46+ PyCodeObject * unsafe_PyInterpreterFrame_GetCode (
47+ _PyInterpreterFrame * frame ) {
48+ assert (frame != NULL );
49+ assert (!_PyFrame_IsIncomplete (frame ));
50+ PyCodeObject * code = frame -> f_code ;
51+ assert (code != NULL );
52+ return code ;
53+ }
54+
55+ // Modified from
56+ // https://github.com/python/cpython/blob/v3.11.4/Objects/frameobject.c#L1326-L1329
57+ // with refcounting removed
58+ _PyInterpreterFrame * unsafe_PyInterpreterFrame_GetBack (
59+ _PyInterpreterFrame * frame ) {
60+ assert (frame != NULL );
61+ assert (!_PyFrame_IsIncomplete (frame ));
62+ _PyInterpreterFrame * prev = frame -> previous ;
63+ while (prev && _PyFrame_IsIncomplete (prev )) {
64+ prev = prev -> previous ;
65+ }
66+ return prev ;
67+ }
68+
69+ // Copied from
70+ // https://github.com/python/cpython/blob/v3.11.4/Python/frame.c#L165-L170 as
71+ // this function is not available in libpython
72+ int _PyInterpreterFrame_GetLine (_PyInterpreterFrame * frame ) {
73+ int addr = _PyInterpreterFrame_LASTI (frame ) * sizeof (_Py_CODEUNIT );
74+ return PyCode_Addr2Line (frame -> f_code , addr );
75+ }
76+ #endif // PY_VERSION_HEX >= PY_311
0 commit comments