traceback.c 5.54 KB
Newer Older
1

Guido van Rossum's avatar
Guido van Rossum committed
2 3
/* Traceback implementation */

Guido van Rossum's avatar
Guido van Rossum committed
4
#include "Python.h"
Guido van Rossum's avatar
Guido van Rossum committed
5 6 7 8

#include "compile.h"
#include "frameobject.h"
#include "structmember.h"
9
#include "osdefs.h"
Guido van Rossum's avatar
Guido van Rossum committed
10 11

typedef struct _tracebackobject {
Guido van Rossum's avatar
Guido van Rossum committed
12
	PyObject_HEAD
Guido van Rossum's avatar
Guido van Rossum committed
13
	struct _tracebackobject *tb_next;
Guido van Rossum's avatar
Guido van Rossum committed
14
	PyFrameObject *tb_frame;
Guido van Rossum's avatar
Guido van Rossum committed
15 16 17 18 19 20 21 22 23 24 25 26 27 28
	int tb_lasti;
	int tb_lineno;
} tracebackobject;

#define OFF(x) offsetof(tracebackobject, x)

static struct memberlist tb_memberlist[] = {
	{"tb_next",	T_OBJECT,	OFF(tb_next)},
	{"tb_frame",	T_OBJECT,	OFF(tb_frame)},
	{"tb_lasti",	T_INT,		OFF(tb_lasti)},
	{"tb_lineno",	T_INT,		OFF(tb_lineno)},
	{NULL}	/* Sentinel */
};

Guido van Rossum's avatar
Guido van Rossum committed
29
static PyObject *
30
tb_getattr(tracebackobject *tb, char *name)
Guido van Rossum's avatar
Guido van Rossum committed
31
{
Guido van Rossum's avatar
Guido van Rossum committed
32
	return PyMember_Get((char *)tb, tb_memberlist, name);
Guido van Rossum's avatar
Guido van Rossum committed
33 34 35
}

static void
36
tb_dealloc(tracebackobject *tb)
Guido van Rossum's avatar
Guido van Rossum committed
37
{
38
	Py_TRASHCAN_SAFE_BEGIN(tb)
Guido van Rossum's avatar
Guido van Rossum committed
39 40
	Py_XDECREF(tb->tb_next);
	Py_XDECREF(tb->tb_frame);
41
	PyObject_DEL(tb);
42
	Py_TRASHCAN_SAFE_END(tb)
Guido van Rossum's avatar
Guido van Rossum committed
43 44
}

45 46
#define Tracebacktype PyTraceBack_Type
#define is_tracebackobject PyTraceBack_Check
47

Guido van Rossum's avatar
Guido van Rossum committed
48 49
PyTypeObject Tracebacktype = {
	PyObject_HEAD_INIT(&PyType_Type)
Guido van Rossum's avatar
Guido van Rossum committed
50 51 52 53
	0,
	"traceback",
	sizeof(tracebackobject),
	0,
54
	(destructor)tb_dealloc, /*tp_dealloc*/
Guido van Rossum's avatar
Guido van Rossum committed
55
	0,		/*tp_print*/
56
	(getattrfunc)tb_getattr, /*tp_getattr*/
Guido van Rossum's avatar
Guido van Rossum committed
57 58 59 60 61 62 63 64 65
	0,		/*tp_setattr*/
	0,		/*tp_compare*/
	0,		/*tp_repr*/
	0,		/*tp_as_number*/
	0,		/*tp_as_sequence*/
	0,		/*tp_as_mapping*/
};

static tracebackobject *
66 67
newtracebackobject(tracebackobject *next, PyFrameObject *frame, int lasti,
		   int lineno)
Guido van Rossum's avatar
Guido van Rossum committed
68 69 70
{
	tracebackobject *tb;
	if ((next != NULL && !is_tracebackobject(next)) ||
Guido van Rossum's avatar
Guido van Rossum committed
71 72
			frame == NULL || !PyFrame_Check(frame)) {
		PyErr_BadInternalCall();
Guido van Rossum's avatar
Guido van Rossum committed
73 74
		return NULL;
	}
Guido van Rossum's avatar
Guido van Rossum committed
75
	tb = PyObject_NEW(tracebackobject, &Tracebacktype);
Guido van Rossum's avatar
Guido van Rossum committed
76
	if (tb != NULL) {
Guido van Rossum's avatar
Guido van Rossum committed
77
		Py_XINCREF(next);
Guido van Rossum's avatar
Guido van Rossum committed
78
		tb->tb_next = next;
Guido van Rossum's avatar
Guido van Rossum committed
79
		Py_XINCREF(frame);
Guido van Rossum's avatar
Guido van Rossum committed
80 81 82 83 84 85 86 87
		tb->tb_frame = frame;
		tb->tb_lasti = lasti;
		tb->tb_lineno = lineno;
	}
	return tb;
}

int
88
PyTraceBack_Here(PyFrameObject *frame)
Guido van Rossum's avatar
Guido van Rossum committed
89
{
90 91 92 93
	PyThreadState *tstate = frame->f_tstate;
	tracebackobject *oldtb = (tracebackobject *) tstate->curexc_traceback;
	tracebackobject *tb = newtracebackobject(oldtb,
				frame, frame->f_lasti, frame->f_lineno);
Guido van Rossum's avatar
Guido van Rossum committed
94 95
	if (tb == NULL)
		return -1;
96 97
	tstate->curexc_traceback = (PyObject *)tb;
	Py_XDECREF(oldtb);
Guido van Rossum's avatar
Guido van Rossum committed
98 99 100
	return 0;
}

101
static int
102
tb_displayline(PyObject *f, char *filename, int lineno, char *name)
Guido van Rossum's avatar
Guido van Rossum committed
103
{
104
	int err = 0;
Guido van Rossum's avatar
Guido van Rossum committed
105
	FILE *xfp;
106
	char linebuf[1000];
Guido van Rossum's avatar
Guido van Rossum committed
107
	int i;
108 109
	if (filename == NULL || name == NULL)
		return -1;
110 111 112 113 114 115 116
#ifdef MPW
	/* This is needed by MPW's File and Line commands */
#define FMT "  File \"%.900s\"; line %d # in %s\n"
#else
	/* This is needed by Emacs' compile command */
#define FMT "  File \"%.900s\", line %d, in %s\n"
#endif
Guido van Rossum's avatar
Guido van Rossum committed
117 118
	xfp = fopen(filename, "r");
	if (xfp == NULL) {
119
		/* Search tail of filename in sys.path before giving up */
Guido van Rossum's avatar
Guido van Rossum committed
120
		PyObject *path;
121 122 123 124 125
		char *tail = strrchr(filename, SEP);
		if (tail == NULL)
			tail = filename;
		else
			tail++;
Guido van Rossum's avatar
Guido van Rossum committed
126 127 128
		path = PySys_GetObject("path");
		if (path != NULL && PyList_Check(path)) {
			int npath = PyList_Size(path);
129
			size_t taillen = strlen(tail);
130 131
			char namebuf[MAXPATHLEN+1];
			for (i = 0; i < npath; i++) {
Guido van Rossum's avatar
Guido van Rossum committed
132
				PyObject *v = PyList_GetItem(path, i);
133 134 135 136
				if (v == NULL) {
					PyErr_Clear();
					break;
				}
Guido van Rossum's avatar
Guido van Rossum committed
137
				if (PyString_Check(v)) {
138
					size_t len;
Guido van Rossum's avatar
Guido van Rossum committed
139
					len = PyString_Size(v);
140 141
					if (len + 1 + taillen >= MAXPATHLEN)
						continue; /* Too long */
Guido van Rossum's avatar
Guido van Rossum committed
142
					strcpy(namebuf, PyString_AsString(v));
143
					if (strlen(namebuf) != len)
144
						continue; /* v contains '\0' */
145 146 147 148 149 150 151 152 153 154 155
					if (len > 0 && namebuf[len-1] != SEP)
						namebuf[len++] = SEP;
					strcpy(namebuf+len, tail);
					xfp = fopen(namebuf, "r");
					if (xfp != NULL) {
						filename = namebuf;
						break;
					}
				}
			}
		}
Guido van Rossum's avatar
Guido van Rossum committed
156
	}
157
	sprintf(linebuf, FMT, filename, lineno, name);
158 159 160
	err = PyFile_WriteString(linebuf, f);
	if (xfp == NULL || err != 0)
		return err;
Guido van Rossum's avatar
Guido van Rossum committed
161
	for (i = 0; i < lineno; i++) {
162 163 164 165 166 167 168 169 170 171 172
		char* pLastChar = &linebuf[sizeof(linebuf)-2];
		do {
			*pLastChar = '\0';
			if (fgets(linebuf, sizeof linebuf, xfp) == NULL)
				break;
			/* fgets read *something*; if it didn't get as
			   far as pLastChar, it must have found a newline
			   or hit the end of the file;	if pLastChar is \n,
			   it obviously found a newline; else we haven't
			   yet seen a newline, so must continue */
		} while (*pLastChar != '\0' && *pLastChar != '\n');
Guido van Rossum's avatar
Guido van Rossum committed
173 174
	}
	if (i == lineno) {
175
		char *p = linebuf;
176
		while (*p == ' ' || *p == '\t' || *p == '\014')
Guido van Rossum's avatar
Guido van Rossum committed
177
			p++;
178 179 180 181 182 183
		err = PyFile_WriteString("    ", f);
		if (err == 0) {
			err = PyFile_WriteString(p, f);
			if (err == 0 && strchr(p, '\n') == NULL)
				err = PyFile_WriteString("\n", f);
		}
Guido van Rossum's avatar
Guido van Rossum committed
184 185
	}
	fclose(xfp);
186
	return err;
Guido van Rossum's avatar
Guido van Rossum committed
187 188
}

189
static int
190
tb_printinternal(tracebackobject *tb, PyObject *f, int limit)
Guido van Rossum's avatar
Guido van Rossum committed
191
{
192
	int err = 0;
193 194 195 196 197 198
	int depth = 0;
	tracebackobject *tb1 = tb;
	while (tb1 != NULL) {
		depth++;
		tb1 = tb1->tb_next;
	}
199
	while (tb != NULL && err == 0) {
200
		if (depth <= limit) {
201 202 203
			if (Py_OptimizeFlag)
				tb->tb_lineno = PyCode_Addr2Line(
					tb->tb_frame->f_code, tb->tb_lasti);
204
			err = tb_displayline(f,
Guido van Rossum's avatar
Guido van Rossum committed
205 206
			    PyString_AsString(
				    tb->tb_frame->f_code->co_filename),
207
			    tb->tb_lineno,
Guido van Rossum's avatar
Guido van Rossum committed
208
			    PyString_AsString(tb->tb_frame->f_code->co_name));
209
		}
210
		depth--;
Guido van Rossum's avatar
Guido van Rossum committed
211
		tb = tb->tb_next;
212 213
		if (err == 0)
			err = PyErr_CheckSignals();
Guido van Rossum's avatar
Guido van Rossum committed
214
	}
215
	return err;
Guido van Rossum's avatar
Guido van Rossum committed
216 217 218
}

int
219
PyTraceBack_Print(PyObject *v, PyObject *f)
Guido van Rossum's avatar
Guido van Rossum committed
220
{
221
	int err;
Guido van Rossum's avatar
Guido van Rossum committed
222
	PyObject *limitv;
223
	int limit = 1000;
Guido van Rossum's avatar
Guido van Rossum committed
224 225 226
	if (v == NULL)
		return 0;
	if (!is_tracebackobject(v)) {
Guido van Rossum's avatar
Guido van Rossum committed
227
		PyErr_BadInternalCall();
Guido van Rossum's avatar
Guido van Rossum committed
228 229
		return -1;
	}
Guido van Rossum's avatar
Guido van Rossum committed
230 231 232
	limitv = PySys_GetObject("tracebacklimit");
	if (limitv && PyInt_Check(limitv)) {
		limit = PyInt_AsLong(limitv);
233 234 235
		if (limit <= 0)
			return 0;
	}
236
	err = PyFile_WriteString("Traceback (most recent call last):\n", f);
237 238 239
	if (!err)
		err = tb_printinternal((tracebackobject *)v, f, limit);
	return err;
Guido van Rossum's avatar
Guido van Rossum committed
240
}