Coverage Report

Created: 2025-07-04 06:49

/src/cpython/Python/traceback.c
Line
Count
Source (jump to first uncovered line)
1
2
/* Traceback implementation */
3
4
#include "Python.h"
5
#include "pycore_call.h"          // _PyObject_CallMethodFormat()
6
#include "pycore_fileutils.h"     // _Py_BEGIN_SUPPRESS_IPH
7
#include "pycore_frame.h"         // PyFrameObject
8
#include "pycore_interp.h"        // PyInterpreterState.gc
9
#include "pycore_interpframe.h"   // _PyFrame_GetCode()
10
#include "pycore_pyerrors.h"      // _PyErr_GetRaisedException()
11
#include "pycore_pystate.h"       // _PyThreadState_GET()
12
#include "pycore_traceback.h"     // EXCEPTION_TB_HEADER
13
14
#include "frameobject.h"          // PyFrame_New()
15
16
#include "osdefs.h"               // SEP
17
#ifdef HAVE_UNISTD_H
18
#  include <unistd.h>             // lseek()
19
#endif
20
21
#if (defined(HAVE_EXECINFO_H) && defined(HAVE_DLFCN_H) && defined(HAVE_LINK_H))
22
#  define _PY_HAS_BACKTRACE_HEADERS 1
23
#endif
24
25
#if (defined(__APPLE__) && defined(HAVE_EXECINFO_H) && defined(HAVE_DLFCN_H))
26
#  define _PY_HAS_BACKTRACE_HEADERS 1
27
#endif
28
29
#ifdef _PY_HAS_BACKTRACE_HEADERS
30
#  include <execinfo.h>           // backtrace(), backtrace_symbols()
31
#  include <dlfcn.h>              // dladdr1()
32
#ifdef HAVE_LINK_H
33
#    include <link.h>               // struct DL_info
34
#endif
35
#  if defined(__APPLE__) && defined(HAVE_BACKTRACE) && defined(HAVE_DLADDR)
36
#    define CAN_C_BACKTRACE
37
#  elif defined(HAVE_BACKTRACE) && defined(HAVE_DLADDR1)
38
#    define CAN_C_BACKTRACE
39
#  endif
40
#endif
41
42
#if defined(__STDC_NO_VLA__) && (__STDC_NO_VLA__ == 1)
43
/* Use alloca() for VLAs. */
44
#  define VLA(type, name, size) type *name = alloca(size)
45
#elif !defined(__STDC_NO_VLA__) || (__STDC_NO_VLA__ == 0)
46
/* Use actual C VLAs.*/
47
0
#  define VLA(type, name, size) type name[size]
48
#elif defined(CAN_C_BACKTRACE)
49
/* VLAs are not possible. Disable C stack trace functions. */
50
#  undef CAN_C_BACKTRACE
51
#endif
52
53
#define OFF(x) offsetof(PyTracebackObject, x)
54
0
#define PUTS(fd, str) (void)_Py_write_noraise(fd, str, strlen(str))
55
56
0
#define MAX_STRING_LENGTH 500
57
0
#define MAX_FRAME_DEPTH 100
58
0
#define MAX_NTHREADS 100
59
60
/* Function from Parser/tokenizer/file_tokenizer.c */
61
extern char* _PyTokenizer_FindEncodingFilename(int, PyObject *);
62
63
/*[clinic input]
64
class traceback "PyTracebackObject *" "&PyTraceback_Type"
65
[clinic start generated code]*/
66
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=cf96294b2bebc811]*/
67
68
33.5M
#define _PyTracebackObject_CAST(op)   ((PyTracebackObject *)(op))
69
70
#include "clinic/traceback.c.h"
71
72
static PyObject *
73
tb_create_raw(PyTracebackObject *next, PyFrameObject *frame, int lasti,
74
              int lineno)
75
33.4M
{
76
33.4M
    PyTracebackObject *tb;
77
33.4M
    if ((next != NULL && !PyTraceBack_Check(next)) ||
78
33.4M
                    frame == NULL || !PyFrame_Check(frame)) {
79
0
        PyErr_BadInternalCall();
80
0
        return NULL;
81
0
    }
82
33.4M
    tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type);
83
33.4M
    if (tb != NULL) {
84
33.4M
        tb->tb_next = (PyTracebackObject*)Py_XNewRef(next);
85
33.4M
        tb->tb_frame = (PyFrameObject*)Py_XNewRef(frame);
86
33.4M
        tb->tb_lasti = lasti;
87
33.4M
        tb->tb_lineno = lineno;
88
33.4M
        PyObject_GC_Track(tb);
89
33.4M
    }
90
33.4M
    return (PyObject *)tb;
91
33.4M
}
92
93
/*[clinic input]
94
@classmethod
95
traceback.__new__ as tb_new
96
97
  tb_next: object
98
  tb_frame: object(type='PyFrameObject *', subclass_of='&PyFrame_Type')
99
  tb_lasti: int
100
  tb_lineno: int
101
102
Create a new traceback object.
103
[clinic start generated code]*/
104
105
static PyObject *
106
tb_new_impl(PyTypeObject *type, PyObject *tb_next, PyFrameObject *tb_frame,
107
            int tb_lasti, int tb_lineno)
108
/*[clinic end generated code: output=fa077debd72d861a input=b88143145454cb59]*/
109
0
{
110
0
    if (tb_next == Py_None) {
111
0
        tb_next = NULL;
112
0
    } else if (!PyTraceBack_Check(tb_next)) {
113
0
        return PyErr_Format(PyExc_TypeError,
114
0
                            "expected traceback object or None, got '%s'",
115
0
                            Py_TYPE(tb_next)->tp_name);
116
0
    }
117
118
0
    return tb_create_raw((PyTracebackObject *)tb_next, tb_frame, tb_lasti,
119
0
                         tb_lineno);
120
0
}
121
122
static PyObject *
123
tb_dir(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
124
0
{
125
0
    return Py_BuildValue("[ssss]", "tb_frame", "tb_next",
126
0
                                   "tb_lasti", "tb_lineno");
127
0
}
128
129
/*[clinic input]
130
@critical_section
131
@getter
132
traceback.tb_next
133
[clinic start generated code]*/
134
135
static PyObject *
136
traceback_tb_next_get_impl(PyTracebackObject *self)
137
/*[clinic end generated code: output=963634df7d5fc837 input=8f6345f2b73cb965]*/
138
0
{
139
0
    PyObject* ret = (PyObject*)self->tb_next;
140
0
    if (!ret) {
141
0
        ret = Py_None;
142
0
    }
143
0
    return Py_NewRef(ret);
144
0
}
145
146
static int
147
tb_get_lineno(PyObject *op)
148
0
{
149
0
    PyTracebackObject *tb = _PyTracebackObject_CAST(op);
150
0
    _PyInterpreterFrame* frame = tb->tb_frame->f_frame;
151
0
    assert(frame != NULL);
152
0
    return PyCode_Addr2Line(_PyFrame_GetCode(frame), tb->tb_lasti);
153
0
}
154
155
static PyObject *
156
tb_lineno_get(PyObject *op, void *Py_UNUSED(_))
157
0
{
158
0
    PyTracebackObject *self = _PyTracebackObject_CAST(op);
159
0
    int lineno = self->tb_lineno;
160
0
    if (lineno == -1) {
161
0
        lineno = tb_get_lineno(op);
162
0
        if (lineno < 0) {
163
0
            Py_RETURN_NONE;
164
0
        }
165
0
    }
166
0
    return PyLong_FromLong(lineno);
167
0
}
168
169
/*[clinic input]
170
@critical_section
171
@setter
172
traceback.tb_next
173
[clinic start generated code]*/
174
175
static int
176
traceback_tb_next_set_impl(PyTracebackObject *self, PyObject *value)
177
/*[clinic end generated code: output=d4868cbc48f2adac input=ce66367f85e3c443]*/
178
0
{
179
0
    if (!value) {
180
0
        PyErr_Format(PyExc_TypeError, "can't delete tb_next attribute");
181
0
        return -1;
182
0
    }
183
184
    /* We accept None or a traceback object, and map None -> NULL (inverse of
185
       tb_next_get) */
186
0
    if (value == Py_None) {
187
0
        value = NULL;
188
0
    } else if (!PyTraceBack_Check(value)) {
189
0
        PyErr_Format(PyExc_TypeError,
190
0
                     "expected traceback object, got '%s'",
191
0
                     Py_TYPE(value)->tp_name);
192
0
        return -1;
193
0
    }
194
195
    /* Check for loops */
196
0
    PyTracebackObject *cursor = (PyTracebackObject *)value;
197
0
    Py_XINCREF(cursor);
198
0
    while (cursor) {
199
0
        if (cursor == self) {
200
0
            PyErr_Format(PyExc_ValueError, "traceback loop detected");
201
0
            Py_DECREF(cursor);
202
0
            return -1;
203
0
        }
204
0
        Py_BEGIN_CRITICAL_SECTION(cursor);
205
0
        Py_XINCREF(cursor->tb_next);
206
0
        Py_SETREF(cursor, cursor->tb_next);
207
0
        Py_END_CRITICAL_SECTION();
208
0
    }
209
210
0
    Py_XSETREF(self->tb_next, (PyTracebackObject *)Py_XNewRef(value));
211
212
0
    return 0;
213
0
}
214
215
216
static PyMethodDef tb_methods[] = {
217
   {"__dir__", tb_dir, METH_NOARGS, NULL},
218
   {NULL, NULL, 0, NULL},
219
};
220
221
static PyMemberDef tb_memberlist[] = {
222
    {"tb_frame",        _Py_T_OBJECT,       OFF(tb_frame),  Py_READONLY|Py_AUDIT_READ},
223
    {"tb_lasti",        Py_T_INT,          OFF(tb_lasti),  Py_READONLY},
224
    {NULL}      /* Sentinel */
225
};
226
227
static PyGetSetDef tb_getsetters[] = {
228
    TRACEBACK_TB_NEXT_GETSETDEF
229
    {"tb_lineno", tb_lineno_get, NULL, NULL, NULL},
230
    {NULL}      /* Sentinel */
231
};
232
233
static void
234
tb_dealloc(PyObject *op)
235
33.4M
{
236
33.4M
    PyTracebackObject *tb = _PyTracebackObject_CAST(op);
237
33.4M
    PyObject_GC_UnTrack(tb);
238
33.4M
    Py_XDECREF(tb->tb_next);
239
33.4M
    Py_XDECREF(tb->tb_frame);
240
33.4M
    PyObject_GC_Del(tb);
241
33.4M
}
242
243
static int
244
tb_traverse(PyObject *op, visitproc visit, void *arg)
245
137k
{
246
137k
    PyTracebackObject *tb = _PyTracebackObject_CAST(op);
247
137k
    Py_VISIT(tb->tb_next);
248
137k
    Py_VISIT(tb->tb_frame);
249
137k
    return 0;
250
137k
}
251
252
static int
253
tb_clear(PyObject *op)
254
0
{
255
0
    PyTracebackObject *tb = _PyTracebackObject_CAST(op);
256
0
    Py_CLEAR(tb->tb_next);
257
0
    Py_CLEAR(tb->tb_frame);
258
0
    return 0;
259
0
}
260
261
PyTypeObject PyTraceBack_Type = {
262
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
263
    "traceback",
264
    sizeof(PyTracebackObject),
265
    0,
266
    tb_dealloc,         /*tp_dealloc*/
267
    0,                  /*tp_vectorcall_offset*/
268
    0,    /*tp_getattr*/
269
    0,                  /*tp_setattr*/
270
    0,                  /*tp_as_async*/
271
    0,                  /*tp_repr*/
272
    0,                  /*tp_as_number*/
273
    0,                  /*tp_as_sequence*/
274
    0,                  /*tp_as_mapping*/
275
    0,                  /* tp_hash */
276
    0,                  /* tp_call */
277
    0,                  /* tp_str */
278
    PyObject_GenericGetAttr,                    /* tp_getattro */
279
    0,                  /* tp_setattro */
280
    0,                                          /* tp_as_buffer */
281
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
282
    tb_new__doc__,                              /* tp_doc */
283
    tb_traverse,                                /* tp_traverse */
284
    tb_clear,                                   /* tp_clear */
285
    0,                                          /* tp_richcompare */
286
    0,                                          /* tp_weaklistoffset */
287
    0,                                          /* tp_iter */
288
    0,                                          /* tp_iternext */
289
    tb_methods,         /* tp_methods */
290
    tb_memberlist,      /* tp_members */
291
    tb_getsetters,                              /* tp_getset */
292
    0,                                          /* tp_base */
293
    0,                                          /* tp_dict */
294
    0,                                          /* tp_descr_get */
295
    0,                                          /* tp_descr_set */
296
    0,                                          /* tp_dictoffset */
297
    0,                                          /* tp_init */
298
    0,                                          /* tp_alloc */
299
    tb_new,                                     /* tp_new */
300
};
301
302
303
PyObject*
304
_PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame)
305
33.4M
{
306
33.4M
    assert(tb_next == NULL || PyTraceBack_Check(tb_next));
307
33.4M
    assert(frame != NULL);
308
33.4M
    int addr = _PyInterpreterFrame_LASTI(frame->f_frame) * sizeof(_Py_CODEUNIT);
309
33.4M
    return tb_create_raw((PyTracebackObject *)tb_next, frame, addr, -1);
310
33.4M
}
311
312
313
int
314
PyTraceBack_Here(PyFrameObject *frame)
315
33.4M
{
316
33.4M
    PyObject *exc = PyErr_GetRaisedException();
317
33.4M
    assert(PyExceptionInstance_Check(exc));
318
33.4M
    PyObject *tb = PyException_GetTraceback(exc);
319
33.4M
    PyObject *newtb = _PyTraceBack_FromFrame(tb, frame);
320
33.4M
    Py_XDECREF(tb);
321
33.4M
    if (newtb == NULL) {
322
0
        _PyErr_ChainExceptions1(exc);
323
0
        return -1;
324
0
    }
325
33.4M
    PyException_SetTraceback(exc, newtb);
326
33.4M
    Py_XDECREF(newtb);
327
33.4M
    PyErr_SetRaisedException(exc);
328
33.4M
    return 0;
329
33.4M
}
330
331
/* Insert a frame into the traceback for (funcname, filename, lineno). */
332
void _PyTraceback_Add(const char *funcname, const char *filename, int lineno)
333
0
{
334
0
    PyObject *globals;
335
0
    PyCodeObject *code;
336
0
    PyFrameObject *frame;
337
0
    PyThreadState *tstate = _PyThreadState_GET();
338
339
    /* Save and clear the current exception. Python functions must not be
340
       called with an exception set. Calling Python functions happens when
341
       the codec of the filesystem encoding is implemented in pure Python. */
342
0
    PyObject *exc = _PyErr_GetRaisedException(tstate);
343
344
0
    globals = PyDict_New();
345
0
    if (!globals)
346
0
        goto error;
347
0
    code = PyCode_NewEmpty(filename, funcname, lineno);
348
0
    if (!code) {
349
0
        Py_DECREF(globals);
350
0
        goto error;
351
0
    }
352
0
    frame = PyFrame_New(tstate, code, globals, NULL);
353
0
    Py_DECREF(globals);
354
0
    Py_DECREF(code);
355
0
    if (!frame)
356
0
        goto error;
357
0
    frame->f_lineno = lineno;
358
359
0
    _PyErr_SetRaisedException(tstate, exc);
360
0
    PyTraceBack_Here(frame);
361
0
    Py_DECREF(frame);
362
0
    return;
363
364
0
error:
365
0
    _PyErr_ChainExceptions1(exc);
366
0
}
367
368
static PyObject *
369
_Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject *io)
370
0
{
371
0
    Py_ssize_t i;
372
0
    PyObject *binary;
373
0
    PyObject *v;
374
0
    Py_ssize_t npath;
375
0
    size_t taillen;
376
0
    PyObject *syspath;
377
0
    PyObject *path;
378
0
    const char* tail;
379
0
    PyObject *filebytes;
380
0
    const char* filepath;
381
0
    Py_ssize_t len;
382
0
    PyObject* result;
383
0
    PyObject *open = NULL;
384
385
0
    filebytes = PyUnicode_EncodeFSDefault(filename);
386
0
    if (filebytes == NULL) {
387
0
        PyErr_Clear();
388
0
        return NULL;
389
0
    }
390
0
    filepath = PyBytes_AS_STRING(filebytes);
391
392
    /* Search tail of filename in sys.path before giving up */
393
0
    tail = strrchr(filepath, SEP);
394
0
    if (tail == NULL)
395
0
        tail = filepath;
396
0
    else
397
0
        tail++;
398
0
    taillen = strlen(tail);
399
400
0
    PyThreadState *tstate = _PyThreadState_GET();
401
0
    if (PySys_GetOptionalAttr(&_Py_ID(path), &syspath) < 0) {
402
0
        PyErr_Clear();
403
0
        goto error;
404
0
    }
405
0
    if (syspath == NULL || !PyList_Check(syspath)) {
406
0
        goto error;
407
0
    }
408
0
    npath = PyList_Size(syspath);
409
410
0
    open = PyObject_GetAttr(io, &_Py_ID(open));
411
0
    for (i = 0; i < npath; i++) {
412
0
        v = PyList_GetItem(syspath, i);
413
0
        if (v == NULL) {
414
0
            PyErr_Clear();
415
0
            break;
416
0
        }
417
0
        if (!PyUnicode_Check(v))
418
0
            continue;
419
0
        path = PyUnicode_EncodeFSDefault(v);
420
0
        if (path == NULL) {
421
0
            PyErr_Clear();
422
0
            continue;
423
0
        }
424
0
        len = PyBytes_GET_SIZE(path);
425
0
        if (len + 1 + (Py_ssize_t)taillen >= (Py_ssize_t)namelen - 1) {
426
0
            Py_DECREF(path);
427
0
            continue; /* Too long */
428
0
        }
429
0
        strcpy(namebuf, PyBytes_AS_STRING(path));
430
0
        Py_DECREF(path);
431
0
        if (strlen(namebuf) != (size_t)len)
432
0
            continue; /* v contains '\0' */
433
0
        if (len > 0 && namebuf[len-1] != SEP)
434
0
            namebuf[len++] = SEP;
435
0
        strcpy(namebuf+len, tail);
436
437
0
        binary = _PyObject_CallMethodFormat(tstate, open, "ss", namebuf, "rb");
438
0
        if (binary != NULL) {
439
0
            result = binary;
440
0
            goto finally;
441
0
        }
442
0
        PyErr_Clear();
443
0
    }
444
0
    goto error;
445
446
0
error:
447
0
    result = NULL;
448
0
finally:
449
0
    Py_XDECREF(open);
450
0
    Py_XDECREF(syspath);
451
0
    Py_DECREF(filebytes);
452
0
    return result;
453
0
}
454
455
/* Writes indent spaces. Returns 0 on success and non-zero on failure.
456
 */
457
int
458
_Py_WriteIndent(int indent, PyObject *f)
459
0
{
460
0
    char buf[11] = "          ";
461
0
    assert(strlen(buf) == 10);
462
0
    while (indent > 0) {
463
0
        if (indent < 10) {
464
0
            buf[indent] = '\0';
465
0
        }
466
0
        if (PyFile_WriteString(buf, f) < 0) {
467
0
            return -1;
468
0
        }
469
0
        indent -= 10;
470
0
    }
471
0
    return 0;
472
0
}
473
474
static int
475
display_source_line(PyObject *f, PyObject *filename, int lineno, int indent,
476
                    int *truncation, PyObject **line)
477
0
{
478
0
    int fd;
479
0
    int i;
480
0
    char *found_encoding;
481
0
    const char *encoding;
482
0
    PyObject *io;
483
0
    PyObject *binary;
484
0
    PyObject *fob = NULL;
485
0
    PyObject *lineobj = NULL;
486
0
    PyObject *res;
487
0
    char buf[MAXPATHLEN+1];
488
0
    int kind;
489
0
    const void *data;
490
491
    /* open the file */
492
0
    if (filename == NULL)
493
0
        return 0;
494
495
    /* Do not attempt to open things like <string> or <stdin> */
496
0
    assert(PyUnicode_Check(filename));
497
0
    if (PyUnicode_READ_CHAR(filename, 0) == '<') {
498
0
        Py_ssize_t len = PyUnicode_GET_LENGTH(filename);
499
0
        if (len > 0 && PyUnicode_READ_CHAR(filename, len - 1) == '>') {
500
0
            return 0;
501
0
        }
502
0
    }
503
504
0
    io = PyImport_ImportModule("io");
505
0
    if (io == NULL) {
506
0
        return -1;
507
0
    }
508
509
0
    binary = _PyObject_CallMethod(io, &_Py_ID(open), "Os", filename, "rb");
510
0
    if (binary == NULL) {
511
0
        PyErr_Clear();
512
513
0
        binary = _Py_FindSourceFile(filename, buf, sizeof(buf), io);
514
0
        if (binary == NULL) {
515
0
            Py_DECREF(io);
516
0
            return -1;
517
0
        }
518
0
    }
519
520
    /* use the right encoding to decode the file as unicode */
521
0
    fd = PyObject_AsFileDescriptor(binary);
522
0
    if (fd < 0) {
523
0
        Py_DECREF(io);
524
0
        Py_DECREF(binary);
525
0
        return 0;
526
0
    }
527
0
    found_encoding = _PyTokenizer_FindEncodingFilename(fd, filename);
528
0
    if (found_encoding == NULL)
529
0
        PyErr_Clear();
530
0
    encoding = (found_encoding != NULL) ? found_encoding : "utf-8";
531
    /* Reset position */
532
0
    if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
533
0
        Py_DECREF(io);
534
0
        Py_DECREF(binary);
535
0
        PyMem_Free(found_encoding);
536
0
        return 0;
537
0
    }
538
0
    fob = _PyObject_CallMethod(io, &_Py_ID(TextIOWrapper),
539
0
                               "Os", binary, encoding);
540
0
    Py_DECREF(io);
541
0
    PyMem_Free(found_encoding);
542
543
0
    if (fob == NULL) {
544
0
        PyErr_Clear();
545
546
0
        res = PyObject_CallMethodNoArgs(binary, &_Py_ID(close));
547
0
        Py_DECREF(binary);
548
0
        if (res)
549
0
            Py_DECREF(res);
550
0
        else
551
0
            PyErr_Clear();
552
0
        return 0;
553
0
    }
554
0
    Py_DECREF(binary);
555
556
    /* get the line number lineno */
557
0
    for (i = 0; i < lineno; i++) {
558
0
        Py_XDECREF(lineobj);
559
0
        lineobj = PyFile_GetLine(fob, -1);
560
0
        if (!lineobj) {
561
0
            PyErr_Clear();
562
0
            break;
563
0
        }
564
0
    }
565
0
    res = PyObject_CallMethodNoArgs(fob, &_Py_ID(close));
566
0
    if (res) {
567
0
        Py_DECREF(res);
568
0
    }
569
0
    else {
570
0
        PyErr_Clear();
571
0
    }
572
0
    Py_DECREF(fob);
573
0
    if (!lineobj || !PyUnicode_Check(lineobj)) {
574
0
        Py_XDECREF(lineobj);
575
0
        return -1;
576
0
    }
577
578
0
    if (line) {
579
0
        *line = Py_NewRef(lineobj);
580
0
    }
581
582
    /* remove the indentation of the line */
583
0
    kind = PyUnicode_KIND(lineobj);
584
0
    data = PyUnicode_DATA(lineobj);
585
0
    for (i=0; i < PyUnicode_GET_LENGTH(lineobj); i++) {
586
0
        Py_UCS4 ch = PyUnicode_READ(kind, data, i);
587
0
        if (ch != ' ' && ch != '\t' && ch != '\014')
588
0
            break;
589
0
    }
590
0
    if (i) {
591
0
        PyObject *truncated;
592
0
        truncated = PyUnicode_Substring(lineobj, i, PyUnicode_GET_LENGTH(lineobj));
593
0
        if (truncated) {
594
0
            Py_SETREF(lineobj, truncated);
595
0
        } else {
596
0
            PyErr_Clear();
597
0
        }
598
0
    }
599
600
0
    if (truncation != NULL) {
601
0
        *truncation = i - indent;
602
0
    }
603
604
    /* Write some spaces before the line */
605
0
    if (_Py_WriteIndent(indent, f) < 0) {
606
0
        goto error;
607
0
    }
608
609
    /* finally display the line */
610
0
    if (PyFile_WriteObject(lineobj, f, Py_PRINT_RAW) < 0) {
611
0
        goto error;
612
0
    }
613
614
0
    if (PyFile_WriteString("\n", f) < 0) {
615
0
        goto error;
616
0
    }
617
618
0
    Py_DECREF(lineobj);
619
0
    return 0;
620
0
error:
621
0
    Py_DECREF(lineobj);
622
0
    return -1;
623
0
}
624
625
int
626
_Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent,
627
                      int *truncation, PyObject **line)
628
0
{
629
0
    return display_source_line(f, filename, lineno, indent, truncation, line);
630
0
}
631
632
633
#define IS_WHITESPACE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\f'))
634
0
#define _TRACEBACK_SOURCE_LINE_INDENT 4
635
636
static inline int
637
0
ignore_source_errors(void) {
638
0
    if (PyErr_Occurred()) {
639
0
        if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
640
0
            return -1;
641
0
        }
642
0
        PyErr_Clear();
643
0
    }
644
0
    return 0;
645
0
}
646
647
static int
648
tb_displayline(PyTracebackObject* tb, PyObject *f, PyObject *filename, int lineno,
649
               PyFrameObject *frame, PyObject *name)
650
0
{
651
0
    if (filename == NULL || name == NULL) {
652
0
        return -1;
653
0
    }
654
655
0
    PyObject *line = PyUnicode_FromFormat("  File \"%U\", line %d, in %U\n",
656
0
                                          filename, lineno, name);
657
0
    if (line == NULL) {
658
0
        return -1;
659
0
    }
660
661
0
    int res = PyFile_WriteObject(line, f, Py_PRINT_RAW);
662
0
    Py_DECREF(line);
663
0
    if (res < 0) {
664
0
        return -1;
665
0
    }
666
667
0
    int err = 0;
668
669
0
    int truncation = _TRACEBACK_SOURCE_LINE_INDENT;
670
0
    PyObject* source_line = NULL;
671
0
    int rc = display_source_line(
672
0
            f, filename, lineno, _TRACEBACK_SOURCE_LINE_INDENT,
673
0
            &truncation, &source_line);
674
0
    if (rc != 0 || !source_line) {
675
        /* ignore errors since we can't report them, can we? */
676
0
        err = ignore_source_errors();
677
0
    }
678
0
    Py_XDECREF(source_line);
679
0
    return err;
680
0
}
681
682
static const int TB_RECURSIVE_CUTOFF = 3; // Also hardcoded in traceback.py.
683
684
static int
685
tb_print_line_repeated(PyObject *f, long cnt)
686
0
{
687
0
    cnt -= TB_RECURSIVE_CUTOFF;
688
0
    PyObject *line = PyUnicode_FromFormat(
689
0
        (cnt > 1)
690
0
          ? "  [Previous line repeated %ld more times]\n"
691
0
          : "  [Previous line repeated %ld more time]\n",
692
0
        cnt);
693
0
    if (line == NULL) {
694
0
        return -1;
695
0
    }
696
0
    int err = PyFile_WriteObject(line, f, Py_PRINT_RAW);
697
0
    Py_DECREF(line);
698
0
    return err;
699
0
}
700
701
static int
702
tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
703
0
{
704
0
    PyCodeObject *code = NULL;
705
0
    Py_ssize_t depth = 0;
706
0
    PyObject *last_file = NULL;
707
0
    int last_line = -1;
708
0
    PyObject *last_name = NULL;
709
0
    long cnt = 0;
710
0
    PyTracebackObject *tb1 = tb;
711
0
    while (tb1 != NULL) {
712
0
        depth++;
713
0
        tb1 = tb1->tb_next;
714
0
    }
715
0
    while (tb != NULL && depth > limit) {
716
0
        depth--;
717
0
        tb = tb->tb_next;
718
0
    }
719
0
    while (tb != NULL) {
720
0
        code = PyFrame_GetCode(tb->tb_frame);
721
0
        int tb_lineno = tb->tb_lineno;
722
0
        if (tb_lineno == -1) {
723
0
            tb_lineno = tb_get_lineno((PyObject *)tb);
724
0
        }
725
0
        if (last_file == NULL ||
726
0
            code->co_filename != last_file ||
727
0
            last_line == -1 || tb_lineno != last_line ||
728
0
            last_name == NULL || code->co_name != last_name) {
729
0
            if (cnt > TB_RECURSIVE_CUTOFF) {
730
0
                if (tb_print_line_repeated(f, cnt) < 0) {
731
0
                    goto error;
732
0
                }
733
0
            }
734
0
            last_file = code->co_filename;
735
0
            last_line = tb_lineno;
736
0
            last_name = code->co_name;
737
0
            cnt = 0;
738
0
        }
739
0
        cnt++;
740
0
        if (cnt <= TB_RECURSIVE_CUTOFF) {
741
0
            if (tb_displayline(tb, f, code->co_filename, tb_lineno,
742
0
                               tb->tb_frame, code->co_name) < 0) {
743
0
                goto error;
744
0
            }
745
746
0
            if (PyErr_CheckSignals() < 0) {
747
0
                goto error;
748
0
            }
749
0
        }
750
0
        Py_CLEAR(code);
751
0
        tb = tb->tb_next;
752
0
    }
753
0
    if (cnt > TB_RECURSIVE_CUTOFF) {
754
0
        if (tb_print_line_repeated(f, cnt) < 0) {
755
0
            goto error;
756
0
        }
757
0
    }
758
0
    return 0;
759
0
error:
760
0
    Py_XDECREF(code);
761
0
    return -1;
762
0
}
763
764
0
#define PyTraceBack_LIMIT 1000
765
766
int
767
_PyTraceBack_Print(PyObject *v, const char *header, PyObject *f)
768
0
{
769
0
    PyObject *limitv;
770
0
    long limit = PyTraceBack_LIMIT;
771
772
0
    if (v == NULL) {
773
0
        return 0;
774
0
    }
775
0
    if (!PyTraceBack_Check(v)) {
776
0
        PyErr_BadInternalCall();
777
0
        return -1;
778
0
    }
779
0
    if (PySys_GetOptionalAttrString("tracebacklimit", &limitv) < 0) {
780
0
        return -1;
781
0
    }
782
0
    else if (limitv != NULL && PyLong_Check(limitv)) {
783
0
        int overflow;
784
0
        limit = PyLong_AsLongAndOverflow(limitv, &overflow);
785
0
        if (overflow > 0) {
786
0
            limit = LONG_MAX;
787
0
        }
788
0
        else if (limit <= 0) {
789
0
            Py_DECREF(limitv);
790
0
            return 0;
791
0
        }
792
0
    }
793
0
    Py_XDECREF(limitv);
794
795
0
    if (PyFile_WriteString(header, f) < 0) {
796
0
        return -1;
797
0
    }
798
799
0
    if (tb_printinternal((PyTracebackObject *)v, f, limit) < 0) {
800
0
        return -1;
801
0
    }
802
803
0
    return 0;
804
0
}
805
806
int
807
PyTraceBack_Print(PyObject *v, PyObject *f)
808
0
{
809
0
    const char *header = EXCEPTION_TB_HEADER;
810
0
    return _PyTraceBack_Print(v, header, f);
811
0
}
812
813
/* Format an integer in range [0; 0xffffffff] to decimal and write it
814
   into the file fd.
815
816
   This function is signal safe. */
817
818
void
819
_Py_DumpDecimal(int fd, size_t value)
820
0
{
821
    /* maximum number of characters required for output of %lld or %p.
822
       We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits,
823
       plus 1 for the null byte.  53/22 is an upper bound for log10(256). */
824
0
    char buffer[1 + (sizeof(size_t)*53-1) / 22 + 1];
825
0
    char *ptr, *end;
826
827
0
    end = &buffer[Py_ARRAY_LENGTH(buffer) - 1];
828
0
    ptr = end;
829
0
    *ptr = '\0';
830
0
    do {
831
0
        --ptr;
832
0
        assert(ptr >= buffer);
833
0
        *ptr = '0' + (value % 10);
834
0
        value /= 10;
835
0
    } while (value);
836
837
0
    (void)_Py_write_noraise(fd, ptr, end - ptr);
838
0
}
839
840
/* Format an integer as hexadecimal with width digits into fd file descriptor.
841
   The function is signal safe. */
842
static void
843
dump_hexadecimal(int fd, uintptr_t value, Py_ssize_t width, int strip_zeros)
844
0
{
845
0
    char buffer[sizeof(uintptr_t) * 2 + 1], *ptr, *end;
846
0
    Py_ssize_t size = Py_ARRAY_LENGTH(buffer) - 1;
847
848
0
    if (width > size)
849
0
        width = size;
850
    /* it's ok if width is negative */
851
852
0
    end = &buffer[size];
853
0
    ptr = end;
854
0
    *ptr = '\0';
855
0
    do {
856
0
        --ptr;
857
0
        assert(ptr >= buffer);
858
0
        *ptr = Py_hexdigits[value & 15];
859
0
        value >>= 4;
860
0
    } while ((end - ptr) < width || value);
861
862
0
    size = end - ptr;
863
0
    if (strip_zeros) {
864
0
        while (*ptr == '0' && size >= 2) {
865
0
            ptr++;
866
0
            size--;
867
0
        }
868
0
    }
869
870
0
    (void)_Py_write_noraise(fd, ptr, size);
871
0
}
872
873
void
874
_Py_DumpHexadecimal(int fd, uintptr_t value, Py_ssize_t width)
875
0
{
876
0
    dump_hexadecimal(fd, value, width, 0);
877
0
}
878
879
#ifdef CAN_C_BACKTRACE
880
static void
881
dump_pointer(int fd, void *ptr)
882
0
{
883
0
    PUTS(fd, "0x");
884
0
    dump_hexadecimal(fd, (uintptr_t)ptr, sizeof(void*), 1);
885
0
}
886
#endif
887
888
static void
889
dump_char(int fd, char ch)
890
0
{
891
0
    char buf[1] = {ch};
892
0
    (void)_Py_write_noraise(fd, buf, 1);
893
0
}
894
895
void
896
_Py_DumpASCII(int fd, PyObject *text)
897
0
{
898
0
    PyASCIIObject *ascii = _PyASCIIObject_CAST(text);
899
0
    Py_ssize_t i, size;
900
0
    int truncated;
901
0
    int kind;
902
0
    void *data = NULL;
903
0
    Py_UCS4 ch;
904
905
0
    if (!PyUnicode_Check(text))
906
0
        return;
907
908
0
    size = ascii->length;
909
0
    kind = ascii->state.kind;
910
0
    if (ascii->state.compact) {
911
0
        if (ascii->state.ascii)
912
0
            data = ascii + 1;
913
0
        else
914
0
            data = _PyCompactUnicodeObject_CAST(text) + 1;
915
0
    }
916
0
    else {
917
0
        data = _PyUnicodeObject_CAST(text)->data.any;
918
0
        if (data == NULL)
919
0
            return;
920
0
    }
921
922
0
    if (MAX_STRING_LENGTH < size) {
923
0
        size = MAX_STRING_LENGTH;
924
0
        truncated = 1;
925
0
    }
926
0
    else {
927
0
        truncated = 0;
928
0
    }
929
930
    // Is an ASCII string?
931
0
    if (ascii->state.ascii) {
932
0
        assert(kind == PyUnicode_1BYTE_KIND);
933
0
        char *str = data;
934
935
0
        int need_escape = 0;
936
0
        for (i=0; i < size; i++) {
937
0
            ch = str[i];
938
0
            if (!(' ' <= ch && ch <= 126)) {
939
0
                need_escape = 1;
940
0
                break;
941
0
            }
942
0
        }
943
0
        if (!need_escape) {
944
            // The string can be written with a single write() syscall
945
0
            (void)_Py_write_noraise(fd, str, size);
946
0
            goto done;
947
0
        }
948
0
    }
949
950
0
    for (i=0; i < size; i++) {
951
0
        ch = PyUnicode_READ(kind, data, i);
952
0
        if (' ' <= ch && ch <= 126) {
953
            /* printable ASCII character */
954
0
            dump_char(fd, (char)ch);
955
0
        }
956
0
        else if (ch <= 0xff) {
957
0
            PUTS(fd, "\\x");
958
0
            _Py_DumpHexadecimal(fd, ch, 2);
959
0
        }
960
0
        else if (ch <= 0xffff) {
961
0
            PUTS(fd, "\\u");
962
0
            _Py_DumpHexadecimal(fd, ch, 4);
963
0
        }
964
0
        else {
965
0
            PUTS(fd, "\\U");
966
0
            _Py_DumpHexadecimal(fd, ch, 8);
967
0
        }
968
0
    }
969
970
0
done:
971
0
    if (truncated) {
972
0
        PUTS(fd, "...");
973
0
    }
974
0
}
975
976
/* Write a frame into the file fd: "File "xxx", line xxx in xxx".
977
978
   This function is signal safe. */
979
980
static void
981
dump_frame(int fd, _PyInterpreterFrame *frame)
982
0
{
983
0
    assert(frame->owner < FRAME_OWNED_BY_INTERPRETER);
984
985
0
    PyCodeObject *code =_PyFrame_GetCode(frame);
986
0
    PUTS(fd, "  File ");
987
0
    if (code->co_filename != NULL
988
0
        && PyUnicode_Check(code->co_filename))
989
0
    {
990
0
        PUTS(fd, "\"");
991
0
        _Py_DumpASCII(fd, code->co_filename);
992
0
        PUTS(fd, "\"");
993
0
    } else {
994
0
        PUTS(fd, "???");
995
0
    }
996
997
0
    int lineno = PyUnstable_InterpreterFrame_GetLine(frame);
998
0
    PUTS(fd, ", line ");
999
0
    if (lineno >= 0) {
1000
0
        _Py_DumpDecimal(fd, (size_t)lineno);
1001
0
    }
1002
0
    else {
1003
0
        PUTS(fd, "???");
1004
0
    }
1005
0
    PUTS(fd, " in ");
1006
1007
0
    if (code->co_name != NULL
1008
0
       && PyUnicode_Check(code->co_name)) {
1009
0
        _Py_DumpASCII(fd, code->co_name);
1010
0
    }
1011
0
    else {
1012
0
        PUTS(fd, "???");
1013
0
    }
1014
1015
0
    PUTS(fd, "\n");
1016
0
}
1017
1018
static int
1019
tstate_is_freed(PyThreadState *tstate)
1020
0
{
1021
0
    if (_PyMem_IsPtrFreed(tstate)) {
1022
0
        return 1;
1023
0
    }
1024
0
    if (_PyMem_IsPtrFreed(tstate->interp)) {
1025
0
        return 1;
1026
0
    }
1027
0
    return 0;
1028
0
}
1029
1030
1031
static int
1032
interp_is_freed(PyInterpreterState *interp)
1033
0
{
1034
0
    return _PyMem_IsPtrFreed(interp);
1035
0
}
1036
1037
1038
static void
1039
dump_traceback(int fd, PyThreadState *tstate, int write_header)
1040
0
{
1041
0
    if (write_header) {
1042
0
        PUTS(fd, "Stack (most recent call first):\n");
1043
0
    }
1044
1045
0
    if (tstate_is_freed(tstate)) {
1046
0
        PUTS(fd, "  <tstate is freed>\n");
1047
0
        return;
1048
0
    }
1049
1050
0
    _PyInterpreterFrame *frame = tstate->current_frame;
1051
0
    if (frame == NULL) {
1052
0
        PUTS(fd, "  <no Python frame>\n");
1053
0
        return;
1054
0
    }
1055
1056
0
    unsigned int depth = 0;
1057
0
    while (1) {
1058
0
        if (frame->owner == FRAME_OWNED_BY_INTERPRETER) {
1059
            /* Trampoline frame */
1060
0
            frame = frame->previous;
1061
0
            if (frame == NULL) {
1062
0
                break;
1063
0
            }
1064
1065
            /* Can't have more than one shim frame in a row */
1066
0
            assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
1067
0
        }
1068
1069
0
        if (MAX_FRAME_DEPTH <= depth) {
1070
0
            if (MAX_FRAME_DEPTH < depth) {
1071
0
                PUTS(fd, "plus ");
1072
0
                _Py_DumpDecimal(fd, depth);
1073
0
                PUTS(fd, " frames\n");
1074
0
            }
1075
0
            break;
1076
0
        }
1077
1078
0
        dump_frame(fd, frame);
1079
0
        frame = frame->previous;
1080
0
        if (frame == NULL) {
1081
0
            break;
1082
0
        }
1083
0
        depth++;
1084
0
    }
1085
0
}
1086
1087
/* Dump the traceback of a Python thread into fd. Use write() to write the
1088
   traceback and retry if write() is interrupted by a signal (failed with
1089
   EINTR), but don't call the Python signal handler.
1090
1091
   The caller is responsible to call PyErr_CheckSignals() to call Python signal
1092
   handlers if signals were received. */
1093
void
1094
_Py_DumpTraceback(int fd, PyThreadState *tstate)
1095
0
{
1096
0
    dump_traceback(fd, tstate, 1);
1097
0
}
1098
1099
#if defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP)
1100
# if defined(__OpenBSD__)
1101
    /* pthread_*_np functions, especially pthread_{get,set}_name_np().
1102
       pthread_np.h exists on both OpenBSD and FreeBSD but the latter declares
1103
       pthread_getname_np() and pthread_setname_np() in pthread.h as long as
1104
       __BSD_VISIBLE remains set.
1105
     */
1106
#   include <pthread_np.h>
1107
# endif
1108
#endif
1109
1110
/* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
1111
   is_current is true, "Thread 0xHHHH:\n" otherwise.
1112
1113
   This function is signal safe. */
1114
1115
static void
1116
write_thread_id(int fd, PyThreadState *tstate, int is_current)
1117
0
{
1118
0
    if (is_current)
1119
0
        PUTS(fd, "Current thread 0x");
1120
0
    else
1121
0
        PUTS(fd, "Thread 0x");
1122
0
    _Py_DumpHexadecimal(fd,
1123
0
                        tstate->thread_id,
1124
0
                        sizeof(unsigned long) * 2);
1125
1126
    // Write the thread name
1127
0
#if defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP)
1128
0
    char name[100];
1129
0
    pthread_t thread = (pthread_t)tstate->thread_id;
1130
0
#ifdef HAVE_PTHREAD_GETNAME_NP
1131
0
    int rc = pthread_getname_np(thread, name, Py_ARRAY_LENGTH(name));
1132
#else /* defined(HAVE_PTHREAD_GET_NAME_NP) */
1133
    int rc = 0; /* pthread_get_name_np() returns void */
1134
    pthread_get_name_np(thread, name, Py_ARRAY_LENGTH(name));
1135
#endif
1136
0
    if (!rc) {
1137
0
        size_t len = strlen(name);
1138
0
        if (len) {
1139
0
            PUTS(fd, " [");
1140
0
            (void)_Py_write_noraise(fd, name, len);
1141
0
            PUTS(fd, "]");
1142
0
        }
1143
0
    }
1144
0
#endif
1145
1146
0
    PUTS(fd, " (most recent call first):\n");
1147
0
}
1148
1149
/* Dump the traceback of all Python threads into fd. Use write() to write the
1150
   traceback and retry if write() is interrupted by a signal (failed with
1151
   EINTR), but don't call the Python signal handler.
1152
1153
   The caller is responsible to call PyErr_CheckSignals() to call Python signal
1154
   handlers if signals were received. */
1155
const char*
1156
_Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
1157
                         PyThreadState *current_tstate)
1158
0
{
1159
0
    if (current_tstate == NULL) {
1160
        /* _Py_DumpTracebackThreads() is called from signal handlers by
1161
           faulthandler.
1162
1163
           SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals
1164
           and are thus delivered to the thread that caused the fault. Get the
1165
           Python thread state of the current thread.
1166
1167
           PyThreadState_Get() doesn't give the state of the thread that caused
1168
           the fault if the thread released the GIL, and so
1169
           _PyThreadState_GET() cannot be used. Read the thread specific
1170
           storage (TSS) instead: call PyGILState_GetThisThreadState(). */
1171
0
        current_tstate = PyGILState_GetThisThreadState();
1172
0
    }
1173
1174
0
    if (current_tstate != NULL && tstate_is_freed(current_tstate)) {
1175
0
        return "tstate is freed";
1176
0
    }
1177
1178
0
    if (interp == NULL) {
1179
0
        if (current_tstate == NULL) {
1180
0
            interp = _PyGILState_GetInterpreterStateUnsafe();
1181
0
            if (interp == NULL) {
1182
                /* We need the interpreter state to get Python threads */
1183
0
                return "unable to get the interpreter state";
1184
0
            }
1185
0
        }
1186
0
        else {
1187
0
            interp = current_tstate->interp;
1188
0
        }
1189
0
    }
1190
0
    assert(interp != NULL);
1191
1192
0
    if (interp_is_freed(interp)) {
1193
0
        return "interp is freed";
1194
0
    }
1195
1196
    /* Get the current interpreter from the current thread */
1197
0
    PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1198
0
    if (tstate == NULL)
1199
0
        return "unable to get the thread head state";
1200
1201
    /* Dump the traceback of each thread */
1202
0
    tstate = PyInterpreterState_ThreadHead(interp);
1203
0
    unsigned int nthreads = 0;
1204
0
    _Py_BEGIN_SUPPRESS_IPH
1205
0
    do
1206
0
    {
1207
0
        if (nthreads != 0)
1208
0
            PUTS(fd, "\n");
1209
0
        if (nthreads >= MAX_NTHREADS) {
1210
0
            PUTS(fd, "...\n");
1211
0
            break;
1212
0
        }
1213
0
        write_thread_id(fd, tstate, tstate == current_tstate);
1214
0
        if (tstate == current_tstate && tstate->interp->gc.collecting) {
1215
0
            PUTS(fd, "  Garbage-collecting\n");
1216
0
        }
1217
0
        dump_traceback(fd, tstate, 0);
1218
0
        tstate = PyThreadState_Next(tstate);
1219
0
        nthreads++;
1220
0
    } while (tstate != NULL);
1221
0
    _Py_END_SUPPRESS_IPH
1222
1223
0
    return NULL;
1224
0
}
1225
1226
#ifdef CAN_C_BACKTRACE
1227
/* Based on glibc's implementation of backtrace_symbols(), but only uses stack memory. */
1228
void
1229
_Py_backtrace_symbols_fd(int fd, void *const *array, Py_ssize_t size)
1230
0
{
1231
0
    VLA(Dl_info, info, size);
1232
0
    VLA(int, status, size);
1233
    /* Fill in the information we can get from dladdr() */
1234
0
    for (Py_ssize_t i = 0; i < size; ++i) {
1235
#ifdef __APPLE__
1236
        status[i] = dladdr(array[i], &info[i]);
1237
#else
1238
0
        struct link_map *map;
1239
0
        status[i] = dladdr1(array[i], &info[i], (void **)&map, RTLD_DL_LINKMAP);
1240
0
        if (status[i] != 0
1241
0
            && info[i].dli_fname != NULL
1242
0
            && info[i].dli_fname[0] != '\0') {
1243
            /* The load bias is more useful to the user than the load
1244
               address. The use of these addresses is to calculate an
1245
               address in the ELF file, so its prelinked bias is not
1246
               something we want to subtract out */
1247
0
            info[i].dli_fbase = (void *) map->l_addr;
1248
0
        }
1249
0
#endif
1250
0
    }
1251
0
    for (Py_ssize_t i = 0; i < size; ++i) {
1252
0
        if (status[i] == 0
1253
0
            || info[i].dli_fname == NULL
1254
0
            || info[i].dli_fname[0] == '\0'
1255
0
        ) {
1256
0
            PUTS(fd, "  Binary file '<unknown>' [");
1257
0
            dump_pointer(fd, array[i]);
1258
0
            PUTS(fd, "]\n");
1259
0
            continue;
1260
0
        }
1261
1262
0
        if (info[i].dli_sname == NULL) {
1263
            /* We found no symbol name to use, so describe it as
1264
               relative to the file. */
1265
0
            info[i].dli_saddr = info[i].dli_fbase;
1266
0
        }
1267
1268
0
        if (info[i].dli_sname == NULL && info[i].dli_saddr == 0) {
1269
0
            PUTS(fd, "  Binary file \"");
1270
0
            PUTS(fd, info[i].dli_fname);
1271
0
            PUTS(fd, "\" [");
1272
0
            dump_pointer(fd, array[i]);
1273
0
            PUTS(fd, "]\n");
1274
0
        }
1275
0
        else {
1276
0
            char sign;
1277
0
            ptrdiff_t offset;
1278
0
            if (array[i] >= (void *) info[i].dli_saddr) {
1279
0
                sign = '+';
1280
0
                offset = array[i] - info[i].dli_saddr;
1281
0
            }
1282
0
            else {
1283
0
                sign = '-';
1284
0
                offset = info[i].dli_saddr - array[i];
1285
0
            }
1286
0
            const char *symbol_name = info[i].dli_sname != NULL ? info[i].dli_sname : "";
1287
0
            PUTS(fd, "  Binary file \"");
1288
0
            PUTS(fd, info[i].dli_fname);
1289
0
            PUTS(fd, "\", at ");
1290
0
            PUTS(fd, symbol_name);
1291
0
            dump_char(fd, sign);
1292
0
            PUTS(fd, "0x");
1293
0
            dump_hexadecimal(fd, offset, sizeof(offset), 1);
1294
0
            PUTS(fd, " [");
1295
0
            dump_pointer(fd, array[i]);
1296
0
            PUTS(fd, "]\n");
1297
0
        }
1298
0
    }
1299
0
}
1300
1301
void
1302
_Py_DumpStack(int fd)
1303
0
{
1304
0
#define BACKTRACE_SIZE 32
1305
0
    PUTS(fd, "Current thread's C stack trace (most recent call first):\n");
1306
0
    VLA(void *, callstack, BACKTRACE_SIZE);
1307
0
    int frames = backtrace(callstack, BACKTRACE_SIZE);
1308
0
    if (frames == 0) {
1309
        // Some systems won't return anything for the stack trace
1310
0
        PUTS(fd, "  <system returned no stack trace>\n");
1311
0
        return;
1312
0
    }
1313
1314
0
    _Py_backtrace_symbols_fd(fd, callstack, frames);
1315
0
    if (frames == BACKTRACE_SIZE) {
1316
0
        PUTS(fd, "  <truncated rest of calls>\n");
1317
0
    }
1318
1319
0
#undef BACKTRACE_SIZE
1320
0
}
1321
#else
1322
void
1323
_Py_DumpStack(int fd)
1324
{
1325
    PUTS(fd, "Current thread's C stack trace (most recent call first):\n");
1326
    PUTS(fd, "  <cannot get C stack on this system>\n");
1327
}
1328
#endif