1 diff -ruN Python-2.6.7-orig/Include/frameobject.h Python-2.6.7/Include/frameobject.h
   2 --- Python-2.6.7-orig/Include/frameobject.h     2008-02-14 12:47:33.000000000 +0000
   3 +++ Python-2.6.7/Include/frameobject.h  2012-02-15 20:06:42.391256713 +0000
   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 -ruN Python-2.6.7-orig/Makefile.pre.in Python-2.6.7/Makefile.pre.in
  13 --- Python-2.6.7-orig/Makefile.pre.in   2010-08-01 22:05:31.000000000 +0000
  14 +++ Python-2.6.7/Makefile.pre.in        2012-02-15 20:06:42.391743222 +0000
  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 -ruN Python-2.6.7-orig/Objects/frameobject.c Python-2.6.7/Objects/frameobject.c
  51 --- Python-2.6.7-orig/Objects/frameobject.c     2010-05-09 15:15:40.000000000 +0000
  52 +++ Python-2.6.7/Objects/frameobject.c  2012-02-15 20:10:17.527441071 +0000
  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 -ruN Python-2.6.7-orig/Python/ceval.c Python-2.6.7/Python/ceval.c
  62 --- Python-2.6.7-orig/Python/ceval.c    2010-06-23 18:17:18.000000000 +0000
  63 +++ Python-2.6.7/Python/ceval.c 2012-02-15 20:09:36.195130867 +0000
  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 @@ -546,6 +551,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 @@ -557,9 +611,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 @@ -782,6 +911,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 @@ -2406,6 +2538,9 @@
 228              PyObject **sp;
 229              PCALL(PCALL_ALL);
 230              sp = stack_pointer;
 231 +#ifdef HAVE_DTRACE
 232 +            f->f_calllineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
 233 +#endif
 234  #ifdef WITH_TSC
 235              x = call_function(&sp, oparg, &intr0, &intr1);
 236  #else
 237 @@ -2448,6 +2583,9 @@
 238              } else
 239                  Py_INCREF(func);
 240              sp = stack_pointer;
 241 +#ifdef HAVE_DTRACE
 242 +            f->f_calllineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
 243 +#endif
 244              READ_TIMESTAMP(intr0);
 245              x = ext_do_call(func, &sp, flags, na, nk);
 246              READ_TIMESTAMP(intr1);
 247 @@ -2746,6 +2884,8 @@
 248  
 249      /* pop frame */
 250  exit_eval_frame:
 251 +    if (PYTHON_FUNCTION_RETURN_ENABLED())
 252 +        dtrace_return(f);
 253      Py_LeaveRecursiveCall();
 254      tstate->frame = f->f_back;
 255  
 256 diff -ruN Python-2.6.7-orig/Python/phelper.d Python-2.6.7/Python/phelper.d
 257 --- Python-2.6.7-orig/Python/phelper.d  1970-01-01 00:00:00.000000000 +0000
 258 +++ Python-2.6.7/Python/phelper.d       2012-02-15 20:06:42.395929142 +0000
 259 @@ -0,0 +1,139 @@
 260 +
 261 +/*
 262 + * Python ustack helper.  This relies on the first argument (PyFrame *) being
 263 + * on the stack; see Python/ceval.c for the contortions we go through to ensure
 264 + * this is the case.
 265 + *
 266 + * On x86, the PyFrame * is two slots up from the frame pointer; on SPARC, it's
 267 + * eight.
 268 + */
 269 +
 270 +/*
 271 + * Yes, this is as gross as it looks. DTrace cannot handle static functions,
 272 + * and our stat_impl.h has them in ILP32.
 273 + */
 274 +#define _SYS_STAT_H
 275 +
 276 +#include <stdio.h>
 277 +#include <sys/types.h>
 278 +
 279 +#include "pyport.h"
 280 +#include "object.h"
 281 +#include "pystate.h"
 282 +#include "pyarena.h"
 283 +#include "pythonrun.h"
 284 +#include "compile.h"
 285 +#include "frameobject.h"
 286 +#include "stringobject.h"
 287 +
 288 +#if defined(__i386)
 289 +#define        startframe PyEval_EvalFrameEx
 290 +#define        endframe PyEval_EvalCodeEx
 291 +#elif defined(__amd64)
 292 +#define        PyEval_EvalFrameEx PyEval_EvalFrameExReal
 293 +#define        startframe PyEval_EvalFrameExReal
 294 +#define        endframe PyEval_EvalCodeEx
 295 +#elif defined(__sparc)
 296 +#define        PyEval_EvalFrameEx PyEval_EvalFrameExReal
 297 +#define        startframe PyEval_EvalFrameEx
 298 +#define        endframe PyEval_EvalFrameExReal
 299 +#endif
 300 +
 301 +#ifdef __sparcv9
 302 +#define        STACK_BIAS (2048-1)
 303 +#else
 304 +#define        STACK_BIAS 0
 305 +#endif
 306 +
 307 +/*
 308 + * Not defining PHELPER lets us test this code as a normal D script.
 309 + */
 310 +#ifdef PHELPER
 311 +
 312 +#define        at_evalframe(addr) \
 313 +    ((uintptr_t)addr >= ((uintptr_t)&``startframe) && \
 314 +     (uintptr_t)addr < ((uintptr_t)&``endframe))
 315 +#define        probe dtrace:helper:ustack:
 316 +#define        print_result(r) (r)
 317 +
 318 +#if defined(__i386) || defined(__amd64)
 319 +#define        frame_ptr_addr ((uintptr_t)arg1 + sizeof(uintptr_t) * 2)
 320 +#elif defined(__sparc)
 321 +#define        frame_ptr_addr ((uintptr_t)arg1 + STACK_BIAS + sizeof(uintptr_t) * 8)
 322 +#else
 323 +#error unknown architecture
 324 +#endif
 325 +
 326 +#else /* PHELPER */
 327 +
 328 +#define        at_evalframe(addr) (1)
 329 +#define        probe pid$target::PyEval_EvalFrame:entry
 330 +#define print_result(r) (trace(r))
 331 +
 332 +#if defined(__i386) || defined(__amd64)
 333 +#define        frame_ptr_addr ((uintptr_t)uregs[R_SP] + sizeof(uintptr_t))
 334 +#elif defined(__sparc)
 335 +/*
 336 + * Not implemented: we could just use R_I0, but what's the point?
 337 + */
 338 +#else
 339 +#error unknown architecture
 340 +#endif
 341 +
 342 +#endif /* PHELPER */
 343 +
 344 +extern uintptr_t PyEval_EvalFrameEx;
 345 +extern uintptr_t PyEval_EvalCodeEx;
 346 +
 347 +#define        copyin_obj(addr, obj) ((obj *)copyin((uintptr_t)addr, sizeof(obj)))
 348 +#define        pystr_addr(addr) ((char *)addr + offsetof(PyStringObject, ob_sval))
 349 +#define        copyin_str(dest, addr, obj) \
 350 +    (copyinto((uintptr_t)pystr_addr(addr), obj->ob_size, (dest)))
 351 +#define        add_str(addr, obj) \
 352 +    copyin_str(this->result + this->pos, addr, obj); \
 353 +    this->pos += obj->ob_size; \
 354 +    this->result[this->pos] = '\0';
 355 +#define        add_digit(nr, div) ((nr / div) ? \
 356 +    (this->result[this->pos++] = '0' + ((nr / div) % 10)) : \
 357 +    (this->result[this->pos] = '\0'))
 358 +#define        add_char(c) (this->result[this->pos++] = c)
 359 +
 360 +probe /at_evalframe(arg0)/ 
 361 +{
 362 +       this->framep = *(uintptr_t *)copyin(frame_ptr_addr, sizeof(uintptr_t));
 363 +       this->frameo = copyin_obj(this->framep, PyFrameObject);
 364 +       this->codep = this->frameo->f_code;
 365 +       this->lineno = this->frameo->f_calllineno;
 366 +       this->codeo = copyin_obj(this->codep, PyCodeObject);
 367 +       this->filenamep = this->codeo->co_filename;
 368 +       this->fnamep = this->codeo->co_name;
 369 +       this->filenameo = copyin_obj(this->filenamep, PyStringObject);
 370 +       this->fnameo = copyin_obj(this->fnamep, PyStringObject);
 371 +
 372 +       this->len = 1 + this->filenameo->ob_size + 1 + 5 + 2 +
 373 +           this->fnameo->ob_size + 1 + 1;
 374 +
 375 +       this->result = (char *)alloca(this->len);
 376 +       this->pos = 0;
 377 +
 378 +       add_char('@');
 379 +       add_str(this->filenamep, this->filenameo);
 380 +       add_char(':');
 381 +       add_digit(this->lineno, 10000);
 382 +       add_digit(this->lineno, 1000);
 383 +       add_digit(this->lineno, 100);
 384 +       add_digit(this->lineno, 10);
 385 +       add_digit(this->lineno, 1);
 386 +       add_char(' ');
 387 +       add_char('(');
 388 +       add_str(this->fnamep, this->fnameo);
 389 +       add_char(')');
 390 +       this->result[this->pos] = '\0';
 391 +
 392 +       print_result(stringof(this->result));
 393 +}
 394 +
 395 +probe /!at_evalframe(arg0)/
 396 +{
 397 +       NULL;
 398 +}
 399 diff -ruN Python-2.6.7-orig/Python/python.d Python-2.6.7/Python/python.d
 400 --- Python-2.6.7-orig/Python/python.d   1970-01-01 00:00:00.000000000 +0000
 401 +++ Python-2.6.7/Python/python.d        2012-02-15 20:06:42.396028117 +0000
 402 @@ -0,0 +1,10 @@
 403 +provider python {
 404 +       probe function__entry(const char *, const char *, int);
 405 +       probe function__return(const char *, const char *, int);
 406 +};
 407 +
 408 +#pragma D attributes Evolving/Evolving/Common provider python provider
 409 +#pragma D attributes Private/Private/Common provider python module
 410 +#pragma D attributes Private/Private/Common provider python function
 411 +#pragma D attributes Evolving/Evolving/Common provider python name
 412 +#pragma D attributes Evolving/Evolving/Common provider python args