--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/components/python/python34/patches/00-dtrace.patch Fri Feb 06 16:51:20 2015 -0800
@@ -0,0 +1,2036 @@
+This patch comes from upstream:
+http://www.jcea.es/artic/python_dtrace-3_4_0_0de6441eedb7.txt
+http://www.jcea.es/artic/python_dtrace.htm
+Follow http://bugs.python.org/issue13405 for plans to get it
+integrated into the main tree.
+
+--- Python-3.4.0/Doc/library/debug.rst
++++ Python-3.4.0/Doc/library/debug.rst
+@@ -15,4 +15,5 @@
+ profile.rst
+ timeit.rst
+ trace.rst
++ dtrace.rst
+ tracemalloc.rst
+--- /dev/null
++++ Python-3.4.0/Doc/library/dtrace.rst
+@@ -0,0 +1,183 @@
++:mod:`dtrace` --- DTrace probes for Python
++===============================================
++
++.. module:: dtrace
++ :synopsis: DTrace probes for Python.
++
++**Source code:** :source:`Lib/dtrace.py`
++
++--------------
++
++The :mod:`dtrace` module indicates if the CPython executable currently
++running has been compiled with DTrace probes support.
++
++.. impl-detail::
++
++ DTrace probes are implementation details of the CPython interpreter!
++ No garantees are made about probe compatibility between versions of
++ CPython. DTrace scripts can stop working or work incorrectly without
++ warning when changing CPython versions.
++
++The :mod:`dtrace` module defines the following variable:
++
++
++.. data:: available
++
++ The variable will be ``True`` if the current CPython interpreter was
++ compiled with DTrace probe support. ``False`` if not.
++
++
++DTrace probes
++-------------
++
++DTrace scripts are run externally to CPython. DTrace probes export
++selected events inside CPython interpreter in order to make them
++accessible to external scripts.
++
++The probes are exported through the "python" provider. The available
++probes are defined in the file :file:`Include/pydtrace.d`.
++
++To learn how to use DTrace, read `DTrace User Guide
++<http://docs.oracle.com/cd/E19253-01/819-5488/>`_.
++
++.. opcode:: function-entry (arg0, arg1, arg2)
++
++ Fires when python code enters a new function. *arg0* is sourcecode
++ file path, *arg1* is the name of the funcion called, and *arg2* is
++ line number.
++
++ The probe is not fired if Python code calls C functions.
++
++.. opcode:: function-return (arg0, arg1, arg2)
++
++ Fires when Python code finishes execution of a function. Parameters
++ are the same as in ``function-entry``.
++
++ The probe is not fired if the finishing function is written in C.
++
++.. opcode:: line (arg0, arg1, arg2)
++
++ Fires when Python code changes the execution line. Parameters are the
++ same as in ``function-entry``.
++
++ The probe is not fired in C functions.
++
++.. opcode:: gc-start (arg0)
++
++ Fires when the Python interpreter starts a garbage collection cycle.
++ *arg0* is the generation to scan, like :func:`gc.collect()`.
++
++.. opcode:: gc-done (arg0)
++
++ Fires when the Python interpreter finishes a garbage collection
++ cycle. *arg0* is the number of collected objects.
++
++.. opcode:: instance-new-start (arg0, arg1)
++
++ Fires when an object instanciation starts. *arg0* is the class name,
++ *arg1* is the filename where the class is defined.
++
++ The probe is not fired for most C code object creations.
++
++.. opcode:: instance-new-done (arg0, arg1)
++
++ Fires when an object instanciation finishes. Parameters are the same
++ as in ``instance-new-done``.
++
++ The probe is not fired for most C code object creations.
++
++.. opcode:: instance-delete-start (arg0, arg1)
++
++ Fires when an object instance is going to be destroyed. Parameters
++ are the same as in ``instance-new-done``.
++
++ The probe is not fired for most C code object destructions.
++
++.. opcode:: instance-delete-done (arg0, arg1)
++
++ Fires when an object instance has been destroyed. parameters are the
++ same as in ``instance-new-done``.
++
++ Between an ``instance-delete-start`` and corresponding
++ ``instance-delete-done`` others probes can fire if, for instance,
++ deletion of an instance creates a deletion cascade.
++
++ The probe is not fired for most C code object destructions.
++
++
++Python stack
++------------
++
++When a DTrace probe is fired, the DTrace script can examine the stack.
++Since CPython is a Python interpreter coded in C, the stack will show C
++functions, with no direct relation to the Python code currently being
++executed.
++
++Using the special "jstack()" DTrace function, the user will be given
++hints about the python program stack, if possible. In particular, the
++augmented stack will show python function calls, filename, name
++of the function or method, and the line number.
++
++DTrace scripts examples
++-----------------------
++
++DTrace python provider is suffixed by the pid of the process to monitor.
++In the examples, the pid will be 9876.
++
++Show the time spent doing garbage collection (in nanoseconds)::
++
++ python9876:::gc-start
++ {
++ self->t = timestamp;
++ }
++
++ python9876:::gc-done
++ /self->t/
++ {
++ printf("%d", timestamp-self->t);
++ self->t = 0;
++ }
++
++Count how many instances are created of each class::
++
++ python9876:::instance-new-start
++ {
++ @v[copyinstr(arg1), copyinstr(arg0)] = count();
++ }
++
++Observe time spent in object destruction, useful if datastructures are
++complicated and deletion of an object can create a cascade effect::
++
++ python9876:::instance-delete-start
++ /self->t==0/
++ {
++ self->t = timestamp;
++ self->level = 0;
++ }
++
++ python9876:::instance-delete-start
++ /self->t/
++ {
++ self->level += 1;
++ }
++
++ python9876:::instance-delete-done
++ /(self->level) && (self->t)/
++ {
++ self->level -= 1;
++ }
++
++ python9876:::instance-delete-done
++ /(self->level==0) && (self->t)/
++ {
++ @time = quantize(timestamp-self->t);
++ self->t = 0;
++ }
++
++To know which python source code lines create new TCP/IP connections::
++
++ pid9876::sock_connect:entry
++ {
++ @conn[jstack()] = count();
++ }
++
+--- Python-3.4.0/Include/code.h
++++ Python-3.4.0/Include/code.h
+@@ -7,6 +7,8 @@
+ extern "C" {
+ #endif
+
++#include "pyconfig.h"
++
+ /* Bytecode object */
+ typedef struct {
+ PyObject_HEAD
+@@ -28,6 +30,9 @@
+ int co_firstlineno; /* first source line number */
+ PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See
+ Objects/lnotab_notes.txt for details. */
++#ifdef WITH_DTRACE
++ unsigned short *co_linenos; /* dtrace stack helper */
++#endif
+ void *co_zombieframe; /* for optimization only (see frameobject.c) */
+ PyObject *co_weakreflist; /* to support weakrefs to code objects */
+ } PyCodeObject;
+--- /dev/null
++++ Python-3.4.0/Include/pydtrace.d
+@@ -0,0 +1,177 @@
++provider python {
++ probe function__entry(const char *, const char *, int);
++ probe function__return(const char *, const char *, int);
++ probe instance__new__start(const char *, const char *);
++ probe instance__new__done(const char *, const char *);
++ probe instance__delete__start(const char *, const char *);
++ probe instance__delete__done(const char *, const char *);
++ probe line(const char *, const char *, int);
++ probe gc__start(int);
++ probe gc__done(long);
++};
++
++#pragma D attributes Evolving/Evolving/Common provider python provider
++#pragma D attributes Private/Private/Common provider python module
++#pragma D attributes Private/Private/Common provider python function
++#pragma D attributes Evolving/Evolving/Common provider python name
++#pragma D attributes Evolving/Evolving/Common provider python args
++
++
++
++#ifdef PYDTRACE_STACK_HELPER
++/*
++ * Python ustack helper. This relies on the first argument (PyFrame *) being
++ * on the stack; see Python/ceval.c for the contortions we go through to ensure
++ * this is the case.
++ *
++ * On x86, the PyFrame * is two slots up from the frame pointer; on SPARC, it's
++ * eight.
++ *
++ * Some details about this in "Python and DTrace in build 65":
++ * http://blogs.oracle.com/levon/entry/python_and_dtrace_in_build
++ */
++
++/*
++ * Yes, this is as gross as it looks. DTrace cannot handle static functions,
++ * and our stat_impl.h has them in ILP32.
++ */
++#define _SYS_STAT_H
++
++/*
++** When compiling in 32 bits:
++** - Early inclusion to avoid problems with
++** _FILE_OFFSET_BITS redefined.
++** - Also, we must "undef" _POSIX_PTHREAD_SEMANTICS
++** to avoid error compiling this source.
++*/
++#include "pyconfig.h"
++#undef _POSIX_PTHREAD_SEMANTICS
++
++#include <stdio.h>
++#include <sys/types.h>
++
++#include "pyport.h"
++#include "pyatomic.h"
++/* "string" type is used in dtrace */
++#define string stringDTRACE
++#include "object.h"
++#include "pystate.h"
++#include "pyarena.h"
++#include "pythonrun.h"
++#include "compile.h"
++#include "frameobject.h"
++/* Avoid a compile error because a symbol (equivalent) redefinition */
++#undef __STDC__
++/* "self" has an special meaning for dtrace */
++#define self selfDTRACE
++#include "unicodeobject.h"
++#undef string
++#undef self
++
++#include "pydtrace_offsets.h"
++
++#if defined(__i386)
++#define startframe PyEval_EvalFrameEx
++#define endframe AFTER_PyEval_EvalFrameEx
++#elif defined(__amd64)
++#define startframe PyEval_EvalFrameExReal
++#define endframe AFTER_PyEval_EvalFrameExReal
++#elif defined(__sparc)
++#define startframe PyEval_EvalFrameExReal
++#define endframe AFTER_PyEval_EvalFrameExReal
++#endif
++
++#ifdef __sparcv9
++#define STACK_BIAS (2048-1)
++#else
++#define STACK_BIAS 0
++#endif
++
++#define at_evalframe(addr) \
++ ((uintptr_t)addr >= ((uintptr_t)&``startframe) && \
++ (uintptr_t)addr < ((uintptr_t)&``endframe))
++#define probe dtrace:helper:ustack:
++#define print_result(r) (r)
++
++#if defined(__i386) || defined(__amd64)
++#define frame_ptr_addr ((uintptr_t)arg1 + sizeof(uintptr_t) * 2)
++#elif defined(__sparc)
++#define frame_ptr_addr ((uintptr_t)arg1 + STACK_BIAS + sizeof(uintptr_t) * 8)
++#else
++#error unknown architecture
++#endif
++
++/* startframe and endframe are macro-expansions */
++extern uintptr_t startframe;
++extern uintptr_t endframe;
++
++
++#define copyin_obj(addr, obj) ((obj *)copyin((uintptr_t)(addr), sizeof(obj)))
++
++/*
++** Check if the string is ASCII. Don't use bitfields, because the
++** packing in GCC and D are different. BEWARE!!!.
++** The size of the structures are also different!. That is the reason for
++** the negative offset. BEWARE!!!
++*/
++#define pystr_len(addr) ((*(((char *)addr)+PYDTRACE_ASCII_OFFSET)) & PYDTRACE_ASCII_MASK ? \
++ (addr)->_base.length : \
++ *(Py_ssize_t *)(((char *)(addr)) + PYDTRACE_UTF8_LENGTH_OFFSET))
++#define pystr_addr(addr, addr2) ((*(((char *)addr)+PYDTRACE_ASCII_OFFSET)) & PYDTRACE_ASCII_MASK ? \
++ (char *)(((char *)(addr2)) + PYDTRACE_PyASCIIObject_SIZE) : \
++ (char *)*(uintptr_t *)(((char *)(addr)) + PYDTRACE_UTF8_OFFSET))
++
++#define add_digit(nr, div) (((nr) / div) ? \
++ (this->result[this->pos++] = '0' + (((nr) / div) % 10)) : \
++ (this->result[this->pos] = '\0'))
++#define add_char(c) (this->result[this->pos++] = c)
++
++probe /at_evalframe(arg0)/
++{
++ this->framep = *(uintptr_t *)copyin(frame_ptr_addr, sizeof(uintptr_t));
++ this->frameo = copyin_obj(this->framep, PyFrameObject);
++ this->codep = this->frameo->f_code;
++ this->codeo = copyin_obj(this->codep, PyCodeObject);
++ /* If we just enter a function, show the definition line */
++ this->lineno = this->codeo->co_firstlineno +
++ (this->frameo->f_lasti == -1 ? 0 :
++ *copyin_obj(this->codeo->co_linenos + this->frameo->f_lasti,
++ unsigned short));
++ this->filenameo = copyin_obj(this->codeo->co_filename, PyCompactUnicodeObject);
++ this->len_filename = pystr_len(this->filenameo);
++ this->nameo = copyin_obj(this->codeo->co_name, PyCompactUnicodeObject);
++ this->len_name = pystr_len(this->nameo);
++ this->len = 1 + (this->len_filename) + 1 + 5 + 2 +
++ (this->len_name) + 1 + 1;
++
++ this->result = (char *)alloca(this->len);
++ this->pos = 0;
++ add_char('@');
++
++ copyinto((uintptr_t)pystr_addr(this->filenameo, this->codeo->co_filename), this->len_filename, this->result+this->pos);
++ this->pos += this->len_filename;
++
++ add_char(':');
++ add_digit(this->lineno, 10000);
++ add_digit(this->lineno, 1000);
++ add_digit(this->lineno, 100);
++ add_digit(this->lineno, 10);
++ add_digit(this->lineno, 1);
++ add_char(' ');
++ add_char('(');
++
++ copyinto((uintptr_t)pystr_addr(this->nameo, this->codeo->co_name), this->len_name, this->result+this->pos);
++ this->pos += this->len_name;
++
++ add_char(')');
++ this->result[this->pos] = '\0';
++ print_result(stringof(this->result));
++}
++
++probe /!at_evalframe(arg0)/
++{
++ NULL;
++}
++
++#endif /* PYDTRACE_STACK_HELPER */
++
+--- /dev/null
++++ Python-3.4.0/Include/pydtrace_offsets.c
+@@ -0,0 +1,40 @@
++#include "Python.h"
++#include "unicodeobject.h"
++#include <stdlib.h>
++#include <stdio.h>
++
++int main(int argc, const char* argv[]) {
++ PyCompactUnicodeObject o;
++ unsigned char *p = (unsigned char *)(&o);
++
++ if (argc != 3) {
++ printf("Parameter number incorrect\n");
++ exit(1);
++ }
++
++ memset(&o, 0, sizeof(o));
++ o._base.state.ascii = 1;
++ while (!*p) p++;
++
++ printf("/* File autogenerated. DO NOT MODIFY MANUALLY */\n");
++ printf("\n");
++ printf("#ifndef PYDTRACE_OFFSETS_H\n");
++ printf("#define PYDTRACE_OFFSETS_H\n");
++ printf("\n");
++ printf("#define PYDTRACE_ASCII_OFFSET %d\n",
++ p-(unsigned char *)(&o));
++ printf("#define PYDTRACE_ASCII_MASK %d\n", *p);
++ printf("#define PYDTRACE_PyASCIIObject_SIZE %d\n",
++ sizeof(PyASCIIObject));
++ printf("#define PYDTRACE_UTF8_LENGTH_OFFSET %d\n",
++ offsetof(PyCompactUnicodeObject, utf8_length));
++ printf("#define PYDTRACE_UTF8_OFFSET %d\n",
++ offsetof(PyCompactUnicodeObject, utf8));
++ printf("\n");
++ printf("#define AFTER_PyEval_EvalFrameEx %s\n", argv[1]);
++ printf("#define AFTER_PyEval_EvalFrameExReal %s\n", argv[2]);
++ printf("\n");
++ printf("#endif\n");
++ return 0;
++}
++
+new file mode 100755
+--- /dev/null
++++ Python-3.4.0/Include/pydtrace_offsets.sh
+@@ -0,0 +1,32 @@
++#!/bin/sh
++
++DTRACE_NM=$1
++CEVAL_O=$2
++PYDTRACE_OFFSETS=$3
++if test "$DTRACE_NM" = "OTHER" ; then
++ $PYDTRACE_OFFSETS \
++ "`nm -n $CEVAL_O | grep \" T \" | \
++ sed -n \"/ T PyEval_EvalFrameEx$/{n;p;}\" | \
++ sed \"s/.* T \(.*\)$/\1/\"`" \
++ "`nm -n $CEVAL_O | grep \" T \" | \
++ sed -n \"/ T PyEval_EvalFrameExReal$/{n;p;}\" | \
++ sed \"s/.* T \(.*\)$/\1/\"`"
++fi
++if test "$DTRACE_NM" = "SOLARIS" ; then
++ $PYDTRACE_OFFSETS \
++ "`/usr/ccs/bin/nm -n $CEVAL_O | \
++ /usr/bin/grep \"\\|FUNC \\|\" | \
++ /usr/bin/grep -v \"\\|IGNORE \\|\" | \
++ /usr/bin/grep -v \"\\|UNDEF \\|\" | \
++ /usr/bin/tr -d \"\\[\\]\\|\" | sort -n | \
++ sed -n \"/ PyEval_EvalFrameEx$/{n;p;}\" | \
++ sed \"s/.* \([a-zA-Z0-9_]*\)$/\1/\"`" \
++ "`/usr/ccs/bin/nm -n $CEVAL_O | \
++ /usr/bin/grep \"\\|FUNC \\|\" | \
++ /usr/bin/grep -v \"\\|UNDEF \\|\" | \
++ /usr/bin/grep -v \"\\|IGNORE \\|\" | \
++ /usr/bin/tr -d \"\\[\\]\\|\" | sort -n | \
++ sed -n \"/ PyEval_EvalFrameExReal$/{n;p;}\" | \
++ sed \"s/.* \([a-zA-Z0-9_]*\)$/\1/\"`"
++fi
++
+--- /dev/null
++++ Python-3.4.0/Lib/test/dtrace_sample.py
+@@ -0,0 +1,80 @@
++# Sample script for use by test_dtrace.py
++# DO NOT MODIFY THIS FILE IN ANY WAY WITHOUT UPDATING test_dtrace.py!!!!!
++
++import gc
++
++def function_1() :
++ pass
++
++# Check stacktrace
++def function_2() :
++ function_1()
++
++# CALL_FUNCTION_VAR
++def function_3(dummy, dummy2) :
++ pass
++
++# CALL_FUNCTION_KW
++def function_4(**dummy) :
++ pass
++
++# CALL_FUNCTION_VAR_KW
++def function_5(dummy, dummy2, **dummy3) :
++ pass
++
++def test_entry_return_and_stack() :
++ function_1()
++ function_2()
++ function_3(*(1,2))
++ function_4(**{"test":42})
++ function_5(*(1,2), **{"test":42})
++
++def test_line() :
++ a = 1 # Preamble
++ for i in range(2) :
++ a = i
++ b = i+2
++ c = i+3
++ d = a + b +c
++ a = 1 # Epilogue
++
++def test_unicode_entry_return_and_stack() :
++ def únícódé() :
++ pass
++ únícódé()
++
++def test_instance_creation_destruction() :
++ class old_style_class() :
++ pass
++ class new_style_class(object) :
++ pass
++
++ a = old_style_class()
++ del a
++ gc.collect()
++ b = new_style_class()
++ del b
++ gc.collect()
++
++ a = old_style_class()
++ del old_style_class
++ gc.collect()
++ b = new_style_class()
++ del new_style_class
++ gc.collect()
++ del a
++ gc.collect()
++ del b
++ gc.collect()
++
++def test_garbage_collection() :
++ gc.collect()
++
++
++if __name__ == "__main__":
++ test_entry_return_and_stack()
++ test_line()
++ test_unicode_entry_return_and_stack()
++ test_instance_creation_destruction()
++ test_garbage_collection()
++
+--- /dev/null
++++ Python-3.4.0/Lib/test/test_dtrace.py
+@@ -0,0 +1,447 @@
++import sys, unittest, subprocess, os.path, dis, types, re
++import dtrace
++from test.support import TESTFN, run_unittest, findfile
++
++sample = os.path.abspath(findfile("dtrace_sample.py"))
++if not dtrace.available :
++ raise unittest.SkipTest("dtrace support not compiled in")
++
++def normalize(data) :
++ # DTRACE keeps a per-CPU buffer, and when showing the fired probes,
++ # buffers are concatenated. So if the operating system moves our
++ # thread around, the straight result can be "non causal".
++ # So we add timestamps to the probe firing, and sort by that field.
++
++ result = data if isinstance(data, str) else data.decode("ascii")
++ # When compiling with '--with-pydebug'
++ result = "".join(re.split("\[[0-9]+ refs\]", result))
++
++ try :
++ result = [i.split("\t") \
++ for i in result.replace("\r", "").split("\n") if len(i)]
++ result.sort(key = lambda i: int(i[0]))
++ result = "".join((i[1] for i in result))
++ result = result.replace(" ", "")
++ except :
++ # If something goes wrong, rebuild the value so we can see the
++ # real result when the assert fails.
++ result = data if isinstance(data, str) else data.decode("ascii")
++ result = result.replace("\r", "").replace("\n", "")
++ return result
++
++dscript = """
++pid$target::PyEval_EvalCode:entry
++"""
++dscript = dscript.replace("\r", "").replace("\n", "")
++result, _ = subprocess.Popen(["dtrace", "-q", "-l", "-n", dscript,
++ "-c", "%s %s" %(sys.executable, sample)], stdout=subprocess.PIPE,
++ stderr=subprocess.STDOUT).communicate()
++if result.decode("ascii").split("\n")[1].split()[-2:] != \
++ ["PyEval_EvalCode", "entry"] :
++ result2 = repr(result)
++ raise unittest.SkipTest("dtrace seems not to be working. " + \
++ "Please, check your privileges. " +
++ "Result: " +result2)
++
++class DTraceTestsNormal(unittest.TestCase) :
++ def setUp(self) :
++ self.optimize = False
++
++ def test_function_entry_return(self) :
++ dscript = """
++python$target:::function-entry
++/(copyinstr(arg0)=="%(path)s") &&
++(copyinstr(arg1)=="test_entry_return_and_stack")/
++{
++ self->trace = 1;
++}
++python$target:::function-entry,python$target:::function-return
++/(copyinstr(arg0)=="%(path)s") && (self->trace)/
++{
++ printf("%%d\t**%%s*%%s*%%s*%%d\\n", timestamp,
++ probename, copyinstr(arg0),
++ copyinstr(arg1), arg2);
++}
++python$target:::function-return
++/(copyinstr(arg0)=="%(path)s") &&
++(copyinstr(arg1)=="test_entry_return_and_stack")/
++{
++ self->trace = 0;
++}
++""" %{"path":sample}
++
++ dscript = dscript.replace("\r", "").replace("\n", "")
++ expected_result = """
++ **function-entry*%(path)s*test_entry_return_and_stack*25
++ **function-entry*%(path)s*function_1*6
++ **function-return*%(path)s*function_1*7
++ **function-entry*%(path)s*function_2*10
++ **function-entry*%(path)s*function_1*6
++ **function-return*%(path)s*function_1*7
++ **function-return*%(path)s*function_2*11
++ **function-entry*%(path)s*function_3*14
++ **function-return*%(path)s*function_3*15
++ **function-entry*%(path)s*function_4*18
++ **function-return*%(path)s*function_4*19
++ **function-entry*%(path)s*function_5*22
++ **function-return*%(path)s*function_5*23
++ **function-return*%(path)s*test_entry_return_and_stack*30
++ """ %{"path":sample}
++
++ command = "%s %s" %(sys.executable, sample)
++ if self.optimize :
++ command = "%s -OO %s" %(sys.executable, sample)
++ actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
++ dscript,
++ "-c", command],
++ stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
++
++ actual_result = normalize(actual_result)
++ expected_result = expected_result.replace("\r", "").replace("\n",
++ "").replace(" ", "")
++ self.assertEqual(actual_result, expected_result)
++
++ @unittest.skipIf(sys.platform == 'darwin',
++ "MacOS X doesn't support jstack()")
++ def test_stack(self) :
++ dscript = """
++python$target:::function-entry
++/(copyinstr(arg0)=="%(path)s") &&
++(copyinstr(arg1)=="test_entry_return_and_stack")/
++{
++ self->trace = 1;
++}
++python$target:::function-entry
++/(copyinstr(arg0)=="%(path)s") && (self->trace)/
++{
++ printf("[x]");
++ jstack();
++}
++python$target:::function-return
++/(copyinstr(arg0)=="%(path)s") &&
++(copyinstr(arg1)=="test_entry_return_and_stack")/
++{
++ self->trace = 0;
++}
++""" %{"path":sample}
++
++ dscript = dscript.replace("\r", "").replace("\n", "")
++ expected_result = """
++ [x]
++ [%(path)s:25(test_entry_return_and_stack)]
++ [x]
++ [%(path)s:6(function_1)]
++ [%(path)s:26(test_entry_return_and_stack)]
++ [x]
++ [%(path)s:10(function_2)]
++ [%(path)s:27(test_entry_return_and_stack)]
++ [x]
++ [%(path)s:6(function_1)]
++ [%(path)s:11(function_2)]
++ [%(path)s:27(test_entry_return_and_stack)]
++ [x]
++ [%(path)s:14(function_3)]
++ [%(path)s:28(test_entry_return_and_stack)]
++ [x]
++ [%(path)s:18(function_4)]
++ [%(path)s:29(test_entry_return_and_stack)]
++ [x]
++ [%(path)s:22(function_5)]
++ [%(path)s:30(test_entry_return_and_stack)]
++ """ %{"path":sample}
++
++ command = "%s %s" %(sys.executable, sample)
++ if self.optimize :
++ command = "%s -OO %s" %(sys.executable, sample)
++ actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
++ dscript,
++ "-c", command],
++ stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
++
++ actual_result = actual_result.decode("ascii")
++ # When compiling with '--with-pydebug'
++ actual_result = "".join(re.split("\[[0-9]+ refs\]", actual_result))
++
++ actual_result = [i for i in actual_result.split("\n") \
++ if (("[" in i) and not i.endswith(" (<module>) ]"))]
++ actual_result = "".join(actual_result)
++ actual_result = actual_result.replace("\r", "").replace("\n",
++ "").replace(" ", "")
++ expected_result = expected_result.replace("\r", "").replace("\n",
++ "").replace(" ", "")
++ self.assertEqual(actual_result, expected_result)
++
++ def test_garbage_collection(self) :
++ dscript = """
++python$target:::gc-start,python$target:::gc-done
++{
++ printf("%d\t**%s(%ld)\\n", timestamp, probename, arg0);
++}
++"""
++
++ dscript = dscript.replace("\r", "").replace("\n", "")
++ command = "%s %s" %(sys.executable, sample)
++ if self.optimize :
++ command = "%s -OO %s" %(sys.executable, sample)
++ actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
++ dscript,
++ "-c", command],
++ stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
++
++ actual_result = normalize(actual_result)
++ for i in range(10) :
++ actual_result = actual_result.replace(str(i), "")
++ expected_result = "**gc-start()**gc-done()" * \
++ actual_result.count("**gc-start()**")
++
++ self.assertEqual(actual_result, expected_result)
++
++ def test_verify_opcodes(self) :
++ # Verify that we are checking:
++ opcodes = set(["CALL_FUNCTION", "CALL_FUNCTION_VAR",
++ "CALL_FUNCTION_KW", "CALL_FUNCTION_VAR_KW"])
++ with open(sample, encoding="utf-8") as f :
++ obj = compile(f.read(), "sample", "exec")
++ class dump() :
++ def __init__(self) :
++ self.buf = []
++ def write(self, v) :
++ self.buf.append(v)
++
++ dump = dump()
++ stdout = sys.stdout
++ sys.stdout = dump
++ for i in obj.co_consts :
++ if isinstance(i, types.CodeType) and \
++ (i.co_name == 'test_entry_return_and_stack') :
++ dis.dis(i)
++ sys.stdout = stdout
++ dump = "\n".join(dump.buf)
++ dump = dump.replace("\r", "").replace("\n", "").split()
++ for i in dump :
++ opcodes.discard(i)
++ # Are we verifying all the relevant opcodes?
++ self.assertEqual(set(), opcodes) # Are we verifying all opcodes?
++
++ def test_line(self) :
++ dscript = """
++python$target:::line
++/(copyinstr(arg0)=="%(path)s") &&
++(copyinstr(arg1)=="test_line")/
++{
++ printf("%%d\t**%%s*%%s*%%s*%%d\\n", timestamp,
++ probename, copyinstr(arg0),
++ copyinstr(arg1), arg2);
++}
++""" %{"path":sample}
++
++ dscript = dscript.replace("\r", "").replace("\n", "")
++ expected_result = """
++ **line*%(path)s*test_line*33
++ **line*%(path)s*test_line*34
++ **line*%(path)s*test_line*35
++ **line*%(path)s*test_line*36
++ **line*%(path)s*test_line*37
++ **line*%(path)s*test_line*38
++ **line*%(path)s*test_line*34
++ **line*%(path)s*test_line*35
++ **line*%(path)s*test_line*36
++ **line*%(path)s*test_line*37
++ **line*%(path)s*test_line*38
++ **line*%(path)s*test_line*34
++ **line*%(path)s*test_line*39
++ """ %{"path":sample}
++
++ command = "%s %s" %(sys.executable, sample)
++ if self.optimize :
++ command = "%s -OO %s" %(sys.executable, sample)
++ actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
++ dscript,
++ "-c", command],
++ stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
++
++ actual_result = normalize(actual_result)
++ expected_result = expected_result.replace("\r", "").replace("\n",
++ "").replace(" ", "")
++ self.assertEqual(actual_result, expected_result)
++
++ def test_instance_creation_destruction(self) :
++ dscript = """
++python$target:::function-entry
++/(copyinstr(arg0)=="%(path)s") &&
++(copyinstr(arg1)=="test_instance_creation_destruction")/
++{
++ self->trace = 1;
++}
++
++python$target:::instance-new-start,
++python$target:::instance-new-done,
++python$target:::instance-delete-start,
++python$target:::instance-delete-done
++/self->trace/
++{
++ printf("%%d\t**%%s* (%%s.%%s)\\n", timestamp,
++ probename, copyinstr(arg1), copyinstr(arg0));
++}
++
++python$target:::function-return
++/(copyinstr(arg0)=="%(path)s") &&
++(copyinstr(arg1)=="test_instance_creation_destruction")/
++{
++ self->trace = 0;
++}
++""" %{"path":sample}
++
++ dscript = dscript.replace("\r", "").replace("\n", "")
++ expected_result = """
++ **instance-new-start*(__main__.old_style_class)
++ **instance-new-done*(__main__.old_style_class)
++ **instance-delete-start*(__main__.old_style_class)
++ **instance-delete-done*(__main__.old_style_class)
++ **instance-new-start*(__main__.new_style_class)
++ **instance-new-done*(__main__.new_style_class)
++ **instance-delete-start*(__main__.new_style_class)
++ **instance-delete-done*(__main__.new_style_class)
++ **instance-new-start*(__main__.old_style_class)
++ **instance-new-done*(__main__.old_style_class)
++ **instance-new-start*(__main__.new_style_class)
++ **instance-new-done*(__main__.new_style_class)
++ **instance-delete-start*(__main__.old_style_class)
++ **instance-delete-done*(__main__.old_style_class)
++ **instance-delete-start*(__main__.new_style_class)
++ **instance-delete-done*(__main__.new_style_class)
++ """
++
++ command = "%s %s" %(sys.executable, sample)
++ if self.optimize :
++ command = "%s -OO %s" %(sys.executable, sample)
++ actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
++ dscript,
++ "-c", command],
++ stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
++
++ actual_result = normalize(actual_result)
++ expected_result = expected_result.replace("\r", "").replace("\n",
++ "").replace(" ", "")
++ self.assertEqual(actual_result, expected_result)
++
++ def test_unicode_function_entry_return(self) :
++ dscript = """
++python$target:::function-entry
++/(copyinstr(arg0)=="%(path)s") &&
++(copyinstr(arg1)=="test_unicode_entry_return_and_stack")/
++{
++ self->trace = 1;
++}
++python$target:::function-entry,python$target:::function-return
++/(copyinstr(arg0)=="%(path)s") && (self->trace)/
++{
++ printf("%%d\t**%%s*%%s*%%s*%%d\\n", timestamp,
++ probename, copyinstr(arg0),
++ copyinstr(arg1), arg2);
++}
++python$target:::function-return
++/(copyinstr(arg0)=="%(path)s") &&
++(copyinstr(arg1)=="test_unicode_entry_return_and_stack")/
++{
++ self->trace = 0;
++}
++""" %{"path":sample}
++
++ dscript = dscript.replace("\r", "").replace("\n", "")
++ expected_result = """
++ **function-entry*%(path)s*test_unicode_entry_return_and_stack*41
++ **function-entry*%(path)s*únícódé*42
++ **function-return*%(path)s*únícódé*43
++ **function-return*%(path)s*test_unicode_entry_return_and_stack*44
++ """ %{"path":sample}
++
++ command = "%s %s" %(sys.executable, sample)
++ if self.optimize :
++ command = "%s -OO %s" %(sys.executable, sample)
++ actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
++ dscript,
++ "-c", command],
++ stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
++
++ actual_result = actual_result.decode("utf8")
++ actual_result = normalize(actual_result)
++ expected_result = expected_result.replace("\r", "").replace("\n",
++ "").replace(" ", "")
++ self.assertEqual(actual_result, expected_result)
++
++ @unittest.skipIf(sys.platform == 'darwin',
++ "MacOS X doesn't support jstack()")
++ def test_unicode_stack(self) :
++ dscript = """
++python$target:::function-entry
++/(copyinstr(arg0)=="%(path)s") &&
++(copyinstr(arg1)=="test_unicode_entry_return_and_stack")/
++{
++ self->trace = 1;
++}
++python$target:::function-entry
++/(copyinstr(arg0)=="%(path)s") && (self->trace)/
++{
++ printf("[x]");
++ jstack();
++}
++python$target:::function-return
++/(copyinstr(arg0)=="%(path)s") &&
++(copyinstr(arg1)=="test_unicode_entry_return_and_stack")/
++{
++ self->trace = 0;
++}
++""" %{"path":sample}
++
++ dscript = dscript.replace("\r", "").replace("\n", "")
++ expected_result = """
++ [x]
++ [%(path)s:41(test_unicode_entry_return_and_stack)]
++ [x]
++ [%(path)s:42(únícódé)]
++ [%(path)s:44(test_unicode_entry_return_and_stack)]
++ """ %{"path":sample}
++
++ command = "%s %s" %(sys.executable, sample)
++ if self.optimize :
++ command = "%s -OO %s" %(sys.executable, sample)
++ actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
++ dscript,
++ "-c", command],
++ stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
++
++ actual_result = actual_result.decode("utf8")
++ # When compiling with '--with-pydebug'
++ actual_result = "".join(re.split("\[[0-9]+ refs\]", actual_result))
++
++ actual_result = [i for i in actual_result.split("\n") \
++ if (("[" in i) and not i.endswith(" (<module>) ]"))]
++ actual_result = "".join(actual_result)
++ actual_result = actual_result.replace("\r", "").replace("\n",
++ "").replace(" ", "")
++ expected_result = expected_result.replace("\r", "").replace("\n",
++ "").replace(" ", "")
++ self.assertEqual(actual_result, expected_result)
++
++
++
++# This class try to verify that dtrace probes
++# are still working with optimizations enabled in the bytecode.
++#
++# Some tests will not actually verify it. For instance,
++# source code compilation follows optimization status of
++# current working Python. So, you should run the test
++# both with an optimizing and a non optimizing Python.
++class DTraceTestsOptimize(DTraceTestsNormal) :
++ def setUp(self) :
++ self.optimize = True
++
++
++def test_main():
++ run_unittest(DTraceTestsNormal)
++ run_unittest(DTraceTestsOptimize)
++
++if __name__ == '__main__':
++ test_main()
++
+--- Python-3.4.0/Lib/test/test_sys.py
++++ Python-3.4.0/Lib/test/test_sys.py
+@@ -729,6 +729,7 @@
+ self.assertEqual(sys.getsizeof(True, -1), size('') + self.longdigit)
+
+ def test_objecttypes(self):
++ import dtrace
+ # check all types defined in Objects/
+ size = test.support.calcobjsize
+ vsize = test.support.calcvobjsize
+@@ -754,13 +755,17 @@
+ return inner
+ check(get_cell().__closure__[0], size('P'))
+ # code
+- check(get_cell().__code__, size('5i9Pi3P'))
+- check(get_cell.__code__, size('5i9Pi3P'))
++ if dtrace.available :
++ code = '5i9PiPH2P'
++ else :
++ code = '5i9Pi3P'
++ check(get_cell().__code__, size(code))
++ check(get_cell.__code__, size(code))
+ def get_cell2(x):
+ def inner():
+ return x
+ return inner
+- check(get_cell2.__code__, size('5i9Pi3P') + 1)
++ check(get_cell2.__code__, size(code) + 1)
+ # complex
+ check(complex(0,1), size('2d'))
+ # method_descriptor (descriptor object)
+--- Python-3.4.0/Makefile.pre.in
++++ Python-3.4.0/Makefile.pre.in
+@@ -52,6 +52,13 @@
+ # Use this to make a link between python$(VERSION) and python in $(BINDIR)
+ LN= @LN@
+
++DTRACE= @DTRACE@
++DFLAGS= @DFLAGS@
++DTRACEOBJS= @DTRACEOBJS@
++DTRACE_NM= @DTRACE_NM@
++DTRACE_LINKER= @DTRACE_LINKER@
++
++
+ # Portable install script (configure doesn't always guess right)
+ INSTALL= @INSTALL@
+ INSTALL_PROGRAM=@INSTALL_PROGRAM@
+@@ -569,7 +576,7 @@
+ $(AR) $(ARFLAGS) $@ $(MODOBJS)
+ $(RANLIB) $@
+
+-libpython$(LDVERSION).so: $(LIBRARY_OBJS)
++libpython$(LDVERSION).so: $(LIBRARY_OBJS) $(DTRACEOBJS)
+ if test $(INSTSONAME) != $(LDLIBRARY); then \
+ $(BLDSHARED) -Wl,-h$(INSTSONAME) -o $(INSTSONAME) $(LIBRARY_OBJS) $(MODLIBS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \
+ $(LN) -f $(INSTSONAME) $@; \
+@@ -580,9 +587,8 @@
+ libpython3.so: libpython$(LDVERSION).so
+ $(BLDSHARED) $(NO_AS_NEEDED) -o $@ -Wl,-h$@ $^
+
+-libpython$(LDVERSION).dylib: $(LIBRARY_OBJS)
+- $(CC) -dynamiclib -Wl,-single_module $(PY_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \
+-
++libpython$(LDVERSION).dylib: $(LIBRARY_OBJS) $(DTRACEOBJS)
++ $(CC) -dynamiclib -Wl,-single_module $(PY_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(DTRACEOBJS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST)
+
+ libpython$(VERSION).sl: $(LIBRARY_OBJS)
+ $(LDSHARED) -o $@ $(LIBRARY_OBJS) $(MODLIBS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST)
+@@ -682,12 +688,18 @@
+ $(MODULE_OBJS) \
+ $(SIGNAL_OBJS) \
+ $(MODOBJS) \
++ $(DTRACEOBJS) \
+ $(srcdir)/Modules/getbuildinfo.c
+ $(CC) -c $(PY_CORE_CFLAGS) \
+ -DHGVERSION="\"`LC_ALL=C $(HGVERSION)`\"" \
+ -DHGTAG="\"`LC_ALL=C $(HGTAG)`\"" \
+ -DHGBRANCH="\"`LC_ALL=C $(HGBRANCH)`\"" \
+ -o $@ $(srcdir)/Modules/getbuildinfo.c
++ if test "$(DTRACEOBJS)" != "" ; then \
++ $(DTRACE_LINKER) --relocatable \
++ $@ $(DTRACEOBJS) -o [email protected] ; \
++ mv [email protected] $@ ; \
++ fi;
+
+ Modules/getpath.o: $(srcdir)/Modules/getpath.c Makefile
+ $(CC) -c $(PY_CORE_CFLAGS) -DPYTHONPATH='"$(PYTHONPATH)"' \
+@@ -820,6 +832,46 @@
+ Objects/typeslots.inc: $(srcdir)/Include/typeslots.h $(srcdir)/Objects/typeslots.py
+ $(PYTHON) $(srcdir)/Objects/typeslots.py < $(srcdir)/Include/typeslots.h > Objects/typeslots.inc
+
++$(srcdir)/Include/pydtrace.h: $(srcdir)/Include/pydtrace.d
++ if test "$(DTRACE)" != "" ; then \
++ $(DTRACE) -o $@ $(DFLAGS) \
++ -C -h -s $(srcdir)/Include/pydtrace.d ; \
++ else touch $@ ; \
++ fi;
++
++$(srcdir)/Include/pydtrace_offsets.h: $(srcdir)/Include/pydtrace_offsets.c Python/ceval.o
++ $(CC) $(PY_CORE_CFLAGS) -o $(srcdir)/Include/pydtrace_offsets \
++ $(srcdir)/Include/pydtrace_offsets.c
++ $(srcdir)/Include/pydtrace_offsets.sh $(DTRACE_NM) \
++ Python/ceval.o $(srcdir)/Include/pydtrace_offsets > \
++ $(srcdir)/Include/pydtrace_offsets.h
++
++Python/ceval.o: Include/pydtrace.h
++Modules/gcmodule.o: Include/pydtrace.h
++Objects/typeobject.o: Include/pydtrace.h
++
++Python/pydtrace.o: $(srcdir)/Include/pydtrace.d $(srcdir)/Include/pydtrace_offsets.h \
++ Python/ceval.o Modules/gcmodule.o Objects/typeobject.o
++ # We do the "touch" game to break a circular dependency between
++ # "Python/ceval.o" and "Include/pydtrace_offsets.h".
++ if test "$(DTRACE)" != "" ; then \
++ touch -r Python/ceval.o Python/ceval.o.ts_dtrace ; \
++ touch -r Modules/gcmodule.o Modules/gcmodule.o.ts_dtrace ; \
++ touch -r Objects/typeobject.o Objects/typeobject.o.ts_dtrace ; \
++ $(DTRACE) -o $@ -DPYDTRACE_STACK_HELPER \
++ $(DFLAGS) $(PY_CPPFLAGS) \
++ -C -G -s $(srcdir)/Include/pydtrace.d \
++ Python/ceval.o Modules/gcmodule.o \
++ Objects/typeobject.o; \
++ touch -r Python/ceval.o.ts_dtrace Python/ceval.o ; \
++ touch -r Modules/gcmodule.o.ts_dtrace Modules/gcmodule.o ; \
++ touch -r Objects/typeobject.o.ts_dtrace Objects/typeobject.o ; \
++ rm Python/ceval.o.ts_dtrace ; \
++ rm Modules/gcmodule.o.ts_dtrace ; \
++ rm Objects/typeobject.o.ts_dtrace ; \
++ else touch $@ ; \
++ fi;
++
+ ############################################################################
+ # Header files
+
+@@ -1515,6 +1567,11 @@
+ find build -name '*.py[co]' -exec rm -f {} ';' || true
+ -rm -f pybuilddir.txt
+ -rm -f Lib/lib2to3/*Grammar*.pickle
++ rm -f Include/pydtrace.h
++ rm -f Include/pydtrace_offsets Include/pydtrace_offsets.h
++ rm -f Python/ceval.o.ts_dtrace
++ rm -f Modules/gcmodule.o.ts_dtrace
++ rm -f Objects/typeobject.o.ts_dtrace
+ -rm -f Modules/_testembed Modules/_freeze_importlib
+
+ profile-removal:
+@@ -1546,6 +1603,11 @@
+ -o -name '*.orig' -o -name '*.rej' \
+ -o -name '*.bak' ')' \
+ -exec rm -f {} ';'
++ rm -f Include/pydtrace.h
++ rm -f Include/pydtrace_offsets Include/pydtrace_offsets.h
++ rm -f Python/ceval.o.ts_dtrace
++ rm -f Modules/gcmodule.o.ts_dtrace
++ rm -f Objects/typeobject.o.ts_dtrace
+
+ # Check for smelly exported symbols (not starting with Py/_Py)
+ smelly: all
+--- Python-3.4.0/Modules/Setup.dist
++++ Python-3.4.0/Modules/Setup.dist
+@@ -390,3 +390,5 @@
+
+ # Another example -- the 'xxsubtype' module shows C-level subtyping in action
+ xxsubtype xxsubtype.c
++
++dtrace dtracemodule.c
+--- /dev/null
++++ Python-3.4.0/Modules/dtracemodule.c
+@@ -0,0 +1,39 @@
++#include "Python.h"
++
++static PyMethodDef dtrace_methods[] = {
++ {NULL, NULL} /* sentinel */
++};
++
++
++static struct PyModuleDef dtracemodule = {
++ PyModuleDef_HEAD_INIT,
++ "dtrace",
++ NULL,
++ -1,
++ dtrace_methods,
++ NULL,
++ NULL,
++ NULL,
++ NULL
++};
++
++PyMODINIT_FUNC
++PyInit_dtrace(void)
++{
++ PyObject *m, *v;
++
++ m = PyModule_Create(&dtracemodule);
++ if (m) {
++#ifdef WITH_DTRACE
++ v = Py_True;
++#else
++ v = Py_False;
++#endif
++ Py_INCREF(v);
++ if (PyModule_AddObject(m, "available", v) < 0) {
++ Py_DECREF(m);
++ return NULL;
++ }
++ }
++ return m;
++}
+--- Python-3.4.0/Modules/gcmodule.c
++++ Python-3.4.0/Modules/gcmodule.c
+@@ -26,6 +26,10 @@
+ #include "Python.h"
+ #include "frameobject.h" /* for PyFrame_ClearFreeList */
+
++#ifdef WITH_DTRACE
++#include "pydtrace.h"
++#endif
++
+ /* Get an object's GC head */
+ #define AS_GC(o) ((PyGC_Head *)(o)-1)
+
+@@ -905,7 +909,12 @@
+ /* This is the main function. Read this to understand how the
+ * collection process works. */
+ static Py_ssize_t
+-collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable,
++#ifdef WITH_DTRACE
++collect2
++#else
++collect
++#endif
++(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable,
+ int nofail)
+ {
+ int i;
+@@ -1080,6 +1089,50 @@
+ return n+m;
+ }
+
++#ifdef WITH_DTRACE
++static void
++dtrace_gc_start(int collection)
++{
++ PYTHON_GC_START(collection);
++
++ /*
++ * Currently a USDT tail-call will not receive the correct arguments.
++ * Disable the tail call here.
++ */
++#if defined(__sparc)
++ asm("nop");
++#endif
++}
++
++static void
++dtrace_gc_done(Py_ssize_t value)
++{
++ PYTHON_GC_DONE((long) value);
++
++ /*
++ * Currently a USDT tail-call will not receive the correct arguments.
++ * Disable the tail call here.
++ */
++#if defined(__sparc)
++ asm("nop");
++#endif
++}
++
++static Py_ssize_t
++collect(int collection, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable,
++ int nofail)
++{
++ Py_ssize_t value;
++
++ if (PYTHON_GC_START_ENABLED())
++ dtrace_gc_start(collection);
++ value = collect2(collection, n_collected, n_uncollectable, nofail);
++ if (PYTHON_GC_DONE_ENABLED())
++ dtrace_gc_done(value);
++ return value;
++}
++#endif /* WITH_DTRACE */
++
+ /* Invoke progress callbacks to notify clients that garbage collection
+ * is starting or stopping
+ */
+--- Python-3.4.0/Objects/codeobject.c
++++ Python-3.4.0/Objects/codeobject.c
+@@ -152,6 +152,37 @@
+ co->co_lnotab = lnotab;
+ co->co_zombieframe = NULL;
+ co->co_weakreflist = NULL;
++
++#ifdef WITH_DTRACE
++ /*
++ ** Cache UTF8 internally, available
++ ** for the pythonframe stack walker.
++ */
++ PyUnicode_AsUTF8(filename);
++ PyUnicode_AsUTF8(name);
++
++ i = PyBytes_Size(co->co_code);
++ co->co_linenos = PyMem_Malloc(sizeof(unsigned short) * i);
++ if (co->co_linenos) {
++ unsigned short *p = (unsigned short *)(co->co_linenos);
++ unsigned char *p2 = (unsigned char*)PyBytes_AsString(co->co_lnotab);
++ int size = PyBytes_Size(co->co_lnotab) / 2;
++ int i2;
++ unsigned short offset = 0;
++
++ while (size) {
++ size -= 1;
++ i2 = *p2++;
++ i-=i2;
++ while (i2--)
++ *p++ = offset;
++ offset += *p2++;
++ }
++ while(i--)
++ *p++ = offset;
++ }
++#endif
++
+ return co;
+ }
+
+--- Python-3.4.0/Objects/frameobject.c
++++ Python-3.4.0/Objects/frameobject.c
+@@ -733,6 +733,15 @@
+ f->f_executing = 0;
+ f->f_gen = NULL;
+
++#ifdef WITH_DTRACE
++ /*
++ ** Cache UTF8 internally, available
++ ** for the pythonframe stack walker.
++ */
++ PyUnicode_AsUTF8(f->f_code->co_filename);
++ PyUnicode_AsUTF8(f->f_code->co_name);
++#endif
++
+ _PyObject_GC_TRACK(f);
+ return f;
+ }
+--- Python-3.4.0/Objects/typeobject.c
++++ Python-3.4.0/Objects/typeobject.c
+@@ -4,6 +4,10 @@
+ #include "frameobject.h"
+ #include "structmember.h"
+
++#ifdef WITH_DTRACE
++#include "pydtrace.h"
++#endif
++
+ #include <ctype.h>
+
+
+@@ -880,8 +884,29 @@
+ PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
+ {
+ PyObject *obj;
+- const size_t size = _PyObject_VAR_SIZE(type, nitems+1);
++ size_t size;
++
++#ifdef WITH_DTRACE
++ PyObject *mod;
++ char *mod_name;
++
++ if (PYTHON_INSTANCE_NEW_START_ENABLED()) {
++ if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
++ mod = PyDict_GetItemString(type->tp_dict, "__module__");
++ if (mod == NULL || !PyUnicode_Check(mod)) {
++ mod_name = "?";
++ } else {
++ mod_name = PyUnicode_AsUTF8(mod);
++ if (!mod_name)
++ mod_name = "?";
++ }
++ PYTHON_INSTANCE_NEW_START((char *)(type->tp_name), mod_name);
++ }
++ }
++#endif
++
+ /* note that we need to add one, for the sentinel */
++ size = _PyObject_VAR_SIZE(type, nitems+1);
+
+ if (PyType_IS_GC(type))
+ obj = _PyObject_GC_Malloc(size);
+@@ -903,6 +928,23 @@
+
+ if (PyType_IS_GC(type))
+ _PyObject_GC_TRACK(obj);
++
++#ifdef WITH_DTRACE
++ if (PYTHON_INSTANCE_NEW_DONE_ENABLED()) {
++ if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
++ mod = PyDict_GetItemString(type->tp_dict, "__module__");
++ if (mod == NULL || !PyUnicode_Check(mod)) {
++ mod_name = "?";
++ } else {
++ mod_name = PyUnicode_AsUTF8(mod);
++ if (!mod_name)
++ mod_name = "?";
++ }
++ PYTHON_INSTANCE_NEW_DONE((char *)(type->tp_name), mod_name);
++ }
++ }
++#endif
++
+ return obj;
+ }
+
+@@ -1023,9 +1065,56 @@
+ return 0;
+ }
+
++#ifdef WITH_DTRACE
++static void subtype_dealloc2(PyObject *); /* Forward declaration */
++
+ static void
+ subtype_dealloc(PyObject *self)
+ {
++ PyObject *mod;
++ char *mod_name;
++ PyTypeObject *type;
++
++ type = Py_TYPE(self);
++ Py_INCREF(type);
++
++ if (PYTHON_INSTANCE_DELETE_START_ENABLED()) {
++ mod = PyDict_GetItemString(type->tp_dict, "__module__");
++ if (mod == NULL || !PyUnicode_Check(mod)) {
++ mod_name = "?";
++ } else {
++ mod_name = PyUnicode_AsUTF8(mod);
++ if (!mod_name)
++ mod_name = "?";
++ }
++ PYTHON_INSTANCE_DELETE_START((char *)(type->tp_name), mod_name);
++ }
++
++ subtype_dealloc2(self);
++
++ if (PYTHON_INSTANCE_DELETE_DONE_ENABLED()) {
++ mod = PyDict_GetItemString(type->tp_dict, "__module__");
++ if (mod == NULL || !PyUnicode_Check(mod)) {
++ mod_name = "?";
++ } else {
++ mod_name = PyUnicode_AsUTF8(mod);
++ if (!mod_name)
++ mod_name = "?";
++ }
++ PYTHON_INSTANCE_DELETE_DONE((char *)(type->tp_name), mod_name);
++ }
++ Py_DECREF(type);
++}
++#endif
++
++static void
++#ifdef WITH_DTRACE
++subtype_dealloc2
++#else
++subtype_dealloc
++#endif
++(PyObject *self)
++{
+ PyTypeObject *type, *base;
+ destructor basedealloc;
+ PyThreadState *tstate = PyThreadState_GET();
+--- Python-3.4.0/Python/ceval.c
++++ Python-3.4.0/Python/ceval.c
+@@ -18,6 +18,13 @@
+
+ #include <ctype.h>
+
++#ifdef WITH_DTRACE
++#include "pydtrace.h"
++#else
++/* We can not have conditional compilation inside macros */
++#define PYTHON_LINE_ENABLED() (0)
++#endif
++
+ #ifndef WITH_TSC
+
+ #define READ_TIMESTAMP(var)
+@@ -119,6 +126,12 @@
+ #define CALL_FLAG_VAR 1
+ #define CALL_FLAG_KW 2
+
++#ifdef WITH_DTRACE
++static void maybe_dtrace_line(PyFrameObject *frame,
++ int *instr_lb, int *instr_ub,
++ int *instr_prev);
++#endif
++
+ #ifdef LLTRACE
+ static int lltrace;
+ static int prtrace(PyObject *, char *);
+@@ -778,6 +791,49 @@
+ NULL, NULL);
+ }
+
++#ifdef WITH_DTRACE
++static void
++dtrace_entry(PyFrameObject *f)
++{
++ char *filename;
++ char *name;
++ int lineno;
++
++ filename = PyUnicode_AsUTF8(f->f_code->co_filename);
++ name = PyUnicode_AsUTF8(f->f_code->co_name);
++ lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
++ PYTHON_FUNCTION_ENTRY(filename, name, lineno);
++
++ /*
++ * Currently a USDT tail-call will not receive the correct arguments.
++ * Disable the tail call here.
++ */
++#if defined(__sparc)
++ asm("nop");
++#endif
++}
++
++static void
++dtrace_return(PyFrameObject *f)
++{
++ char *filename;
++ char *name;
++ int lineno;
++
++ filename = PyUnicode_AsUTF8(f->f_code->co_filename);
++ name = PyUnicode_AsUTF8(f->f_code->co_name);
++ lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
++ PYTHON_FUNCTION_RETURN(filename, name, lineno);
++
++ /*
++ * Currently a USDT tail-call will not receive the correct arguments.
++ * Disable the tail call here.
++ */
++#if defined(__sparc)
++ asm("nop");
++#endif
++}
++#endif
+
+ /* Interpreter main loop */
+
+@@ -789,8 +845,16 @@
+ return PyEval_EvalFrameEx(f, 0);
+ }
+
++
+ PyObject *
++#if defined(WITH_DTRACE) && defined(__amd64)
++PyEval_EvalFrameExReal(long a1, long a2, long a3, long a4, long a5, long a6,
++ PyFrameObject *f, int throwflag)
++#elif defined(WITH_DTRACE) && defined(__sparc)
++PyEval_EvalFrameExReal(PyFrameObject *f, int throwflag)
++#else
+ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
++#endif
+ {
+ #ifdef DXPAIRS
+ int lastopcode = 0;
+@@ -911,7 +975,7 @@
+ #ifdef LLTRACE
+ #define FAST_DISPATCH() \
+ { \
+- if (!lltrace && !_Py_TracingPossible) { \
++ if (!lltrace && !_Py_TracingPossible && !PYTHON_LINE_ENABLED()) { \
+ f->f_lasti = INSTR_OFFSET(); \
+ goto *opcode_targets[*next_instr++]; \
+ } \
+@@ -920,7 +984,7 @@
+ #else
+ #define FAST_DISPATCH() \
+ { \
+- if (!_Py_TracingPossible) { \
++ if (!_Py_TracingPossible && !PYTHON_LINE_ENABLED()) { \
+ f->f_lasti = INSTR_OFFSET(); \
+ goto *opcode_targets[*next_instr++]; \
+ } \
+@@ -1156,6 +1220,11 @@
+ }
+ }
+
++#ifdef WITH_DTRACE
++ if (PYTHON_FUNCTION_ENTRY_ENABLED())
++ dtrace_entry(f);
++#endif
++
+ co = f->f_code;
+ names = co->co_names;
+ consts = co->co_consts;
+@@ -1343,6 +1412,12 @@
+ /* Main switch on opcode */
+ READ_TIMESTAMP(inst0);
+
++#ifdef WITH_DTRACE
++ if (PYTHON_LINE_ENABLED()) {
++ maybe_dtrace_line(f, &instr_lb, &instr_ub, &instr_prev);
++ }
++#endif
++
+ switch (opcode) {
+
+ /* BEWARE!
+@@ -3216,6 +3291,10 @@
+
+ /* pop frame */
+ exit_eval_frame:
++#ifdef WITH_DTRACE
++ if (PYTHON_FUNCTION_RETURN_ENABLED())
++ dtrace_return(f);
++#endif
+ Py_LeaveRecursiveCall();
+ f->f_executing = 0;
+ tstate->frame = f->f_back;
+@@ -3915,6 +3994,57 @@
+ return result;
+ }
+
++/*
++ * These shenanigans look like utter madness, but what we're actually doing is
++ * making sure that the ustack helper will see the PyFrameObject pointer on the
++ * stack. We have two tricky cases:
++ *
++ * amd64
++ *
++ * We use up the six registers for passing arguments, meaning the call can't
++ * use a register for passing 'f', and has to push it onto the stack in a known
++ * location.
++ *
++ * And how does "throwflag" figure in to this? -PN
++ *
++ * SPARC
++ *
++ * Here the problem is that (on 32-bit) the compiler is re-using %i0 before
++ * some calls inside PyEval_EvalFrameReal(), which means that when it's saved,
++ * it's just some junk value rather than the real first argument. So, instead,
++ * we trace our proxy PyEval_EvalFrame(), where we 'know' the compiler won't
++ * decide to re-use %i0. We also need to defeat optimization of our proxy.
++ */
++
++#if defined(WITH_DTRACE)
++
++#if defined(__amd64)
++
++PyObject *
++PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
++{
++ volatile PyObject *f2;
++ f2 = PyEval_EvalFrameExReal(0, 0, 0, 0, 0, 0, f, throwflag);
++ return (PyObject *)f2;
++}
++
++#elif defined(__sparc)
++
++volatile int dummy;
++
++PyObject *
++PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
++{
++ volatile PyObject *f2;
++ f2 = PyEval_EvalFrameExReal(f, throwflag);
++ dummy = f->ob_base.ob_base.ob_refcnt;
++ return (PyObject *)f2;
++}
++
++#endif
++#endif
++
++
+ PyObject *
+ _PyEval_CallTracing(PyObject *func, PyObject *args)
+ {
+@@ -3932,6 +4062,51 @@
+ return result;
+ }
+
++#ifdef WITH_DTRACE
++/* See Objects/lnotab_notes.txt for a description of how tracing works. */
++/* Practically a ripoff of "maybe_call_line_trace" function. */
++static void
++maybe_dtrace_line(PyFrameObject *frame,
++ int *instr_lb, int *instr_ub, int *instr_prev)
++{
++ int line = frame->f_lineno;
++ char *co_filename, *co_name;
++
++ /* If the last instruction executed isn't in the current
++ instruction window, reset the window.
++ */
++ if (frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub) {
++ PyAddrPair bounds;
++ line = _PyCode_CheckLineNumber(frame->f_code, frame->f_lasti,
++ &bounds);
++ *instr_lb = bounds.ap_lower;
++ *instr_ub = bounds.ap_upper;
++ }
++ /* If the last instruction falls at the start of a line or if
++ it represents a jump backwards, update the frame's line
++ number and call the trace function. */
++ if (frame->f_lasti == *instr_lb || frame->f_lasti < *instr_prev) {
++ frame->f_lineno = line;
++ co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename);
++ if (!co_filename)
++ co_filename = "?";
++ co_name = PyUnicode_AsUTF8(frame->f_code->co_name);
++ if (!co_name)
++ co_name = "?";
++ PYTHON_LINE(co_filename, co_name, line);
++ }
++ *instr_prev = frame->f_lasti;
++
++ /*
++ * Currently a USDT tail-call will not receive the correct arguments.
++ * Disable the tail call here.
++ */
++#if defined(__sparc)
++ asm("nop");
++#endif
++}
++#endif
++
+ /* See Objects/lnotab_notes.txt for a description of how tracing works. */
+ static int
+ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
+--- Python-3.4.0/configure
++++ Python-3.4.0/configure
+@@ -642,6 +642,11 @@
+ MACHDEP_OBJS
+ DYNLOADFILE
+ DLINCLDIR
++DTRACEOBJS
++DTRACE_LINKER
++DTRACE_NM
++DFLAGS
++DTRACE
+ THREADOBJ
+ LDLAST
+ USE_THREAD_MODULE
+@@ -811,6 +816,7 @@
+ with_tsc
+ with_pymalloc
+ with_valgrind
++with_dtrace
+ with_fpectl
+ with_libm
+ with_libc
+@@ -1494,6 +1500,7 @@
+ --with(out)-tsc enable/disable timestamp counter profile
+ --with(out)-pymalloc disable/enable specialized mallocs
+ --with-valgrind Enable Valgrind support
++ --with(out)-dtrace disable/enable dtrace support
+ --with-fpectl enable SIGFPE catching
+ --with-libm=STRING math library
+ --with-libc=STRING C library
+@@ -10391,6 +10398,174 @@
+ OPT="-DDYNAMIC_ANNOTATIONS_ENABLED=1 $OPT"
+ fi
+
++# Check for dtrace support
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-dtrace" >&5
++$as_echo_n "checking for --with-dtrace... " >&6; }
++
++# Check whether --with-dtrace was given.
++if test "${with_dtrace+set}" = set; then :
++ withval=$with_dtrace;
++else
++ with_dtrace=no
++fi
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_dtrace" >&5
++$as_echo "$with_dtrace" >&6; }
++
++
++
++
++
++DTRACE=
++DFLAGS=
++if test "$with_dtrace" = "yes"
++then
++ DTRACE_NM=OTHER
++ DTRACE_LINKER=ld
++ DTRACEOBJS="Python/pydtrace.o"
++ # Extract the first word of "dtrace", so it can be a program name with args.
++set dummy dtrace; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_path_DTRACE+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ case $DTRACE in
++ [\\/]* | ?:[\\/]*)
++ ac_cv_path_DTRACE="$DTRACE" # Let the user override the test with a path.
++ ;;
++ *)
++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH$PATH_SEPARATOR/usr/sbin
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_path_DTRACE="$as_dir/$ac_word$ac_exec_ext"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++ test -z "$ac_cv_path_DTRACE" && ac_cv_path_DTRACE="dtrace"
++ ;;
++esac
++fi
++DTRACE=$ac_cv_path_DTRACE
++if test -n "$DTRACE"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DTRACE" >&5
++$as_echo "$DTRACE" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++ # The cast to long int works around a bug in the HP C Compiler
++# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
++# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
++# This bug is HP SR number 8606223364.
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5
++$as_echo_n "checking size of long... " >&6; }
++if ${ac_cv_sizeof_long+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then :
++
++else
++ if test "$ac_cv_type_long" = yes; then
++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error 77 "cannot compute sizeof (long)
++See \`config.log' for more details" "$LINENO" 5; }
++ else
++ ac_cv_sizeof_long=0
++ fi
++fi
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5
++$as_echo "$ac_cv_sizeof_long" >&6; }
++
++
++
++cat >>confdefs.h <<_ACEOF
++#define SIZEOF_LONG $ac_cv_sizeof_long
++_ACEOF
++
++
++ if test "$ac_cv_sizeof_long" -eq 8
++ then
++ DFLAGS="-64"
++ else
++ DFLAGS="-32"
++ fi
++ sys_release="$ac_sys_release"
++ case $ac_sys_system/$sys_release in
++ SunOS/5.10)
++ DTRACE_NM=SOLARIS
++ DTRACE_LINKER=/usr/ccs/bin/ld
++ ;;
++ SunOS/5.11 | SunOS/5.12)
++ DTRACE_NM=SOLARIS
++ DTRACE_LINKER=/usr/bin/ld
++ ;;
++ SunOS/*)
++ DTRACE_LINKER=/usr/ccs/bin/ld
++ ;;
++ Darwin/*)
++ DTRACEOBJS="" # Not needed in Mac
++ # The cast to long int works around a bug in the HP C Compiler
++# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
++# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
++# This bug is HP SR number 8606223364.
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5
++$as_echo_n "checking size of long... " >&6; }
++if ${ac_cv_sizeof_long+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then :
++
++else
++ if test "$ac_cv_type_long" = yes; then
++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error 77 "cannot compute sizeof (long)
++See \`config.log' for more details" "$LINENO" 5; }
++ else
++ ac_cv_sizeof_long=0
++ fi
++fi
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5
++$as_echo "$ac_cv_sizeof_long" >&6; }
++
++
++
++cat >>confdefs.h <<_ACEOF
++#define SIZEOF_LONG $ac_cv_sizeof_long
++_ACEOF
++
++
++ if test "$ac_cv_sizeof_long" -eq 8
++ then
++ DFLAGS="-arch i386"
++ else
++ DFLAGS="-arch x86_64"
++ fi
++ ;;
++ esac
++
++$as_echo "#define WITH_DTRACE 1" >>confdefs.h
++
++fi
++
++
++
+ # -I${DLINCLDIR} is added to the compile rule for importdl.o
+
+ DLINCLDIR=.
+--- Python-3.4.0/configure.ac
++++ Python-3.4.0/configure.ac
+@@ -2868,6 +2868,62 @@
+ OPT="-DDYNAMIC_ANNOTATIONS_ENABLED=1 $OPT"
+ fi
+
++# Check for dtrace support
++AC_MSG_CHECKING(for --with-dtrace)
++AC_ARG_WITH(dtrace,
++ AC_HELP_STRING(--with(out)-dtrace, disable/enable dtrace support),,
++ with_dtrace=no)
++AC_MSG_RESULT($with_dtrace)
++
++AC_SUBST(DTRACE)
++AC_SUBST(DFLAGS)
++AC_SUBST(DTRACE_NM)
++AC_SUBST(DTRACE_LINKER)
++DTRACE=
++DFLAGS=
++if test "$with_dtrace" = "yes"
++then
++ DTRACE_NM=OTHER
++ DTRACE_LINKER=ld
++ DTRACEOBJS="Python/pydtrace.o"
++ AC_PATH_PROG(DTRACE, [dtrace], [dtrace], [$PATH$PATH_SEPARATOR/usr/sbin])
++ AC_CHECK_SIZEOF([long])
++ if [test "$ac_cv_sizeof_long" -eq 8]
++ then
++ DFLAGS="-64"
++ else
++ DFLAGS="-32"
++ fi
++ sys_release="$ac_sys_release"
++ case $ac_sys_system/$sys_release in
++ SunOS/5.10)
++ DTRACE_NM=SOLARIS
++ DTRACE_LINKER=/usr/ccs/bin/ld
++ ;;
++ SunOS/5.11 | SunOS/5.12)
++ DTRACE_NM=SOLARIS
++ DTRACE_LINKER=/usr/bin/ld
++ ;;
++ SunOS/*)
++ DTRACE_LINKER=/usr/ccs/bin/ld
++ ;;
++ Darwin/*)
++ DTRACEOBJS="" # Not needed in Mac
++ AC_CHECK_SIZEOF([long])
++ if [test "$ac_cv_sizeof_long" -eq 8]
++ then
++ DFLAGS="-arch i386"
++ else
++ DFLAGS="-arch x86_64"
++ fi
++ ;;
++ esac
++ AC_DEFINE(WITH_DTRACE, 1,
++ [Define if you want to compile in Dtrace support])
++fi
++
++AC_SUBST(DTRACEOBJS)
++
+ # -I${DLINCLDIR} is added to the compile rule for importdl.o
+ AC_SUBST(DLINCLDIR)
+ DLINCLDIR=.
+--- Python-3.4.0/pyconfig.h.in
++++ Python-3.4.0/pyconfig.h.in
+@@ -1328,6 +1328,9 @@
+ /* Define if you want documentation strings in extension modules */
+ #undef WITH_DOC_STRINGS
+
++/* Define if you want to compile in Dtrace support */
++#undef WITH_DTRACE
++
+ /* Define if you want to use the new-style (Openstep, Rhapsody, MacOS) dynamic
+ linker (dyld) instead of the old-style (NextStep) dynamic linker (rld).
+ Dyld is necessary to support frameworks. */
+--- Python-3.4.0/setup.py
++++ Python-3.4.0/setup.py
+@@ -637,6 +637,9 @@
+ # syslog daemon interface
+ exts.append( Extension('syslog', ['syslogmodule.c']) )
+
++ # jcea DTRACE probes
++ exts.append( Extension('dtrace', ['dtracemodule.c']) )
++
+ #
+ # Here ends the simple stuff. From here on, modules need certain
+ # libraries, are platform-specific, or present other surprises.