123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614 |
- /* Support for debug methods in Python.
- Copyright (C) 2013-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "defs.h"
- #include "arch-utils.h"
- #include "extension-priv.h"
- #include "objfiles.h"
- #include "value.h"
- #include "language.h"
- #include "python.h"
- #include "python-internal.h"
- static const char enabled_field_name[] = "enabled";
- static const char match_method_name[] = "match";
- static const char get_arg_types_method_name[] = "get_arg_types";
- static const char get_result_type_method_name[] = "get_result_type";
- static const char matchers_attr_str[] = "xmethods";
- static PyObject *py_match_method_name = NULL;
- static PyObject *py_get_arg_types_method_name = NULL;
- struct python_xmethod_worker : xmethod_worker
- {
- python_xmethod_worker (PyObject *worker, PyObject *this_type);
- ~python_xmethod_worker ();
- DISABLE_COPY_AND_ASSIGN (python_xmethod_worker);
- /* Implementation of xmethod_worker::invoke for Python. */
- value *invoke (value *obj, gdb::array_view<value *> args) override;
- /* Implementation of xmethod_worker::do_get_arg_types for Python. */
- ext_lang_rc do_get_arg_types (std::vector<type *> *type_args) override;
- /* Implementation of xmethod_worker::do_get_result_type for Python.
- For backward compatibility with 7.9, which did not support getting the
- result type, if the get_result_type operation is not provided by WORKER
- then EXT_LANG_RC_OK is returned and NULL is returned in *RESULT_TYPE. */
- ext_lang_rc do_get_result_type (value *obj, gdb::array_view<value *> args,
- type **result_type_ptr) override;
- private:
- PyObject *m_py_worker;
- PyObject *m_this_type;
- };
- python_xmethod_worker::~python_xmethod_worker ()
- {
- /* We don't do much here, but we still need the GIL. */
- gdbpy_enter enter_py;
- Py_DECREF (m_py_worker);
- Py_DECREF (m_this_type);
- }
- /* Invoke the "match" method of the MATCHER and return a new reference
- to the result. Returns NULL on error. */
- static PyObject *
- invoke_match_method (PyObject *matcher, PyObject *py_obj_type,
- const char *xmethod_name)
- {
- int enabled;
- gdbpy_ref<> enabled_field (PyObject_GetAttrString (matcher,
- enabled_field_name));
- if (enabled_field == NULL)
- return NULL;
- enabled = PyObject_IsTrue (enabled_field.get ());
- if (enabled == -1)
- return NULL;
- if (enabled == 0)
- {
- /* Return 'None' if the matcher is not enabled. */
- Py_RETURN_NONE;
- }
- gdbpy_ref<> match_method (PyObject_GetAttrString (matcher,
- match_method_name));
- if (match_method == NULL)
- return NULL;
- gdbpy_ref<> py_xmethod_name (PyUnicode_FromString (xmethod_name));
- if (py_xmethod_name == NULL)
- return NULL;
- return PyObject_CallMethodObjArgs (matcher, py_match_method_name,
- py_obj_type, py_xmethod_name.get (),
- NULL);
- }
- /* Implementation of get_matching_xmethod_workers for Python. */
- 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)
- {
- gdb_assert (obj_type != NULL && method_name != NULL);
- gdbpy_enter enter_py;
- gdbpy_ref<> py_type (type_to_type_object (obj_type));
- if (py_type == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- /* Create an empty list of debug methods. */
- gdbpy_ref<> py_xmethod_matcher_list (PyList_New (0));
- if (py_xmethod_matcher_list == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- /* Gather debug method matchers registered with the object files.
- This could be done differently by iterating over each objfile's matcher
- list individually, but there's no data yet to show it's needed. */
- for (objfile *objfile : current_program_space->objfiles ())
- {
- gdbpy_ref<> py_objfile = objfile_to_objfile_object (objfile);
- if (py_objfile == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- gdbpy_ref<> objfile_matchers (objfpy_get_xmethods (py_objfile.get (),
- NULL));
- gdbpy_ref<> temp (PySequence_Concat (py_xmethod_matcher_list.get (),
- objfile_matchers.get ()));
- if (temp == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- py_xmethod_matcher_list = std::move (temp);
- }
- /* Gather debug methods matchers registered with the current program
- space. */
- gdbpy_ref<> py_progspace = pspace_to_pspace_object (current_program_space);
- if (py_progspace != NULL)
- {
- gdbpy_ref<> pspace_matchers (pspy_get_xmethods (py_progspace.get (),
- NULL));
- gdbpy_ref<> temp (PySequence_Concat (py_xmethod_matcher_list.get (),
- pspace_matchers.get ()));
- if (temp == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- py_xmethod_matcher_list = std::move (temp);
- }
- else
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- /* Gather debug method matchers registered globally. */
- if (gdb_python_module != NULL
- && PyObject_HasAttrString (gdb_python_module, matchers_attr_str))
- {
- gdbpy_ref<> gdb_matchers (PyObject_GetAttrString (gdb_python_module,
- matchers_attr_str));
- if (gdb_matchers != NULL)
- {
- gdbpy_ref<> temp (PySequence_Concat (py_xmethod_matcher_list.get (),
- gdb_matchers.get ()));
- if (temp == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- py_xmethod_matcher_list = std::move (temp);
- }
- else
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- }
- gdbpy_ref<> list_iter (PyObject_GetIter (py_xmethod_matcher_list.get ()));
- if (list_iter == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- while (true)
- {
- gdbpy_ref<> matcher (PyIter_Next (list_iter.get ()));
- if (matcher == NULL)
- {
- if (PyErr_Occurred ())
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- break;
- }
- gdbpy_ref<> match_result (invoke_match_method (matcher.get (),
- py_type.get (),
- method_name));
- if (match_result == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- if (match_result == Py_None)
- ; /* This means there was no match. */
- else if (PySequence_Check (match_result.get ()))
- {
- gdbpy_ref<> iter (PyObject_GetIter (match_result.get ()));
- if (iter == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- while (true)
- {
- struct xmethod_worker *worker;
- gdbpy_ref<> py_worker (PyIter_Next (iter.get ()));
- if (py_worker == NULL)
- {
- if (PyErr_Occurred ())
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- break;
- }
- worker = new python_xmethod_worker (py_worker.get (),
- py_type.get ());
- dm_vec->emplace_back (worker);
- }
- }
- else
- {
- struct xmethod_worker *worker;
- worker = new python_xmethod_worker (match_result.get (),
- py_type.get ());
- dm_vec->emplace_back (worker);
- }
- }
- return EXT_LANG_RC_OK;
- }
- /* See declaration. */
- ext_lang_rc
- python_xmethod_worker::do_get_arg_types (std::vector<type *> *arg_types)
- {
- /* The gdbpy_enter object needs to be placed first, so that it's the last to
- be destroyed. */
- gdbpy_enter enter_py;
- struct type *obj_type;
- int i = 1, arg_count;
- gdbpy_ref<> list_iter;
- gdbpy_ref<> get_arg_types_method
- (PyObject_GetAttrString (m_py_worker, get_arg_types_method_name));
- if (get_arg_types_method == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- gdbpy_ref<> py_argtype_list
- (PyObject_CallMethodObjArgs (m_py_worker, py_get_arg_types_method_name,
- NULL));
- if (py_argtype_list == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- if (py_argtype_list == Py_None)
- arg_count = 0;
- else if (PySequence_Check (py_argtype_list.get ()))
- {
- arg_count = PySequence_Size (py_argtype_list.get ());
- if (arg_count == -1)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- list_iter.reset (PyObject_GetIter (py_argtype_list.get ()));
- if (list_iter == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- }
- else
- arg_count = 1;
- /* Include the 'this' argument in the size. */
- arg_types->resize (arg_count + 1);
- i = 1;
- if (list_iter != NULL)
- {
- while (true)
- {
- gdbpy_ref<> item (PyIter_Next (list_iter.get ()));
- if (item == NULL)
- {
- if (PyErr_Occurred ())
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- break;
- }
- struct type *arg_type = type_object_to_type (item.get ());
- if (arg_type == NULL)
- {
- PyErr_SetString (PyExc_TypeError,
- _("Arg type returned by the get_arg_types "
- "method of a debug method worker object is "
- "not a gdb.Type object."));
- return EXT_LANG_RC_ERROR;
- }
- (*arg_types)[i] = arg_type;
- i++;
- }
- }
- else if (arg_count == 1)
- {
- /* py_argtype_list is not actually a list but a single gdb.Type
- object. */
- struct type *arg_type = type_object_to_type (py_argtype_list.get ());
- if (arg_type == NULL)
- {
- PyErr_SetString (PyExc_TypeError,
- _("Arg type returned by the get_arg_types method "
- "of an xmethod worker object is not a gdb.Type "
- "object."));
- return EXT_LANG_RC_ERROR;
- }
- else
- {
- (*arg_types)[i] = arg_type;
- i++;
- }
- }
- /* Add the type of 'this' as the first argument. The 'this' pointer should
- be a 'const' value. Hence, create a 'const' variant of the 'this' pointer
- type. */
- obj_type = type_object_to_type (m_this_type);
- (*arg_types)[0] = make_cv_type (1, 0, lookup_pointer_type (obj_type),
- NULL);
- return EXT_LANG_RC_OK;
- }
- /* See declaration. */
- ext_lang_rc
- python_xmethod_worker::do_get_result_type (value *obj,
- gdb::array_view<value *> args,
- type **result_type_ptr)
- {
- struct type *obj_type, *this_type;
- int i;
- gdbpy_enter enter_py;
- /* First see if there is a get_result_type method.
- If not this could be an old xmethod (pre 7.9.1). */
- gdbpy_ref<> get_result_type_method
- (PyObject_GetAttrString (m_py_worker, get_result_type_method_name));
- if (get_result_type_method == NULL)
- {
- PyErr_Clear ();
- *result_type_ptr = NULL;
- return EXT_LANG_RC_OK;
- }
- obj_type = check_typedef (value_type (obj));
- this_type = check_typedef (type_object_to_type (m_this_type));
- if (obj_type->code () == TYPE_CODE_PTR)
- {
- struct type *this_ptr = lookup_pointer_type (this_type);
- if (!types_equal (obj_type, this_ptr))
- obj = value_cast (this_ptr, obj);
- }
- else if (TYPE_IS_REFERENCE (obj_type))
- {
- struct type *this_ref
- = lookup_reference_type (this_type, obj_type->code ());
- if (!types_equal (obj_type, this_ref))
- obj = value_cast (this_ref, obj);
- }
- else
- {
- if (!types_equal (obj_type, this_type))
- obj = value_cast (this_type, obj);
- }
- gdbpy_ref<> py_value_obj (value_to_value_object (obj));
- if (py_value_obj == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- gdbpy_ref<> py_arg_tuple (PyTuple_New (args.size () + 1));
- if (py_arg_tuple == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- /* PyTuple_SET_ITEM steals the reference of the element, hence the
- release. */
- PyTuple_SET_ITEM (py_arg_tuple.get (), 0, py_value_obj.release ());
- for (i = 0; i < args.size (); i++)
- {
- PyObject *py_value_arg = value_to_value_object (args[i]);
- if (py_value_arg == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- PyTuple_SET_ITEM (py_arg_tuple.get (), i + 1, py_value_arg);
- }
- gdbpy_ref<> py_result_type
- (PyObject_CallObject (get_result_type_method.get (), py_arg_tuple.get ()));
- if (py_result_type == NULL)
- {
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- *result_type_ptr = type_object_to_type (py_result_type.get ());
- if (*result_type_ptr == NULL)
- {
- PyErr_SetString (PyExc_TypeError,
- _("Type returned by the get_result_type method of an"
- " xmethod worker object is not a gdb.Type object."));
- gdbpy_print_stack ();
- return EXT_LANG_RC_ERROR;
- }
- return EXT_LANG_RC_OK;
- }
- /* See declaration. */
- struct value *
- python_xmethod_worker::invoke (struct value *obj,
- gdb::array_view<value *> args)
- {
- gdbpy_enter enter_py;
- int i;
- struct type *obj_type, *this_type;
- struct value *res = NULL;
- obj_type = check_typedef (value_type (obj));
- this_type = check_typedef (type_object_to_type (m_this_type));
- if (obj_type->code () == TYPE_CODE_PTR)
- {
- struct type *this_ptr = lookup_pointer_type (this_type);
- if (!types_equal (obj_type, this_ptr))
- obj = value_cast (this_ptr, obj);
- }
- else if (TYPE_IS_REFERENCE (obj_type))
- {
- struct type *this_ref
- = lookup_reference_type (this_type, obj_type->code ());
- if (!types_equal (obj_type, this_ref))
- obj = value_cast (this_ref, obj);
- }
- else
- {
- if (!types_equal (obj_type, this_type))
- obj = value_cast (this_type, obj);
- }
- gdbpy_ref<> py_value_obj (value_to_value_object (obj));
- if (py_value_obj == NULL)
- {
- gdbpy_print_stack ();
- error (_("Error while executing Python code."));
- }
- gdbpy_ref<> py_arg_tuple (PyTuple_New (args.size () + 1));
- if (py_arg_tuple == NULL)
- {
- gdbpy_print_stack ();
- error (_("Error while executing Python code."));
- }
- /* PyTuple_SET_ITEM steals the reference of the element, hence the
- release. */
- PyTuple_SET_ITEM (py_arg_tuple.get (), 0, py_value_obj.release ());
- for (i = 0; i < args.size (); i++)
- {
- PyObject *py_value_arg = value_to_value_object (args[i]);
- if (py_value_arg == NULL)
- {
- gdbpy_print_stack ();
- error (_("Error while executing Python code."));
- }
- PyTuple_SET_ITEM (py_arg_tuple.get (), i + 1, py_value_arg);
- }
- gdbpy_ref<> py_result (PyObject_CallObject (m_py_worker,
- py_arg_tuple.get ()));
- if (py_result == NULL)
- {
- gdbpy_print_stack ();
- error (_("Error while executing Python code."));
- }
- if (py_result != Py_None)
- {
- res = convert_value_from_python (py_result.get ());
- if (res == NULL)
- {
- gdbpy_print_stack ();
- error (_("Error while executing Python code."));
- }
- }
- else
- {
- res = allocate_value (lookup_typename (current_language,
- "void", NULL, 0));
- }
- return res;
- }
- python_xmethod_worker::python_xmethod_worker (PyObject *py_worker,
- PyObject *this_type)
- : xmethod_worker (&extension_language_python),
- m_py_worker (py_worker), m_this_type (this_type)
- {
- gdb_assert (m_py_worker != NULL && m_this_type != NULL);
- Py_INCREF (py_worker);
- Py_INCREF (this_type);
- }
- int
- gdbpy_initialize_xmethods (void)
- {
- py_match_method_name = PyUnicode_FromString (match_method_name);
- if (py_match_method_name == NULL)
- return -1;
- py_get_arg_types_method_name
- = PyUnicode_FromString (get_arg_types_method_name);
- if (py_get_arg_types_method_name == NULL)
- return -1;
- return 1;
- }
|