diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 70f1e4a2..c05a2fa8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -65,7 +65,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] env: AUSTIN_TESTS_PYTHON_VERSIONS: ${{ matrix.python-version }} @@ -194,7 +194,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] env: AUSTIN_TESTS_PYTHON_VERSIONS: ${{ matrix.python-version }} @@ -303,7 +303,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] env: AUSTIN_TESTS_PYTHON_VERSIONS: ${{ matrix.python-version }} @@ -381,7 +381,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] env: AUSTIN_TESTS_PYTHON_VERSIONS: ${{ matrix.python-version }} diff --git a/ChangeLog b/ChangeLog index 7b182165..00aab9f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2023-xx-xx v3.6.0 + + Dropped support for Python 2, 3.3, 3.4, 3.5, 3.6 and 3.7. + + 2023-02-21 v3.5.0 Added support for fine-grained, column-level location information when diff --git a/README.md b/README.md index e5dc0e61..aaf96fb1 100644 --- a/README.md +++ b/README.md @@ -581,7 +581,7 @@ folder in either the SVG, PDF or PNG format # Compatibility -Austin supports Python 2.3-2.7 and 3.3-3.11 and has been tested on the +Austin supports Python 3.8-3.11 and has been tested on the following platforms and architectures | | | | | @@ -594,7 +594,8 @@ following platforms and architectures > **NOTE** Austin *might* work with other versions of Python on all the > platforms and architectures above. So it is worth giving it a try even if -> your system is not listed below. +> your system is not listed below. If you are looking for support for Python < +> 3.8, you can use Austin 3.5. Because of platform-specific details, Austin usage may vary slightly. Below are further compatibility details to be aware of. diff --git a/configure.ac b/configure.ac index 8cda77ff..1f62949c 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ AC_PREREQ([2.69]) # from scripts.utils import get_current_version_from_changelog as version # print(f"AC_INIT([austin], [{version()}], [https://github.com/p403n1x87/austin/issues])") # ]]] -AC_INIT([austin], [3.5.0], [https://github.com/p403n1x87/austin/issues]) +AC_INIT([austin], [3.6.0], [https://github.com/p403n1x87/austin/issues]) # [[[end]]] AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADERS([config.h]) diff --git a/doc/cheatsheet.pdf b/doc/cheatsheet.pdf index ceb0183a..9a5b6739 100644 Binary files a/doc/cheatsheet.pdf and b/doc/cheatsheet.pdf differ diff --git a/doc/cheatsheet.png b/doc/cheatsheet.png index b66f0831..fecbd6fb 100644 Binary files a/doc/cheatsheet.png and b/doc/cheatsheet.png differ diff --git a/doc/cheatsheet.svg b/doc/cheatsheet.svg index ed54a09a..8ab215aa 100644 --- a/doc/cheatsheet.svg +++ b/doc/cheatsheet.svg @@ -7,7 +7,7 @@ viewBox="0 0 210 297" version="1.1" id="svg8" - inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)" + inkscape:version="1.2.2 (b0a8486, 2022-12-01)" sodipodi:docname="cheatsheet.svg" inkscape:export-filename="/home/gabriele/Projects/austin/doc/cheatsheet.png" inkscape:export-xdpi="191.99664" @@ -757,17 +757,19 @@ inkscape:pageopacity="1" inkscape:pageshadow="2" inkscape:zoom="1.4" - inkscape:cx="355.35714" - inkscape:cy="-3878.5714" + inkscape:cx="273.21429" + inkscape:cy="20" inkscape:document-units="mm" - inkscape:current-layer="layer1" + inkscape:current-layer="layer3" showgrid="false" - inkscape:window-width="2560" - inkscape:window-height="1413" + inkscape:window-width="1440" + inkscape:window-height="900" inkscape:window-x="0" - inkscape:window-y="328" - inkscape:window-maximized="1" - inkscape:pagecheckerboard="0" /> + inkscape:window-y="0" + inkscape:window-maximized="0" + inkscape:pagecheckerboard="0" + inkscape:showpageshadow="2" + inkscape:deskcolor="#ebece0" /> @@ -6340,7 +6342,7 @@ y="293.48233" x="49.886612" id="tspan9522" - sodipodi:role="line">2.3 thru 2.7 and 3.3 thru 3.11 + sodipodi:role="line">3.8 | 3.9 | 3.10 | 3.11 CHEATSHEET for version 3.5 + sodipodi:role="line">for version 3.6 filename); p++; *major = *(p++) - '0'; - if (*major != 2 && *major != 3) { + if (*major != 3) { FAIL; } @@ -175,7 +175,6 @@ _get_version_from_filename(char * filename, const char * needle, int * major, in #elif defined PL_MACOS /* MAC */ char * ver_needle = strstr(filename, "3."); - if (ver_needle == NULL) ver_needle = strstr(filename, "2."); if (ver_needle != NULL && sscanf(ver_needle, "%d.%d", major, minor) == 2) { SUCCESS; } @@ -323,30 +322,6 @@ _py_proc__infer_python_version(py_proc_t * self) { set_version: self->py_v = get_version_descriptor(major, minor, patch); SUCCESS; - - // Scan the rodata section for something that looks like the Python version. - // There are good chances this is at the very beginning of the section so - // it shouldn't take too long to find a match. This is more reliable than - // waiting until the version appears in the bss section at run-time. - // NOTE: This method is not guaranteed to find a valid Python version. - // If this causes problems then another method is required. - // char * p_ver = (char *) map + (Elf64_Addr) self->map.rodata.base; - // for (register int i = 0; i < self->map.rodata.size; i++) { - // if ( - // p_ver[i] == '.' && - // p_ver[i+1] != '.' && - // p_ver[i+2] == '.' && - // p_ver[i-2] == 0 - // ) { - // if ( - // sscanf(p_ver + i - 1, "%d.%d.%d", &major, &minor, &patch) == 3 && - // (major == 2 || major == 3) - // ) { - // log_i("Python version: %s", p_ver + i - 1, p_ver); - // // break; - // } - // } - // } } @@ -434,57 +409,6 @@ _py_proc__check_interp_state(py_proc_t * self, void * raddr) { SUCCESS; } - -#ifdef CHECK_HEAP -// ---------------------------------------------------------------------------- -static int -_py_proc__is_heap_raddr(py_proc_t * self, void * raddr) { - if (!isvalid(self) || !isvalid(raddr) || !isvalid(self->map.heap.base)) - return FALSE; - - return ( - raddr >= self->map.heap.base && - raddr < self->map.heap.base + self->map.heap.size - ); -} - - -// ---------------------------------------------------------------------------- -static int -_py_proc__is_raddr_within_max_range(py_proc_t * self, void * raddr) { - if (!isvalid(self) || !isvalid(raddr) || !isvalid(self->map.heap.base)) - return FALSE; - - return (raddr >= self->min_raddr && raddr < self->max_raddr); -} - - -// ---------------------------------------------------------------------------- -static int -_py_proc__scan_heap(py_proc_t * self) { - log_d("Scanning HEAP"); - // NOTE: This seems to be required by Python 2.7 on i386 Linux. - void * upper_bound = self->map.heap.base + self->map.heap.size; - for ( - register void ** raddr = (void **) self->map.heap.base; - (void *) raddr < upper_bound; - raddr++ - ) { - switch (_py_proc__check_interp_state(self, raddr)) { - case 0: - self->is_raddr = raddr; - SUCCESS; - - case OUT_OF_BOUND: - return OUT_OF_BOUND; - } - } - - FAIL; -} -#endif - - // ---------------------------------------------------------------------------- static int _py_proc__scan_bss(py_proc_t * self) { @@ -531,11 +455,6 @@ _py_proc__scan_bss(py_proc_t * self) { ) { if ( (!shift && - #ifdef CHECK_HEAP - (isvalid(self->lib_path) - ? _py_proc__is_raddr_within_max_range(self, *raddr) - : _py_proc__is_heap_raddr(self, *raddr)) && - #endif success(_py_proc__check_interp_state(self, *raddr))) ||(shift && success(_py_proc__check_interp_state(self, (void*) raddr - self->bss + base))) ) { @@ -755,22 +674,6 @@ _py_proc__wait_for_interp_state(py_proc_t * self) { if (self->child) FAIL; - #ifdef CHECK_HEAP - log_w("BSS scan unsuccessful so we scan the heap directly ..."); - - // TODO: Consider copying heap over and check for pointers - TIMER_SET(100) - TIMER_START - switch (_py_proc__scan_heap(self)) { - case 0: - SUCCESS; - - case OUT_OF_BOUND: - TIMER_STOP - } - TIMER_END - #endif - set_error(EPROCISTIMEOUT); FAIL; } // _py_proc__wait_for_interp_state diff --git a/src/py_string.h b/src/py_string.h index d1651687..b6db19f4 100644 --- a/src/py_string.h +++ b/src/py_string.h @@ -57,59 +57,38 @@ string__hash(char * string) { // ---------------------------------------------------------------------------- static inline char * _string_from_raddr(proc_ref_t pref, void * raddr, python_v * py_v) { - PyStringObject string; PyUnicodeObject3 unicode; char * buffer = NULL; ssize_t len = 0; - // This switch statement is required by the changes regarding the string type - // introduced in Python 3. - switch (py_v->major) { - case 2: - if (fail(copy_datatype(pref, raddr, string))) { - log_ie("Cannot read remote PyStringObject"); - goto failed; - } - - len = string.ob_base.ob_size; - buffer = (char *) malloc(len + 1); - if (fail(copy_memory(pref, raddr + offsetof(PyStringObject, ob_sval), len, buffer))) { - log_ie("Cannot read remote value of PyStringObject"); - goto failed; - } - buffer[len] = 0; - break; - - case 3: - if (fail(copy_datatype(pref, raddr, unicode))) { - log_ie("Cannot read remote PyUnicodeObject3"); - goto failed; - } - - PyASCIIObject ascii = unicode._base._base; - - if (ascii.state.kind != 1) { - set_error(ECODEFMT); - goto failed; - } - - void * data = ascii.state.compact ? p_ascii_data(raddr) : unicode._base.utf8; - len = ascii.state.compact ? ascii.length : unicode._base.utf8_length; - - if (len < 0 || len > 4096) { - log_e("Invalid string length"); - goto failed; - } - - buffer = (char *) malloc(len + 1); - - if (!isvalid(data) || fail(copy_memory(pref, data, len, buffer))) { - log_ie("Cannot read remote value of PyUnicodeObject3"); - goto failed; - } - buffer[len] = 0; + if (fail(copy_datatype(pref, raddr, unicode))) { + log_ie("Cannot read remote PyUnicodeObject3"); + goto failed; } + PyASCIIObject ascii = unicode._base._base; + + if (ascii.state.kind != 1) { + set_error(ECODEFMT); + goto failed; + } + + void * data = ascii.state.compact ? p_ascii_data(raddr) : unicode._base.utf8; + len = ascii.state.compact ? ascii.length : unicode._base.utf8_length; + + if (len < 0 || len > 4096) { + log_e("Invalid string length"); + goto failed; + } + + buffer = (char *) malloc(len + 1); + + if (!isvalid(data) || fail(copy_memory(pref, data, len, buffer))) { + log_ie("Cannot read remote value of PyUnicodeObject3"); + goto failed; + } + buffer[len] = 0; + return buffer; failed: @@ -121,51 +100,25 @@ _string_from_raddr(proc_ref_t pref, void * raddr, python_v * py_v) { // ---------------------------------------------------------------------------- static inline unsigned char * _bytes_from_raddr(proc_ref_t pref, void * raddr, ssize_t * size, python_v * py_v) { - PyStringObject string; PyBytesObject bytes; ssize_t len = 0; unsigned char * array = NULL; - switch (py_v->major) { - case 2: // Python 2 - if (fail(copy_datatype(pref, raddr, string))) { - log_ie("Cannot read remote PyStringObject"); - goto error; - } - - len = string.ob_base.ob_size + 1; - if (py_v->minor <= 4) { - // In Python 2.4, the ob_size field is of type int. If we cannot - // allocate on the first try it's because we are getting a ridiculous - // value for len. In that case, chop it down to an int and try again. - // This approach is simpler than adding version support. - len = (int) len; - } - - array = (unsigned char *) malloc((len + 1) * sizeof(unsigned char *)); - if (fail(copy_memory(pref, raddr + offsetof(PyStringObject, ob_sval), len, array))) { - log_ie("Cannot read remote value of PyStringObject"); - goto error; - } - break; - - case 3: // Python 3 - if (fail(copy_datatype(pref, raddr, bytes))) { - log_ie("Cannot read remote PyBytesObject"); - goto error; - } - - if ((len = bytes.ob_base.ob_size + 1) < 1) { // Include null-terminator - set_error(ECODEBYTES); - log_e("PyBytesObject is too short"); - goto error; - } - - array = (unsigned char *) malloc((len + 1) * sizeof(unsigned char *)); - if (fail(copy_memory(pref, raddr + offsetof(PyBytesObject, ob_sval), len, array))) { - log_ie("Cannot read remote value of PyBytesObject"); - goto error; - } + if (fail(copy_datatype(pref, raddr, bytes))) { + log_ie("Cannot read remote PyBytesObject"); + goto error; + } + + if ((len = bytes.ob_base.ob_size + 1) < 1) { // Include null-terminator + set_error(ECODEBYTES); + log_e("PyBytesObject is too short"); + goto error; + } + + array = (unsigned char *) malloc((len + 1) * sizeof(unsigned char *)); + if (fail(copy_memory(pref, raddr + offsetof(PyBytesObject, ob_sval), len, array))) { + log_ie("Cannot read remote value of PyBytesObject"); + goto error; } array[len] = 0; diff --git a/src/py_thread.c b/src/py_thread.c index a542ef16..15c92d08 100644 --- a/src/py_thread.c +++ b/src/py_thread.c @@ -946,8 +946,7 @@ py_thread__emit_collapsed_stack(py_thread_t * self, ctime_t time_delta, ssize_t int is_frame_eval = FALSE; if (isvalid(eval_frame_fn)) { char c = *(eval_frame_fn+16); - V_DESC(self->proc->py_v); - is_frame_eval = (c == 'D') || (V_MAX(3, 5) && c == 'E'); + is_frame_eval = (c == 'D'); } if (!stack_is_empty() && is_frame_eval) { // TODO: if the py stack is empty we have a mismatch. diff --git a/src/python/code.h b/src/python/code.h index b4438e33..74aed199 100644 --- a/src/python/code.h +++ b/src/python/code.h @@ -32,64 +32,6 @@ // ---- code.h ---------------------------------------------------------------- -typedef struct { - PyObject_HEAD - int co_argcount; /* #arguments, except *args */ - int co_nlocals; /* #local variables */ - int co_stacksize; /* #entries needed for evaluation stack */ - int co_flags; /* CO_..., see below */ - PyObject *co_code; /* instruction opcodes */ - PyObject *co_consts; /* list (constants used) */ - PyObject *co_names; /* list of strings (names used) */ - PyObject *co_varnames; /* tuple of strings (local variable names) */ - PyObject *co_freevars; /* tuple of strings (free variable names) */ - PyObject *co_cellvars; /* tuple of strings (cell variable names) */ - PyObject *co_filename; /* string (where it was loaded from) */ - PyObject *co_name; /* string (name, for reference) */ - int co_firstlineno; /* first source line number */ - PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) */ -} PyCodeObject2; - -typedef struct { - PyObject_HEAD - int co_argcount; /* #arguments, except *args */ - int co_kwonlyargcount; /* #keyword only arguments */ - int co_nlocals; /* #local variables */ - int co_stacksize; /* #entries needed for evaluation stack */ - int co_flags; /* CO_..., see below */ - PyObject *co_code; /* instruction opcodes */ - PyObject *co_consts; /* list (constants used) */ - PyObject *co_names; /* list of strings (names used) */ - PyObject *co_varnames; /* tuple of strings (local variable names) */ - PyObject *co_freevars; /* tuple of strings (free variable names) */ - PyObject *co_cellvars; /* tuple of strings (cell variable names) */ - unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */ - PyObject *co_filename; /* unicode (where it was loaded from) */ - PyObject *co_name; /* unicode (name, for reference) */ - int co_firstlineno; /* first source line number */ - PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) */ -} PyCodeObject3_3; - -typedef struct { - PyObject_HEAD - int co_argcount; /* #arguments, except *args */ - int co_kwonlyargcount; /* #keyword only arguments */ - int co_nlocals; /* #local variables */ - int co_stacksize; /* #entries needed for evaluation stack */ - int co_flags; /* CO_..., see below */ - int co_firstlineno; /* first source line number */ - PyObject *co_code; /* instruction opcodes */ - PyObject *co_consts; /* list (constants used) */ - PyObject *co_names; /* list of strings (names used) */ - PyObject *co_varnames; /* tuple of strings (local variable names) */ - PyObject *co_freevars; /* tuple of strings (free variable names) */ - PyObject *co_cellvars; /* tuple of strings (cell variable names) */ - unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */ - PyObject *co_filename; /* unicode (where it was loaded from) */ - PyObject *co_name; /* unicode (name, for reference) */ - PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) */ -} PyCodeObject3_6; - typedef struct { PyObject_HEAD int co_argcount; /* #arguments, except *args */ @@ -151,9 +93,6 @@ typedef struct _PyCode_DEF_311(1) PyCodeObject3_11; typedef union { - PyCodeObject2 v2; - PyCodeObject3_3 v3_3; - PyCodeObject3_6 v3_6; PyCodeObject3_8 v3_8; PyCodeObject3_11 v3_11; } PyCodeObject; diff --git a/src/python/frame.h b/src/python/frame.h index 76a471e8..cd51b320 100644 --- a/src/python/frame.h +++ b/src/python/frame.h @@ -33,24 +33,6 @@ // ---- frameobject.h --------------------------------------------------------- -typedef struct _frame2_3 { - PyObject_VAR_HEAD - struct _frame2_3 *f_back; /* previous frame, or NULL */ - PyCodeObject *f_code; /* code segment */ - PyObject *f_builtins; /* builtin symbol table (PyDictObject) */ - PyObject *f_globals; /* global symbol table (PyDictObject) */ - PyObject *f_locals; /* local symbol table (any mapping) */ - PyObject **f_valuestack; /* points after the last local */ - PyObject **f_stacktop; - PyObject *f_trace; /* Trace function */ - - PyObject *f_exc_type, *f_exc_value, *f_exc_traceback; - PyObject *f_gen; - - int f_lasti; /* Last instruction if called */ - int f_lineno; /* Current line number */ -} PyFrameObject2; - typedef struct _frame3_7 { PyObject_VAR_HEAD struct _frame3_7 *f_back; /* previous frame, or NULL */ @@ -90,7 +72,6 @@ typedef struct _frame3_10 { } PyFrameObject3_10; typedef union { - PyFrameObject2 v2; PyFrameObject3_7 v3_7; PyFrameObject3_10 v3_10; } PyFrameObject; diff --git a/src/python/gc.h b/src/python/gc.h index 85ac238c..9ce10f4d 100644 --- a/src/python/gc.h +++ b/src/python/gc.h @@ -34,15 +34,6 @@ // ---- include/objimpl.h ----------------------------------------------------- -typedef union _gc_head3_7 { - struct { - union _gc_head3_7 *gc_next; - union _gc_head3_7 *gc_prev; - Py_ssize_t gc_refs; - } gc; - long double dummy; /* force worst-case alignment */ -} PyGC_Head3_7; - typedef struct { uintptr_t _gc_next; uintptr_t _gc_prev; @@ -52,13 +43,6 @@ typedef struct { #define NUM_GENERATIONS 3 -struct gc_generation3_7 { - PyGC_Head3_7 head; - int threshold; /* collection threshold */ - int count; /* count of allocations or collections of younger - generations */ -}; - struct gc_generation3_8 { PyGC_Head3_8 head; @@ -74,18 +58,6 @@ struct gc_generation_stats { Py_ssize_t uncollectable; }; -struct _gc_runtime_state3_7 { - PyObject *trash_delete_later; - int trash_delete_nesting; - int enabled; - int debug; - struct gc_generation3_7 generations[NUM_GENERATIONS]; - PyGC_Head3_7 *generation0; - struct gc_generation3_7 permanent_generation; - struct gc_generation_stats generation_stats[NUM_GENERATIONS]; - int collecting; -}; - struct _gc_runtime_state3_8 { PyObject *trash_delete_later; int trash_delete_nesting; @@ -99,7 +71,6 @@ struct _gc_runtime_state3_8 { }; typedef union { - struct _gc_runtime_state3_7 v3_7; struct _gc_runtime_state3_8 v3_8; } GCRuntimeState; diff --git a/src/python/runtime.h b/src/python/runtime.h index 22f7722a..44d0bc51 100644 --- a/src/python/runtime.h +++ b/src/python/runtime.h @@ -34,29 +34,6 @@ #include "misc.h" #include "thread.h" -// ---- internal/pystate.h ---------------------------------------------------- - -typedef struct pyruntimestate3_7 { - int initialized; - int core_initialized; - PyThreadState *finalizing; - - struct pyinterpreters3_7 { - PyThread_type_lock mutex; - PyInterpreterState *head; - PyInterpreterState *main; - int64_t next_id; - } interpreters; -#define NEXITFUNCS 32 - void (*exitfuncs[NEXITFUNCS])(void); - int nexitfuncs; - - struct _gc_runtime_state3_7 gc; - // struct _warnings_runtime_state warnings; - // struct _ceval_runtime_state ceval; - // struct _gilstate_runtime_state gilstate; -} _PyRuntimeState3_7; - // ---- internal/pycore_pystate.h --------------------------------------------- typedef struct pyruntimestate3_8 { @@ -125,7 +102,6 @@ typedef struct pyruntimestate3_11 { typedef union { - _PyRuntimeState3_7 v3_7; _PyRuntimeState3_8 v3_8; _PyRuntimeState3_11 v3_11; } _PyRuntimeState; diff --git a/src/python/string.h b/src/python/string.h index 56bd0a18..ed36fa3d 100644 --- a/src/python/string.h +++ b/src/python/string.h @@ -42,16 +42,6 @@ typedef uint8_t Py_UCS1; typedef PY_UNICODE_TYPE Py_UNICODE; - -typedef struct { - PyObject_HEAD - Py_ssize_t length; /* Length of raw Unicode data in buffer */ - Py_UNICODE *str; /* Raw Unicode buffer */ - long hash; /* Hash value; -1 if not set */ - PyObject *defenc; /* (Default) Encoded version as Python string */ -} PyUnicodeObject2; - - typedef Py_ssize_t Py_hash_t; typedef struct { @@ -91,7 +81,6 @@ typedef struct { typedef union { - PyUnicodeObject2 v2; PyUnicodeObject3 v3; } PyUnicodeObject; diff --git a/src/python/thread.h b/src/python/thread.h index 56d94a11..44270ba1 100644 --- a/src/python/thread.h +++ b/src/python/thread.h @@ -40,107 +40,11 @@ struct _frame; typedef int (*Py_tracefunc)(PyObject *, struct _frame *, int, PyObject *); -typedef struct _ts2 { - struct _ts2 *next; - PyInterpreterState *interp; - - struct _frame *frame; - int recursion_depth; - char overflowed; - char recursion_critical; - int tracing; - int use_tracing; - - Py_tracefunc c_profilefunc; - Py_tracefunc c_tracefunc; - PyObject *c_profileobj; - PyObject *c_traceobj; - - PyObject *curexc_type; - PyObject *curexc_value; - PyObject *curexc_traceback; - - PyObject *exc_type; - PyObject *exc_value; - PyObject *exc_traceback; - - PyObject *dict; /* Stores per-thread state */ - - int tick_counter; - - int gilstate_counter; - - PyObject *async_exc; /* Asynchronous exception to raise */ - long thread_id; /* Thread id where this tstate was created */ -} PyThreadState2; - - -typedef struct _ts3_4 { - struct _ts3_4 *prev; - struct _ts3_4 *next; - PyInterpreterState *interp; - - struct _frame *frame; - int recursion_depth; - char overflowed; - char recursion_critical; - int tracing; - int use_tracing; - - Py_tracefunc c_profilefunc; - Py_tracefunc c_tracefunc; - PyObject *c_profileobj; - PyObject *c_traceobj; - - PyObject *curexc_type; - PyObject *curexc_value; - PyObject *curexc_traceback; - - PyObject *exc_type; - PyObject *exc_value; - PyObject *exc_traceback; - - PyObject *dict; /* Stores per-thread state */ - - int gilstate_counter; - - PyObject *async_exc; /* Asynchronous exception to raise */ - long thread_id; /* Thread id where this tstate was created */ -} PyThreadState3_4; - - - typedef struct _err_stackitem3_7 { PyObject *exc_type, *exc_value, *exc_traceback; struct _err_stackitem3_7 *previous_item; } _PyErr_StackItem3_7; -typedef struct _ts_3_7 { - struct _ts *prev; - struct _ts *next; - PyInterpreterState *interp; - struct _frame *frame; - int recursion_depth; - char overflowed; - char recursion_critical; - int stackcheck_counter; - int tracing; - int use_tracing; - Py_tracefunc c_profilefunc; - Py_tracefunc c_tracefunc; - PyObject *c_profileobj; - PyObject *c_traceobj; - PyObject *curexc_type; - PyObject *curexc_value; - PyObject *curexc_traceback; - _PyErr_StackItem3_7 exc_state; - _PyErr_StackItem3_7 *exc_info; - PyObject *dict; /* Stores per-thread state */ - int gilstate_counter; - PyObject *async_exc; /* Asynchronous exception to raise */ - unsigned long thread_id; /* Thread id where this tstate was created */ -} PyThreadState3_7; - typedef struct _ts3_8 { struct _ts *prev; @@ -249,8 +153,6 @@ typedef struct _ts3_11 { typedef union { - PyThreadState2 v2; - PyThreadState3_4 v3_4; PyThreadState3_8 v3_8; PyThreadState3_11 v3_11; } PyThreadState; diff --git a/src/version.h b/src/version.h index 6c373571..e2022942 100644 --- a/src/version.h +++ b/src/version.h @@ -79,8 +79,8 @@ * @return TRUE if the current version is at least/at most the requested one, * FALSE otherwise. */ -#define V_MIN(M, m) (py_v->major > M || (py_v->major == M && py_v->minor >= m)) -#define V_MAX(M, m) (py_v->major < M || (py_v->major == M && py_v->minor <= m)) +#define V_MIN(M, m) (((py_v->major << 8) | py_v->minor) >= ((M << 8) | m)) +#define V_MAX(M, m) (((py_v->major << 8) | py_v->minor) <= ((M << 8) | m)) typedef unsigned long offset_t; @@ -234,17 +234,6 @@ typedef struct { offsetof(s, is_entry), \ } - -/* Hack. Python 3.3 and below don't have the prev field */ -#define PY_THREAD_2(s) { \ - sizeof(s), \ - offsetof(s, next), \ - offsetof(s, next), \ - offsetof(s, interp), \ - offsetof(s, frame), \ - offsetof(s, thread_id) \ -} - #define PY_THREAD(s) { \ sizeof(s), \ offsetof(s, prev), \ @@ -305,53 +294,6 @@ typedef struct { offsetof(s, collecting), \ } -// ---- Python 2 -------------------------------------------------------------- - -python_v python_v2 = { - PY_CODE (PyCodeObject2), - PY_FRAME (PyFrameObject2), - PY_THREAD_2 (PyThreadState2), - PY_IS (PyInterpreterState2), -}; - -// ---- Python 3.3 ------------------------------------------------------------ - -python_v python_v3_3 = { - PY_CODE (PyCodeObject3_3), - PY_FRAME (PyFrameObject2), - PY_THREAD_2 (PyThreadState2), - PY_IS (PyInterpreterState2), -}; - -// ---- Python 3.4 ------------------------------------------------------------ - -python_v python_v3_4 = { - PY_CODE (PyCodeObject3_3), - PY_FRAME (PyFrameObject2), - PY_THREAD (PyThreadState3_4), - PY_IS (PyInterpreterState2), -}; - -// ---- Python 3.6 ------------------------------------------------------------ - -python_v python_v3_6 = { - PY_CODE (PyCodeObject3_6), - PY_FRAME (PyFrameObject2), - PY_THREAD (PyThreadState3_4), - PY_IS (PyInterpreterState2), -}; - -// ---- Python 3.7 ------------------------------------------------------------ - -python_v python_v3_7 = { - PY_CODE (PyCodeObject3_6), - PY_FRAME (PyFrameObject3_7), - PY_THREAD (PyThreadState3_7), - PY_IS (PyInterpreterState2), - PY_RUNTIME (_PyRuntimeState3_7), - PY_GC (struct _gc_runtime_state3_7), -}; - // ---- Python 3.8 ------------------------------------------------------------ python_v python_v3_8 = { @@ -409,48 +351,19 @@ get_version_descriptor(int major, int minor, int patch) { switch (major) { - // ---- Python 2 ------------------------------------------------------------ - case 2: + // ---- Python 3 ------------------------------------------------------------ + case 3: switch (minor) { case 0: case 1: case 2: - UNSUPPORTED_VERSION; // NOTE: These versions haven't been tested. - - // 2.3, 2.4, 2.5, 2.6, 2.7 case 3: case 4: case 5: case 6: - case 7: py_v = &python_v2; - break; - - default: py_v = &python_v2; - UNSUPPORTED_VERSION; - } - break; - - // ---- Python 3 ------------------------------------------------------------ - case 3: - switch (minor) { - case 0: - case 1: - case 2: + case 7: UNSUPPORTED_VERSION; // NOTE: These versions haven't been tested. - // 3.3 - case 3: py_v = &python_v3_3; break; - - // 3.4, 3.5 - case 4: - case 5: py_v = &python_v3_4; break; - - // 3.6 - case 6: py_v = &python_v3_6; break; - - // 3.7 - case 7: py_v = &python_v3_7; break; - // 3.8 case 8: py_v = &python_v3_8; break; diff --git a/src/win/py_proc.h b/src/win/py_proc.h index 2454f237..8ac39c00 100644 --- a/src/win/py_proc.h +++ b/src/win/py_proc.h @@ -30,7 +30,6 @@ #include "../resources.h" -#define CHECK_HEAP #define DEREF_SYM diff --git a/test/__init__.py b/test/__init__.py index f1543e76..2e9b4318 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -1,7 +1,6 @@ import os import platform - PY3_LATEST = 11 try: @@ -16,9 +15,9 @@ match platform.system(): case "Darwin": PYTHON_VERSIONS = REQUESTED_PYTHON_VERSIONS or [ - (3, _) for _ in range(7, PY3_LATEST + 1) + (3, _) for _ in range(8, PY3_LATEST + 1) ] case _: - PYTHON_VERSIONS = REQUESTED_PYTHON_VERSIONS or [(2, 7)] + [ - (3, _) for _ in range(5, PY3_LATEST + 1) + PYTHON_VERSIONS = REQUESTED_PYTHON_VERSIONS or [ + (3, _) for _ in range(8, PY3_LATEST + 1) ]