components/python/python26/Python26-07-dtrace.patch
changeset 99 c15c9099bb44
equal deleted inserted replaced
98:7eea11439375 99:c15c9099bb44
       
     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