https://github.com/python/cpython/pull/125019 --- Python-3.14.2/Python/bytecodes.c.orig +++ Python-3.14.2/Python/bytecodes.c @@ -1201,6 +1201,7 @@ DEAD(retval); SAVE_STACK(); assert(STACK_LEVEL() == 0); + DTRACE_FUNCTION_EXIT(); _Py_LeaveRecursiveCallPy(tstate); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; @@ -1376,6 +1377,7 @@ _PyStackRef temp = retval; DEAD(retval); SAVE_STACK(); + DTRACE_FUNCTION_EXIT(); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); --- Python-3.14.2/Python/ceval.c.orig +++ Python-3.14.2/Python/ceval.c @@ -1197,6 +1197,7 @@ #endif /* Because this avoids the RESUME, we need to update instrumentation */ _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); + DTRACE_FUNCTION_ENTRY(); next_instr = frame->instr_ptr; monitor_throw(tstate, frame, next_instr); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -1216,6 +1217,8 @@ _PyExecutorObject *current_executor = NULL; const _PyUOpInstruction *next_uop = NULL; #endif + DTRACE_FUNCTION_ENTRY(); + #if Py_TAIL_CALL_INTERP # if Py_STATS return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, 0, lastopcode); @@ -3494,6 +3497,37 @@ return new_index; } + +static void +dtrace_function_entry(_PyInterpreterFrame *frame) +{ + const char *filename; + const char *funcname; + int lineno; + + PyCodeObject *code = _PyFrame_GetCode(frame); + filename = PyUnicode_AsUTF8(code->co_filename); + funcname = PyUnicode_AsUTF8(code->co_name); + lineno = PyUnstable_InterpreterFrame_GetLine(frame); + + PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno); +} + +static void +dtrace_function_return(_PyInterpreterFrame *frame) +{ + const char *filename; + const char *funcname; + int lineno; + + PyCodeObject *code = _PyFrame_GetCode(frame); + filename = PyUnicode_AsUTF8(code->co_filename); + funcname = PyUnicode_AsUTF8(code->co_name); + lineno = PyUnstable_InterpreterFrame_GetLine(frame); + + PyDTrace_FUNCTION_RETURN(filename, funcname, lineno); +} + /* Implement Py_EnterRecursiveCall() and Py_LeaveRecursiveCall() as functions for the limited API. */ --- Python-3.14.2/Python/ceval_macros.h.orig +++ Python-3.14.2/Python/ceval_macros.h @@ -41,6 +41,8 @@ * the CFG. */ +#include "pycore_frame.h" + #ifdef WITH_DTRACE #define OR_DTRACE_LINE | (PyDTrace_LINE_ENABLED() ? 255 : 0) #else @@ -274,6 +276,15 @@ #define CONSTS() _PyFrame_GetCode(frame)->co_consts #define NAMES() _PyFrame_GetCode(frame)->co_names +static void dtrace_function_entry(_PyInterpreterFrame *); +static void dtrace_function_return(_PyInterpreterFrame *); + +#define DTRACE_FUNCTION_EXIT() \ + if (PyDTrace_FUNCTION_RETURN_ENABLED()) { \ + dtrace_function_return(frame); \ + } + + #define DTRACE_FUNCTION_ENTRY() \ if (PyDTrace_FUNCTION_ENTRY_ENABLED()) { \ dtrace_function_entry(frame); \ --- Python-3.14.2/Python/executor_cases.c.h.orig +++ Python-3.14.2/Python/executor_cases.c.h @@ -1812,6 +1812,7 @@ assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(STACK_LEVEL() == 0); + DTRACE_FUNCTION_EXIT(); _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *dying = frame; frame = tstate->current_frame = dying->previous; @@ -1966,6 +1967,7 @@ stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); + DTRACE_FUNCTION_EXIT(); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); --- Python-3.14.2/Python/generated_cases.c.h.orig +++ Python-3.14.2/Python/generated_cases.c.h @@ -7590,6 +7590,7 @@ assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(STACK_LEVEL() == 0); + DTRACE_FUNCTION_EXIT(); _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *dying = frame; frame = tstate->current_frame = dying->previous; @@ -7647,6 +7648,7 @@ stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); + DTRACE_FUNCTION_EXIT(); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); @@ -10627,6 +10629,7 @@ assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(STACK_LEVEL() == 0); + DTRACE_FUNCTION_EXIT(); _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *dying = frame; frame = tstate->current_frame = dying->previous; @@ -12330,6 +12333,7 @@ stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); + DTRACE_FUNCTION_EXIT(); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); --- Python-3.14.2/Tools/jit/template.c.orig +++ Python-3.14.2/Tools/jit/template.c @@ -26,6 +26,7 @@ #include "pycore_setobject.h" #include "pycore_sliceobject.h" #include "pycore_stackref.h" +#include "pydtrace.h" #include "pycore_template.h" #include "pycore_tuple.h" #include "pycore_unicodeobject.h"