blob: 37673d93e04c81e79d47d61c2ae2e0e78e7b5e7f [file] [log] [blame]
Guido van Rossumf70e43a1991-02-19 12:39:46 +00001
Guido van Rossum3f5da241990-12-20 15:06:42 +00002/* Traceback implementation */
3
Guido van Rossum65bf9f21997-04-29 18:33:38 +00004#include "Python.h"
Guido van Rossum3f5da241990-12-20 15:06:42 +00005
Jeremy Hylton3e0055f2005-10-20 19:59:25 +00006#include "code.h"
Guido van Rossum3f5da241990-12-20 15:06:42 +00007#include "frameobject.h"
Guido van Rossum3f5da241990-12-20 15:06:42 +00008#include "structmember.h"
Guido van Rossum7169dbb1992-02-26 15:17:59 +00009#include "osdefs.h"
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +000010#ifdef HAVE_FCNTL_H
11#include <fcntl.h>
12#endif
Guido van Rossum3f5da241990-12-20 15:06:42 +000013
Nicholas Bastina7604bf2004-03-21 18:37:23 +000014#define OFF(x) offsetof(PyTracebackObject, x)
Guido van Rossum3f5da241990-12-20 15:06:42 +000015
Victor Stinner024e37a2011-03-31 01:31:06 +020016#define PUTS(fd, str) write(fd, str, strlen(str))
17#define MAX_STRING_LENGTH 100
18#define MAX_FRAME_DEPTH 100
19#define MAX_NTHREADS 100
20
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +000021/* Method from Parser/tokenizer.c */
22extern char * PyTokenizer_FindEncoding(int);
23
Collin Winter3eed7652007-08-14 17:53:54 +000024static PyObject *
25tb_dir(PyTracebackObject *self)
26{
27 return Py_BuildValue("[ssss]", "tb_frame", "tb_next",
28 "tb_lasti", "tb_lineno");
29}
30
31static PyMethodDef tb_methods[] = {
32 {"__dir__", (PyCFunction)tb_dir, METH_NOARGS},
33 {NULL, NULL, 0, NULL},
34};
35
Neal Norwitz8dfc4a92007-08-11 06:39:53 +000036static PyMemberDef tb_memberlist[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000037 {"tb_next", T_OBJECT, OFF(tb_next), READONLY},
38 {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY},
39 {"tb_lasti", T_INT, OFF(tb_lasti), READONLY},
40 {"tb_lineno", T_INT, OFF(tb_lineno), READONLY},
41 {NULL} /* Sentinel */
Guido van Rossum3f5da241990-12-20 15:06:42 +000042};
43
Guido van Rossum3f5da241990-12-20 15:06:42 +000044static void
Nicholas Bastina7604bf2004-03-21 18:37:23 +000045tb_dealloc(PyTracebackObject *tb)
Guido van Rossum3f5da241990-12-20 15:06:42 +000046{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000047 PyObject_GC_UnTrack(tb);
48 Py_TRASHCAN_SAFE_BEGIN(tb)
49 Py_XDECREF(tb->tb_next);
50 Py_XDECREF(tb->tb_frame);
51 PyObject_GC_Del(tb);
52 Py_TRASHCAN_SAFE_END(tb)
Guido van Rossum3f5da241990-12-20 15:06:42 +000053}
54
Jeremy Hyltonfd14d8e2001-10-22 22:17:41 +000055static int
Nicholas Bastina7604bf2004-03-21 18:37:23 +000056tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg)
Jeremy Hyltonfd14d8e2001-10-22 22:17:41 +000057{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000058 Py_VISIT(tb->tb_next);
59 Py_VISIT(tb->tb_frame);
60 return 0;
Jeremy Hyltonfd14d8e2001-10-22 22:17:41 +000061}
62
63static void
Nicholas Bastina7604bf2004-03-21 18:37:23 +000064tb_clear(PyTracebackObject *tb)
Jeremy Hyltonfd14d8e2001-10-22 22:17:41 +000065{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000066 Py_CLEAR(tb->tb_next);
67 Py_CLEAR(tb->tb_frame);
Jeremy Hyltonfd14d8e2001-10-22 22:17:41 +000068}
69
Tim Petersd7c36522001-10-22 19:34:09 +000070PyTypeObject PyTraceBack_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000071 PyVarObject_HEAD_INIT(&PyType_Type, 0)
72 "traceback",
73 sizeof(PyTracebackObject),
74 0,
75 (destructor)tb_dealloc, /*tp_dealloc*/
76 0, /*tp_print*/
77 0, /*tp_getattr*/
78 0, /*tp_setattr*/
79 0, /*tp_reserved*/
80 0, /*tp_repr*/
81 0, /*tp_as_number*/
82 0, /*tp_as_sequence*/
83 0, /*tp_as_mapping*/
84 0, /* tp_hash */
85 0, /* tp_call */
86 0, /* tp_str */
87 PyObject_GenericGetAttr, /* tp_getattro */
88 0, /* tp_setattro */
89 0, /* tp_as_buffer */
90 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
91 0, /* tp_doc */
92 (traverseproc)tb_traverse, /* tp_traverse */
93 (inquiry)tb_clear, /* tp_clear */
94 0, /* tp_richcompare */
95 0, /* tp_weaklistoffset */
96 0, /* tp_iter */
97 0, /* tp_iternext */
98 tb_methods, /* tp_methods */
99 tb_memberlist, /* tp_members */
100 0, /* tp_getset */
101 0, /* tp_base */
102 0, /* tp_dict */
Guido van Rossum3f5da241990-12-20 15:06:42 +0000103};
104
Nicholas Bastina7604bf2004-03-21 18:37:23 +0000105static PyTracebackObject *
106newtracebackobject(PyTracebackObject *next, PyFrameObject *frame)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000107{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000108 PyTracebackObject *tb;
109 if ((next != NULL && !PyTraceBack_Check(next)) ||
110 frame == NULL || !PyFrame_Check(frame)) {
111 PyErr_BadInternalCall();
112 return NULL;
113 }
114 tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type);
115 if (tb != NULL) {
116 Py_XINCREF(next);
117 tb->tb_next = next;
118 Py_XINCREF(frame);
119 tb->tb_frame = frame;
120 tb->tb_lasti = frame->f_lasti;
121 tb->tb_lineno = PyFrame_GetLineNumber(frame);
122 PyObject_GC_Track(tb);
123 }
124 return tb;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000125}
126
Guido van Rossum3f5da241990-12-20 15:06:42 +0000127int
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000128PyTraceBack_Here(PyFrameObject *frame)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000129{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000130 PyThreadState *tstate = PyThreadState_GET();
131 PyTracebackObject *oldtb = (PyTracebackObject *) tstate->curexc_traceback;
132 PyTracebackObject *tb = newtracebackobject(oldtb, frame);
133 if (tb == NULL)
134 return -1;
135 tstate->curexc_traceback = (PyObject *)tb;
136 Py_XDECREF(oldtb);
137 return 0;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000138}
139
Victor Stinner0fe25a42010-06-17 23:08:50 +0000140static PyObject *
141_Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject *io)
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000142{
Victor Stinner0fe25a42010-06-17 23:08:50 +0000143 Py_ssize_t i;
144 PyObject *binary;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000145 PyObject *v;
Victor Stinner0fe25a42010-06-17 23:08:50 +0000146 Py_ssize_t npath;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000147 size_t taillen;
148 PyObject *syspath;
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000149 PyObject *path;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000150 const char* tail;
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000151 PyObject *filebytes;
Victor Stinner0fe25a42010-06-17 23:08:50 +0000152 const char* filepath;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000153 Py_ssize_t len;
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000154 PyObject* result;
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000155
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000156 filebytes = PyUnicode_EncodeFSDefault(filename);
157 if (filebytes == NULL) {
Victor Stinner0fe25a42010-06-17 23:08:50 +0000158 PyErr_Clear();
159 return NULL;
160 }
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000161 filepath = PyBytes_AS_STRING(filebytes);
Victor Stinner0fe25a42010-06-17 23:08:50 +0000162
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000163 /* Search tail of filename in sys.path before giving up */
Victor Stinner0fe25a42010-06-17 23:08:50 +0000164 tail = strrchr(filepath, SEP);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000165 if (tail == NULL)
Victor Stinner0fe25a42010-06-17 23:08:50 +0000166 tail = filepath;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000167 else
168 tail++;
169 taillen = strlen(tail);
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000170
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000171 syspath = PySys_GetObject("path");
172 if (syspath == NULL || !PyList_Check(syspath))
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000173 goto error;
Victor Stinner0fe25a42010-06-17 23:08:50 +0000174 npath = PyList_Size(syspath);
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000175
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000176 for (i = 0; i < npath; i++) {
177 v = PyList_GetItem(syspath, i);
178 if (v == NULL) {
179 PyErr_Clear();
180 break;
181 }
182 if (!PyUnicode_Check(v))
183 continue;
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000184 path = PyUnicode_EncodeFSDefault(v);
Victor Stinner0fe25a42010-06-17 23:08:50 +0000185 if (path == NULL) {
186 PyErr_Clear();
187 continue;
188 }
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000189 len = PyBytes_GET_SIZE(path);
190 if (len + 1 + (Py_ssize_t)taillen >= (Py_ssize_t)namelen - 1) {
191 Py_DECREF(path);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000192 continue; /* Too long */
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000193 }
194 strcpy(namebuf, PyBytes_AS_STRING(path));
195 Py_DECREF(path);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000196 if (strlen(namebuf) != len)
197 continue; /* v contains '\0' */
198 if (len > 0 && namebuf[len-1] != SEP)
199 namebuf[len++] = SEP;
200 strcpy(namebuf+len, tail);
Victor Stinner0fe25a42010-06-17 23:08:50 +0000201
202 binary = PyObject_CallMethod(io, "open", "ss", namebuf, "rb");
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000203 if (binary != NULL) {
204 result = binary;
205 goto finally;
206 }
Victor Stinner0fe25a42010-06-17 23:08:50 +0000207 PyErr_Clear();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000208 }
Victor Stinner4c7c8c32010-10-16 13:14:10 +0000209 goto error;
210
211error:
212 result = NULL;
213finally:
214 Py_DECREF(filebytes);
215 return result;
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000216}
217
Christian Heimes33fe8092008-04-13 13:53:33 +0000218int
Victor Stinner0fe25a42010-06-17 23:08:50 +0000219_Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000220{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000221 int err = 0;
222 int fd;
223 int i;
224 char *found_encoding;
225 char *encoding;
Victor Stinner0fe25a42010-06-17 23:08:50 +0000226 PyObject *io;
227 PyObject *binary;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000228 PyObject *fob = NULL;
229 PyObject *lineobj = NULL;
Antoine Pitroub86680e2010-10-14 21:15:17 +0000230 PyObject *res;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000231 char buf[MAXPATHLEN+1];
232 Py_UNICODE *u, *p;
233 Py_ssize_t len;
Christian Heimes679db4a2008-01-18 09:56:22 +0000234
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000235 /* open the file */
236 if (filename == NULL)
237 return 0;
Victor Stinner0fe25a42010-06-17 23:08:50 +0000238
239 io = PyImport_ImportModuleNoBlock("io");
240 if (io == NULL)
241 return -1;
242 binary = PyObject_CallMethod(io, "open", "Os", filename, "rb");
243
244 if (binary == NULL) {
245 binary = _Py_FindSourceFile(filename, buf, sizeof(buf), io);
246 if (binary == NULL) {
247 Py_DECREF(io);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000248 return 0;
Victor Stinner0fe25a42010-06-17 23:08:50 +0000249 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000250 }
Christian Heimes33fe8092008-04-13 13:53:33 +0000251
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000252 /* use the right encoding to decode the file as unicode */
Victor Stinner0fe25a42010-06-17 23:08:50 +0000253 fd = PyObject_AsFileDescriptor(binary);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000254 found_encoding = PyTokenizer_FindEncoding(fd);
Victor Stinner0fe25a42010-06-17 23:08:50 +0000255 encoding = (found_encoding != NULL) ? found_encoding : "utf-8";
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000256 lseek(fd, 0, 0); /* Reset position */
Victor Stinner0fe25a42010-06-17 23:08:50 +0000257 fob = PyObject_CallMethod(io, "TextIOWrapper", "Os", binary, encoding);
258 Py_DECREF(io);
259 Py_DECREF(binary);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000260 PyMem_FREE(found_encoding);
Victor Stinner0fe25a42010-06-17 23:08:50 +0000261
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000262 if (fob == NULL) {
263 PyErr_Clear();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000264 return 0;
265 }
Christian Heimes33fe8092008-04-13 13:53:33 +0000266
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000267 /* get the line number lineno */
268 for (i = 0; i < lineno; i++) {
269 Py_XDECREF(lineobj);
270 lineobj = PyFile_GetLine(fob, -1);
271 if (!lineobj) {
272 err = -1;
273 break;
274 }
275 }
Antoine Pitroub86680e2010-10-14 21:15:17 +0000276 res = PyObject_CallMethod(fob, "close", "");
277 if (res)
278 Py_DECREF(res);
279 else
280 PyErr_Clear();
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000281 Py_DECREF(fob);
282 if (!lineobj || !PyUnicode_Check(lineobj)) {
283 Py_XDECREF(lineobj);
284 return err;
285 }
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000286
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000287 /* remove the indentation of the line */
288 u = PyUnicode_AS_UNICODE(lineobj);
289 len = PyUnicode_GET_SIZE(lineobj);
290 for (p=u; *p == ' ' || *p == '\t' || *p == '\014'; p++)
291 len--;
292 if (u != p) {
293 PyObject *truncated;
294 truncated = PyUnicode_FromUnicode(p, len);
295 if (truncated) {
296 Py_DECREF(lineobj);
297 lineobj = truncated;
298 } else {
299 PyErr_Clear();
300 }
301 }
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000302
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000303 /* Write some spaces before the line */
304 strcpy(buf, " ");
305 assert (strlen(buf) == 10);
306 while (indent > 0) {
307 if(indent < 10)
308 buf[indent] = '\0';
309 err = PyFile_WriteString(buf, f);
310 if (err != 0)
311 break;
312 indent -= 10;
313 }
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000314
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000315 /* finally display the line */
316 if (err == 0)
317 err = PyFile_WriteObject(lineobj, f, Py_PRINT_RAW);
318 Py_DECREF(lineobj);
319 if (err == 0)
320 err = PyFile_WriteString("\n", f);
321 return err;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000322}
323
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000324static int
Victor Stinner0fe25a42010-06-17 23:08:50 +0000325tb_displayline(PyObject *f, PyObject *filename, int lineno, PyObject *name)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000326{
Victor Stinner0fe25a42010-06-17 23:08:50 +0000327 int err;
328 PyObject *line;
Christian Heimes33fe8092008-04-13 13:53:33 +0000329
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000330 if (filename == NULL || name == NULL)
331 return -1;
Victor Stinner0fe25a42010-06-17 23:08:50 +0000332 line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U\n",
333 filename, lineno, name);
334 if (line == NULL)
335 return -1;
336 err = PyFile_WriteObject(line, f, Py_PRINT_RAW);
337 Py_DECREF(line);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000338 if (err != 0)
339 return err;
340 return _Py_DisplaySourceLine(f, filename, lineno, 4);
Christian Heimes33fe8092008-04-13 13:53:33 +0000341}
342
343static int
344tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
345{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000346 int err = 0;
347 long depth = 0;
348 PyTracebackObject *tb1 = tb;
349 while (tb1 != NULL) {
350 depth++;
351 tb1 = tb1->tb_next;
352 }
353 while (tb != NULL && err == 0) {
354 if (depth <= limit) {
355 err = tb_displayline(f,
Victor Stinner0fe25a42010-06-17 23:08:50 +0000356 tb->tb_frame->f_code->co_filename,
357 tb->tb_lineno,
358 tb->tb_frame->f_code->co_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000359 }
360 depth--;
361 tb = tb->tb_next;
362 if (err == 0)
363 err = PyErr_CheckSignals();
364 }
365 return err;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000366}
367
Christian Heimes0fbab7f2007-12-04 21:55:18 +0000368#define PyTraceBack_LIMIT 1000
369
Guido van Rossum3f5da241990-12-20 15:06:42 +0000370int
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000371PyTraceBack_Print(PyObject *v, PyObject *f)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000372{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000373 int err;
374 PyObject *limitv;
375 long limit = PyTraceBack_LIMIT;
Christian Heimes0fbab7f2007-12-04 21:55:18 +0000376
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000377 if (v == NULL)
378 return 0;
379 if (!PyTraceBack_Check(v)) {
380 PyErr_BadInternalCall();
381 return -1;
382 }
383 limitv = PySys_GetObject("tracebacklimit");
384 if (limitv) {
385 PyObject *exc_type, *exc_value, *exc_tb;
Christian Heimes0fbab7f2007-12-04 21:55:18 +0000386
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000387 PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
388 limit = PyLong_AsLong(limitv);
389 if (limit == -1 && PyErr_Occurred()) {
390 if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
391 limit = PyTraceBack_LIMIT;
392 }
393 else {
394 Py_XDECREF(exc_type);
395 Py_XDECREF(exc_value);
396 Py_XDECREF(exc_tb);
397 return 0;
398 }
399 }
400 else if (limit <= 0) {
401 limit = PyTraceBack_LIMIT;
402 }
403 PyErr_Restore(exc_type, exc_value, exc_tb);
404 }
405 err = PyFile_WriteString("Traceback (most recent call last):\n", f);
406 if (!err)
407 err = tb_printinternal((PyTracebackObject *)v, f, limit);
408 return err;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000409}
Victor Stinner024e37a2011-03-31 01:31:06 +0200410
411/* Reverse a string. For example, "abcd" becomes "dcba".
412
413 This function is signal safe. */
414
415static void
416reverse_string(char *text, const size_t len)
417{
418 char tmp;
419 size_t i, j;
420 if (len == 0)
421 return;
422 for (i=0, j=len-1; i < j; i++, j--) {
423 tmp = text[i];
424 text[i] = text[j];
425 text[j] = tmp;
426 }
427}
428
429/* Format an integer in range [0; 999999] to decimal,
430 and write it into the file fd.
431
432 This function is signal safe. */
433
434static void
435dump_decimal(int fd, int value)
436{
437 char buffer[7];
438 int len;
439 if (value < 0 || 999999 < value)
440 return;
441 len = 0;
442 do {
443 buffer[len] = '0' + (value % 10);
444 value /= 10;
445 len++;
446 } while (value);
447 reverse_string(buffer, len);
448 write(fd, buffer, len);
449}
450
451/* Format an integer in range [0; 0xffffffff] to hexdecimal of 'width' digits,
452 and write it into the file fd.
453
454 This function is signal safe. */
455
456static void
457dump_hexadecimal(int width, unsigned long value, int fd)
458{
459 const char *hexdigits = "0123456789abcdef";
460 int len;
461 char buffer[sizeof(unsigned long) * 2 + 1];
462 len = 0;
463 do {
464 buffer[len] = hexdigits[value & 15];
465 value >>= 4;
466 len++;
467 } while (len < width || value);
468 reverse_string(buffer, len);
469 write(fd, buffer, len);
470}
471
472/* Write an unicode object into the file fd using ascii+backslashreplace.
473
474 This function is signal safe. */
475
476static void
477dump_ascii(int fd, PyObject *text)
478{
479 Py_ssize_t i, size;
480 int truncated;
481 Py_UNICODE *u;
482 char c;
483
484 size = PyUnicode_GET_SIZE(text);
485 u = PyUnicode_AS_UNICODE(text);
486
487 if (MAX_STRING_LENGTH < size) {
488 size = MAX_STRING_LENGTH;
489 truncated = 1;
490 }
491 else
492 truncated = 0;
493
494 for (i=0; i < size; i++, u++) {
495 if (*u < 128) {
496 c = (char)*u;
497 write(fd, &c, 1);
498 }
499 else if (*u < 256) {
500 PUTS(fd, "\\x");
501 dump_hexadecimal(2, *u, fd);
502 }
503 else
504#ifdef Py_UNICODE_WIDE
505 if (*u < 65536)
506#endif
507 {
508 PUTS(fd, "\\u");
509 dump_hexadecimal(4, *u, fd);
510#ifdef Py_UNICODE_WIDE
511 }
512 else {
513 PUTS(fd, "\\U");
514 dump_hexadecimal(8, *u, fd);
515#endif
516 }
517 }
518 if (truncated)
519 PUTS(fd, "...");
520}
521
522/* Write a frame into the file fd: "File "xxx", line xxx in xxx".
523
524 This function is signal safe. */
525
526static void
527dump_frame(int fd, PyFrameObject *frame)
528{
529 PyCodeObject *code;
530 int lineno;
531
532 code = frame->f_code;
533 PUTS(fd, " File ");
534 if (code != NULL && code->co_filename != NULL
535 && PyUnicode_Check(code->co_filename))
536 {
537 write(fd, "\"", 1);
538 dump_ascii(fd, code->co_filename);
539 write(fd, "\"", 1);
540 } else {
541 PUTS(fd, "???");
542 }
543
544 /* PyFrame_GetLineNumber() was introduced in Python 2.7.0 and 3.2.0 */
545 lineno = PyCode_Addr2Line(frame->f_code, frame->f_lasti);
546 PUTS(fd, ", line ");
547 dump_decimal(fd, lineno);
548 PUTS(fd, " in ");
549
550 if (code != NULL && code->co_name != NULL
551 && PyUnicode_Check(code->co_name))
552 dump_ascii(fd, code->co_name);
553 else
554 PUTS(fd, "???");
555
556 write(fd, "\n", 1);
557}
558
559static int
560dump_traceback(int fd, PyThreadState *tstate, int write_header)
561{
562 PyFrameObject *frame;
563 unsigned int depth;
564
565 frame = _PyThreadState_GetFrame(tstate);
566 if (frame == NULL)
567 return -1;
568
569 if (write_header)
570 PUTS(fd, "Traceback (most recent call first):\n");
571 depth = 0;
572 while (frame != NULL) {
573 if (MAX_FRAME_DEPTH <= depth) {
574 PUTS(fd, " ...\n");
575 break;
576 }
577 if (!PyFrame_Check(frame))
578 break;
579 dump_frame(fd, frame);
580 frame = frame->f_back;
581 depth++;
582 }
583 return 0;
584}
585
586int
587_Py_DumpTraceback(int fd, PyThreadState *tstate)
588{
589 return dump_traceback(fd, tstate, 1);
590}
591
592/* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
593 is_current is true, "Thread 0xHHHH:\n" otherwise.
594
595 This function is signal safe. */
596
597static void
598write_thread_id(int fd, PyThreadState *tstate, int is_current)
599{
600 if (is_current)
601 PUTS(fd, "Current thread 0x");
602 else
603 PUTS(fd, "Thread 0x");
604 dump_hexadecimal(sizeof(long)*2, (unsigned long)tstate->thread_id, fd);
605 PUTS(fd, ":\n");
606}
607
608const char*
609_Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
610 PyThreadState *current_thread)
611{
612 PyThreadState *tstate;
613 unsigned int nthreads;
614
615 /* Get the current interpreter from the current thread */
616 tstate = PyInterpreterState_ThreadHead(interp);
617 if (tstate == NULL)
618 return "unable to get the thread head state";
619
620 /* Dump the traceback of each thread */
621 tstate = PyInterpreterState_ThreadHead(interp);
622 nthreads = 0;
623 do
624 {
625 if (nthreads != 0)
626 write(fd, "\n", 1);
627 if (nthreads >= MAX_NTHREADS) {
628 PUTS(fd, "...\n");
629 break;
630 }
631 write_thread_id(fd, tstate, tstate == current_thread);
632 dump_traceback(fd, tstate, 0);
633 tstate = PyThreadState_Next(tstate);
634 nthreads++;
635 } while (tstate != NULL);
636
637 return NULL;
638}
639