From: Andrew Burgess <aburgess@redhat.com>
To: gdb-patches@sourceware.org
Cc: Andrew Burgess <aburgess@redhat.com>
Subject: [PATCHv2 3/3] gdb/python: add Corefile.mapped_files method
Date: Tue, 23 Sep 2025 14:44:08 +0100 [thread overview]
Message-ID: <9ab589510f784da2752b72d0b1385afa33aca406.1758634958.git.aburgess@redhat.com> (raw)
In-Reply-To: <cover.1758634958.git.aburgess@redhat.com>
Add a new Corefile.mapped_files method which returns a list of
gdb.CorefileMappedFile objects.
Each gdb.CorefileMappedFile object represents a file that was mapped
into the process when the core file was created.
A gdb.CorefileMappedFile has attributes:
+ filename -- A string, the name of the mapped file.
+ build_id -- A string or None, the build-id of the mapped file if
GDB could find it (None if not).
+ is_main_executable -- A boolean, True if this mapping is the main
executable.
+ regions -- A list containing the regions of this file that were
mapped into the process.
The 'regions' list is a list of gdb.CorefileMappedFileRegion objects,
each of these objects has the following attributes:
+ start -- the start address within the inferior.
+ end -- the end address within the inferior.
+ file_offset -- the offset within the mapped file for this mapping.
There are docs and tests.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32844
---
gdb/NEWS | 21 ++
gdb/doc/python.texi | 61 ++++
gdb/python/py-corefile.c | 397 +++++++++++++++++++++++
gdb/testsuite/gdb.python/py-corefile.exp | 58 ++++
gdb/testsuite/gdb.python/py-corefile.py | 144 ++++++++
5 files changed, 681 insertions(+)
create mode 100644 gdb/testsuite/gdb.python/py-corefile.py
diff --git a/gdb/NEWS b/gdb/NEWS
index 07838e41bd2..5cdd81a6ff3 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -45,6 +45,27 @@ single-inf-arg in qSupported
contains the gdb.Corefile object if a core file is loaded into
the inferior, otherwise, this contains None.
+ ** New gdb.Corefile class which represents a loaded core file. This
+ has an attribute Corefile.filename, the file name of the loaded
+ core file, and a method Corefile.is_valid(), which returns False
+ when a Corefile object becomes invalid (e.g. when the core file
+ is unloaded). There is also Corefile.mapped_files() which
+ returns a list of CorefileMappedFile objects, representing files
+ that were mapped into the core file when it was created.
+
+ ** New gdb.CorefileMappedFile type representing a file that was
+ mapped when the core file was created. Has read-only attributes
+ filename (string), build_id (string), is_main_executable
+ (boolean), and regions (list of CorefileMappedFileRegion objects).
+
+ ** New gdb.CorefileMappedFileRegion type, which represents a mapped
+ region of a file (see gdb.CorefileMappedFile above). Has
+ read-only attributes start, end, and file_offset.
+
+ ** New Inferior.corefile attribute. This read only attribute
+ contains the gdb.Corefile object if a core file is loaded into
+ the inferior, otherwise, this contains None.
+
*** Changes in GDB 17
* Debugging Linux programs that use x86-64 or x86-64 with 32-bit pointer
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index d25567e8943..b37d84a989e 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -8667,12 +8667,73 @@ Core Files In Python
accessed.
@end defun
+@defun Corefile.mapped_files ()
+Return a list of @code{gdb.CorefileMappedFile} (see below) objects
+representing files that were mapped into the process when the core
+file was created. This information is read from the @samp{NT_FILE}
+core file note on Linux. Not every target supports accessing this
+information, for targets without support, an empty list will be
+returned.
+@end defun
+
One may add arbitrary attributes to @code{gdb.Corefile} objects in the
usual Python way. This is useful if, for example, one needs to do
some extra record keeping associated with the corefile.
@xref{choosing attribute names}, for guidance on selecting a suitable
name for new attributes.
+The @code{Corefile.mapped_files ()} method returns a list of
+@code{gdb.CorefileMappedFile} objects. Each of these objects
+represents a file that was fully, or partially, mapped into the
+processes address space when the core file was created.
+
+A @code{gdb.CorefileMappedFile} object has the following attributes:
+
+@defvar CorefileMappedFile.filename
+This read only attribute contains a non-empty string, the file name of
+the mapped file.
+@end defvar
+
+@defvar CorefileMappedFile.build_id
+This read only attribute contains a non-empty string or @code{None}.
+This is the build-id of the mapped file extracted from the core file,
+or @code{None} if there was no build-id, or @value{GDBN} was unable to
+extract the build-id.
+@end defvar
+
+@defvar CorefileMappedFile.is_main_executable
+This read only attribute is @code{True} if @value{GDBN} believes this
+mapping represents the main executable for which this core file was
+created. This will be @code{False} for all other mappings.
+@end defvar
+
+@defvar CorefileMappedFile.regions
+This read only attribute contains a list of
+@code{gdb.CorefileMappedFileRegion} objects. Each of these objects
+describes a region of the file that was mapped into the process when
+the core file was created, further details are given below.
+@end defvar
+
+The @code{gdb.CorefileMappedFileRegion} object describes which part of
+a file that was mapped into a process when the core file was created.
+
+A @code{gdb.CorefileMappedFile} object has the following attributes:
+
+@defvar CorefileMappedFileRegion.start
+This read only attribute contains the start address of this mapping
+within the inferior.
+@end defvar
+
+@defvar CorefileMappedFileRegion.end
+This read only attribute contains end address of this mapping within
+the inferior.
+@end defvar
+
+@defvar CorefileMappedFileRegion.file_offset
+This read only attribute contains the offset within the mapped file
+for this mapping.
+@end defvar
+
@node Python Auto-loading
@subsection Python Auto-loading
@cindex Python auto-loading
diff --git a/gdb/python/py-corefile.c b/gdb/python/py-corefile.c
index f199a2c82be..757369fa0a3 100644
--- a/gdb/python/py-corefile.c
+++ b/gdb/python/py-corefile.c
@@ -21,6 +21,8 @@
#include "progspace.h"
#include "observable.h"
#include "inferior.h"
+#include "gdbcore.h"
+#include "gdbsupport/rsp-low.h"
/* A gdb.Corefile object. */
@@ -37,11 +39,61 @@ struct corefile_object
/* Dictionary holding user-added attributes. This is the __dict__
attribute of the object. This is an owning reference. */
PyObject *dict;
+
+ /* A Tuple of gdb.CorefileMappedFile objects. This tuple is only created
+ the first time the user calls gdb.Corefile.mapped_files(), the result
+ is cached here. If this pointer is not NULL then this is an owning
+ pointer (i.e. this owns a reference to the Tuple). */
+ PyObject *mapped_files;
};
extern PyTypeObject corefile_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("corefile_object");
+/* A gdb.CorefileMapped object. */
+
+struct corefile_mapped_file_object
+{
+ PyObject_HEAD
+
+ /* The name of a file that was mapped when the core file was created.
+ This is a 'str' object. */
+ PyObject *filename;
+
+ /* The build-id of a file that was mapped when the core file was
+ created. This is either a 'str' if the file had a build-id, or
+ 'None' if there was no build-id for this file. */
+ PyObject *build_id;
+
+ /* A List of gdb.CorefileMappedFileRegion objects. */
+ PyObject *regions;
+
+ /* True if this represents the main executable from which the core file
+ was created. */
+ bool is_main_exec_p;
+};
+
+extern PyTypeObject corefile_mapped_file_object_type
+ CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("corefile_mapped_file_object");
+
+/* A gdb.CorefileMappedFileRegion object. */
+
+struct corefile_mapped_file_region_object
+{
+ PyObject_HEAD
+
+ /* The start and end addresses for this mapping, these are addresses
+ within the inferior's address space. */
+ CORE_ADDR start;
+ CORE_ADDR end;
+
+ /* The offset within the mapped file for this mapping. */
+ ULONGEST file_offset;
+};
+
+extern PyTypeObject corefile_mapped_file_region_object_type
+ CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("corefile_mapped_file_region_object");
+
/* Clear the inferior pointer in a Corefile object OBJ when an inferior is
deleted. */
@@ -94,6 +146,7 @@ gdbpy_core_file_from_inferior (inferior *inf)
cfpy_dealloc will be called, which requires that the 'inferior' be
set to NULL. */
object->inferior = nullptr;
+ object->mapped_files = nullptr;
object->dict = PyDict_New ();
if (object->dict == nullptr)
return nullptr;
@@ -168,6 +221,123 @@ cfpy_is_valid (PyObject *self, PyObject *args)
Py_RETURN_TRUE;
}
+/* Implement gdb.Corefile.mapped_files (). Return a List of
+ gdb.CorefileMappedFile objects. The list is created the first time
+ this method is called, and then cached within the gdb.Corefile object,
+ future calls just return a reference to the same list. */
+
+static PyObject *
+cfpy_mapped_files (PyObject *self, PyObject *args)
+{
+ corefile_object *obj = (corefile_object *) self;
+
+ CFPY_REQUIRE_VALID (obj);
+
+ /* If we have already created the List then just return another reference
+ to the existing list. */
+ if (obj->mapped_files != nullptr)
+ {
+ Py_INCREF (obj->mapped_files);
+ return obj->mapped_files;
+ }
+
+ /* Get all the mapping data from GDB. */
+ std::vector<core_mapped_file> mapped_files;
+ try
+ {
+ mapped_files
+ = gdb_read_core_file_mappings (obj->inferior->arch (),
+ current_program_space->core_bfd ());
+ }
+ catch (const gdb_exception &except)
+ {
+ return gdbpy_handle_gdb_exception (nullptr, except);
+ }
+
+ /* Create a new list to hold the results. */
+ gdbpy_ref<> tuple (PyTuple_New (mapped_files.size ()));
+ if (tuple == nullptr)
+ return nullptr;
+
+ /* Create each gdb.CorefileMappedFile object. */
+ Py_ssize_t tuple_idx = 0;
+ for (const core_mapped_file &file : mapped_files)
+ {
+ /* The filename 'str' object. */
+ gdbpy_ref<> filename
+ = host_string_to_python_string (file.filename.c_str ());
+ if (filename == nullptr)
+ return nullptr;
+
+ /* The build-id object. Either a 'str' or 'None'. */
+ gdbpy_ref<> build_id;
+ if (file.build_id != nullptr)
+ {
+ std::string hex_form = bin2hex (file.build_id->data,
+ file.build_id->size);
+
+ build_id
+ = host_string_to_python_string (hex_form.c_str ());
+ if (build_id == nullptr)
+ return nullptr;
+ }
+ else
+ build_id = gdbpy_ref<>::new_reference (Py_None);
+
+ /* List to hold all the gdb.CorefileMappedFileRegion objects. */
+ gdbpy_ref<> regions (PyTuple_New (file.regions.size ()));
+ if (regions == nullptr)
+ return nullptr;
+
+ /* Create all the gdb.CorefileMappedFileRegion objects. */
+ Py_ssize_t regions_idx = 0;
+ for (const core_mapped_file::region &r : file.regions)
+ {
+ /* Actually create the object. */
+ gdbpy_ref<corefile_mapped_file_region_object> region_obj
+ (PyObject_New (corefile_mapped_file_region_object,
+ &corefile_mapped_file_region_object_type));
+ if (region_obj == nullptr)
+ return nullptr;
+
+ /* Initialise the object. */
+ region_obj->start = r.start;
+ region_obj->end = r.end;
+ region_obj->file_offset = r.file_ofs;
+
+ /* Add to the gdb.CorefileMappedFileRegion list. */
+ if (PyTuple_SetItem (regions.get (), regions_idx++,
+ (PyObject *) region_obj.release ()) < 0)
+ return nullptr;
+ }
+
+ /* Actually create the gdb.CorefileMappedFile object. */
+ gdbpy_ref<corefile_mapped_file_object> entry
+ (PyObject_New (corefile_mapped_file_object,
+ &corefile_mapped_file_object_type));
+ if (entry == nullptr)
+ return nullptr;
+
+ /* Initialise the object. */
+ entry->filename = filename.release ();
+ entry->build_id = build_id.release ();
+ entry->regions = regions.release ();
+ entry->is_main_exec_p = file.is_main_exec;
+
+ /* Add to the gdb.CorefileMappedFile list. */
+ if (PyTuple_SetItem (tuple.get (), tuple_idx++,
+ (PyObject *) entry.release ()) < 0)
+ return nullptr;
+ }
+
+ /* No errors. Move the reference currently in LIST into the Corefile
+ object itself. Then create a new reference and hand this back to the
+ user. */
+ obj->mapped_files = tuple.release ();
+ Py_INCREF (obj->mapped_files);
+ return obj->mapped_files;
+}
+
/* Callback from gdb::observers::core_file_changed. The core file in
PSPACE has been changed. */
@@ -191,6 +361,7 @@ cfpy_dealloc (PyObject *obj)
gdb_assert (corefile->inferior == nullptr);
Py_XDECREF (corefile->dict);
+ Py_XDECREF (corefile->mapped_files);
Py_TYPE (obj)->tp_free (obj);
}
@@ -215,6 +386,114 @@ cfpy_repr (PyObject *self)
\f
+/* Called when a gdb.CorefileMappedFile is destroyed. */
+
+static void
+cfmfpy_dealloc (PyObject *obj)
+{
+ corefile_mapped_file_object *mapped_file
+ = (corefile_mapped_file_object *) obj;
+
+ Py_XDECREF (mapped_file->filename);
+ Py_XDECREF (mapped_file->build_id);
+ Py_XDECREF (mapped_file->regions);
+
+ Py_TYPE (obj)->tp_free (obj);
+}
+
+/* Read the gdb.CorefileMappedFile.filename attribute. */
+
+static PyObject *
+cfmfpy_get_filename (PyObject *self, void *closure)
+{
+ corefile_mapped_file_object *obj
+ = (corefile_mapped_file_object *) self;
+
+ gdb_assert (obj->filename != nullptr);
+
+ Py_INCREF (obj->filename);
+ return obj->filename;
+}
+
+/* Read the gdb.CorefileMappedFile.build_id attribute. */
+
+static PyObject *
+cfmfpy_get_build_id (PyObject *self, void *closure)
+{
+ corefile_mapped_file_object *obj
+ = (corefile_mapped_file_object *) self;
+
+ gdb_assert (obj->build_id != nullptr);
+
+ Py_INCREF (obj->build_id);
+ return obj->build_id;
+}
+
+/* Read the gdb.CorefileMappedFile.regions attribute. */
+
+static PyObject *
+cfmfpy_get_regions (PyObject *self, void *closure)
+{
+ corefile_mapped_file_object *obj
+ = (corefile_mapped_file_object *) self;
+
+ gdb_assert (obj->regions != nullptr);
+
+ Py_INCREF (obj->regions);
+ return obj->regions;
+}
+
+/* Read the gdb.CorefileMappedFile.is_main_executable attribute. */
+
+static PyObject *
+cfmf_is_main_exec (PyObject *self, void *closure)
+{
+ corefile_mapped_file_object *obj
+ = (corefile_mapped_file_object *) self;
+
+ if (obj->is_main_exec_p)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+\f
+
+/* Read the gdb.CorefileMappedFileRegion.start attribute. */
+
+static PyObject *
+cfmfrpy_get_start (PyObject *self, void *closure)
+{
+ corefile_mapped_file_region_object *obj
+ = (corefile_mapped_file_region_object *) self;
+
+ return gdb_py_object_from_ulongest (obj->start).release ();
+}
+
+/* Read the gdb.CorefileMappedFileRegion.end attribute. */
+
+static PyObject *
+cfmfrpy_get_end (PyObject *self, void *closure)
+{
+ corefile_mapped_file_region_object *obj
+ = (corefile_mapped_file_region_object *) self;
+
+ return gdb_py_object_from_ulongest (obj->end).release ();
+}
+
+/* Read the gdb.CorefileMappedFileRegion.file_offset attribute. */
+
+static PyObject *
+cfmfrpy_get_file_offset (PyObject *self, void *closure)
+{
+ corefile_mapped_file_region_object *obj
+ = (corefile_mapped_file_region_object *) self;
+
+ return gdb_py_object_from_ulongest (obj->file_offset).release ();
+}
+
+\f
+
static int
gdbpy_initialize_corefile ()
{
@@ -224,6 +503,12 @@ gdbpy_initialize_corefile ()
if (gdbpy_type_ready (&corefile_object_type) < 0)
return -1;
+ if (gdbpy_type_ready (&corefile_mapped_file_object_type) < 0)
+ return -1;
+
+ if (gdbpy_type_ready (&corefile_mapped_file_region_object_type) < 0)
+ return -1;
+
return 0;
}
@@ -245,6 +530,10 @@ static PyMethodDef corefile_object_methods[] =
{ "is_valid", cfpy_is_valid, METH_NOARGS,
"is_valid () -> Boolean.\n\
Return true if this Corefile is valid, false if not." },
+ { "mapped_files", cfpy_mapped_files, METH_NOARGS,
+ "mapped_files () -> List of mapping tuples.\n\
+Return a list of tuples. Each tuple represents a mapping from the\
+core file." },
{ nullptr }
};
@@ -289,3 +578,111 @@ PyTypeObject corefile_object_type =
0, /* tp_alloc */
0, /* tp_new */
};
+
+static gdb_PyGetSetDef corefile_mapped_file_object_getset[] =
+{
+ { "filename", cfmfpy_get_filename, nullptr,
+ "The filename of a CorefileMappedFile object.", nullptr },
+ { "build_id", cfmfpy_get_build_id, nullptr,
+ "The build-id of a CorefileMappedFile object or None.", nullptr },
+ { "regions", cfmfpy_get_regions, nullptr,
+ "The list of regions from a CorefileMappedFile object.", nullptr },
+ { "is_main_executable", cfmf_is_main_exec, nullptr,
+ "True for the main executable mapping, otherwise False.", nullptr },
+ { nullptr }
+};
+
+PyTypeObject corefile_mapped_file_object_type =
+{
+ PyVarObject_HEAD_INIT (NULL, 0)
+ "gdb.CorefileMappedFile", /*tp_name*/
+ sizeof (corefile_mapped_file_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ cfmfpy_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 corefile mapped file 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 */
+ corefile_mapped_file_object_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 */
+ 0, /* tp_new */
+};
+
+static gdb_PyGetSetDef corefile_mapped_file_region_object_getset[] =
+{
+ { "start", cfmfrpy_get_start, nullptr,
+ "The start address of a CorefileMappedFileRegion object.", nullptr },
+ { "end", cfmfrpy_get_end, nullptr,
+ "The end address of a CorefileMappedFileRegion object.", nullptr },
+ { "file_offset", cfmfrpy_get_file_offset, nullptr,
+ "The file offset of a CorefileMappedFileRegion object.", nullptr },
+ { nullptr }
+};
+
+PyTypeObject corefile_mapped_file_region_object_type =
+{
+ PyVarObject_HEAD_INIT (NULL, 0)
+ "gdb.CorefileMappedFileRegion", /*tp_name*/
+ sizeof (corefile_mapped_file_region_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*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 corefile mapped file region 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 */
+ corefile_mapped_file_region_object_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 */
+ 0, /* tp_new */
+};
diff --git a/gdb/testsuite/gdb.python/py-corefile.exp b/gdb/testsuite/gdb.python/py-corefile.exp
index e9254bd9e78..3b57cc0e250 100644
--- a/gdb/testsuite/gdb.python/py-corefile.exp
+++ b/gdb/testsuite/gdb.python/py-corefile.exp
@@ -176,3 +176,61 @@ with_test_prefix "remove second inferior" {
gdb_test "python print(core1.is_valid())" "^True" \
"check inferior 1 core file is still valid"
}
+
+# Test the Corefile.mapped_files() API. The Python script that is
+# sourced here implements 'info proc mappings' in Python using the
+# mapped_files API. The output from the built-in command, and the
+# Python command should be identical.
+with_test_prefix "test mapped files data" {
+ clean_restart
+
+ set remote_python_file \
+ [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py]
+
+ # Load the Python script into GDB.
+ gdb_test "source $remote_python_file" "^Success" \
+ "source python script"
+
+ # Load the core file.
+ gdb_test "core-file $corefile" ".*" \
+ "load core file"
+
+ # Two files to write the output to.
+ set out_1 [standard_output_file ${gdb_test_file_name}-out-1.txt]
+ set out_2 [standard_output_file ${gdb_test_file_name}-out-2.txt]
+
+ # Run the built-in command, then the new Python command, capture
+ # the output.
+ gdb_test "pipe info proc mappings | tee $out_1" ".*" \
+ "capture built-in mappings output"
+ gdb_test "pipe info proc py-mappings | tee $out_2" ".*" \
+ "capture Python based mappings data"
+
+ # Check the output is identical.
+ gdb_test "shell diff -s $out_1 $out_2" \
+ "Files \[^\r\n\]+-out-1.txt and \[^\r\n\]+-out-2.txt are identical" \
+ "diff input and output one"
+
+ # Check build-ids within the core file mapping data.
+ gdb_test "check-build-ids" "^PASS"
+
+ # Check the is_main_executable flag in the mapping data.
+ gdb_test "check-main-executable" "^PASS"
+
+ # Check that the mapped files "list" is actually an immutable
+ # tuple.
+ gdb_test_no_output "python core = gdb.selected_inferior().corefile"
+ gdb_test_no_output "python mapped_files = core.mapped_files()"
+ gdb_test "python print(type(mapped_files))" \
+ "^<class 'tuple'>"
+ gdb_test "python mapped_files\[0\] = None" \
+ "'tuple' object does not support item assignment"
+ gdb_test "python print(mapped_files\[0\] is None)" "^False"
+
+ # And same for the list of regions for a mapped file.
+ gdb_test_no_output "python regions = mapped_files\[0\].regions"
+ gdb_test "python print(type(regions))" \
+ "^<class 'tuple'>"
+ gdb_test "python regions\[0\] = None" \
+ "'tuple' object does not support item assignment"
+}
diff --git a/gdb/testsuite/gdb.python/py-corefile.py b/gdb/testsuite/gdb.python/py-corefile.py
new file mode 100644
index 00000000000..cffd037a23b
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-corefile.py
@@ -0,0 +1,144 @@
+# Copyright (C) 2025 Free Software Foundation, Inc.
+
+# 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/>.
+
+import pathlib
+
+
+class Mapping:
+ def __init__(self, mapping, region):
+ self._mapping = mapping
+ self._region = region
+
+ @property
+ def start(self):
+ return self._region.start
+
+ @property
+ def end(self):
+ return self._region.end
+
+ @property
+ def offset(self):
+ return self._region.file_offset
+
+ @property
+ def filename(self):
+ return self._mapping.filename
+
+
+def info_proc_mappings():
+ print("Mapped address spaces:")
+ print("")
+ format_str = "%-18s %-18s %-18s %-18s %s "
+ print(format_str % ("Start Addr", "End Addr", "Size", "Offset", "File"))
+
+ core = gdb.selected_inferior().corefile
+ mappings = core.mapped_files()
+
+ result = []
+ for m in mappings:
+ for r in m.regions:
+ result.append(Mapping(m, r))
+
+ result.sort(key=lambda x: x.start)
+ for r in result:
+ sz = r.end - r.start
+ print(
+ format_str
+ % (
+ "0x%016x" % r.start,
+ "0x%016x" % r.end,
+ "0x%-16x" % sz,
+ "0x%-16x" % r.offset,
+ "%s" % r.filename,
+ )
+ )
+
+
+class InfoProcPyMappings(gdb.Command):
+ def __init__(self):
+ gdb.Command.__init__(self, "info proc py-mappings", gdb.COMMAND_DATA)
+
+ def invoke(self, args, from_tty):
+ info_proc_mappings()
+
+
+InfoProcPyMappings()
+
+
+class CheckBuildIds(gdb.Command):
+ def __init__(self):
+ gdb.Command.__init__(self, "check-build-ids", gdb.COMMAND_DATA)
+
+ def invoke(self, args, from_tty):
+ inf = gdb.selected_inferior()
+ objfiles = inf.progspace.objfiles()
+
+ path_to_build_id = {}
+
+ for o in objfiles:
+ if not o.is_file or o.build_id is None:
+ continue
+ p = pathlib.Path(o.filename).resolve()
+ b = o.build_id
+ path_to_build_id[p] = b
+
+ count = 0
+ core_mapped_files = inf.corefile.mapped_files()
+ for m in core_mapped_files:
+ p = pathlib.Path(m.filename).resolve()
+ b = m.build_id
+
+ if p in path_to_build_id:
+ count += 1
+ assert path_to_build_id[p] == b, "build-id mismatch for %s" % p
+
+ assert count > 0, "no mapped files checked"
+
+ print("PASS")
+
+
+CheckBuildIds()
+
+
+class CheckMainExec(gdb.Command):
+ def __init__(self):
+ gdb.Command.__init__(self, "check-main-executable", gdb.COMMAND_DATA)
+
+ def invoke(self, args, from_tty):
+ inf = gdb.selected_inferior()
+ pspace = inf.progspace
+ exec_filename = pathlib.Path(pspace.executable_filename).resolve()
+
+ count = 0
+ core_mapped_files = inf.corefile.mapped_files()
+ for m in core_mapped_files:
+ if not m.is_main_executable:
+ continue
+
+ p = pathlib.Path(m.filename).resolve()
+
+ count += 1
+ assert exec_filename == p, "main exec filename mismatch"
+
+ assert count == 1, "invalid main executable count"
+
+ print("PASS")
+
+
+CheckMainExec()
+
+
+print("Success")
--
2.47.1
next prev parent reply other threads:[~2025-09-23 13:55 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-02 16:03 [PATCH 0/3] Core file Python API Andrew Burgess
2025-09-02 16:03 ` [PATCH 1/3] gdb/python: introduce gdb.Corefile API Andrew Burgess
2025-09-02 16:26 ` Eli Zaretskii
2025-09-16 17:25 ` Tom Tromey
2025-09-23 13:50 ` Andrew Burgess
2025-09-02 16:03 ` [PATCH 2/3] gdb: make structured core file mappings processing global Andrew Burgess
2025-09-16 17:28 ` Tom Tromey
2025-09-02 16:03 ` [PATCH 3/3] gdb/python: add Corefile.mapped_files method Andrew Burgess
2025-09-16 17:54 ` Tom Tromey
2025-09-23 13:52 ` Andrew Burgess
2025-09-23 13:44 ` [PATCHv2 0/3] Core file Python API Andrew Burgess
2025-09-23 13:44 ` [PATCHv2 1/3] gdb/python: introduce gdb.Corefile API Andrew Burgess
2025-10-03 18:56 ` Tom Tromey
2025-10-06 8:54 ` Andrew Burgess
2025-10-06 15:39 ` Tom Tromey
2025-10-06 16:13 ` Andrew Burgess
2025-09-23 13:44 ` [PATCHv2 2/3] gdb: make structured core file mappings processing global Andrew Burgess
2025-10-13 13:57 ` Lancelot SIX
2025-10-13 14:37 ` Andrew Burgess
2025-10-13 15:16 ` Six, Lancelot
2025-10-14 9:12 ` Lancelot SIX
2025-09-23 13:44 ` Andrew Burgess [this message]
2025-10-03 19:15 ` [PATCHv2 3/3] gdb/python: add Corefile.mapped_files method Tom Tromey
2025-10-07 6:24 ` Tom de Vries
2025-10-07 12:21 ` Andrew Burgess
2025-10-07 13:08 ` Tom de Vries
2025-10-07 13:26 ` Andrew Burgess
2025-10-07 14:38 ` Andrew Burgess
2025-10-07 15:43 ` Tom de Vries
2025-10-07 16:28 ` Andrew Burgess
2025-10-08 9:29 ` Andrew Burgess
2025-10-08 10:36 ` Tom de Vries
2025-10-08 14:14 ` Andrew Burgess
2025-10-08 15:43 ` Tom de Vries
2025-10-08 16:03 ` Andrew Burgess
2025-10-16 20:00 ` Tom Tromey
2025-10-17 10:02 ` Andrew Burgess
2025-10-17 13:32 ` Andrew Burgess
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=9ab589510f784da2752b72d0b1385afa33aca406.1758634958.git.aburgess@redhat.com \
--to=aburgess@redhat.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox