|  | /* Python interface to architecture | 
|  |  | 
|  | Copyright (C) 2013-2025 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 "gdbarch.h" | 
|  | #include "arch-utils.h" | 
|  | #include "disasm.h" | 
|  | #include "python-internal.h" | 
|  |  | 
|  | struct arch_object { | 
|  | PyObject_HEAD | 
|  | struct gdbarch *gdbarch; | 
|  | }; | 
|  |  | 
|  | static const registry<gdbarch>::key<PyObject, gdb::noop_deleter<PyObject>> | 
|  | arch_object_data; | 
|  |  | 
|  | /* Require a valid Architecture.  */ | 
|  | #define ARCHPY_REQUIRE_VALID(arch_obj, arch)			\ | 
|  | do {								\ | 
|  | arch = arch_object_to_gdbarch (arch_obj);			\ | 
|  | if (arch == NULL)						\ | 
|  | {								\ | 
|  | PyErr_SetString (PyExc_RuntimeError,			\ | 
|  | _("Architecture is invalid."));	\ | 
|  | return NULL;						\ | 
|  | }								\ | 
|  | } while (0) | 
|  |  | 
|  | extern PyTypeObject arch_object_type | 
|  | CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("arch_object"); | 
|  |  | 
|  | /* Associates an arch_object with GDBARCH as gdbarch_data via the gdbarch | 
|  | post init registration mechanism (gdbarch_data_register_post_init).  */ | 
|  |  | 
|  | static PyObject * | 
|  | arch_object_data_init (struct gdbarch *gdbarch) | 
|  | { | 
|  | arch_object *arch_obj = PyObject_New (arch_object, &arch_object_type); | 
|  |  | 
|  | if (arch_obj == NULL) | 
|  | return NULL; | 
|  |  | 
|  | arch_obj->gdbarch = gdbarch; | 
|  |  | 
|  | return (PyObject *) arch_obj; | 
|  | } | 
|  |  | 
|  | /* Returns the struct gdbarch value corresponding to the given Python | 
|  | architecture object OBJ, which must be a gdb.Architecture object.  */ | 
|  |  | 
|  | struct gdbarch * | 
|  | arch_object_to_gdbarch (PyObject *obj) | 
|  | { | 
|  | gdb_assert (gdbpy_is_architecture (obj)); | 
|  |  | 
|  | arch_object *py_arch = (arch_object *) obj; | 
|  | return py_arch->gdbarch; | 
|  | } | 
|  |  | 
|  | /* See python-internal.h.  */ | 
|  |  | 
|  | bool | 
|  | gdbpy_is_architecture (PyObject *obj) | 
|  | { | 
|  | return PyObject_TypeCheck (obj, &arch_object_type); | 
|  | } | 
|  |  | 
|  | /* Returns the Python architecture object corresponding to GDBARCH. | 
|  | Returns a new reference to the arch_object associated as data with | 
|  | GDBARCH.  */ | 
|  |  | 
|  | PyObject * | 
|  | gdbarch_to_arch_object (struct gdbarch *gdbarch) | 
|  | { | 
|  | PyObject *new_ref = arch_object_data.get (gdbarch); | 
|  | if (new_ref == nullptr) | 
|  | { | 
|  | new_ref = arch_object_data_init (gdbarch); | 
|  | arch_object_data.set (gdbarch, new_ref); | 
|  | } | 
|  |  | 
|  | /* new_ref could be NULL if creation failed.  */ | 
|  | Py_XINCREF (new_ref); | 
|  |  | 
|  | return new_ref; | 
|  | } | 
|  |  | 
|  | /* Implementation of gdb.Architecture.name (self) -> String. | 
|  | Returns the name of the architecture as a string value.  */ | 
|  |  | 
|  | static PyObject * | 
|  | archpy_name (PyObject *self, PyObject *args) | 
|  | { | 
|  | struct gdbarch *gdbarch = NULL; | 
|  | const char *name; | 
|  |  | 
|  | ARCHPY_REQUIRE_VALID (self, gdbarch); | 
|  |  | 
|  | name = (gdbarch_bfd_arch_info (gdbarch))->printable_name; | 
|  | return PyUnicode_FromString (name); | 
|  | } | 
|  |  | 
|  | /* Implementation of | 
|  | gdb.Architecture.disassemble (self, start_pc [, end_pc [,count]]) -> List. | 
|  | Returns a list of instructions in a memory address range.  Each instruction | 
|  | in the list is a Python dict object. | 
|  | */ | 
|  |  | 
|  | static PyObject * | 
|  | archpy_disassemble (PyObject *self, PyObject *args, PyObject *kw) | 
|  | { | 
|  | static const char *keywords[] = { "start_pc", "end_pc", "count", NULL }; | 
|  | CORE_ADDR start = 0, end = 0; | 
|  | CORE_ADDR pc; | 
|  | long count = 0, i; | 
|  | PyObject *start_obj = nullptr, *end_obj = nullptr, *count_obj = nullptr; | 
|  | struct gdbarch *gdbarch = NULL; | 
|  |  | 
|  | ARCHPY_REQUIRE_VALID (self, gdbarch); | 
|  |  | 
|  | if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "O|OO", | 
|  | keywords, &start_obj, &end_obj, | 
|  | &count_obj)) | 
|  | return NULL; | 
|  |  | 
|  | if (get_addr_from_python (start_obj, &start) < 0) | 
|  | return nullptr; | 
|  |  | 
|  | if (end_obj != nullptr) | 
|  | { | 
|  | if (get_addr_from_python (end_obj, &end) < 0) | 
|  | return nullptr; | 
|  |  | 
|  | if (end < start) | 
|  | { | 
|  | PyErr_SetString (PyExc_ValueError, | 
|  | _("Argument 'end_pc' should be greater than or " | 
|  | "equal to the argument 'start_pc'.")); | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  | if (count_obj) | 
|  | { | 
|  | count = PyLong_AsLong (count_obj); | 
|  | if (PyErr_Occurred () || count < 0) | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | _("Argument 'count' should be an non-negative " | 
|  | "integer.")); | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | gdbpy_ref<> result_list (PyList_New (0)); | 
|  | if (result_list == NULL) | 
|  | return NULL; | 
|  |  | 
|  | for (pc = start, i = 0; | 
|  | /* All args are specified.  */ | 
|  | (end_obj && count_obj && pc <= end && i < count) | 
|  | /* end_pc is specified, but no count.  */ | 
|  | || (end_obj && count_obj == NULL && pc <= end) | 
|  | /* end_pc is not specified, but a count is.  */ | 
|  | || (end_obj == NULL && count_obj && i < count) | 
|  | /* Both end_pc and count are not specified.  */ | 
|  | || (end_obj == NULL && count_obj == NULL && pc == start);) | 
|  | { | 
|  | int insn_len = 0; | 
|  | gdbpy_ref<> insn_dict (PyDict_New ()); | 
|  |  | 
|  | if (insn_dict == NULL) | 
|  | return NULL; | 
|  | if (PyList_Append (result_list.get (), insn_dict.get ())) | 
|  | return NULL;  /* PyList_Append Sets the exception.  */ | 
|  |  | 
|  | string_file stb; | 
|  |  | 
|  | try | 
|  | { | 
|  | insn_len = gdb_print_insn (gdbarch, pc, &stb, NULL); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | return gdbpy_handle_gdb_exception (nullptr, except); | 
|  | } | 
|  |  | 
|  | gdbpy_ref<> pc_obj = gdb_py_object_from_ulongest (pc); | 
|  | if (pc_obj == nullptr) | 
|  | return nullptr; | 
|  |  | 
|  | gdbpy_ref<> asm_obj | 
|  | (PyUnicode_FromString (!stb.empty () ? stb.c_str () : "<unknown>")); | 
|  | if (asm_obj == nullptr) | 
|  | return nullptr; | 
|  |  | 
|  | gdbpy_ref<> len_obj = gdb_py_object_from_longest (insn_len); | 
|  | if (len_obj == nullptr) | 
|  | return nullptr; | 
|  |  | 
|  | if (PyDict_SetItemString (insn_dict.get (), "addr", pc_obj.get ()) | 
|  | || PyDict_SetItemString (insn_dict.get (), "asm", asm_obj.get ()) | 
|  | || PyDict_SetItemString (insn_dict.get (), "length", len_obj.get ())) | 
|  | return NULL; | 
|  |  | 
|  | pc += insn_len; | 
|  | i++; | 
|  | } | 
|  |  | 
|  | return result_list.release (); | 
|  | } | 
|  |  | 
|  | /* Implementation of gdb.Architecture.registers (self, reggroup) -> Iterator. | 
|  | Returns an iterator over register descriptors for registers in GROUP | 
|  | within the architecture SELF.  */ | 
|  |  | 
|  | static PyObject * | 
|  | archpy_registers (PyObject *self, PyObject *args, PyObject *kw) | 
|  | { | 
|  | static const char *keywords[] = { "reggroup", NULL }; | 
|  | struct gdbarch *gdbarch = NULL; | 
|  | const char *group_name = NULL; | 
|  |  | 
|  | /* Parse method arguments.  */ | 
|  | if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "|s", keywords, | 
|  | &group_name)) | 
|  | return NULL; | 
|  |  | 
|  | /* Extract the gdbarch from the self object.  */ | 
|  | ARCHPY_REQUIRE_VALID (self, gdbarch); | 
|  |  | 
|  | return gdbpy_new_register_descriptor_iterator (gdbarch, group_name); | 
|  | } | 
|  |  | 
|  | /* Implementation of gdb.Architecture.register_groups (self) -> Iterator. | 
|  | Returns an iterator that will give up all valid register groups in the | 
|  | architecture SELF.  */ | 
|  |  | 
|  | static PyObject * | 
|  | archpy_register_groups (PyObject *self, PyObject *args) | 
|  | { | 
|  | struct gdbarch *gdbarch = NULL; | 
|  |  | 
|  | /* Extract the gdbarch from the self object.  */ | 
|  | ARCHPY_REQUIRE_VALID (self, gdbarch); | 
|  | return gdbpy_new_reggroup_iterator (gdbarch); | 
|  | } | 
|  |  | 
|  | /* Implementation of gdb.integer_type.  */ | 
|  | static PyObject * | 
|  | archpy_integer_type (PyObject *self, PyObject *args, PyObject *kw) | 
|  | { | 
|  | static const char *keywords[] = { "size", "signed", NULL }; | 
|  | int size; | 
|  | PyObject *is_signed_obj = Py_True; | 
|  |  | 
|  | if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "i|O!", keywords, | 
|  | &size, | 
|  | &PyBool_Type, &is_signed_obj)) | 
|  | return nullptr; | 
|  |  | 
|  | /* Assume signed by default.  */ | 
|  | gdb_assert (PyBool_Check (is_signed_obj)); | 
|  | bool is_signed = is_signed_obj == Py_True; | 
|  |  | 
|  | struct gdbarch *gdbarch; | 
|  | ARCHPY_REQUIRE_VALID (self, gdbarch); | 
|  |  | 
|  | const struct builtin_type *builtins = builtin_type (gdbarch); | 
|  | struct type *type = nullptr; | 
|  | switch (size) | 
|  | { | 
|  | case 0: | 
|  | type = builtins->builtin_int0; | 
|  | break; | 
|  | case 8: | 
|  | type = is_signed ? builtins->builtin_int8 : builtins->builtin_uint8; | 
|  | break; | 
|  | case 16: | 
|  | type = is_signed ? builtins->builtin_int16 : builtins->builtin_uint16; | 
|  | break; | 
|  | case 24: | 
|  | type = is_signed ? builtins->builtin_int24 : builtins->builtin_uint24; | 
|  | break; | 
|  | case 32: | 
|  | type = is_signed ? builtins->builtin_int32 : builtins->builtin_uint32; | 
|  | break; | 
|  | case 64: | 
|  | type = is_signed ? builtins->builtin_int64 : builtins->builtin_uint64; | 
|  | break; | 
|  | case 128: | 
|  | type = is_signed ? builtins->builtin_int128 : builtins->builtin_uint128; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | PyErr_SetString (PyExc_ValueError, | 
|  | _("no integer type of that size is available")); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | return type_to_type_object (type); | 
|  | } | 
|  |  | 
|  | /* Implementation of gdb.void_type.  */ | 
|  | static PyObject * | 
|  | archpy_void_type (PyObject *self, PyObject *args) | 
|  | { | 
|  | struct gdbarch *gdbarch; | 
|  | ARCHPY_REQUIRE_VALID (self, gdbarch); | 
|  |  | 
|  | return type_to_type_object (builtin_type (gdbarch)->builtin_void); | 
|  | } | 
|  |  | 
|  | /* __repr__ implementation for gdb.Architecture.  */ | 
|  |  | 
|  | static PyObject * | 
|  | archpy_repr (PyObject *self) | 
|  | { | 
|  | const auto gdbarch = arch_object_to_gdbarch (self); | 
|  | if (gdbarch == nullptr) | 
|  | return gdb_py_invalid_object_repr (self); | 
|  |  | 
|  | auto arch_info = gdbarch_bfd_arch_info (gdbarch); | 
|  | return PyUnicode_FromFormat ("<%s arch_name=%s printable_name=%s>", | 
|  | Py_TYPE (self)->tp_name, arch_info->arch_name, | 
|  | arch_info->printable_name); | 
|  | } | 
|  |  | 
|  | /* Implementation of gdb.architecture_names().  Return a list of all the | 
|  | BFD architecture names that GDB understands.  */ | 
|  |  | 
|  | PyObject * | 
|  | gdbpy_all_architecture_names (PyObject *self, PyObject *args) | 
|  | { | 
|  | gdbpy_ref<> list (PyList_New (0)); | 
|  | if (list == nullptr) | 
|  | return nullptr; | 
|  |  | 
|  | std::vector<const char *> name_list = gdbarch_printable_names (); | 
|  | for (const char *name : name_list) | 
|  | { | 
|  | gdbpy_ref <> py_name (PyUnicode_FromString (name)); | 
|  | if (py_name == nullptr) | 
|  | return nullptr; | 
|  | if (PyList_Append (list.get (), py_name.get ()) < 0) | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | return list.release (); | 
|  | } | 
|  |  | 
|  | /* Initializes the Architecture class in the gdb module.  */ | 
|  |  | 
|  | static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION | 
|  | gdbpy_initialize_arch (void) | 
|  | { | 
|  | arch_object_type.tp_new = PyType_GenericNew; | 
|  | return gdbpy_type_ready (&arch_object_type); | 
|  | } | 
|  |  | 
|  | GDBPY_INITIALIZE_FILE (gdbpy_initialize_arch); | 
|  |  | 
|  |  | 
|  |  | 
|  | static PyMethodDef arch_object_methods [] = { | 
|  | { "name", archpy_name, METH_NOARGS, | 
|  | "name () -> String.\n\ | 
|  | Return the name of the architecture as a string value." }, | 
|  | { "disassemble", (PyCFunction) archpy_disassemble, | 
|  | METH_VARARGS | METH_KEYWORDS, | 
|  | "disassemble (start_pc [, end_pc [, count]]) -> List.\n\ | 
|  | Return a list of at most COUNT disassembled instructions from START_PC to\n\ | 
|  | END_PC." }, | 
|  | { "integer_type", (PyCFunction) archpy_integer_type, | 
|  | METH_VARARGS | METH_KEYWORDS, | 
|  | "integer_type (size [, signed]) -> type\n\ | 
|  | Return an integer Type corresponding to the given bitsize and signed-ness.\n\ | 
|  | If not specified, the type defaults to signed." }, | 
|  | { "void_type", (PyCFunction) archpy_void_type, | 
|  | METH_NOARGS, | 
|  | "void_type () -> type\n\ | 
|  | Return a void Type." }, | 
|  | { "registers", (PyCFunction) archpy_registers, | 
|  | METH_VARARGS | METH_KEYWORDS, | 
|  | "registers ([ group-name ]) -> Iterator.\n\ | 
|  | Return an iterator of register descriptors for the registers in register\n\ | 
|  | group GROUP-NAME." }, | 
|  | { "register_groups", archpy_register_groups, | 
|  | METH_NOARGS, | 
|  | "register_groups () -> Iterator.\n\ | 
|  | Return an iterator over all of the register groups in this architecture." }, | 
|  | {NULL}  /* Sentinel */ | 
|  | }; | 
|  |  | 
|  | PyTypeObject arch_object_type = { | 
|  | PyVarObject_HEAD_INIT (NULL, 0) | 
|  | "gdb.Architecture",                 /* tp_name */ | 
|  | sizeof (arch_object),               /* tp_basicsize */ | 
|  | 0,                                  /* tp_itemsize */ | 
|  | 0,                                  /* tp_dealloc */ | 
|  | 0,                                  /* tp_print */ | 
|  | 0,                                  /* tp_getattr */ | 
|  | 0,                                  /* tp_setattr */ | 
|  | 0,                                  /* tp_compare */ | 
|  | archpy_repr,                        /* tp_repr */ | 
|  | 0,                                  /* tp_as_number */ | 
|  | 0,                                  /* tp_as_sequence */ | 
|  | 0,                                  /* tp_as_mapping */ | 
|  | 0,                                  /* tp_hash  */ | 
|  | 0,                                  /* tp_call */ | 
|  | 0,                                  /* tp_str */ | 
|  | 0,                                  /* tp_getattro */ | 
|  | 0,                                  /* tp_setattro */ | 
|  | 0,                                  /* tp_as_buffer */ | 
|  | Py_TPFLAGS_DEFAULT,                 /* tp_flags */ | 
|  | "GDB architecture object",          /* tp_doc */ | 
|  | 0,                                  /* tp_traverse */ | 
|  | 0,                                  /* tp_clear */ | 
|  | 0,                                  /* tp_richcompare */ | 
|  | 0,                                  /* tp_weaklistoffset */ | 
|  | 0,                                  /* tp_iter */ | 
|  | 0,                                  /* tp_iternext */ | 
|  | arch_object_methods,                /* tp_methods */ | 
|  | 0,                                  /* tp_members */ | 
|  | 0,                                  /* tp_getset */ | 
|  | 0,                                  /* tp_base */ | 
|  | 0,                                  /* tp_dict */ | 
|  | 0,                                  /* tp_descr_get */ | 
|  | 0,                                  /* tp_descr_set */ | 
|  | 0,                                  /* tp_dictoffset */ | 
|  | 0,                                  /* tp_init */ | 
|  | 0,                                  /* tp_alloc */ | 
|  | }; |