1 /* Support for debug methods in Python.
2 
3    Copyright (C) 2013-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 "arch-utils.h"
21 #include "extension-priv.h"
22 #include "objfiles.h"
23 #include "value.h"
24 #include "language.h"
25 
26 #include "python.h"
27 #include "python-internal.h"
28 
29 static const char enabled_field_name[] = "enabled";
30 static const char match_method_name[] = "match";
31 static const char get_arg_types_method_name[] = "get_arg_types";
32 static const char get_result_type_method_name[] = "get_result_type";
33 static const char matchers_attr_str[] = "xmethods";
34 
35 static PyObject *py_match_method_name = NULL;
36 static PyObject *py_get_arg_types_method_name = NULL;
37 
38 struct python_xmethod_worker : xmethod_worker
39 {
40   python_xmethod_worker (PyObject *worker, PyObject *this_type);
41   ~python_xmethod_worker ();
42 
43   DISABLE_COPY_AND_ASSIGN (python_xmethod_worker);
44 
45   /* Implementation of xmethod_worker::invoke for Python.  */
46 
47   value *invoke (value *obj, gdb::array_view<value *> args) override;
48 
49   /* Implementation of xmethod_worker::do_get_arg_types for Python.  */
50 
51   ext_lang_rc do_get_arg_types (std::vector<type *> *type_args) override;
52 
53   /* Implementation of xmethod_worker::do_get_result_type for Python.
54 
55      For backward compatibility with 7.9, which did not support getting the
56      result type, if the get_result_type operation is not provided by WORKER
57      then EXT_LANG_RC_OK is returned and NULL is returned in *RESULT_TYPE.  */
58 
59   ext_lang_rc do_get_result_type (value *obj, gdb::array_view<value *> args,
60                                           type **result_type_ptr) override;
61 
62 private:
63 
64   PyObject *m_py_worker;
65   PyObject *m_this_type;
66 };
67 
~python_xmethod_worker()68 python_xmethod_worker::~python_xmethod_worker ()
69 {
70   /* We don't do much here, but we still need the GIL.  */
71   gdbpy_enter enter_py;
72 
73   Py_DECREF (m_py_worker);
74   Py_DECREF (m_this_type);
75 }
76 
77 /* Invoke the "match" method of the MATCHER and return a new reference
78    to the result.  Returns NULL on error.  */
79 
80 static PyObject *
invoke_match_method(PyObject * matcher,PyObject * py_obj_type,const char * xmethod_name)81 invoke_match_method (PyObject *matcher, PyObject *py_obj_type,
82                          const char *xmethod_name)
83 {
84   int enabled;
85 
86   gdbpy_ref<> enabled_field (PyObject_GetAttrString (matcher,
87                                                                  enabled_field_name));
88   if (enabled_field == NULL)
89     return NULL;
90 
91   enabled = PyObject_IsTrue (enabled_field.get ());
92   if (enabled == -1)
93     return NULL;
94   if (enabled == 0)
95     {
96       /* Return 'None' if the matcher is not enabled.  */
97       Py_RETURN_NONE;
98     }
99 
100   gdbpy_ref<> match_method (PyObject_GetAttrString (matcher,
101                                                                 match_method_name));
102   if (match_method == NULL)
103     return NULL;
104 
105   gdbpy_ref<> py_xmethod_name (PyUnicode_FromString (xmethod_name));
106   if (py_xmethod_name == NULL)
107     return NULL;
108 
109   return PyObject_CallMethodObjArgs (matcher, py_match_method_name,
110                                              py_obj_type, py_xmethod_name.get (),
111                                              NULL);
112 }
113 
114 /* Implementation of get_matching_xmethod_workers for Python.  */
115 
116 enum ext_lang_rc
gdbpy_get_matching_xmethod_workers(const struct extension_language_defn * extlang,struct type * obj_type,const char * method_name,std::vector<xmethod_worker_up> * dm_vec)117 gdbpy_get_matching_xmethod_workers
118   (const struct extension_language_defn *extlang,
119    struct type *obj_type, const char *method_name,
120    std::vector<xmethod_worker_up> *dm_vec)
121 {
122   gdb_assert (obj_type != NULL && method_name != NULL);
123 
124   gdbpy_enter enter_py;
125 
126   gdbpy_ref<> py_type (type_to_type_object (obj_type));
127   if (py_type == NULL)
128     {
129       gdbpy_print_stack ();
130       return EXT_LANG_RC_ERROR;
131     }
132 
133   /* Create an empty list of debug methods.  */
134   gdbpy_ref<> py_xmethod_matcher_list (PyList_New (0));
135   if (py_xmethod_matcher_list == NULL)
136     {
137       gdbpy_print_stack ();
138       return EXT_LANG_RC_ERROR;
139     }
140 
141   /* Gather debug method matchers registered with the object files.
142      This could be done differently by iterating over each objfile's matcher
143      list individually, but there's no data yet to show it's needed.  */
144   for (objfile *objfile : current_program_space->objfiles ())
145     {
146       gdbpy_ref<> py_objfile = objfile_to_objfile_object (objfile);
147 
148       if (py_objfile == NULL)
149           {
150             gdbpy_print_stack ();
151             return EXT_LANG_RC_ERROR;
152           }
153 
154       gdbpy_ref<> objfile_matchers (objfpy_get_xmethods (py_objfile.get (),
155                                                                        NULL));
156       gdbpy_ref<> temp (PySequence_Concat (py_xmethod_matcher_list.get (),
157                                                      objfile_matchers.get ()));
158       if (temp == NULL)
159           {
160             gdbpy_print_stack ();
161             return EXT_LANG_RC_ERROR;
162           }
163 
164       py_xmethod_matcher_list = std::move (temp);
165     }
166 
167   /* Gather debug methods matchers registered with the current program
168      space.  */
169   gdbpy_ref<> py_progspace = pspace_to_pspace_object (current_program_space);
170   if (py_progspace != NULL)
171     {
172       gdbpy_ref<> pspace_matchers (pspy_get_xmethods (py_progspace.get (),
173                                                                   NULL));
174 
175       gdbpy_ref<> temp (PySequence_Concat (py_xmethod_matcher_list.get (),
176                                                      pspace_matchers.get ()));
177       if (temp == NULL)
178           {
179             gdbpy_print_stack ();
180             return EXT_LANG_RC_ERROR;
181           }
182 
183       py_xmethod_matcher_list = std::move (temp);
184     }
185   else
186     {
187       gdbpy_print_stack ();
188       return EXT_LANG_RC_ERROR;
189     }
190 
191   /* Gather debug method matchers registered globally.  */
192   if (gdb_python_module != NULL
193       && PyObject_HasAttrString (gdb_python_module, matchers_attr_str))
194     {
195       gdbpy_ref<> gdb_matchers (PyObject_GetAttrString (gdb_python_module,
196                                                                       matchers_attr_str));
197       if (gdb_matchers != NULL)
198           {
199             gdbpy_ref<> temp (PySequence_Concat (py_xmethod_matcher_list.get (),
200                                                          gdb_matchers.get ()));
201             if (temp == NULL)
202               {
203                 gdbpy_print_stack ();
204                 return EXT_LANG_RC_ERROR;
205               }
206 
207             py_xmethod_matcher_list = std::move (temp);
208           }
209       else
210           {
211             gdbpy_print_stack ();
212             return EXT_LANG_RC_ERROR;
213           }
214     }
215 
216   gdbpy_ref<> list_iter (PyObject_GetIter (py_xmethod_matcher_list.get ()));
217   if (list_iter == NULL)
218     {
219       gdbpy_print_stack ();
220       return EXT_LANG_RC_ERROR;
221     }
222   while (true)
223     {
224       gdbpy_ref<> matcher (PyIter_Next (list_iter.get ()));
225       if (matcher == NULL)
226           {
227             if (PyErr_Occurred ())
228               {
229                 gdbpy_print_stack ();
230                 return EXT_LANG_RC_ERROR;
231               }
232             break;
233           }
234 
235       gdbpy_ref<> match_result (invoke_match_method (matcher.get (),
236                                                                  py_type.get (),
237                                                                  method_name));
238 
239       if (match_result == NULL)
240           {
241             gdbpy_print_stack ();
242             return EXT_LANG_RC_ERROR;
243           }
244       if (match_result == Py_None)
245           ; /* This means there was no match.  */
246       else if (PySequence_Check (match_result.get ()))
247           {
248             gdbpy_ref<> iter (PyObject_GetIter (match_result.get ()));
249 
250             if (iter == NULL)
251               {
252                 gdbpy_print_stack ();
253                 return EXT_LANG_RC_ERROR;
254               }
255             while (true)
256               {
257                 struct xmethod_worker *worker;
258 
259                 gdbpy_ref<> py_worker (PyIter_Next (iter.get ()));
260                 if (py_worker == NULL)
261                     {
262                       if (PyErr_Occurred ())
263                         {
264                           gdbpy_print_stack ();
265                           return EXT_LANG_RC_ERROR;
266                         }
267                       break;
268                     }
269 
270                 worker = new python_xmethod_worker (py_worker.get (),
271                                                               py_type.get ());
272 
273                 dm_vec->emplace_back (worker);
274               }
275           }
276       else
277           {
278             struct xmethod_worker *worker;
279 
280             worker = new python_xmethod_worker (match_result.get (),
281                                                         py_type.get ());
282             dm_vec->emplace_back (worker);
283           }
284     }
285 
286   return EXT_LANG_RC_OK;
287 }
288 
289 /* See declaration.  */
290 
291 ext_lang_rc
do_get_arg_types(std::vector<type * > * arg_types)292 python_xmethod_worker::do_get_arg_types (std::vector<type *> *arg_types)
293 {
294   /* The gdbpy_enter object needs to be placed first, so that it's the last to
295      be destroyed.  */
296   gdbpy_enter enter_py;
297   struct type *obj_type;
298   int i = 1, arg_count;
299   gdbpy_ref<> list_iter;
300 
301   gdbpy_ref<> get_arg_types_method
302     (PyObject_GetAttrString (m_py_worker, get_arg_types_method_name));
303   if (get_arg_types_method == NULL)
304     {
305       gdbpy_print_stack ();
306       return EXT_LANG_RC_ERROR;
307     }
308 
309   gdbpy_ref<> py_argtype_list
310     (PyObject_CallMethodObjArgs (m_py_worker, py_get_arg_types_method_name,
311                                          NULL));
312   if (py_argtype_list == NULL)
313     {
314       gdbpy_print_stack ();
315       return EXT_LANG_RC_ERROR;
316     }
317 
318   if (py_argtype_list == Py_None)
319     arg_count = 0;
320   else if (PySequence_Check (py_argtype_list.get ()))
321     {
322       arg_count = PySequence_Size (py_argtype_list.get ());
323       if (arg_count == -1)
324           {
325             gdbpy_print_stack ();
326             return EXT_LANG_RC_ERROR;
327           }
328 
329       list_iter.reset (PyObject_GetIter (py_argtype_list.get ()));
330       if (list_iter == NULL)
331           {
332             gdbpy_print_stack ();
333             return EXT_LANG_RC_ERROR;
334           }
335     }
336   else
337     arg_count = 1;
338 
339   /* Include the 'this' argument in the size.  */
340   arg_types->resize (arg_count + 1);
341   i = 1;
342   if (list_iter != NULL)
343     {
344       while (true)
345           {
346             gdbpy_ref<> item (PyIter_Next (list_iter.get ()));
347             if (item == NULL)
348               {
349                 if (PyErr_Occurred ())
350                     {
351                       gdbpy_print_stack ();
352                       return EXT_LANG_RC_ERROR;
353                     }
354                 break;
355               }
356 
357             struct type *arg_type = type_object_to_type (item.get ());
358             if (arg_type == NULL)
359               {
360                 PyErr_SetString (PyExc_TypeError,
361                                      _("Arg type returned by the get_arg_types "
362                                          "method of a debug method worker object is "
363                                          "not a gdb.Type object."));
364                 return EXT_LANG_RC_ERROR;
365               }
366 
367             (*arg_types)[i] = arg_type;
368             i++;
369           }
370     }
371   else if (arg_count == 1)
372     {
373       /* py_argtype_list is not actually a list but a single gdb.Type
374            object.  */
375       struct type *arg_type = type_object_to_type (py_argtype_list.get ());
376 
377       if (arg_type == NULL)
378           {
379             PyErr_SetString (PyExc_TypeError,
380                                  _("Arg type returned by the get_arg_types method "
381                                    "of an xmethod worker object is not a gdb.Type "
382                                    "object."));
383             return EXT_LANG_RC_ERROR;
384           }
385       else
386           {
387             (*arg_types)[i] = arg_type;
388             i++;
389           }
390     }
391 
392   /* Add the type of 'this' as the first argument.  The 'this' pointer should
393      be a 'const' value.  Hence, create a 'const' variant of the 'this' pointer
394      type.  */
395   obj_type = type_object_to_type (m_this_type);
396   (*arg_types)[0] = make_cv_type (1, 0, lookup_pointer_type (obj_type),
397                                           NULL);
398 
399   return EXT_LANG_RC_OK;
400 }
401 
402 /* See declaration.  */
403 
404 ext_lang_rc
do_get_result_type(value * obj,gdb::array_view<value * > args,type ** result_type_ptr)405 python_xmethod_worker::do_get_result_type (value *obj,
406                                                      gdb::array_view<value *> args,
407                                                      type **result_type_ptr)
408 {
409   struct type *obj_type, *this_type;
410   int i;
411 
412   gdbpy_enter enter_py;
413 
414   /* First see if there is a get_result_type method.
415      If not this could be an old xmethod (pre 7.9.1).  */
416   gdbpy_ref<> get_result_type_method
417     (PyObject_GetAttrString (m_py_worker, get_result_type_method_name));
418   if (get_result_type_method == NULL)
419     {
420       PyErr_Clear ();
421       *result_type_ptr = NULL;
422       return EXT_LANG_RC_OK;
423     }
424 
425   scoped_value_mark free_values;
426   obj_type = check_typedef (obj->type ());
427   this_type = check_typedef (type_object_to_type (m_this_type));
428   if (obj_type->code () == TYPE_CODE_PTR)
429     {
430       struct type *this_ptr = lookup_pointer_type (this_type);
431 
432       if (!types_equal (obj_type, this_ptr))
433           obj = value_cast (this_ptr, obj);
434     }
435   else if (TYPE_IS_REFERENCE (obj_type))
436     {
437       struct type *this_ref
438           = lookup_reference_type (this_type, obj_type->code ());
439 
440       if (!types_equal (obj_type, this_ref))
441           obj = value_cast (this_ref, obj);
442     }
443   else
444     {
445       if (!types_equal (obj_type, this_type))
446           obj = value_cast (this_type, obj);
447     }
448   gdbpy_ref<> py_value_obj (value_to_value_object (obj));
449   if (py_value_obj == NULL)
450     {
451       gdbpy_print_stack ();
452       return EXT_LANG_RC_ERROR;
453     }
454 
455   gdbpy_ref<> py_arg_tuple (PyTuple_New (args.size () + 1));
456   if (py_arg_tuple == NULL)
457     {
458       gdbpy_print_stack ();
459       return EXT_LANG_RC_ERROR;
460     }
461 
462   /* PyTuple_SET_ITEM steals the reference of the element, hence the
463      release.  */
464   PyTuple_SET_ITEM (py_arg_tuple.get (), 0, py_value_obj.release ());
465 
466   for (i = 0; i < args.size (); i++)
467     {
468       PyObject *py_value_arg = value_to_value_object (args[i]);
469 
470       if (py_value_arg == NULL)
471           {
472             gdbpy_print_stack ();
473             return EXT_LANG_RC_ERROR;
474           }
475       PyTuple_SET_ITEM (py_arg_tuple.get (), i + 1, py_value_arg);
476     }
477 
478   gdbpy_ref<> py_result_type
479     (PyObject_CallObject (get_result_type_method.get (), py_arg_tuple.get ()));
480   if (py_result_type == NULL)
481     {
482       gdbpy_print_stack ();
483       return EXT_LANG_RC_ERROR;
484     }
485 
486   *result_type_ptr = type_object_to_type (py_result_type.get ());
487   if (*result_type_ptr == NULL)
488     {
489       PyErr_SetString (PyExc_TypeError,
490                            _("Type returned by the get_result_type method of an"
491                                " xmethod worker object is not a gdb.Type object."));
492       gdbpy_print_stack ();
493       return EXT_LANG_RC_ERROR;
494     }
495 
496   return EXT_LANG_RC_OK;
497 }
498 
499 /* See declaration.  */
500 
501 struct value *
invoke(struct value * obj,gdb::array_view<value * > args)502 python_xmethod_worker::invoke (struct value *obj,
503                                      gdb::array_view<value *> args)
504 {
505   gdbpy_enter enter_py;
506 
507   int i;
508   struct type *obj_type, *this_type;
509   struct value *res = NULL;
510 
511   obj_type = check_typedef (obj->type ());
512   this_type = check_typedef (type_object_to_type (m_this_type));
513   if (obj_type->code () == TYPE_CODE_PTR)
514     {
515       struct type *this_ptr = lookup_pointer_type (this_type);
516 
517       if (!types_equal (obj_type, this_ptr))
518           obj = value_cast (this_ptr, obj);
519     }
520   else if (TYPE_IS_REFERENCE (obj_type))
521     {
522       struct type *this_ref
523           = lookup_reference_type (this_type, obj_type->code ());
524 
525       if (!types_equal (obj_type, this_ref))
526           obj = value_cast (this_ref, obj);
527     }
528   else
529     {
530       if (!types_equal (obj_type, this_type))
531           obj = value_cast (this_type, obj);
532     }
533   gdbpy_ref<> py_value_obj (value_to_value_object (obj));
534   if (py_value_obj == NULL)
535     {
536       gdbpy_print_stack ();
537       error (_("Error while executing Python code."));
538     }
539 
540   gdbpy_ref<> py_arg_tuple (PyTuple_New (args.size () + 1));
541   if (py_arg_tuple == NULL)
542     {
543       gdbpy_print_stack ();
544       error (_("Error while executing Python code."));
545     }
546 
547   /* PyTuple_SET_ITEM steals the reference of the element, hence the
548      release.  */
549   PyTuple_SET_ITEM (py_arg_tuple.get (), 0, py_value_obj.release ());
550 
551   for (i = 0; i < args.size (); i++)
552     {
553       PyObject *py_value_arg = value_to_value_object (args[i]);
554 
555       if (py_value_arg == NULL)
556           {
557             gdbpy_print_stack ();
558             error (_("Error while executing Python code."));
559           }
560 
561       PyTuple_SET_ITEM (py_arg_tuple.get (), i + 1, py_value_arg);
562     }
563 
564   gdbpy_ref<> py_result (PyObject_CallObject (m_py_worker,
565                                                         py_arg_tuple.get ()));
566   if (py_result == NULL)
567     {
568       gdbpy_print_stack ();
569       error (_("Error while executing Python code."));
570     }
571 
572   if (py_result != Py_None)
573     {
574       res = convert_value_from_python (py_result.get ());
575       if (res == NULL)
576           {
577             gdbpy_print_stack ();
578             error (_("Error while executing Python code."));
579           }
580     }
581   else
582     {
583       res = value::allocate (lookup_typename (current_language,
584                                                        "void", NULL, 0));
585     }
586 
587   return res;
588 }
589 
python_xmethod_worker(PyObject * py_worker,PyObject * this_type)590 python_xmethod_worker::python_xmethod_worker (PyObject *py_worker,
591                                                          PyObject *this_type)
592 : xmethod_worker (&extension_language_python),
593   m_py_worker (py_worker), m_this_type (this_type)
594 {
595   gdb_assert (m_py_worker != NULL && m_this_type != NULL);
596 
597   Py_INCREF (py_worker);
598   Py_INCREF (this_type);
599 }
600 
601 static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_xmethods(void)602 gdbpy_initialize_xmethods (void)
603 {
604   py_match_method_name = PyUnicode_FromString (match_method_name);
605   if (py_match_method_name == NULL)
606     return -1;
607 
608   py_get_arg_types_method_name
609     = PyUnicode_FromString (get_arg_types_method_name);
610   if (py_get_arg_types_method_name == NULL)
611     return -1;
612 
613   return 1;
614 }
615 
616 GDBPY_INITIALIZE_FILE (gdbpy_initialize_xmethods);
617