2 /* Traceback implementation */
7 #include "frameobject.h"
8 #include "structmember.h"
10 #include "traceback.h"
12 #define OFF(x) offsetof(PyTracebackObject, x)
14 static PyMemberDef tb_memberlist
[] = {
15 {"tb_next", T_OBJECT
, OFF(tb_next
), READONLY
},
16 {"tb_frame", T_OBJECT
, OFF(tb_frame
), READONLY
},
17 {"tb_lasti", T_INT
, OFF(tb_lasti
), READONLY
},
18 {"tb_lineno", T_INT
, OFF(tb_lineno
), READONLY
},
23 tb_dealloc(PyTracebackObject
*tb
)
25 PyObject_GC_UnTrack(tb
);
26 Py_TRASHCAN_SAFE_BEGIN(tb
)
27 Py_XDECREF(tb
->tb_next
);
28 Py_XDECREF(tb
->tb_frame
);
30 Py_TRASHCAN_SAFE_END(tb
)
34 tb_traverse(PyTracebackObject
*tb
, visitproc visit
, void *arg
)
36 Py_VISIT(tb
->tb_next
);
37 Py_VISIT(tb
->tb_frame
);
42 tb_clear(PyTracebackObject
*tb
)
44 Py_CLEAR(tb
->tb_next
);
45 Py_CLEAR(tb
->tb_frame
);
48 PyTypeObject PyTraceBack_Type
= {
49 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
51 sizeof(PyTracebackObject
),
53 (destructor
)tb_dealloc
, /*tp_dealloc*/
68 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
,/* tp_flags */
70 (traverseproc
)tb_traverse
, /* tp_traverse */
71 (inquiry
)tb_clear
, /* tp_clear */
72 0, /* tp_richcompare */
73 0, /* tp_weaklistoffset */
77 tb_memberlist
, /* tp_members */
83 static PyTracebackObject
*
84 newtracebackobject(PyTracebackObject
*next
, PyFrameObject
*frame
)
86 PyTracebackObject
*tb
;
87 if ((next
!= NULL
&& !PyTraceBack_Check(next
)) ||
88 frame
== NULL
|| !PyFrame_Check(frame
)) {
89 PyErr_BadInternalCall();
92 tb
= PyObject_GC_New(PyTracebackObject
, &PyTraceBack_Type
);
98 tb
->tb_lasti
= frame
->f_lasti
;
99 tb
->tb_lineno
= PyFrame_GetLineNumber(frame
);
100 PyObject_GC_Track(tb
);
106 PyTraceBack_Here(PyFrameObject
*frame
)
108 PyThreadState
*tstate
= PyThreadState_GET();
109 PyTracebackObject
*oldtb
= (PyTracebackObject
*) tstate
->curexc_traceback
;
110 PyTracebackObject
*tb
= newtracebackobject(oldtb
, frame
);
113 tstate
->curexc_traceback
= (PyObject
*)tb
;
119 _Py_DisplaySourceLine(PyObject
*f
, const char *filename
, int lineno
, int indent
)
125 char namebuf
[MAXPATHLEN
+1];
127 if (filename
== NULL
)
129 /* This is needed by Emacs' compile command */
130 #define FMT " File \"%.500s\", line %d, in %.500s\n"
131 xfp
= fopen(filename
, "r" PY_STDIOTEXTMODE
);
133 /* Search tail of filename in sys.path before giving up */
135 const char *tail
= strrchr(filename
, SEP
);
140 path
= PySys_GetObject("path");
141 if (path
!= NULL
&& PyList_Check(path
)) {
142 Py_ssize_t _npath
= PyList_Size(path
);
143 int npath
= Py_SAFE_DOWNCAST(_npath
, Py_ssize_t
, int);
144 size_t taillen
= strlen(tail
);
145 for (i
= 0; i
< npath
; i
++) {
146 PyObject
*v
= PyList_GetItem(path
, i
);
151 if (PyString_Check(v
)) {
153 len
= PyString_GET_SIZE(v
);
154 if (len
+ 1 + taillen
>= MAXPATHLEN
)
155 continue; /* Too long */
156 strcpy(namebuf
, PyString_AsString(v
));
157 if (strlen(namebuf
) != len
)
158 continue; /* v contains '\0' */
159 if (len
> 0 && namebuf
[len
-1] != SEP
)
160 namebuf
[len
++] = SEP
;
161 strcpy(namebuf
+len
, tail
);
162 xfp
= fopen(namebuf
, "r" PY_STDIOTEXTMODE
);
179 for (i
= 0; i
< lineno
; i
++) {
180 char* pLastChar
= &linebuf
[sizeof(linebuf
)-2];
183 if (Py_UniversalNewlineFgets(linebuf
, sizeof linebuf
, xfp
, NULL
) == NULL
)
185 /* fgets read *something*; if it didn't get as
186 far as pLastChar, it must have found a newline
187 or hit the end of the file; if pLastChar is \n,
188 it obviously found a newline; else we haven't
189 yet seen a newline, so must continue */
190 } while (*pLastChar
!= '\0' && *pLastChar
!= '\n');
195 while (*p
== ' ' || *p
== '\t' || *p
== '\014')
198 /* Write some spaces before the line */
200 assert (strlen(buf
) == 10);
204 err
= PyFile_WriteString(buf
, f
);
211 err
= PyFile_WriteString(p
, f
);
212 if (err
== 0 && strchr(p
, '\n') == NULL
)
213 err
= PyFile_WriteString("\n", f
);
220 tb_displayline(PyObject
*f
, const char *filename
, int lineno
, const char *name
)
225 if (filename
== NULL
|| name
== NULL
)
227 /* This is needed by Emacs' compile command */
228 #define FMT " File \"%.500s\", line %d, in %.500s\n"
229 PyOS_snprintf(linebuf
, sizeof(linebuf
), FMT
, filename
, lineno
, name
);
230 err
= PyFile_WriteString(linebuf
, f
);
233 return _Py_DisplaySourceLine(f
, filename
, lineno
, 4);
237 tb_printinternal(PyTracebackObject
*tb
, PyObject
*f
, long limit
)
241 PyTracebackObject
*tb1
= tb
;
242 while (tb1
!= NULL
) {
246 while (tb
!= NULL
&& err
== 0) {
247 if (depth
<= limit
) {
248 err
= tb_displayline(f
,
250 tb
->tb_frame
->f_code
->co_filename
),
252 PyString_AsString(tb
->tb_frame
->f_code
->co_name
));
257 err
= PyErr_CheckSignals();
263 PyTraceBack_Print(PyObject
*v
, PyObject
*f
)
270 if (!PyTraceBack_Check(v
)) {
271 PyErr_BadInternalCall();
274 limitv
= PySys_GetObject("tracebacklimit");
275 if (limitv
&& PyInt_Check(limitv
)) {
276 limit
= PyInt_AsLong(limitv
);
280 err
= PyFile_WriteString("Traceback (most recent call last):\n", f
);
282 err
= tb_printinternal((PyTracebackObject
*)v
, f
, limit
);