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