1 /* Python interface to inferior threads. 2 3 Copyright (C) 2009-2017 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 gdb::unique_xmalloc_ptr<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 { 99 /* Nothing. */ 100 } 101 else if (! gdbpy_is_string (newvalue)) 102 { 103 PyErr_SetString (PyExc_TypeError, 104 _("The value of `name' must be a string.")); 105 return -1; 106 } 107 else 108 { 109 name = python_string_to_host_string (newvalue); 110 if (! name) 111 return -1; 112 } 113 114 xfree (thread_obj->thread->name); 115 thread_obj->thread->name = name.release (); 116 117 return 0; 118 } 119 120 /* Getter for InferiorThread.num. */ 121 122 static PyObject * 123 thpy_get_num (PyObject *self, void *closure) 124 { 125 thread_object *thread_obj = (thread_object *) self; 126 127 THPY_REQUIRE_VALID (thread_obj); 128 129 return PyLong_FromLong (thread_obj->thread->per_inf_num); 130 } 131 132 /* Getter for InferiorThread.global_num. */ 133 134 static PyObject * 135 thpy_get_global_num (PyObject *self, void *closure) 136 { 137 thread_object *thread_obj = (thread_object *) self; 138 139 THPY_REQUIRE_VALID (thread_obj); 140 141 return PyLong_FromLong (thread_obj->thread->global_num); 142 } 143 144 /* Getter for InferiorThread.ptid -> (pid, lwp, tid). 145 Returns a tuple with the thread's ptid components. */ 146 147 static PyObject * 148 thpy_get_ptid (PyObject *self, void *closure) 149 { 150 thread_object *thread_obj = (thread_object *) self; 151 152 THPY_REQUIRE_VALID (thread_obj); 153 154 return gdbpy_create_ptid_object (thread_obj->thread->ptid); 155 } 156 157 /* Getter for InferiorThread.inferior -> Inferior. */ 158 159 static PyObject * 160 thpy_get_inferior (PyObject *self, void *ignore) 161 { 162 thread_object *thread_obj = (thread_object *) self; 163 164 THPY_REQUIRE_VALID (thread_obj); 165 166 return thread_obj->inf_obj; 167 } 168 169 /* Implementation of InferiorThread.switch (). 170 Makes this the GDB selected thread. */ 171 172 static PyObject * 173 thpy_switch (PyObject *self, PyObject *args) 174 { 175 thread_object *thread_obj = (thread_object *) self; 176 177 THPY_REQUIRE_VALID (thread_obj); 178 179 TRY 180 { 181 switch_to_thread (thread_obj->thread->ptid); 182 } 183 CATCH (except, RETURN_MASK_ALL) 184 { 185 GDB_PY_HANDLE_EXCEPTION (except); 186 } 187 END_CATCH 188 189 Py_RETURN_NONE; 190 } 191 192 /* Implementation of InferiorThread.is_stopped () -> Boolean. 193 Return whether the thread is stopped. */ 194 195 static PyObject * 196 thpy_is_stopped (PyObject *self, PyObject *args) 197 { 198 thread_object *thread_obj = (thread_object *) self; 199 200 THPY_REQUIRE_VALID (thread_obj); 201 202 if (is_stopped (thread_obj->thread->ptid)) 203 Py_RETURN_TRUE; 204 205 Py_RETURN_FALSE; 206 } 207 208 /* Implementation of InferiorThread.is_running () -> Boolean. 209 Return whether the thread is running. */ 210 211 static PyObject * 212 thpy_is_running (PyObject *self, PyObject *args) 213 { 214 thread_object *thread_obj = (thread_object *) self; 215 216 THPY_REQUIRE_VALID (thread_obj); 217 218 if (is_running (thread_obj->thread->ptid)) 219 Py_RETURN_TRUE; 220 221 Py_RETURN_FALSE; 222 } 223 224 /* Implementation of InferiorThread.is_exited () -> Boolean. 225 Return whether the thread is exited. */ 226 227 static PyObject * 228 thpy_is_exited (PyObject *self, PyObject *args) 229 { 230 thread_object *thread_obj = (thread_object *) self; 231 232 THPY_REQUIRE_VALID (thread_obj); 233 234 if (is_exited (thread_obj->thread->ptid)) 235 Py_RETURN_TRUE; 236 237 Py_RETURN_FALSE; 238 } 239 240 /* Implementation of gdb.InfThread.is_valid (self) -> Boolean. 241 Returns True if this inferior Thread object still exists 242 in GDB. */ 243 244 static PyObject * 245 thpy_is_valid (PyObject *self, PyObject *args) 246 { 247 thread_object *thread_obj = (thread_object *) self; 248 249 if (! thread_obj->thread) 250 Py_RETURN_FALSE; 251 252 Py_RETURN_TRUE; 253 } 254 255 /* Return a reference to a new Python object representing a ptid_t. 256 The object is a tuple containing (pid, lwp, tid). */ 257 PyObject * 258 gdbpy_create_ptid_object (ptid_t ptid) 259 { 260 int pid; 261 long tid, lwp; 262 PyObject *ret; 263 264 ret = PyTuple_New (3); 265 if (!ret) 266 return NULL; 267 268 pid = ptid_get_pid (ptid); 269 lwp = ptid_get_lwp (ptid); 270 tid = ptid_get_tid (ptid); 271 272 PyTuple_SET_ITEM (ret, 0, PyInt_FromLong (pid)); 273 PyTuple_SET_ITEM (ret, 1, PyInt_FromLong (lwp)); 274 PyTuple_SET_ITEM (ret, 2, PyInt_FromLong (tid)); 275 276 return ret; 277 } 278 279 /* Implementation of gdb.selected_thread () -> gdb.InferiorThread. 280 Returns the selected thread object. */ 281 282 PyObject * 283 gdbpy_selected_thread (PyObject *self, PyObject *args) 284 { 285 PyObject *thread_obj; 286 287 thread_obj = (PyObject *) find_thread_object (inferior_ptid); 288 if (thread_obj) 289 { 290 Py_INCREF (thread_obj); 291 return thread_obj; 292 } 293 294 Py_RETURN_NONE; 295 } 296 297 int 298 gdbpy_initialize_thread (void) 299 { 300 if (PyType_Ready (&thread_object_type) < 0) 301 return -1; 302 303 return gdb_pymodule_addobject (gdb_module, "InferiorThread", 304 (PyObject *) &thread_object_type); 305 } 306 307 static gdb_PyGetSetDef thread_object_getset[] = 308 { 309 { "name", thpy_get_name, thpy_set_name, 310 "The name of the thread, as set by the user or the OS.", NULL }, 311 { "num", thpy_get_num, NULL, 312 "Per-inferior number of the thread, as assigned by GDB.", NULL }, 313 { "global_num", thpy_get_global_num, NULL, 314 "Global number of the thread, as assigned by GDB.", NULL }, 315 { "ptid", thpy_get_ptid, NULL, "ID of the thread, as assigned by the OS.", 316 NULL }, 317 { "inferior", thpy_get_inferior, NULL, 318 "The Inferior object this thread belongs to.", NULL }, 319 320 { NULL } 321 }; 322 323 static PyMethodDef thread_object_methods[] = 324 { 325 { "is_valid", thpy_is_valid, METH_NOARGS, 326 "is_valid () -> Boolean.\n\ 327 Return true if this inferior thread is valid, false if not." }, 328 { "switch", thpy_switch, METH_NOARGS, 329 "switch ()\n\ 330 Makes this the GDB selected thread." }, 331 { "is_stopped", thpy_is_stopped, METH_NOARGS, 332 "is_stopped () -> Boolean\n\ 333 Return whether the thread is stopped." }, 334 { "is_running", thpy_is_running, METH_NOARGS, 335 "is_running () -> Boolean\n\ 336 Return whether the thread is running." }, 337 { "is_exited", thpy_is_exited, METH_NOARGS, 338 "is_exited () -> Boolean\n\ 339 Return whether the thread is exited." }, 340 341 { NULL } 342 }; 343 344 PyTypeObject thread_object_type = 345 { 346 PyVarObject_HEAD_INIT (NULL, 0) 347 "gdb.InferiorThread", /*tp_name*/ 348 sizeof (thread_object), /*tp_basicsize*/ 349 0, /*tp_itemsize*/ 350 thpy_dealloc, /*tp_dealloc*/ 351 0, /*tp_print*/ 352 0, /*tp_getattr*/ 353 0, /*tp_setattr*/ 354 0, /*tp_compare*/ 355 0, /*tp_repr*/ 356 0, /*tp_as_number*/ 357 0, /*tp_as_sequence*/ 358 0, /*tp_as_mapping*/ 359 0, /*tp_hash */ 360 0, /*tp_call*/ 361 0, /*tp_str*/ 362 0, /*tp_getattro*/ 363 0, /*tp_setattro*/ 364 0, /*tp_as_buffer*/ 365 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ 366 "GDB thread object", /* tp_doc */ 367 0, /* tp_traverse */ 368 0, /* tp_clear */ 369 0, /* tp_richcompare */ 370 0, /* tp_weaklistoffset */ 371 0, /* tp_iter */ 372 0, /* tp_iternext */ 373 thread_object_methods, /* tp_methods */ 374 0, /* tp_members */ 375 thread_object_getset, /* tp_getset */ 376 0, /* tp_base */ 377 0, /* tp_dict */ 378 0, /* tp_descr_get */ 379 0, /* tp_descr_set */ 380 0, /* tp_dictoffset */ 381 0, /* tp_init */ 382 0 /* tp_alloc */ 383 }; 384