]>
Commit | Line | Data |
---|---|---|
0e3b7c25 AB |
1 | /* Python interface to inferiors. |
2 | ||
4a94e368 | 3 | Copyright (C) 2009-2022 Free Software Foundation, Inc. |
0e3b7c25 AB |
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 "python-internal.h" | |
22 | #include "process-stratum-target.h" | |
23 | #include "inferior.h" | |
24 | #include "observable.h" | |
25 | #include "target-connection.h" | |
26 | #include "py-events.h" | |
27 | #include "py-event.h" | |
28 | #include "arch-utils.h" | |
24b2de7b AB |
29 | #include "remote.h" |
30 | #include "charset.h" | |
0e3b7c25 AB |
31 | |
32 | #include <map> | |
33 | ||
34 | /* The Python object that represents a connection. */ | |
35 | ||
36 | struct connection_object | |
37 | { | |
38 | PyObject_HEAD | |
39 | ||
40 | /* The process target that represents this connection. When a | |
41 | connection_object is created this field will always point at a valid | |
42 | target. Later, if GDB stops using this target (the target is popped | |
43 | from all target stacks) then this field is set to nullptr, which | |
44 | indicates that this Python object is now in the invalid state (see | |
45 | the is_valid() method below). */ | |
46 | struct process_stratum_target *target; | |
47 | }; | |
48 | ||
49 | extern PyTypeObject connection_object_type | |
50 | CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("connection_object"); | |
51 | ||
24b2de7b AB |
52 | extern PyTypeObject remote_connection_object_type |
53 | CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("remote_connection_object"); | |
54 | ||
0e3b7c25 AB |
55 | /* Require that CONNECTION be valid. */ |
56 | #define CONNPY_REQUIRE_VALID(connection) \ | |
57 | do { \ | |
58 | if (connection->target == nullptr) \ | |
59 | { \ | |
60 | PyErr_SetString (PyExc_RuntimeError, \ | |
61 | _("Connection no longer exists.")); \ | |
62 | return nullptr; \ | |
63 | } \ | |
64 | } while (0) | |
65 | ||
66 | /* A map between process_stratum targets and the Python object representing | |
67 | them. We actually hold a gdbpy_ref around the Python object so that | |
68 | reference counts are handled correctly when entries are deleted. */ | |
69 | static std::map<process_stratum_target *, | |
70 | gdbpy_ref<connection_object>> all_connection_objects; | |
71 | ||
72 | /* Return a reference to a gdb.TargetConnection object for TARGET. If | |
73 | TARGET is nullptr then a reference to None is returned. | |
74 | ||
75 | Previously created gdb.TargetConnection objects are cached, and | |
76 | additional references to the same connection object can be returned with | |
77 | later calls to this function. */ | |
78 | ||
79 | gdbpy_ref<> | |
80 | target_to_connection_object (process_stratum_target *target) | |
81 | { | |
82 | if (target == nullptr) | |
83 | return gdbpy_ref<>::new_reference (Py_None); | |
84 | ||
85 | gdbpy_ref <connection_object> conn_obj; | |
86 | auto conn_obj_iter = all_connection_objects.find (target); | |
87 | if (conn_obj_iter == all_connection_objects.end ()) | |
88 | { | |
24b2de7b AB |
89 | PyTypeObject *type; |
90 | ||
91 | if (is_remote_target (target)) | |
92 | type = &remote_connection_object_type; | |
93 | else | |
94 | type = &connection_object_type; | |
95 | ||
96 | conn_obj.reset (PyObject_New (connection_object, type)); | |
0e3b7c25 AB |
97 | if (conn_obj == nullptr) |
98 | return nullptr; | |
99 | conn_obj->target = target; | |
100 | all_connection_objects.emplace (target, conn_obj); | |
101 | } | |
102 | else | |
103 | conn_obj = conn_obj_iter->second; | |
104 | ||
105 | gdb_assert (conn_obj != nullptr); | |
106 | ||
107 | /* Repackage the result as a PyObject reference. */ | |
108 | return gdbpy_ref<> ((PyObject *) conn_obj.release ()); | |
109 | } | |
110 | ||
111 | /* Return a list of gdb.TargetConnection objects, one for each currently | |
112 | active connection. The returned list is in no particular order. */ | |
113 | ||
114 | PyObject * | |
115 | gdbpy_connections (PyObject *self, PyObject *args) | |
116 | { | |
117 | gdbpy_ref<> list (PyList_New (0)); | |
118 | if (list == nullptr) | |
119 | return nullptr; | |
120 | ||
121 | for (process_stratum_target *target : all_non_exited_process_targets ()) | |
122 | { | |
123 | gdb_assert (target != nullptr); | |
124 | ||
125 | gdbpy_ref<> conn = target_to_connection_object (target); | |
126 | if (conn == nullptr) | |
127 | return nullptr; | |
128 | gdb_assert (conn.get () != Py_None); | |
129 | ||
130 | if (PyList_Append (list.get (), conn.get ()) < 0) | |
131 | return nullptr; | |
132 | } | |
133 | ||
134 | return list.release (); | |
135 | } | |
136 | ||
137 | /* Emit a connection event for TARGET to REGISTRY. Return 0 on success, or | |
138 | a negative value on error. */ | |
139 | ||
140 | static int | |
141 | emit_connection_event (process_stratum_target *target, | |
142 | eventregistry_object *registry) | |
143 | { | |
144 | gdbpy_ref<> event_obj | |
145 | = create_event_object (&connection_event_object_type); | |
146 | if (event_obj == nullptr) | |
147 | return -1; | |
148 | ||
149 | gdbpy_ref<> conn = target_to_connection_object (target); | |
150 | if (evpy_add_attribute (event_obj.get (), "connection", conn.get ()) < 0) | |
151 | return -1; | |
152 | ||
153 | return evpy_emit_event (event_obj.get (), registry); | |
154 | } | |
155 | ||
156 | /* Callback for the connection_removed observer. */ | |
157 | ||
158 | static void | |
159 | connpy_connection_removed (process_stratum_target *target) | |
160 | { | |
161 | if (!gdb_python_initialized) | |
162 | return; | |
163 | ||
1da5d0e6 | 164 | gdbpy_enter enter_py; |
0e3b7c25 AB |
165 | |
166 | if (!evregpy_no_listeners_p (gdb_py_events.connection_removed)) | |
167 | if (emit_connection_event (target, gdb_py_events.connection_removed) < 0) | |
168 | gdbpy_print_stack (); | |
169 | ||
170 | auto conn_obj_iter = all_connection_objects.find (target); | |
171 | if (conn_obj_iter != all_connection_objects.end ()) | |
172 | { | |
173 | gdbpy_ref <connection_object> conn_obj = conn_obj_iter->second; | |
174 | conn_obj->target = nullptr; | |
175 | all_connection_objects.erase (target); | |
176 | } | |
177 | } | |
178 | ||
179 | /* Called when a gdb.TargetConnection object is deallocated. */ | |
180 | ||
181 | static void | |
182 | connpy_connection_dealloc (PyObject *obj) | |
183 | { | |
184 | connection_object *conn_obj = (connection_object *) obj; | |
185 | ||
186 | /* As the all_connection_objects map holds a reference to each connection | |
187 | object we can only enter the dealloc function when the reference in | |
188 | all_connection_objects has been erased. | |
189 | ||
190 | As we always set the target pointer back to nullptr before we erase | |
191 | items from all_connection_objects then, when we get here, the target | |
192 | pointer must be nullptr. */ | |
193 | gdb_assert (conn_obj->target == nullptr); | |
194 | ||
195 | Py_TYPE (obj)->tp_free (obj); | |
196 | } | |
197 | ||
198 | /* Implement repr() for gdb.TargetConnection. */ | |
199 | ||
200 | static PyObject * | |
201 | connpy_repr (PyObject *obj) | |
202 | { | |
203 | connection_object *self = (connection_object *) obj; | |
204 | process_stratum_target *target = self->target; | |
205 | ||
206 | if (target == nullptr) | |
5aee4587 | 207 | return PyUnicode_FromFormat ("<%s (invalid)>", Py_TYPE (obj)->tp_name); |
0e3b7c25 | 208 | |
5aee4587 SM |
209 | return PyUnicode_FromFormat ("<%s num=%d, what=\"%s\">", |
210 | Py_TYPE (obj)->tp_name, | |
211 | target->connection_number, | |
212 | make_target_connection_string (target).c_str ()); | |
0e3b7c25 AB |
213 | } |
214 | ||
215 | /* Implementation of gdb.TargetConnection.is_valid() -> Boolean. Returns | |
216 | True if this connection object is still associated with a | |
217 | process_stratum_target, otherwise, returns False. */ | |
218 | ||
219 | static PyObject * | |
220 | connpy_is_valid (PyObject *self, PyObject *args) | |
221 | { | |
222 | connection_object *conn = (connection_object *) self; | |
223 | ||
224 | if (conn->target == nullptr) | |
225 | Py_RETURN_FALSE; | |
226 | ||
227 | Py_RETURN_TRUE; | |
228 | } | |
229 | ||
230 | /* Return the id number of this connection. */ | |
231 | ||
232 | static PyObject * | |
233 | connpy_get_connection_num (PyObject *self, void *closure) | |
234 | { | |
235 | connection_object *conn = (connection_object *) self; | |
236 | ||
237 | CONNPY_REQUIRE_VALID (conn); | |
238 | ||
239 | auto num = conn->target->connection_number; | |
240 | return gdb_py_object_from_longest (num).release (); | |
241 | } | |
242 | ||
243 | /* Return a string that gives the short name for this connection type. */ | |
244 | ||
245 | static PyObject * | |
246 | connpy_get_connection_type (PyObject *self, void *closure) | |
247 | { | |
248 | connection_object *conn = (connection_object *) self; | |
249 | ||
250 | CONNPY_REQUIRE_VALID (conn); | |
251 | ||
252 | const char *shortname = conn->target->shortname (); | |
253 | return host_string_to_python_string (shortname).release (); | |
254 | } | |
255 | ||
256 | /* Return a string that gives a longer description of this connection type. */ | |
257 | ||
258 | static PyObject * | |
259 | connpy_get_description (PyObject *self, void *closure) | |
260 | { | |
261 | connection_object *conn = (connection_object *) self; | |
262 | ||
263 | CONNPY_REQUIRE_VALID (conn); | |
264 | ||
265 | const char *longname = conn->target->longname (); | |
266 | return host_string_to_python_string (longname).release (); | |
267 | } | |
268 | ||
269 | /* Return a string that gives additional details about this connection, or | |
270 | None, if there are no additional details for this connection type. */ | |
271 | ||
272 | static PyObject * | |
273 | connpy_get_connection_details (PyObject *self, void *closure) | |
274 | { | |
275 | connection_object *conn = (connection_object *) self; | |
276 | ||
277 | CONNPY_REQUIRE_VALID (conn); | |
278 | ||
279 | const char *details = conn->target->connection_string (); | |
280 | if (details != nullptr) | |
281 | return host_string_to_python_string (details).release (); | |
282 | else | |
283 | Py_RETURN_NONE; | |
284 | } | |
285 | ||
286 | /* Python specific initialization for this file. */ | |
287 | ||
288 | int | |
289 | gdbpy_initialize_connection (void) | |
290 | { | |
291 | if (PyType_Ready (&connection_object_type) < 0) | |
292 | return -1; | |
293 | ||
294 | if (gdb_pymodule_addobject (gdb_module, "TargetConnection", | |
295 | (PyObject *) &connection_object_type) < 0) | |
296 | return -1; | |
297 | ||
24b2de7b AB |
298 | if (PyType_Ready (&remote_connection_object_type) < 0) |
299 | return -1; | |
300 | ||
301 | if (gdb_pymodule_addobject (gdb_module, "RemoteTargetConnection", | |
302 | (PyObject *) &remote_connection_object_type) < 0) | |
303 | return -1; | |
304 | ||
0e3b7c25 AB |
305 | return 0; |
306 | } | |
307 | ||
24b2de7b AB |
308 | /* Set of callbacks used to implement gdb.send_packet. */ |
309 | ||
310 | struct py_send_packet_callbacks : public send_remote_packet_callbacks | |
311 | { | |
312 | /* Constructor, initialise the result to nullptr. It is invalid to try | |
313 | and read the result before sending a packet and processing the | |
314 | reply. */ | |
315 | ||
316 | py_send_packet_callbacks () | |
317 | : m_result (nullptr) | |
318 | { /* Nothing. */ } | |
319 | ||
320 | /* There's nothing to do when the packet is sent. */ | |
321 | ||
322 | void sending (gdb::array_view<const char> &buf) override | |
323 | { /* Nothing. */ } | |
324 | ||
325 | /* When the result is returned create a Python object and assign this | |
326 | into M_RESULT. If for any reason we can't create a Python object to | |
327 | represent the result then M_RESULT is set to nullptr, and Python's | |
328 | internal error flags will be set. If the result we got back from the | |
329 | remote is empty then set the result to None. */ | |
330 | ||
331 | void received (gdb::array_view<const char> &buf) override | |
332 | { | |
333 | if (buf.size () > 0 && buf.data ()[0] != '\0') | |
334 | m_result.reset (PyBytes_FromStringAndSize (buf.data (), buf.size ())); | |
335 | else | |
336 | { | |
337 | /* We didn't get back any result data; set the result to None. */ | |
338 | Py_INCREF (Py_None); | |
339 | m_result.reset (Py_None); | |
340 | } | |
341 | } | |
342 | ||
343 | /* Get a reference to the result as a Python object. It is invalid to | |
344 | call this before sending a packet to the remote and processing the | |
345 | reply. | |
346 | ||
347 | The result value is setup in the RECEIVED call above. If the RECEIVED | |
348 | call causes an error then the result value will be set to nullptr, | |
349 | and the error reason is left stored in Python's global error state. | |
350 | ||
351 | It is important that the result is inspected immediately after sending | |
352 | a packet to the remote, and any error fetched, calling any other | |
353 | Python functions that might clear the error state, or rely on an error | |
354 | not being set will cause undefined behaviour. */ | |
355 | ||
356 | gdbpy_ref<> result () const | |
357 | { | |
358 | return m_result; | |
359 | } | |
360 | ||
361 | private: | |
362 | ||
363 | /* A reference to the result value. */ | |
364 | ||
365 | gdbpy_ref<> m_result; | |
366 | }; | |
367 | ||
368 | /* Implement RemoteTargetConnection.send_packet function. Send a packet to | |
369 | the target identified by SELF. The connection must still be valid, and | |
370 | the packet to be sent must be non-empty, otherwise an exception will be | |
371 | thrown. */ | |
372 | ||
373 | static PyObject * | |
374 | connpy_send_packet (PyObject *self, PyObject *args, PyObject *kw) | |
375 | { | |
376 | connection_object *conn = (connection_object *) self; | |
377 | ||
378 | CONNPY_REQUIRE_VALID (conn); | |
379 | ||
380 | static const char *keywords[] = {"packet", nullptr}; | |
381 | PyObject *packet_obj; | |
382 | ||
383 | if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "O", keywords, | |
384 | &packet_obj)) | |
385 | return nullptr; | |
386 | ||
387 | /* If the packet is a unicode string then convert it to a bytes object. */ | |
388 | if (PyUnicode_Check (packet_obj)) | |
389 | { | |
390 | /* We encode the string to bytes using the ascii codec, if this fails | |
391 | then a suitable error will have been set. */ | |
392 | packet_obj = PyUnicode_AsASCIIString (packet_obj); | |
393 | if (packet_obj == nullptr) | |
394 | return nullptr; | |
395 | } | |
396 | ||
397 | /* Check the packet is now a bytes object. */ | |
398 | if (!PyBytes_Check (packet_obj)) | |
399 | { | |
400 | PyErr_SetString (PyExc_TypeError, _("Packet is not a bytes object")); | |
401 | return nullptr; | |
402 | } | |
403 | ||
404 | Py_ssize_t packet_len = 0; | |
405 | char *packet_str_nonconst = nullptr; | |
406 | if (PyBytes_AsStringAndSize (packet_obj, &packet_str_nonconst, | |
407 | &packet_len) < 0) | |
408 | return nullptr; | |
409 | const char *packet_str = packet_str_nonconst; | |
410 | gdb_assert (packet_str != nullptr); | |
411 | ||
412 | if (packet_len == 0) | |
413 | { | |
414 | PyErr_SetString (PyExc_ValueError, _("Packet must not be empty")); | |
415 | return nullptr; | |
416 | } | |
417 | ||
418 | try | |
419 | { | |
420 | scoped_restore_current_thread restore_thread; | |
421 | switch_to_target_no_thread (conn->target); | |
422 | ||
423 | gdb::array_view<const char> view (packet_str, packet_len); | |
424 | py_send_packet_callbacks callbacks; | |
425 | send_remote_packet (view, &callbacks); | |
426 | PyObject *result = callbacks.result ().release (); | |
427 | /* If we encountered an error converting the reply to a Python | |
428 | object, then the result here can be nullptr. In that case, Python | |
429 | should be aware that an error occurred. */ | |
430 | gdb_assert ((result == nullptr) == (PyErr_Occurred () != nullptr)); | |
431 | return result; | |
432 | } | |
433 | catch (const gdb_exception &except) | |
434 | { | |
435 | gdbpy_convert_exception (except); | |
436 | return nullptr; | |
437 | } | |
438 | } | |
439 | ||
0e3b7c25 AB |
440 | /* Global initialization for this file. */ |
441 | ||
442 | void _initialize_py_connection (); | |
443 | void | |
444 | _initialize_py_connection () | |
445 | { | |
446 | gdb::observers::connection_removed.attach (connpy_connection_removed, | |
447 | "py-connection"); | |
448 | } | |
449 | ||
450 | /* Methods for the gdb.TargetConnection object type. */ | |
451 | ||
452 | static PyMethodDef connection_object_methods[] = | |
453 | { | |
454 | { "is_valid", connpy_is_valid, METH_NOARGS, | |
455 | "is_valid () -> Boolean.\n\ | |
456 | Return true if this TargetConnection is valid, false if not." }, | |
457 | { NULL } | |
458 | }; | |
459 | ||
24b2de7b AB |
460 | /* Methods for the gdb.RemoteTargetConnection object type. */ |
461 | ||
462 | static PyMethodDef remote_connection_object_methods[] = | |
463 | { | |
464 | { "send_packet", (PyCFunction) connpy_send_packet, | |
465 | METH_VARARGS | METH_KEYWORDS, | |
466 | "send_packet (PACKET) -> Bytes\n\ | |
467 | Send PACKET to a remote target, return the reply as a bytes array." }, | |
468 | { NULL } | |
469 | }; | |
470 | ||
0e3b7c25 AB |
471 | /* Attributes for the gdb.TargetConnection object type. */ |
472 | ||
473 | static gdb_PyGetSetDef connection_object_getset[] = | |
474 | { | |
475 | { "num", connpy_get_connection_num, NULL, | |
476 | "ID number of this connection, as assigned by GDB.", NULL }, | |
477 | { "type", connpy_get_connection_type, NULL, | |
478 | "A short string that is the name for this connection type.", NULL }, | |
479 | { "description", connpy_get_description, NULL, | |
480 | "A longer string describing this connection type.", NULL }, | |
481 | { "details", connpy_get_connection_details, NULL, | |
482 | "A string containing additional connection details.", NULL }, | |
483 | { NULL } | |
484 | }; | |
485 | ||
486 | /* Define the gdb.TargetConnection object type. */ | |
487 | ||
488 | PyTypeObject connection_object_type = | |
489 | { | |
490 | PyVarObject_HEAD_INIT (NULL, 0) | |
491 | "gdb.TargetConnection", /* tp_name */ | |
492 | sizeof (connection_object), /* tp_basicsize */ | |
493 | 0, /* tp_itemsize */ | |
494 | connpy_connection_dealloc, /* tp_dealloc */ | |
495 | 0, /* tp_print */ | |
496 | 0, /* tp_getattr */ | |
497 | 0, /* tp_setattr */ | |
498 | 0, /* tp_compare */ | |
499 | connpy_repr, /* tp_repr */ | |
500 | 0, /* tp_as_number */ | |
501 | 0, /* tp_as_sequence */ | |
502 | 0, /* tp_as_mapping */ | |
503 | 0, /* tp_hash */ | |
504 | 0, /* tp_call */ | |
505 | 0, /* tp_str */ | |
506 | 0, /* tp_getattro */ | |
507 | 0, /* tp_setattro */ | |
508 | 0, /* tp_as_buffer */ | |
24b2de7b | 509 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
0e3b7c25 AB |
510 | "GDB target connection object", /* tp_doc */ |
511 | 0, /* tp_traverse */ | |
512 | 0, /* tp_clear */ | |
513 | 0, /* tp_richcompare */ | |
514 | 0, /* tp_weaklistoffset */ | |
515 | 0, /* tp_iter */ | |
516 | 0, /* tp_iternext */ | |
517 | connection_object_methods, /* tp_methods */ | |
518 | 0, /* tp_members */ | |
519 | connection_object_getset, /* tp_getset */ | |
520 | 0, /* tp_base */ | |
521 | 0, /* tp_dict */ | |
522 | 0, /* tp_descr_get */ | |
523 | 0, /* tp_descr_set */ | |
524 | 0, /* tp_dictoffset */ | |
525 | 0, /* tp_init */ | |
526 | 0 /* tp_alloc */ | |
527 | }; | |
24b2de7b AB |
528 | |
529 | /* Define the gdb.RemoteTargetConnection object type. */ | |
530 | ||
531 | PyTypeObject remote_connection_object_type = | |
532 | { | |
533 | PyVarObject_HEAD_INIT (NULL, 0) | |
534 | "gdb.RemoteTargetConnection", /* tp_name */ | |
535 | sizeof (connection_object), /* tp_basicsize */ | |
536 | 0, /* tp_itemsize */ | |
537 | connpy_connection_dealloc, /* tp_dealloc */ | |
538 | 0, /* tp_print */ | |
539 | 0, /* tp_getattr */ | |
540 | 0, /* tp_setattr */ | |
541 | 0, /* tp_compare */ | |
542 | connpy_repr, /* tp_repr */ | |
543 | 0, /* tp_as_number */ | |
544 | 0, /* tp_as_sequence */ | |
545 | 0, /* tp_as_mapping */ | |
546 | 0, /* tp_hash */ | |
547 | 0, /* tp_call */ | |
548 | 0, /* tp_str */ | |
549 | 0, /* tp_getattro */ | |
550 | 0, /* tp_setattro */ | |
551 | 0, /* tp_as_buffer */ | |
552 | Py_TPFLAGS_DEFAULT, /* tp_flags */ | |
553 | "GDB remote target connection object", /* tp_doc */ | |
554 | 0, /* tp_traverse */ | |
555 | 0, /* tp_clear */ | |
556 | 0, /* tp_richcompare */ | |
557 | 0, /* tp_weaklistoffset */ | |
558 | 0, /* tp_iter */ | |
559 | 0, /* tp_iternext */ | |
560 | remote_connection_object_methods, /* tp_methods */ | |
561 | 0, /* tp_members */ | |
562 | 0, /* tp_getset */ | |
563 | &connection_object_type, /* tp_base */ | |
564 | 0, /* tp_dict */ | |
565 | 0, /* tp_descr_get */ | |
566 | 0, /* tp_descr_set */ | |
567 | 0, /* tp_dictoffset */ | |
568 | 0, /* tp_init */ | |
569 | 0 /* tp_alloc */ | |
570 | }; |