13956N/A /* As of 2.3 f_lineno is only valid when tracing is active (
i.e. when
13956N/A f_trace is set) -- at other times use PyCode_Addr2Line instead. */
13956N/A int f_lineno; /* Current line number */
13956N/A+ int f_calllineno; /* line number of call site */
13956N/A int f_iblock; /* index in f_blockstack */
13956N/A PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
13956N/A PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
13956N/A ##########################################################################
############################################################################
+ f->f_calllineno = code->co_firstlineno;
f->f_lineno = code->co_firstlineno;
#define READ_TIMESTAMP(var)
+dtrace_entry(PyFrameObject *f)
+ filename = PyString_AsString(f->f_code->co_filename);
+ fname = PyString_AsString(f->f_code->co_name);
+ lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+ PYTHON_FUNCTION_ENTRY((char *)filename, (char *)fname, lineno);
+ * Currently a USDT tail-call will not receive the correct arguments.
+ * Disable the tail call here.
+dtrace_return(PyFrameObject *f)
+ filename = PyString_AsString(f->f_code->co_filename);
+ fname = PyString_AsString(f->f_code->co_name);
+ lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+ PYTHON_FUNCTION_RETURN((char *)filename, (char *)fname, lineno);
+ * Currently a USDT tail-call will not receive the correct arguments.
+ * Disable the tail call here.
+#define PYTHON_FUNCTION_ENTRY_ENABLED 0
+#define PYTHON_FUNCTION_RETURN_ENABLED 0
/* Interpreter main loop */
return PyEval_EvalFrameEx(f, 0);
+ * These shenanigans look like utter madness, but what we're actually doing is
+ * making sure that the ustack helper will see the PyFrameObject pointer on the
+ * stack. We have two tricky cases:
+ * We use up the six registers for passing arguments, meaning the call can't
+ * use a register for passing 'f', and has to push it onto the stack in a known
+ * And how does "throwflag" figure in to this? -PN
+ * Here the problem is that (on 32-bit) the compiler is re-using %i0 before
+ * some calls inside PyEval_EvalFrameReal(), which means that when it's saved,
+ * it's just some junk value rather than the real first argument. So, instead,
+ * we trace our proxy PyEval_EvalFrame(), where we 'know' the compiler won't
+ * decide to re-use %i0. We also need to defeat optimization of our proxy.
+#if defined(HAVE_DTRACE)
+PyObject *PyEval_EvalFrameExReal(long, long, long, long, long, long,
+ PyFrameObject *, int throwflag);
+PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
+ f2 = PyEval_EvalFrameExReal(0, 0, 0, 0, 0, 0, f, throwflag);
+PyEval_EvalFrameExReal(long a1, long a2, long a3, long a4, long a5, long a6,
+ PyFrameObject *f, int throwflag)
+PyObject *PyEval_EvalFrameExReal(PyFrameObject *f, int throwflag);
+PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
+ f2 = PyEval_EvalFrameExReal(f, throwflag);
+PyEval_EvalFrameExReal(PyFrameObject *f, int throwflag)
+#else /* __amd64 || __sparc */
PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
+#endif /* __amd64 || __sparc */
+#else /* don't HAVE_DTRACE */
+PyEval_EvalFrameexEx(PyFrameObject *f, int throwflag))
+#endif /* HAVE_DTRACE */
+ if (PYTHON_FUNCTION_ENTRY_ENABLED())
+ f->f_calllineno = PyCode_Addr2Line(f->f_code,
x = call_function(&sp, oparg, &intr0, &intr1);
+ f->f_calllineno = PyCode_Addr2Line(f->f_code,
x = ext_do_call(func, &sp, flags, na, nk);
+ if (PYTHON_FUNCTION_RETURN_ENABLED())
tstate->frame = f->f_back;
+ * Python ustack helper. This relies on the first argument (PyFrame *) being
+ * on the stack; see
Python/ceval.c for the contortions we go through to ensure
+ * On x86, the PyFrame * is two slots up from the frame pointer; on SPARC, it's
+ * Yes, this is as gross as it looks. DTrace cannot handle static functions,
+#define startframe PyEval_EvalFrameEx
+#define endframe PyEval_EvalCodeEx
+#define PyEval_EvalFrameEx PyEval_EvalFrameExReal
+#define startframe PyEval_EvalFrameExReal
+#define endframe PyEval_EvalCodeEx
+#define startframe PyEval_EvalFrameEx
+#define endframe PyEval_EvalFrameExReal
+#define STACK_BIAS (2048-1)
+ * Not defining PHELPER lets us test this code as a normal D script.
+#define at_evalframe(addr) \
+ ((uintptr_t)addr >= ((uintptr_t)&``startframe) && \
+ (uintptr_t)addr < ((uintptr_t)&``endframe))
+#define probe dtrace:helper:ustack:
+#define print_result(r) (r)
+#if defined(__i386) || defined(__amd64)
+#define frame_ptr_addr ((uintptr_t)arg1 + sizeof(uintptr_t) * 2)
+#define frame_ptr_addr ((uintptr_t)arg1 + STACK_BIAS + sizeof(uintptr_t) * 8)
+#error unknown architecture
+#define at_evalframe(addr) (1)
+#define probe pid$target::PyEval_EvalFrame:entry
+#define print_result(r) (trace(r))
+#if defined(__i386) || defined(__amd64)
+#define frame_ptr_addr ((uintptr_t)uregs[R_SP] + sizeof(uintptr_t))
+ * Not implemented: we could just use R_I0, but what's the point?
+#error unknown architecture
+extern uintptr_t PyEval_EvalFrameEx;
+extern uintptr_t PyEval_EvalCodeEx;
+#define copyin_obj(addr, obj) ((obj *)copyin((uintptr_t)addr, sizeof(obj)))
+#define pystr_addr(addr) ((char *)addr + offsetof(PyStringObject, ob_sval))
+#define copyin_str(dest, addr, obj) \
+ (copyinto((uintptr_t)pystr_addr(addr), obj->ob_size, (dest)))
+#define add_str(addr, obj) \
+ copyin_str(this->result + this->pos, addr, obj); \
+ this->pos += obj->ob_size; \
+ this->result[this->pos] = '\0';
+#define add_digit(nr, div) ((nr / div) ? \
+ (this->result[this->pos++] = '0' + ((nr / div) % 10)) : \
+ (this->result[this->pos] = '\0'))
+#define add_char(c) (this->result[this->pos++] = c)
+probe /at_evalframe(arg0)/
+ this->framep = *(uintptr_t *)copyin(frame_ptr_addr, sizeof(uintptr_t));
+ this->frameo = copyin_obj(this->framep, PyFrameObject);
+ this->codep = this->frameo->f_code;
+ this->lineno = this->frameo->f_calllineno;
+ this->codeo = copyin_obj(this->codep, PyCodeObject);
+ this->filenamep = this->codeo->co_filename;
+ this->fnamep = this->codeo->co_name;
+ this->filenameo = copyin_obj(this->filenamep, PyStringObject);
+ this->fnameo = copyin_obj(this->fnamep, PyStringObject);
+ this->len = 1 + this->filenameo->ob_size + 1 + 5 + 2 +
+ this->fnameo->ob_size + 1 + 1;
+ this->result = (char *)alloca(this->len);
+ add_str(this->filenamep, this->filenameo);
+ add_digit(this->lineno, 10000);
+ add_digit(this->lineno, 1000);
+ add_digit(this->lineno, 100);
+ add_digit(this->lineno, 10);
+ add_digit(this->lineno, 1);
+ add_str(this->fnamep, this->fnameo);
+ this->result[this->pos] = '\0';
+ print_result(stringof(this->result));
+probe /!at_evalframe(arg0)/
+ probe function__entry(const char *, const char *, int);
+ probe function__return(const char *, const char *, int);