LCOV - code coverage report
Current view: top level - libreoffice/workdir/unxlngi6.pro/UnpackedTarball/python3/Python - traceback.c (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 33 335 9.9 %
Date: 2012-12-17 Functions: 4 20 20.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : 
       2             : /* Traceback implementation */
       3             : 
       4             : #include "Python.h"
       5             : 
       6             : #include "code.h"
       7             : #include "frameobject.h"
       8             : #include "structmember.h"
       9             : #include "osdefs.h"
      10             : #ifdef HAVE_FCNTL_H
      11             : #include <fcntl.h>
      12             : #endif
      13             : 
      14             : #define OFF(x) offsetof(PyTracebackObject, x)
      15             : 
      16             : #define PUTS(fd, str) write(fd, str, strlen(str))
      17             : #define MAX_STRING_LENGTH 500
      18             : #define MAX_FRAME_DEPTH 100
      19             : #define MAX_NTHREADS 100
      20             : 
      21             : /* Function from Parser/tokenizer.c */
      22             : extern char * PyTokenizer_FindEncodingFilename(int, PyObject *);
      23             : 
      24             : static PyObject *
      25           0 : tb_dir(PyTracebackObject *self)
      26             : {
      27           0 :     return Py_BuildValue("[ssss]", "tb_frame", "tb_next",
      28             :                                    "tb_lasti", "tb_lineno");
      29             : }
      30             : 
      31             : static PyMethodDef tb_methods[] = {
      32             :    {"__dir__", (PyCFunction)tb_dir, METH_NOARGS},
      33             :    {NULL, NULL, 0, NULL},
      34             : };
      35             : 
      36             : static PyMemberDef tb_memberlist[] = {
      37             :     {"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 */
      42             : };
      43             : 
      44             : static void
      45        1272 : tb_dealloc(PyTracebackObject *tb)
      46             : {
      47        1272 :     PyObject_GC_UnTrack(tb);
      48        1272 :     Py_TRASHCAN_SAFE_BEGIN(tb)
      49        1272 :     Py_XDECREF(tb->tb_next);
      50        1272 :     Py_XDECREF(tb->tb_frame);
      51        1272 :     PyObject_GC_Del(tb);
      52        1272 :     Py_TRASHCAN_SAFE_END(tb)
      53        1272 : }
      54             : 
      55             : static int
      56           4 : tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg)
      57             : {
      58           4 :     Py_VISIT(tb->tb_next);
      59           4 :     Py_VISIT(tb->tb_frame);
      60           4 :     return 0;
      61             : }
      62             : 
      63             : static void
      64           0 : tb_clear(PyTracebackObject *tb)
      65             : {
      66           0 :     Py_CLEAR(tb->tb_next);
      67           0 :     Py_CLEAR(tb->tb_frame);
      68           0 : }
      69             : 
      70             : PyTypeObject PyTraceBack_Type = {
      71             :     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 */
     103             : };
     104             : 
     105             : static PyTracebackObject *
     106        1272 : newtracebackobject(PyTracebackObject *next, PyFrameObject *frame)
     107             : {
     108             :     PyTracebackObject *tb;
     109        1272 :     if ((next != NULL && !PyTraceBack_Check(next)) ||
     110        1272 :                     frame == NULL || !PyFrame_Check(frame)) {
     111           0 :         PyErr_BadInternalCall();
     112           0 :         return NULL;
     113             :     }
     114        1272 :     tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type);
     115        1272 :     if (tb != NULL) {
     116        1272 :         Py_XINCREF(next);
     117        1272 :         tb->tb_next = next;
     118        1272 :         Py_XINCREF(frame);
     119        1272 :         tb->tb_frame = frame;
     120        1272 :         tb->tb_lasti = frame->f_lasti;
     121        1272 :         tb->tb_lineno = PyFrame_GetLineNumber(frame);
     122        1272 :         PyObject_GC_Track(tb);
     123             :     }
     124        1272 :     return tb;
     125             : }
     126             : 
     127             : int
     128        1272 : PyTraceBack_Here(PyFrameObject *frame)
     129             : {
     130        1272 :     PyThreadState *tstate = PyThreadState_GET();
     131        1272 :     PyTracebackObject *oldtb = (PyTracebackObject *) tstate->curexc_traceback;
     132        1272 :     PyTracebackObject *tb = newtracebackobject(oldtb, frame);
     133        1272 :     if (tb == NULL)
     134           0 :         return -1;
     135        1272 :     tstate->curexc_traceback = (PyObject *)tb;
     136        1272 :     Py_XDECREF(oldtb);
     137        1272 :     return 0;
     138             : }
     139             : 
     140             : static PyObject *
     141           0 : _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject *io)
     142             : {
     143             :     Py_ssize_t i;
     144             :     PyObject *binary;
     145             :     PyObject *v;
     146             :     Py_ssize_t npath;
     147             :     size_t taillen;
     148             :     PyObject *syspath;
     149             :     PyObject *path;
     150             :     const char* tail;
     151             :     PyObject *filebytes;
     152             :     const char* filepath;
     153             :     Py_ssize_t len;
     154             :     PyObject* result;
     155             :     _Py_IDENTIFIER(open);
     156             : 
     157           0 :     filebytes = PyUnicode_EncodeFSDefault(filename);
     158           0 :     if (filebytes == NULL) {
     159           0 :         PyErr_Clear();
     160           0 :         return NULL;
     161             :     }
     162           0 :     filepath = PyBytes_AS_STRING(filebytes);
     163             : 
     164             :     /* Search tail of filename in sys.path before giving up */
     165           0 :     tail = strrchr(filepath, SEP);
     166           0 :     if (tail == NULL)
     167           0 :         tail = filepath;
     168             :     else
     169           0 :         tail++;
     170           0 :     taillen = strlen(tail);
     171             : 
     172           0 :     syspath = PySys_GetObject("path");
     173           0 :     if (syspath == NULL || !PyList_Check(syspath))
     174             :         goto error;
     175           0 :     npath = PyList_Size(syspath);
     176             : 
     177           0 :     for (i = 0; i < npath; i++) {
     178           0 :         v = PyList_GetItem(syspath, i);
     179           0 :         if (v == NULL) {
     180           0 :             PyErr_Clear();
     181           0 :             break;
     182             :         }
     183           0 :         if (!PyUnicode_Check(v))
     184           0 :             continue;
     185           0 :         path = PyUnicode_EncodeFSDefault(v);
     186           0 :         if (path == NULL) {
     187           0 :             PyErr_Clear();
     188           0 :             continue;
     189             :         }
     190           0 :         len = PyBytes_GET_SIZE(path);
     191           0 :         if (len + 1 + (Py_ssize_t)taillen >= (Py_ssize_t)namelen - 1) {
     192           0 :             Py_DECREF(path);
     193           0 :             continue; /* Too long */
     194             :         }
     195           0 :         strcpy(namebuf, PyBytes_AS_STRING(path));
     196           0 :         Py_DECREF(path);
     197           0 :         if (strlen(namebuf) != len)
     198           0 :             continue; /* v contains '\0' */
     199           0 :         if (len > 0 && namebuf[len-1] != SEP)
     200           0 :             namebuf[len++] = SEP;
     201           0 :         strcpy(namebuf+len, tail);
     202             : 
     203           0 :         binary = _PyObject_CallMethodId(io, &PyId_open, "ss", namebuf, "rb");
     204           0 :         if (binary != NULL) {
     205           0 :             result = binary;
     206           0 :             goto finally;
     207             :         }
     208           0 :         PyErr_Clear();
     209             :     }
     210           0 :     goto error;
     211             : 
     212             : error:
     213           0 :     result = NULL;
     214             : finally:
     215           0 :     Py_DECREF(filebytes);
     216           0 :     return result;
     217             : }
     218             : 
     219             : int
     220           0 : _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent)
     221             : {
     222           0 :     int err = 0;
     223             :     int fd;
     224             :     int i;
     225             :     char *found_encoding;
     226             :     char *encoding;
     227             :     PyObject *io;
     228             :     PyObject *binary;
     229           0 :     PyObject *fob = NULL;
     230           0 :     PyObject *lineobj = NULL;
     231             :     PyObject *res;
     232             :     char buf[MAXPATHLEN+1];
     233             :     int kind;
     234             :     void *data;
     235             :     _Py_IDENTIFIER(close);
     236             :     _Py_IDENTIFIER(open);
     237             :     _Py_IDENTIFIER(TextIOWrapper);
     238             : 
     239             :     /* open the file */
     240           0 :     if (filename == NULL)
     241           0 :         return 0;
     242             : 
     243           0 :     io = PyImport_ImportModuleNoBlock("io");
     244           0 :     if (io == NULL)
     245           0 :         return -1;
     246           0 :     binary = _PyObject_CallMethodId(io, &PyId_open, "Os", filename, "rb");
     247             : 
     248           0 :     if (binary == NULL) {
     249           0 :         binary = _Py_FindSourceFile(filename, buf, sizeof(buf), io);
     250           0 :         if (binary == NULL) {
     251           0 :             Py_DECREF(io);
     252           0 :             return 0;
     253             :         }
     254             :     }
     255             : 
     256             :     /* use the right encoding to decode the file as unicode */
     257           0 :     fd = PyObject_AsFileDescriptor(binary);
     258           0 :     found_encoding = PyTokenizer_FindEncodingFilename(fd, filename);
     259           0 :     encoding = (found_encoding != NULL) ? found_encoding : "utf-8";
     260           0 :     lseek(fd, 0, 0); /* Reset position */
     261           0 :     fob = _PyObject_CallMethodId(io, &PyId_TextIOWrapper, "Os", binary, encoding);
     262           0 :     Py_DECREF(io);
     263           0 :     Py_DECREF(binary);
     264           0 :     PyMem_FREE(found_encoding);
     265             : 
     266           0 :     if (fob == NULL) {
     267           0 :         PyErr_Clear();
     268           0 :         return 0;
     269             :     }
     270             : 
     271             :     /* get the line number lineno */
     272           0 :     for (i = 0; i < lineno; i++) {
     273           0 :         Py_XDECREF(lineobj);
     274           0 :         lineobj = PyFile_GetLine(fob, -1);
     275           0 :         if (!lineobj) {
     276           0 :             err = -1;
     277           0 :             break;
     278             :         }
     279             :     }
     280           0 :     res = _PyObject_CallMethodId(fob, &PyId_close, "");
     281           0 :     if (res)
     282           0 :         Py_DECREF(res);
     283             :     else
     284           0 :         PyErr_Clear();
     285           0 :     Py_DECREF(fob);
     286           0 :     if (!lineobj || !PyUnicode_Check(lineobj)) {
     287           0 :         Py_XDECREF(lineobj);
     288           0 :         return err;
     289             :     }
     290             : 
     291             :     /* remove the indentation of the line */
     292           0 :     kind = PyUnicode_KIND(lineobj);
     293           0 :     data = PyUnicode_DATA(lineobj);
     294           0 :     for (i=0; i < PyUnicode_GET_LENGTH(lineobj); i++) {
     295           0 :         Py_UCS4 ch = PyUnicode_READ(kind, data, i);
     296           0 :         if (ch != ' ' && ch != '\t' && ch != '\014')
     297           0 :             break;
     298             :     }
     299           0 :     if (i) {
     300             :         PyObject *truncated;
     301           0 :         truncated = PyUnicode_Substring(lineobj, i, PyUnicode_GET_LENGTH(lineobj));
     302           0 :         if (truncated) {
     303           0 :             Py_DECREF(lineobj);
     304           0 :             lineobj = truncated;
     305             :         } else {
     306           0 :             PyErr_Clear();
     307             :         }
     308             :     }
     309             : 
     310             :     /* Write some spaces before the line */
     311           0 :     strcpy(buf, "          ");
     312             :     assert (strlen(buf) == 10);
     313           0 :     while (indent > 0) {
     314           0 :         if(indent < 10)
     315           0 :             buf[indent] = '\0';
     316           0 :         err = PyFile_WriteString(buf, f);
     317           0 :         if (err != 0)
     318           0 :             break;
     319           0 :         indent -= 10;
     320             :     }
     321             : 
     322             :     /* finally display the line */
     323           0 :     if (err == 0)
     324           0 :         err = PyFile_WriteObject(lineobj, f, Py_PRINT_RAW);
     325           0 :     Py_DECREF(lineobj);
     326           0 :     if  (err == 0)
     327           0 :         err = PyFile_WriteString("\n", f);
     328           0 :     return err;
     329             : }
     330             : 
     331             : static int
     332           0 : tb_displayline(PyObject *f, PyObject *filename, int lineno, PyObject *name)
     333             : {
     334             :     int err;
     335             :     PyObject *line;
     336             : 
     337           0 :     if (filename == NULL || name == NULL)
     338           0 :         return -1;
     339           0 :     line = PyUnicode_FromFormat("  File \"%U\", line %d, in %U\n",
     340             :                                 filename, lineno, name);
     341           0 :     if (line == NULL)
     342           0 :         return -1;
     343           0 :     err = PyFile_WriteObject(line, f, Py_PRINT_RAW);
     344           0 :     Py_DECREF(line);
     345           0 :     if (err != 0)
     346           0 :         return err;
     347             :     /* ignore errors since we can't report them, can we? */
     348           0 :     if (_Py_DisplaySourceLine(f, filename, lineno, 4))
     349           0 :         PyErr_Clear();
     350           0 :     return err;
     351             : }
     352             : 
     353             : static int
     354           0 : tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
     355             : {
     356           0 :     int err = 0;
     357           0 :     long depth = 0;
     358           0 :     PyTracebackObject *tb1 = tb;
     359           0 :     while (tb1 != NULL) {
     360           0 :         depth++;
     361           0 :         tb1 = tb1->tb_next;
     362             :     }
     363           0 :     while (tb != NULL && err == 0) {
     364           0 :         if (depth <= limit) {
     365           0 :             err = tb_displayline(f,
     366           0 :                                  tb->tb_frame->f_code->co_filename,
     367             :                                  tb->tb_lineno,
     368           0 :                                  tb->tb_frame->f_code->co_name);
     369             :         }
     370           0 :         depth--;
     371           0 :         tb = tb->tb_next;
     372           0 :         if (err == 0)
     373           0 :             err = PyErr_CheckSignals();
     374             :     }
     375           0 :     return err;
     376             : }
     377             : 
     378             : #define PyTraceBack_LIMIT 1000
     379             : 
     380             : int
     381           0 : PyTraceBack_Print(PyObject *v, PyObject *f)
     382             : {
     383             :     int err;
     384             :     PyObject *limitv;
     385           0 :     long limit = PyTraceBack_LIMIT;
     386             : 
     387           0 :     if (v == NULL)
     388           0 :         return 0;
     389           0 :     if (!PyTraceBack_Check(v)) {
     390           0 :         PyErr_BadInternalCall();
     391           0 :         return -1;
     392             :     }
     393           0 :     limitv = PySys_GetObject("tracebacklimit");
     394           0 :     if (limitv) {
     395             :         PyObject *exc_type, *exc_value, *exc_tb;
     396             : 
     397           0 :         PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
     398           0 :         limit = PyLong_AsLong(limitv);
     399           0 :         if (limit == -1 && PyErr_Occurred()) {
     400           0 :             if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
     401           0 :                 limit = PyTraceBack_LIMIT;
     402             :             }
     403             :             else {
     404           0 :                 Py_XDECREF(exc_type);
     405           0 :                 Py_XDECREF(exc_value);
     406           0 :                 Py_XDECREF(exc_tb);
     407           0 :                 return 0;
     408             :             }
     409             :         }
     410           0 :         else if (limit <= 0) {
     411           0 :             limit = PyTraceBack_LIMIT;
     412             :         }
     413           0 :         PyErr_Restore(exc_type, exc_value, exc_tb);
     414             :     }
     415           0 :     err = PyFile_WriteString("Traceback (most recent call last):\n", f);
     416           0 :     if (!err)
     417           0 :         err = tb_printinternal((PyTracebackObject *)v, f, limit);
     418           0 :     return err;
     419             : }
     420             : 
     421             : /* Reverse a string. For example, "abcd" becomes "dcba".
     422             : 
     423             :    This function is signal safe. */
     424             : 
     425             : static void
     426           0 : reverse_string(char *text, const size_t len)
     427             : {
     428             :     char tmp;
     429             :     size_t i, j;
     430           0 :     if (len == 0)
     431           0 :         return;
     432           0 :     for (i=0, j=len-1; i < j; i++, j--) {
     433           0 :         tmp = text[i];
     434           0 :         text[i] = text[j];
     435           0 :         text[j] = tmp;
     436             :     }
     437             : }
     438             : 
     439             : /* Format an integer in range [0; 999999] to decimal,
     440             :    and write it into the file fd.
     441             : 
     442             :    This function is signal safe. */
     443             : 
     444             : static void
     445           0 : dump_decimal(int fd, int value)
     446             : {
     447             :     char buffer[7];
     448             :     int len;
     449           0 :     if (value < 0 || 999999 < value)
     450           0 :         return;
     451           0 :     len = 0;
     452             :     do {
     453           0 :         buffer[len] = '0' + (value % 10);
     454           0 :         value /= 10;
     455           0 :         len++;
     456           0 :     } while (value);
     457           0 :     reverse_string(buffer, len);
     458           0 :     write(fd, buffer, len);
     459             : }
     460             : 
     461             : /* Format an integer in range [0; 0xffffffff] to hexdecimal of 'width' digits,
     462             :    and write it into the file fd.
     463             : 
     464             :    This function is signal safe. */
     465             : 
     466             : static void
     467           0 : dump_hexadecimal(int width, unsigned long value, int fd)
     468             : {
     469             :     int len;
     470             :     char buffer[sizeof(unsigned long) * 2 + 1];
     471           0 :     len = 0;
     472             :     do {
     473           0 :         buffer[len] = Py_hexdigits[value & 15];
     474           0 :         value >>= 4;
     475           0 :         len++;
     476           0 :     } while (len < width || value);
     477           0 :     reverse_string(buffer, len);
     478           0 :     write(fd, buffer, len);
     479           0 : }
     480             : 
     481             : /* Write an unicode object into the file fd using ascii+backslashreplace.
     482             : 
     483             :    This function is signal safe. */
     484             : 
     485             : static void
     486           0 : dump_ascii(int fd, PyObject *text)
     487             : {
     488           0 :     PyASCIIObject *ascii = (PyASCIIObject *)text;
     489             :     Py_ssize_t i, size;
     490             :     int truncated;
     491             :     int kind;
     492           0 :     void *data = NULL;
     493           0 :     wchar_t *wstr = NULL;
     494             :     Py_UCS4 ch;
     495             : 
     496           0 :     size = ascii->length;
     497           0 :     kind = ascii->state.kind;
     498           0 :     if (ascii->state.compact) {
     499           0 :         if (ascii->state.ascii)
     500           0 :             data = ((PyASCIIObject*)text) + 1;
     501             :         else
     502           0 :             data = ((PyCompactUnicodeObject*)text) + 1;
     503             :     }
     504           0 :     else if (kind != PyUnicode_WCHAR_KIND) {
     505           0 :         data = ((PyUnicodeObject *)text)->data.any;
     506           0 :         if (data == NULL)
     507           0 :             return;
     508             :     }
     509             :     else {
     510           0 :         wstr = ((PyASCIIObject *)text)->wstr;
     511           0 :         if (wstr == NULL)
     512           0 :             return;
     513           0 :         size = ((PyCompactUnicodeObject *)text)->wstr_length;
     514             :     }
     515             : 
     516           0 :     if (MAX_STRING_LENGTH < size) {
     517           0 :         size = MAX_STRING_LENGTH;
     518           0 :         truncated = 1;
     519             :     }
     520             :     else
     521           0 :         truncated = 0;
     522             : 
     523           0 :     for (i=0; i < size; i++) {
     524           0 :         if (kind != PyUnicode_WCHAR_KIND)
     525           0 :             ch = PyUnicode_READ(kind, data, i);
     526             :         else
     527           0 :             ch = wstr[i];
     528           0 :         if (ch < 128) {
     529           0 :             char c = (char)ch;
     530           0 :             write(fd, &c, 1);
     531             :         }
     532           0 :         else if (ch < 0xff) {
     533           0 :             PUTS(fd, "\\x");
     534           0 :             dump_hexadecimal(2, ch, fd);
     535             :         }
     536           0 :         else if (ch < 0xffff) {
     537           0 :             PUTS(fd, "\\u");
     538           0 :             dump_hexadecimal(4, ch, fd);
     539             :         }
     540             :         else {
     541           0 :             PUTS(fd, "\\U");
     542           0 :             dump_hexadecimal(8, ch, fd);
     543             :         }
     544             :     }
     545           0 :     if (truncated)
     546           0 :         PUTS(fd, "...");
     547             : }
     548             : 
     549             : /* Write a frame into the file fd: "File "xxx", line xxx in xxx".
     550             : 
     551             :    This function is signal safe. */
     552             : 
     553             : static void
     554           0 : dump_frame(int fd, PyFrameObject *frame)
     555             : {
     556             :     PyCodeObject *code;
     557             :     int lineno;
     558             : 
     559           0 :     code = frame->f_code;
     560           0 :     PUTS(fd, "  File ");
     561           0 :     if (code != NULL && code->co_filename != NULL
     562           0 :         && PyUnicode_Check(code->co_filename))
     563             :     {
     564           0 :         write(fd, "\"", 1);
     565           0 :         dump_ascii(fd, code->co_filename);
     566           0 :         write(fd, "\"", 1);
     567             :     } else {
     568           0 :         PUTS(fd, "???");
     569             :     }
     570             : 
     571             :     /* PyFrame_GetLineNumber() was introduced in Python 2.7.0 and 3.2.0 */
     572           0 :     lineno = PyCode_Addr2Line(code, frame->f_lasti);
     573           0 :     PUTS(fd, ", line ");
     574           0 :     dump_decimal(fd, lineno);
     575           0 :     PUTS(fd, " in ");
     576             : 
     577           0 :     if (code != NULL && code->co_name != NULL
     578           0 :         && PyUnicode_Check(code->co_name))
     579           0 :         dump_ascii(fd, code->co_name);
     580             :     else
     581           0 :         PUTS(fd, "???");
     582             : 
     583           0 :     write(fd, "\n", 1);
     584           0 : }
     585             : 
     586             : static void
     587           0 : dump_traceback(int fd, PyThreadState *tstate, int write_header)
     588             : {
     589             :     PyFrameObject *frame;
     590             :     unsigned int depth;
     591             : 
     592           0 :     if (write_header)
     593           0 :         PUTS(fd, "Traceback (most recent call first):\n");
     594             : 
     595           0 :     frame = _PyThreadState_GetFrame(tstate);
     596           0 :     if (frame == NULL)
     597           0 :         return;
     598             : 
     599           0 :     depth = 0;
     600           0 :     while (frame != NULL) {
     601           0 :         if (MAX_FRAME_DEPTH <= depth) {
     602           0 :             PUTS(fd, "  ...\n");
     603           0 :             break;
     604             :         }
     605           0 :         if (!PyFrame_Check(frame))
     606           0 :             break;
     607           0 :         dump_frame(fd, frame);
     608           0 :         frame = frame->f_back;
     609           0 :         depth++;
     610             :     }
     611             : }
     612             : 
     613             : void
     614           0 : _Py_DumpTraceback(int fd, PyThreadState *tstate)
     615             : {
     616           0 :     dump_traceback(fd, tstate, 1);
     617           0 : }
     618             : 
     619             : /* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
     620             :    is_current is true, "Thread 0xHHHH:\n" otherwise.
     621             : 
     622             :    This function is signal safe. */
     623             : 
     624             : static void
     625           0 : write_thread_id(int fd, PyThreadState *tstate, int is_current)
     626             : {
     627           0 :     if (is_current)
     628           0 :         PUTS(fd, "Current thread 0x");
     629             :     else
     630           0 :         PUTS(fd, "Thread 0x");
     631           0 :     dump_hexadecimal(sizeof(long)*2, (unsigned long)tstate->thread_id, fd);
     632           0 :     PUTS(fd, ":\n");
     633           0 : }
     634             : 
     635             : const char*
     636           0 : _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
     637             :                          PyThreadState *current_thread)
     638             : {
     639             :     PyThreadState *tstate;
     640             :     unsigned int nthreads;
     641             : 
     642             :     /* Get the current interpreter from the current thread */
     643           0 :     tstate = PyInterpreterState_ThreadHead(interp);
     644           0 :     if (tstate == NULL)
     645           0 :         return "unable to get the thread head state";
     646             : 
     647             :     /* Dump the traceback of each thread */
     648           0 :     tstate = PyInterpreterState_ThreadHead(interp);
     649           0 :     nthreads = 0;
     650             :     do
     651             :     {
     652           0 :         if (nthreads != 0)
     653           0 :             write(fd, "\n", 1);
     654           0 :         if (nthreads >= MAX_NTHREADS) {
     655           0 :             PUTS(fd, "...\n");
     656           0 :             break;
     657             :         }
     658           0 :         write_thread_id(fd, tstate, tstate == current_thread);
     659           0 :         dump_traceback(fd, tstate, 0);
     660           0 :         tstate = PyThreadState_Next(tstate);
     661           0 :         nthreads++;
     662           0 :     } while (tstate != NULL);
     663             : 
     664           0 :     return NULL;
     665             : }
     666             : 

Generated by: LCOV version 1.10