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