mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2026-08-27 00:26:02 -04:00
The current implementation of gdb_py_tp_name() leaks a reference to the object returned by PyType_GetFullyQualifiedName() for Python >= 3.13, and PyType_GetQualName() for Python >= 3.11. Managing the strong reference on the returned PyObject* with a gdbpy_ref<> fixes the reference count, but also causes the temporary object to be deallocated on function exit. As a consequence, the 'const char *' returned by PyUnicode_AsUTF8AndSize() becomes dangling and can no longer safely be returned. The proposed approach consists in changing gdb_py_tp_name() to return a std::string, and forcing a copy of the 'const char *' value, statically or dynamically allocated, stored in a temporary or non-temporary PyObject, depending on the version of Python it was compiled with. An unfortunate side effect of this fix is that every call sites where the tp_name is printed, must now use `.c_str()' because PyErr_Format() and its siblings cannot handle std::string. Approved-By: Andrew Burgess <aburgess@redhat.com>
707 lines
20 KiB
C
707 lines
20 KiB
C
/* Python interface to core files.
|
||
|
||
Copyright (C) 2025-2026 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 "python-internal.h"
|
||
#include "progspace.h"
|
||
#include "observable.h"
|
||
#include "inferior.h"
|
||
#include "gdbcore.h"
|
||
#include "gdbsupport/rsp-low.h"
|
||
#include "py-event.h"
|
||
|
||
/* A gdb.Corefile object. */
|
||
|
||
struct corefile_object : public gdbpy_dict_wrapper
|
||
{
|
||
/* The inferior this core file is attached to. This will be set to NULL
|
||
when the inferior is deleted, or if a different core file is loaded
|
||
for the inferior. When this is NULL the gdb.Corefile object is
|
||
considered invalid.*/
|
||
struct inferior *inferior;
|
||
|
||
/* 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;
|
||
|
||
/* A gdb.CorefileMapped object. */
|
||
|
||
struct corefile_mapped_file_object : public PyObject
|
||
{
|
||
/* 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;
|
||
};
|
||
|
||
static_assert (gdb::is_python_allocatable_v<corefile_mapped_file_object>);
|
||
|
||
extern PyTypeObject corefile_mapped_file_object_type;
|
||
|
||
/* A gdb.CorefileMappedFileRegion object. */
|
||
|
||
struct corefile_mapped_file_region_object : public PyObject
|
||
{
|
||
/* 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;
|
||
};
|
||
|
||
static_assert (gdb::is_python_allocatable_v<corefile_mapped_file_region_object>);
|
||
|
||
extern PyTypeObject corefile_mapped_file_region_object_type;
|
||
|
||
/* Clear the inferior pointer in a Corefile object OBJ when an inferior is
|
||
deleted. */
|
||
|
||
struct inferior_corefile_deleter
|
||
{
|
||
void operator() (corefile_object *obj)
|
||
{
|
||
if (!gdb_python_initialized)
|
||
return;
|
||
|
||
gdbpy_enter enter_py;
|
||
|
||
/* When OBJECT goes out of scope this will Py_DECREF on OBJ. */
|
||
gdbpy_ref<corefile_object> object (obj);
|
||
|
||
/* Clearing the inferior pointer marks the gdb.Corefile as invalid. */
|
||
object->inferior = nullptr;
|
||
}
|
||
};
|
||
|
||
/* Store a gdb.Corefile object in an inferior's registry. */
|
||
|
||
static const registry<inferior>::key<corefile_object,
|
||
inferior_corefile_deleter>
|
||
cfpy_inferior_corefile_data_key;
|
||
|
||
/* See python-internal.h. */
|
||
|
||
gdbpy_ref<>
|
||
gdbpy_core_file_from_inferior (inferior *inf)
|
||
{
|
||
gdb_assert (inf != nullptr);
|
||
gdb_assert (inf->pspace != nullptr);
|
||
|
||
if (get_inferior_core_bfd (inf) == nullptr)
|
||
return py_none ();
|
||
|
||
PyObject *result = (PyObject *) cfpy_inferior_corefile_data_key.get (inf);
|
||
if (result != nullptr)
|
||
return gdbpy_ref<>::new_reference (result);
|
||
|
||
gdbpy_ref<corefile_object> object
|
||
(PyObject_New (corefile_object, &corefile_object_type));
|
||
if (object == nullptr)
|
||
return nullptr;
|
||
|
||
/* Ensure the 'inferior' field is set to NULL. If the PyDict_New call fails
|
||
then the gdb.Corefile will be discarded and cfpy_dealloc will be called,
|
||
which requires that the 'inferior' be set to NULL. */
|
||
object->inferior = nullptr;
|
||
object->mapped_files = nullptr;
|
||
if (!object->allocate_dict ())
|
||
return nullptr;
|
||
|
||
/* Now that the gdb.Corefile has been successfully initialised and we know
|
||
that it is going to be passed back to the user, move it out of the invalid
|
||
state by setting the 'inferior' field to a non NULL value. */
|
||
object->inferior = inf;
|
||
|
||
/* PyObject_New initializes the new object with a refcount of 1. This counts
|
||
for the reference we are keeping in the inferior corefile data. */
|
||
cfpy_inferior_corefile_data_key.set (inf, object.get ());
|
||
|
||
return gdbpy_ref<>::new_reference (object.release ());
|
||
}
|
||
|
||
/* Return true if OBJ is valid. */
|
||
|
||
static bool
|
||
cfpy_corefile_object_is_valid (const corefile_object *obj)
|
||
{
|
||
if (obj->inferior == nullptr)
|
||
return false;
|
||
|
||
return get_inferior_core_bfd (obj->inferior) != nullptr;
|
||
}
|
||
|
||
/* Require that COREFILE_OBJ be a valid core file. A valid core file
|
||
object has a valid program space, and the program space has a core file
|
||
loaded into it. */
|
||
#define CFPY_REQUIRE_VALID(corefile_obj) \
|
||
do { \
|
||
if (!cfpy_corefile_object_is_valid (corefile_obj)) \
|
||
{ \
|
||
PyErr_SetString (PyExc_RuntimeError, \
|
||
_("Corefile no longer exists.")); \
|
||
return nullptr; \
|
||
} \
|
||
} while (0)
|
||
|
||
/* Read the gdb.Corefile.filename attribute. */
|
||
|
||
static PyObject *
|
||
cfpy_get_filename (PyObject *self, void *closure)
|
||
{
|
||
corefile_object *obj = (corefile_object *) self;
|
||
|
||
CFPY_REQUIRE_VALID (obj);
|
||
|
||
/* If the program space's core file had been cleared, then this Corefile
|
||
object would have been invalidated. */
|
||
bfd *abfd = get_inferior_core_bfd (obj->inferior);
|
||
gdb_assert (abfd != nullptr);
|
||
|
||
return host_string_to_python_string (bfd_get_filename (abfd)).release ();
|
||
}
|
||
|
||
/* Implementation of gdb.Corefile.is_valid (self) -> Boolean.
|
||
Returns True if this core file object is associated with a program space
|
||
that still exists, an the program space still has a core file loaded. */
|
||
|
||
static PyObject *
|
||
cfpy_is_valid (PyObject *self, PyObject *args)
|
||
{
|
||
corefile_object *obj = (corefile_object *) self;
|
||
|
||
if (!cfpy_corefile_object_is_valid (obj))
|
||
return py_false ().release ();
|
||
|
||
return py_true ().release ();
|
||
}
|
||
|
||
/* 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 (),
|
||
get_inferior_core_bfd (obj->inferior));
|
||
}
|
||
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 = 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;
|
||
}
|
||
|
||
/* Emit a CorefileChangedEvent event, INF is the inferior in which the core
|
||
file changed. Return 0 on success, or a negative value on error. */
|
||
|
||
static int
|
||
emit_corefile_changed_event (inferior *inf)
|
||
{
|
||
/* If there are no listeners then we are done. */
|
||
if (evregpy_no_listeners_p (gdb_py_events.corefile_changed))
|
||
return 0;
|
||
|
||
gdbpy_ref<> event_obj
|
||
= create_event_object (&corefile_changed_event_object_type);
|
||
if (event_obj == nullptr)
|
||
return -1;
|
||
|
||
gdbpy_ref<inferior_object> inf_obj = inferior_to_inferior_object (inf);
|
||
if (inf_obj == nullptr
|
||
|| evpy_add_attribute (event_obj.get (), "inferior",
|
||
inf_obj.get ()) < 0)
|
||
return -1;
|
||
|
||
return evpy_emit_event (event_obj.get (), gdb_py_events.corefile_changed);
|
||
}
|
||
|
||
/* Callback from gdb::observers::core_file_changed. The core file for
|
||
INF has been changed. */
|
||
|
||
static void
|
||
cfpy_corefile_changed (inferior *inf)
|
||
{
|
||
/* It's safe to do this even if Python is not initialized, but there
|
||
should be nothing to clear in that case. */
|
||
cfpy_inferior_corefile_data_key.clear (inf);
|
||
|
||
if (!gdb_python_initialized)
|
||
return;
|
||
|
||
gdbpy_enter enter_py;
|
||
|
||
if (emit_corefile_changed_event (inf) < 0)
|
||
gdbpy_print_stack ();
|
||
}
|
||
|
||
/* Called when a gdb.Corefile is destroyed. */
|
||
|
||
static void
|
||
cfpy_dealloc (PyObject *obj)
|
||
{
|
||
corefile_object *corefile = (corefile_object *) obj;
|
||
|
||
/* Every gdb.Corefile is cached in an inferior's registry. The only way
|
||
for a gdb.Corefile to be deallocated is to remove the object reference
|
||
from the registry (and dec its ref count), but before we do that, we
|
||
set the object's inferior pointer to NULL. */
|
||
gdb_assert (corefile->inferior == nullptr);
|
||
|
||
Py_XDECREF (corefile->dict);
|
||
Py_XDECREF (corefile->mapped_files);
|
||
|
||
Py_TYPE (obj)->tp_free (obj);
|
||
}
|
||
|
||
/* __repr__ implementation for gdb.Corefile. */
|
||
|
||
static PyObject *
|
||
cfpy_repr (PyObject *self)
|
||
{
|
||
corefile_object *obj = (corefile_object *) self;
|
||
|
||
if (!cfpy_corefile_object_is_valid (obj))
|
||
return gdb_py_invalid_object_repr (self);
|
||
|
||
bfd *core_bfd = get_inferior_core_bfd (obj->inferior);
|
||
gdb_assert (core_bfd != nullptr);
|
||
return PyUnicode_FromFormat ("<%s inferior=%d filename='%s'>",
|
||
gdbpy_py_obj_tp_name (self).c_str (),
|
||
obj->inferior->num,
|
||
bfd_get_filename (core_bfd));
|
||
}
|
||
|
||
|
||
|
||
/* 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)
|
||
return py_true ().release ();
|
||
else
|
||
return py_false ().release ();
|
||
}
|
||
|
||
|
||
|
||
/* 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 ();
|
||
}
|
||
|
||
|
||
|
||
static int
|
||
gdbpy_initialize_corefile ()
|
||
{
|
||
gdb::observers::core_file_changed.attach (cfpy_corefile_changed,
|
||
"py-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;
|
||
}
|
||
|
||
GDBPY_INITIALIZE_FILE (gdbpy_initialize_corefile);
|
||
|
||
|
||
|
||
static gdb_PyGetSetDef corefile_getset[] =
|
||
{
|
||
gdbpy_dict_wrapper_cfg_dict_getter ("corefile"),
|
||
{ "filename", cfpy_get_filename, nullptr,
|
||
"The filename of a valid Corefile object.", nullptr },
|
||
{ nullptr }
|
||
};
|
||
|
||
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 }
|
||
};
|
||
|
||
PyTypeObject corefile_object_type =
|
||
{
|
||
PyVarObject_HEAD_INIT (nullptr, 0)
|
||
"gdb.Corefile", /*tp_name*/
|
||
sizeof (corefile_object), /*tp_basicsize*/
|
||
0, /*tp_itemsize*/
|
||
cfpy_dealloc, /*tp_dealloc*/
|
||
0, /*tp_print*/
|
||
0, /*tp_getattr*/
|
||
0, /*tp_setattr*/
|
||
0, /*tp_compare*/
|
||
cfpy_repr, /*tp_repr*/
|
||
0, /*tp_as_number*/
|
||
0, /*tp_as_sequence*/
|
||
0, /*tp_as_mapping*/
|
||
0, /*tp_hash */
|
||
0, /*tp_call*/
|
||
0, /*tp_str*/
|
||
gdbpy_dict_wrapper_getsetattro,
|
||
0, /*tp_as_buffer*/
|
||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||
"GDB corefile object", /* tp_doc */
|
||
0, /* tp_traverse */
|
||
0, /* tp_clear */
|
||
0, /* tp_richcompare */
|
||
0, /* tp_weaklistoffset */
|
||
0, /* tp_iter */
|
||
0, /* tp_iternext */
|
||
corefile_object_methods, /* tp_methods */
|
||
0, /* tp_members */
|
||
corefile_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_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 */
|
||
};
|