|
1 diff --git Python-2.6.4/Include/frameobject.h Python-2.6.4/Include/frameobject.h |
|
2 --- Python-2.6.4/Include/frameobject.h |
|
3 +++ Python-2.6.4/Include/frameobject.h |
|
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 --git Python-2.6.4/Makefile.pre.in Python-2.6.4/Makefile.pre.in |
|
13 --- Python-2.6.4/Makefile.pre.in |
|
14 +++ Python-2.6.4/Makefile.pre.in |
|
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 --git Python-2.6.4/Objects/frameobject.c Python-2.6.4/Objects/frameobject.c |
|
51 --- Python-2.6.4/Objects/frameobject.c |
|
52 +++ Python-2.6.4/Objects/frameobject.c |
|
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 --git Python-2.6.4/Python/ceval.c Python-2.6.4/Python/ceval.c |
|
62 --- Python-2.6.4/Python/ceval.c |
|
63 +++ Python-2.6.4/Python/ceval.c |
|
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 @@ -527,6 +532,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 @@ -538,9 +592,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 @@ -763,6 +892,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 @@ -2383,6 +2515,10 @@ |
|
228 PyObject **sp; |
|
229 PCALL(PCALL_ALL); |
|
230 sp = stack_pointer; |
|
231 +#ifdef HAVE_DTRACE |
|
232 + f->f_calllineno = PyCode_Addr2Line(f->f_code, |
|
233 + f->f_lasti); |
|
234 +#endif |
|
235 #ifdef WITH_TSC |
|
236 x = call_function(&sp, oparg, &intr0, &intr1); |
|
237 #else |
|
238 @@ -2425,6 +2561,11 @@ |
|
239 } else |
|
240 Py_INCREF(func); |
|
241 sp = stack_pointer; |
|
242 +#ifdef HAVE_DTRACE |
|
243 + f->f_calllineno = PyCode_Addr2Line(f->f_code, |
|
244 + f->f_lasti); |
|
245 +#endif |
|
246 + |
|
247 READ_TIMESTAMP(intr0); |
|
248 x = ext_do_call(func, &sp, flags, na, nk); |
|
249 READ_TIMESTAMP(intr1); |
|
250 @@ -2723,6 +2864,8 @@ |
|
251 |
|
252 /* pop frame */ |
|
253 exit_eval_frame: |
|
254 + if (PYTHON_FUNCTION_RETURN_ENABLED()) |
|
255 + dtrace_return(f); |
|
256 Py_LeaveRecursiveCall(); |
|
257 tstate->frame = f->f_back; |
|
258 |
|
259 diff --git Python-2.6.4/Python/phelper.d Python-2.6.4/Python/phelper.d |
|
260 new file mode 100644 |
|
261 --- /dev/null |
|
262 +++ Python-2.6.4/Python/phelper.d |
|
263 @@ -0,0 +1,139 @@ |
|
264 + |
|
265 +/* |
|
266 + * Python ustack helper. This relies on the first argument (PyFrame *) being |
|
267 + * on the stack; see Python/ceval.c for the contortions we go through to ensure |
|
268 + * this is the case. |
|
269 + * |
|
270 + * On x86, the PyFrame * is two slots up from the frame pointer; on SPARC, it's |
|
271 + * eight. |
|
272 + */ |
|
273 + |
|
274 +/* |
|
275 + * Yes, this is as gross as it looks. DTrace cannot handle static functions, |
|
276 + * and our stat_impl.h has them in ILP32. |
|
277 + */ |
|
278 +#define _SYS_STAT_H |
|
279 + |
|
280 +#include <stdio.h> |
|
281 +#include <sys/types.h> |
|
282 + |
|
283 +#include "pyport.h" |
|
284 +#include "object.h" |
|
285 +#include "pystate.h" |
|
286 +#include "pyarena.h" |
|
287 +#include "pythonrun.h" |
|
288 +#include "compile.h" |
|
289 +#include "frameobject.h" |
|
290 +#include "stringobject.h" |
|
291 + |
|
292 +#if defined(__i386) |
|
293 +#define startframe PyEval_EvalFrameEx |
|
294 +#define endframe PyEval_EvalCodeEx |
|
295 +#elif defined(__amd64) |
|
296 +#define PyEval_EvalFrameEx PyEval_EvalFrameExReal |
|
297 +#define startframe PyEval_EvalFrameExReal |
|
298 +#define endframe PyEval_EvalCodeEx |
|
299 +#elif defined(__sparc) |
|
300 +#define PyEval_EvalFrameEx PyEval_EvalFrameExReal |
|
301 +#define startframe PyEval_EvalFrameEx |
|
302 +#define endframe PyEval_EvalFrameExReal |
|
303 +#endif |
|
304 + |
|
305 +#ifdef __sparcv9 |
|
306 +#define STACK_BIAS (2048-1) |
|
307 +#else |
|
308 +#define STACK_BIAS 0 |
|
309 +#endif |
|
310 + |
|
311 +/* |
|
312 + * Not defining PHELPER lets us test this code as a normal D script. |
|
313 + */ |
|
314 +#ifdef PHELPER |
|
315 + |
|
316 +#define at_evalframe(addr) \ |
|
317 + ((uintptr_t)addr >= ((uintptr_t)&``startframe) && \ |
|
318 + (uintptr_t)addr < ((uintptr_t)&``endframe)) |
|
319 +#define probe dtrace:helper:ustack: |
|
320 +#define print_result(r) (r) |
|
321 + |
|
322 +#if defined(__i386) || defined(__amd64) |
|
323 +#define frame_ptr_addr ((uintptr_t)arg1 + sizeof(uintptr_t) * 2) |
|
324 +#elif defined(__sparc) |
|
325 +#define frame_ptr_addr ((uintptr_t)arg1 + STACK_BIAS + sizeof(uintptr_t) * 8) |
|
326 +#else |
|
327 +#error unknown architecture |
|
328 +#endif |
|
329 + |
|
330 +#else /* PHELPER */ |
|
331 + |
|
332 +#define at_evalframe(addr) (1) |
|
333 +#define probe pid$target::PyEval_EvalFrame:entry |
|
334 +#define print_result(r) (trace(r)) |
|
335 + |
|
336 +#if defined(__i386) || defined(__amd64) |
|
337 +#define frame_ptr_addr ((uintptr_t)uregs[R_SP] + sizeof(uintptr_t)) |
|
338 +#elif defined(__sparc) |
|
339 +/* |
|
340 + * Not implemented: we could just use R_I0, but what's the point? |
|
341 + */ |
|
342 +#else |
|
343 +#error unknown architecture |
|
344 +#endif |
|
345 + |
|
346 +#endif /* PHELPER */ |
|
347 + |
|
348 +extern uintptr_t PyEval_EvalFrameEx; |
|
349 +extern uintptr_t PyEval_EvalCodeEx; |
|
350 + |
|
351 +#define copyin_obj(addr, obj) ((obj *)copyin((uintptr_t)addr, sizeof(obj))) |
|
352 +#define pystr_addr(addr) ((char *)addr + offsetof(PyStringObject, ob_sval)) |
|
353 +#define copyin_str(dest, addr, obj) \ |
|
354 + (copyinto((uintptr_t)pystr_addr(addr), obj->ob_size, (dest))) |
|
355 +#define add_str(addr, obj) \ |
|
356 + copyin_str(this->result + this->pos, addr, obj); \ |
|
357 + this->pos += obj->ob_size; \ |
|
358 + this->result[this->pos] = '\0'; |
|
359 +#define add_digit(nr, div) ((nr / div) ? \ |
|
360 + (this->result[this->pos++] = '0' + ((nr / div) % 10)) : \ |
|
361 + (this->result[this->pos] = '\0')) |
|
362 +#define add_char(c) (this->result[this->pos++] = c) |
|
363 + |
|
364 +probe /at_evalframe(arg0)/ |
|
365 +{ |
|
366 + this->framep = *(uintptr_t *)copyin(frame_ptr_addr, sizeof(uintptr_t)); |
|
367 + this->frameo = copyin_obj(this->framep, PyFrameObject); |
|
368 + this->codep = this->frameo->f_code; |
|
369 + this->lineno = this->frameo->f_calllineno; |
|
370 + this->codeo = copyin_obj(this->codep, PyCodeObject); |
|
371 + this->filenamep = this->codeo->co_filename; |
|
372 + this->fnamep = this->codeo->co_name; |
|
373 + this->filenameo = copyin_obj(this->filenamep, PyStringObject); |
|
374 + this->fnameo = copyin_obj(this->fnamep, PyStringObject); |
|
375 + |
|
376 + this->len = 1 + this->filenameo->ob_size + 1 + 5 + 2 + |
|
377 + this->fnameo->ob_size + 1 + 1; |
|
378 + |
|
379 + this->result = (char *)alloca(this->len); |
|
380 + this->pos = 0; |
|
381 + |
|
382 + add_char('@'); |
|
383 + add_str(this->filenamep, this->filenameo); |
|
384 + add_char(':'); |
|
385 + add_digit(this->lineno, 10000); |
|
386 + add_digit(this->lineno, 1000); |
|
387 + add_digit(this->lineno, 100); |
|
388 + add_digit(this->lineno, 10); |
|
389 + add_digit(this->lineno, 1); |
|
390 + add_char(' '); |
|
391 + add_char('('); |
|
392 + add_str(this->fnamep, this->fnameo); |
|
393 + add_char(')'); |
|
394 + this->result[this->pos] = '\0'; |
|
395 + |
|
396 + print_result(stringof(this->result)); |
|
397 +} |
|
398 + |
|
399 +probe /!at_evalframe(arg0)/ |
|
400 +{ |
|
401 + NULL; |
|
402 +} |
|
403 diff --git Python-2.6.4/Python/python.d Python-2.6.4/Python/python.d |
|
404 new file mode 100644 |
|
405 --- /dev/null |
|
406 +++ Python-2.6.4/Python/python.d |
|
407 @@ -0,0 +1,10 @@ |
|
408 +provider python { |
|
409 + probe function__entry(const char *, const char *, int); |
|
410 + probe function__return(const char *, const char *, int); |
|
411 +}; |
|
412 + |
|
413 +#pragma D attributes Evolving/Evolving/Common provider python provider |
|
414 +#pragma D attributes Private/Private/Common provider python module |
|
415 +#pragma D attributes Private/Private/Common provider python function |
|
416 +#pragma D attributes Evolving/Evolving/Common provider python name |
|
417 +#pragma D attributes Evolving/Evolving/Common provider python args |