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