2 /* Traceback implementation */
7 #include "frameobject.h"
8 #include "structmember.h"
10 #include "traceback.h"
12 #define OFF(x) offsetof(PyTracebackObject, x)
14 static struct memberlist tb_memberlist
[] = {
15 {"tb_next", T_OBJECT
, OFF(tb_next
)},
16 {"tb_frame", T_OBJECT
, OFF(tb_frame
)},
17 {"tb_lasti", T_INT
, OFF(tb_lasti
)},
18 {"tb_lineno", T_INT
, OFF(tb_lineno
)},
23 tb_getattr(PyTracebackObject
*tb
, char *name
)
25 return PyMember_Get((char *)tb
, tb_memberlist
, name
);
29 tb_dealloc(PyTracebackObject
*tb
)
31 PyObject_GC_UnTrack(tb
);
32 Py_TRASHCAN_SAFE_BEGIN(tb
)
33 Py_XDECREF(tb
->tb_next
);
34 Py_XDECREF(tb
->tb_frame
);
36 Py_TRASHCAN_SAFE_END(tb
)
40 tb_traverse(PyTracebackObject
*tb
, visitproc visit
, void *arg
)
42 Py_VISIT(tb
->tb_next
);
43 Py_VISIT(tb
->tb_frame
);
48 tb_clear(PyTracebackObject
*tb
)
50 Py_CLEAR(tb
->tb_next
);
51 Py_CLEAR(tb
->tb_frame
);
54 PyTypeObject PyTraceBack_Type
= {
55 PyObject_HEAD_INIT(&PyType_Type
)
58 sizeof(PyTracebackObject
),
60 (destructor
)tb_dealloc
, /*tp_dealloc*/
62 (getattrfunc
)tb_getattr
, /*tp_getattr*/
75 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
,/* tp_flags */
77 (traverseproc
)tb_traverse
, /* tp_traverse */
78 (inquiry
)tb_clear
, /* tp_clear */
79 0, /* tp_richcompare */
80 0, /* tp_weaklistoffset */
90 static PyTracebackObject
*
91 newtracebackobject(PyTracebackObject
*next
, PyFrameObject
*frame
)
93 PyTracebackObject
*tb
;
94 if ((next
!= NULL
&& !PyTraceBack_Check(next
)) ||
95 frame
== NULL
|| !PyFrame_Check(frame
)) {
96 PyErr_BadInternalCall();
99 tb
= PyObject_GC_New(PyTracebackObject
, &PyTraceBack_Type
);
104 tb
->tb_frame
= frame
;
105 tb
->tb_lasti
= frame
->f_lasti
;
106 tb
->tb_lineno
= PyCode_Addr2Line(frame
->f_code
,
108 PyObject_GC_Track(tb
);
114 PyTraceBack_Here(PyFrameObject
*frame
)
116 PyThreadState
*tstate
= frame
->f_tstate
;
117 PyTracebackObject
*oldtb
= (PyTracebackObject
*) tstate
->curexc_traceback
;
118 PyTracebackObject
*tb
= newtracebackobject(oldtb
, frame
);
121 tstate
->curexc_traceback
= (PyObject
*)tb
;
127 tb_displayline(PyObject
*f
, char *filename
, int lineno
, char *name
)
133 if (filename
== NULL
|| name
== NULL
)
135 /* This is needed by Emacs' compile command */
136 #define FMT " File \"%.500s\", line %d, in %.500s\n"
137 xfp
= fopen(filename
, "r" PY_STDIOTEXTMODE
);
139 /* Search tail of filename in sys.path before giving up */
141 char *tail
= strrchr(filename
, SEP
);
146 path
= PySys_GetObject("path");
147 if (path
!= NULL
&& PyList_Check(path
)) {
148 Py_ssize_t _npath
= PyList_Size(path
);
149 int npath
= Py_SAFE_DOWNCAST(_npath
, Py_ssize_t
, int);
150 size_t taillen
= strlen(tail
);
151 char namebuf
[MAXPATHLEN
+1];
152 for (i
= 0; i
< npath
; i
++) {
153 PyObject
*v
= PyList_GetItem(path
, i
);
158 if (PyString_Check(v
)) {
160 len
= PyString_GET_SIZE(v
);
161 if (len
+ 1 + taillen
>= MAXPATHLEN
)
162 continue; /* Too long */
163 strcpy(namebuf
, PyString_AsString(v
));
164 if (strlen(namebuf
) != len
)
165 continue; /* v contains '\0' */
166 if (len
> 0 && namebuf
[len
-1] != SEP
)
167 namebuf
[len
++] = SEP
;
168 strcpy(namebuf
+len
, tail
);
169 xfp
= fopen(namebuf
, "r" PY_STDIOTEXTMODE
);
178 PyOS_snprintf(linebuf
, sizeof(linebuf
), FMT
, filename
, lineno
, name
);
179 err
= PyFile_WriteString(linebuf
, f
);
186 for (i
= 0; i
< lineno
; i
++) {
187 char* pLastChar
= &linebuf
[sizeof(linebuf
)-2];
190 if (Py_UniversalNewlineFgets(linebuf
, sizeof linebuf
, xfp
, NULL
) == NULL
)
192 /* fgets read *something*; if it didn't get as
193 far as pLastChar, it must have found a newline
194 or hit the end of the file; if pLastChar is \n,
195 it obviously found a newline; else we haven't
196 yet seen a newline, so must continue */
197 } while (*pLastChar
!= '\0' && *pLastChar
!= '\n');
201 while (*p
== ' ' || *p
== '\t' || *p
== '\014')
203 err
= PyFile_WriteString(" ", f
);
205 err
= PyFile_WriteString(p
, f
);
206 if (err
== 0 && strchr(p
, '\n') == NULL
)
207 err
= PyFile_WriteString("\n", f
);
215 tb_printinternal(PyTracebackObject
*tb
, PyObject
*f
, int limit
)
219 PyTracebackObject
*tb1
= tb
;
220 while (tb1
!= NULL
) {
224 while (tb
!= NULL
&& err
== 0) {
225 if (depth
<= limit
) {
226 err
= tb_displayline(f
,
228 tb
->tb_frame
->f_code
->co_filename
),
230 PyString_AsString(tb
->tb_frame
->f_code
->co_name
));
235 err
= PyErr_CheckSignals();
241 PyTraceBack_Print(PyObject
*v
, PyObject
*f
)
248 if (!PyTraceBack_Check(v
)) {
249 PyErr_BadInternalCall();
252 limitv
= PySys_GetObject("tracebacklimit");
253 if (limitv
&& PyInt_Check(limitv
)) {
254 limit
= PyInt_AsLong(limitv
);
258 err
= PyFile_WriteString("Traceback (most recent call last):\n", f
);
260 err
= tb_printinternal((PyTracebackObject
*)v
, f
, limit
);