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