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
