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 #include "traceback.h" 11 12 #define OFF(x) offsetof(PyTracebackObject, x) 13 14 static PyMemberDef tb_memberlist[] = { 15 {"tb_next", T_OBJECT, OFF(tb_next), READONLY}, 16 {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY}, 17 {"tb_lasti", T_INT, OFF(tb_lasti), READONLY}, 18 {"tb_lineno", T_INT, OFF(tb_lineno), READONLY}, 19 {NULL} /* Sentinel */ 20 }; 21 22 static void 23 tb_dealloc(PyTracebackObject *tb) 24 { 25 PyObject_GC_UnTrack(tb); 26 Py_TRASHCAN_SAFE_BEGIN(tb) 27 Py_XDECREF(tb->tb_next); 28 Py_XDECREF(tb->tb_frame); 29 PyObject_GC_Del(tb); 30 Py_TRASHCAN_SAFE_END(tb) 31 } 32 33 static int 34 tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg) 35 { 36 Py_VISIT(tb->tb_next); 37 Py_VISIT(tb->tb_frame); 38 return 0; 39 } 40 41 static void 42 tb_clear(PyTracebackObject *tb) 43 { 44 Py_CLEAR(tb->tb_next); 45 Py_CLEAR(tb->tb_frame); 46 } 47 48 PyTypeObject PyTraceBack_Type = { 49 PyVarObject_HEAD_INIT(&PyType_Type, 0) 50 "traceback", 51 sizeof(PyTracebackObject), 52 0, 53 (destructor)tb_dealloc, /*tp_dealloc*/ 54 0, /*tp_print*/ 55 0, /*tp_getattr*/ 56 0, /*tp_setattr*/ 57 0, /*tp_compare*/ 58 0, /*tp_repr*/ 59 0, /*tp_as_number*/ 60 0, /*tp_as_sequence*/ 61 0, /*tp_as_mapping*/ 62 0, /* tp_hash */ 63 0, /* tp_call */ 64 0, /* tp_str */ 65 0, /* tp_getattro */ 66 0, /* tp_setattro */ 67 0, /* tp_as_buffer */ 68 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ 69 0, /* tp_doc */ 70 (traverseproc)tb_traverse, /* tp_traverse */ 71 (inquiry)tb_clear, /* tp_clear */ 72 0, /* tp_richcompare */ 73 0, /* tp_weaklistoffset */ 74 0, /* tp_iter */ 75 0, /* tp_iternext */ 76 0, /* tp_methods */ 77 tb_memberlist, /* tp_members */ 78 0, /* tp_getset */ 79 0, /* tp_base */ 80 0, /* tp_dict */ 81 }; 82 83 static PyTracebackObject * 84 newtracebackobject(PyTracebackObject *next, PyFrameObject *frame) 85 { 86 PyTracebackObject *tb; 87 if ((next != NULL && !PyTraceBack_Check(next)) || 88 frame == NULL || !PyFrame_Check(frame)) { 89 PyErr_BadInternalCall(); 90 return NULL; 91 } 92 tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type); 93 if (tb != NULL) { 94 Py_XINCREF(next); 95 tb->tb_next = next; 96 Py_XINCREF(frame); 97 tb->tb_frame = frame; 98 tb->tb_lasti = frame->f_lasti; 99 tb->tb_lineno = PyFrame_GetLineNumber(frame); 100 PyObject_GC_Track(tb); 101 } 102 return tb; 103 } 104 105 int 106 PyTraceBack_Here(PyFrameObject *frame) 107 { 108 PyThreadState *tstate = PyThreadState_GET(); 109 PyTracebackObject *oldtb = (PyTracebackObject *) tstate->curexc_traceback; 110 PyTracebackObject *tb = newtracebackobject(oldtb, frame); 111 if (tb == NULL) 112 return -1; 113 tstate->curexc_traceback = (PyObject *)tb; 114 Py_XDECREF(oldtb); 115 return 0; 116 } 117 118 int 119 _Py_DisplaySourceLine(PyObject *f, const char *filename, int lineno, int indent) 120 { 121 int err = 0; 122 FILE *xfp = NULL; 123 char linebuf[2000]; 124 int i; 125 char namebuf[MAXPATHLEN+1]; 126 127 if (filename == NULL) 128 return -1; 129 /* This is needed by Emacs' compile command */ 130 #define FMT " File \"%.500s\", line %d, in %.500s\n" 131 xfp = fopen(filename, "r" PY_STDIOTEXTMODE); 132 if (xfp == NULL) { 133 /* Search tail of filename in sys.path before giving up */ 134 PyObject *path; 135 const char *tail = strrchr(filename, SEP); 136 if (tail == NULL) 137 tail = filename; 138 else 139 tail++; 140 path = PySys_GetObject("path"); 141 if (path != NULL && PyList_Check(path)) { 142 Py_ssize_t _npath = PyList_Size(path); 143 int npath = Py_SAFE_DOWNCAST(_npath, Py_ssize_t, int); 144 size_t taillen = strlen(tail); 145 for (i = 0; i < npath; i++) { 146 PyObject *v = PyList_GetItem(path, i); 147 if (v == NULL) { 148 PyErr_Clear(); 149 break; 150 } 151 if (PyString_Check(v)) { 152 size_t len; 153 len = PyString_GET_SIZE(v); 154 if (len + 1 + taillen >= MAXPATHLEN) 155 continue; /* Too long */ 156 strcpy(namebuf, PyString_AsString(v)); 157 if (strlen(namebuf) != len) 158 continue; /* v contains '\0' */ 159 if (len > 0 && namebuf[len-1] != SEP) 160 namebuf[len++] = SEP; 161 strcpy(namebuf+len, tail); 162 xfp = fopen(namebuf, "r" PY_STDIOTEXTMODE); 163 if (xfp != NULL) { 164 break; 165 } 166 } 167 } 168 } 169 } 170 171 if (xfp == NULL) 172 return err; 173 if (err != 0) { 174 fclose(xfp); 175 return err; 176 } 177 178 for (i = 0; i < lineno; i++) { 179 char* pLastChar = &linebuf[sizeof(linebuf)-2]; 180 do { 181 *pLastChar = '\0'; 182 if (Py_UniversalNewlineFgets(linebuf, sizeof linebuf, xfp, NULL) == NULL) 183 break; 184 /* fgets read *something*; if it didn't get as 185 far as pLastChar, it must have found a newline 186 or hit the end of the file; if pLastChar is \n, 187 it obviously found a newline; else we haven't 188 yet seen a newline, so must continue */ 189 } while (*pLastChar != '\0' && *pLastChar != '\n'); 190 } 191 if (i == lineno) { 192 char buf[11]; 193 char *p = linebuf; 194 while (*p == ' ' || *p == '\t' || *p == '\014') 195 p++; 196 197 /* Write some spaces before the line */ 198 strcpy(buf, " "); 199 assert (strlen(buf) == 10); 200 while (indent > 0) { 201 if(indent < 10) 202 buf[indent] = '\0'; 203 err = PyFile_WriteString(buf, f); 204 if (err != 0) 205 break; 206 indent -= 10; 207 } 208 209 if (err == 0) 210 err = PyFile_WriteString(p, f); 211 if (err == 0 && strchr(p, '\n') == NULL) 212 err = PyFile_WriteString("\n", f); 213 } 214 fclose(xfp); 215 return err; 216 } 217 218 static int 219 tb_displayline(PyObject *f, const char *filename, int lineno, const char *name) 220 { 221 int err = 0; 222 char linebuf[2000]; 223 224 if (filename == NULL || name == NULL) 225 return -1; 226 /* This is needed by Emacs' compile command */ 227 #define FMT " File \"%.500s\", line %d, in %.500s\n" 228 PyOS_snprintf(linebuf, sizeof(linebuf), FMT, filename, lineno, name); 229 err = PyFile_WriteString(linebuf, f); 230 if (err != 0) 231 return err; 232 return _Py_DisplaySourceLine(f, filename, lineno, 4); 233 } 234 235 static int 236 tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit) 237 { 238 int err = 0; 239 long depth = 0; 240 PyTracebackObject *tb1 = tb; 241 while (tb1 != NULL) { 242 depth++; 243 tb1 = tb1->tb_next; 244 } 245 while (tb != NULL && err == 0) { 246 if (depth <= limit) { 247 err = tb_displayline(f, 248 PyString_AsString( 249 tb->tb_frame->f_code->co_filename), 250 tb->tb_lineno, 251 PyString_AsString(tb->tb_frame->f_code->co_name)); 252 } 253 depth--; 254 tb = tb->tb_next; 255 if (err == 0) 256 err = PyErr_CheckSignals(); 257 } 258 return err; 259 } 260 261 int 262 PyTraceBack_Print(PyObject *v, PyObject *f) 263 { 264 int err; 265 PyObject *limitv; 266 long limit = 1000; 267 if (v == NULL) 268 return 0; 269 if (!PyTraceBack_Check(v)) { 270 PyErr_BadInternalCall(); 271 return -1; 272 } 273 limitv = PySys_GetObject("tracebacklimit"); 274 if (limitv && PyInt_Check(limitv)) { 275 limit = PyInt_AsLong(limitv); 276 if (limit <= 0) 277 return 0; 278 } 279 err = PyFile_WriteString("Traceback (most recent call last):\n", f); 280 if (!err) 281 err = tb_printinternal((PyTracebackObject *)v, f, limit); 282 return err; 283 } 284