OpenGrok

Cross Reference: Python-07-dtrace.diff
xref: /jds/spec-files/trunk/patches/Python-07-dtrace.diff
Home | History | Annotate | Line # | Download | only in patches
      1 diff -prauN Python-2.4.4/Include/frameobject.h Python-new/Include/frameobject.h
      2 --- Python-2.4.4/Include/frameobject.h	2004-07-01 23:41:07.000000000 -0700
      3 +++ Python-new/Include/frameobject.h	2007-07-03 07:59:58.696193000 -0700
      4 @@ -32,6 +32,7 @@ typedef struct _frame {
      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_restricted;		/* Flag set if restricted operations
     10  				   in this scope */
     11      int f_iblock;		/* index in f_blockstack */
     12 diff -prauN Python-2.4.4/Makefile.pre.in Python-new/Makefile.pre.in
     13 --- Python-2.4.4/Makefile.pre.in	2006-10-08 10:41:25.000000000 -0700
     14 +++ Python-new/Makefile.pre.in	2007-07-12 11:34:02.483271000 -0700
     15 @@ -217,6 +217,7 @@ PGOBJS=		\
     16  
     17  PGENOBJS=	$(PGENMAIN) $(POBJS) $(PGOBJS)
     18  
     19 +DTRACE_OBJS=Python/dtrace.o Python/phelper.o
     20  
     21  ##########################################################################
     22  # Python
     23 @@ -253,6 +254,7 @@ PYTHON_OBJS=	\
     24  		Python/getopt.o \
     25  		Python/pystrtod.o \
     26  		Python/$(DYNLOADFILE) \
     27 +		$(DTRACE_OBJS) \
     28  		$(MACHDEP_OBJS) \
     29  		$(THREADOBJ)
     30  
     31 @@ -479,6 +481,17 @@ Python/importdl.o: $(srcdir)/Python/impo
     32  Objects/unicodectype.o:	$(srcdir)/Objects/unicodectype.c \
     33  				$(srcdir)/Objects/unicodetype_db.h
     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 -prauN Python-2.4.4/Objects/frameobject.c Python-new/Objects/frameobject.c
     50 --- Python-2.4.4/Objects/frameobject.c	2004-07-01 23:41:07.000000000 -0700
     51 +++ Python-new/Objects/frameobject.c	2007-07-03 07:59:58.720162000 -0700
     52 @@ -633,6 +633,7 @@ PyFrame_New(PyThreadState *tstate, PyCod
     53  
     54  	f->f_lasti = -1;
     55  	f->f_lineno = code->co_firstlineno;
     56 +	f->f_calllineno = code->co_firstlineno;
     57  	f->f_restricted = (builtins != tstate->interp->builtins);
     58  	f->f_iblock = 0;
     59  	f->f_nlocals = code->co_nlocals;
     60 diff -prauN Python-2.4.4/Python/ceval.c Python-new/Python/ceval.c
     61 --- Python-2.4.4/Python/ceval.c	2006-10-06 12:09:36.000000000 -0700
     62 +++ Python-new/Python/ceval.c	2007-07-12 12:39:29.067739000 -0700
     63 @@ -16,6 +16,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  #define rdtscll(var)
     74  #else /*WITH_TSC defined*/
     75 @@ -490,11 +495,132 @@ PyEval_EvalCode(PyCodeObject *co, PyObje
     76  }
     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 +/*
    132 + * These shenanigans look like utter madness, but what we're actually doing is
    133 + * making sure that the ustack helper will see the PyFrameObject pointer on the
    134 + * stack. We have two tricky cases:
    135 + *
    136 + * amd64
    137 + *
    138 + * We use up the six registers for passing arguments, meaning the call can't
    139 + * use a register for passing 'f', and has to push it onto the stack in a known
    140 + * location.
    141 + *
    142 + * SPARC
    143 + *
    144 + * Here the problem is that (on 32-bit) the compiler is re-using %i0 before
    145 + * some calls inside PyEval_EvalFrameReal(), which means that when it's saved,
    146 + * it's just some junk value rather than the real first argument. So, instead,
    147 + * we trace our proxy PyEval_EvalFrame(), where we 'know' the compiler won't
    148 + * decide to re-use %i0. We also need to defeat optimization of our proxy.
    149 + */
    150 +
    151 +#if defined(HAVE_DTRACE)
    152 +
    153 +#if defined(__amd64)
    154 +PyObject *PyEval_EvalFrameReal(long, long, long, long, long, long,
    155 +    PyFrameObject *);
    156 +
    157  PyObject *
    158  PyEval_EvalFrame(PyFrameObject *f)
    159  {
    160 +	volatile PyObject *f2;
    161 +	f2 = PyEval_EvalFrameReal(0, 0, 0, 0, 0, 0, f);
    162 +	return (PyObject *)f2;
    163 +}
    164 +
    165 +PyObject *
    166 +PyEval_EvalFrameReal(long a1, long a2, long a3, long a4, long a5, long a6,
    167 +    PyFrameObject *f)
    168 +{
    169 +
    170 +#elif defined(__sparc)
    171 +
    172 +PyObject *PyEval_EvalFrameReal(PyFrameObject *f);
    173 +
    174 +volatile int dummy;
    175 +
    176 +PyObject *
    177 +PyEval_EvalFrame(PyFrameObject *f)
    178 +{
    179 +	volatile PyObject *f2;
    180 +	f2 = PyEval_EvalFrameReal(f);
    181 +	dummy = f->ob_refcnt;
    182 +	return (PyObject *)f2;
    183 +}
    184 +
    185 +PyObject *
    186 +PyEval_EvalFrameReal(PyFrameObject *f)
    187 +{
    188 +
    189 +#else /* __amd64 || __sparc */
    190 +
    191 +PyObject *
    192 +PyEval_EvalFrame(PyFrameObject *f)
    193 +{
    194 +
    195 +#endif /* __amd64 || __sparc */
    196 +
    197 +#else /* HAVE_DTRACE */
    198 +
    199 +PyObject *
    200 +PyEval_EvalFrame(PyFrameObject *f)
    201 +{
    202 +
    203 +#endif /* HAVE_DTRACE */
    204 +
    205  #ifdef DXPAIRS
    206  	int lastopcode = 0;
    207  #endif
    208 @@ -710,6 +836,9 @@ PyEval_EvalFrame(PyFrameObject *f)
    209  		}
    210  	}
    211  
    212 +	if (PYTHON_FUNCTION_ENTRY_ENABLED())
    213 +		dtrace_entry(f);
    214 +
    215  	co = f->f_code;
    216  	names = co->co_names;
    217  	consts = co->co_consts;
    218 @@ -2161,6 +2290,10 @@ PyEval_EvalFrame(PyFrameObject *f)
    219  			PyObject **sp;
    220  			PCALL(PCALL_ALL);
    221  			sp = stack_pointer;
    222 +#ifdef HAVE_DTRACE
    223 +			f->f_calllineno = PyCode_Addr2Line(f->f_code,
    224 +			                                   f->f_lasti);
    225 +#endif
    226  #ifdef WITH_TSC
    227  			x = call_function(&sp, oparg, &intr0, &intr1);
    228  #else
    229 @@ -2203,6 +2336,10 @@ PyEval_EvalFrame(PyFrameObject *f)
    230  		    } else
    231  			    Py_INCREF(func);
    232  		    sp = stack_pointer;
    233 +#ifdef HAVE_DTRACE
    234 +		    f->f_calllineno = PyCode_Addr2Line(f->f_code,
    235 +		                                       f->f_lasti);
    236 +#endif
    237  		    rdtscll(intr0);
    238  		    x = ext_do_call(func, &sp, flags, na, nk);
    239  		    rdtscll(intr1);
    240 @@ -2501,6 +2638,8 @@ fast_yield:
    241  
    242  	/* pop frame */
    243      exit_eval_frame:
    244 +	if (PYTHON_FUNCTION_RETURN_ENABLED())
    245 +		dtrace_return(f);
    246  	Py_LeaveRecursiveCall();
    247  	tstate->frame = f->f_back;
    248  
    249 diff -prauN Python-2.4.4/Python/phelper.d Python-new/Python/phelper.d
    250 --- Python-2.4.4/Python/phelper.d	1969-12-31 16:00:00.000000000 -0800
    251 +++ Python-new/Python/phelper.d	2007-07-03 07:59:58.727255000 -0700
    252 @@ -0,0 +1,138 @@
    253 +
    254 +/*
    255 + * Python ustack helper.  This relies on the first argument (PyFrame *) being
    256 + * on the stack; see Python/ceval.c for the contortions we go through to ensure
    257 + * this is the case.
    258 + *
    259 + * On x86, the PyFrame * is two slots up from the frame pointer; on SPARC, it's
    260 + * eight.
    261 + */
    262 +
    263 +/*
    264 + * Yes, this is as gross as it looks. DTrace cannot handle static functions,
    265 + * and our stat_impl.h has them in ILP32.
    266 + */
    267 +#define _SYS_STAT_H
    268 +
    269 +#include <stdio.h>
    270 +#include <sys/types.h>
    271 +
    272 +#include "pyport.h"
    273 +#include "object.h"
    274 +#include "pystate.h"
    275 +#include "pythonrun.h"
    276 +#include "compile.h"
    277 +#include "frameobject.h"
    278 +#include "stringobject.h"
    279 +
    280 +#if defined(__i386)
    281 +#define	startframe PyEval_EvalFrame
    282 +#define	endframe PyEval_EvalCodeEx
    283 +#elif defined(__amd64)
    284 +#define	PyEval_EvalFrame PyEval_EvalFrameReal
    285 +#define	startframe PyEval_EvalFrameReal
    286 +#define	endframe PyEval_EvalCodeEx
    287 +#elif defined(__sparc)
    288 +#define	startframe PyEval_EvalFrame
    289 +#define	endframe PyEval_EvalFrameReal
    290 +#endif
    291 +
    292 +#ifdef __sparcv9
    293 +#define	STACK_BIAS (2048-1)
    294 +#else
    295 +#define	STACK_BIAS 0
    296 +#endif
    297 +
    298 +/*
    299 + * Not defining PHELPER lets us test this code as a normal D script.
    300 + */
    301 +#ifdef PHELPER
    302 +
    303 +#define	at_evalframe(addr) \
    304 +    ((uintptr_t)addr >= ((uintptr_t)&``startframe) && \
    305 +     (uintptr_t)addr < ((uintptr_t)&``endframe))
    306 +#define	probe dtrace:helper:ustack:
    307 +#define	print_result(r) (r)
    308 +
    309 +#if defined(__i386) || defined(__amd64)
    310 +#define	frame_ptr_addr ((uintptr_t)arg1 + sizeof(uintptr_t) * 2)
    311 +#elif defined(__sparc)
    312 +#define	frame_ptr_addr ((uintptr_t)arg1 + STACK_BIAS + sizeof(uintptr_t) * 8)
    313 +#else
    314 +#error unknown architecture
    315 +#endif
    316 +
    317 +#else /* PHELPER */
    318 +
    319 +#define	at_evalframe(addr) (1)
    320 +#define	probe pid$target::PyEval_EvalFrame:entry
    321 +#define print_result(r) (trace(r))
    322 +
    323 +#if defined(__i386) || defined(__amd64)
    324 +#define	frame_ptr_addr ((uintptr_t)uregs[R_SP] + sizeof(uintptr_t))
    325 +#elif defined(__sparc)
    326 +/*
    327 + * Not implemented: we could just use R_I0, but what's the point?
    328 + */
    329 +#else
    330 +#error unknown architecture
    331 +#endif
    332 +
    333 +#endif /* PHELPER */
    334 +
    335 +extern uintptr_t PyEval_EvalFrame;
    336 +extern uintptr_t PyEval_EvalFrameReal;
    337 +extern uintptr_t PyEval_EvalCodeEx;
    338 +
    339 +#define	copyin_obj(addr, obj) ((obj *)copyin((uintptr_t)addr, sizeof(obj)))
    340 +#define	pystr_addr(addr) ((char *)addr + offsetof(PyStringObject, ob_sval))
    341 +#define	copyin_str(dest, addr, obj) \
    342 +    (copyinto((uintptr_t)pystr_addr(addr), obj->ob_size, (dest)))
    343 +#define	add_str(addr, obj) \
    344 +    copyin_str(this->result + this->pos, addr, obj); \
    345 +    this->pos += obj->ob_size; \
    346 +    this->result[this->pos] = '\0';
    347 +#define	add_digit(nr, div) ((nr / div) ? \
    348 +    (this->result[this->pos++] = '0' + ((nr / div) % 10)) : \
    349 +    (this->result[this->pos] = '\0'))
    350 +#define	add_char(c) (this->result[this->pos++] = c)
    351 +
    352 +probe /at_evalframe(arg0)/ 
    353 +{
    354 +	this->framep = *(uintptr_t *)copyin(frame_ptr_addr, sizeof(uintptr_t));
    355 +	this->frameo = copyin_obj(this->framep, PyFrameObject);
    356 +	this->codep = this->frameo->f_code;
    357 +	this->lineno = this->frameo->f_calllineno;
    358 +	this->codeo = copyin_obj(this->codep, PyCodeObject);
    359 +	this->filenamep = this->codeo->co_filename;
    360 +	this->fnamep = this->codeo->co_name;
    361 +	this->filenameo = copyin_obj(this->filenamep, PyStringObject);
    362 +	this->fnameo = copyin_obj(this->fnamep, PyStringObject);
    363 +
    364 +	this->len = 1 + this->filenameo->ob_size + 1 + 5 + 2 +
    365 +	    this->fnameo->ob_size + 1 + 1;
    366 +
    367 +	this->result = (char *)alloca(this->len);
    368 +	this->pos = 0;
    369 +
    370 +	add_char('@');
    371 +	add_str(this->filenamep, this->filenameo);
    372 +	add_char(':');
    373 +	add_digit(this->lineno, 10000);
    374 +	add_digit(this->lineno, 1000);
    375 +	add_digit(this->lineno, 100);
    376 +	add_digit(this->lineno, 10);
    377 +	add_digit(this->lineno, 1);
    378 +	add_char(' ');
    379 +	add_char('(');
    380 +	add_str(this->fnamep, this->fnameo);
    381 +	add_char(')');
    382 +	this->result[this->pos] = '\0';
    383 +
    384 +	print_result(stringof(this->result));
    385 +}
    386 +
    387 +probe /!at_evalframe(arg0)/
    388 +{
    389 +	NULL;
    390 +}
    391 diff -prauN Python-2.4.4/Python/python.d Python-new/Python/python.d
    392 --- Python-2.4.4/Python/python.d	1969-12-31 16:00:00.000000000 -0800
    393 +++ Python-new/Python/python.d	2007-07-03 07:59:58.727981000 -0700
    394 @@ -0,0 +1,10 @@
    395 +provider python {
    396 +	probe function__entry(const char *, const char *, int);
    397 +	probe function__return(const char *, const char *, int);
    398 +};
    399 +
    400 +#pragma D attributes Evolving/Evolving/Common provider python provider
    401 +#pragma D attributes Private/Private/Common provider python module
    402 +#pragma D attributes Private/Private/Common provider python function
    403 +#pragma D attributes Evolving/Evolving/Common provider python name
    404 +#pragma D attributes Evolving/Evolving/Common provider python args
    405