1 /* Python interface to inferior threads. 2 3 Copyright (C) 2009-2016 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 #include "defs.h" 21 #include "gdbthread.h" 22 #include "inferior.h" 23 #include "python-internal.h" 24 25 extern PyTypeObject thread_object_type 26 CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("thread_object"); 27 28 /* Require that INFERIOR be a valid inferior ID. */ 29 #define THPY_REQUIRE_VALID(Thread) \ 30 do { \ 31 if (!Thread->thread) \ 32 { \ 33 PyErr_SetString (PyExc_RuntimeError, \ 34 _("Thread no longer exists.")); \ 35 return NULL; \ 36 } \ 37 } while (0) 38 39 thread_object * 40 create_thread_object (struct thread_info *tp) 41 { 42 thread_object *thread_obj; 43 44 thread_obj = PyObject_New (thread_object, &thread_object_type); 45 if (!thread_obj) 46 return NULL; 47 48 thread_obj->thread = tp; 49 thread_obj->inf_obj = find_inferior_object (ptid_get_pid (tp->ptid)); 50 51 return thread_obj; 52 } 53 54 static void 55 thpy_dealloc (PyObject *self) 56 { 57 Py_DECREF (((thread_object *) self)->inf_obj); 58 Py_TYPE (self)->tp_free (self); 59 } 60 61 static PyObject * 62 thpy_get_name (PyObject *self, void *ignore) 63 { 64 thread_object *thread_obj = (thread_object *) self; 65 const char *name; 66 67 THPY_REQUIRE_VALID (thread_obj); 68 69 name = thread_obj->thread->name; 70 if (name == NULL) 71 name = target_thread_name (thread_obj->thread); 72 73 if (name == NULL) 74 Py_RETURN_NONE; 75 76 return PyString_FromString (name); 77 } 78 79 static int 80 thpy_set_name (PyObject *self, PyObject *newvalue, void *ignore) 81 { 82 thread_object *thread_obj = (thread_object *) self; 83 char *name; 84 85 if (! thread_obj->thread) 86 { 87 PyErr_SetString (PyExc_RuntimeError, _("Thread no longer exists.")); 88 return -1; 89 } 90 91 if (newvalue == NULL) 92 { 93 PyErr_SetString (PyExc_TypeError, 94 _("Cannot delete `name' attribute.")); 95 return -1; 96 } 97 else if (newvalue == Py_None) 98 name = NULL; 99 else if (! gdbpy_is_string (newvalue)) 100 { 101 PyErr_SetString (PyExc_TypeError, 102 _("The value of `name' must be a string.")); 103 return -1; 104 } 105 else 106 { 107 name = python_string_to_host_string (newvalue); 108 if (! name) 109 return -1; 110 } 111 112 xfree (thread_obj->thread->name); 113 thread_obj->thread->name = name; 114 115 return 0; 116 } 117 118 /* Getter for InferiorThread.num. */ 119 120 static PyObject * 121 thpy_get_num (PyObject *self, void *closure) 122 { 123 thread_object *thread_obj = (thread_object *) self; 124 125 THPY_REQUIRE_VALID (thread_obj); 126 127 return PyLong_FromLong (thread_obj->thread->per_inf_num); 128 } 129 130 /* Getter for InferiorThread.global_num. */ 131 132 static PyObject * 133 thpy_get_global_num (PyObject *self, void *closure) 134 { 135 thread_object *thread_obj = (thread_object *) self; 136 137 THPY_REQUIRE_VALID (thread_obj); 138 139 return PyLong_FromLong (thread_obj->thread->global_num); 140 } 141 142 /* Getter for InferiorThread.ptid -> (pid, lwp, tid). 143 Returns a tuple with the thread's ptid components. */ 144 145 static PyObject * 146 thpy_get_ptid (PyObject *self, void *closure) 147 { 148 thread_object *thread_obj = (thread_object *) self; 149 150 THPY_REQUIRE_VALID (thread_obj); 151 152 return gdbpy_create_ptid_object (thread_obj->thread->ptid); 153 } 154 155 /* Getter for InferiorThread.inferior -> Inferior. */ 156 157 static PyObject * 158 thpy_get_inferior (PyObject *self, void *ignore) 159 { 160 thread_object *thread_obj = (thread_object *) self; 161 162 THPY_REQUIRE_VALID (thread_obj); 163 164 return thread_obj->inf_obj; 165 } 166 167 /* Implementation of InferiorThread.switch (). 168 Makes this the GDB selected thread. */ 169 170 static PyObject * 171 thpy_switch (PyObject *self, PyObject *args) 172 { 173 thread_object *thread_obj = (thread_object *) self; 174 175 THPY_REQUIRE_VALID (thread_obj); 176 177 TRY 178 { 179 switch_to_thread (thread_obj->thread->ptid); 180 } 181 CATCH (except, RETURN_MASK_ALL) 182 { 183 GDB_PY_HANDLE_EXCEPTION (except); 184 } 185 END_CATCH 186 187 Py_RETURN_NONE; 188 } 189 190 /* Implementation of InferiorThread.is_stopped () -> Boolean. 191 Return whether the thread is stopped. */ 192 193 static PyObject * 194 thpy_is_stopped (PyObject *self, PyObject *args) 195 { 196 thread_object *thread_obj = (thread_object *) self; 197 198 THPY_REQUIRE_VALID (thread_obj); 199 200 if (is_stopped (thread_obj->thread->ptid)) 201 Py_RETURN_TRUE; 202 203 Py_RETURN_FALSE; 204 } 205 206 /* Implementation of InferiorThread.is_running () -> Boolean. 207 Return whether the thread is running. */ 208 209 static PyObject * 210 thpy_is_running (PyObject *self, PyObject *args) 211 { 212 thread_object *thread_obj = (thread_object *) self; 213 214 THPY_REQUIRE_VALID (thread_obj); 215 216 if (is_running (thread_obj->thread->ptid)) 217 Py_RETURN_TRUE; 218 219 Py_RETURN_FALSE; 220 } 221 222 /* Implementation of InferiorThread.is_exited () -> Boolean. 223 Return whether the thread is exited. */ 224 225 static PyObject * 226 thpy_is_exited (PyObject *self, PyObject *args) 227 { 228 thread_object *thread_obj = (thread_object *) self; 229 230 THPY_REQUIRE_VALID (thread_obj); 231 232 if (is_exited (thread_obj->thread->ptid)) 233 Py_RETURN_TRUE; 234 235 Py_RETURN_FALSE; 236 } 237 238 /* Implementation of gdb.InfThread.is_valid (self) -> Boolean. 239 Returns True if this inferior Thread object still exists 240 in GDB. */ 241 242 static PyObject * 243 thpy_is_valid (PyObject *self, PyObject *args) 244 { 245 thread_object *thread_obj = (thread_object *) self; 246 247 if (! thread_obj->thread) 248 Py_RETURN_FALSE; 249 250 Py_RETURN_TRUE; 251 } 252 253 /* Return a reference to a new Python object representing a ptid_t. 254 The object is a tuple containing (pid, lwp, tid). */ 255 PyObject * 256 gdbpy_create_ptid_object (ptid_t ptid) 257 { 258 int pid; 259 long tid, lwp; 260 PyObject *ret; 261 262 ret = PyTuple_New (3); 263 if (!ret) 264 return NULL; 265 266 pid = ptid_get_pid (ptid); 267 lwp = ptid_get_lwp (ptid); 268 tid = ptid_get_tid (ptid); 269 270 PyTuple_SET_ITEM (ret, 0, PyInt_FromLong (pid)); 271 PyTuple_SET_ITEM (ret, 1, PyInt_FromLong (lwp)); 272 PyTuple_SET_ITEM (ret, 2, PyInt_FromLong (tid)); 273 274 return ret; 275 } 276 277 /* Implementation of gdb.selected_thread () -> gdb.InferiorThread. 278 Returns the selected thread object. */ 279 280 PyObject * 281 gdbpy_selected_thread (PyObject *self, PyObject *args) 282 { 283 PyObject *thread_obj; 284 285 thread_obj = (PyObject *) find_thread_object (inferior_ptid); 286 if (thread_obj) 287 { 288 Py_INCREF (thread_obj); 289 return thread_obj; 290 } 291 292 Py_RETURN_NONE; 293 } 294 295 int 296 gdbpy_initialize_thread (void) 297 { 298 if (PyType_Ready (&thread_object_type) < 0) 299 return -1; 300 301 return gdb_pymodule_addobject (gdb_module, "InferiorThread", 302 (PyObject *) &thread_object_type); 303 } 304 305 static PyGetSetDef thread_object_getset[] = 306 { 307 { "name", thpy_get_name, thpy_set_name, 308 "The name of the thread, as set by the user or the OS.", NULL }, 309 { "num", thpy_get_num, NULL, 310 "Per-inferior number of the thread, as assigned by GDB.", NULL }, 311 { "global_num", thpy_get_global_num, NULL, 312 "Global number of the thread, as assigned by GDB.", NULL }, 313 { "ptid", thpy_get_ptid, NULL, "ID of the thread, as assigned by the OS.", 314 NULL }, 315 { "inferior", thpy_get_inferior, NULL, 316 "The Inferior object this thread belongs to.", NULL }, 317 318 { NULL } 319 }; 320 321 static PyMethodDef thread_object_methods[] = 322 { 323 { "is_valid", thpy_is_valid, METH_NOARGS, 324 "is_valid () -> Boolean.\n\ 325 Return true if this inferior thread is valid, false if not." }, 326 { "switch", thpy_switch, METH_NOARGS, 327 "switch ()\n\ 328 Makes this the GDB selected thread." }, 329 { "is_stopped", thpy_is_stopped, METH_NOARGS, 330 "is_stopped () -> Boolean\n\ 331 Return whether the thread is stopped." }, 332 { "is_running", thpy_is_running, METH_NOARGS, 333 "is_running () -> Boolean\n\ 334 Return whether the thread is running." }, 335 { "is_exited", thpy_is_exited, METH_NOARGS, 336 "is_exited () -> Boolean\n\ 337 Return whether the thread is exited." }, 338 339 { NULL } 340 }; 341 342 PyTypeObject thread_object_type = 343 { 344 PyVarObject_HEAD_INIT (NULL, 0) 345 "gdb.InferiorThread", /*tp_name*/ 346 sizeof (thread_object), /*tp_basicsize*/ 347 0, /*tp_itemsize*/ 348 thpy_dealloc, /*tp_dealloc*/ 349 0, /*tp_print*/ 350 0, /*tp_getattr*/ 351 0, /*tp_setattr*/ 352 0, /*tp_compare*/ 353 0, /*tp_repr*/ 354 0, /*tp_as_number*/ 355 0, /*tp_as_sequence*/ 356 0, /*tp_as_mapping*/ 357 0, /*tp_hash */ 358 0, /*tp_call*/ 359 0, /*tp_str*/ 360 0, /*tp_getattro*/ 361 0, /*tp_setattro*/ 362 0, /*tp_as_buffer*/ 363 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ 364 "GDB thread object", /* tp_doc */ 365 0, /* tp_traverse */ 366 0, /* tp_clear */ 367 0, /* tp_richcompare */ 368 0, /* tp_weaklistoffset */ 369 0, /* tp_iter */ 370 0, /* tp_iternext */ 371 thread_object_methods, /* tp_methods */ 372 0, /* tp_members */ 373 thread_object_getset, /* tp_getset */ 374 0, /* tp_base */ 375 0, /* tp_dict */ 376 0, /* tp_descr_get */ 377 0, /* tp_descr_set */ 378 0, /* tp_dictoffset */ 379 0, /* tp_init */ 380 0 /* tp_alloc */ 381 }; 382