17757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch/* C-based Tracer for Coverage. */
27757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
37757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "Python.h"
47757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "compile.h"        /* in 2.3, this wasn't part of Python.h */
57757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "eval.h"           /* or this. */
67757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "structmember.h"
77757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "frameobject.h"
87757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
97757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch/* Compile-time debugging helpers */
107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#undef WHAT_LOG         /* Define to log the WHAT params in the trace function. */
117757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#undef TRACE_LOG        /* Define to log our bookkeeping. */
127757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#undef COLLECT_STATS    /* Collect counters: stats are printed when tracer is stopped. */
137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#if COLLECT_STATS
157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define STATS(x)        x
167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#else
177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define STATS(x)
187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#endif
197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch/* Py 2.x and 3.x compatibility */
217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#ifndef Py_TYPE
237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define Py_TYPE(o)    (((PyObject*)(o))->ob_type)
247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#endif
257757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#if PY_MAJOR_VERSION >= 3
277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define MyText_Type         PyUnicode_Type
297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define MyText_Check(o)     PyUnicode_Check(o)
307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define MyText_AS_STRING(o) PyBytes_AS_STRING(PyUnicode_AsASCIIString(o))
317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define MyInt_FromLong(l)   PyLong_FromLong(l)
327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define MyType_HEAD_INIT    PyVarObject_HEAD_INIT(NULL, 0)
347757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#else
367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
377757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define MyText_Type         PyString_Type
387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define MyText_Check(o)     PyString_Check(o)
397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define MyText_AS_STRING(o) PyString_AS_STRING(o)
407757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define MyInt_FromLong(l)   PyInt_FromLong(l)
417757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
427757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define MyType_HEAD_INIT    PyObject_HEAD_INIT(NULL)  0,
437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#endif /* Py3k */
457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
467757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch/* The values returned to indicate ok or error. */
477757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define RET_OK      0
487757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define RET_ERROR   -1
497757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
507757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch/* An entry on the data stack.  For each call frame, we need to record the
517757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    dictionary to capture data, and the last line number executed in that
527757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    frame.
537757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch*/
547757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochtypedef struct {
557757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject * file_data;  /* PyMem_Malloc'ed, a borrowed ref. */
567757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    int last_line;
577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch} DataStackEntry;
587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch/* The CTracer type. */
607757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
617757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochtypedef struct {
627757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject_HEAD
637757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
647757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /* Python objects manipulated directly by the Collector class. */
657757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject * should_trace;
667757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject * warn;
677757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject * data;
687757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject * should_trace_cache;
697757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject * arcs;
707757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
717757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /* Has the tracer been started? */
727757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    int started;
737757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /* Are we tracing arcs, or just lines? */
747757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    int tracing_arcs;
757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
767757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /*
777757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        The data stack is a stack of dictionaries.  Each dictionary collects
787757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        data for a single source file.  The data stack parallels the call stack:
797757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        each call pushes the new frame's file data onto the data stack, and each
807757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        return pops file data off.
817757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
827757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        The file data is a dictionary whose form depends on the tracing options.
837757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        If tracing arcs, the keys are line number pairs.  If not tracing arcs,
847757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        the keys are line numbers.  In both cases, the value is irrelevant
857757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        (None).
867757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    */
877757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /* The index of the last-used entry in data_stack. */
887757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    int depth;
897757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /* The file data at each level, or NULL if not recording. */
907757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    DataStackEntry * data_stack;
917757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    int data_stack_alloc;       /* number of entries allocated at data_stack. */
927757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
937757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /* The current file_data dictionary.  Borrowed. */
947757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject * cur_file_data;
957757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
967757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /* The line number of the last line recorded, for tracing arcs.
977757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        -1 means there was no previous line, as when entering a code object.
987757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    */
997757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    int last_line;
1007757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1017757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /* The parent frame for the last exception event, to fix missing returns. */
1027757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyFrameObject * last_exc_back;
1037757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    int last_exc_firstlineno;
1047757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1057757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#if COLLECT_STATS
1067757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    struct {
10707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        unsigned calls;
10807a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        unsigned lines;
10907a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        unsigned returns;
11007a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        unsigned exceptions;
11107a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        unsigned others;
11207a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        unsigned new_files;
11307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        unsigned missed_returns;
11407a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        unsigned stack_reallocs;
11507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        unsigned errors;
1167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    } stats;
1177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#endif /* COLLECT_STATS */
1187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch} CTracer;
1197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define STACK_DELTA    100
1217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic int
1237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochCTracer_init(CTracer *self, PyObject *args_unused, PyObject *kwds_unused)
1247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch{
1257757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#if COLLECT_STATS
1267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->stats.calls = 0;
1277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->stats.lines = 0;
1287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->stats.returns = 0;
1297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->stats.exceptions = 0;
1307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->stats.others = 0;
1317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->stats.new_files = 0;
1327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->stats.missed_returns = 0;
1337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->stats.stack_reallocs = 0;
1347757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->stats.errors = 0;
1357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#endif /* COLLECT_STATS */
1367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1377757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->should_trace = NULL;
1387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->warn = NULL;
1397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->data = NULL;
1407757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->should_trace_cache = NULL;
1417757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->arcs = NULL;
1427757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->started = 0;
1447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->tracing_arcs = 0;
1457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1467757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->depth = -1;
1477757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->data_stack = PyMem_Malloc(STACK_DELTA*sizeof(DataStackEntry));
1487757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (self->data_stack == NULL) {
1497757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        STATS( self->stats.errors++; )
1507757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        PyErr_NoMemory();
1517757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        return RET_ERROR;
1527757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
1537757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->data_stack_alloc = STACK_DELTA;
1547757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1557757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->cur_file_data = NULL;
1567757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->last_line = -1;
1577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->last_exc_back = NULL;
1597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1607757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    return RET_OK;
1617757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch}
1627757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1637757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic void
1647757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochCTracer_dealloc(CTracer *self)
1657757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch{
1667757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (self->started) {
1677757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        PyEval_SetTrace(NULL, NULL);
1687757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
1697757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1707757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    Py_XDECREF(self->should_trace);
1717757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    Py_XDECREF(self->warn);
1727757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    Py_XDECREF(self->data);
1737757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    Py_XDECREF(self->should_trace_cache);
1747757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyMem_Free(self->data_stack);
1767757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1777757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    Py_TYPE(self)->tp_free((PyObject*)self);
1787757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch}
1797757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1807757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#if TRACE_LOG
1817757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic const char *
1827757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochindent(int n)
1837757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch{
1847757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    static const char * spaces =
1857757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "                                                                    "
1867757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "                                                                    "
1877757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "                                                                    "
1887757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "                                                                    "
1897757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        ;
1907757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    return spaces + strlen(spaces) - n*2;
1917757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch}
1927757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1937757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic int logging = 0;
1947757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch/* Set these constants to be a file substring and line number to start logging. */
1957757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic const char * start_file = "tests/views";
1967757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic int start_line = 27;
1977757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
1987757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic void
1997757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochshowlog(int depth, int lineno, PyObject * filename, const char * msg)
2007757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch{
2017757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (logging) {
2027757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        printf("%s%3d ", indent(depth), depth);
2037757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (lineno) {
2047757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            printf("%4d", lineno);
2057757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
2067757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        else {
2077757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            printf("    ");
2087757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
2097757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (filename) {
2107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            printf(" %s", MyText_AS_STRING(filename));
2117757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
2127757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (msg) {
2137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            printf(" %s", msg);
2147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
2157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        printf("\n");
2167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
2177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch}
2187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
2197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define SHOWLOG(a,b,c,d)    showlog(a,b,c,d)
2207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#else
2217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define SHOWLOG(a,b,c,d)
2227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#endif /* TRACE_LOG */
2237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
2247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#if WHAT_LOG
2257757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic const char * what_sym[] = {"CALL", "EXC ", "LINE", "RET "};
2267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#endif
2277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
2287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch/* Record a pair of integers in self->cur_file_data. */
2297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic int
2307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochCTracer_record_pair(CTracer *self, int l1, int l2)
2317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch{
2327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    int ret = RET_OK;
2337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
2347757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject * t = PyTuple_New(2);
2357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (t != NULL) {
2367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        PyTuple_SET_ITEM(t, 0, MyInt_FromLong(l1));
2377757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        PyTuple_SET_ITEM(t, 1, MyInt_FromLong(l2));
2387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (PyDict_SetItem(self->cur_file_data, t, Py_None) < 0) {
2397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            STATS( self->stats.errors++; )
2407757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            ret = RET_ERROR;
2417757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
2427757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        Py_DECREF(t);
2437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
2447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    else {
2457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        STATS( self->stats.errors++; )
2467757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        ret = RET_ERROR;
2477757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
2487757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    return ret;
2497757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch}
2507757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
2517757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch/*
2527757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * The Trace Function
2537757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch */
2547757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic int
2557757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochCTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unused)
2567757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch{
2577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    int ret = RET_OK;
2587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject * filename = NULL;
2597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject * tracename = NULL;
2607757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
2617757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    #if WHAT_LOG
2627757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (what <= sizeof(what_sym)/sizeof(const char *)) {
2637757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        printf("trace: %s @ %s %d\n", what_sym[what], MyText_AS_STRING(frame->f_code->co_filename), frame->f_lineno);
2647757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
2657757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    #endif
2667757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
2677757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    #if TRACE_LOG
2687757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (strstr(MyText_AS_STRING(frame->f_code->co_filename), start_file) && frame->f_lineno == start_line) {
2697757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        logging = 1;
2707757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
2717757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    #endif
2727757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
2737757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /* See below for details on missing-return detection. */
2747757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (self->last_exc_back) {
2757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (frame == self->last_exc_back) {
2767757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            /* Looks like someone forgot to send a return event. We'll clear
2777757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch               the exception state and do the RETURN code here.  Notice that the
2787757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch               frame we have in hand here is not the correct frame for the RETURN,
2797757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch               that frame is gone.  Our handling for RETURN doesn't need the
2807757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch               actual frame, but we do log it, so that will look a little off if
2817757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch               you're looking at the detailed log.
2827757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
2837757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch               If someday we need to examine the frame when doing RETURN, then
2847757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch               we'll need to keep more of the missed frame's state.
2857757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            */
2867757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            STATS( self->stats.missed_returns++; )
2877757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            if (self->depth >= 0) {
2887757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                if (self->tracing_arcs && self->cur_file_data) {
2897757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    if (CTracer_record_pair(self, self->last_line, -self->last_exc_firstlineno) < 0) {
2907757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                        return RET_ERROR;
2917757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    }
2927757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                }
2937757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename, "missedreturn");
2947757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                self->cur_file_data = self->data_stack[self->depth].file_data;
2957757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                self->last_line = self->data_stack[self->depth].last_line;
2967757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                self->depth--;
2977757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            }
2987757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
2997757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        self->last_exc_back = NULL;
3007757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
3017757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
3027757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
3037757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    switch (what) {
3047757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    case PyTrace_CALL:      /* 0 */
3057757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        STATS( self->stats.calls++; )
3067757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        /* Grow the stack. */
3077757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        self->depth++;
3087757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (self->depth >= self->data_stack_alloc) {
3097757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            STATS( self->stats.stack_reallocs++; )
3107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            /* We've outgrown our data_stack array: make it bigger. */
3117757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            int bigger = self->data_stack_alloc + STACK_DELTA;
3127757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            DataStackEntry * bigger_data_stack = PyMem_Realloc(self->data_stack, bigger * sizeof(DataStackEntry));
3137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            if (bigger_data_stack == NULL) {
3147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                STATS( self->stats.errors++; )
3157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                PyErr_NoMemory();
3167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                self->depth--;
3177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                return RET_ERROR;
3187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            }
3197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            self->data_stack = bigger_data_stack;
3207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            self->data_stack_alloc = bigger;
3217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
3227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
3237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        /* Push the current state on the stack. */
3247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        self->data_stack[self->depth].file_data = self->cur_file_data;
3257757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        self->data_stack[self->depth].last_line = self->last_line;
3267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
3277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        /* Check if we should trace this line. */
3287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        filename = frame->f_code->co_filename;
3297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        tracename = PyDict_GetItem(self->should_trace_cache, filename);
3307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (tracename == NULL) {
3317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            STATS( self->stats.new_files++; )
3327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            /* We've never considered this file before. */
3337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            /* Ask should_trace about it. */
3347757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            PyObject * args = Py_BuildValue("(OO)", filename, frame);
3357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            tracename = PyObject_Call(self->should_trace, args, NULL);
3367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            Py_DECREF(args);
3377757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            if (tracename == NULL) {
3387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                /* An error occurred inside should_trace. */
3397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                STATS( self->stats.errors++; )
3407757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                return RET_ERROR;
3417757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            }
3427757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            if (PyDict_SetItem(self->should_trace_cache, filename, tracename) < 0) {
3437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                STATS( self->stats.errors++; )
3447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                return RET_ERROR;
3457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            }
3467757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
3477757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        else {
3487757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            Py_INCREF(tracename);
3497757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
3507757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
3517757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        /* If tracename is a string, then we're supposed to trace. */
3527757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (MyText_Check(tracename)) {
3537757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            PyObject * file_data = PyDict_GetItem(self->data, tracename);
3547757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            if (file_data == NULL) {
3557757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                file_data = PyDict_New();
3567757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                if (file_data == NULL) {
3577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    STATS( self->stats.errors++; )
3587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    return RET_ERROR;
3597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                }
3607757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                ret = PyDict_SetItem(self->data, tracename, file_data);
3617757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                Py_DECREF(file_data);
3627757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                if (ret < 0) {
3637757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    STATS( self->stats.errors++; )
3647757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    return RET_ERROR;
3657757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                }
3667757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            }
3677757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            self->cur_file_data = file_data;
3687757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            /* Make the frame right in case settrace(gettrace()) happens. */
3697757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            Py_INCREF(self);
3707757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            frame->f_trace = (PyObject*)self;
3717757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            SHOWLOG(self->depth, frame->f_lineno, filename, "traced");
3727757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
3737757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        else {
3747757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            self->cur_file_data = NULL;
3757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            SHOWLOG(self->depth, frame->f_lineno, filename, "skipped");
3767757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
3777757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
3787757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        Py_DECREF(tracename);
3797757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
3807757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        self->last_line = -1;
3817757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        break;
3827757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
3837757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    case PyTrace_RETURN:    /* 3 */
3847757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        STATS( self->stats.returns++; )
3857757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        /* A near-copy of this code is above in the missing-return handler. */
3867757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (self->depth >= 0) {
3877757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            if (self->tracing_arcs && self->cur_file_data) {
3887757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                int first = frame->f_code->co_firstlineno;
3897757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                if (CTracer_record_pair(self, self->last_line, -first) < 0) {
3907757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    return RET_ERROR;
3917757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                }
3927757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            }
3937757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
3947757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename, "return");
3957757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            self->cur_file_data = self->data_stack[self->depth].file_data;
3967757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            self->last_line = self->data_stack[self->depth].last_line;
3977757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            self->depth--;
3987757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
3997757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        break;
4007757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
4017757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    case PyTrace_LINE:      /* 2 */
4027757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        STATS( self->stats.lines++; )
4037757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (self->depth >= 0) {
4047757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename, "line");
4057757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            if (self->cur_file_data) {
4067757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                /* We're tracing in this frame: record something. */
4077757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                if (self->tracing_arcs) {
4087757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    /* Tracing arcs: key is (last_line,this_line). */
4097757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    if (CTracer_record_pair(self, self->last_line, frame->f_lineno) < 0) {
4107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                        return RET_ERROR;
4117757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    }
4127757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                }
4137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                else {
4147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    /* Tracing lines: key is simply this_line. */
4157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    PyObject * this_line = MyInt_FromLong(frame->f_lineno);
4167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    if (this_line == NULL) {
4177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                        STATS( self->stats.errors++; )
4187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                        return RET_ERROR;
4197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    }
4207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    ret = PyDict_SetItem(self->cur_file_data, this_line, Py_None);
4217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    Py_DECREF(this_line);
4227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    if (ret < 0) {
4237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                        STATS( self->stats.errors++; )
4247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                        return RET_ERROR;
4257757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                    }
4267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                }
4277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            }
4287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            self->last_line = frame->f_lineno;
4297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
4307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        break;
4317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
4327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    case PyTrace_EXCEPTION:
4337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        /* Some code (Python 2.3, and pyexpat anywhere) fires an exception event
4347757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch           without a return event.  To detect that, we'll keep a copy of the
4357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch           parent frame for an exception event.  If the next event is in that
4367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch           frame, then we must have returned without a return event.  We can
4377757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch           synthesize the missing event then.
4387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
4397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch           Python itself fixed this problem in 2.4.  Pyexpat still has the bug.
4407757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch           I've reported the problem with pyexpat as http://bugs.python.org/issue6359 .
4417757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch           If it gets fixed, this code should still work properly.  Maybe some day
4427757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch           the bug will be fixed everywhere coverage.py is supported, and we can
4437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch           remove this missing-return detection.
4447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
4457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch           More about this fix: http://nedbatchelder.com/blog/200907/a_nasty_little_bug.html
4467757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        */
4477757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        STATS( self->stats.exceptions++; )
4487757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        self->last_exc_back = frame->f_back;
4497757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        self->last_exc_firstlineno = frame->f_code->co_firstlineno;
4507757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        break;
4517757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
4527757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    default:
4537757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        STATS( self->stats.others++; )
4547757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        break;
4557757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
4567757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
4577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    return RET_OK;
4587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch}
4597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
4607757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch/*
4617757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * Python has two ways to set the trace function: sys.settrace(fn), which
4627757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * takes a Python callable, and PyEval_SetTrace(func, obj), which takes
4637757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * a C function and a Python object.  The way these work together is that
4647757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * sys.settrace(pyfn) calls PyEval_SetTrace(builtin_func, pyfn), using the
4657757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * Python callable as the object in PyEval_SetTrace.  So sys.gettrace()
4667757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * simply returns the Python object used as the second argument to
4677757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * PyEval_SetTrace.  So sys.gettrace() will return our self parameter, which
4687757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * means it must be callable to be used in sys.settrace().
4697757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch *
4707757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * So we make our self callable, equivalent to invoking our trace function.
4717757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch *
4727757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * To help with the process of replaying stored frames, this function has an
4737757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * optional keyword argument:
4747757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch *
4757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch *      def CTracer_call(frame, event, arg, lineno=0)
4767757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch *
4777757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * If provided, the lineno argument is used as the line number, and the
4787757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch * frame's f_lineno member is ignored.
4797757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch */
4807757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic PyObject *
4817757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochCTracer_call(CTracer *self, PyObject *args, PyObject *kwds)
4827757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch{
4837757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyFrameObject *frame;
4847757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject *what_str;
4857757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject *arg;
4867757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    int lineno = 0;
4877757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    int what;
4887757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    int orig_lineno;
4897757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject *ret = NULL;
4907757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
4917757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    static char *what_names[] = {
4927757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "call", "exception", "line", "return",
4937757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "c_call", "c_exception", "c_return",
4947757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        NULL
4957757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        };
4967757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
4977757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    #if WHAT_LOG
4987757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    printf("pytrace\n");
4997757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    #endif
5007757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5017757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    static char *kwlist[] = {"frame", "event", "arg", "lineno", NULL};
5027757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5037757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!O|i:Tracer_call", kwlist,
5047757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            &PyFrame_Type, &frame, &MyText_Type, &what_str, &arg, &lineno)) {
5057757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        goto done;
5067757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
5077757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5087757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /* In Python, the what argument is a string, we need to find an int
5097757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch       for the C function. */
5107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    for (what = 0; what_names[what]; what++) {
5117757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (!strcmp(MyText_AS_STRING(what_str), what_names[what])) {
5127757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            break;
5137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
5147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
5157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /* Save off the frame's lineno, and use the forced one, if provided. */
5177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    orig_lineno = frame->f_lineno;
5187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (lineno > 0) {
5197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        frame->f_lineno = lineno;
5207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
5217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /* Invoke the C function, and return ourselves. */
5237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (CTracer_trace(self, frame, what, arg) == RET_OK) {
5247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        Py_INCREF(self);
5257757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        ret = (PyObject *)self;
5267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
5277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /* Clean up. */
5297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    frame->f_lineno = orig_lineno;
5307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochdone:
5327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    return ret;
5337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch}
5347757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic PyObject *
5367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochCTracer_start(CTracer *self, PyObject *args_unused)
5377757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch{
5387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyEval_SetTrace((Py_tracefunc)CTracer_trace, (PyObject*)self);
5397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->started = 1;
5407757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->tracing_arcs = self->arcs && PyObject_IsTrue(self->arcs);
5417757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    self->last_line = -1;
5427757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    /* start() returns a trace function usable with sys.settrace() */
5447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    Py_INCREF(self);
5457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    return (PyObject *)self;
5467757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch}
5477757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5487757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic PyObject *
5497757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochCTracer_stop(CTracer *self, PyObject *args_unused)
5507757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch{
5517757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (self->started) {
5527757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        PyEval_SetTrace(NULL, NULL);
5537757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        self->started = 0;
5547757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
5557757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5567757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    return Py_BuildValue("");
5577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch}
5587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic PyObject *
5607757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochCTracer_get_stats(CTracer *self)
5617757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch{
5627757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#if COLLECT_STATS
5637757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    return Py_BuildValue(
5647757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "{sI,sI,sI,sI,sI,sI,sI,sI,si,sI}",
5657757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "calls", self->stats.calls,
5667757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "lines", self->stats.lines,
5677757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "returns", self->stats.returns,
5687757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "exceptions", self->stats.exceptions,
5697757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "others", self->stats.others,
5707757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "new_files", self->stats.new_files,
5717757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "missed_returns", self->stats.missed_returns,
5727757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "stack_reallocs", self->stats.stack_reallocs,
5737757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "stack_alloc", self->data_stack_alloc,
5747757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        "errors", self->stats.errors
5757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        );
5767757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#else
5777757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    return Py_BuildValue("");
5787757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#endif /* COLLECT_STATS */
5797757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch}
5807757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5817757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic PyMemberDef
5827757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochCTracer_members[] = {
5837757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    { "should_trace",       T_OBJECT, offsetof(CTracer, should_trace), 0,
5847757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            PyDoc_STR("Function indicating whether to trace a file.") },
5857757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5867757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    { "warn",               T_OBJECT, offsetof(CTracer, warn), 0,
5877757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            PyDoc_STR("Function for issuing warnings.") },
5887757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5897757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    { "data",               T_OBJECT, offsetof(CTracer, data), 0,
5907757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            PyDoc_STR("The raw dictionary of trace data.") },
5917757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5927757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    { "should_trace_cache", T_OBJECT, offsetof(CTracer, should_trace_cache), 0,
5937757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            PyDoc_STR("Dictionary caching should_trace results.") },
5947757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5957757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    { "arcs",               T_OBJECT, offsetof(CTracer, arcs), 0,
5967757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            PyDoc_STR("Should we trace arcs, or just lines?") },
5977757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5987757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    { NULL }
5997757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch};
6007757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6017757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic PyMethodDef
6027757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochCTracer_methods[] = {
6037757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    { "start",      (PyCFunction) CTracer_start,        METH_VARARGS,
6047757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            PyDoc_STR("Start the tracer") },
6057757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6067757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    { "stop",       (PyCFunction) CTracer_stop,         METH_VARARGS,
6077757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            PyDoc_STR("Stop the tracer") },
6087757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6097757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    { "get_stats",  (PyCFunction) CTracer_get_stats,    METH_VARARGS,
6107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            PyDoc_STR("Get statistics about the tracing") },
6117757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6127757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    { NULL }
6137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch};
6147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic PyTypeObject
6167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochCTracerType = {
6177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    MyType_HEAD_INIT
6187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    "coverage.CTracer",        /*tp_name*/
6197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    sizeof(CTracer),           /*tp_basicsize*/
6207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /*tp_itemsize*/
6217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    (destructor)CTracer_dealloc, /*tp_dealloc*/
6227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /*tp_print*/
6237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /*tp_getattr*/
6247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /*tp_setattr*/
6257757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /*tp_compare*/
6267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /*tp_repr*/
6277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /*tp_as_number*/
6287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /*tp_as_sequence*/
6297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /*tp_as_mapping*/
6307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /*tp_hash */
6317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    (ternaryfunc)CTracer_call, /*tp_call*/
6327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /*tp_str*/
6337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /*tp_getattro*/
6347757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /*tp_setattro*/
6357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /*tp_as_buffer*/
6367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
6377757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    "CTracer objects",         /* tp_doc */
6387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /* tp_traverse */
6397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /* tp_clear */
6407757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /* tp_richcompare */
6417757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /* tp_weaklistoffset */
6427757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /* tp_iter */
6437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /* tp_iternext */
6447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    CTracer_methods,           /* tp_methods */
6457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    CTracer_members,           /* tp_members */
6467757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /* tp_getset */
6477757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /* tp_base */
6487757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /* tp_dict */
6497757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /* tp_descr_get */
6507757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /* tp_descr_set */
6517757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /* tp_dictoffset */
6527757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    (initproc)CTracer_init,    /* tp_init */
6537757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /* tp_alloc */
6547757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    0,                         /* tp_new */
6557757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch};
6567757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch/* Module definition */
6587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#define MODULE_DOC PyDoc_STR("Fast coverage tracer.")
6607757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6617757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#if PY_MAJOR_VERSION >= 3
6627757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6637757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic PyModuleDef
6647757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochmoduledef = {
6657757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyModuleDef_HEAD_INIT,
6667757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    "coverage.tracer",
6677757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    MODULE_DOC,
6687757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    -1,
6697757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    NULL,       /* methods */
6707757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    NULL,
6717757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    NULL,       /* traverse */
6727757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    NULL,       /* clear */
6737757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    NULL
6747757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch};
6757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6767757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6777757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochPyObject *
6787757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochPyInit_tracer(void)
6797757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch{
6807757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject * mod = PyModule_Create(&moduledef);
6817757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (mod == NULL) {
6827757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        return NULL;
6837757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
6847757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6857757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    CTracerType.tp_new = PyType_GenericNew;
6867757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (PyType_Ready(&CTracerType) < 0) {
6877757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        Py_DECREF(mod);
6887757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        return NULL;
6897757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
6907757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6917757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    Py_INCREF(&CTracerType);
6927757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyModule_AddObject(mod, "CTracer", (PyObject *)&CTracerType);
6937757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6947757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    return mod;
6957757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch}
6967757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6977757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#else
6987757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
6997757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochvoid
7007757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochinittracer(void)
7017757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch{
7027757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyObject * mod;
7037757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
7047757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    mod = Py_InitModule3("coverage.tracer", NULL, MODULE_DOC);
7057757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (mod == NULL) {
7067757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        return;
7077757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
7087757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
7097757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    CTracerType.tp_new = PyType_GenericNew;
7107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (PyType_Ready(&CTracerType) < 0) {
7117757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        return;
7127757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    }
7137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
7147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    Py_INCREF(&CTracerType);
7157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    PyModule_AddObject(mod, "CTracer", (PyObject *)&CTracerType);
7167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch}
7177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
7187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#endif /* Py3k */
7197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
720