Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
411 lines (394 sloc) 11.9 KB
Appears to be original DTrace patch. Unfortunately, it's impossible to
tell, since Oracle nuked the OpenSolaris commit history when they closed
Solaris source. This is sketchily extracted from an OpenIndiana JDS
repository?
REF: http://hg.opensolaris.cz/oi-jds/raw-file/cc5807d26ec5/patches/Python-07-dtrace.diff
diff -prauN Python-2.4.4/Include/frameobject.h Python-new/Include/frameobject.h
--- Python-2.4.4/Include/frameobject.h 2004-07-01 23:41:07.000000000 -0700
+++ Python-new/Include/frameobject.h 2007-07-03 07:59:58.696193000 -0700
@@ -32,6 +32,7 @@ typedef struct _frame {
/* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
f_trace is set) -- at other times use PyCode_Addr2Line instead. */
int f_lineno; /* Current line number */
+ int f_calllineno; /* line number of call site */
int f_restricted; /* Flag set if restricted operations
in this scope */
int f_iblock; /* index in f_blockstack */
diff -prauN Python-2.4.4/Makefile.pre.in Python-new/Makefile.pre.in
--- Python-2.4.4/Makefile.pre.in 2006-10-08 10:41:25.000000000 -0700
+++ Python-new/Makefile.pre.in 2007-07-12 11:34:02.483271000 -0700
@@ -217,6 +217,7 @@ PGOBJS= \
PGENOBJS= $(PGENMAIN) $(POBJS) $(PGOBJS)
+DTRACE_OBJS=Python/dtrace.o Python/phelper.o
##########################################################################
# Python
@@ -253,6 +254,7 @@ PYTHON_OBJS= \
Python/getopt.o \
Python/pystrtod.o \
Python/$(DYNLOADFILE) \
+ $(DTRACE_OBJS) \
$(MACHDEP_OBJS) \
$(THREADOBJ)
@@ -479,6 +481,17 @@ Python/importdl.o: $(srcdir)/Python/impo
Objects/unicodectype.o: $(srcdir)/Objects/unicodectype.c \
$(srcdir)/Objects/unicodetype_db.h
+Python/phelper.o: $(srcdir)/Python/phelper.d
+ dtrace -o $@ -DPHELPER $(DFLAGS) $(CPPFLAGS) -C -G -s $(srcdir)/Python/phelper.d
+
+Python/python.h: $(srcdir)/Python/python.d
+ dtrace -o $@ $(DFLAGS) -C -h -s $(srcdir)/Python/python.d
+
+Python/ceval.o: Python/python.h
+
+Python/dtrace.o: $(srcdir)/Python/python.d Python/ceval.o
+ dtrace -o $@ $(DFLAGS) -C -G -s $(srcdir)/Python/python.d Python/ceval.o
+
############################################################################
# Header files
diff -prauN Python-2.4.4/Objects/frameobject.c Python-new/Objects/frameobject.c
--- Python-2.4.4/Objects/frameobject.c 2004-07-01 23:41:07.000000000 -0700
+++ Python-new/Objects/frameobject.c 2007-07-03 07:59:58.720162000 -0700
@@ -633,6 +633,7 @@ PyFrame_New(PyThreadState *tstate, PyCod
f->f_lasti = -1;
f->f_lineno = code->co_firstlineno;
+ f->f_calllineno = code->co_firstlineno;
f->f_restricted = (builtins != tstate->interp->builtins);
f->f_iblock = 0;
f->f_nlocals = code->co_nlocals;
diff -prauN Python-2.4.4/Python/ceval.c Python-new/Python/ceval.c
--- Python-2.4.4/Python/ceval.c 2006-10-06 12:09:36.000000000 -0700
+++ Python-new/Python/ceval.c 2007-07-12 12:39:29.067739000 -0700
@@ -16,6 +16,11 @@
#include <ctype.h>
+#define HAVE_DTRACE
+#ifdef HAVE_DTRACE
+#include "python.h"
+#endif
+
#ifndef WITH_TSC
#define rdtscll(var)
#else /*WITH_TSC defined*/
@@ -490,11 +495,132 @@ PyEval_EvalCode(PyCodeObject *co, PyObje
}
+#ifdef HAVE_DTRACE
+static void
+dtrace_entry(PyFrameObject *f)
+{
+ const char *filename;
+ const char *fname;
+ int lineno;
+
+ 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.
+ */
+#if defined(__sparc)
+ asm("nop");
+#endif
+}
+
+static void
+dtrace_return(PyFrameObject *f)
+{
+ const char *filename;
+ const char *fname;
+ int lineno;
+
+ 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.
+ */
+#if defined(__sparc)
+ asm("nop");
+#endif
+}
+#else
+#define PYTHON_FUNCTION_ENTRY_ENABLED 0
+#define PYTHON_FUNCTION_RETURN_ENABLED 0
+#define dtrace_entry()
+#define dtrace_return()
+#endif
+
/* Interpreter main loop */
+/*
+ * 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:
+ *
+ * amd64
+ *
+ * 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
+ * location.
+ *
+ * SPARC
+ *
+ * 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)
+
+#if defined(__amd64)
+PyObject *PyEval_EvalFrameReal(long, long, long, long, long, long,
+ PyFrameObject *);
+
PyObject *
PyEval_EvalFrame(PyFrameObject *f)
{
+ volatile PyObject *f2;
+ f2 = PyEval_EvalFrameReal(0, 0, 0, 0, 0, 0, f);
+ return (PyObject *)f2;
+}
+
+PyObject *
+PyEval_EvalFrameReal(long a1, long a2, long a3, long a4, long a5, long a6,
+ PyFrameObject *f)
+{
+
+#elif defined(__sparc)
+
+PyObject *PyEval_EvalFrameReal(PyFrameObject *f);
+
+volatile int dummy;
+
+PyObject *
+PyEval_EvalFrame(PyFrameObject *f)
+{
+ volatile PyObject *f2;
+ f2 = PyEval_EvalFrameReal(f);
+ dummy = f->ob_refcnt;
+ return (PyObject *)f2;
+}
+
+PyObject *
+PyEval_EvalFrameReal(PyFrameObject *f)
+{
+
+#else /* __amd64 || __sparc */
+
+PyObject *
+PyEval_EvalFrame(PyFrameObject *f)
+{
+
+#endif /* __amd64 || __sparc */
+
+#else /* HAVE_DTRACE */
+
+PyObject *
+PyEval_EvalFrame(PyFrameObject *f)
+{
+
+#endif /* HAVE_DTRACE */
+
#ifdef DXPAIRS
int lastopcode = 0;
#endif
@@ -710,6 +836,9 @@ PyEval_EvalFrame(PyFrameObject *f)
}
}
+ if (PYTHON_FUNCTION_ENTRY_ENABLED())
+ dtrace_entry(f);
+
co = f->f_code;
names = co->co_names;
consts = co->co_consts;
@@ -2161,6 +2290,10 @@ PyEval_EvalFrame(PyFrameObject *f)
PyObject **sp;
PCALL(PCALL_ALL);
sp = stack_pointer;
+#ifdef HAVE_DTRACE
+ f->f_calllineno = PyCode_Addr2Line(f->f_code,
+ f->f_lasti);
+#endif
#ifdef WITH_TSC
x = call_function(&sp, oparg, &intr0, &intr1);
#else
@@ -2203,6 +2336,10 @@ PyEval_EvalFrame(PyFrameObject *f)
} else
Py_INCREF(func);
sp = stack_pointer;
+#ifdef HAVE_DTRACE
+ f->f_calllineno = PyCode_Addr2Line(f->f_code,
+ f->f_lasti);
+#endif
rdtscll(intr0);
x = ext_do_call(func, &sp, flags, na, nk);
rdtscll(intr1);
@@ -2501,6 +2638,8 @@ fast_yield:
/* pop frame */
exit_eval_frame:
+ if (PYTHON_FUNCTION_RETURN_ENABLED())
+ dtrace_return(f);
Py_LeaveRecursiveCall();
tstate->frame = f->f_back;
diff -prauN Python-2.4.4/Python/phelper.d Python-new/Python/phelper.d
--- Python-2.4.4/Python/phelper.d 1969-12-31 16:00:00.000000000 -0800
+++ Python-new/Python/phelper.d 2007-07-03 07:59:58.727255000 -0700
@@ -0,0 +1,138 @@
+
+/*
+ * 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
+ * this is the case.
+ *
+ * On x86, the PyFrame * is two slots up from the frame pointer; on SPARC, it's
+ * eight.
+ */
+
+/*
+ * Yes, this is as gross as it looks. DTrace cannot handle static functions,
+ * and our stat_impl.h has them in ILP32.
+ */
+#define _SYS_STAT_H
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "pyport.h"
+#include "object.h"
+#include "pystate.h"
+#include "pythonrun.h"
+#include "compile.h"
+#include "frameobject.h"
+#include "stringobject.h"
+
+#if defined(__i386)
+#define startframe PyEval_EvalFrame
+#define endframe PyEval_EvalCodeEx
+#elif defined(__amd64)
+#define PyEval_EvalFrame PyEval_EvalFrameReal
+#define startframe PyEval_EvalFrameReal
+#define endframe PyEval_EvalCodeEx
+#elif defined(__sparc)
+#define startframe PyEval_EvalFrame
+#define endframe PyEval_EvalFrameReal
+#endif
+
+#ifdef __sparcv9
+#define STACK_BIAS (2048-1)
+#else
+#define STACK_BIAS 0
+#endif
+
+/*
+ * Not defining PHELPER lets us test this code as a normal D script.
+ */
+#ifdef PHELPER
+
+#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)
+#elif defined(__sparc)
+#define frame_ptr_addr ((uintptr_t)arg1 + STACK_BIAS + sizeof(uintptr_t) * 8)
+#else
+#error unknown architecture
+#endif
+
+#else /* PHELPER */
+
+#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))
+#elif defined(__sparc)
+/*
+ * Not implemented: we could just use R_I0, but what's the point?
+ */
+#else
+#error unknown architecture
+#endif
+
+#endif /* PHELPER */
+
+extern uintptr_t PyEval_EvalFrame;
+extern uintptr_t PyEval_EvalFrameReal;
+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);
+ this->pos = 0;
+
+ add_char('@');
+ add_str(this->filenamep, this->filenameo);
+ add_char(':');
+ 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_char(' ');
+ add_char('(');
+ add_str(this->fnamep, this->fnameo);
+ add_char(')');
+ this->result[this->pos] = '\0';
+
+ print_result(stringof(this->result));
+}
+
+probe /!at_evalframe(arg0)/
+{
+ NULL;
+}
diff -prauN Python-2.4.4/Python/python.d Python-new/Python/python.d
--- Python-2.4.4/Python/python.d 1969-12-31 16:00:00.000000000 -0800
+++ Python-new/Python/python.d 2007-07-03 07:59:58.727981000 -0700
@@ -0,0 +1,10 @@
+provider python {
+ probe function__entry(const char *, const char *, int);
+ probe function__return(const char *, const char *, int);
+};
+
+#pragma D attributes Evolving/Evolving/Common provider python provider
+#pragma D attributes Private/Private/Common provider python module
+#pragma D attributes Private/Private/Common provider python function
+#pragma D attributes Evolving/Evolving/Common provider python name
+#pragma D attributes Evolving/Evolving/Common provider python args
You can’t perform that action at this time.