aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'gdb')
-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.c25
-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/dwarf2/die.c4
-rw-r--r--gdb/dwarf2/die.h12
-rw-r--r--gdb/dwarf2/read.c248
-rw-r--r--gdb/gcore-1.in4
-rw-r--r--gdb/linux-thread-db.c3
-rw-r--r--gdb/main.c6
-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/source-cache.c28
-rw-r--r--gdb/source-cache.h2
-rw-r--r--gdb/testsuite/gdb.python/py-arch.exp5
-rw-r--r--gdb/testsuite/gdb.python/py-source-styling.exp107
-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.rocm/precise-memory.cpp12
-rw-r--r--gdb/testsuite/gdb.rocm/precise-memory.exp38
-rw-r--r--gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.c2
-rw-r--r--gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.exp4
-rw-r--r--gdb/testsuite/lib/rocm.exp19
-rw-r--r--gdb/utils.c6
-rw-r--r--gdb/value.c54
36 files changed, 976 insertions, 539 deletions
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..5484245 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. */
@@ -353,7 +372,9 @@ set_style_enabled (const char *args, int from_tty, struct cmd_list_element *c)
warning ("The current terminal doesn't support styling. Styled output "
"might not appear as expected.");
- g_source_cache.clear ();
+ /* It is not necessary to flush the source cache here. The source cache
+ tracks whether entries are styled or not. */
+
gdb::observers::styling_changed.notify ();
}
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/dwarf2/die.c b/gdb/dwarf2/die.c
index 500d7bf..9437c2f 100644
--- a/gdb/dwarf2/die.c
+++ b/gdb/dwarf2/die.c
@@ -184,9 +184,9 @@ dump_die_1 (struct ui_file *f, int level, int max_level, struct die_info *die)
}
}
- if (die->sibling != NULL && level > 0)
+ if (die->next != NULL && level > 0)
{
- dump_die_1 (f, level, max_level, die->sibling);
+ dump_die_1 (f, level, max_level, die->next);
}
}
diff --git a/gdb/dwarf2/die.h b/gdb/dwarf2/die.h
index 770964e..cffb5cb 100644
--- a/gdb/dwarf2/die.h
+++ b/gdb/dwarf2/die.h
@@ -22,6 +22,7 @@
#include "complaints.h"
#include "dwarf2/attribute.h"
+#include "gdbsupport/next-iterator.h"
/* This data structure holds a complete die structure. */
struct die_info
@@ -103,6 +104,13 @@ struct die_info
return 0;
}
+ /* Return a range suitable for iterating over the children of this
+ DIE. */
+ next_range<die_info> children () const
+ {
+ return next_range<die_info> (child);
+ }
+
/* DWARF-2 tag for this DIE. */
ENUM_BITFIELD(dwarf_tag) tag : 16;
@@ -128,9 +136,9 @@ struct die_info
/* The dies in a compilation unit form an n-ary tree. PARENT
points to this die's parent; CHILD points to the first child of
this node; and all the children of a given node are chained
- together via their SIBLING fields. */
+ together via their NEXT fields. */
struct die_info *child; /* Its first child, if any. */
- struct die_info *sibling; /* Its next sibling, if any. */
+ struct die_info *next; /* Its next sibling, if any. */
struct die_info *parent; /* Its parent, if any. */
/* An array of attributes, with NUM_ATTRS elements. There may be
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index b9040a5..8875e97 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -5456,12 +5456,11 @@ dwarf2_compute_name (const char *name,
if (lang == language_cplus && strchr (name, '<') == NULL)
{
struct attribute *attr;
- struct die_info *child;
int first = 1;
die->building_fullname = 1;
- for (child = die->child; child != NULL; child = child->sibling)
+ for (die_info *child : die->children ())
{
struct type *type;
LONGEST value;
@@ -5825,7 +5824,7 @@ read_import_statement (struct die_info *die, struct dwarf2_cu *cu)
{
struct objfile *objfile = cu->per_objfile->objfile;
struct attribute *import_attr;
- struct die_info *imported_die, *child_die;
+ struct die_info *imported_die;
struct dwarf2_cu *imported_cu;
const char *imported_name;
const char *imported_name_prefix;
@@ -5908,10 +5907,8 @@ read_import_statement (struct die_info *die, struct dwarf2_cu *cu)
else
canonical_name = imported_name;
- if (die->tag == DW_TAG_imported_module
- && cu->lang () == language_fortran)
- for (child_die = die->child; child_die && child_die->tag;
- child_die = child_die->sibling)
+ if (die->tag == DW_TAG_imported_module && cu->lang () == language_fortran)
+ for (die_info *child_die : die->children ())
{
/* DWARF-4: A Fortran use statement with a “rename list” may be
represented by an imported module entry with an import attribute
@@ -6098,7 +6095,6 @@ read_file_scope (struct die_info *die, struct dwarf2_cu *cu)
struct objfile *objfile = per_objfile->objfile;
CORE_ADDR lowpc;
struct attribute *attr;
- struct die_info *child_die;
unrelocated_addr unrel_low, unrel_high;
get_scope_pc_bounds (die, &unrel_low, &unrel_high, cu);
@@ -6145,15 +6141,9 @@ read_file_scope (struct die_info *die, struct dwarf2_cu *cu)
handle_DW_AT_stmt_list (die, cu, fnd, unrel_low, unrel_low != unrel_high);
/* Process all dies in compilation unit. */
- if (die->child != NULL)
- {
- child_die = die->child;
- while (child_die && child_die->tag)
- {
- process_die (child_die, cu);
- child_die = child_die->sibling;
- }
- }
+ for (die_info *child_die : die->children ())
+ process_die (child_die, cu);
+
per_objfile->sym_cu = nullptr;
/* Decode macro information, if present. Dwarf 2 macro information
@@ -6309,22 +6299,13 @@ dwarf2_cu::setup_type_unit_groups (struct die_info *die)
static void
read_type_unit_scope (struct die_info *die, struct dwarf2_cu *cu)
{
- struct die_info *child_die;
-
/* Initialize (or reinitialize) the machinery for building symtabs.
We do this before processing child DIEs, so that the line header table
is available for DW_AT_decl_file. */
cu->setup_type_unit_groups (die);
- if (die->child != NULL)
- {
- child_die = die->child;
- while (child_die && child_die->tag)
- {
- process_die (child_die, cu);
- child_die = child_die->sibling;
- }
- }
+ for (die_info *child_die : die->children ())
+ process_die (child_die, cu);
}
/* DWO/DWP files.
@@ -8210,8 +8191,8 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
break;
}
- concrete_child = concrete_child->sibling;
- abstract_child = abstract_child->sibling;
+ concrete_child = concrete_child->next;
+ abstract_child = abstract_child->next;
}
/* Walk the origin's children in parallel to the concrete children.
@@ -8224,9 +8205,7 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
std::vector<sect_offset> offsets;
- for (die_info *child_die = die->child;
- child_die && child_die->tag;
- child_die = child_die->sibling)
+ for (die_info *child_die : die->children ())
{
/* We are trying to process concrete instance entries:
DW_TAG_call_site DIEs indeed have a DW_AT_abstract_origin tag, but
@@ -8238,7 +8217,7 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
{
if (are_isomorphic)
corresponding_abstract_child
- = corresponding_abstract_child->sibling;
+ = corresponding_abstract_child->next;
continue;
}
@@ -8296,7 +8275,7 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
}
if (are_isomorphic)
- corresponding_abstract_child = corresponding_abstract_child->sibling;
+ corresponding_abstract_child = corresponding_abstract_child->next;
}
if (!offsets.empty ())
@@ -8314,8 +8293,7 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
}
auto offsets_it = offsets.begin ();
- die_info *origin_child_die = origin_die->child;
- while (origin_child_die != nullptr && origin_child_die->tag != 0)
+ for (die_info *origin_child_die : origin_die->children ())
{
/* Is ORIGIN_CHILD_DIE referenced by any of the DIE children? */
while (offsets_it < offsets.end ()
@@ -8332,8 +8310,6 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
if (!origin_child_die->in_process)
process_die (origin_child_die, origin_cu);
}
-
- origin_child_die = origin_child_die->sibling;
}
origin_cu->list_in_scope = origin_previous_list_in_scope;
@@ -8424,7 +8400,6 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
struct context_stack *newobj;
CORE_ADDR lowpc;
CORE_ADDR highpc;
- struct die_info *child_die;
struct attribute *attr, *call_line, *call_file;
const char *name;
struct block *block;
@@ -8501,7 +8476,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
/* If we have any template arguments, then we must allocate a
different sort of symbol. */
- for (child_die = die->child; child_die; child_die = child_die->sibling)
+ for (die_info *child_die : die->children ())
{
if (child_die->tag == DW_TAG_template_type_param
|| child_die->tag == DW_TAG_template_value_param)
@@ -8539,23 +8514,18 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
cu->list_in_scope = cu->get_builder ()->get_local_symbols ();
- if (die->child != NULL)
+ for (die_info *child_die : die->children ())
{
- child_die = die->child;
- while (child_die && child_die->tag)
+ if (child_die->tag == DW_TAG_template_type_param
+ || child_die->tag == DW_TAG_template_value_param)
{
- if (child_die->tag == DW_TAG_template_type_param
- || child_die->tag == DW_TAG_template_value_param)
- {
- struct symbol *arg = new_symbol (child_die, NULL, cu);
+ struct symbol *arg = new_symbol (child_die, NULL, cu);
- if (arg != NULL)
- template_args.push_back (arg);
- }
- else
- process_die (child_die, cu);
- child_die = child_die->sibling;
+ if (arg != NULL)
+ template_args.push_back (arg);
}
+ else
+ process_die (child_die, cu);
}
inherit_abstract_dies (die, cu);
@@ -8571,13 +8541,9 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
while (spec_die)
{
- child_die = spec_die->child;
- while (child_die && child_die->tag)
- {
- if (child_die->tag == DW_TAG_imported_module)
- process_die (child_die, spec_cu);
- child_die = child_die->sibling;
- }
+ for (die_info *child_die : spec_die->children ())
+ if (child_die->tag == DW_TAG_imported_module)
+ process_die (child_die, spec_cu);
/* In some cases, GCC generates specification DIEs that
themselves contain DW_AT_specification attributes. */
@@ -8646,7 +8612,6 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
{
dwarf2_per_objfile *per_objfile = cu->per_objfile;
CORE_ADDR lowpc, highpc;
- struct die_info *child_die;
/* Ignore blocks with missing or invalid low and high pc attributes. */
/* ??? Perhaps consider discontiguous blocks defined by DW_AT_ranges
@@ -8661,9 +8626,7 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
/* DW_TAG_lexical_block has no attributes, process its children as if
there was no wrapping by that DW_TAG_lexical_block.
GCC does no longer produces such DWARF since GCC r224161. */
- for (child_die = die->child;
- child_die != NULL && child_die->tag;
- child_die = child_die->sibling)
+ for (die_info *child_die : die->children ())
{
/* We might already be processing this DIE. This can happen
in an unusual circumstance -- where a subroutine A
@@ -8682,15 +8645,9 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
highpc = per_objfile->relocate (unrel_high);
cu->get_builder ()->push_context (0, lowpc);
- if (die->child != NULL)
- {
- child_die = die->child;
- while (child_die && child_die->tag)
- {
- process_die (child_die, cu);
- child_die = child_die->sibling;
- }
- }
+ for (die_info *child_die : die->children ())
+ process_die (child_die, cu);
+
inherit_abstract_dies (die, cu);
struct context_stack cstk = cu->get_builder ()->pop_context ();
@@ -8733,7 +8690,6 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
struct gdbarch *gdbarch = objfile->arch ();
struct attribute *attr;
int nparams;
- struct die_info *child_die;
attr = dwarf2_attr (die, DW_AT_call_return_pc, cu);
if (attr == NULL)
@@ -8754,8 +8710,7 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
/* Count parameters at the caller. */
nparams = 0;
- for (child_die = die->child; child_die && child_die->tag;
- child_die = child_die->sibling)
+ for (die_info *child_die : die->children ())
{
if (child_die->tag != DW_TAG_call_site_parameter
&& child_die->tag != DW_TAG_GNU_call_site_parameter)
@@ -8924,9 +8879,7 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
"block nor reference, for DIE %s [in module %s]"),
sect_offset_str (die->sect_off), objfile_name (objfile));
- for (child_die = die->child;
- child_die && child_die->tag;
- child_die = child_die->sibling)
+ for (die_info *child_die : die->children ())
{
struct call_site_parameter *parameter;
struct attribute *loc, *origin;
@@ -9646,7 +9599,6 @@ dwarf2_get_subprogram_pc_bounds (struct die_info *die,
struct dwarf2_cu *cu)
{
unrelocated_addr low, high;
- struct die_info *child = die->child;
if (dwarf2_get_pc_bounds (die, &low, &high, cu, nullptr, nullptr)
>= PC_BOUNDS_RANGES)
@@ -9664,12 +9616,11 @@ dwarf2_get_subprogram_pc_bounds (struct die_info *die,
subprograms, then check their pc bounds. Likewise, we need to
check lexical blocks as well, as they may also contain subprogram
definitions. */
- while (child && child->tag)
+ for (die_info *child : die->children ())
{
if (child->tag == DW_TAG_subprogram
|| child->tag == DW_TAG_lexical_block)
dwarf2_get_subprogram_pc_bounds (child, lowpc, highpc, cu);
- child = child->sibling;
}
}
@@ -9695,9 +9646,7 @@ get_scope_pc_bounds (struct die_info *die,
}
else
{
- struct die_info *child = die->child;
-
- while (child && child->tag)
+ for (die_info *child : die->children ())
{
switch (child->tag) {
case DW_TAG_subprogram:
@@ -9725,8 +9674,6 @@ get_scope_pc_bounds (struct die_info *die,
/* Ignore. */
break;
}
-
- child = child->sibling;
}
}
@@ -11277,9 +11224,7 @@ handle_variant_part (struct die_info *die, struct type *type,
objfile_name (cu->per_objfile->objfile));
}
- for (die_info *child_die = die->child;
- child_die != NULL;
- child_die = child_die->sibling)
+ for (die_info *child_die : die->children ())
handle_struct_member_die (child_die, type, fi, template_args, cu);
}
@@ -11330,9 +11275,7 @@ handle_variant (struct die_info *die, struct type *type,
else
variant.discriminant_value = discr->constant_value (0);
- for (die_info *variant_child = die->child;
- variant_child != NULL;
- variant_child = variant_child->sibling)
+ for (die_info *variant_child : die->children ())
handle_struct_member_die (variant_child, type, fi, template_args, cu);
variant.last_field = fi->fields.size ();
@@ -11401,7 +11344,6 @@ static void
process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
{
struct objfile *objfile = cu->per_objfile->objfile;
- struct die_info *child_die;
struct type *type;
type = get_die_type (die, cu);
@@ -11414,13 +11356,8 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
struct field_info fi;
std::vector<struct symbol *> template_args;
- child_die = die->child;
-
- while (child_die && child_die->tag)
- {
- handle_struct_member_die (child_die, type, &fi, &template_args, cu);
- child_die = child_die->sibling;
- }
+ for (die_info *child_die : die->children ())
+ handle_struct_member_die (child_die, type, &fi, &template_args, cu);
/* Attach template arguments to type. */
if (!template_args.empty ())
@@ -11558,9 +11495,7 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
current die is a declaration. Normally, of course, a declaration
won't have any children at all. */
- child_die = die->child;
-
- while (child_die != NULL && child_die->tag)
+ for (die_info *child_die : die->children ())
{
if (child_die->tag == DW_TAG_member
|| child_die->tag == DW_TAG_variable
@@ -11572,8 +11507,6 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
}
else
process_die (child_die, cu);
-
- child_die = child_die->sibling;
}
/* Do not consider external references. According to the DWARF standard,
@@ -11673,16 +11606,13 @@ update_enumeration_type_from_children (struct die_info *die,
struct type *type,
struct dwarf2_cu *cu)
{
- struct die_info *child_die;
int unsigned_enum = 1;
int flag_enum = 1;
auto_obstack obstack;
std::vector<struct field> fields;
- for (child_die = die->child;
- child_die != NULL && child_die->tag;
- child_die = child_die->sibling)
+ for (die_info *child_die : die->children ())
{
struct attribute *attr;
LONGEST value;
@@ -11840,10 +11770,7 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu)
if (die->child != NULL)
{
- struct die_info *child_die;
-
- child_die = die->child;
- while (child_die && child_die->tag)
+ for (die_info *child_die : die->children ())
{
if (child_die->tag != DW_TAG_enumerator)
{
@@ -11851,8 +11778,6 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu)
}
else
new_symbol (child_die, this_type, cu);
-
- child_die = child_die->sibling;
}
}
@@ -12033,9 +11958,7 @@ quirk_ada_thick_pointer (struct die_info *die, struct dwarf2_cu *cu,
int bounds_offset = -1;
int max_align = -1;
std::vector<struct field> range_fields;
- for (struct die_info *child_die = die->child;
- child_die;
- child_die = child_die->sibling)
+ for (die_info *child_die : die->children ())
{
if (child_die->tag == DW_TAG_subrange_type)
{
@@ -12136,7 +12059,6 @@ static struct type *
read_array_type (struct die_info *die, struct dwarf2_cu *cu)
{
struct objfile *objfile = cu->per_objfile->objfile;
- struct die_info *child_die;
struct type *type;
struct type *element_type, *range_type, *index_type;
struct attribute *attr;
@@ -12191,8 +12113,7 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu)
}
std::vector<struct type *> range_types;
- child_die = die->child;
- while (child_die && child_die->tag)
+ for (die_info *child_die : die->children ())
{
if (child_die->tag == DW_TAG_subrange_type
|| child_die->tag == DW_TAG_generic_subrange)
@@ -12206,7 +12127,6 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu)
range_types.push_back (child_type);
}
}
- child_die = child_die->sibling;
}
if (range_types.empty ())
@@ -12473,15 +12393,12 @@ read_common_block (struct die_info *die, struct dwarf2_cu *cu)
if (die->child != NULL)
{
struct objfile *objfile = cu->per_objfile->objfile;
- struct die_info *child_die;
- size_t n_entries = 0, size;
+ size_t size;
struct common_block *common_block;
struct symbol *sym;
- for (child_die = die->child;
- child_die && child_die->tag;
- child_die = child_die->sibling)
- ++n_entries;
+ auto range = die->children ();
+ size_t n_entries = std::distance (range.begin (), range.end ());
size = (sizeof (struct common_block)
+ (n_entries - 1) * sizeof (struct symbol *));
@@ -12491,9 +12408,7 @@ read_common_block (struct die_info *die, struct dwarf2_cu *cu)
memset (common_block->contents, 0, n_entries * sizeof (struct symbol *));
common_block->n_entries = 0;
- for (child_die = die->child;
- child_die && child_die->tag;
- child_die = child_die->sibling)
+ for (die_info *child_die : die->children ())
{
/* Create the symbol in the DW_TAG_common_block block in the current
symbol scope. */
@@ -12616,13 +12531,8 @@ read_namespace (struct die_info *die, struct dwarf2_cu *cu)
if (die->child != NULL)
{
- struct die_info *child_die = die->child;
-
- while (child_die && child_die->tag)
- {
- process_die (child_die, cu);
- child_die = child_die->sibling;
- }
+ for (die_info *child_die : die->children ())
+ process_die (child_die, cu);
}
}
@@ -12660,17 +12570,13 @@ read_module_type (struct die_info *die, struct dwarf2_cu *cu)
static void
read_module (struct die_info *die, struct dwarf2_cu *cu)
{
- struct die_info *child_die = die->child;
struct type *type;
type = read_type_die (die, cu);
new_symbol (die, type, cu);
- while (child_die && child_die->tag)
- {
- process_die (child_die, cu);
- child_die = child_die->sibling;
- }
+ for (die_info *child_die : die->children ())
+ process_die (child_die, cu);
}
/* Return the name of the namespace represented by DIE. Set
@@ -13168,22 +13074,18 @@ read_subroutine_type (struct die_info *die, struct dwarf2_cu *cu)
if (die->child != NULL)
{
struct type *void_type = builtin_type (objfile)->builtin_void;
- struct die_info *child_die;
int nparams, iparams;
/* Count the number of parameters.
FIXME: GDB currently ignores vararg functions, but knows about
vararg member functions. */
nparams = 0;
- child_die = die->child;
- while (child_die && child_die->tag)
+ for (die_info *child_die : die->children ())
{
if (child_die->tag == DW_TAG_formal_parameter)
nparams++;
else if (child_die->tag == DW_TAG_unspecified_parameters)
ftype->set_has_varargs (true);
-
- child_die = child_die->sibling;
}
/* Allocate storage for parameters and fill them in. */
@@ -13195,8 +13097,7 @@ read_subroutine_type (struct die_info *die, struct dwarf2_cu *cu)
ftype->field (iparams).set_type (void_type);
iparams = 0;
- child_die = die->child;
- while (child_die && child_die->tag)
+ for (die_info *child_die : die->children ())
{
if (child_die->tag == DW_TAG_formal_parameter)
{
@@ -13253,7 +13154,6 @@ read_subroutine_type (struct die_info *die, struct dwarf2_cu *cu)
ftype->field (iparams).set_type (arg_type);
iparams++;
}
- child_die = child_die->sibling;
}
}
@@ -14350,7 +14250,7 @@ read_unspecified_type (struct die_info *die, struct dwarf2_cu *cu)
return set_die_type (die, type, cu);
}
-/* Read a single die and all its descendents. Set the die's sibling
+/* Read a single die and all its descendents. Set the die's next
field to NULL; set other fields in the die correctly, and set all
of the descendents' fields correctly. PARENT is the parent of the
die in question. */
@@ -14371,7 +14271,7 @@ cutu_reader::read_die_and_children (die_info *parent)
else
die->child = nullptr;
- die->sibling = nullptr;
+ die->next = nullptr;
die->parent = parent;
return die;
}
@@ -14396,7 +14296,7 @@ cutu_reader::read_die_and_siblings (die_info *parent)
if (first_die == nullptr)
first_die = die;
else
- last_sibling->sibling = die;
+ last_sibling->next = die;
last_sibling = die;
}
@@ -14435,7 +14335,7 @@ cutu_reader::read_all_dies ()
and updating die_info::num_attrs.
Return a newly allocated die with its information, except for its
- child, sibling, and parent fields. */
+ child, next, and parent fields. */
die_info *
cutu_reader::read_full_die (int num_extra_attrs, bool allow_reprocess)
@@ -14479,7 +14379,7 @@ cutu_reader::read_full_die (int num_extra_attrs, bool allow_reprocess)
/* Read a die and all its attributes.
Return a newly allocated die with its information, except for its
- child, sibling, and parent fields. */
+ child, next, and parent fields. */
die_info *
cutu_reader::read_toplevel_die (gdb::array_view<attribute *> extra_attrs)
@@ -17767,7 +17667,6 @@ guess_full_die_structure_name (struct die_info *die, struct dwarf2_cu *cu)
{
struct die_info *spec_die;
struct dwarf2_cu *spec_cu;
- struct die_info *child;
struct objfile *objfile = cu->per_objfile->objfile;
spec_cu = cu;
@@ -17778,9 +17677,7 @@ guess_full_die_structure_name (struct die_info *die, struct dwarf2_cu *cu)
cu = spec_cu;
}
- for (child = die->child;
- child != NULL;
- child = child->sibling)
+ for (die_info *child : die->children ())
{
if (child->tag == DW_TAG_subprogram)
{
@@ -18106,18 +18003,19 @@ unnamed_template_tag_name (die_info *die, dwarf2_cu *cu)
arrive at our entry. */
size_t nth_unnamed = 0;
- die_info *child = die->parent->child;
- while (child != die)
- {
- gdb_assert (child != nullptr);
- if (child->tag == DW_TAG_template_type_param
- || child->tag == DW_TAG_template_value_param)
- {
- if (dwarf2_attr (child, DW_AT_name, cu) == nullptr)
- ++nth_unnamed;
- }
- child = child->sibling;
- }
+ for (die_info *child : die->parent->children ())
+ {
+ if (child == die)
+ break;
+
+ gdb_assert (child != nullptr);
+ if (child->tag == DW_TAG_template_type_param
+ || child->tag == DW_TAG_template_value_param)
+ {
+ if (dwarf2_attr (child, DW_AT_name, cu) == nullptr)
+ ++nth_unnamed;
+ }
+ }
const std::string name_str = "<unnamed" + std::to_string (nth_unnamed) + ">";
return cu->per_objfile->objfile->intern (name_str.c_str ());
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/linux-thread-db.c b/gdb/linux-thread-db.c
index 9d84187..f946c2a 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -778,9 +778,6 @@ check_thread_db (struct thread_db_info *info, bool log_progress)
}
catch (const gdb_exception_error &except)
{
- if (warning_pre_print)
- gdb_puts (warning_pre_print, gdb_stderr);
-
exception_fprintf (gdb_stderr, except,
_("libthread_db integrity checks failed: "));
diff --git a/gdb/main.c b/gdb/main.c
index d126e98..b173eb6 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -705,7 +705,7 @@ captured_main_1 (struct captured_main_args *context)
/* Prefix warning messages with the command name. */
gdb::unique_xmalloc_ptr<char> tmp_warn_preprint
- = xstrprintf ("%s: warning: ", gdb_program_name);
+ = xstrprintf ("%s: ", gdb_program_name);
warning_pre_print = tmp_warn_preprint.get ();
current_directory = getcwd (NULL, 0);
@@ -1169,7 +1169,7 @@ captured_main_1 (struct captured_main_args *context)
/* Set off error and warning messages with a blank line. */
tmp_warn_preprint.reset ();
- warning_pre_print = _("\nwarning: ");
+ warning_pre_print = "\n";
/* Read and execute the system-wide gdbinit file, if it exists.
This is done *before* all the command line arguments are
@@ -1274,7 +1274,7 @@ captured_main_1 (struct captured_main_args *context)
current_inferior ()->set_tty (ttyarg);
/* Error messages should no longer be distinguished with extra output. */
- warning_pre_print = _("warning: ");
+ warning_pre_print = "";
/* Read the .gdbinit file in the current directory, *if* it isn't
the same as the $HOME/.gdbinit file (it should exist, also). */
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/source-cache.c b/gdb/source-cache.c
index f08c872..30c9e61 100644
--- a/gdb/source-cache.c
+++ b/gdb/source-cache.c
@@ -325,11 +325,26 @@ source_cache::ensure (struct symtab *s)
least one caller. */
if (i != size - 1)
std::swap (m_source_map[i], m_source_map[size - 1]);
- return true;
+
+ /* If the styling status of the cached entry matches our desired
+ styling status, or we know this file cannot be styled, in
+ which case, this (unstyled) content, is the best we can do. */
+ if (((source_styling && gdb_stdout->can_emit_style_escape ())
+ == m_source_map[size - 1].styled)
+ || m_no_styling_files.count (fullname) > 0)
+ return true;
+
+ /* We found a match, but styling status doesn't match the desired
+ styling status. We already moved the matching item to the
+ back of M_SOURCE_MAP, so drop the entry now, and then
+ recompute with the desired styling. */
+ m_source_map.pop_back ();
+ break;
}
}
std::string contents;
+ bool styled_p = false;
try
{
contents = get_plain_source_lines (s, fullname);
@@ -343,21 +358,21 @@ source_cache::ensure (struct symtab *s)
if (source_styling && gdb_stdout->can_emit_style_escape ()
&& m_no_styling_files.count (fullname) == 0)
{
- bool already_styled
+ styled_p
= try_source_highlight (contents, s->language (), fullname);
- if (!already_styled)
+ if (!styled_p)
{
std::optional<std::string> ext_contents;
ext_contents = ext_lang_colorize (fullname, contents);
if (ext_contents.has_value ())
{
contents = std::move (*ext_contents);
- already_styled = true;
+ styled_p = true;
}
}
- if (!already_styled)
+ if (!styled_p)
{
/* Styling failed. Styling can fail for instance for these
reasons:
@@ -374,7 +389,8 @@ source_cache::ensure (struct symtab *s)
}
}
- source_text result = { std::move (fullname), std::move (contents) };
+ source_text result
+ = { std::move (fullname), std::move (contents), styled_p };
m_source_map.push_back (std::move (result));
if (m_source_map.size () > MAX_ENTRIES)
diff --git a/gdb/source-cache.h b/gdb/source-cache.h
index 03f4b79..c7d204b 100644
--- a/gdb/source-cache.h
+++ b/gdb/source-cache.h
@@ -78,6 +78,8 @@ private:
std::string fullname;
/* The contents of the file. */
std::string contents;
+ /* True if CONTENTS are styled. Otherwise, false. */
+ bool styled;
};
/* A helper function for get_source_lines reads a source file.
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-source-styling.exp b/gdb/testsuite/gdb.python/py-source-styling.exp
index ba7e795..8eed56b 100644
--- a/gdb/testsuite/gdb.python/py-source-styling.exp
+++ b/gdb/testsuite/gdb.python/py-source-styling.exp
@@ -33,12 +33,43 @@ if { [build_executable "failed to build" ${testfile} ${srcfile}] == -1 } {
set line_number [gdb_get_line_number "List this line."]
+# Helper proc. Run CMD, which should produce a source listing, and
+# check if the source code is styled or not. EXPECT_STYLED indicates
+# if we expect the source listing to be styled or not.
+proc check_source_listing_styling { cmd expect_styled { testname "" } } {
+ if { $testname eq "" } {
+ set testname $cmd
+ }
+
+ set seen_style_escape false
+ gdb_test_multiple $cmd $testname {
+ -re -wrap "Python Exception.*" {
+ fail $gdb_test_name
+ return
+ }
+ -re "\033" {
+ set seen_style_escape true
+ exp_continue
+ }
+ -re "$::gdb_prompt $" {
+ gdb_assert { $seen_style_escape == $expect_styled } \
+ $gdb_test_name
+ }
+ }
+}
+
# Check that the Python pygments module can be used for source
# highlighting when GNU source highlight is not available (or is
# disabled, as is done in this test).
proc test_pygments_styling {} {
clean_restart $::binfile
+ # Remote host boards disable styling via GDB's command line. Turn
+ # it back on now.
+ if {[is_remote host]} {
+ gdb_test "set style enabled on"
+ }
+
if { ![gdb_py_module_available "pygments"] } {
unsupported "pygments module not available"
return
@@ -52,19 +83,7 @@ proc test_pygments_styling {} {
gdb_test "maint flush source-cache" "Source cache flushed\\."
- set seen_style_escape false
- gdb_test_multiple "list $::line_number" "" {
- -re "Python Exception.*" {
- fail $gdb_test_name
- }
- -re "\033" {
- set seen_style_escape true
- exp_continue
- }
- -re "$::gdb_prompt $" {
- gdb_assert { $seen_style_escape } $gdb_test_name
- }
- }
+ check_source_listing_styling "list $::line_number" true
}
# Use gdb.execute to list source code containing non-utf-8 character.
@@ -93,6 +112,67 @@ proc test_gdb_execute_non_utf8_source {} {
gdb_test "python print(source)" ".*List this line.*"
}
+# Use gdb.execute() to list source code. Alternate between asking for
+# styled, and unstyled source code. In some cases we ask for the
+# output to be returned via a string, and in other cases we ask for
+# the output to be sent straight to stdout.
+proc_with_prefix test_source_cache_style_tracking {} {
+ clean_restart $::binfile
+
+ # Remote host boards disable styling via GDB's command line. Turn
+ # it back on now.
+ if {[is_remote host]} {
+ gdb_test "set style enabled on"
+ }
+
+ gdb_test_no_output "set host-charset ISO-8859-1"
+
+ # Commands which return styled, and non-styled source code mixed
+ # together. This ensures that the source cache will need to keep
+ # discarding the entry with the wrong styling mode. All of these
+ # gdb.execute calls send their output via a string.
+ check_source_listing_styling \
+ "python print(gdb.execute('list $::line_number', to_string=True), end='')" \
+ false
+ check_source_listing_styling \
+ "python print(gdb.execute('list $::line_number', to_string=True, styling=True), end='')" \
+ true
+ foreach from_tty { True False } {
+ check_source_listing_styling \
+ "python print(gdb.execute('list $::line_number', $from_tty, True), end='')" \
+ false
+ check_source_listing_styling \
+ "python print(gdb.execute('list $::line_number', $from_tty, True, True), end='')" \
+ true
+ check_source_listing_styling \
+ "python print(gdb.execute('list $::line_number', $from_tty, True, False), end='')" \
+ false
+ }
+
+ # The same again, but this time the output is sent directly to
+ # stdout.
+ check_source_listing_styling \
+ "python gdb.execute('list $::line_number')" \
+ true
+ check_source_listing_styling \
+ "python gdb.execute('list $::line_number', to_string=False, styling=False)" \
+ false
+ check_source_listing_styling \
+ "python gdb.execute('list $::line_number', to_string=False, styling=True)" \
+ true
+ foreach from_tty { True False } {
+ check_source_listing_styling \
+ "python gdb.execute('list $::line_number', $from_tty, False, False)" \
+ false
+ check_source_listing_styling \
+ "python gdb.execute('list $::line_number', $from_tty, False, True)" \
+ true
+ check_source_listing_styling \
+ "python gdb.execute('list $::line_number', $from_tty, False)" \
+ true
+ }
+}
+
# We need an ANSI-capable terminal to get the output, additionally we
# need to set LC_ALL so GDB knows the terminal is UTF-8 capable,
# otherwise we'll get a UnicodeEncodeError trying to encode the
@@ -100,4 +180,5 @@ proc test_gdb_execute_non_utf8_source {} {
with_ansi_styling_terminal {
test_pygments_styling
test_gdb_execute_non_utf8_source
+ test_source_cache_style_tracking
}
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.rocm/precise-memory.cpp b/gdb/testsuite/gdb.rocm/precise-memory.cpp
index 769b58a..7a8c37e 100644
--- a/gdb/testsuite/gdb.rocm/precise-memory.cpp
+++ b/gdb/testsuite/gdb.rocm/precise-memory.cpp
@@ -31,7 +31,17 @@
__global__ void
kernel ()
{
- __builtin_amdgcn_s_sleep (1);
+
+ /* Simple kernel which loads from address 0 to trigger a pagefault.
+ When precise memory is not enabled, it is expected that the memory fault
+ is reported after the s_nop instruction. With precise-memory, the
+ exception should be reported on the s_nop. */
+ asm volatile ("s_mov_b64 [s10, s11], 0\n"
+ "s_load_dword s12, [s10, s11]\n"
+ "s_nop 0"
+ :
+ :
+ : "s10", "s11", "s12");
}
int
diff --git a/gdb/testsuite/gdb.rocm/precise-memory.exp b/gdb/testsuite/gdb.rocm/precise-memory.exp
index f423a11..8c39f80 100644
--- a/gdb/testsuite/gdb.rocm/precise-memory.exp
+++ b/gdb/testsuite/gdb.rocm/precise-memory.exp
@@ -39,18 +39,40 @@ proc do_test { } {
"AMDGPU precise memory access reporting is off \\(currently disabled\\)." \
"show precise-memory setting in CLI before"
- if {[hip_devices_support_precise_memory]} {
- gdb_test_no_output "set amdgpu precise-memory on"
- set cli_effective_value "enabled"
- } else {
- gdb_test "set amdgpu precise-memory on" \
- "warning: AMDGPU precise memory access reporting could not be enabled."
- set cli_effective_value "disabled"
+ # Assume precise-memory is available, unless GDB reports otherwise.
+ gdb_test_multiple "set amdgpu precise-memory on" "" {
+ -re -wrap "warning: AMDGPU precise memory access reporting could not be enabled\\." {
+ set cli_effective_value "disabled"
+ pass $gdb_test_name
+ }
+ -re -wrap "^" {
+ set cli_effective_value "enabled"
+ pass $gdb_test_name
+ }
}
gdb_test "show amdgpu precise-memory" \
- "AMDGPU precise memory access reporting is on \\(currently ${cli_effective_value}\\)." \
+ "AMDGPU precise memory access reporting is on \\(currently ${cli_effective_value}\\)\\." \
"show precise-memory setting in CLI after"
+
+ if { $cli_effective_value eq "disabled" } {
+ return
+ }
+
+ # Get to the begining of the GPU kernel without precise memory enabled.
+ with_test_prefix "goto gpu code" {
+ gdb_test_no_output "set amdgpu precise-memory off"
+ gdb_breakpoint "kernel" allow-pending
+ gdb_test "continue" "Thread ${::decimal}.* hit Breakpoint .*"
+ gdb_test_no_output "set amdgpu precise-memory on"
+ }
+
+ # If precise-memory is available, run until a SIGSEGV is reported. At
+ # that point, the PC should point to the s_nop instruction (the one
+ # following the one which caused the memory violation).
+ gdb_test "continue" "Thread ${::decimal}\[^\r\n\]* received signal SIGSEGV, Segmentation fault.*"
+
+ gdb_test "x/i \$pc" "=> ${::hex} <_Z6kernelv\\+${::decimal}>:\[ \t\]+s_nop\[ \t\]+0"
}
}
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/testsuite/gdb.threads/infcall-from-bp-cond-simple.exp b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.exp
index c9508c9..feec37b 100644
--- a/gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.exp
+++ b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.exp
@@ -79,7 +79,7 @@ proc run_condition_test { message n_expected_hits condition \
gdb_breakpoint \
"${::srcfile}:${::cond_bp_line} if ((++\$n_cond_eval) && (${condition}))"
- # And a breakpoint that we hit when the test is over, this one is
+ # Add a breakpoint that we hit when the test is over, this one is
# not conditional. Only the main thread gets here once all the
# other threads have finished.
gdb_breakpoint "${::srcfile}:${::stop_bp_line}"
@@ -114,7 +114,7 @@ proc run_condition_test { message n_expected_hits condition \
# includes an inferior call), it is still possible to kill the running
# inferior, and then restart the inferior.
#
-# At once point doing this would result in GDB giving an assertion error.
+# At one point doing this would result in GDB giving an assertion error.
proc_with_prefix run_kill_and_restart_test { target_async target_non_stop } {
# This test relies on the 'start' command, which is not possible with
# the plain 'remote' target.
diff --git a/gdb/testsuite/lib/rocm.exp b/gdb/testsuite/lib/rocm.exp
index 3eb51db..5164f1e 100644
--- a/gdb/testsuite/lib/rocm.exp
+++ b/gdb/testsuite/lib/rocm.exp
@@ -176,22 +176,3 @@ proc hip_devices_support_debug_multi_process {} {
}
return 1
}
-
-# Return true if all the devices on the host support precise memory.
-
-proc hip_devices_support_precise_memory {} {
- set unsupported_targets \
- {gfx900 gfx906 gfx908 gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032}
-
- set targets [find_amdgpu_devices]
- if { [llength $targets] == 0 } {
- return 0
- }
-
- foreach target $targets {
- if { [lsearch -exact $unsupported_targets $target] != -1 } {
- return 0
- }
- }
- return 1
-}
diff --git a/gdb/utils.c b/gdb/utils.c
index 3d216e1..ee7cf4d 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -119,7 +119,7 @@ show_sevenbit_strings (struct ui_file *file, int from_tty,
/* String to be printed before warning messages, if any. */
-const char *warning_pre_print = "\nwarning: ";
+const char *warning_pre_print = "\n";
bool pagination_enabled = true;
static void
@@ -176,8 +176,8 @@ vwarning (const char *string, va_list args)
term_state.emplace ();
target_terminal::ours_for_output ();
}
- if (warning_pre_print)
- gdb_puts (warning_pre_print, gdb_stderr);
+ gdb_puts (warning_pre_print, gdb_stderr);
+ gdb_puts (_("warning: "), gdb_stderr);
gdb_vprintf (gdb_stderr, string, args);
gdb_printf (gdb_stderr, "\n");
}
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);
}