mirror of
https://github.com/python/cpython.git
synced 2025-07-19 01:05:26 +00:00
DTrace support: function calls, GC activity, line execution
Tested on macOS 10.11 dtrace, Ubuntu 16.04 SystemTap, and libbcc. Largely based by an initial patch by Jesús Cea Avión, with some influence from Dave Malcolm's SystemTap patch and Nikhil Benesch's unification patch. Things deliberately left out for simplicity: - ustack helpers, I have no way of testing them at this point since they are Solaris-specific - PyFrameObject * in function__entry/function__return, this is SystemTap-specific - SPARC support - dynamic tracing - sys module dtrace facility introspection All of those might be added later.
This commit is contained in:
parent
39b42ae8db
commit
a785c87d6e
31 changed files with 1305 additions and 18 deletions
|
@ -15,6 +15,7 @@
|
|||
#include "dictobject.h"
|
||||
#include "frameobject.h"
|
||||
#include "opcode.h"
|
||||
#include "pydtrace.h"
|
||||
#include "setobject.h"
|
||||
#include "structmember.h"
|
||||
|
||||
|
@ -50,6 +51,9 @@ static void call_exc_trace(Py_tracefunc, PyObject *,
|
|||
PyThreadState *, PyFrameObject *);
|
||||
static int maybe_call_line_trace(Py_tracefunc, PyObject *,
|
||||
PyThreadState *, PyFrameObject *, int *, int *, int *);
|
||||
static void maybe_dtrace_line(PyFrameObject *, int *, int *, int *);
|
||||
static void dtrace_function_entry(PyFrameObject *);
|
||||
static void dtrace_function_return(PyFrameObject *);
|
||||
|
||||
static PyObject * cmp_outcome(int, PyObject *, PyObject *);
|
||||
static PyObject * import_name(PyFrameObject *, PyObject *, PyObject *, PyObject *);
|
||||
|
@ -822,7 +826,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
|
|||
#ifdef LLTRACE
|
||||
#define FAST_DISPATCH() \
|
||||
{ \
|
||||
if (!lltrace && !_Py_TracingPossible) { \
|
||||
if (!lltrace && !_Py_TracingPossible && !PyDTrace_LINE_ENABLED()) { \
|
||||
f->f_lasti = INSTR_OFFSET(); \
|
||||
NEXTOPARG(); \
|
||||
goto *opcode_targets[opcode]; \
|
||||
|
@ -832,7 +836,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
|
|||
#else
|
||||
#define FAST_DISPATCH() \
|
||||
{ \
|
||||
if (!_Py_TracingPossible) { \
|
||||
if (!_Py_TracingPossible && !PyDTrace_LINE_ENABLED()) { \
|
||||
f->f_lasti = INSTR_OFFSET(); \
|
||||
NEXTOPARG(); \
|
||||
goto *opcode_targets[opcode]; \
|
||||
|
@ -1042,6 +1046,9 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
|
|||
}
|
||||
}
|
||||
|
||||
if (PyDTrace_FUNCTION_ENTRY_ENABLED())
|
||||
dtrace_function_entry(f);
|
||||
|
||||
co = f->f_code;
|
||||
names = co->co_names;
|
||||
consts = co->co_consts;
|
||||
|
@ -1162,6 +1169,9 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
|
|||
fast_next_opcode:
|
||||
f->f_lasti = INSTR_OFFSET();
|
||||
|
||||
if (PyDTrace_LINE_ENABLED())
|
||||
maybe_dtrace_line(f, &instr_lb, &instr_ub, &instr_prev);
|
||||
|
||||
/* line-by-line tracing support */
|
||||
|
||||
if (_Py_TracingPossible &&
|
||||
|
@ -3620,6 +3630,8 @@ fast_yield:
|
|||
|
||||
/* pop frame */
|
||||
exit_eval_frame:
|
||||
if (PyDTrace_FUNCTION_RETURN_ENABLED())
|
||||
dtrace_function_return(f);
|
||||
Py_LeaveRecursiveCall();
|
||||
f->f_executing = 0;
|
||||
tstate->frame = f->f_back;
|
||||
|
@ -5415,3 +5427,65 @@ _PyEval_RequestCodeExtraIndex(freefunc free)
|
|||
tstate->co_extra_freefuncs[new_index] = free;
|
||||
return new_index;
|
||||
}
|
||||
|
||||
static void
|
||||
dtrace_function_entry(PyFrameObject *f)
|
||||
{
|
||||
char* filename;
|
||||
char* funcname;
|
||||
int lineno;
|
||||
|
||||
filename = PyUnicode_AsUTF8(f->f_code->co_filename);
|
||||
funcname = PyUnicode_AsUTF8(f->f_code->co_name);
|
||||
lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
|
||||
|
||||
PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno);
|
||||
}
|
||||
|
||||
static void
|
||||
dtrace_function_return(PyFrameObject *f)
|
||||
{
|
||||
char* filename;
|
||||
char* funcname;
|
||||
int lineno;
|
||||
|
||||
filename = PyUnicode_AsUTF8(f->f_code->co_filename);
|
||||
funcname = PyUnicode_AsUTF8(f->f_code->co_name);
|
||||
lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
|
||||
|
||||
PyDTrace_FUNCTION_RETURN(filename, funcname, lineno);
|
||||
}
|
||||
|
||||
/* DTrace equivalent of maybe_call_line_trace. */
|
||||
static void
|
||||
maybe_dtrace_line(PyFrameObject *frame,
|
||||
int *instr_lb, int *instr_ub, int *instr_prev)
|
||||
{
|
||||
int line = frame->f_lineno;
|
||||
char *co_filename, *co_name;
|
||||
|
||||
/* If the last instruction executed isn't in the current
|
||||
instruction window, reset the window.
|
||||
*/
|
||||
if (frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub) {
|
||||
PyAddrPair bounds;
|
||||
line = _PyCode_CheckLineNumber(frame->f_code, frame->f_lasti,
|
||||
&bounds);
|
||||
*instr_lb = bounds.ap_lower;
|
||||
*instr_ub = bounds.ap_upper;
|
||||
}
|
||||
/* If the last instruction falls at the start of a line or if
|
||||
it represents a jump backwards, update the frame's line
|
||||
number and call the trace function. */
|
||||
if (frame->f_lasti == *instr_lb || frame->f_lasti < *instr_prev) {
|
||||
frame->f_lineno = line;
|
||||
co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename);
|
||||
if (!co_filename)
|
||||
co_filename = "?";
|
||||
co_name = PyUnicode_AsUTF8(frame->f_code->co_name);
|
||||
if (!co_name)
|
||||
co_name = "?";
|
||||
PyDTrace_LINE(co_filename, co_name, line);
|
||||
}
|
||||
*instr_prev = frame->f_lasti;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue