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