2 /* Traceback implementation */
7 #include "frameobject.h"
8 #include "structmember.h"
10 #include "traceback.h"
15 #define OFF(x) offsetof(PyTracebackObject, x)
17 /* Method from Parser/tokenizer.c */
18 extern char * PyTokenizer_FindEncoding(int);
21 tb_dir(PyTracebackObject
*self
)
23 return Py_BuildValue("[ssss]", "tb_frame", "tb_next",
24 "tb_lasti", "tb_lineno");
27 static PyMethodDef tb_methods
[] = {
28 {"__dir__", (PyCFunction
)tb_dir
, METH_NOARGS
},
29 {NULL
, NULL
, 0, NULL
},
32 static PyMemberDef tb_memberlist
[] = {
33 {"tb_next", T_OBJECT
, OFF(tb_next
), READONLY
},
34 {"tb_frame", T_OBJECT
, OFF(tb_frame
), READONLY
},
35 {"tb_lasti", T_INT
, OFF(tb_lasti
), READONLY
},
36 {"tb_lineno", T_INT
, OFF(tb_lineno
), READONLY
},
41 tb_dealloc(PyTracebackObject
*tb
)
43 PyObject_GC_UnTrack(tb
);
44 Py_TRASHCAN_SAFE_BEGIN(tb
)
45 Py_XDECREF(tb
->tb_next
);
46 Py_XDECREF(tb
->tb_frame
);
48 Py_TRASHCAN_SAFE_END(tb
)
52 tb_traverse(PyTracebackObject
*tb
, visitproc visit
, void *arg
)
54 Py_VISIT(tb
->tb_next
);
55 Py_VISIT(tb
->tb_frame
);
60 tb_clear(PyTracebackObject
*tb
)
62 Py_CLEAR(tb
->tb_next
);
63 Py_CLEAR(tb
->tb_frame
);
66 PyTypeObject PyTraceBack_Type
= {
67 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
69 sizeof(PyTracebackObject
),
71 (destructor
)tb_dealloc
, /*tp_dealloc*/
83 PyObject_GenericGetAttr
, /* tp_getattro */
86 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
,/* tp_flags */
88 (traverseproc
)tb_traverse
, /* tp_traverse */
89 (inquiry
)tb_clear
, /* tp_clear */
90 0, /* tp_richcompare */
91 0, /* tp_weaklistoffset */
94 tb_methods
, /* tp_methods */
95 tb_memberlist
, /* tp_members */
101 static PyTracebackObject
*
102 newtracebackobject(PyTracebackObject
*next
, PyFrameObject
*frame
)
104 PyTracebackObject
*tb
;
105 if ((next
!= NULL
&& !PyTraceBack_Check(next
)) ||
106 frame
== NULL
|| !PyFrame_Check(frame
)) {
107 PyErr_BadInternalCall();
110 tb
= PyObject_GC_New(PyTracebackObject
, &PyTraceBack_Type
);
115 tb
->tb_frame
= frame
;
116 tb
->tb_lasti
= frame
->f_lasti
;
117 tb
->tb_lineno
= PyCode_Addr2Line(frame
->f_code
,
119 PyObject_GC_Track(tb
);
125 PyTraceBack_Here(PyFrameObject
*frame
)
127 PyThreadState
*tstate
= PyThreadState_GET();
128 PyTracebackObject
*oldtb
= (PyTracebackObject
*) tstate
->curexc_traceback
;
129 PyTracebackObject
*tb
= newtracebackobject(oldtb
, frame
);
132 tstate
->curexc_traceback
= (PyObject
*)tb
;
138 _Py_FindSourceFile(const char* filename
, char* namebuf
, size_t namelen
, int open_flags
)
151 /* Search tail of filename in sys.path before giving up */
152 tail
= strrchr(filename
, SEP
);
157 taillen
= strlen(tail
);
159 syspath
= PySys_GetObject("path");
160 if (syspath
== NULL
|| !PyList_Check(syspath
))
162 _npath
= PyList_Size(syspath
);
163 npath
= Py_SAFE_DOWNCAST(_npath
, Py_ssize_t
, int);
165 for (i
= 0; i
< npath
; i
++) {
166 v
= PyList_GetItem(syspath
, i
);
171 if (!PyUnicode_Check(v
))
173 path
= _PyUnicode_AsStringAndSize(v
, &len
);
174 if (len
+ 1 + (Py_ssize_t
)taillen
>= (Py_ssize_t
)namelen
- 1)
175 continue; /* Too long */
176 strcpy(namebuf
, path
);
177 if (strlen(namebuf
) != len
)
178 continue; /* v contains '\0' */
179 if (len
> 0 && namebuf
[len
-1] != SEP
)
180 namebuf
[len
++] = SEP
;
181 strcpy(namebuf
+len
, tail
);
182 Py_BEGIN_ALLOW_THREADS
183 fd
= open(namebuf
, open_flags
);
193 _Py_DisplaySourceLine(PyObject
*f
, const char *filename
, int lineno
, int indent
)
198 char *found_encoding
;
200 PyObject
*fob
= NULL
;
201 PyObject
*lineobj
= NULL
;
203 const int open_flags
= O_RDONLY
| O_BINARY
; /* necessary for Windows */
205 const int open_flags
= O_RDONLY
;
207 char buf
[MAXPATHLEN
+1];
212 if (filename
== NULL
)
214 Py_BEGIN_ALLOW_THREADS
215 fd
= open(filename
, open_flags
);
218 fd
= _Py_FindSourceFile(filename
, buf
, sizeof(buf
), open_flags
);
224 /* use the right encoding to decode the file as unicode */
225 found_encoding
= PyTokenizer_FindEncoding(fd
);
226 encoding
= (found_encoding
!= NULL
) ? found_encoding
:
227 (char*)PyUnicode_GetDefaultEncoding();
228 lseek(fd
, 0, 0); /* Reset position */
229 fob
= PyFile_FromFd(fd
, (char*)filename
, "r", -1, (char*)encoding
,
231 PyMem_FREE(found_encoding
);
238 /* get the line number lineno */
239 for (i
= 0; i
< lineno
; i
++) {
241 lineobj
= PyFile_GetLine(fob
, -1);
248 if (!lineobj
|| !PyUnicode_Check(lineobj
)) {
253 /* remove the indentation of the line */
254 u
= PyUnicode_AS_UNICODE(lineobj
);
255 len
= PyUnicode_GET_SIZE(lineobj
);
256 for (p
=u
; *p
== ' ' || *p
== '\t' || *p
== '\014'; p
++)
260 truncated
= PyUnicode_FromUnicode(p
, len
);
269 /* Write some spaces before the line */
271 assert (strlen(buf
) == 10);
275 err
= PyFile_WriteString(buf
, f
);
281 /* finally display the line */
283 err
= PyFile_WriteObject(lineobj
, f
, Py_PRINT_RAW
);
286 err
= PyFile_WriteString("\n", f
);
291 tb_displayline(PyObject
*f
, const char *filename
, int lineno
, const char *name
)
296 if (filename
== NULL
|| name
== NULL
)
298 /* This is needed by Emacs' compile command */
299 #define FMT " File \"%.500s\", line %d, in %.500s\n"
300 PyOS_snprintf(linebuf
, sizeof(linebuf
), FMT
, filename
, lineno
, name
);
301 err
= PyFile_WriteString(linebuf
, f
);
304 return _Py_DisplaySourceLine(f
, filename
, lineno
, 4);
308 tb_printinternal(PyTracebackObject
*tb
, PyObject
*f
, long limit
)
312 PyTracebackObject
*tb1
= tb
;
313 while (tb1
!= NULL
) {
317 while (tb
!= NULL
&& err
== 0) {
318 if (depth
<= limit
) {
319 err
= tb_displayline(f
,
321 tb
->tb_frame
->f_code
->co_filename
),
323 _PyUnicode_AsString(tb
->tb_frame
->f_code
->co_name
));
328 err
= PyErr_CheckSignals();
333 #define PyTraceBack_LIMIT 1000
336 PyTraceBack_Print(PyObject
*v
, PyObject
*f
)
340 long limit
= PyTraceBack_LIMIT
;
344 if (!PyTraceBack_Check(v
)) {
345 PyErr_BadInternalCall();
348 limitv
= PySys_GetObject("tracebacklimit");
350 PyObject
*exc_type
, *exc_value
, *exc_tb
;
352 PyErr_Fetch(&exc_type
, &exc_value
, &exc_tb
);
353 limit
= PyLong_AsLong(limitv
);
354 if (limit
== -1 && PyErr_Occurred()) {
355 if (PyErr_ExceptionMatches(PyExc_OverflowError
)) {
356 limit
= PyTraceBack_LIMIT
;
359 Py_XDECREF(exc_type
);
360 Py_XDECREF(exc_value
);
365 else if (limit
<= 0) {
366 limit
= PyTraceBack_LIMIT
;
368 PyErr_Restore(exc_type
, exc_value
, exc_tb
);
370 err
= PyFile_WriteString("Traceback (most recent call last):\n", f
);
372 err
= tb_printinternal((PyTracebackObject
*)v
, f
, limit
);