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 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
57 sizeof(PyTracebackObject
),
59 (destructor
)tb_dealloc
, /*tp_dealloc*/
61 (getattrfunc
)tb_getattr
, /*tp_getattr*/
74 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
,/* tp_flags */
76 (traverseproc
)tb_traverse
, /* tp_traverse */
77 (inquiry
)tb_clear
, /* tp_clear */
78 0, /* tp_richcompare */
79 0, /* tp_weaklistoffset */
89 static PyTracebackObject
*
90 newtracebackobject(PyTracebackObject
*next
, PyFrameObject
*frame
)
92 PyTracebackObject
*tb
;
93 if ((next
!= NULL
&& !PyTraceBack_Check(next
)) ||
94 frame
== NULL
|| !PyFrame_Check(frame
)) {
95 PyErr_BadInternalCall();
98 tb
= PyObject_GC_New(PyTracebackObject
, &PyTraceBack_Type
);
103 tb
->tb_frame
= frame
;
104 tb
->tb_lasti
= frame
->f_lasti
;
105 tb
->tb_lineno
= PyCode_Addr2Line(frame
->f_code
,
107 PyObject_GC_Track(tb
);
113 PyTraceBack_Here(PyFrameObject
*frame
)
115 PyThreadState
*tstate
= PyThreadState_GET();
116 PyTracebackObject
*oldtb
= (PyTracebackObject
*) tstate
->curexc_traceback
;
117 PyTracebackObject
*tb
= newtracebackobject(oldtb
, frame
);
120 tstate
->curexc_traceback
= (PyObject
*)tb
;
126 Py_DisplaySourceLine(PyObject
*f
, const char *filename
, int lineno
)
132 char namebuf
[MAXPATHLEN
+1];
134 if (filename
== NULL
)
136 /* This is needed by Emacs' compile command */
137 #define FMT " File \"%.500s\", line %d, in %.500s\n"
138 xfp
= fopen(filename
, "r" PY_STDIOTEXTMODE
);
140 /* Search tail of filename in sys.path before giving up */
142 const char *tail
= strrchr(filename
, SEP
);
147 path
= PySys_GetObject("path");
148 if (path
!= NULL
&& PyList_Check(path
)) {
149 Py_ssize_t _npath
= PyList_Size(path
);
150 int npath
= Py_SAFE_DOWNCAST(_npath
, Py_ssize_t
, int);
151 size_t taillen
= strlen(tail
);
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
);
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(p
, f
);
204 if (err
== 0 && strchr(p
, '\n') == NULL
)
205 err
= PyFile_WriteString("\n", f
);
212 tb_displayline(PyObject
*f
, const char *filename
, int lineno
, const char *name
)
217 if (filename
== NULL
|| name
== NULL
)
219 /* This is needed by Emacs' compile command */
220 #define FMT " File \"%.500s\", line %d, in %.500s\n"
221 PyOS_snprintf(linebuf
, sizeof(linebuf
), FMT
, filename
, lineno
, name
);
222 err
= PyFile_WriteString(linebuf
, f
);
225 return Py_DisplaySourceLine(f
, filename
, lineno
);
229 tb_printinternal(PyTracebackObject
*tb
, PyObject
*f
, long limit
)
233 PyTracebackObject
*tb1
= tb
;
234 while (tb1
!= NULL
) {
238 while (tb
!= NULL
&& err
== 0) {
239 if (depth
<= limit
) {
240 err
= tb_displayline(f
,
242 tb
->tb_frame
->f_code
->co_filename
),
244 PyString_AsString(tb
->tb_frame
->f_code
->co_name
));
249 err
= PyErr_CheckSignals();
255 PyTraceBack_Print(PyObject
*v
, PyObject
*f
)
262 if (!PyTraceBack_Check(v
)) {
263 PyErr_BadInternalCall();
266 limitv
= PySys_GetObject("tracebacklimit");
267 if (limitv
&& PyInt_Check(limitv
)) {
268 limit
= PyInt_AsLong(limitv
);
272 err
= PyFile_WriteString("Traceback (most recent call last):\n", f
);
274 err
= tb_printinternal((PyTracebackObject
*)v
, f
, limit
);