1 diff -ruN Python-2.6.7-orig/Include/frameobject.h Python-2.6.7/Include/frameobject.h
2 --- Python-2.6.7-orig/Include/frameobject.h 2008-02-14 12:47:33.000000000 +0000
3 +++ Python-2.6.7/Include/frameobject.h 2012-02-15 20:06:42.391256713 +0000
4 @@ -41,6 +41,7 @@
5 /* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
6 f_trace is set) -- at other times use PyCode_Addr2Line instead. */
7 int f_lineno; /* Current line number */
8 + int f_calllineno; /* line number of call site */
9 int f_iblock; /* index in f_blockstack */
10 PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
11 PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
12 diff -ruN Python-2.6.7-orig/Makefile.pre.in Python-2.6.7/Makefile.pre.in
13 --- Python-2.6.7-orig/Makefile.pre.in 2010-08-01 22:05:31.000000000 +0000
14 +++ Python-2.6.7/Makefile.pre.in 2012-02-15 20:06:42.391743222 +0000
15 @@ -201,6 +201,7 @@
16 GRAMMAR_C= $(srcdir)/Python/graminit.c
17 GRAMMAR_INPUT= $(srcdir)/Grammar/Grammar
18
19 +DTRACE_OBJS=Python/dtrace.o Python/phelper.o
20
21 ##########################################################################
22 # Parser
23 @@ -290,6 +291,7 @@
24 Python/formatter_unicode.o \
25 Python/formatter_string.o \
26 Python/$(DYNLOADFILE) \
27 + $(DTRACE_OBJS) \
28 $(LIBOBJS) \
29 $(MACHDEP_OBJS) \
30 $(THREADOBJ)
31 @@ -577,6 +579,18 @@
32 Python/formatter_string.o: $(srcdir)/Python/formatter_string.c \
33 $(STRINGLIB_HEADERS)
34
35 +Python/phelper.o: $(srcdir)/Python/phelper.d
36 + dtrace -o $@ -DPHELPER $(DFLAGS) $(CPPFLAGS) -C -G -s $(srcdir)/Python/phelper.d
37 +
38 +Python/python.h: $(srcdir)/Python/python.d
39 + dtrace -o $@ $(DFLAGS) -C -h -s $(srcdir)/Python/python.d
40 +
41 +Python/ceval.o: Python/ceval.c Python/python.h
42 + $(CC) -c $(BASECFLAGS) $(EXTRA_CFLAGS) $(CPPFLAGS) $(CFLAGSFORSHARED) -DPy_BUILD_CORE -o $@ $<
43 +
44 +Python/dtrace.o: $(srcdir)/Python/python.d Python/ceval.o
45 + dtrace -o $@ $(DFLAGS) -C -G -s $(srcdir)/Python/python.d Python/ceval.o
46 +
47 ############################################################################
48 # Header files
49
50 diff -ruN Python-2.6.7-orig/Objects/frameobject.c Python-2.6.7/Objects/frameobject.c
51 --- Python-2.6.7-orig/Objects/frameobject.c 2010-05-09 15:15:40.000000000 +0000
52 +++ Python-2.6.7/Objects/frameobject.c 2012-02-15 20:10:17.527441071 +0000
53 @@ -698,6 +698,7 @@
54 f->f_tstate = tstate;
55
56 f->f_lasti = -1;
57 + f->f_calllineno = code->co_firstlineno;
58 f->f_lineno = code->co_firstlineno;
59 f->f_iblock = 0;
60
61 diff -ruN Python-2.6.7-orig/Python/ceval.c Python-2.6.7/Python/ceval.c
62 --- Python-2.6.7-orig/Python/ceval.c 2010-06-23 18:17:18.000000000 +0000
63 +++ Python-2.6.7/Python/ceval.c 2012-02-15 20:09:36.195130867 +0000
64 @@ -19,6 +19,11 @@
65
66 #include <ctype.h>
67
68 +#define HAVE_DTRACE
69 +#ifdef HAVE_DTRACE
70 +#include "python.h"
71 +#endif
72 +
73 #ifndef WITH_TSC
74
75 #define READ_TIMESTAMP(var)
76 @@ -546,6 +551,55 @@
77 NULL);
78 }
79
80 +#ifdef HAVE_DTRACE
81 +static void
82 +dtrace_entry(PyFrameObject *f)
83 +{
84 + const char *filename;
85 + const char *fname;
86 + int lineno;
87 +
88 + filename = PyString_AsString(f->f_code->co_filename);
89 + fname = PyString_AsString(f->f_code->co_name);
90 + lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
91 +
92 + PYTHON_FUNCTION_ENTRY((char *)filename, (char *)fname, lineno);
93 +
94 + /*
95 + * Currently a USDT tail-call will not receive the correct arguments.
96 + * Disable the tail call here.
97 + */
98 +#if defined(__sparc)
99 + asm("nop");
100 +#endif
101 +}
102 +
103 +static void
104 +dtrace_return(PyFrameObject *f)
105 +{
106 + const char *filename;
107 + const char *fname;
108 + int lineno;
109 +
110 + filename = PyString_AsString(f->f_code->co_filename);
111 + fname = PyString_AsString(f->f_code->co_name);
112 + lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
113 + PYTHON_FUNCTION_RETURN((char *)filename, (char *)fname, lineno);
114 +
115 + /*
116 + * Currently a USDT tail-call will not receive the correct arguments.
117 + * Disable the tail call here.
118 + */
119 +#if defined(__sparc)
120 + asm("nop");
121 +#endif
122 +}
123 +#else
124 +#define PYTHON_FUNCTION_ENTRY_ENABLED 0
125 +#define PYTHON_FUNCTION_RETURN_ENABLED 0
126 +#define dtrace_entry()
127 +#define dtrace_return()
128 +#endif
129
130 /* Interpreter main loop */
131
132 @@ -557,9 +611,84 @@
133 return PyEval_EvalFrameEx(f, 0);
134 }
135
136 +/*
137 + * These shenanigans look like utter madness, but what we're actually doing is
138 + * making sure that the ustack helper will see the PyFrameObject pointer on the
139 + * stack. We have two tricky cases:
140 + *
141 + * amd64
142 + *
143 + * We use up the six registers for passing arguments, meaning the call can't
144 + * use a register for passing 'f', and has to push it onto the stack in a known
145 + * location.
146 + *
147 + * And how does "throwflag" figure in to this? -PN
148 + *
149 + * SPARC
150 + *
151 + * Here the problem is that (on 32-bit) the compiler is re-using %i0 before
152 + * some calls inside PyEval_EvalFrameReal(), which means that when it's saved,
153 + * it's just some junk value rather than the real first argument. So, instead,
154 + * we trace our proxy PyEval_EvalFrame(), where we 'know' the compiler won't
155 + * decide to re-use %i0. We also need to defeat optimization of our proxy.
156 + */
157 +
158 +#if defined(HAVE_DTRACE)
159 +
160 +#if defined(__amd64)
161 +PyObject *PyEval_EvalFrameExReal(long, long, long, long, long, long,
162 + PyFrameObject *, int throwflag);
163 +
164 +
165 +
166 PyObject *
167 PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
168 {
169 + volatile PyObject *f2;
170 + f2 = PyEval_EvalFrameExReal(0, 0, 0, 0, 0, 0, f, throwflag);
171 + return (PyObject *)f2;
172 +}
173 +
174 +PyObject *
175 +PyEval_EvalFrameExReal(long a1, long a2, long a3, long a4, long a5, long a6,
176 + PyFrameObject *f, int throwflag)
177 +{
178 +
179 +#elif defined(__sparc)
180 +
181 +PyObject *PyEval_EvalFrameExReal(PyFrameObject *f, int throwflag);
182 +
183 +volatile int dummy;
184 +
185 +PyObject *
186 +PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
187 +{
188 + volatile PyObject *f2;
189 + f2 = PyEval_EvalFrameExReal(f, throwflag);
190 + dummy = f->ob_refcnt;
191 + return (PyObject *)f2;
192 +}
193 +
194 +PyObject *
195 +PyEval_EvalFrameExReal(PyFrameObject *f, int throwflag)
196 +{
197 +
198 +#else /* __amd64 || __sparc */
199 +
200 +PyObject *
201 +PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
202 +{
203 +
204 +#endif /* __amd64 || __sparc */
205 +
206 +#else /* don't HAVE_DTRACE */
207 +
208 +PyObject *
209 +PyEval_EvalFrameexEx(PyFrameObject *f, int throwflag))
210 +{
211 +
212 +#endif /* HAVE_DTRACE */
213 +
214 #ifdef DXPAIRS
215 int lastopcode = 0;
216 #endif
217 @@ -782,6 +911,9 @@
218 }
219 }
220
221 + if (PYTHON_FUNCTION_ENTRY_ENABLED())
222 + dtrace_entry(f);
223 +
224 co = f->f_code;
225 names = co->co_names;
226 consts = co->co_consts;
227 @@ -2406,6 +2538,9 @@
228 PyObject **sp;
229 PCALL(PCALL_ALL);
230 sp = stack_pointer;
231 +#ifdef HAVE_DTRACE
232 + f->f_calllineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
233 +#endif
234 #ifdef WITH_TSC
235 x = call_function(&sp, oparg, &intr0, &intr1);
236 #else
237 @@ -2448,6 +2583,9 @@
238 } else
239 Py_INCREF(func);
240 sp = stack_pointer;
241 +#ifdef HAVE_DTRACE
242 + f->f_calllineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
243 +#endif
244 READ_TIMESTAMP(intr0);
245 x = ext_do_call(func, &sp, flags, na, nk);
246 READ_TIMESTAMP(intr1);
247 @@ -2746,6 +2884,8 @@
248
249 /* pop frame */
250 exit_eval_frame:
251 + if (PYTHON_FUNCTION_RETURN_ENABLED())
252 + dtrace_return(f);
253 Py_LeaveRecursiveCall();
254 tstate->frame = f->f_back;
255
256 diff -ruN Python-2.6.7-orig/Python/phelper.d Python-2.6.7/Python/phelper.d
257 --- Python-2.6.7-orig/Python/phelper.d 1970-01-01 00:00:00.000000000 +0000
258 +++ Python-2.6.7/Python/phelper.d 2012-02-15 20:06:42.395929142 +0000
259 @@ -0,0 +1,139 @@
260 +
261 +/*
262 + * Python ustack helper. This relies on the first argument (PyFrame *) being
263 + * on the stack; see Python/ceval.c for the contortions we go through to ensure
264 + * this is the case.
265 + *
266 + * On x86, the PyFrame * is two slots up from the frame pointer; on SPARC, it's
267 + * eight.
268 + */
269 +
270 +/*
271 + * Yes, this is as gross as it looks. DTrace cannot handle static functions,
272 + * and our stat_impl.h has them in ILP32.
273 + */
274 +#define _SYS_STAT_H
275 +
276 +#include <stdio.h>
277 +#include <sys/types.h>
278 +
279 +#include "pyport.h"
280 +#include "object.h"
281 +#include "pystate.h"
282 +#include "pyarena.h"
283 +#include "pythonrun.h"
284 +#include "compile.h"
285 +#include "frameobject.h"
286 +#include "stringobject.h"
287 +
288 +#if defined(__i386)
289 +#define startframe PyEval_EvalFrameEx
290 +#define endframe PyEval_EvalCodeEx
291 +#elif defined(__amd64)
292 +#define PyEval_EvalFrameEx PyEval_EvalFrameExReal
293 +#define startframe PyEval_EvalFrameExReal
294 +#define endframe PyEval_EvalCodeEx
295 +#elif defined(__sparc)
296 +#define PyEval_EvalFrameEx PyEval_EvalFrameExReal
297 +#define startframe PyEval_EvalFrameEx
298 +#define endframe PyEval_EvalFrameExReal
299 +#endif
300 +
301 +#ifdef __sparcv9
302 +#define STACK_BIAS (2048-1)
303 +#else
304 +#define STACK_BIAS 0
305 +#endif
306 +
307 +/*
308 + * Not defining PHELPER lets us test this code as a normal D script.
309 + */
310 +#ifdef PHELPER
311 +
312 +#define at_evalframe(addr) \
313 + ((uintptr_t)addr >= ((uintptr_t)&``startframe) && \
314 + (uintptr_t)addr < ((uintptr_t)&``endframe))
315 +#define probe dtrace:helper:ustack:
316 +#define print_result(r) (r)
317 +
318 +#if defined(__i386) || defined(__amd64)
319 +#define frame_ptr_addr ((uintptr_t)arg1 + sizeof(uintptr_t) * 2)
320 +#elif defined(__sparc)
321 +#define frame_ptr_addr ((uintptr_t)arg1 + STACK_BIAS + sizeof(uintptr_t) * 8)
322 +#else
323 +#error unknown architecture
324 +#endif
325 +
326 +#else /* PHELPER */
327 +
328 +#define at_evalframe(addr) (1)
329 +#define probe pid$target::PyEval_EvalFrame:entry
330 +#define print_result(r) (trace(r))
331 +
332 +#if defined(__i386) || defined(__amd64)
333 +#define frame_ptr_addr ((uintptr_t)uregs[R_SP] + sizeof(uintptr_t))
334 +#elif defined(__sparc)
335 +/*
336 + * Not implemented: we could just use R_I0, but what's the point?
337 + */
338 +#else
339 +#error unknown architecture
340 +#endif
341 +
342 +#endif /* PHELPER */
343 +
344 +extern uintptr_t PyEval_EvalFrameEx;
345 +extern uintptr_t PyEval_EvalCodeEx;
346 +
347 +#define copyin_obj(addr, obj) ((obj *)copyin((uintptr_t)addr, sizeof(obj)))
348 +#define pystr_addr(addr) ((char *)addr + offsetof(PyStringObject, ob_sval))
349 +#define copyin_str(dest, addr, obj) \
350 + (copyinto((uintptr_t)pystr_addr(addr), obj->ob_size, (dest)))
351 +#define add_str(addr, obj) \
352 + copyin_str(this->result + this->pos, addr, obj); \
353 + this->pos += obj->ob_size; \
354 + this->result[this->pos] = '\0';
355 +#define add_digit(nr, div) ((nr / div) ? \
356 + (this->result[this->pos++] = '0' + ((nr / div) % 10)) : \
357 + (this->result[this->pos] = '\0'))
358 +#define add_char(c) (this->result[this->pos++] = c)
359 +
360 +probe /at_evalframe(arg0)/
361 +{
362 + this->framep = *(uintptr_t *)copyin(frame_ptr_addr, sizeof(uintptr_t));
363 + this->frameo = copyin_obj(this->framep, PyFrameObject);
364 + this->codep = this->frameo->f_code;
365 + this->lineno = this->frameo->f_calllineno;
366 + this->codeo = copyin_obj(this->codep, PyCodeObject);
367 + this->filenamep = this->codeo->co_filename;
368 + this->fnamep = this->codeo->co_name;
369 + this->filenameo = copyin_obj(this->filenamep, PyStringObject);
370 + this->fnameo = copyin_obj(this->fnamep, PyStringObject);
371 +
372 + this->len = 1 + this->filenameo->ob_size + 1 + 5 + 2 +
373 + this->fnameo->ob_size + 1 + 1;
374 +
375 + this->result = (char *)alloca(this->len);
376 + this->pos = 0;
377 +
378 + add_char('@');
379 + add_str(this->filenamep, this->filenameo);
380 + add_char(':');
381 + add_digit(this->lineno, 10000);
382 + add_digit(this->lineno, 1000);
383 + add_digit(this->lineno, 100);
384 + add_digit(this->lineno, 10);
385 + add_digit(this->lineno, 1);
386 + add_char(' ');
387 + add_char('(');
388 + add_str(this->fnamep, this->fnameo);
389 + add_char(')');
390 + this->result[this->pos] = '\0';
391 +
392 + print_result(stringof(this->result));
393 +}
394 +
395 +probe /!at_evalframe(arg0)/
396 +{
397 + NULL;
398 +}
399 diff -ruN Python-2.6.7-orig/Python/python.d Python-2.6.7/Python/python.d
400 --- Python-2.6.7-orig/Python/python.d 1970-01-01 00:00:00.000000000 +0000
401 +++ Python-2.6.7/Python/python.d 2012-02-15 20:06:42.396028117 +0000
402 @@ -0,0 +1,10 @@
403 +provider python {
404 + probe function__entry(const char *, const char *, int);
405 + probe function__return(const char *, const char *, int);
406 +};
407 +
408 +#pragma D attributes Evolving/Evolving/Common provider python provider
409 +#pragma D attributes Private/Private/Common provider python module
410 +#pragma D attributes Private/Private/Common provider python function
411 +#pragma D attributes Evolving/Evolving/Common provider python name
412 +#pragma D attributes Evolving/Evolving/Common provider python args