aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/version.h2
-rw-r--r--gdb/NEWS12
-rw-r--r--gdb/cli/cli-script.c4
-rw-r--r--gdb/cli/cli-script.h6
-rw-r--r--gdb/cli/cli-style.c21
-rw-r--r--gdb/cli/cli-style.h19
-rwxr-xr-xgdb/contrib/gdb-add-index.sh4
-rw-r--r--gdb/doc/gdb.texinfo6
-rw-r--r--gdb/doc/python.texi10
-rw-r--r--gdb/dwarf2/attribute.h4
-rw-r--r--gdb/gcore-1.in4
-rw-r--r--gdb/python/py-symbol.c73
-rw-r--r--gdb/python/py-symtab.c181
-rw-r--r--gdb/python/py-type.c92
-rw-r--r--gdb/python/py-value.c40
-rw-r--r--gdb/python/python-internal.h195
-rw-r--r--gdb/python/python.c39
-rw-r--r--gdb/solib-svr4.c99
-rw-r--r--gdb/testsuite/gdb.python/py-arch.exp5
-rw-r--r--gdb/testsuite/gdb.python/py-styled-execute.exp109
-rw-r--r--gdb/testsuite/gdb.python/py-symtab.exp28
-rw-r--r--gdb/testsuite/gdb.python/py-type.exp15
-rw-r--r--gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.c2
-rw-r--r--gdb/value.c54
-rw-r--r--gdbserver/netbsd-low.cc5
25 files changed, 726 insertions, 303 deletions
diff --git a/bfd/version.h b/bfd/version.h
index c90df07..01650eb 100644
--- a/bfd/version.h
+++ b/bfd/version.h
@@ -16,7 +16,7 @@
In releases, the date is not included in either version strings or
sonames. */
-#define BFD_VERSION_DATE 20250318
+#define BFD_VERSION_DATE 20250320
#define BFD_VERSION @bfd_version@
#define BFD_VERSION_STRING @bfd_version_package@ @bfd_version_string@
#define REPORT_BUGS_TO @report_bugs_to@
diff --git a/gdb/NEWS b/gdb/NEWS
index 0aac7a7..2fdb849 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -45,6 +45,13 @@ show riscv numeric-register-names
(e.g 'x1') or their abi names (e.g. 'ra').
Defaults to 'off', matching the old behaviour (abi names).
+* Changed commands
+
+info sharedlibrary
+ On Linux and FreeBSD, the addresses shown in the output of this
+ command are now for the full memory range allocated to the shared
+ library.
+
* Python API
** New class gdb.Color for dealing with colors.
@@ -58,6 +65,11 @@ show riscv numeric-register-names
was never documented in the GDB manual, so users should not have
been using it.
+ ** gdb.execute has an additional 'styling' argument. When True, then
+ output will be styled. The default for this argument is True
+ when output is going to standard output, and False when output is
+ going to a string.
+
* Guile API
** New type <gdb:color> for dealing with colors.
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index 9131768..5decf3b 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -422,14 +422,14 @@ execute_control_commands (struct command_line *cmdlines, int from_tty)
std::string
execute_control_commands_to_string (struct command_line *commands,
- int from_tty)
+ int from_tty, bool term_out)
{
std::string result;
execute_fn_to_string (result, [&] ()
{
execute_control_commands (commands, from_tty);
- }, false);
+ }, term_out);
return result;
}
diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h
index 23bd83e..df7316e 100644
--- a/gdb/cli/cli-script.h
+++ b/gdb/cli/cli-script.h
@@ -143,10 +143,12 @@ extern void execute_control_commands (struct command_line *cmdlines,
/* Run execute_control_commands for COMMANDS. Capture its output into
the returned string, do not display it to the screen. BATCH_FLAG
- will be temporarily set to true. */
+ will be temporarily set to true. When TERM_OUT is true the output is
+ collected with terminal behavior (e.g. with styling). When TERM_OUT is
+ false raw output will be collected (e.g. no styling). */
extern std::string execute_control_commands_to_string
- (struct command_line *commands, int from_tty);
+ (struct command_line *commands, int from_tty, bool term_out);
/* Exported to gdb/breakpoint.c */
diff --git a/gdb/cli/cli-style.c b/gdb/cli/cli-style.c
index 3ca30a4..b436275 100644
--- a/gdb/cli/cli-style.c
+++ b/gdb/cli/cli-style.c
@@ -51,6 +51,25 @@ static const char * const cli_intensities[] = {
nullptr
};
+/* When true styling is being temporarily suppressed. */
+
+static bool scoped_disable_styling_p = false;
+
+/* See cli/cli-style.h. */
+
+scoped_disable_styling::scoped_disable_styling ()
+{
+ m_old_value = scoped_disable_styling_p;
+ scoped_disable_styling_p = true;
+}
+
+/* See cli/cli-style.h. */
+
+scoped_disable_styling::~scoped_disable_styling ()
+{
+ scoped_disable_styling_p = m_old_value;
+}
+
/* Return true if GDB's output terminal should support styling, otherwise,
return false. This function really checks for things that indicate
styling might not be supported, so a return value of false indicates
@@ -91,7 +110,7 @@ disable_cli_styling ()
bool
term_cli_styling ()
{
- return cli_styling;
+ return cli_styling && !scoped_disable_styling_p;
}
/* See cli/cli-style.h. */
diff --git a/gdb/cli/cli-style.h b/gdb/cli/cli-style.h
index 18827ce..e94b48d 100644
--- a/gdb/cli/cli-style.h
+++ b/gdb/cli/cli-style.h
@@ -171,4 +171,23 @@ extern void disable_cli_styling ();
/* Return true styled output is currently enabled. */
extern bool term_cli_styling ();
+/* Allow styling to be temporarily suppressed without changing the value of
+ 'set style enabled' user setting. This is useful in, for example, the
+ Python gdb.execute() call which can produce unstyled output. */
+struct scoped_disable_styling
+{
+ /* Temporarily suppress styling without changing the value of 'set
+ style enabled' user setting. */
+ scoped_disable_styling ();
+
+ /* If the constructor started suppressing styling, then styling is
+ resumed after this destructor call. */
+ ~scoped_disable_styling ();
+
+private:
+
+ /* The value to restore in the destructor. */
+ bool m_old_value;
+};
+
#endif /* GDB_CLI_CLI_STYLE_H */
diff --git a/gdb/contrib/gdb-add-index.sh b/gdb/contrib/gdb-add-index.sh
index 4db1234..b299f83 100755
--- a/gdb/contrib/gdb-add-index.sh
+++ b/gdb/contrib/gdb-add-index.sh
@@ -22,8 +22,8 @@ GDB=${GDB:=gdb}
OBJCOPY=${OBJCOPY:=objcopy}
READELF=${READELF:=readelf}
-PKGVERSION=@PKGVERSION@
-VERSION=@VERSION@
+PKGVERSION="@PKGVERSION@"
+VERSION="@VERSION@"
myname="${0##*/}"
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 4734310..e034ac5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -22166,6 +22166,12 @@ Print the names of the shared libraries which are currently loaded
that match @var{regex}. If @var{regex} is omitted then print
all shared libraries that are loaded.
+For each library, @value{GDBN} also lists the address range allocated
+to that library if it can be determined. If the address range cannot
+be determined then the address range for the @code{.text} section from
+the library will be listed. If the @code{.text} section cannot be
+found then no addresses will be listed.
+
@kindex info dll
@item info dll @var{regex}
This is an alias of @code{info sharedlibrary}.
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 0dbb37b..50342bb 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -285,7 +285,7 @@ offered for debugging purposes only, expect them to change over time.
A string containing the python directory (@pxref{Python}).
@end defvar
-@defun gdb.execute (command @r{[}, from_tty @r{[}, to_string@r{]]})
+@defun gdb.execute (command @r{[}, from_tty @r{[}, to_string @w{@r{[}, styling @r{]]]}})
Evaluate @var{command}, a string, as a @value{GDBN} CLI command.
If a GDB exception happens while @var{command} runs, it is
translated as described in @ref{Exception Handling,,Exception Handling}.
@@ -302,6 +302,14 @@ returned as a string. The default is @code{False}, in which case the
return value is @code{None}. If @var{to_string} is @code{True}, the
@value{GDBN} virtual terminal will be temporarily set to unlimited width
and height, and its pagination will be disabled; @pxref{Screen Size}.
+
+When @var{styling} is @code{True}, the output, whether sent to
+standard output, or to a string, will have styling applied, if
+@value{GDBN}'s standard output supports styling, and @kbd{show style
+enabled} is @kbd{on}. When @var{styling} is @code{False} then no
+styling is applied. The default for @var{styling} is @code{True} when
+@var{to_string} is @code{False}, and @code{False} when @var{to_string}
+is @code{True}.
@end defun
@defun gdb.breakpoints ()
diff --git a/gdb/dwarf2/attribute.h b/gdb/dwarf2/attribute.h
index 4dce04d..ce6c563 100644
--- a/gdb/dwarf2/attribute.h
+++ b/gdb/dwarf2/attribute.h
@@ -105,8 +105,8 @@ struct attribute
/* Return an unsigned constant value. This only handles constant
forms (i.e., form_is_constant -- and not the extended list of
"unsigned" forms) and assumes an unsigned value is desired. This
- can intended for use with DWARF-defined enumerations like DW_CC_*
- or DW_INL_*, but also in situations where a nonnegative constant
+ can be used with DWARF-defined enumerations like DW_CC_* or
+ DW_INL_*, but also in situations where a nonnegative constant
integer is specified by DWARF.
If a signed form and negative value is used, or if a non-constant
diff --git a/gdb/gcore-1.in b/gdb/gcore-1.in
index 129e369..c0979a5 100644
--- a/gdb/gcore-1.in
+++ b/gdb/gcore-1.in
@@ -20,8 +20,8 @@
# It starts up gdb, attaches to the given PID and invokes the gcore command.
#
-PKGVERSION=@PKGVERSION@
-VERSION=@VERSION@
+PKGVERSION="@PKGVERSION@"
+VERSION="@VERSION@"
# Need to check for -o option, but set default basename to "core".
prefix=core
diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
index 3ce1049..3028a30 100644
--- a/gdb/python/py-symbol.c
+++ b/gdb/python/py-symbol.c
@@ -29,12 +29,6 @@ struct symbol_object {
PyObject_HEAD
/* The GDB symbol structure this object is wrapping. */
struct symbol *symbol;
- /* A symbol object is associated with an objfile, so keep track with
- doubly-linked list, rooted in the objfile. This lets us
- invalidate the underlying struct symbol when the objfile is
- deleted. */
- symbol_object *prev;
- symbol_object *next;
};
/* Require a valid symbol. All access to symbol_object->symbol should be
@@ -50,26 +44,8 @@ struct symbol_object {
} \
} while (0)
-/* A deleter that is used when an objfile is about to be freed. */
-struct symbol_object_deleter
-{
- void operator() (symbol_object *obj)
- {
- while (obj)
- {
- symbol_object *next = obj->next;
-
- obj->symbol = NULL;
- obj->next = NULL;
- obj->prev = NULL;
-
- obj = next;
- }
- }
-};
-
-static const registry<objfile>::key<symbol_object, symbol_object_deleter>
- sympy_objfile_data_key;
+static const gdbpy_registry<gdbpy_memoizing_registry_storage<symbol_object,
+ symbol, &symbol_object::symbol>> sympy_registry;
static PyObject *
sympy_str (PyObject *self)
@@ -347,19 +323,18 @@ static void
set_symbol (symbol_object *obj, struct symbol *symbol)
{
obj->symbol = symbol;
- obj->prev = NULL;
- if (symbol->is_objfile_owned ()
- && symbol->symtab () != NULL)
+ if (symbol->is_objfile_owned ())
{
- struct objfile *objfile = symbol->objfile ();
-
- obj->next = sympy_objfile_data_key.get (objfile);
- if (obj->next)
- obj->next->prev = obj;
- sympy_objfile_data_key.set (objfile, obj);
+ /* Can it really happen that symbol->symtab () is NULL? */
+ if (symbol->symtab () != nullptr)
+ {
+ sympy_registry.add (symbol->objfile (), obj);
+ }
}
else
- obj->next = NULL;
+ {
+ sympy_registry.add (symbol->arch (), obj);
+ }
}
/* Create a new symbol object (gdb.Symbol) that encapsulates the struct
@@ -369,6 +344,15 @@ symbol_to_symbol_object (struct symbol *sym)
{
symbol_object *sym_obj;
+ /* Look if there's already a gdb.Symbol object for given SYMBOL
+ and if so, return it. */
+ if (sym->is_objfile_owned ())
+ sym_obj = sympy_registry.lookup (sym->objfile (), sym);
+ else
+ sym_obj = sympy_registry.lookup (sym->arch (), sym);
+ if (sym_obj != nullptr)
+ return (PyObject*)sym_obj;
+
sym_obj = PyObject_New (symbol_object, &symbol_object_type);
if (sym_obj)
set_symbol (sym_obj, sym);
@@ -390,15 +374,14 @@ sympy_dealloc (PyObject *obj)
{
symbol_object *sym_obj = (symbol_object *) obj;
- if (sym_obj->prev)
- sym_obj->prev->next = sym_obj->next;
- else if (sym_obj->symbol != NULL
- && sym_obj->symbol->is_objfile_owned ()
- && sym_obj->symbol->symtab () != NULL)
- sympy_objfile_data_key.set (sym_obj->symbol->objfile (), sym_obj->next);
- if (sym_obj->next)
- sym_obj->next->prev = sym_obj->prev;
- sym_obj->symbol = NULL;
+ if (sym_obj->symbol != nullptr)
+ {
+ if (sym_obj->symbol->is_objfile_owned ())
+ sympy_registry.remove (sym_obj->symbol->objfile (), sym_obj);
+ else
+ sympy_registry.remove (sym_obj->symbol->arch (), sym_obj);
+ }
+
Py_TYPE (obj)->tp_free (obj);
}
diff --git a/gdb/python/py-symtab.c b/gdb/python/py-symtab.c
index 99a5094..2381e4d 100644
--- a/gdb/python/py-symtab.c
+++ b/gdb/python/py-symtab.c
@@ -28,39 +28,12 @@ struct symtab_object {
PyObject_HEAD
/* The GDB Symbol table structure. */
struct symtab *symtab;
- /* A symtab object is associated with an objfile, so keep track with
- a doubly-linked list, rooted in the objfile. This allows
- invalidation of the underlying struct symtab when the objfile is
- deleted. */
- symtab_object *prev;
- symtab_object *next;
-};
-
-/* This function is called when an objfile is about to be freed.
- Invalidate the symbol table as further actions on the symbol table
- would result in bad data. All access to obj->symtab should be
- gated by STPY_REQUIRE_VALID which will raise an exception on
- invalid symbol tables. */
-struct stpy_deleter
-{
- void operator() (symtab_object *obj)
- {
- while (obj)
- {
- symtab_object *next = obj->next;
-
- obj->symtab = NULL;
- obj->next = NULL;
- obj->prev = NULL;
- obj = next;
- }
- }
};
extern PyTypeObject symtab_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("symtab_object");
-static const registry<objfile>::key<symtab_object, stpy_deleter>
- stpy_objfile_data_key;
+static const gdbpy_registry<gdbpy_memoizing_registry_storage<symtab_object,
+ symtab, &symtab_object::symtab>> stpy_registry;
/* Require a valid symbol table. All access to symtab_object->symtab
should be gated by this call. */
@@ -77,8 +50,6 @@ static const registry<objfile>::key<symtab_object, stpy_deleter>
struct sal_object {
PyObject_HEAD
- /* The GDB Symbol table structure. */
- PyObject *symtab;
/* The GDB Symbol table and line structure. */
struct symtab_and_line *sal;
/* A Symtab and line object is associated with an objfile, so keep
@@ -94,34 +65,19 @@ struct sal_object {
data. All access to obj->sal should be gated by
SALPY_REQUIRE_VALID which will raise an exception on invalid symbol
table and line objects. */
-struct salpy_deleter
+struct salpy_invalidator
{
void operator() (sal_object *obj)
{
- gdbpy_enter enter_py;
-
- while (obj)
- {
- sal_object *next = obj->next;
-
- gdbpy_ref<> tmp (obj->symtab);
- obj->symtab = Py_None;
- Py_INCREF (Py_None);
-
- obj->next = NULL;
- obj->prev = NULL;
- xfree (obj->sal);
- obj->sal = NULL;
-
- obj = next;
- }
+ xfree (obj->sal);
+ obj->sal = nullptr;
}
};
extern PyTypeObject sal_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("sal_object");
-static const registry<objfile>::key<sal_object, salpy_deleter>
- salpy_objfile_data_key;
+static const gdbpy_registry<gdbpy_tracking_registry_storage<sal_object,
+ symtab_and_line, &sal_object::sal, salpy_invalidator>> salpy_registry;
/* Require a valid symbol table and line object. All access to
sal_object->sal should be gated by this call. */
@@ -272,18 +228,15 @@ salpy_str (PyObject *self)
{
const char *filename;
sal_object *sal_obj;
- struct symtab_and_line *sal = NULL;
+ struct symtab_and_line *sal = nullptr;
SALPY_REQUIRE_VALID (self, sal);
sal_obj = (sal_object *) self;
- if (sal_obj->symtab == Py_None)
+ if (sal_obj->sal->symtab == nullptr)
filename = "<unknown>";
else
- {
- symtab *symtab = symtab_object_to_symtab (sal_obj->symtab);
- filename = symtab_to_filename_for_display (symtab);
- }
+ filename = symtab_to_filename_for_display (sal_obj->sal->symtab);
return PyUnicode_FromFormat ("symbol and line for %s, line %d", filename,
sal->line);
@@ -292,16 +245,12 @@ salpy_str (PyObject *self)
static void
stpy_dealloc (PyObject *obj)
{
- symtab_object *symtab = (symtab_object *) obj;
-
- if (symtab->prev)
- symtab->prev->next = symtab->next;
- else if (symtab->symtab)
- stpy_objfile_data_key.set (symtab->symtab->compunit ()->objfile (),
- symtab->next);
- if (symtab->next)
- symtab->next->prev = symtab->prev;
- symtab->symtab = NULL;
+ symtab_object *symtab_obj = (symtab_object *) obj;
+
+ if (symtab_obj->symtab != nullptr)
+ stpy_registry.remove (symtab_obj->symtab->compunit ()->objfile(),
+ symtab_obj);
+
Py_TYPE (obj)->tp_free (obj);
}
@@ -346,13 +295,13 @@ static PyObject *
salpy_get_symtab (PyObject *self, void *closure)
{
struct symtab_and_line *sal;
- sal_object *self_sal = (sal_object *) self;
SALPY_REQUIRE_VALID (self, sal);
- Py_INCREF (self_sal->symtab);
-
- return (PyObject *) self_sal->symtab;
+ if (sal->symtab == nullptr)
+ Py_RETURN_NONE;
+ else
+ return symtab_to_symtab_object (sal->symtab);
}
/* Implementation of gdb.Symtab_and_line.is_valid (self) -> Boolean.
@@ -375,17 +324,10 @@ salpy_dealloc (PyObject *self)
{
sal_object *self_sal = (sal_object *) self;
- if (self_sal->prev)
- self_sal->prev->next = self_sal->next;
- else if (self_sal->symtab != Py_None)
- salpy_objfile_data_key.set
- (symtab_object_to_symtab (self_sal->symtab)->compunit ()->objfile (),
- self_sal->next);
-
- if (self_sal->next)
- self_sal->next->prev = self_sal->prev;
+ if (self_sal->sal != nullptr && self_sal->sal->symtab != nullptr)
+ salpy_registry.remove (self_sal->sal->symtab->compunit ()->objfile (),
+ self_sal);
- Py_DECREF (self_sal->symtab);
xfree (self_sal->sal);
Py_TYPE (self)->tp_free (self);
}
@@ -395,48 +337,20 @@ salpy_dealloc (PyObject *self)
Also, register the sal_object life-cycle with the life-cycle of the
object file associated with this sal, if needed. If a failure
occurs during the sal population, this function will return -1. */
-static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
+static void
set_sal (sal_object *sal_obj, struct symtab_and_line sal)
{
- PyObject *symtab_obj;
-
- if (sal.symtab)
- {
- symtab_obj = symtab_to_symtab_object (sal.symtab);
- /* If a symtab existed in the sal, but it cannot be duplicated,
- we exit. */
- if (symtab_obj == NULL)
- return -1;
- }
- else
- {
- symtab_obj = Py_None;
- Py_INCREF (Py_None);
- }
-
sal_obj->sal = ((struct symtab_and_line *)
xmemdup (&sal, sizeof (struct symtab_and_line),
sizeof (struct symtab_and_line)));
- sal_obj->symtab = symtab_obj;
- sal_obj->prev = NULL;
+ sal_obj->prev = nullptr;
+ sal_obj->next = nullptr;
/* If the SAL does not have a symtab, we do not add it to the
objfile cleanup observer linked list. */
- if (sal_obj->symtab != Py_None)
- {
- symtab *symtab = symtab_object_to_symtab (sal_obj->symtab);
-
- sal_obj->next
- = salpy_objfile_data_key.get (symtab->compunit ()->objfile ());
- if (sal_obj->next)
- sal_obj->next->prev = sal_obj;
-
- salpy_objfile_data_key.set (symtab->compunit ()->objfile (), sal_obj);
- }
- else
- sal_obj->next = NULL;
-
- return 0;
+ symtab *symtab = sal_obj->sal->symtab;
+ if (symtab != nullptr)
+ salpy_registry.add (symtab->compunit ()->objfile (), sal_obj);
}
/* Given a symtab, and a symtab_object that has previously been
@@ -448,16 +362,8 @@ static void
set_symtab (symtab_object *obj, struct symtab *symtab)
{
obj->symtab = symtab;
- obj->prev = NULL;
- if (symtab)
- {
- obj->next = stpy_objfile_data_key.get (symtab->compunit ()->objfile ());
- if (obj->next)
- obj->next->prev = obj;
- stpy_objfile_data_key.set (symtab->compunit ()->objfile (), obj);
- }
- else
- obj->next = NULL;
+ if (symtab != nullptr)
+ stpy_registry.add (symtab->compunit ()->objfile (), obj);
}
/* Create a new symbol table (gdb.Symtab) object that encapsulates the
@@ -467,6 +373,16 @@ symtab_to_symtab_object (struct symtab *symtab)
{
symtab_object *symtab_obj;
+ /* Look if there's already a gdb.Symtab object for given SYMTAB
+ and if so, return it. */
+ if (symtab != nullptr)
+ {
+ symtab_obj = stpy_registry.lookup (symtab->compunit ()->objfile (),
+ symtab);
+ if (symtab_obj != nullptr)
+ return (PyObject*)symtab_obj;
+ }
+
symtab_obj = PyObject_New (symtab_object, &symtab_object_type);
if (symtab_obj)
set_symtab (symtab_obj, symtab);
@@ -479,14 +395,13 @@ symtab_to_symtab_object (struct symtab *symtab)
PyObject *
symtab_and_line_to_sal_object (struct symtab_and_line sal)
{
- gdbpy_ref<sal_object> sal_obj (PyObject_New (sal_object, &sal_object_type));
- if (sal_obj != NULL)
- {
- if (set_sal (sal_obj.get (), sal) < 0)
- return NULL;
- }
+ sal_object *sal_obj;
+
+ sal_obj = PyObject_New (sal_object, &sal_object_type);
+ if (sal_obj != nullptr)
+ set_sal (sal_obj, sal);
- return (PyObject *) sal_obj.release ();
+ return (PyObject *) sal_obj;
}
/* Return struct symtab_and_line reference that is wrapped by this
@@ -560,7 +475,7 @@ PyTypeObject symtab_object_type = {
"gdb.Symtab", /*tp_name*/
sizeof (symtab_object), /*tp_basicsize*/
0, /*tp_itemsize*/
- stpy_dealloc, /*tp_dealloc*/
+ stpy_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index 11a96d5..24e754d 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -32,12 +32,6 @@ struct type_object
{
PyObject_HEAD
struct type *type;
-
- /* If a Type object is associated with an objfile, it is kept on a
- doubly-linked list, rooted in the objfile. This lets us copy the
- underlying struct type when the objfile is deleted. */
- struct type_object *prev;
- struct type_object *next;
};
extern PyTypeObject type_object_type
@@ -1162,75 +1156,61 @@ typy_richcompare (PyObject *self, PyObject *other, int op)
-/* Deleter that saves types when an objfile is being destroyed. */
-struct typy_deleter
+/* Forward declaration, see below. */
+static void set_type (type_object *obj, struct type *type);
+
+/* Invalidator that saves types when an objfile is being destroyed. */
+struct typy_invalidator
{
void operator() (type_object *obj)
{
- if (!gdb_python_initialized)
- return;
-
- /* This prevents another thread from freeing the objects we're
- operating on. */
- gdbpy_enter enter_py;
-
- copied_types_hash_t copied_types;
-
- while (obj)
+ if (obj->type->is_objfile_owned ())
{
- type_object *next = obj->next;
+ copied_types_hash_t copied_types;
- copied_types.clear ();
- obj->type = copy_type_recursive (obj->type, copied_types);
-
- obj->next = NULL;
- obj->prev = NULL;
-
- obj = next;
+ /* Set a copied (now arch-owned) type. As a side-effect this
+ adds OBJ to per-arch list. We do not need to remove it from
+ per-objfile list since the objfile is going to go completely
+ anyway. */
+ set_type (obj, copy_type_recursive (obj->type, copied_types));
+ }
+ else
+ {
+ obj->type = nullptr;
}
}
};
-static const registry<objfile>::key<type_object, typy_deleter>
- typy_objfile_data_key;
+static const gdbpy_registry<gdbpy_memoizing_registry_storage<type_object,
+ type, &type_object::type, typy_invalidator>> typy_registry;
static void
set_type (type_object *obj, struct type *type)
{
+ gdb_assert (type != nullptr);
+
obj->type = type;
- obj->prev = NULL;
- if (type != nullptr && type->objfile_owner () != nullptr)
- {
- struct objfile *objfile = type->objfile_owner ();
- obj->next = typy_objfile_data_key.get (objfile);
- if (obj->next)
- obj->next->prev = obj;
- typy_objfile_data_key.set (objfile, obj);
- }
+ if (type->objfile_owner () != nullptr)
+ typy_registry.add (type->objfile_owner (), obj);
else
- obj->next = NULL;
+ typy_registry.add (type->arch_owner (), obj);
}
static void
typy_dealloc (PyObject *obj)
{
- type_object *type = (type_object *) obj;
+ type_object *type_obj = (type_object *) obj;
- if (type->prev)
- type->prev->next = type->next;
- else if (type->type != nullptr && type->type->objfile_owner () != nullptr)
+ if (type_obj->type != nullptr)
{
- /* Must reset head of list. */
- struct objfile *objfile = type->type->objfile_owner ();
-
- if (objfile)
- typy_objfile_data_key.set (objfile, type->next);
+ if (type_obj->type->is_objfile_owned ())
+ typy_registry.remove (type_obj->type->objfile_owner (), type_obj);
+ else
+ typy_registry.remove (type_obj->type->arch_owner (), type_obj);
}
- if (type->next)
- type->next->prev = type->prev;
- Py_TYPE (type)->tp_free (type);
+ Py_TYPE (obj)->tp_free (obj);
}
/* Return number of fields ("length" of the field dictionary). */
@@ -1473,6 +1453,16 @@ type_to_type_object (struct type *type)
return gdbpy_handle_gdb_exception (nullptr, except);
}
+ /* Look if there's already a gdb.Type object for given TYPE
+ and if so, return it. */
+ if (type->is_objfile_owned ())
+ type_obj = typy_registry.lookup (type->objfile_owner (), type);
+ else
+ type_obj = typy_registry.lookup (type->arch_owner (), type);
+
+ if (type_obj != nullptr)
+ return (PyObject*)type_obj;
+
type_obj = PyObject_New (type_object, &type_object_type);
if (type_obj)
set_type (type_obj, type);
@@ -1684,7 +1674,7 @@ PyTypeObject type_object_type =
"gdb.Type", /*tp_name*/
sizeof (type_object), /*tp_basicsize*/
0, /*tp_itemsize*/
- typy_dealloc, /*tp_dealloc*/
+ typy_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index 02c50b4..cf1e3ea 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -60,7 +60,6 @@ struct value_object {
struct value_object *prev;
struct value *value;
PyObject *address;
- PyObject *type;
PyObject *dynamic_type;
PyObject *content_bytes;
};
@@ -84,8 +83,6 @@ valpy_clear_value (value_object *self)
self->value = nullptr;
Py_CLEAR (self->address);
- Py_CLEAR (self->type);
- Py_CLEAR (self->dynamic_type);
Py_CLEAR (self->content_bytes);
}
@@ -438,14 +435,7 @@ valpy_get_type (PyObject *self, void *closure)
{
value_object *obj = (value_object *) self;
- if (!obj->type)
- {
- obj->type = type_to_type_object (obj->value->type ());
- if (!obj->type)
- return NULL;
- }
- Py_INCREF (obj->type);
- return obj->type;
+ return type_to_type_object (obj->value->type ());
}
/* Return dynamic type of the value. */
@@ -454,13 +444,7 @@ static PyObject *
valpy_get_dynamic_type (PyObject *self, void *closure)
{
value_object *obj = (value_object *) self;
- struct type *type = NULL;
-
- if (obj->dynamic_type != NULL)
- {
- Py_INCREF (obj->dynamic_type);
- return obj->dynamic_type;
- }
+ struct type *type = nullptr;
try
{
@@ -493,23 +477,14 @@ valpy_get_dynamic_type (PyObject *self, void *closure)
else if (type->code () == TYPE_CODE_STRUCT)
type = value_rtti_type (val, NULL, NULL, NULL);
else
- {
- /* Re-use object's static type. */
- type = NULL;
- }
+ type = val->type ();
}
catch (const gdb_exception &except)
{
return gdbpy_handle_gdb_exception (nullptr, except);
}
- if (type == NULL)
- obj->dynamic_type = valpy_get_type (self, NULL);
- else
- obj->dynamic_type = type_to_type_object (type);
-
- Py_XINCREF (obj->dynamic_type);
- return obj->dynamic_type;
+ return type_to_type_object (type);
}
/* Implementation of gdb.Value.lazy_string ([encoding] [, length]) ->
@@ -1937,15 +1912,14 @@ value_to_value_object (struct value *val)
value_object *val_obj;
val_obj = PyObject_New (value_object, &value_object_type);
- if (val_obj != NULL)
+ if (val_obj != nullptr)
{
val->incref ();
val_obj->value = val;
val_obj->next = nullptr;
val_obj->prev = nullptr;
- val_obj->address = NULL;
- val_obj->type = NULL;
- val_obj->dynamic_type = NULL;
+ val_obj->address = nullptr;
+ val_obj->dynamic_type = nullptr;
val_obj->content_bytes = nullptr;
note_value (val_obj);
}
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index c48f260..3f1a206 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -22,6 +22,7 @@
#include "extension.h"
#include "extension-priv.h"
+#include "registry.h"
/* These WITH_* macros are defined by the CPython API checker that
comes with the Python plugin for GCC. See:
@@ -1145,4 +1146,198 @@ gdbpy_type_ready (PyTypeObject *type, PyObject *mod = nullptr)
# define PyType_Ready POISONED_PyType_Ready
#endif
+/* A class to manage lifecycle of Python objects for objects that are "owned"
+ by an objfile or a gdbarch. It keeps track of Python objects and when
+ the "owning" object (objfile or gdbarch) is about to be freed, ensures that
+ all Python objects "owned" by that object are properly invalidated.
+
+ The actual tracking of "owned" Python objects is handled externally
+ by storage class. Storage object is created for each owning object
+ on demand and it is deleted when owning object is about to be freed.
+
+ The storage class must provide two member types:
+
+ * obj_type - the type of Python object whose lifecycle is managed.
+ * val_type - the type of GDB structure the Python objects are
+ representing.
+
+ It must also provide following methods:
+
+ void add (obj_type *obj);
+ void remove (obj_type *obj);
+
+ Memoizing storage must in addition to method above provide:
+
+ obj_type *lookup (val_type *val);
+
+ Finally it must invalidate all registered Python objects upon deletion. */
+template <typename Storage>
+class gdbpy_registry
+{
+public:
+ using obj_type = typename Storage::obj_type;
+ using val_type = typename Storage::val_type;
+
+ /* Register Python object OBJ as being "owned" by OWNER. When OWNER is
+ about to be freed, OBJ will be invalidated. */
+ template <typename O>
+ void add (O *owner, obj_type *obj) const
+ {
+ get_storage (owner)->add (obj);
+ }
+
+ /* Unregister Python object OBJ. OBJ will no longer be invalidated when
+ OWNER is about to be be freed. */
+ template <typename O>
+ void remove (O *owner, obj_type *obj) const
+ {
+ get_storage (owner)->remove (obj);
+ }
+
+ /* Lookup pre-existing Python object for given VAL. Return such object
+ if found, otherwise return NULL. This method always returns new
+ reference. */
+ template <typename O>
+ obj_type *lookup (O *owner, val_type *val) const
+ {
+ obj_type *obj = get_storage (owner)->lookup (val);
+ Py_XINCREF (obj);
+ return obj;
+ }
+
+private:
+
+ template<typename O>
+ using StorageKey = typename registry<O>::template key<Storage>;
+
+ template<typename O>
+ Storage *get_storage (O *owner, const StorageKey<O> &key) const
+ {
+ Storage *r = key.get (owner);
+ if (r == nullptr)
+ {
+ r = new Storage();
+ key.set (owner, r);
+ }
+ return r;
+ }
+
+ Storage *get_storage (struct objfile* objf) const
+ {
+ return get_storage (objf, m_key_for_objf);
+ }
+
+ Storage *get_storage (struct gdbarch* arch) const
+ {
+ return get_storage (arch, m_key_for_arch);
+ }
+
+ const registry<objfile>::key<Storage> m_key_for_objf;
+ const registry<gdbarch>::key<Storage> m_key_for_arch;
+};
+
+/* Default invalidator for Python objects. */
+template <typename P, typename V, V* P::*val_slot>
+struct gdbpy_default_invalidator
+{
+ void operator() (P *obj)
+ {
+ obj->*val_slot = nullptr;
+ }
+};
+
+/* A "storage" implementation suitable for temporary (on-demand) objects. */
+template <typename P,
+ typename V,
+ V* P::*val_slot,
+ typename Invalidator = gdbpy_default_invalidator<P, V, val_slot>>
+class gdbpy_tracking_registry_storage
+{
+public:
+ using obj_type = P;
+ using val_type = V;
+
+ void add (obj_type *obj)
+ {
+ gdb_assert (obj != nullptr && obj->*val_slot != nullptr);
+
+ m_objects.insert (obj);
+ }
+
+ void remove (obj_type *obj)
+ {
+ gdb_assert (obj != nullptr && obj->*val_slot != nullptr);
+ gdb_assert (m_objects.contains (obj));
+
+ m_objects.erase (obj);
+ }
+
+ ~gdbpy_tracking_registry_storage ()
+ {
+ Invalidator invalidate;
+ gdbpy_enter enter_py;
+
+ for (auto each : m_objects)
+ invalidate (each);
+ m_objects.clear ();
+ }
+
+protected:
+ gdb::unordered_set<obj_type *> m_objects;
+};
+
+/* A "storage" implementation suitable for memoized (interned) Python objects.
+
+ Python objects are memoized (interned) temporarily, meaning that when user
+ drops all their references the Python object is deallocated and removed
+ from storage.
+ */
+template <typename P,
+ typename V,
+ V* P::*val_slot,
+ typename Invalidator = gdbpy_default_invalidator<P, V, val_slot>>
+class gdbpy_memoizing_registry_storage
+{
+public:
+ using obj_type = P;
+ using val_type = V;
+
+ void add (obj_type *obj)
+ {
+ gdb_assert (obj != nullptr && obj->*val_slot != nullptr);
+
+ m_objects[obj->*val_slot] = obj;
+ }
+
+ void remove (obj_type *obj)
+ {
+ gdb_assert (obj != nullptr && obj->*val_slot != nullptr);
+ gdb_assert (m_objects.contains (obj->*val_slot));
+
+ m_objects.erase (obj->*val_slot);
+ }
+
+ obj_type *lookup (val_type *val) const
+ {
+ auto result = m_objects.find (val);
+ if (result != m_objects.end ())
+ return result->second;
+ else
+ return nullptr;
+ }
+
+ ~gdbpy_memoizing_registry_storage ()
+ {
+ Invalidator invalidate;
+ gdbpy_enter enter_py;
+
+ for (auto each : m_objects)
+ invalidate (each.second);
+ m_objects.clear ();
+ }
+
+protected:
+ gdb::unordered_map<val_type *, obj_type *> m_objects;
+};
+
#endif /* GDB_PYTHON_PYTHON_INTERNAL_H */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 8f8030c..2aaa30c 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -36,6 +36,7 @@
#include "run-on-main-thread.h"
#include "observable.h"
#include "build-id.h"
+#include "cli/cli-style.h"
#if GDB_SELF_TEST
#include "gdbsupport/selftest.h"
@@ -660,12 +661,14 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
const char *arg;
PyObject *from_tty_obj = nullptr;
PyObject *to_string_obj = nullptr;
- static const char *keywords[] = { "command", "from_tty", "to_string",
- nullptr };
+ PyObject *styling = nullptr;
+ static const char *keywords[]
+ = { "command", "from_tty", "to_string", "styling", nullptr };
- if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|O!O!", keywords, &arg,
+ if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|O!O!O!", keywords, &arg,
&PyBool_Type, &from_tty_obj,
- &PyBool_Type, &to_string_obj))
+ &PyBool_Type, &to_string_obj,
+ &PyBool_Type, &styling))
return nullptr;
bool from_tty = false;
@@ -686,6 +689,15 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
to_string = (cmp != 0);
}
+ bool styling_p = !to_string;
+ if (styling != nullptr)
+ {
+ int cmp = PyObject_IsTrue (styling);
+ if (cmp < 0)
+ return nullptr;
+ styling_p = (cmp != 0);
+ }
+
std::string to_string_res;
scoped_restore preventer = prevent_dont_repeat ();
@@ -745,14 +757,29 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
scoped_restore save_uiout = make_scoped_restore (&current_uiout);
+ /* If the Python 'styling' argument was False then temporarily
+ disable styling. Otherwise, don't do anything, styling could
+ already be disabled for some other reason, we shouldn't override
+ that and force styling on. */
+ std::optional<scoped_disable_styling> disable_styling;
+ if (!styling_p)
+ disable_styling.emplace ();
+
/* Use the console interpreter uiout to have the same print format
for console or MI. */
interp = interp_lookup (current_ui, "console");
current_uiout = interp->interp_ui_out ();
if (to_string)
- to_string_res = execute_control_commands_to_string (lines.get (),
- from_tty);
+ {
+ /* Pass 'true' here to always request styling, however, if
+ the scoped_disable_styling disabled styling, or the user
+ has globally disabled styling, then the output will not be
+ styled. */
+ to_string_res
+ = execute_control_commands_to_string (lines.get (), from_tty,
+ true);
+ }
else
execute_control_commands (lines.get (), from_tty);
}
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 8378eca..398123f 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -3093,6 +3093,37 @@ svr4_truncate_ptr (CORE_ADDR addr)
return addr & (((CORE_ADDR) 1 << gdbarch_ptr_bit (current_inferior ()->arch ())) - 1);
}
+/* Find the LOAD-able program header in ABFD that contains ASECT. Return
+ NULL if no such header can be found. */
+
+static Elf_Internal_Phdr *
+find_loadable_elf_internal_phdr (bfd *abfd, bfd_section *asect)
+{
+ Elf_Internal_Ehdr *ehdr = elf_tdata (abfd)->elf_header;
+ Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr;
+
+ for (int i = 0; i < ehdr->e_phnum; i++)
+ {
+ if (phdr[i].p_type == PT_LOAD)
+ {
+ /* A section without the SEC_LOAD flag is a no-bits section
+ (e.g. .bss) and has zero size within ABFD. */
+ ULONGEST section_file_size
+ = (((bfd_section_flags (asect) & SEC_LOAD) != 0)
+ ? bfd_section_size (asect)
+ : 0);
+
+ if (asect->filepos >= phdr[i].p_offset
+ && ((asect->filepos + section_file_size)
+ <= (phdr[i].p_offset + phdr[i].p_filesz)))
+ return &phdr[i];
+ }
+ }
+
+ return nullptr;
+}
+
+/* Implement solib_ops::relocate_section_addresses() for svr4 targets. */
static void
svr4_relocate_section_addresses (solib &so, target_section *sec)
@@ -3101,6 +3132,74 @@ svr4_relocate_section_addresses (solib &so, target_section *sec)
sec->addr = svr4_truncate_ptr (sec->addr + lm_addr_check (so, abfd));
sec->endaddr = svr4_truncate_ptr (sec->endaddr + lm_addr_check (so, abfd));
+
+ struct bfd_section *asect = sec->the_bfd_section;
+ gdb_assert (asect != nullptr);
+
+ /* Update the address range of SO based on ASECT. */
+ if ((bfd_section_flags (asect) & SEC_ALLOC) != 0
+ && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+ {
+ /* First, SO must cover the contents of ASECT. */
+ if (so.addr_low == 0 || sec->addr < so.addr_low)
+ so.addr_low = sec->addr;
+
+ if (so.addr_high == 0 || sec->endaddr > so.addr_high)
+ so.addr_high = sec->endaddr;
+
+ gdb_assert (so.addr_low <= so.addr_high);
+
+ /* But we can do better. Find the program header which contains
+ ASECT, and figure out its extents. This gives an larger possible
+ region for SO. */
+ Elf_Internal_Phdr *phdr = find_loadable_elf_internal_phdr (abfd, asect);
+
+ if (phdr != nullptr)
+ {
+ /* Figure out the alignment required by this segment. */
+ ULONGEST minpagesize = get_elf_backend_data (abfd)->minpagesize;
+ ULONGEST segment_alignment
+ = std::max (minpagesize, static_cast<ULONGEST> (phdr->p_align));
+ ULONGEST at_pagesz;
+ if (target_auxv_search (AT_PAGESZ, &at_pagesz) > 0)
+ segment_alignment = std::max (segment_alignment, at_pagesz);
+
+ /* The offset of this section within the segment. */
+ ULONGEST section_offset = asect->vma - phdr->p_vaddr;
+
+ /* The start address for the segment, without alignment. */
+ CORE_ADDR unaligned_start = sec->addr - section_offset;
+
+ /* And the start address with downward alignment. */
+ CORE_ADDR aligned_start
+ = align_down (unaligned_start, segment_alignment);
+
+ /* The end address of the segment depends on its size. Start
+ with the size as described in the ELF. This check of the
+ memory size and file size is what BFD does, so assume it
+ knows best and copy this logic. */
+ ULONGEST seg_size = std::max (phdr->p_memsz, phdr->p_filesz);
+
+ /* But by aligning the start address down we need to also include
+ that difference in the segment size. */
+ seg_size += (unaligned_start - aligned_start);
+
+ /* And align the segment size upward. */
+ seg_size = align_up (seg_size, segment_alignment);
+
+ /* Finally, we can compute the end address. */
+ CORE_ADDR end = aligned_start + seg_size;
+
+ /* And now we can update the extend of SO. */
+ if (so.addr_low == 0 || aligned_start < so.addr_low)
+ so.addr_low = aligned_start;
+
+ if (so.addr_high == 0 || end > so.addr_high)
+ so.addr_high = end;
+
+ gdb_assert (so.addr_low <= so.addr_high);
+ }
+ }
}
diff --git a/gdb/testsuite/gdb.python/py-arch.exp b/gdb/testsuite/gdb.python/py-arch.exp
index c76fc778..c294011 100644
--- a/gdb/testsuite/gdb.python/py-arch.exp
+++ b/gdb/testsuite/gdb.python/py-arch.exp
@@ -108,6 +108,11 @@ gdb_test "python print(arch.void_type())" \
"void" \
"get void type"
+# Test type identity
+gdb_test "python print(arch.integer_type(32) is arch.integer_type(32))" \
+ "True" \
+ "arch.integer_type(32) always return the same Python object"
+
# Test for gdb.architecture_names(). First we're going to grab the
# complete list of architecture names using the 'complete' command.
set arch_names []
diff --git a/gdb/testsuite/gdb.python/py-styled-execute.exp b/gdb/testsuite/gdb.python/py-styled-execute.exp
new file mode 100644
index 0000000..0b27c63
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-styled-execute.exp
@@ -0,0 +1,109 @@
+# 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/>.
+
+# Check the the output of gdb.execute can be styled or not depending
+# on the value of the third argument passed to gdb.execute.
+
+require allow_python_tests
+
+load_lib gdb-python.exp
+
+# Use gdb.execute() to run CMD passing different argument values. The
+# output should match either STYLED_RE or UNSTYLED_RE depending on
+# whether the 'styling' argument is True or False.
+proc do_gdb_execute { cmd styled_re unstyled_re } {
+ gdb_test "python gdb.execute('$cmd')" $styled_re
+
+ foreach from_tty { True False } {
+ gdb_test \
+ "python gdb.execute('$cmd', $from_tty)" \
+ $styled_re
+ gdb_test \
+ "python gdb.execute('$cmd', $from_tty, False)" \
+ $styled_re
+ gdb_test \
+ "python gdb.execute('$cmd', $from_tty, False, True)" \
+ $styled_re
+ gdb_test \
+ "python gdb.execute('$cmd', $from_tty, False, False)" \
+ $unstyled_re
+ gdb_test \
+ "python print(gdb.execute('$cmd', $from_tty, True), end='')" \
+ $unstyled_re
+ gdb_test \
+ "python print(gdb.execute('$cmd', $from_tty, True, False), end='')" \
+ $unstyled_re
+ gdb_test \
+ "python print(gdb.execute('$cmd', $from_tty, True, True), end='')" \
+ $styled_re
+ }
+}
+
+# Test that the output from gdb.execute is styled or not based on the
+# arguments passed in.
+proc test_gdb_execute_styling {} {
+ clean_restart
+
+ # Two possible outputs, BASIC_RE, the unstyled output text, or
+ # STYLED_RE, the same things, but with styling applied.
+ set text "\"version\" style"
+ set styled_text \
+ [style "\"" version][style "version" version][style "\" style" version]
+ set basic_re "The $text foreground color is: \[^\r\n\]+"
+ set styled_re "The $styled_text foreground color is: \[^\r\n\]+"
+
+ # The command we'll run. It's output matches the above regexp.
+ set show_style_version_cmd "show style version foreground"
+
+ # Another command we'll run. The output of this command is never
+ # styled, but we run this to check that the output doesn't change
+ # even when gdb.execute() asks for styled, or unstyled output.
+ set show_style_enabled_cmd "show style enabled"
+
+ with_test_prefix "with style enabled on" {
+ do_gdb_execute $show_style_version_cmd $styled_re $basic_re
+
+ # This time, print the value of 'show style enabled'. This
+ # output is unstyled, so there's only one regexp. The
+ # interesting thing here is that we don't expect the output to
+ # change, even when gdb.execute() is printing unstyled output.
+ # The "styling=False" argument to gdb.execute() is separate to
+ # the 'set style enabled on|off' setting.
+ set re "CLI output styling is enabled\\."
+ do_gdb_execute $show_style_enabled_cmd $re $re
+ }
+
+ gdb_test_no_output "set style enabled off"
+
+ with_test_prefix "with style enabled off" {
+ # With 'set style enabled off' in use, even a request to
+ # gdb.execute() to produce styled output should produce
+ # unstyled output. The assumption is that 'set style enabled
+ # off' is done by the user, while the gdb.execute() is likely
+ # from some Python extension. The users request for no
+ # styling overrules the extensions request for styled output.
+ do_gdb_execute $show_style_version_cmd $basic_re $basic_re
+
+ # Now check that even when we request styled output, the 'show
+ # style enabled' value is always reported as disabled.
+ set re "CLI output styling is disabled\\."
+ do_gdb_execute $show_style_enabled_cmd $re $re
+ }
+}
+
+# Run the tests.
+with_ansi_styling_terminal {
+ test_gdb_execute_styling
+}
diff --git a/gdb/testsuite/gdb.python/py-symtab.exp b/gdb/testsuite/gdb.python/py-symtab.exp
index 4765ef5..18d77a0 100644
--- a/gdb/testsuite/gdb.python/py-symtab.exp
+++ b/gdb/testsuite/gdb.python/py-symtab.exp
@@ -90,6 +90,34 @@ gdb_test_multiple "python print (\"simple_struct\" in static_symbols)" \
}
}
+# Test symtab identity
+gdb_test "python print (symtab is symtab)"\
+ "True" \
+ "test symtab identity 1"
+gdb_test "python print (symtab is gdb.selected_frame().find_sal().symtab)"\
+ "True" \
+ "test symtab identity 2"
+gdb_test "python print (sal.symtab is gdb.selected_frame().find_sal().symtab)"\
+ "True" \
+ "test symtab identity 3"
+gdb_test "python print (symtab is not \"xxx\")"\
+ "True" \
+ "test symtab non-identity with non-symtab"
+
+# Test symtab equality
+gdb_test "python print (symtab == symtab)"\
+ "True" \
+ "test symtab equality 1"
+gdb_test "python print (symtab == gdb.selected_frame().find_sal().symtab)"\
+ "True" \
+ "test symtab equality 2"
+gdb_test "python print (sal.symtab == gdb.selected_frame().find_sal().symtab)"\
+ "True" \
+ "test symtab equality 3"
+gdb_test "python print (symtab != \"xxx\")"\
+ "True" \
+ "test symtab non-equality with non-symtab"
+
# Test is_valid when the objfile is unloaded. This must be the last
# test as it unloads the object file in GDB.
gdb_unload
diff --git a/gdb/testsuite/gdb.python/py-type.exp b/gdb/testsuite/gdb.python/py-type.exp
index 7e469c9..c9d4353 100644
--- a/gdb/testsuite/gdb.python/py-type.exp
+++ b/gdb/testsuite/gdb.python/py-type.exp
@@ -324,6 +324,19 @@ proc test_type_equality {} {
}
}
+# Test type identity
+proc test_type_identity {} {
+ gdb_test_no_output "python v1 = gdb.parse_and_eval('global_unsigned_int')"
+ gdb_test_no_output "python v2 = gdb.parse_and_eval('global_unsigned_int')"
+
+ gdb_test "python print(v1.type is v2.type)" "True"
+
+ gdb_test_no_output "python t1 = gdb.lookup_type ('char')"
+ gdb_test_no_output "python t2 = gdb.lookup_type ('char')"
+
+ gdb_test "python print(t1 is t2)" "True"
+}
+
# Test the gdb.Type.is_scalar property.
proc test_is_scalar { lang } {
if {$lang == "c++"} {
@@ -376,6 +389,7 @@ if { [build_inferior "${binfile}" "c"] == 0 } {
test_is_scalar "c"
test_is_signed "c"
test_type_equality
+ test_type_identity
}
}
@@ -392,6 +406,7 @@ if { [build_inferior "${binfile}-cxx" "c++"] == 0 } {
test_is_scalar "c++"
test_is_signed "c++"
test_type_equality
+ test_type_identity
}
}
diff --git a/gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.c b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.c
index 2e23f12..d0707cd 100644
--- a/gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.c
+++ b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.c
@@ -43,6 +43,7 @@ function_that_segfaults ()
{
int *p = 0;
*p = 1; /* Segfault happens here. */
+ return 0;
}
int
@@ -55,6 +56,7 @@ void *
worker_func (void *arg)
{
int a = 42; /* Breakpoint here. */
+ return NULL;
}
void
diff --git a/gdb/value.c b/gdb/value.c
index e498632..ddc0959 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -55,10 +55,17 @@
/* Definition of a user function. */
struct internal_function
{
+ internal_function (std::string name, internal_function_fn_noside handler,
+ void *cookie)
+ : name (std::move (name)),
+ handler (handler),
+ cookie (cookie)
+ {}
+
/* The name of the function. It is a bit odd to have this in the
function itself -- the user might use a differently-named
convenience variable to hold the function. */
- char *name;
+ std::string name;
/* The handler. */
internal_function_fn_noside handler;
@@ -67,6 +74,8 @@ struct internal_function
void *cookie;
};
+using internal_function_up = std::unique_ptr<internal_function>;
+
/* Returns true if the ranges defined by [offset1, offset1+len1) and
[offset2, offset2+len2) overlap. */
@@ -1865,6 +1874,19 @@ struct internalvar
: name (std::move (name))
{}
+ internalvar (internalvar &&other)
+ : name (std::move(other.name)),
+ kind (other.kind),
+ u (other.u)
+ {
+ other.kind = INTERNALVAR_VOID;
+ }
+
+ ~internalvar ()
+ {
+ clear_internalvar (this);
+ }
+
std::string name;
/* We support various different kinds of content of an internal variable.
@@ -2277,13 +2299,13 @@ set_internalvar_string (struct internalvar *var, const char *string)
}
static void
-set_internalvar_function (struct internalvar *var, struct internal_function *f)
+set_internalvar_function (internalvar *var, internal_function_up f)
{
/* Clean up old contents. */
clear_internalvar (var);
var->kind = INTERNALVAR_FUNCTION;
- var->u.fn.function = f;
+ var->u.fn.function = f.release ();
var->u.fn.canonical = 1;
/* Variables installed here are always the canonical version. */
}
@@ -2302,6 +2324,10 @@ clear_internalvar (struct internalvar *var)
xfree (var->u.string);
break;
+ case INTERNALVAR_FUNCTION:
+ delete var->u.fn.function;
+ break;
+
default:
break;
}
@@ -2316,18 +2342,6 @@ internalvar_name (const struct internalvar *var)
return var->name.c_str ();
}
-static struct internal_function *
-create_internal_function (const char *name,
- internal_function_fn_noside handler, void *cookie)
-{
- struct internal_function *ifn = new (struct internal_function);
-
- ifn->name = xstrdup (name);
- ifn->handler = handler;
- ifn->cookie = cookie;
- return ifn;
-}
-
const char *
value_internal_function_name (struct value *val)
{
@@ -2338,7 +2352,7 @@ value_internal_function_name (struct value *val)
result = get_internalvar_function (VALUE_INTERNALVAR (val), &ifn);
gdb_assert (result);
- return ifn->name;
+ return ifn->name.c_str ();
}
struct value *
@@ -2373,11 +2387,9 @@ static struct cmd_list_element *
do_add_internal_function (const char *name, const char *doc,
internal_function_fn_noside handler, void *cookie)
{
- struct internal_function *ifn;
- struct internalvar *var = lookup_internalvar (name);
-
- ifn = create_internal_function (name, handler, cookie);
- set_internalvar_function (var, ifn);
+ set_internalvar_function (lookup_internalvar (name),
+ std::make_unique<internal_function> (name, handler,
+ cookie));
return add_cmd (name, no_class, function_command, doc, &functionlist);
}
diff --git a/gdbserver/netbsd-low.cc b/gdbserver/netbsd-low.cc
index 9e7314b..0c75f4b 100644
--- a/gdbserver/netbsd-low.cc
+++ b/gdbserver/netbsd-low.cc
@@ -453,7 +453,10 @@ netbsd_process_target::detach (process_info *process)
void
netbsd_process_target::mourn (struct process_info *proc)
{
- proc->for_each_thread (remove_thread);
+ proc->for_each_thread ([proc] (thread_info *thread)
+ {
+ proc->remove_thread (thread);
+ });
remove_process (proc);
}