diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-06-17-46-24.gh-issue-98894.uG2s-h.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-06-17-46-24.gh-issue-98894.uG2s-h.rst new file mode 100644 index 00000000000000..d0bf4410dc01de --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-06-17-46-24.gh-issue-98894.uG2s-h.rst @@ -0,0 +1 @@ +Fix ``function__return`` and ``function__entry`` dtrace probe missing after :gh:`103083`. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index be22c7446f5402..0e85432618f012 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1149,6 +1149,7 @@ dummy_func( 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; @@ -1324,6 +1325,7 @@ dummy_func( _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); diff --git a/Python/ceval.c b/Python/ceval.c index 490b653f132a6a..53bd68568f893f 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1078,6 +1078,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int #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); @@ -1097,6 +1098,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _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); @@ -3279,6 +3282,37 @@ PyUnstable_Eval_RequestCodeExtraIndex(freefunc free) 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. */ diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 187ec8fdd26584..85e70d712ba9ae 100644 --- a/Python/ceval_macros.h +++ b/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 @@ -266,6 +268,15 @@ GETITEM(PyObject *v, Py_ssize_t i) { #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); \ diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 40090e692e4a72..874d45e04169fd 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1780,6 +1780,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; @@ -1934,6 +1935,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); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 1c98e1ce4fcf5c..69e6cf74b0d44d 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -7586,6 +7586,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; @@ -7643,6 +7644,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); @@ -10563,6 +10565,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; @@ -12250,6 +12253,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); diff --git a/Tools/jit/template.c b/Tools/jit/template.c index 5ee26f93f1e266..a23d0bad95200d 100644 --- a/Tools/jit/template.c +++ b/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"