From 89c73adef9f9fac7e1efeb6961a867f46e54e24b Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Thu, 28 May 2009 00:40:24 +0000 Subject: [PATCH] gdb 2009-04-01 Tom Tromey Thiago Jung Bauermann Phil Muldoon * python/python.c: Include objfiles.h, observer.h. (gdbpy_auto_load): New global. (gdbpy_current_objfile): Likewise. (GDBPY_AUTO_FILENAME): New define. (gdbpy_new_objfile): New function. (gdbpy_get_current_objfile): Likewise. (gdbpy_objfiles): Likewise. (_initialize_python): Add "maint set auto-load". Call gdbpy_initialize_objfile. Attach objfile observer. (GdbMethods): New methods current_objfile, objfiles. * python/python-objfile.c: New file. * python/python-internal.h (objfile_to_objfile_object): Declare. (objfpy_get_printers): Likewise. (gdbpy_initialize_objfile): Likewise. * Makefile.in (SUBDIR_PYTHON_OBS): Add python-objfile.o. (SUBDIR_PYTHON_SRCS): Add python-objfile.c. (python-objfile.o): New target. gdb/doc 2009-04-01 Tom Tromey Thiago Jung Bauermann * gdb.texinfo (Python API): Update. (Auto-loading): New node. (Objfiles In Python): New node. gdb/testsuite 2009-04-06 Tom Tromey * gdb.python/python.exp (gdb_py_test_multiple): Add two objfile tests. * gdb.python/python-value.exp (py_objfile_tests): New proc. Call it. --- gdb/ChangeLog | 22 +++ gdb/Makefile.in | 6 + gdb/doc/ChangeLog | 9 + gdb/doc/gdb.texinfo | 94 +++++++++ gdb/python/python-internal.h | 4 + gdb/python/python-objfile.c | 229 ++++++++++++++++++++++ gdb/python/python.c | 146 ++++++++++++++ gdb/testsuite/ChangeLog | 7 + gdb/testsuite/gdb.python/python-value.exp | 10 + gdb/testsuite/gdb.python/python.exp | 3 + 10 files changed, 530 insertions(+) create mode 100644 gdb/python/python-objfile.c diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3cf2a01450..6cf87ec582 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,25 @@ +2009-05-27 Tom Tromey + Thiago Jung Bauermann + Phil Muldoon + + * python/python.c: Include objfiles.h, observer.h. + (gdbpy_auto_load): New global. + (gdbpy_current_objfile): Likewise. + (GDBPY_AUTO_FILENAME): New define. + (gdbpy_new_objfile): New function. + (gdbpy_get_current_objfile): Likewise. + (gdbpy_objfiles): Likewise. + (_initialize_python): Add "maint set auto-load". Call + gdbpy_initialize_objfile. Attach objfile observer. + (GdbMethods): New methods current_objfile, objfiles. + * python/python-objfile.c: New file. + * python/python-internal.h (objfile_to_objfile_object): Declare. + (objfpy_get_printers): Likewise. + (gdbpy_initialize_objfile): Likewise. + * Makefile.in (SUBDIR_PYTHON_OBS): Add python-objfile.o. + (SUBDIR_PYTHON_SRCS): Add python-objfile.c. + (python-objfile.o): New target. + 2009-05-27 Pedro Alves * infrun.c (follow_exec): Clear the stop_requested flag. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 89fb8725dd..df157bf721 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -267,6 +267,7 @@ SUBDIR_PYTHON_OBS = \ python-cmd.o \ python-frame.o \ python-function.o \ + python-objfile.o \ python-utils.o \ python-value.o SUBDIR_PYTHON_SRCS = \ @@ -274,6 +275,7 @@ SUBDIR_PYTHON_SRCS = \ python/python-cmd.c \ python/python-frame.c \ python/python-function.c \ + python/python-objfile.c \ python/python-utils.c \ python/python-value.c SUBDIR_PYTHON_DEPS = @@ -1864,6 +1866,10 @@ python-function.o: $(srcdir)/python/python-function.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-function.c $(POSTCOMPILE) +python-objfile.o: $(srcdir)/python/python-objfile.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c + $(POSTCOMPILE) + python-utils.o: $(srcdir)/python/python-utils.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c $(POSTCOMPILE) diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 6d81aef53c..c5594ff5e0 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,12 @@ +2009-05-27 Tom Tromey + Thiago Jung Bauermann + Phil Muldoon + + * gdb.texinfo: Add @syncodeindex for `tp'. + (Python API): Update. + (Auto-loading): New node. + (Objfiles In Python): New node. + 2009-05-15 Paul Pluzhnikov * gdb.texinfo (Threads): Document libthread-db-search-path. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index b7bf14e8cb..ba06b420c4 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -21,6 +21,7 @@ @finalout @syncodeindex ky cp +@syncodeindex tp cp @c readline appendices use @vindex, @findex and @ftable, @c annotate.texi and gdbmi use @findex. @@ -18513,9 +18514,11 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown. @menu * Basic Python:: Basic Python Functions. * Exception Handling:: +* Auto-loading:: Automatically loading Python code. * Values From Inferior:: * Commands In Python:: Implementing new commands in Python. * Functions In Python:: Writing new convenience functions. +* Objfiles In Python:: Object files. * Frames In Python:: Acessing inferior stack frames from Python. @end menu @@ -18614,6 +18617,53 @@ message as its value, and the Python call stack backtrace at the Python statement closest to where the @value{GDBN} error occured as the traceback. +@node Auto-loading +@subsubsection Auto-loading +@cindex auto-loading, Python + +When a new object file is read (for example, due to the @code{file} +command, or because the inferior has loaded a shared library), +@value{GDBN} will look for a file named @file{@var{objfile}-gdb.py}, +where @var{objfile} is the object file's real name, formed by ensuring +that the file name is absolute, following all symlinks, and resolving +@code{.} and @code{..} components. If this file exists and is +readable, @value{GDBN} will evaluate it as a Python script. + +If this file does not exist, and if the parameter +@code{debug-file-directory} is set (@pxref{Separate Debug Files}), +then @value{GDBN} will use the file named +@file{@var{debug-file-directory}/@var{real-name}}, where +@var{real-name} is the object file's real name, as described above. + +Finally, if this file does not exist, then @value{GDBN} will look for +a file named @file{@var{data-directory}/python/auto-load/@var{real-name}}, where +@var{data-directory} is @value{GDBN}'s data directory (available via +@code{show data-directory}, @pxref{Data Files}), and @var{real-name} +is the object file's real name, as described above. + +When reading an auto-loaded file, @value{GDBN} sets the ``current +objfile''. This is available via the @code{gdb.current_objfile} +function (@pxref{Objfiles In Python}). This can be useful for +registering objfile-specific pretty-printers. + +The auto-loading feature is useful for supplying application-specific +debugging commands and scripts. You can enable or disable this +feature, and view its current state. + +@table @code +@kindex maint set python auto-load +@item maint set python auto-load [yes|no] +Enable or disable the Python auto-loading feature. + +@kindex show python auto-load +@item show python auto-load +Show whether Python auto-loading is enabled or disabled. +@end table + +@value{GDBN} does not track which files it has already auto-loaded. +So, your @samp{-gdb.py} file should take care to ensure that it may be +evaluated multiple times without error. + @node Values From Inferior @subsubsection Values From Inferior @cindex values from inferior, with Python @@ -19027,6 +19077,50 @@ registration of the function with @value{GDBN}. Depending on how the Python code is read into @value{GDBN}, you may need to import the @code{gdb} module explicitly. +@node Objfiles In Python +@subsubsection Objfiles In Python + +@cindex objfiles in python +@tindex gdb.Objfile +@tindex Objfile +@value{GDBN} loads symbols for an inferior from various +symbol-containing files (@pxref{Files}). These include the primary +executable file, any shared libraries used by the inferior, and any +separate debug info files (@pxref{Separate Debug Files}). +@value{GDBN} calls these symbol-containing files @dfn{objfiles}. + +The following objfile-related functions are available in the +@code{gdb} module: + +@findex gdb.current_objfile +@defun current_objfile +When auto-loading a Python script (@pxref{Auto-loading}), @value{GDBN} +sets the ``current objfile'' to the corresponding objfile. This +function returns the current objfile. If there is no current objfile, +this function returns @code{None}. +@end defun + +@findex gdb.objfiles +@defun objfiles +Return a sequence of all the objfiles current known to @value{GDBN}. +@xref{Objfiles In Python}. +@end defun + +Each objfile is represented by an instance of the @code{gdb.Objfile} +class. + +@defivar Objfile filename +The file name of the objfile as a string. +@end defivar + +@defivar Objfile pretty_printers +The @code{pretty_printers} attribute is a list of functions. It is +used to look up pretty-printers. A @code{Value} is passed to each +function in order; if the function returns @code{None}, then the +search continues. Otherwise, the return value should be an object +which is used to format the value. +@end defivar + @node Frames In Python @subsubsection Acessing inferior stack frames from Python. diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index f8d08962c6..f16b509b38 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -68,6 +68,9 @@ PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *); PyObject *gdbpy_selected_frame (PyObject *self, PyObject *args); PyObject *value_to_value_object (struct value *v); +PyObject *objfile_to_objfile_object (struct objfile *); + +PyObject *objfpy_get_printers (PyObject *, void *); struct value *convert_value_from_python (PyObject *obj); @@ -75,6 +78,7 @@ void gdbpy_initialize_values (void); void gdbpy_initialize_frames (void); void gdbpy_initialize_commands (void); void gdbpy_initialize_functions (void); +void gdbpy_initialize_objfile (void); struct cleanup *make_cleanup_py_decref (PyObject *py); struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state); diff --git a/gdb/python/python-objfile.c b/gdb/python/python-objfile.c new file mode 100644 index 0000000000..b70a0067c1 --- /dev/null +++ b/gdb/python/python-objfile.c @@ -0,0 +1,229 @@ +/* Python interface to objfiles. + + Copyright (C) 2008, 2009 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 . */ + +#include "defs.h" +#include "python-internal.h" +#include "charset.h" +#include "objfiles.h" + +typedef struct +{ + PyObject_HEAD + + /* The corresponding objfile. */ + struct objfile *objfile; + + /* The pretty-printer list of functions. */ + PyObject *printers; +} objfile_object; + +static PyTypeObject objfile_object_type; + +static const struct objfile_data *objfpy_objfile_data_key; + + + +/* An Objfile method which returns the objfile's file name, or None. */ +static PyObject * +objfpy_get_filename (PyObject *self, void *closure) +{ + objfile_object *obj = (objfile_object *) self; + if (obj->objfile && obj->objfile->name) + return PyString_Decode (obj->objfile->name, strlen (obj->objfile->name), + host_charset (), NULL); + Py_RETURN_NONE; +} + +static void +objfpy_dealloc (PyObject *o) +{ + objfile_object *self = (objfile_object *) o; + Py_XDECREF (self->printers); + self->ob_type->tp_free ((PyObject *) self); +} + +static PyObject * +objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords) +{ + objfile_object *self = (objfile_object *) type->tp_alloc (type, 0); + if (self) + { + self->objfile = NULL; + + self->printers = PyList_New (0); + if (!self->printers) + { + Py_DECREF (self); + return NULL; + } + } + return (PyObject *) self; +} + +PyObject * +objfpy_get_printers (PyObject *o, void *ignore) +{ + objfile_object *self = (objfile_object *) o; + Py_INCREF (self->printers); + return self->printers; +} + +static int +objfpy_set_printers (PyObject *o, PyObject *value, void *ignore) +{ + PyObject *tmp; + objfile_object *self = (objfile_object *) o; + if (! value) + { + PyErr_SetString (PyExc_TypeError, + "cannot delete the pretty_printers attribute"); + return -1; + } + + if (! PyList_Check (value)) + { + PyErr_SetString (PyExc_TypeError, + "the pretty_printers attribute must be a list"); + return -1; + } + + /* Take care in case the LHS and RHS are related somehow. */ + tmp = self->printers; + Py_INCREF (value); + self->printers = value; + Py_XDECREF (tmp); + + return 0; +} + + + +/* Clear the OBJFILE pointer in an Objfile object and remove the + reference. */ +static void +clean_up_objfile (struct objfile *objfile, void *datum) +{ + PyGILState_STATE state; + objfile_object *object = datum; + + state = PyGILState_Ensure (); + object->objfile = NULL; + Py_DECREF ((PyObject *) object); + PyGILState_Release (state); +} + +/* Return a borrowed reference to the Python object of type Objfile + representing OBJFILE. If the object has already been created, + return it. Otherwise, create it. Return NULL and set the Python + error on failure. */ +PyObject * +objfile_to_objfile_object (struct objfile *objfile) +{ + objfile_object *object; + + object = objfile_data (objfile, objfpy_objfile_data_key); + if (!object) + { + object = PyObject_New (objfile_object, &objfile_object_type); + if (object) + { + PyObject *dict; + + object->objfile = objfile; + + object->printers = PyList_New (0); + if (!object->printers) + { + Py_DECREF (object); + return NULL; + } + + set_objfile_data (objfile, objfpy_objfile_data_key, object); + } + } + + return (PyObject *) object; +} + +void +gdbpy_initialize_objfile (void) +{ + objfpy_objfile_data_key + = register_objfile_data_with_cleanup (clean_up_objfile); + + if (PyType_Ready (&objfile_object_type) < 0) + return; + + Py_INCREF (&objfile_object_type); + PyModule_AddObject (gdb_module, "Objfile", (PyObject *) &objfile_object_type); +} + + + +static PyGetSetDef objfile_getset[] = +{ + { "filename", objfpy_get_filename, NULL, + "The objfile's filename, or None.", NULL }, + { "pretty_printers", objfpy_get_printers, objfpy_set_printers, + "Pretty printers.", NULL }, + { NULL } +}; + +static PyTypeObject objfile_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Objfile", /*tp_name*/ + sizeof (objfile_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + objfpy_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*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 objfile object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + objfile_getset, /* 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 */ + objfpy_new, /* tp_new */ +}; diff --git a/gdb/python/python.c b/gdb/python/python.c index 52fc7808ca..78a23c7d71 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -22,6 +22,8 @@ #include "ui-out.h" #include "cli/cli-script.h" #include "gdbcmd.h" +#include "objfiles.h" +#include "observer.h" #include @@ -29,6 +31,10 @@ false otherwise. */ static int gdbpy_should_print_stack = 1; +/* This is true if we should auto-load python code when an objfile is + opened, false otherwise. */ +static int gdbpy_auto_load = 1; + #ifdef HAVE_PYTHON #include "python.h" @@ -301,6 +307,129 @@ gdbpy_print_stack (void) PyErr_Clear (); } + + +/* The "current" objfile. This is set when gdb detects that a new + objfile has been loaded. It is only set for the duration of a call + to gdbpy_new_objfile; it is NULL at other times. */ +static struct objfile *gdbpy_current_objfile; + +/* The file name we attempt to read. */ +#define GDBPY_AUTO_FILENAME "-gdb.py" + +/* This is a new_objfile observer callback which loads python code + based on the path to the objfile. */ +static void +gdbpy_new_objfile (struct objfile *objfile) +{ + char *realname; + char *filename, *debugfile; + int len; + FILE *input; + PyGILState_STATE state; + struct cleanup *cleanups; + + if (!gdbpy_auto_load || !objfile || !objfile->name) + return; + + state = PyGILState_Ensure (); + + gdbpy_current_objfile = objfile; + + realname = gdb_realpath (objfile->name); + len = strlen (realname); + filename = xmalloc (len + sizeof (GDBPY_AUTO_FILENAME)); + memcpy (filename, realname, len); + strcpy (filename + len, GDBPY_AUTO_FILENAME); + + input = fopen (filename, "r"); + debugfile = filename; + + cleanups = make_cleanup (xfree, filename); + make_cleanup (xfree, realname); + + if (!input && debug_file_directory) + { + /* Also try the same file in the separate debug info directory. */ + debugfile = xmalloc (strlen (filename) + + strlen (debug_file_directory) + 1); + strcpy (debugfile, debug_file_directory); + /* FILENAME is absolute, so we don't need a "/" here. */ + strcat (debugfile, filename); + + make_cleanup (xfree, debugfile); + input = fopen (debugfile, "r"); + } + + if (!input && gdb_datadir) + { + /* Also try the same file in a subdirectory of gdb's data + directory. */ + debugfile = xmalloc (strlen (gdb_datadir) + strlen (filename) + + strlen ("/auto-load") + 1); + strcpy (debugfile, gdb_datadir); + strcat (debugfile, "/auto-load"); + /* FILENAME is absolute, so we don't need a "/" here. */ + strcat (debugfile, filename); + + make_cleanup (xfree, debugfile); + input = fopen (debugfile, "r"); + } + + if (input) + { + /* We don't want to throw an exception here -- but the user + would like to know that something went wrong. */ + if (PyRun_SimpleFile (input, debugfile)) + gdbpy_print_stack (); + fclose (input); + } + + do_cleanups (cleanups); + gdbpy_current_objfile = NULL; + + PyGILState_Release (state); +} + +/* Return the current Objfile, or None if there isn't one. */ +static PyObject * +gdbpy_get_current_objfile (PyObject *unused1, PyObject *unused2) +{ + PyObject *result; + + if (! gdbpy_current_objfile) + Py_RETURN_NONE; + + result = objfile_to_objfile_object (gdbpy_current_objfile); + if (result) + Py_INCREF (result); + return result; +} + +/* Return a sequence holding all the Objfiles. */ +static PyObject * +gdbpy_objfiles (PyObject *unused1, PyObject *unused2) +{ + struct objfile *objf; + PyObject *list; + + list = PyList_New (0); + if (!list) + return NULL; + + ALL_OBJFILES (objf) + { + PyObject *item = objfile_to_objfile_object (objf); + if (!item || PyList_Append (list, item) == -1) + { + Py_DECREF (list); + return NULL; + } + } + + return list; +} + #else /* HAVE_PYTHON */ /* Dummy implementation of the gdb "python" command. */ @@ -399,6 +528,15 @@ Enables or disables printing of Python stack traces."), &set_python_list, &show_python_list); + add_setshow_boolean_cmd ("auto-load", class_maintenance, + &gdbpy_auto_load, _("\ +Enable or disable auto-loading of Python code when an object is opened."), _("\ +Show whether Python code will be auto-loaded when an object is opened."), _("\ +Enables or disables auto-loading of Python code when an object is opened."), + NULL, NULL, + &set_python_list, + &show_python_list); + #ifdef HAVE_PYTHON Py_Initialize (); PyEval_InitThreads (); @@ -414,9 +552,12 @@ Enables or disables printing of Python stack traces."), gdbpy_initialize_frames (); gdbpy_initialize_commands (); gdbpy_initialize_functions (); + gdbpy_initialize_objfile (); PyRun_SimpleString ("import gdb"); + observer_attach_new_objfile (gdbpy_new_objfile); + gdbpy_doc_cst = PyString_FromString ("__doc__"); /* Create a couple objects which are used for Python's stdout and @@ -465,6 +606,11 @@ static PyMethodDef GdbMethods[] = { "get_parameter", get_parameter, METH_VARARGS, "Return a gdb parameter's value" }, + { "current_objfile", gdbpy_get_current_objfile, METH_NOARGS, + "Return the current Objfile being loaded, or None." }, + { "objfiles", gdbpy_objfiles, METH_NOARGS, + "Return a sequence of all loaded objfiles." }, + { "selected_frame", gdbpy_selected_frame, METH_NOARGS, "selected_frame () -> gdb.Frame.\n\ Return the selected frame object." }, diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index dc559990f0..ff1cfea252 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2009-05-27 Tom Tromey + + * gdb.python/python.exp (gdb_py_test_multiple): Add two objfile + tests. + * gdb.python/python-value.exp (py_objfile_tests): New proc. + Call it. + 2009-05-27 Pedro Alves * gdb.mi/nsthrexec.c, gdb.mi/mi-nsthrexec.exp: New. diff --git a/gdb/testsuite/gdb.python/python-value.exp b/gdb/testsuite/gdb.python/python-value.exp index b3b57463dc..93e9d893d0 100644 --- a/gdb/testsuite/gdb.python/python-value.exp +++ b/gdb/testsuite/gdb.python/python-value.exp @@ -236,6 +236,15 @@ proc test_value_in_inferior {} { gdb_test "python print 'result =', arg0.address" "= 0x\[\[:xdigit:\]\]+" "Test address attribute" } +# A few objfile tests. +proc test_objfiles {} { + gdb_test "python\nok=False\nfor file in gdb.objfiles():\n if 'python-value' in file.filename:\n ok=True\nprint ok\nend" "True" + + gdb_test "python print gdb.objfiles()\[0\].pretty_printers" "\\\[\\\]" + + gdb_test "python gdb.objfiles()\[0\].pretty_printers = 0" \ + "pretty_printers attribute must be a list.*Error while executing Python code." +} # Start with a fresh gdb. @@ -256,6 +265,7 @@ test_value_creation test_value_numeric_ops test_value_boolean test_value_compare +test_objfiles # The following tests require execution. diff --git a/gdb/testsuite/gdb.python/python.exp b/gdb/testsuite/gdb.python/python.exp index a0c9b391cd..5223fc8e58 100644 --- a/gdb/testsuite/gdb.python/python.exp +++ b/gdb/testsuite/gdb.python/python.exp @@ -71,3 +71,6 @@ gdb_py_test_multiple "indented multi-line python command" \ " print 'hello, world!'" "" \ "foo ()" "" \ "end" "hello, world!" + +gdb_test "python print gdb.current_objfile()" "None" +gdb_test "python print gdb.objfiles()" "\\\[\\\]" -- 2.34.1