diff --git a/gdb/NEWS b/gdb/NEWS index bd26d2b1ec2..d001a03145d 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -45,6 +45,10 @@ maint show internal-warning backtrace event is triggered once GDB decides it is going to exit, but before GDB starts to clean up its internal state. + ** New function gdb.architecture_names(), which returns a list + containing all of the possible Architecture.name() values. Each + entry is a string. + *** Changes in GDB 11 * The 'set disassembler-options' command now supports specifying options diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index 15bf9dc3e21..90214f24238 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -557,6 +557,14 @@ such as those used by readline for command input, and annotation related prompts are prohibited from being changed. @end defun +@defun gdb.architecture_names () +Return a list containing all of the architecture names that the +current build of @value{GDBN} supports. Each architecture name is a +string. The names returned in this list are the same names as are +returned from @code{gdb.Architecture.name} +(@pxref{gdbpy_architecture_name,,Architecture.name}). +@end defun + @node Exception Handling @subsubsection Exception Handling @cindex python exceptions @@ -5834,6 +5842,7 @@ by an instance of the @code{gdb.Architecture} class. A @code{gdb.Architecture} class has the following methods: +@anchor{gdbpy_architecture_name} @defun Architecture.name () Return the name (string value) of the architecture. @end defun diff --git a/gdb/python/py-arch.c b/gdb/python/py-arch.c index 66f2d28b94a..3e7970ab764 100644 --- a/gdb/python/py-arch.c +++ b/gdb/python/py-arch.c @@ -271,6 +271,29 @@ archpy_register_groups (PyObject *self, PyObject *args) return gdbpy_new_reggroup_iterator (gdbarch); } +/* 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 name_list = gdbarch_printable_names (); + for (const char *name : name_list) + { + gdbpy_ref <> py_name (PyString_FromString (name)); + if (py_name == nullptr) + return nullptr; + if (PyList_Append (list.get (), py_name.get ()) < 0) + return nullptr; + } + + return list.release (); +} + void _initialize_py_arch (); void _initialize_py_arch () diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 022d4a67172..2ad3bc944a7 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -469,6 +469,7 @@ PyObject *objfpy_get_xmethods (PyObject *, void *); PyObject *gdbpy_lookup_objfile (PyObject *self, PyObject *args, PyObject *kw); PyObject *gdbarch_to_arch_object (struct gdbarch *gdbarch); +PyObject *gdbpy_all_architecture_names (PyObject *self, PyObject *args); PyObject *gdbpy_new_register_descriptor_iterator (struct gdbarch *gdbarch, const char *group_name); diff --git a/gdb/python/python.c b/gdb/python/python.c index 44ec4b7094c..5b1c295fff6 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -2324,6 +2324,10 @@ Set the value of the convenience variable $NAME." }, Register a TUI window constructor." }, #endif /* TUI */ + { "architecture_names", gdbpy_all_architecture_names, METH_NOARGS, + "architecture_names () -> List.\n\ +Return a list of all the architecture names GDB understands." }, + {NULL, NULL, 0, NULL} }; diff --git a/gdb/testsuite/gdb.python/py-arch.exp b/gdb/testsuite/gdb.python/py-arch.exp index 4f971127197..415fbd475b0 100644 --- a/gdb/testsuite/gdb.python/py-arch.exp +++ b/gdb/testsuite/gdb.python/py-arch.exp @@ -62,3 +62,54 @@ if { ![is_address_zero_readable] } { gdb_test "python arch.disassemble(0, 0)" ".*gdb\.MemoryError.*" \ "test bad memory access" } + +# Test for gdb.architecture_names(). First we're going to grab the +# complete list of architecture names using the 'complete' command. +set arch_names [] +gdb_test_no_output "set max-completions unlimited" +gdb_test_multiple "complete set architecture " "" { + -re "complete set architecture\[^\r\n\]+\r\n" { + exp_continue + } + -re "^set architecture \(\[^\r\n\]+\)\r\n" { + set arch $expect_out(1,string) + if { "$arch" != "auto" } { + set arch_names [lappend arch_names $arch] + } + exp_continue + } + -re "^$gdb_prompt $" { + gdb_assert { [llength $arch_names] > 0 } + } +} + +# Now find all of the architecture names using Python. +set py_arch_names [] +gdb_test_no_output "python all_arch = gdb.architecture_names()" +gdb_test_no_output "python all_arch.sort()" +gdb_test_multiple "python print(\"\\n\".join((\"Arch: %s\" % a) for a in all_arch))" "" { + -re "python \[^\r\n\]+\r\n" { + exp_continue + } + -re "^Arch: \(\[^\r\n\]+\)\r\n" { + set arch $expect_out(1,string) + set py_arch_names [lappend py_arch_names $arch] + exp_continue + } + -re "$gdb_prompt $" { + gdb_assert { [llength $py_arch_names] > 0 } + } +} + +# Check the two lists of architecture names are the same length, and +# that the list contents all match. +gdb_assert { [llength $arch_names] == [llength $py_arch_names] } +set lists_match true +foreach a $arch_names b $py_arch_names { + if { $a != $b } { + set lists_match false + verbose -log "Mismatch is architecture list '$a' != '$b'" + break + } +} +gdb_assert { $lists_match }