forked from Imagelibrary/binutils-gdb
Compare commits
22 Commits
users/ibha
...
users/sima
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee8f65ec48 | ||
|
|
18784a7fe2 | ||
|
|
6a501c2c93 | ||
|
|
fd85b25156 | ||
|
|
340e6b6185 | ||
|
|
c26bf42ae4 | ||
|
|
134a3c34a5 | ||
|
|
c2dfac7b84 | ||
|
|
5dafb0e289 | ||
|
|
379d644f7a | ||
|
|
05b4831efd | ||
|
|
4c81a25468 | ||
|
|
d30767bbdc | ||
|
|
7564aea624 | ||
|
|
de8c68c641 | ||
|
|
7f6f1e7f00 | ||
|
|
c4f180d72d | ||
|
|
a0b54aa74d | ||
|
|
f2f3218633 | ||
|
|
8af6d2db6c | ||
|
|
449c4c6900 | ||
|
|
1d4b607f0e |
@@ -1121,7 +1121,6 @@ COMMON_SFILES = \
|
||||
f-lang.c \
|
||||
f-typeprint.c \
|
||||
f-valprint.c \
|
||||
filename-seen-cache.c \
|
||||
filesystem.c \
|
||||
findcmd.c \
|
||||
findvar.c \
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <ctype.h>
|
||||
#include "event-top.h"
|
||||
#include "exceptions.h"
|
||||
#include "hashtab.h"
|
||||
#include "gdbsupport/unordered_set.h"
|
||||
#include "symtab.h"
|
||||
#include "frame.h"
|
||||
#include "breakpoint.h"
|
||||
@@ -12749,25 +12749,20 @@ all_locations_are_pending (struct breakpoint *b, struct program_space *pspace)
|
||||
static bool
|
||||
ambiguous_names_p (const bp_location_range &locs)
|
||||
{
|
||||
htab_up htab (htab_create_alloc (13, htab_hash_string, htab_eq_string, NULL,
|
||||
xcalloc, xfree));
|
||||
gdb::unordered_set<std::string_view> htab;
|
||||
|
||||
for (const bp_location &l : locs)
|
||||
{
|
||||
const char **slot;
|
||||
const char *name = l.function_name.get ();
|
||||
|
||||
/* Allow for some names to be NULL, ignore them. */
|
||||
if (name == NULL)
|
||||
continue;
|
||||
|
||||
slot = (const char **) htab_find_slot (htab.get (), (const void *) name,
|
||||
INSERT);
|
||||
/* NOTE: We can assume slot != NULL here because xcalloc never
|
||||
returns NULL. */
|
||||
if (*slot != NULL)
|
||||
bool inserted = htab.insert (name).second;
|
||||
|
||||
if (!inserted)
|
||||
return true;
|
||||
*slot = name;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "gdbtypes.h"
|
||||
#include "dwarf2/loc.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#include "gdbsupport/unordered_set.h"
|
||||
|
||||
/* Compute the name of the pointer representing a local symbol's
|
||||
address. */
|
||||
@@ -441,46 +441,6 @@ gcc_symbol_address (void *datum, struct gcc_c_context *gcc_context,
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* A hash function for symbol names. */
|
||||
|
||||
static hashval_t
|
||||
hash_symname (const void *a)
|
||||
{
|
||||
const struct symbol *sym = (const struct symbol *) a;
|
||||
|
||||
return htab_hash_string (sym->natural_name ());
|
||||
}
|
||||
|
||||
/* A comparison function for hash tables that just looks at symbol
|
||||
names. */
|
||||
|
||||
static int
|
||||
eq_symname (const void *a, const void *b)
|
||||
{
|
||||
const struct symbol *syma = (const struct symbol *) a;
|
||||
const struct symbol *symb = (const struct symbol *) b;
|
||||
|
||||
return strcmp (syma->natural_name (), symb->natural_name ()) == 0;
|
||||
}
|
||||
|
||||
/* If a symbol with the same name as SYM is already in HASHTAB, return
|
||||
1. Otherwise, add SYM to HASHTAB and return 0. */
|
||||
|
||||
static int
|
||||
symbol_seen (htab_t hashtab, struct symbol *sym)
|
||||
{
|
||||
void **slot;
|
||||
|
||||
slot = htab_find_slot (hashtab, sym, INSERT);
|
||||
if (*slot != NULL)
|
||||
return 1;
|
||||
|
||||
*slot = sym;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generate C code to compute the length of a VLA. */
|
||||
|
||||
static void
|
||||
@@ -626,8 +586,7 @@ generate_c_for_variable_locations (compile_instance *compiler,
|
||||
|
||||
/* Ensure that a given name is only entered once. This reflects the
|
||||
reality of shadowing. */
|
||||
htab_up symhash (htab_create_alloc (1, hash_symname, eq_symname, NULL,
|
||||
xcalloc, xfree));
|
||||
gdb::unordered_set<std::string_view> symset;
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -635,7 +594,9 @@ generate_c_for_variable_locations (compile_instance *compiler,
|
||||
compute the location of each local variable. */
|
||||
for (struct symbol *sym : block_iterator_range (block))
|
||||
{
|
||||
if (!symbol_seen (symhash.get (), sym))
|
||||
bool inserted = symset.insert (sym->natural_name ()).second;
|
||||
|
||||
if (inserted)
|
||||
generate_c_for_for_one_variable (compiler, stream, gdbarch,
|
||||
registers_used, pc, sym);
|
||||
}
|
||||
|
||||
@@ -105,9 +105,9 @@ do_module_cleanup (void *arg, int registers_valid)
|
||||
static type *
|
||||
create_copied_type_recursive (objfile *objfile, type *func_type)
|
||||
{
|
||||
htab_up copied_types = create_copied_types_hash ();
|
||||
func_type = copy_type_recursive (func_type, copied_types.get ());
|
||||
return func_type;
|
||||
copied_types_hash_t copied_types;
|
||||
|
||||
return copy_type_recursive (func_type, copied_types);
|
||||
}
|
||||
|
||||
/* Perform inferior call of MODULE. This function may throw an error.
|
||||
|
||||
@@ -60,112 +60,15 @@ static struct cmd_list_element *compile_command_list;
|
||||
|
||||
bool compile_debug;
|
||||
|
||||
/* Object of this type are stored in the compiler's symbol_err_map. */
|
||||
|
||||
struct symbol_error
|
||||
{
|
||||
/* The symbol. */
|
||||
|
||||
const struct symbol *sym;
|
||||
|
||||
/* The error message to emit. This is malloc'd and owned by the
|
||||
hash table. */
|
||||
|
||||
char *message;
|
||||
};
|
||||
|
||||
/* An object that maps a gdb type to a gcc type. */
|
||||
|
||||
struct type_map_instance
|
||||
{
|
||||
/* The gdb type. */
|
||||
|
||||
struct type *type;
|
||||
|
||||
/* The corresponding gcc type handle. */
|
||||
|
||||
gcc_type gcc_type_handle;
|
||||
};
|
||||
|
||||
/* Hash a type_map_instance. */
|
||||
|
||||
static hashval_t
|
||||
hash_type_map_instance (const void *p)
|
||||
{
|
||||
const struct type_map_instance *inst = (const struct type_map_instance *) p;
|
||||
|
||||
return htab_hash_pointer (inst->type);
|
||||
}
|
||||
|
||||
/* Check two type_map_instance objects for equality. */
|
||||
|
||||
static int
|
||||
eq_type_map_instance (const void *a, const void *b)
|
||||
{
|
||||
const struct type_map_instance *insta = (const struct type_map_instance *) a;
|
||||
const struct type_map_instance *instb = (const struct type_map_instance *) b;
|
||||
|
||||
return insta->type == instb->type;
|
||||
}
|
||||
|
||||
/* Hash function for struct symbol_error. */
|
||||
|
||||
static hashval_t
|
||||
hash_symbol_error (const void *a)
|
||||
{
|
||||
const struct symbol_error *se = (const struct symbol_error *) a;
|
||||
|
||||
return htab_hash_pointer (se->sym);
|
||||
}
|
||||
|
||||
/* Equality function for struct symbol_error. */
|
||||
|
||||
static int
|
||||
eq_symbol_error (const void *a, const void *b)
|
||||
{
|
||||
const struct symbol_error *sea = (const struct symbol_error *) a;
|
||||
const struct symbol_error *seb = (const struct symbol_error *) b;
|
||||
|
||||
return sea->sym == seb->sym;
|
||||
}
|
||||
|
||||
/* Deletion function for struct symbol_error. */
|
||||
|
||||
static void
|
||||
del_symbol_error (void *a)
|
||||
{
|
||||
struct symbol_error *se = (struct symbol_error *) a;
|
||||
|
||||
xfree (se->message);
|
||||
xfree (se);
|
||||
}
|
||||
|
||||
/* Constructor for compile_instance. */
|
||||
|
||||
compile_instance::compile_instance (struct gcc_base_context *gcc_fe,
|
||||
const char *options)
|
||||
: m_gcc_fe (gcc_fe), m_gcc_target_options (options),
|
||||
m_type_map (htab_create_alloc (10, hash_type_map_instance,
|
||||
eq_type_map_instance,
|
||||
xfree, xcalloc, xfree)),
|
||||
m_symbol_err_map (htab_create_alloc (10, hash_symbol_error,
|
||||
eq_symbol_error, del_symbol_error,
|
||||
xcalloc, xfree))
|
||||
{
|
||||
}
|
||||
|
||||
/* See compile-internal.h. */
|
||||
|
||||
bool
|
||||
compile_instance::get_cached_type (struct type *type, gcc_type *ret) const
|
||||
{
|
||||
struct type_map_instance inst, *found;
|
||||
|
||||
inst.type = type;
|
||||
found = (struct type_map_instance *) htab_find (m_type_map.get (), &inst);
|
||||
if (found != NULL)
|
||||
if (auto iter = m_type_map.find (type);
|
||||
iter != m_type_map.end ())
|
||||
{
|
||||
*ret = found->gcc_type_handle;
|
||||
*ret = iter->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -177,25 +80,12 @@ compile_instance::get_cached_type (struct type *type, gcc_type *ret) const
|
||||
void
|
||||
compile_instance::insert_type (struct type *type, gcc_type gcc_type)
|
||||
{
|
||||
struct type_map_instance inst, *add;
|
||||
void **slot;
|
||||
auto [it, inserted] = m_type_map.emplace (type, gcc_type);
|
||||
|
||||
inst.type = type;
|
||||
inst.gcc_type_handle = gcc_type;
|
||||
slot = htab_find_slot (m_type_map.get (), &inst, INSERT);
|
||||
|
||||
add = (struct type_map_instance *) *slot;
|
||||
/* The type might have already been inserted in order to handle
|
||||
recursive types. */
|
||||
if (add != NULL && add->gcc_type_handle != gcc_type)
|
||||
if (!inserted && it->second != gcc_type)
|
||||
error (_("Unexpected type id from GCC, check you use recent enough GCC."));
|
||||
|
||||
if (add == NULL)
|
||||
{
|
||||
add = XNEW (struct type_map_instance);
|
||||
*add = inst;
|
||||
*slot = add;
|
||||
}
|
||||
}
|
||||
|
||||
/* See compile-internal.h. */
|
||||
@@ -204,19 +94,7 @@ void
|
||||
compile_instance::insert_symbol_error (const struct symbol *sym,
|
||||
const char *text)
|
||||
{
|
||||
struct symbol_error e;
|
||||
void **slot;
|
||||
|
||||
e.sym = sym;
|
||||
slot = htab_find_slot (m_symbol_err_map.get (), &e, INSERT);
|
||||
if (*slot == NULL)
|
||||
{
|
||||
struct symbol_error *ep = XNEW (struct symbol_error);
|
||||
|
||||
ep->sym = sym;
|
||||
ep->message = xstrdup (text);
|
||||
*slot = ep;
|
||||
}
|
||||
m_symbol_err_map.emplace (sym, text);
|
||||
}
|
||||
|
||||
/* See compile-internal.h. */
|
||||
@@ -224,20 +102,12 @@ compile_instance::insert_symbol_error (const struct symbol *sym,
|
||||
void
|
||||
compile_instance::error_symbol_once (const struct symbol *sym)
|
||||
{
|
||||
struct symbol_error search;
|
||||
struct symbol_error *err;
|
||||
|
||||
if (m_symbol_err_map == NULL)
|
||||
return;
|
||||
|
||||
search.sym = sym;
|
||||
err = (struct symbol_error *) htab_find (m_symbol_err_map.get (), &search);
|
||||
if (err == NULL || err->message == NULL)
|
||||
return;
|
||||
|
||||
gdb::unique_xmalloc_ptr<char> message (err->message);
|
||||
err->message = NULL;
|
||||
error (_("%s"), message.get ());
|
||||
if (auto iter = m_symbol_err_map.find (sym);
|
||||
iter != m_symbol_err_map.end () && !iter->second.empty ())
|
||||
{
|
||||
std::string message = std::move (iter->second);
|
||||
error (_("%s"), message.c_str ());
|
||||
}
|
||||
}
|
||||
|
||||
/* Implement "show debug compile". */
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#define COMPILE_COMPILE_H
|
||||
|
||||
#include "gcc-c-interface.h"
|
||||
#include "gdbsupport/gdb-hashtab.h"
|
||||
#include "gdbsupport/unordered_map.h"
|
||||
|
||||
struct ui_file;
|
||||
struct gdbarch;
|
||||
@@ -61,7 +61,10 @@ enum compile_i_scope_types
|
||||
class compile_instance
|
||||
{
|
||||
public:
|
||||
compile_instance (struct gcc_base_context *gcc_fe, const char *options);
|
||||
compile_instance (struct gcc_base_context *gcc_fe, const char *options)
|
||||
: m_gcc_fe (gcc_fe),
|
||||
m_gcc_target_options (options)
|
||||
{}
|
||||
|
||||
virtual ~compile_instance ()
|
||||
{
|
||||
@@ -163,10 +166,10 @@ protected:
|
||||
std::string m_gcc_target_options;
|
||||
|
||||
/* Map from gdb types to gcc types. */
|
||||
htab_up m_type_map;
|
||||
gdb::unordered_map<type *, gcc_type> m_type_map;
|
||||
|
||||
/* Map from gdb symbols to gcc error messages to emit. */
|
||||
htab_up m_symbol_err_map;
|
||||
gdb::unordered_map<const symbol *, std::string> m_symbol_err_map;
|
||||
};
|
||||
|
||||
/* Public function that is called from compile_control case in the
|
||||
|
||||
85
gdb/disasm.c
85
gdb/disasm.c
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "arch-utils.h"
|
||||
#include "event-top.h"
|
||||
#include "gdbsupport/unordered_set.h"
|
||||
#include "target.h"
|
||||
#include "value.h"
|
||||
#include "ui-out.h"
|
||||
@@ -122,73 +123,25 @@ struct deprecated_dis_line_entry
|
||||
|
||||
struct dis_line_entry
|
||||
{
|
||||
dis_line_entry (struct symtab *symtab, int line) noexcept
|
||||
: symtab (symtab),
|
||||
line (line)
|
||||
{}
|
||||
|
||||
bool operator== (const dis_line_entry &other) const noexcept
|
||||
{ return this->symtab == other.symtab && this->line == other.line; }
|
||||
|
||||
struct symtab *symtab;
|
||||
int line;
|
||||
};
|
||||
|
||||
/* Hash function for dis_line_entry. */
|
||||
|
||||
static hashval_t
|
||||
hash_dis_line_entry (const void *item)
|
||||
struct dis_line_entry_hash
|
||||
{
|
||||
const struct dis_line_entry *dle = (const struct dis_line_entry *) item;
|
||||
|
||||
return htab_hash_pointer (dle->symtab) + dle->line;
|
||||
}
|
||||
|
||||
/* Equal function for dis_line_entry. */
|
||||
|
||||
static int
|
||||
eq_dis_line_entry (const void *item_lhs, const void *item_rhs)
|
||||
{
|
||||
const struct dis_line_entry *lhs = (const struct dis_line_entry *) item_lhs;
|
||||
const struct dis_line_entry *rhs = (const struct dis_line_entry *) item_rhs;
|
||||
|
||||
return (lhs->symtab == rhs->symtab
|
||||
&& lhs->line == rhs->line);
|
||||
}
|
||||
|
||||
/* Create the table to manage lines for mixed source/disassembly. */
|
||||
|
||||
static htab_t
|
||||
allocate_dis_line_table (void)
|
||||
{
|
||||
return htab_create_alloc (41,
|
||||
hash_dis_line_entry, eq_dis_line_entry,
|
||||
xfree, xcalloc, xfree);
|
||||
}
|
||||
|
||||
/* Add a new dis_line_entry containing SYMTAB and LINE to TABLE. */
|
||||
|
||||
static void
|
||||
add_dis_line_entry (htab_t table, struct symtab *symtab, int line)
|
||||
{
|
||||
void **slot;
|
||||
struct dis_line_entry dle, *dlep;
|
||||
|
||||
dle.symtab = symtab;
|
||||
dle.line = line;
|
||||
slot = htab_find_slot (table, &dle, INSERT);
|
||||
if (*slot == NULL)
|
||||
{
|
||||
dlep = XNEW (struct dis_line_entry);
|
||||
dlep->symtab = symtab;
|
||||
dlep->line = line;
|
||||
*slot = dlep;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return non-zero if SYMTAB, LINE are in TABLE. */
|
||||
|
||||
static int
|
||||
line_has_code_p (htab_t table, struct symtab *symtab, int line)
|
||||
{
|
||||
struct dis_line_entry dle;
|
||||
|
||||
dle.symtab = symtab;
|
||||
dle.line = line;
|
||||
return htab_find (table, &dle) != NULL;
|
||||
}
|
||||
uint64_t operator() (const dis_line_entry &x) const noexcept
|
||||
{ return std::hash<symtab *> () (x.symtab) + std::hash<int> () (x.line); }
|
||||
};
|
||||
|
||||
/* Wrapper of target_read_code. */
|
||||
|
||||
@@ -747,7 +700,7 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch,
|
||||
but if that text is for code that will be disassembled later, then
|
||||
we'll want to defer printing it until later with its associated code. */
|
||||
|
||||
htab_up dis_line_table (allocate_dis_line_table ());
|
||||
gdb::unordered_set<dis_line_entry, dis_line_entry_hash> dis_line_table;
|
||||
|
||||
struct objfile *objfile = main_symtab->compunit ()->objfile ();
|
||||
|
||||
@@ -786,7 +739,7 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch,
|
||||
pc += length;
|
||||
|
||||
if (sal.symtab != NULL)
|
||||
add_dis_line_entry (dis_line_table.get (), sal.symtab, sal.line);
|
||||
dis_line_table.emplace (sal.symtab, sal.line);
|
||||
}
|
||||
|
||||
/* Second pass: print the disassembly.
|
||||
@@ -859,11 +812,9 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch,
|
||||
/* Several preceding source lines. Print the trailing ones
|
||||
not associated with code that we'll print later. */
|
||||
for (l = sal.line - 1; l > last_line; --l)
|
||||
{
|
||||
if (line_has_code_p (dis_line_table.get (),
|
||||
sal.symtab, l))
|
||||
break;
|
||||
}
|
||||
if (dis_line_table.contains ({sal.symtab, l}))
|
||||
break;
|
||||
|
||||
if (l < sal.line - 1)
|
||||
{
|
||||
start_preceding_line_to_display = l + 1;
|
||||
|
||||
@@ -20,33 +20,6 @@
|
||||
#include "dwarf2/read.h"
|
||||
#include "dwarf2/abbrev-cache.h"
|
||||
|
||||
/* Hash function for an abbrev table. */
|
||||
|
||||
hashval_t
|
||||
abbrev_cache::hash_table (const void *item)
|
||||
{
|
||||
const struct abbrev_table *table = (const struct abbrev_table *) item;
|
||||
return to_underlying (table->sect_off);
|
||||
}
|
||||
|
||||
/* Comparison function for abbrev table. */
|
||||
|
||||
int
|
||||
abbrev_cache::eq_table (const void *lhs, const void *rhs)
|
||||
{
|
||||
const struct abbrev_table *l_table = (const struct abbrev_table *) lhs;
|
||||
const search_key *key = (const search_key *) rhs;
|
||||
return (l_table->section == key->section
|
||||
&& l_table->sect_off == key->offset);
|
||||
}
|
||||
|
||||
abbrev_cache::abbrev_cache ()
|
||||
: m_tables (htab_create_alloc (20, hash_table, eq_table,
|
||||
htab_delete_entry<abbrev_table>,
|
||||
xcalloc, xfree))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
abbrev_cache::add (abbrev_table_up table)
|
||||
{
|
||||
@@ -54,11 +27,10 @@ abbrev_cache::add (abbrev_table_up table)
|
||||
if (table == nullptr)
|
||||
return;
|
||||
|
||||
search_key key = { table->section, table->sect_off };
|
||||
void **slot = htab_find_slot_with_hash (m_tables.get (), &key,
|
||||
to_underlying (table->sect_off),
|
||||
INSERT);
|
||||
bool inserted
|
||||
= m_tables.emplace (key {table->section,
|
||||
table->sect_off}, std::move (table)).second;
|
||||
|
||||
/* If this one already existed, then it should have been reused. */
|
||||
gdb_assert (*slot == nullptr);
|
||||
*slot = (void *) table.release ();
|
||||
gdb_assert (inserted);
|
||||
}
|
||||
|
||||
@@ -21,12 +21,13 @@
|
||||
#define GDB_DWARF2_ABBREV_CACHE_H
|
||||
|
||||
#include "dwarf2/abbrev.h"
|
||||
#include "gdbsupport/unordered_map.h"
|
||||
|
||||
/* An abbrev cache holds abbrev tables for easier reuse. */
|
||||
class abbrev_cache
|
||||
{
|
||||
public:
|
||||
abbrev_cache ();
|
||||
abbrev_cache () = default;
|
||||
DISABLE_COPY_AND_ASSIGN (abbrev_cache);
|
||||
|
||||
/* Find an abbrev table coming from the abbrev section SECTION at
|
||||
@@ -34,10 +35,11 @@ public:
|
||||
been registered. */
|
||||
abbrev_table *find (struct dwarf2_section_info *section, sect_offset offset)
|
||||
{
|
||||
search_key key = { section, offset };
|
||||
if (auto iter = m_tables.find ({ section, offset });
|
||||
iter != m_tables.end ())
|
||||
return iter->second.get ();
|
||||
|
||||
return (abbrev_table *) htab_find_with_hash (m_tables.get (), &key,
|
||||
to_underlying (offset));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Add TABLE to this cache. Ownership of TABLE is transferred to
|
||||
@@ -48,18 +50,29 @@ public:
|
||||
void add (abbrev_table_up table);
|
||||
|
||||
private:
|
||||
|
||||
static hashval_t hash_table (const void *item);
|
||||
static int eq_table (const void *lhs, const void *rhs);
|
||||
|
||||
struct search_key
|
||||
struct key
|
||||
{
|
||||
struct dwarf2_section_info *section;
|
||||
dwarf2_section_info *section;
|
||||
sect_offset offset;
|
||||
};
|
||||
|
||||
struct key_hash
|
||||
{
|
||||
std::size_t operator() (const key &k) const noexcept
|
||||
{
|
||||
return (std::hash<dwarf2_section_info *> () (k.section)
|
||||
+ std::hash<std::uint64_t> () (to_underlying (k.offset)));
|
||||
}
|
||||
};
|
||||
|
||||
struct key_eq
|
||||
{
|
||||
bool operator() (const key &lhs, const key &rhs) const noexcept
|
||||
{ return lhs.section == rhs.section && lhs.offset == rhs.offset; }
|
||||
};
|
||||
|
||||
/* Hash table of abbrev tables. */
|
||||
htab_up m_tables;
|
||||
gdb::unordered_map<key, abbrev_table_up, key_hash, key_eq> m_tables;
|
||||
};
|
||||
|
||||
#endif /* GDB_DWARF2_ABBREV_CACHE_H */
|
||||
|
||||
@@ -29,52 +29,6 @@
|
||||
#include "dwarf2/leb.h"
|
||||
#include "bfd.h"
|
||||
|
||||
/* Hash function for an abbrev. */
|
||||
|
||||
static hashval_t
|
||||
hash_abbrev (const void *item)
|
||||
{
|
||||
const struct abbrev_info *info = (const struct abbrev_info *) item;
|
||||
/* Warning: if you change this next line, you must also update the
|
||||
other code in this class using the _with_hash functions. */
|
||||
return info->number;
|
||||
}
|
||||
|
||||
/* Comparison function for abbrevs. */
|
||||
|
||||
static int
|
||||
eq_abbrev (const void *lhs, const void *rhs)
|
||||
{
|
||||
const struct abbrev_info *l_info = (const struct abbrev_info *) lhs;
|
||||
const struct abbrev_info *r_info = (const struct abbrev_info *) rhs;
|
||||
return l_info->number == r_info->number;
|
||||
}
|
||||
|
||||
/* Abbreviation tables.
|
||||
|
||||
In DWARF version 2, the description of the debugging information is
|
||||
stored in a separate .debug_abbrev section. Before we read any
|
||||
dies from a section we read in all abbreviations and install them
|
||||
in a hash table. */
|
||||
|
||||
abbrev_table::abbrev_table (sect_offset off, struct dwarf2_section_info *sect)
|
||||
: sect_off (off),
|
||||
section (sect),
|
||||
m_abbrevs (htab_create_alloc (20, hash_abbrev, eq_abbrev,
|
||||
nullptr, xcalloc, xfree))
|
||||
{
|
||||
}
|
||||
|
||||
/* Add an abbreviation to the table. */
|
||||
|
||||
void
|
||||
abbrev_table::add_abbrev (struct abbrev_info *abbrev)
|
||||
{
|
||||
void **slot = htab_find_slot_with_hash (m_abbrevs.get (), abbrev,
|
||||
abbrev->number, INSERT);
|
||||
*slot = abbrev;
|
||||
}
|
||||
|
||||
/* Helper function that returns true if a DIE with the given tag might
|
||||
plausibly be indexed. */
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#ifndef GDB_DWARF2_ABBREV_H
|
||||
#define GDB_DWARF2_ABBREV_H
|
||||
|
||||
#include "hashtab.h"
|
||||
#include "gdbsupport/unordered_map.h"
|
||||
|
||||
struct attr_abbrev
|
||||
{
|
||||
@@ -60,7 +60,12 @@ struct abbrev_info
|
||||
struct abbrev_table;
|
||||
typedef std::unique_ptr<struct abbrev_table> abbrev_table_up;
|
||||
|
||||
/* Top level data structure to contain an abbreviation table. */
|
||||
/* Top level data structure to contain an abbreviation table.
|
||||
|
||||
In DWARF version 2, the description of the debugging information is
|
||||
stored in a separate .debug_abbrev section. Before we read any
|
||||
dies from a section we read in all abbreviations and install them
|
||||
in a hash table. */
|
||||
|
||||
struct abbrev_table
|
||||
{
|
||||
@@ -76,12 +81,11 @@ struct abbrev_table
|
||||
|
||||
const struct abbrev_info *lookup_abbrev (unsigned int abbrev_number) const
|
||||
{
|
||||
struct abbrev_info search;
|
||||
search.number = abbrev_number;
|
||||
if (auto iter = m_abbrevs.find (abbrev_number);
|
||||
iter != m_abbrevs.end ())
|
||||
return iter->second;
|
||||
|
||||
return (struct abbrev_info *) htab_find_with_hash (m_abbrevs.get (),
|
||||
&search,
|
||||
abbrev_number);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Where the abbrev table came from.
|
||||
@@ -92,15 +96,20 @@ struct abbrev_table
|
||||
|
||||
private:
|
||||
|
||||
abbrev_table (sect_offset off, struct dwarf2_section_info *sect);
|
||||
abbrev_table (sect_offset off, struct dwarf2_section_info *sect)
|
||||
: sect_off (off),
|
||||
section (sect)
|
||||
{
|
||||
}
|
||||
|
||||
DISABLE_COPY_AND_ASSIGN (abbrev_table);
|
||||
|
||||
/* Add an abbreviation to the table. */
|
||||
void add_abbrev (struct abbrev_info *abbrev);
|
||||
void add_abbrev (struct abbrev_info *abbrev)
|
||||
{ m_abbrevs.emplace (abbrev->number, abbrev); }
|
||||
|
||||
/* Hash table of abbrevs. */
|
||||
htab_up m_abbrevs;
|
||||
gdb::unordered_map<int, abbrev_info *> m_abbrevs;
|
||||
|
||||
/* Storage for the abbrev table. */
|
||||
auto_obstack m_abbrev_obstack;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "dwarf2/types.h"
|
||||
#include "../frame.h"
|
||||
#include "gdbsupport/function-view.h"
|
||||
#include "gdbsupport/unordered_map.h"
|
||||
|
||||
struct dwarf2_locexpr_baton;
|
||||
struct dwarf2_per_cu_data;
|
||||
@@ -241,4 +242,6 @@ public:
|
||||
struct call_site_parameter parameter[];
|
||||
};
|
||||
|
||||
using call_site_htab_t = gdb::unordered_map<unrelocated_addr, call_site *>;
|
||||
|
||||
#endif /* CALL_SITE_H */
|
||||
|
||||
@@ -119,57 +119,33 @@ dwarf2_cu::addr_type () const
|
||||
return addr_type;
|
||||
}
|
||||
|
||||
/* A hashtab traversal function that marks the dependent CUs. */
|
||||
|
||||
static int
|
||||
dwarf2_mark_helper (void **slot, void *data)
|
||||
{
|
||||
dwarf2_per_cu_data *per_cu = (dwarf2_per_cu_data *) *slot;
|
||||
dwarf2_per_objfile *per_objfile = (dwarf2_per_objfile *) data;
|
||||
dwarf2_cu *cu = per_objfile->get_cu (per_cu);
|
||||
|
||||
/* cu->m_dependencies references may not yet have been ever read if
|
||||
QUIT aborts reading of the chain. As such dependencies remain
|
||||
valid it is not much useful to track and undo them during QUIT
|
||||
cleanups. */
|
||||
if (cu != nullptr)
|
||||
cu->mark ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* See dwarf2/cu.h. */
|
||||
|
||||
void
|
||||
dwarf2_cu::mark ()
|
||||
{
|
||||
if (!m_mark)
|
||||
if (m_mark)
|
||||
return;
|
||||
|
||||
m_mark = true;
|
||||
|
||||
for (dwarf2_per_cu_data *per_cu : m_dependencies)
|
||||
{
|
||||
m_mark = true;
|
||||
if (m_dependencies != nullptr)
|
||||
htab_traverse_noresize (m_dependencies.get (), dwarf2_mark_helper,
|
||||
per_objfile);
|
||||
/* cu->m_dependencies references may not yet have been ever
|
||||
read if QUIT aborts reading of the chain. As such
|
||||
dependencies remain valid it is not much useful to track
|
||||
and undo them during QUIT cleanups. */
|
||||
dwarf2_cu *cu = per_objfile->get_cu (per_cu);
|
||||
|
||||
if (cu == nullptr)
|
||||
continue;
|
||||
|
||||
cu->mark ();
|
||||
}
|
||||
}
|
||||
|
||||
/* See dwarf2/cu.h. */
|
||||
|
||||
void
|
||||
dwarf2_cu::add_dependence (struct dwarf2_per_cu_data *ref_per_cu)
|
||||
{
|
||||
void **slot;
|
||||
|
||||
if (m_dependencies == nullptr)
|
||||
m_dependencies.reset (htab_create_alloc
|
||||
(5, htab_hash_pointer, htab_eq_pointer,
|
||||
nullptr, xcalloc, xfree));
|
||||
|
||||
slot = htab_find_slot (m_dependencies.get (), ref_per_cu, INSERT);
|
||||
if (*slot == nullptr)
|
||||
*slot = ref_per_cu;
|
||||
}
|
||||
|
||||
/* See dwarf2/cu.h. */
|
||||
|
||||
buildsym_compunit *
|
||||
dwarf2_cu::get_builder ()
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "dwarf2/comp-unit-head.h"
|
||||
#include <optional>
|
||||
#include "language.h"
|
||||
#include "gdbsupport/unordered_set.h"
|
||||
|
||||
/* Type used for delaying computation of method physnames.
|
||||
See comments for compute_delayed_physnames. */
|
||||
@@ -95,7 +96,8 @@ struct dwarf2_cu
|
||||
}
|
||||
|
||||
/* Add a dependence relationship from this cu to REF_PER_CU. */
|
||||
void add_dependence (struct dwarf2_per_cu_data *ref_per_cu);
|
||||
void add_dependence (struct dwarf2_per_cu_data *ref_per_cu)
|
||||
{ m_dependencies.emplace (ref_per_cu); }
|
||||
|
||||
/* The header of the compilation unit. */
|
||||
struct comp_unit_head header;
|
||||
@@ -120,9 +122,9 @@ private:
|
||||
std::unique_ptr<buildsym_compunit> m_builder;
|
||||
|
||||
/* A set of pointers to dwarf2_per_cu_data objects for compilation
|
||||
units referenced by this one. Only set during full symbol processing;
|
||||
units referenced by this one. Only used during full symbol processing;
|
||||
partial symbol tables do not have dependencies. */
|
||||
htab_up m_dependencies;
|
||||
gdb::unordered_set<dwarf2_per_cu_data *> m_dependencies;
|
||||
|
||||
public:
|
||||
/* The generic symbol table building routines have separate lists for
|
||||
@@ -151,7 +153,7 @@ public:
|
||||
|
||||
/* A hash table of DIE cu_offset for following references with
|
||||
die_info->offset.sect_off as hash. */
|
||||
htab_up die_hash;
|
||||
gdb::unordered_map<sect_offset, die_info *> die_hash;
|
||||
|
||||
/* Full DIEs if read in. */
|
||||
struct die_info *dies = nullptr;
|
||||
@@ -170,7 +172,7 @@ public:
|
||||
std::vector<delayed_method_info> method_list;
|
||||
|
||||
/* To be copied to symtab->call_site_htab. */
|
||||
htab_up call_site_htab;
|
||||
call_site_htab_t call_site_htab;
|
||||
|
||||
/* Non-NULL if this CU came from a DWO file.
|
||||
There is an invariant here that is important to remember:
|
||||
|
||||
@@ -35,27 +35,6 @@ die_info::allocate (struct obstack *obstack, int num_attrs)
|
||||
return die;
|
||||
}
|
||||
|
||||
/* See die.h. */
|
||||
|
||||
hashval_t
|
||||
die_info::hash (const void *item)
|
||||
{
|
||||
const struct die_info *die = (const struct die_info *) item;
|
||||
|
||||
return to_underlying (die->sect_off);
|
||||
}
|
||||
|
||||
/* See die.h. */
|
||||
|
||||
int
|
||||
die_info::eq (const void *item_lhs, const void *item_rhs)
|
||||
{
|
||||
const struct die_info *die_lhs = (const struct die_info *) item_lhs;
|
||||
const struct die_info *die_rhs = (const struct die_info *) item_rhs;
|
||||
|
||||
return die_lhs->sect_off == die_rhs->sect_off;
|
||||
}
|
||||
|
||||
static void
|
||||
dump_die_shallow (struct ui_file *f, int indent, struct die_info *die)
|
||||
{
|
||||
|
||||
@@ -31,14 +31,6 @@ struct die_info
|
||||
attributes that are needed. */
|
||||
static die_info *allocate (struct obstack *obstack, int num_attrs);
|
||||
|
||||
/* Trivial hash function for die_info: the hash value of a DIE is
|
||||
its offset in .debug_info for this objfile. */
|
||||
static hashval_t hash (const void *item);
|
||||
|
||||
/* Trivial comparison function for die_info structures: two DIEs
|
||||
are equal if they have the same offset. */
|
||||
static int eq (const void *item_lhs, const void *item_rhs);
|
||||
|
||||
/* Dump this DIE and any children to MAX_LEVEL. They are written to
|
||||
gdb_stdlog. Note this is called from the pdie user command in
|
||||
gdb-gdb.gdb. */
|
||||
|
||||
@@ -422,7 +422,8 @@ dwarf_decode_macro_bytes (dwarf2_per_objfile *per_objfile,
|
||||
struct dwarf2_section_info *str_section,
|
||||
struct dwarf2_section_info *str_offsets_section,
|
||||
std::optional<ULONGEST> str_offsets_base,
|
||||
htab_t include_hash, struct dwarf2_cu *cu)
|
||||
gdb::unordered_set<const gdb_byte *> &include_hash,
|
||||
struct dwarf2_cu *cu)
|
||||
{
|
||||
struct objfile *objfile = per_objfile->objfile;
|
||||
enum dwarf_macro_record_type macinfo_type;
|
||||
@@ -697,7 +698,6 @@ dwarf_decode_macro_bytes (dwarf2_per_objfile *per_objfile,
|
||||
case DW_MACRO_import_sup:
|
||||
{
|
||||
LONGEST offset;
|
||||
void **slot;
|
||||
bfd *include_bfd = abfd;
|
||||
const struct dwarf2_section_info *include_section = section;
|
||||
const gdb_byte *include_mac_end = mac_end;
|
||||
@@ -719,9 +719,10 @@ dwarf_decode_macro_bytes (dwarf2_per_objfile *per_objfile,
|
||||
}
|
||||
|
||||
new_mac_ptr = include_section->buffer + offset;
|
||||
slot = htab_find_slot (include_hash, new_mac_ptr, INSERT);
|
||||
|
||||
if (*slot != NULL)
|
||||
bool inserted = include_hash.insert (new_mac_ptr).second;
|
||||
|
||||
if (!inserted)
|
||||
{
|
||||
/* This has actually happened; see
|
||||
http://sourceware.org/bugzilla/show_bug.cgi?id=13568. */
|
||||
@@ -730,8 +731,6 @@ dwarf_decode_macro_bytes (dwarf2_per_objfile *per_objfile,
|
||||
}
|
||||
else
|
||||
{
|
||||
*slot = (void *) new_mac_ptr;
|
||||
|
||||
dwarf_decode_macro_bytes (per_objfile, builder, include_bfd,
|
||||
new_mac_ptr, include_mac_end,
|
||||
current_file, lh, section,
|
||||
@@ -739,7 +738,7 @@ dwarf_decode_macro_bytes (dwarf2_per_objfile *per_objfile,
|
||||
str_section, str_offsets_section,
|
||||
str_offsets_base, include_hash, cu);
|
||||
|
||||
htab_remove_elt (include_hash, (void *) new_mac_ptr);
|
||||
include_hash.erase (new_mac_ptr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -788,7 +787,6 @@ dwarf_decode_macros (dwarf2_per_objfile *per_objfile,
|
||||
struct macro_source_file *current_file = 0;
|
||||
enum dwarf_macro_record_type macinfo_type;
|
||||
const gdb_byte *opcode_definitions[256];
|
||||
void **slot;
|
||||
|
||||
abfd = section->get_bfd_owner ();
|
||||
|
||||
@@ -933,14 +931,11 @@ dwarf_decode_macros (dwarf2_per_objfile *per_objfile,
|
||||
command-line macro definitions/undefinitions. This flag is unset when we
|
||||
reach the first DW_MACINFO_start_file entry. */
|
||||
|
||||
htab_up include_hash (htab_create_alloc (1, htab_hash_pointer,
|
||||
htab_eq_pointer,
|
||||
NULL, xcalloc, xfree));
|
||||
gdb::unordered_set<const gdb_byte *> include_hash;
|
||||
mac_ptr = section->buffer + offset;
|
||||
slot = htab_find_slot (include_hash.get (), mac_ptr, INSERT);
|
||||
*slot = (void *) mac_ptr;
|
||||
include_hash.insert (mac_ptr);
|
||||
dwarf_decode_macro_bytes (per_objfile, builder, abfd, mac_ptr, mac_end,
|
||||
current_file, lh, section, section_is_gnu, 0,
|
||||
offset_size, str_section, str_offsets_section,
|
||||
str_offsets_base, include_hash.get (), cu);
|
||||
str_offsets_base, include_hash, cu);
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
#include "gdbsupport/thread-pool.h"
|
||||
#include "run-on-main-thread.h"
|
||||
#include "dwarf2/parent-map.h"
|
||||
#include "gdbsupport/unordered_dense.h"
|
||||
|
||||
/* When == 1, print basic high level tracing messages.
|
||||
When > 1, be more verbose.
|
||||
@@ -2876,12 +2877,8 @@ dw_expand_symtabs_matching_file_matcher
|
||||
if (file_matcher == NULL)
|
||||
return;
|
||||
|
||||
htab_up visited_found (htab_create_alloc (10, htab_hash_pointer,
|
||||
htab_eq_pointer,
|
||||
NULL, xcalloc, xfree));
|
||||
htab_up visited_not_found (htab_create_alloc (10, htab_hash_pointer,
|
||||
htab_eq_pointer,
|
||||
NULL, xcalloc, xfree));
|
||||
gdb::unordered_set<quick_file_names *> visited_found;
|
||||
gdb::unordered_set<quick_file_names *> visited_not_found;
|
||||
|
||||
/* The rule is CUs specify all the files, including those used by
|
||||
any TU, so there's no need to scan TUs here. */
|
||||
@@ -2924,9 +2921,9 @@ dw_expand_symtabs_matching_file_matcher
|
||||
if (file_data == NULL)
|
||||
continue;
|
||||
|
||||
if (htab_find (visited_not_found.get (), file_data) != NULL)
|
||||
if (visited_not_found.contains (file_data))
|
||||
continue;
|
||||
else if (htab_find (visited_found.get (), file_data) != NULL)
|
||||
else if (visited_found.contains (file_data))
|
||||
{
|
||||
per_cu->mark = 1;
|
||||
continue;
|
||||
@@ -2957,11 +2954,10 @@ dw_expand_symtabs_matching_file_matcher
|
||||
}
|
||||
}
|
||||
|
||||
void **slot = htab_find_slot (per_cu->mark
|
||||
? visited_found.get ()
|
||||
: visited_not_found.get (),
|
||||
file_data, INSERT);
|
||||
*slot = file_data;
|
||||
if (per_cu->mark)
|
||||
visited_found.insert (file_data);
|
||||
else
|
||||
visited_not_found.insert (file_data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5495,11 +5491,8 @@ load_full_comp_unit (dwarf2_per_cu_data *this_cu,
|
||||
struct dwarf2_cu *cu = reader.cu;
|
||||
const gdb_byte *info_ptr = reader.info_ptr;
|
||||
|
||||
gdb_assert (cu->die_hash == NULL);
|
||||
cu->die_hash.reset (htab_create_alloc
|
||||
(cu->header.get_length_without_initial () / 12,
|
||||
die_info::hash, die_info::eq,
|
||||
nullptr, xcalloc, xfree));
|
||||
gdb_assert (cu->die_hash.empty ());
|
||||
cu->die_hash.reserve (cu->header.get_length_without_initial () / 12);
|
||||
|
||||
if (reader.comp_unit_die->has_children)
|
||||
reader.comp_unit_die->child
|
||||
@@ -6036,21 +6029,21 @@ void dwarf2_per_objfile::set_type_for_signatured_type
|
||||
included by PER_CU. */
|
||||
|
||||
static void
|
||||
recursively_compute_inclusions (std::vector<compunit_symtab *> *result,
|
||||
htab_t all_children, htab_t all_type_symtabs,
|
||||
dwarf2_per_cu_data *per_cu,
|
||||
dwarf2_per_objfile *per_objfile,
|
||||
struct compunit_symtab *immediate_parent)
|
||||
recursively_compute_inclusions
|
||||
(std::vector<compunit_symtab *> *result,
|
||||
gdb::unordered_set<dwarf2_per_cu_data *> &all_children,
|
||||
gdb::unordered_set<compunit_symtab *> &all_type_symtabs,
|
||||
dwarf2_per_cu_data *per_cu,
|
||||
dwarf2_per_objfile *per_objfile,
|
||||
struct compunit_symtab *immediate_parent)
|
||||
{
|
||||
void **slot = htab_find_slot (all_children, per_cu, INSERT);
|
||||
if (*slot != NULL)
|
||||
if (bool inserted = all_children.emplace (per_cu).second;
|
||||
!inserted)
|
||||
{
|
||||
/* This inclusion and its children have been processed. */
|
||||
return;
|
||||
}
|
||||
|
||||
*slot = per_cu;
|
||||
|
||||
/* Only add a CU if it has a symbol table. */
|
||||
compunit_symtab *cust = per_objfile->get_symtab (per_cu);
|
||||
if (cust != NULL)
|
||||
@@ -6059,10 +6052,9 @@ recursively_compute_inclusions (std::vector<compunit_symtab *> *result,
|
||||
seen it yet (type unit per_cu's can share symtabs). */
|
||||
if (per_cu->is_debug_types)
|
||||
{
|
||||
slot = htab_find_slot (all_type_symtabs, cust, INSERT);
|
||||
if (*slot == NULL)
|
||||
if (bool inserted = all_type_symtabs.insert (cust).second;
|
||||
inserted)
|
||||
{
|
||||
*slot = cust;
|
||||
result->push_back (cust);
|
||||
if (cust->user == NULL)
|
||||
cust->user = immediate_parent;
|
||||
@@ -6101,16 +6093,12 @@ compute_compunit_symtab_includes (dwarf2_per_cu_data *per_cu,
|
||||
if (cust == NULL)
|
||||
return;
|
||||
|
||||
htab_up all_children (htab_create_alloc (1, htab_hash_pointer,
|
||||
htab_eq_pointer,
|
||||
NULL, xcalloc, xfree));
|
||||
htab_up all_type_symtabs (htab_create_alloc (1, htab_hash_pointer,
|
||||
htab_eq_pointer,
|
||||
NULL, xcalloc, xfree));
|
||||
gdb::unordered_set<dwarf2_per_cu_data *> all_children;
|
||||
gdb::unordered_set<compunit_symtab *> all_type_symtabs;
|
||||
|
||||
for (dwarf2_per_cu_data *ptr : per_cu->imported_symtabs)
|
||||
recursively_compute_inclusions (&result_symtabs, all_children.get (),
|
||||
all_type_symtabs.get (), ptr,
|
||||
recursively_compute_inclusions (&result_symtabs, all_children,
|
||||
all_type_symtabs, ptr,
|
||||
per_objfile, cust);
|
||||
|
||||
/* Now we have a transitive closure of all the included symtabs. */
|
||||
@@ -10195,7 +10183,6 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
|
||||
struct objfile *objfile = per_objfile->objfile;
|
||||
struct gdbarch *gdbarch = objfile->arch ();
|
||||
struct attribute *attr;
|
||||
void **slot;
|
||||
int nparams;
|
||||
struct die_info *child_die;
|
||||
|
||||
@@ -10215,21 +10202,6 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
|
||||
}
|
||||
unrelocated_addr pc = attr->as_address ();
|
||||
|
||||
if (cu->call_site_htab == nullptr)
|
||||
cu->call_site_htab.reset (htab_create_alloc (16, call_site::hash,
|
||||
call_site::eq, nullptr,
|
||||
xcalloc, xfree));
|
||||
struct call_site call_site_local (pc, nullptr, nullptr);
|
||||
slot = htab_find_slot (cu->call_site_htab.get (), &call_site_local, INSERT);
|
||||
if (*slot != NULL)
|
||||
{
|
||||
complaint (_("Duplicate PC %s for DW_TAG_call_site "
|
||||
"DIE %s [in module %s]"),
|
||||
paddress (gdbarch, (CORE_ADDR) pc), sect_offset_str (die->sect_off),
|
||||
objfile_name (objfile));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Count parameters at the caller. */
|
||||
|
||||
nparams = 0;
|
||||
@@ -10254,7 +10226,16 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
|
||||
struct call_site,
|
||||
sizeof (*call_site) + sizeof (call_site->parameter[0]) * nparams))
|
||||
struct call_site (pc, cu->per_cu, per_objfile);
|
||||
*slot = call_site;
|
||||
|
||||
bool inserted = cu->call_site_htab.emplace (pc, call_site).second;
|
||||
if (!inserted)
|
||||
{
|
||||
complaint (_("Duplicate PC %s for DW_TAG_call_site "
|
||||
"DIE %s [in module %s]"),
|
||||
paddress (gdbarch, (CORE_ADDR) pc), sect_offset_str (die->sect_off),
|
||||
objfile_name (objfile));
|
||||
return;
|
||||
}
|
||||
|
||||
/* We never call the destructor of call_site, so we must ensure it is
|
||||
trivially destructible. */
|
||||
@@ -15776,10 +15757,8 @@ read_die_and_children (const struct die_reader_specs *reader,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void **slot = htab_find_slot_with_hash (reader->cu->die_hash.get (), die,
|
||||
to_underlying (die->sect_off),
|
||||
INSERT);
|
||||
*slot = die;
|
||||
bool inserted = reader->cu->die_hash.emplace (die->sect_off, die).second;
|
||||
gdb_assert (inserted);
|
||||
|
||||
if (die->has_children)
|
||||
die->child = read_die_and_siblings_1 (reader, cur_ptr, new_info_ptr, die);
|
||||
@@ -20274,7 +20253,6 @@ static struct die_info *
|
||||
follow_die_offset (sect_offset sect_off, int offset_in_dwz,
|
||||
struct dwarf2_cu **ref_cu)
|
||||
{
|
||||
struct die_info temp_die;
|
||||
struct dwarf2_cu *target_cu, *cu = *ref_cu;
|
||||
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
||||
|
||||
@@ -20330,11 +20308,9 @@ follow_die_offset (sect_offset sect_off, int offset_in_dwz,
|
||||
}
|
||||
|
||||
*ref_cu = target_cu;
|
||||
temp_die.sect_off = sect_off;
|
||||
|
||||
return (struct die_info *) htab_find_with_hash (target_cu->die_hash.get (),
|
||||
&temp_die,
|
||||
to_underlying (sect_off));
|
||||
auto it = target_cu->die_hash.find (sect_off);
|
||||
return it != target_cu->die_hash.end () ? it->second : nullptr;
|
||||
}
|
||||
|
||||
/* Follow reference attribute ATTR of SRC_DIE.
|
||||
@@ -20688,9 +20664,7 @@ static struct die_info *
|
||||
follow_die_sig_1 (struct die_info *src_die, struct signatured_type *sig_type,
|
||||
struct dwarf2_cu **ref_cu)
|
||||
{
|
||||
struct die_info temp_die;
|
||||
struct dwarf2_cu *sig_cu;
|
||||
struct die_info *die;
|
||||
dwarf2_per_objfile *per_objfile = (*ref_cu)->per_objfile;
|
||||
|
||||
|
||||
@@ -20711,11 +20685,9 @@ follow_die_sig_1 (struct die_info *src_die, struct signatured_type *sig_type,
|
||||
sig_cu = per_objfile->get_cu (sig_type);
|
||||
gdb_assert (sig_cu != NULL);
|
||||
gdb_assert (to_underlying (sig_type->type_offset_in_section) != 0);
|
||||
temp_die.sect_off = sig_type->type_offset_in_section;
|
||||
die = (struct die_info *) htab_find_with_hash (sig_cu->die_hash.get (),
|
||||
&temp_die,
|
||||
to_underlying (temp_die.sect_off));
|
||||
if (die)
|
||||
|
||||
auto die_it = sig_cu->die_hash.find (sig_type->type_offset_in_section);
|
||||
if (die_it != sig_cu->die_hash.end ())
|
||||
{
|
||||
/* For .gdb_index version 7 keep track of included TUs.
|
||||
http://sourceware.org/bugzilla/show_bug.cgi?id=15021. */
|
||||
@@ -20724,7 +20696,7 @@ follow_die_sig_1 (struct die_info *src_die, struct signatured_type *sig_type,
|
||||
(*ref_cu)->per_cu->imported_symtabs.push_back (sig_cu->per_cu);
|
||||
|
||||
*ref_cu = sig_cu;
|
||||
return die;
|
||||
return die_it->second;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -20900,11 +20872,8 @@ read_signatured_type (signatured_type *sig_type,
|
||||
struct dwarf2_cu *cu = reader.cu;
|
||||
const gdb_byte *info_ptr = reader.info_ptr;
|
||||
|
||||
gdb_assert (cu->die_hash == NULL);
|
||||
cu->die_hash.reset (htab_create_alloc
|
||||
(cu->header.get_length_without_initial () / 12,
|
||||
die_info::hash, die_info::eq,
|
||||
nullptr, xcalloc, xfree));
|
||||
gdb_assert (cu->die_hash.empty ());
|
||||
cu->die_hash.reserve (cu->header.get_length_without_initial () / 12);
|
||||
|
||||
if (reader.comp_unit_die->has_children)
|
||||
reader.comp_unit_die->child
|
||||
@@ -21684,52 +21653,6 @@ dwarf2_per_objfile::~dwarf2_per_objfile ()
|
||||
remove_all_cus ();
|
||||
}
|
||||
|
||||
/* A set of CU "per_cu" pointer, DIE offset, and GDB type pointer.
|
||||
We store these in a hash table separate from the DIEs, and preserve them
|
||||
when the DIEs are flushed out of cache.
|
||||
|
||||
The CU "per_cu" pointer is needed because offset alone is not enough to
|
||||
uniquely identify the type. A file may have multiple .debug_types sections,
|
||||
or the type may come from a DWO file. Furthermore, while it's more logical
|
||||
to use per_cu->section+offset, with Fission the section with the data is in
|
||||
the DWO file but we don't know that section at the point we need it.
|
||||
We have to use something in dwarf2_per_cu_data (or the pointer to it)
|
||||
because we can enter the lookup routine, get_die_type_at_offset, from
|
||||
outside this file, and thus won't necessarily have PER_CU->cu.
|
||||
Fortunately, PER_CU is stable for the life of the objfile. */
|
||||
|
||||
struct dwarf2_per_cu_offset_and_type
|
||||
{
|
||||
const struct dwarf2_per_cu_data *per_cu;
|
||||
sect_offset sect_off;
|
||||
struct type *type;
|
||||
};
|
||||
|
||||
/* Hash function for a dwarf2_per_cu_offset_and_type. */
|
||||
|
||||
static hashval_t
|
||||
per_cu_offset_and_type_hash (const void *item)
|
||||
{
|
||||
const struct dwarf2_per_cu_offset_and_type *ofs
|
||||
= (const struct dwarf2_per_cu_offset_and_type *) item;
|
||||
|
||||
return (uintptr_t) ofs->per_cu + to_underlying (ofs->sect_off);
|
||||
}
|
||||
|
||||
/* Equality function for a dwarf2_per_cu_offset_and_type. */
|
||||
|
||||
static int
|
||||
per_cu_offset_and_type_eq (const void *item_lhs, const void *item_rhs)
|
||||
{
|
||||
const struct dwarf2_per_cu_offset_and_type *ofs_lhs
|
||||
= (const struct dwarf2_per_cu_offset_and_type *) item_lhs;
|
||||
const struct dwarf2_per_cu_offset_and_type *ofs_rhs
|
||||
= (const struct dwarf2_per_cu_offset_and_type *) item_rhs;
|
||||
|
||||
return (ofs_lhs->per_cu == ofs_rhs->per_cu
|
||||
&& ofs_lhs->sect_off == ofs_rhs->sect_off);
|
||||
}
|
||||
|
||||
/* Set the type associated with DIE to TYPE. Save it in CU's hash
|
||||
table if necessary. For convenience, return TYPE.
|
||||
|
||||
@@ -21753,8 +21676,6 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
|
||||
bool skip_data_location)
|
||||
{
|
||||
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
||||
struct dwarf2_per_cu_offset_and_type **slot, ofs;
|
||||
struct objfile *objfile = per_objfile->objfile;
|
||||
struct attribute *attr;
|
||||
struct dynamic_prop prop;
|
||||
|
||||
@@ -21810,24 +21731,13 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
|
||||
type->add_dyn_prop (DYN_PROP_DATA_LOCATION, prop);
|
||||
}
|
||||
|
||||
if (per_objfile->die_type_hash == NULL)
|
||||
per_objfile->die_type_hash
|
||||
= htab_up (htab_create_alloc (127,
|
||||
per_cu_offset_and_type_hash,
|
||||
per_cu_offset_and_type_eq,
|
||||
NULL, xcalloc, xfree));
|
||||
|
||||
ofs.per_cu = cu->per_cu;
|
||||
ofs.sect_off = die->sect_off;
|
||||
ofs.type = type;
|
||||
slot = (struct dwarf2_per_cu_offset_and_type **)
|
||||
htab_find_slot (per_objfile->die_type_hash.get (), &ofs, INSERT);
|
||||
if (*slot)
|
||||
bool inserted
|
||||
= per_objfile->die_type_hash.emplace
|
||||
(per_cu_and_offset {cu->per_cu, die->sect_off}, type).second;
|
||||
if (!inserted)
|
||||
complaint (_("A problem internal to GDB: DIE %s has type already set"),
|
||||
sect_offset_str (die->sect_off));
|
||||
*slot = XOBNEW (&objfile->objfile_obstack,
|
||||
struct dwarf2_per_cu_offset_and_type);
|
||||
**slot = ofs;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -21839,19 +21749,9 @@ get_die_type_at_offset (sect_offset sect_off,
|
||||
dwarf2_per_cu_data *per_cu,
|
||||
dwarf2_per_objfile *per_objfile)
|
||||
{
|
||||
struct dwarf2_per_cu_offset_and_type *slot, ofs;
|
||||
auto it = per_objfile->die_type_hash.find ({per_cu, sect_off});
|
||||
|
||||
if (per_objfile->die_type_hash == NULL)
|
||||
return NULL;
|
||||
|
||||
ofs.per_cu = per_cu;
|
||||
ofs.sect_off = sect_off;
|
||||
slot = ((struct dwarf2_per_cu_offset_and_type *)
|
||||
htab_find (per_objfile->die_type_hash.get (), &ofs));
|
||||
if (slot)
|
||||
return slot->type;
|
||||
else
|
||||
return NULL;
|
||||
return it != per_objfile->die_type_hash.end () ? it->second : nullptr;
|
||||
}
|
||||
|
||||
/* Look up the type for DIE in CU in die_type_hash,
|
||||
|
||||
@@ -627,6 +627,26 @@ struct type_unit_group_unshareable
|
||||
struct symtab **symtabs = nullptr;
|
||||
};
|
||||
|
||||
struct per_cu_and_offset
|
||||
{
|
||||
dwarf2_per_cu_data *per_cu;
|
||||
sect_offset offset;
|
||||
|
||||
bool operator== (const per_cu_and_offset &other) const noexcept
|
||||
{
|
||||
return this->per_cu == other.per_cu && this->offset == other.offset;
|
||||
}
|
||||
};
|
||||
|
||||
struct per_cu_and_offset_hash
|
||||
{
|
||||
std::uint64_t operator() (const per_cu_and_offset &key) const noexcept
|
||||
{
|
||||
return (std::hash<dwarf2_per_cu_data *> () (key.per_cu)
|
||||
+ std::hash<sect_offset> () (key.offset));
|
||||
}
|
||||
};
|
||||
|
||||
/* Collection of data recorded per objfile.
|
||||
This hangs off of dwarf2_objfile_data_key.
|
||||
|
||||
@@ -701,10 +721,22 @@ struct dwarf2_per_objfile
|
||||
other objfiles backed by the same BFD. */
|
||||
struct dwarf2_per_bfd *per_bfd;
|
||||
|
||||
/* Table mapping type DIEs to their struct type *.
|
||||
This is nullptr if not allocated yet.
|
||||
The mapping is done via (CU/TU + DIE offset) -> type. */
|
||||
htab_up die_type_hash;
|
||||
/* A mapping of (CU "per_cu" pointer, DIE offset) to GDB type pointer.
|
||||
|
||||
We store these in a hash table separate from the DIEs, and preserve them
|
||||
when the DIEs are flushed out of cache.
|
||||
|
||||
The CU "per_cu" pointer is needed because offset alone is not enough to
|
||||
uniquely identify the type. A file may have multiple .debug_types sections,
|
||||
or the type may come from a DWO file. Furthermore, while it's more logical
|
||||
to use per_cu->section+offset, with Fission the section with the data is in
|
||||
the DWO file but we don't know that section at the point we need it.
|
||||
We have to use something in dwarf2_per_cu_data (or the pointer to it)
|
||||
because we can enter the lookup routine, get_die_type_at_offset, from
|
||||
outside this file, and thus won't necessarily have PER_CU->cu.
|
||||
Fortunately, PER_CU is stable for the life of the objfile. */
|
||||
gdb::unordered_map<per_cu_and_offset, type *, per_cu_and_offset_hash>
|
||||
die_type_hash;
|
||||
|
||||
/* Table containing line_header indexed by offset and offset_in_dwz. */
|
||||
htab_up line_header_hash;
|
||||
|
||||
@@ -201,7 +201,8 @@ struct extension_language_ops
|
||||
COPIED_TYPES is used to prevent cycles / duplicates and is passed to
|
||||
preserve_one_value. */
|
||||
void (*preserve_values) (const struct extension_language_defn *,
|
||||
struct objfile *objfile, htab_t copied_types);
|
||||
struct objfile *objfile,
|
||||
copied_types_hash_t &copied_types);
|
||||
|
||||
/* Return non-zero if there is a stop condition for the breakpoint.
|
||||
This is used to implement the restriction that a breakpoint may have
|
||||
|
||||
@@ -584,7 +584,8 @@ apply_ext_lang_ptwrite_filter (btrace_thread_info *btinfo)
|
||||
preserve_one_value. */
|
||||
|
||||
void
|
||||
preserve_ext_lang_values (struct objfile *objfile, htab_t copied_types)
|
||||
preserve_ext_lang_values (struct objfile *objfile,
|
||||
copied_types_hash_t &copied_types)
|
||||
{
|
||||
for (const struct extension_language_defn *extlang : extension_languages)
|
||||
{
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
|
||||
#include "mi/mi-cmds.h"
|
||||
#include "gdbsupport/array-view.h"
|
||||
#include "hashtab.h"
|
||||
#include <optional>
|
||||
#include "gdbtypes.h"
|
||||
|
||||
struct breakpoint;
|
||||
struct command_line;
|
||||
@@ -306,7 +306,8 @@ extern enum ext_lang_bt_status apply_ext_lang_frame_filter
|
||||
extern void apply_ext_lang_ptwrite_filter
|
||||
(struct btrace_thread_info *btinfo);
|
||||
|
||||
extern void preserve_ext_lang_values (struct objfile *, htab_t copied_types);
|
||||
extern void preserve_ext_lang_values (struct objfile *,
|
||||
copied_types_hash_t &copied_types);
|
||||
|
||||
extern const struct extension_language_defn *get_breakpoint_cond_ext_lang
|
||||
(struct breakpoint *b, enum extension_language skip_lang);
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/* Filename-seen cache for the GNU debugger, GDB.
|
||||
|
||||
Copyright (C) 1986-2024 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "filename-seen-cache.h"
|
||||
#include "filenames.h"
|
||||
|
||||
/* Initial size of the table. It automagically grows from here. */
|
||||
#define INITIAL_FILENAME_SEEN_CACHE_SIZE 100
|
||||
|
||||
/* filename_seen_cache constructor. */
|
||||
|
||||
filename_seen_cache::filename_seen_cache ()
|
||||
: m_tab (htab_create_alloc (INITIAL_FILENAME_SEEN_CACHE_SIZE,
|
||||
filename_hash, filename_eq,
|
||||
NULL, xcalloc, xfree))
|
||||
{
|
||||
}
|
||||
|
||||
/* See filename-seen-cache.h. */
|
||||
|
||||
void
|
||||
filename_seen_cache::clear ()
|
||||
{
|
||||
htab_empty (m_tab.get ());
|
||||
}
|
||||
|
||||
/* See filename-seen-cache.h. */
|
||||
|
||||
bool
|
||||
filename_seen_cache::seen (const char *file)
|
||||
{
|
||||
void **slot;
|
||||
|
||||
/* Is FILE in tab? */
|
||||
slot = htab_find_slot (m_tab.get (), file, INSERT);
|
||||
if (*slot != NULL)
|
||||
return true;
|
||||
|
||||
/* No; add it to tab. */
|
||||
*slot = (char *) file;
|
||||
return false;
|
||||
}
|
||||
@@ -20,46 +20,45 @@
|
||||
#ifndef FILENAME_SEEN_CACHE_H
|
||||
#define FILENAME_SEEN_CACHE_H
|
||||
|
||||
#include "gdbsupport/function-view.h"
|
||||
#include "gdbsupport/gdb-hashtab.h"
|
||||
#include "gdbsupport/unordered_set.h"
|
||||
#include "filenames.h"
|
||||
|
||||
/* Cache to watch for file names already seen. */
|
||||
|
||||
class filename_seen_cache
|
||||
{
|
||||
public:
|
||||
filename_seen_cache ();
|
||||
filename_seen_cache () = default;
|
||||
|
||||
DISABLE_COPY_AND_ASSIGN (filename_seen_cache);
|
||||
|
||||
/* Empty the cache, but do not delete it. */
|
||||
void clear ();
|
||||
/* Empty the cache. */
|
||||
void clear ()
|
||||
{ m_tab.clear (); }
|
||||
|
||||
/* If FILE is not already in the table of files in CACHE, add it and
|
||||
/* If FILE is not already in the table of files of the cache, add it and
|
||||
return false; otherwise return true.
|
||||
|
||||
NOTE: We don't manage space for FILE, we assume FILE lives as
|
||||
long as the caller needs. */
|
||||
bool seen (const char *file);
|
||||
|
||||
/* Traverse all cache entries, calling CALLBACK on each. The
|
||||
filename is passed as argument to CALLBACK. */
|
||||
void traverse (gdb::function_view<void (const char *filename)> callback)
|
||||
{
|
||||
auto erased_cb = [] (void **slot, void *info) -> int
|
||||
{
|
||||
auto filename = (const char *) *slot;
|
||||
auto restored_cb = (decltype (callback) *) info;
|
||||
(*restored_cb) (filename);
|
||||
return 1;
|
||||
};
|
||||
|
||||
htab_traverse_noresize (m_tab.get (), erased_cb, &callback);
|
||||
}
|
||||
bool seen (const char *file)
|
||||
{ return !m_tab.insert (file).second; }
|
||||
|
||||
private:
|
||||
struct hash
|
||||
{
|
||||
std::size_t operator() (const char *s) const noexcept
|
||||
{ return filename_hash (s); }
|
||||
};
|
||||
|
||||
struct eq
|
||||
{
|
||||
bool operator() (const char *lhs, const char *rhs) const noexcept
|
||||
{ return filename_eq (lhs, rhs); }
|
||||
};
|
||||
|
||||
/* Table of files seen so far. */
|
||||
htab_up m_tab;
|
||||
gdb::unordered_set<const char *, hash, eq> m_tab;
|
||||
};
|
||||
|
||||
#endif /* FILENAME_SEEN_CACHE_H */
|
||||
|
||||
153
gdb/gdb_bfd.c
153
gdb/gdb_bfd.c
@@ -34,6 +34,7 @@
|
||||
#include "inferior.h"
|
||||
#include "cli/cli-style.h"
|
||||
#include <unordered_map>
|
||||
#include "gdbsupport/unordered_set.h"
|
||||
|
||||
#if CXX_STD_THREAD
|
||||
|
||||
@@ -80,12 +81,12 @@ struct gdb_bfd_section_data
|
||||
void *map_addr;
|
||||
};
|
||||
|
||||
/* A hash table holding every BFD that gdb knows about. This is not
|
||||
/* A hash set holding every BFD that gdb knows about. This is not
|
||||
to be confused with 'gdb_bfd_cache', which is used for sharing
|
||||
BFDs; in contrast, this hash is used just to implement
|
||||
"maint info bfd". */
|
||||
|
||||
static htab_t all_bfds;
|
||||
static gdb::unordered_set<bfd *> all_bfds;
|
||||
|
||||
/* An object of this type is stored in each BFD's user data. */
|
||||
|
||||
@@ -153,10 +154,6 @@ registry_accessor<bfd>::get (bfd *abfd)
|
||||
return &gdata->registry_fields;
|
||||
}
|
||||
|
||||
/* A hash table storing all the BFDs maintained in the cache. */
|
||||
|
||||
static htab_t gdb_bfd_cache;
|
||||
|
||||
/* When true gdb will reuse an existing bfd object if the filename,
|
||||
modification time, and file size all match. */
|
||||
|
||||
@@ -202,34 +199,39 @@ struct gdb_bfd_cache_search
|
||||
dev_t device_id;
|
||||
};
|
||||
|
||||
/* A hash function for BFDs. */
|
||||
|
||||
static hashval_t
|
||||
hash_bfd (const void *b)
|
||||
struct bfd_cache_hash
|
||||
{
|
||||
const bfd *abfd = (const struct bfd *) b;
|
||||
using is_transparent = void;
|
||||
|
||||
/* It is simplest to just hash the filename. */
|
||||
return htab_hash_string (bfd_get_filename (abfd));
|
||||
}
|
||||
std::size_t operator() (bfd *abfd) const noexcept
|
||||
{ return htab_hash_string (bfd_get_filename (abfd)); }
|
||||
|
||||
/* An equality function for BFDs. Note that this expects the caller
|
||||
to search using struct gdb_bfd_cache_search only, not BFDs. */
|
||||
std::size_t operator() (const gdb_bfd_cache_search &search) const noexcept
|
||||
{ return htab_hash_string (search.filename); }
|
||||
};
|
||||
|
||||
static int
|
||||
eq_bfd (const void *a, const void *b)
|
||||
struct bfd_cache_eq
|
||||
{
|
||||
const bfd *abfd = (const struct bfd *) a;
|
||||
const struct gdb_bfd_cache_search *s
|
||||
= (const struct gdb_bfd_cache_search *) b;
|
||||
struct gdb_bfd_data *gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd);
|
||||
using is_transparent = void;
|
||||
|
||||
return (gdata->mtime == s->mtime
|
||||
&& gdata->size == s->size
|
||||
&& gdata->inode == s->inode
|
||||
&& gdata->device_id == s->device_id
|
||||
&& strcmp (bfd_get_filename (abfd), s->filename) == 0);
|
||||
}
|
||||
bool operator() (bfd *lhs, bfd *rhs) const noexcept
|
||||
{ return lhs == rhs; }
|
||||
|
||||
bool operator() (const gdb_bfd_cache_search &s, bfd *abfd) const noexcept
|
||||
{
|
||||
auto gdata = static_cast<gdb_bfd_data *> (bfd_usrdata (abfd));
|
||||
|
||||
return (gdata->mtime == s.mtime
|
||||
&& gdata->size == s.size
|
||||
&& gdata->inode == s.inode
|
||||
&& gdata->device_id == s.device_id
|
||||
&& strcmp (bfd_get_filename (abfd), s.filename) == 0);
|
||||
}
|
||||
};
|
||||
|
||||
/* A hash set storing all the BFDs maintained in the cache. */
|
||||
|
||||
static gdb::unordered_set<bfd *, bfd_cache_hash, bfd_cache_eq> gdb_bfd_cache;
|
||||
|
||||
/* See gdb_bfd.h. */
|
||||
|
||||
@@ -482,7 +484,6 @@ static void
|
||||
gdb_bfd_init_data (struct bfd *abfd, struct stat *st)
|
||||
{
|
||||
struct gdb_bfd_data *gdata;
|
||||
void **slot;
|
||||
|
||||
gdb_assert (bfd_usrdata (abfd) == nullptr);
|
||||
|
||||
@@ -493,9 +494,8 @@ gdb_bfd_init_data (struct bfd *abfd, struct stat *st)
|
||||
bfd_set_usrdata (abfd, gdata);
|
||||
|
||||
/* This is the first we've seen it, so add it to the hash table. */
|
||||
slot = htab_find_slot (all_bfds, abfd, INSERT);
|
||||
gdb_assert (slot && !*slot);
|
||||
*slot = abfd;
|
||||
bool inserted = all_bfds.emplace (abfd).second;
|
||||
gdb_assert (inserted);
|
||||
}
|
||||
|
||||
/* See gdb_bfd.h. */
|
||||
@@ -504,8 +504,6 @@ gdb_bfd_ref_ptr
|
||||
gdb_bfd_open (const char *name, const char *target, int fd,
|
||||
bool warn_if_slow)
|
||||
{
|
||||
hashval_t hash;
|
||||
void **slot;
|
||||
bfd *abfd;
|
||||
struct gdb_bfd_cache_search search;
|
||||
struct stat st;
|
||||
@@ -532,10 +530,6 @@ gdb_bfd_open (const char *name, const char *target, int fd,
|
||||
std::lock_guard<std::recursive_mutex> guard (gdb_bfd_mutex);
|
||||
#endif
|
||||
|
||||
if (gdb_bfd_cache == NULL)
|
||||
gdb_bfd_cache = htab_create_alloc (1, hash_bfd, eq_bfd, NULL,
|
||||
xcalloc, xfree);
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
fd = gdb_open_cloexec (name, O_RDONLY | O_BINARY, 0).release ();
|
||||
@@ -562,19 +556,18 @@ gdb_bfd_open (const char *name, const char *target, int fd,
|
||||
search.inode = st.st_ino;
|
||||
search.device_id = st.st_dev;
|
||||
|
||||
/* Note that this must compute the same result as hash_bfd. */
|
||||
hash = htab_hash_string (name);
|
||||
/* Note that we cannot use htab_find_slot_with_hash here, because
|
||||
opening the BFD may fail; and this would violate hashtab
|
||||
invariants. */
|
||||
abfd = (struct bfd *) htab_find_with_hash (gdb_bfd_cache, &search, hash);
|
||||
if (bfd_sharing && abfd != NULL)
|
||||
if (bfd_sharing)
|
||||
{
|
||||
bfd_cache_debug_printf ("Reusing cached bfd %s for %s",
|
||||
host_address_to_string (abfd),
|
||||
bfd_get_filename (abfd));
|
||||
close (fd);
|
||||
return gdb_bfd_ref_ptr::new_reference (abfd);
|
||||
if (auto iter = gdb_bfd_cache.find (search);
|
||||
iter != gdb_bfd_cache.end ())
|
||||
{
|
||||
abfd = *iter;
|
||||
bfd_cache_debug_printf ("Reusing cached bfd %s for %s",
|
||||
host_address_to_string (abfd),
|
||||
bfd_get_filename (abfd));
|
||||
close (fd);
|
||||
return gdb_bfd_ref_ptr::new_reference (abfd);
|
||||
}
|
||||
}
|
||||
|
||||
abfd = bfd_fopen (name, target, FOPEN_RB, fd);
|
||||
@@ -589,9 +582,8 @@ gdb_bfd_open (const char *name, const char *target, int fd,
|
||||
|
||||
if (bfd_sharing)
|
||||
{
|
||||
slot = htab_find_slot_with_hash (gdb_bfd_cache, &search, hash, INSERT);
|
||||
gdb_assert (!*slot);
|
||||
*slot = abfd;
|
||||
bool inserted = gdb_bfd_cache.emplace (abfd).second;
|
||||
gdb_assert (inserted);
|
||||
}
|
||||
|
||||
/* It's important to pass the already-computed stat info here,
|
||||
@@ -686,7 +678,6 @@ void
|
||||
gdb_bfd_unref (struct bfd *abfd)
|
||||
{
|
||||
struct gdb_bfd_data *gdata;
|
||||
struct gdb_bfd_cache_search search;
|
||||
bfd *archive_bfd;
|
||||
|
||||
if (abfd == NULL)
|
||||
@@ -713,28 +704,14 @@ gdb_bfd_unref (struct bfd *abfd)
|
||||
bfd_get_filename (abfd));
|
||||
|
||||
archive_bfd = gdata->archive_bfd;
|
||||
search.filename = bfd_get_filename (abfd);
|
||||
|
||||
if (gdb_bfd_cache && search.filename)
|
||||
{
|
||||
hashval_t hash = htab_hash_string (search.filename);
|
||||
void **slot;
|
||||
|
||||
search.mtime = gdata->mtime;
|
||||
search.size = gdata->size;
|
||||
search.inode = gdata->inode;
|
||||
search.device_id = gdata->device_id;
|
||||
slot = htab_find_slot_with_hash (gdb_bfd_cache, &search, hash,
|
||||
NO_INSERT);
|
||||
|
||||
if (slot && *slot)
|
||||
htab_clear_slot (gdb_bfd_cache, slot);
|
||||
}
|
||||
if (bfd_get_filename (abfd) != nullptr)
|
||||
gdb_bfd_cache.erase (abfd);
|
||||
|
||||
delete gdata;
|
||||
bfd_set_usrdata (abfd, NULL); /* Paranoia. */
|
||||
|
||||
htab_remove_elt (all_bfds, abfd);
|
||||
all_bfds.erase (abfd);
|
||||
|
||||
gdb_bfd_close_or_warn (abfd);
|
||||
|
||||
@@ -1145,25 +1122,6 @@ gdb_bfd_errmsg (bfd_error_type error_tag, char **matching)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* A callback for htab_traverse that prints a single BFD. */
|
||||
|
||||
static int
|
||||
print_one_bfd (void **slot, void *data)
|
||||
{
|
||||
bfd *abfd = (struct bfd *) *slot;
|
||||
struct gdb_bfd_data *gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd);
|
||||
struct ui_out *uiout = (struct ui_out *) data;
|
||||
|
||||
ui_out_emit_tuple tuple_emitter (uiout, NULL);
|
||||
uiout->field_signed ("refcount", gdata->refc);
|
||||
uiout->field_string ("addr", host_address_to_string (abfd));
|
||||
uiout->field_string ("filename", bfd_get_filename (abfd),
|
||||
file_name_style.style ());
|
||||
uiout->text ("\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Implement the 'maint info bfd' command. */
|
||||
|
||||
static void
|
||||
@@ -1177,7 +1135,17 @@ maintenance_info_bfds (const char *arg, int from_tty)
|
||||
uiout->table_header (40, ui_left, "filename", "Filename");
|
||||
|
||||
uiout->table_body ();
|
||||
htab_traverse_noresize (all_bfds, print_one_bfd, uiout);
|
||||
|
||||
for (auto abfd : all_bfds)
|
||||
{
|
||||
auto gdata = static_cast<gdb_bfd_data *> (bfd_usrdata (abfd));
|
||||
ui_out_emit_tuple tuple_emitter (uiout, nullptr);
|
||||
uiout->field_signed ("refcount", gdata->refc);
|
||||
uiout->field_string ("addr", host_address_to_string (abfd));
|
||||
uiout->field_string ("filename", bfd_get_filename (abfd),
|
||||
file_name_style.style ());
|
||||
uiout->text ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* BFD related per-inferior data. */
|
||||
@@ -1272,9 +1240,6 @@ void _initialize_gdb_bfd ();
|
||||
void
|
||||
_initialize_gdb_bfd ()
|
||||
{
|
||||
all_bfds = htab_create_alloc (10, htab_hash_pointer, htab_eq_pointer,
|
||||
NULL, xcalloc, xfree);
|
||||
|
||||
add_cmd ("bfds", class_maintenance, maintenance_info_bfds, _("\
|
||||
List the BFDs that are currently open."),
|
||||
&maintenanceinfolist);
|
||||
|
||||
@@ -5372,46 +5372,6 @@ recursive_dump_type (struct type *type, int spaces)
|
||||
obstack_free (&dont_print_type_obstack, NULL);
|
||||
}
|
||||
|
||||
/* Trivial helpers for the libiberty hash table, for mapping one
|
||||
type to another. */
|
||||
|
||||
struct type_pair
|
||||
{
|
||||
type_pair (struct type *old_, struct type *newobj_)
|
||||
: old (old_), newobj (newobj_)
|
||||
{}
|
||||
|
||||
struct type * const old, * const newobj;
|
||||
};
|
||||
|
||||
static hashval_t
|
||||
type_pair_hash (const void *item)
|
||||
{
|
||||
const struct type_pair *pair = (const struct type_pair *) item;
|
||||
|
||||
return htab_hash_pointer (pair->old);
|
||||
}
|
||||
|
||||
static int
|
||||
type_pair_eq (const void *item_lhs, const void *item_rhs)
|
||||
{
|
||||
const struct type_pair *lhs = (const struct type_pair *) item_lhs;
|
||||
const struct type_pair *rhs = (const struct type_pair *) item_rhs;
|
||||
|
||||
return lhs->old == rhs->old;
|
||||
}
|
||||
|
||||
/* Allocate the hash table used by copy_type_recursive to walk
|
||||
types without duplicates. */
|
||||
|
||||
htab_up
|
||||
create_copied_types_hash ()
|
||||
{
|
||||
return htab_up (htab_create_alloc (1, type_pair_hash, type_pair_eq,
|
||||
htab_delete_entry<type_pair>,
|
||||
xcalloc, xfree));
|
||||
}
|
||||
|
||||
/* Recursively copy (deep copy) a dynamic attribute list of a type. */
|
||||
|
||||
static struct dynamic_prop_list *
|
||||
@@ -5443,27 +5403,20 @@ copy_dynamic_prop_list (struct obstack *storage,
|
||||
it is not associated with OBJFILE. */
|
||||
|
||||
struct type *
|
||||
copy_type_recursive (struct type *type, htab_t copied_types)
|
||||
copy_type_recursive (struct type *type, copied_types_hash_t &copied_types)
|
||||
{
|
||||
void **slot;
|
||||
struct type *new_type;
|
||||
|
||||
if (!type->is_objfile_owned ())
|
||||
return type;
|
||||
|
||||
struct type_pair pair (type, nullptr);
|
||||
if (auto iter = copied_types.find (type);
|
||||
iter != copied_types.end ())
|
||||
return iter->second;
|
||||
|
||||
slot = htab_find_slot (copied_types, &pair, INSERT);
|
||||
if (*slot != NULL)
|
||||
return ((struct type_pair *) *slot)->newobj;
|
||||
|
||||
new_type = type_allocator (type->arch ()).new_type ();
|
||||
struct type *new_type = type_allocator (type->arch ()).new_type ();
|
||||
|
||||
/* We must add the new type to the hash table immediately, in case
|
||||
we encounter this type again during a recursive call below. */
|
||||
struct type_pair *stored = new type_pair (type, new_type);
|
||||
|
||||
*slot = stored;
|
||||
copied_types.emplace (type, new_type);
|
||||
|
||||
/* Copy the common fields of types. For the main type, we simply
|
||||
copy the entire thing and then update specific fields as needed. */
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
written such that they can be used as both rvalues and lvalues.
|
||||
*/
|
||||
|
||||
#include "hashtab.h"
|
||||
#include "gdbsupport/array-view.h"
|
||||
#include "gdbsupport/gdb-hashtab.h"
|
||||
#include <optional>
|
||||
@@ -56,6 +55,7 @@
|
||||
#include "dwarf2.h"
|
||||
#include "gdbsupport/gdb_obstack.h"
|
||||
#include "gmp-utils.h"
|
||||
#include "gdbsupport/unordered_map.h"
|
||||
|
||||
/* Forward declarations for prototypes. */
|
||||
struct field;
|
||||
@@ -2789,10 +2789,10 @@ extern int class_or_union_p (const struct type *);
|
||||
|
||||
extern void maintenance_print_type (const char *, int);
|
||||
|
||||
extern htab_up create_copied_types_hash ();
|
||||
using copied_types_hash_t = gdb::unordered_map<type *, type *>;
|
||||
|
||||
extern struct type *copy_type_recursive (struct type *type,
|
||||
htab_t copied_types);
|
||||
copied_types_hash_t &copied_types);
|
||||
|
||||
extern struct type *copy_type (const struct type *type);
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "cli/cli-style.h"
|
||||
#include "dwarf2/loc.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbsupport/unordered_map.h"
|
||||
|
||||
static struct cp_abi_ops gnu_v3_abi_ops;
|
||||
|
||||
@@ -791,51 +792,32 @@ gnuv3_method_ptr_to_value (struct value **this_p, struct value *method_ptr)
|
||||
return value_from_pointer (lookup_pointer_type (method_type), ptr_value);
|
||||
}
|
||||
|
||||
/* Objects of this type are stored in a hash table and a vector when
|
||||
printing the vtables for a class. */
|
||||
|
||||
struct value_and_voffset
|
||||
struct vtable_value_hash_t
|
||||
{
|
||||
/* The value representing the object. */
|
||||
struct value *value;
|
||||
|
||||
/* The maximum vtable offset we've found for any object at this
|
||||
offset in the outermost object. */
|
||||
int max_voffset;
|
||||
std::size_t operator() (value *val) const noexcept
|
||||
{ return val->address () + val->embedded_offset (); }
|
||||
};
|
||||
|
||||
/* Hash function for value_and_voffset. */
|
||||
|
||||
static hashval_t
|
||||
hash_value_and_voffset (const void *p)
|
||||
struct vtable_value_eq_t
|
||||
{
|
||||
const struct value_and_voffset *o = (const struct value_and_voffset *) p;
|
||||
bool operator() (value *lhs, value *rhs) const noexcept
|
||||
{
|
||||
return (lhs->address () + lhs->embedded_offset ()
|
||||
== rhs->address () + rhs->embedded_offset ());
|
||||
}
|
||||
};
|
||||
|
||||
return o->value->address () + o->value->embedded_offset ();
|
||||
}
|
||||
using vtable_hash_t
|
||||
= gdb::unordered_map<value *, int, vtable_value_hash_t, vtable_value_eq_t>;
|
||||
|
||||
/* Equality function for value_and_voffset. */
|
||||
|
||||
static int
|
||||
eq_value_and_voffset (const void *a, const void *b)
|
||||
{
|
||||
const struct value_and_voffset *ova = (const struct value_and_voffset *) a;
|
||||
const struct value_and_voffset *ovb = (const struct value_and_voffset *) b;
|
||||
|
||||
return (ova->value->address () + ova->value->embedded_offset ()
|
||||
== ovb->value->address () + ovb->value->embedded_offset ());
|
||||
}
|
||||
|
||||
/* Comparison function for value_and_voffset. */
|
||||
/* Comparison function used for sorting the vtable entries. */
|
||||
|
||||
static bool
|
||||
compare_value_and_voffset (const struct value_and_voffset *va,
|
||||
const struct value_and_voffset *vb)
|
||||
compare_value_and_voffset (const std::pair<value *, int> &va,
|
||||
const std::pair<value *, int> &vb)
|
||||
{
|
||||
CORE_ADDR addra = (va->value->address ()
|
||||
+ va->value->embedded_offset ());
|
||||
CORE_ADDR addrb = (vb->value->address ()
|
||||
+ vb->value->embedded_offset ());
|
||||
CORE_ADDR addra = va.first->address () + va.first->embedded_offset ();
|
||||
CORE_ADDR addrb = vb.first->address () + vb.first->embedded_offset ();
|
||||
|
||||
return addra < addrb;
|
||||
}
|
||||
@@ -843,18 +825,14 @@ compare_value_and_voffset (const struct value_and_voffset *va,
|
||||
/* A helper function used when printing vtables. This determines the
|
||||
key (most derived) sub-object at each address and also computes the
|
||||
maximum vtable offset seen for the corresponding vtable. Updates
|
||||
OFFSET_HASH and OFFSET_VEC with a new value_and_voffset object, if
|
||||
needed. VALUE is the object to examine. */
|
||||
OFFSET_HASH with a new value_and_voffset object, if needed. VALUE
|
||||
is the object to examine. */
|
||||
|
||||
static void
|
||||
compute_vtable_size (htab_t offset_hash,
|
||||
std::vector<value_and_voffset *> *offset_vec,
|
||||
struct value *value)
|
||||
compute_vtable_size (vtable_hash_t &offset_hash, struct value *value)
|
||||
{
|
||||
int i;
|
||||
struct type *type = check_typedef (value->type ());
|
||||
void **slot;
|
||||
struct value_and_voffset search_vo, *current_vo;
|
||||
|
||||
gdb_assert (type->code () == TYPE_CODE_STRUCT);
|
||||
|
||||
@@ -864,18 +842,7 @@ compute_vtable_size (htab_t offset_hash,
|
||||
return;
|
||||
|
||||
/* Update the hash and the vec, if needed. */
|
||||
search_vo.value = value;
|
||||
slot = htab_find_slot (offset_hash, &search_vo, INSERT);
|
||||
if (*slot)
|
||||
current_vo = (struct value_and_voffset *) *slot;
|
||||
else
|
||||
{
|
||||
current_vo = XNEW (struct value_and_voffset);
|
||||
current_vo->value = value;
|
||||
current_vo->max_voffset = -1;
|
||||
*slot = current_vo;
|
||||
offset_vec->push_back (current_vo);
|
||||
}
|
||||
int ¤t_max_voffset = offset_hash.emplace (value, -1).first->second;
|
||||
|
||||
/* Update the value_and_voffset object with the highest vtable
|
||||
offset from this class. */
|
||||
@@ -890,15 +857,15 @@ compute_vtable_size (htab_t offset_hash,
|
||||
{
|
||||
int voffset = TYPE_FN_FIELD_VOFFSET (fn, j);
|
||||
|
||||
if (voffset > current_vo->max_voffset)
|
||||
current_vo->max_voffset = voffset;
|
||||
if (voffset > current_max_voffset)
|
||||
current_max_voffset = voffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Recurse into base classes. */
|
||||
for (i = 0; i < TYPE_N_BASECLASSES (type); ++i)
|
||||
compute_vtable_size (offset_hash, offset_vec, value_field (value, i));
|
||||
compute_vtable_size (offset_hash, value_field (value, i));
|
||||
}
|
||||
|
||||
/* Helper for gnuv3_print_vtable that prints a single vtable. */
|
||||
@@ -999,23 +966,22 @@ gnuv3_print_vtable (struct value *value)
|
||||
return;
|
||||
}
|
||||
|
||||
htab_up offset_hash (htab_create_alloc (1, hash_value_and_voffset,
|
||||
eq_value_and_voffset,
|
||||
xfree, xcalloc, xfree));
|
||||
std::vector<value_and_voffset *> result_vec;
|
||||
vtable_hash_t offset_hash;
|
||||
compute_vtable_size (offset_hash, value);
|
||||
|
||||
compute_vtable_size (offset_hash.get (), &result_vec, value);
|
||||
std::vector<std::pair<struct value *, int>> result_vec (offset_hash.begin (),
|
||||
offset_hash.end ());
|
||||
std::sort (result_vec.begin (), result_vec.end (),
|
||||
compare_value_and_voffset);
|
||||
|
||||
count = 0;
|
||||
for (value_and_voffset *iter : result_vec)
|
||||
for (auto &item : result_vec)
|
||||
{
|
||||
if (iter->max_voffset >= 0)
|
||||
if (item.second >= 0)
|
||||
{
|
||||
if (count > 0)
|
||||
gdb_printf ("\n");
|
||||
print_one_vtable (gdbarch, iter->value, iter->max_voffset, &opts);
|
||||
print_one_vtable (gdbarch, item.first, item.second, &opts);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -596,7 +596,7 @@ extern bool gdbscm_auto_load_enabled (const struct extension_language_defn *);
|
||||
|
||||
extern void gdbscm_preserve_values
|
||||
(const struct extension_language_defn *,
|
||||
struct objfile *, htab_t copied_types);
|
||||
struct objfile *, copied_types_hash_t &copied_types);
|
||||
|
||||
extern enum ext_lang_rc gdbscm_apply_val_pretty_printer
|
||||
(const struct extension_language_defn *,
|
||||
|
||||
@@ -94,8 +94,8 @@ struct tyscm_deleter
|
||||
return;
|
||||
|
||||
gdb_assert (htab != nullptr);
|
||||
htab_up copied_types = create_copied_types_hash ();
|
||||
htab_traverse_noresize (htab, tyscm_copy_type_recursive, copied_types.get ());
|
||||
copied_types_hash_t copied_types;
|
||||
htab_traverse_noresize (htab, tyscm_copy_type_recursive, &copied_types);
|
||||
htab_delete (htab);
|
||||
}
|
||||
};
|
||||
@@ -375,12 +375,11 @@ static int
|
||||
tyscm_copy_type_recursive (void **slot, void *info)
|
||||
{
|
||||
type_smob *t_smob = (type_smob *) *slot;
|
||||
htab_t copied_types = (htab_t) info;
|
||||
copied_types_hash_t &copied_types = *static_cast<copied_types_hash_t *> (info);
|
||||
htab_t htab;
|
||||
eqable_gdb_smob **new_slot;
|
||||
type_smob t_smob_for_lookup;
|
||||
|
||||
htab_empty (copied_types);
|
||||
t_smob->type = copy_type_recursive (t_smob->type, copied_types);
|
||||
|
||||
/* The eq?-hashtab that the type lived in is going away.
|
||||
|
||||
@@ -86,7 +86,8 @@ static SCM substitute_symbol;
|
||||
|
||||
void
|
||||
gdbscm_preserve_values (const struct extension_language_defn *extlang,
|
||||
struct objfile *objfile, htab_t copied_types)
|
||||
struct objfile *objfile,
|
||||
copied_types_hash_t &copied_types)
|
||||
{
|
||||
value_smob *iter;
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "gdbsupport/def-vector.h"
|
||||
#include <algorithm>
|
||||
#include "inferior.h"
|
||||
#include "gdbsupport/unordered_set.h"
|
||||
|
||||
/* An enumeration of the various things a user might attempt to
|
||||
complete for a linespec location. */
|
||||
@@ -3363,12 +3364,9 @@ namespace {
|
||||
class decode_compound_collector
|
||||
{
|
||||
public:
|
||||
decode_compound_collector ()
|
||||
: m_unique_syms (htab_create_alloc (1, htab_hash_pointer,
|
||||
htab_eq_pointer, NULL,
|
||||
xcalloc, xfree))
|
||||
{
|
||||
}
|
||||
decode_compound_collector () = default;
|
||||
|
||||
DISABLE_COPY_AND_ASSIGN (decode_compound_collector);
|
||||
|
||||
/* Return all symbols collected. */
|
||||
std::vector<block_symbol> release_symbols ()
|
||||
@@ -3382,7 +3380,7 @@ public:
|
||||
private:
|
||||
/* A hash table of all symbols we found. We use this to avoid
|
||||
adding any symbol more than once. */
|
||||
htab_up m_unique_syms;
|
||||
gdb::unordered_set<const symbol *> m_unique_syms;
|
||||
|
||||
/* The result vector. */
|
||||
std::vector<block_symbol> m_symbols;
|
||||
@@ -3391,7 +3389,6 @@ private:
|
||||
bool
|
||||
decode_compound_collector::operator () (block_symbol *bsym)
|
||||
{
|
||||
void **slot;
|
||||
struct type *t;
|
||||
struct symbol *sym = bsym->symbol;
|
||||
|
||||
@@ -3405,12 +3402,10 @@ decode_compound_collector::operator () (block_symbol *bsym)
|
||||
&& t->code () != TYPE_CODE_NAMESPACE)
|
||||
return true; /* Continue iterating. */
|
||||
|
||||
slot = htab_find_slot (m_unique_syms.get (), sym, INSERT);
|
||||
if (!*slot)
|
||||
{
|
||||
*slot = sym;
|
||||
m_symbols.push_back (*bsym);
|
||||
}
|
||||
bool inserted = m_unique_syms.insert (sym).second;
|
||||
|
||||
if (inserted)
|
||||
m_symbols.push_back (*bsym);
|
||||
|
||||
return true; /* Continue iterating. */
|
||||
}
|
||||
@@ -3634,14 +3629,20 @@ namespace {
|
||||
class symtab_collector
|
||||
{
|
||||
public:
|
||||
symtab_collector ()
|
||||
: m_symtab_table (htab_create (1, htab_hash_pointer, htab_eq_pointer,
|
||||
NULL))
|
||||
{
|
||||
}
|
||||
symtab_collector () = default;
|
||||
|
||||
DISABLE_COPY_AND_ASSIGN (symtab_collector);
|
||||
|
||||
/* Callable as a symbol_found_callback_ftype callback. */
|
||||
bool operator () (symtab *sym);
|
||||
bool operator () (struct symtab *symtab)
|
||||
{
|
||||
bool inserted = m_symtab_table.insert (symtab).second;
|
||||
|
||||
if (inserted)
|
||||
m_symtabs.push_back (symtab);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return an rvalue reference to the collected symtabs. */
|
||||
std::vector<symtab *> &&release_symtabs ()
|
||||
@@ -3654,24 +3655,9 @@ private:
|
||||
std::vector<symtab *> m_symtabs;
|
||||
|
||||
/* This is used to ensure the symtabs are unique. */
|
||||
htab_up m_symtab_table;
|
||||
gdb::unordered_set<const symtab *> m_symtab_table;
|
||||
};
|
||||
|
||||
bool
|
||||
symtab_collector::operator () (struct symtab *symtab)
|
||||
{
|
||||
void **slot;
|
||||
|
||||
slot = htab_find_slot (m_symtab_table.get (), symtab, INSERT);
|
||||
if (!*slot)
|
||||
{
|
||||
*slot = symtab;
|
||||
m_symtabs.push_back (symtab);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/* Given a file name, return a list of all matching symtabs. If
|
||||
|
||||
@@ -153,39 +153,6 @@ set_objfile_main_name (struct objfile *objfile,
|
||||
objfile->per_bfd->language_of_main = lang;
|
||||
}
|
||||
|
||||
/* Helper structure to map blocks to static link properties in hash tables. */
|
||||
|
||||
struct static_link_htab_entry
|
||||
{
|
||||
const struct block *block;
|
||||
const struct dynamic_prop *static_link;
|
||||
};
|
||||
|
||||
/* Return a hash code for struct static_link_htab_entry *P. */
|
||||
|
||||
static hashval_t
|
||||
static_link_htab_entry_hash (const void *p)
|
||||
{
|
||||
const struct static_link_htab_entry *e
|
||||
= (const struct static_link_htab_entry *) p;
|
||||
|
||||
return htab_hash_pointer (e->block);
|
||||
}
|
||||
|
||||
/* Return whether P1 an P2 (pointers to struct static_link_htab_entry) are
|
||||
mappings for the same block. */
|
||||
|
||||
static int
|
||||
static_link_htab_entry_eq (const void *p1, const void *p2)
|
||||
{
|
||||
const struct static_link_htab_entry *e1
|
||||
= (const struct static_link_htab_entry *) p1;
|
||||
const struct static_link_htab_entry *e2
|
||||
= (const struct static_link_htab_entry *) p2;
|
||||
|
||||
return e1->block == e2->block;
|
||||
}
|
||||
|
||||
/* Register STATIC_LINK as the static link for BLOCK, which is part of OBJFILE.
|
||||
Must not be called more than once for each BLOCK. */
|
||||
|
||||
@@ -194,25 +161,10 @@ objfile_register_static_link (struct objfile *objfile,
|
||||
const struct block *block,
|
||||
const struct dynamic_prop *static_link)
|
||||
{
|
||||
void **slot;
|
||||
struct static_link_htab_entry lookup_entry;
|
||||
struct static_link_htab_entry *entry;
|
||||
|
||||
if (objfile->static_links == NULL)
|
||||
objfile->static_links.reset (htab_create_alloc
|
||||
(1, &static_link_htab_entry_hash, static_link_htab_entry_eq, NULL,
|
||||
xcalloc, xfree));
|
||||
|
||||
/* Create a slot for the mapping, make sure it's the first mapping for this
|
||||
block and then create the mapping itself. */
|
||||
lookup_entry.block = block;
|
||||
slot = htab_find_slot (objfile->static_links.get (), &lookup_entry, INSERT);
|
||||
gdb_assert (*slot == NULL);
|
||||
|
||||
entry = XOBNEW (&objfile->objfile_obstack, static_link_htab_entry);
|
||||
entry->block = block;
|
||||
entry->static_link = static_link;
|
||||
*slot = (void *) entry;
|
||||
/* Enter the mapping and make sure it's the first mapping for this
|
||||
block. */
|
||||
bool inserted = objfile->static_links.emplace (block, static_link).second;
|
||||
gdb_assert (inserted);
|
||||
}
|
||||
|
||||
/* Look for a static link for BLOCK, which is part of OBJFILE. Return NULL if
|
||||
@@ -222,19 +174,11 @@ const struct dynamic_prop *
|
||||
objfile_lookup_static_link (struct objfile *objfile,
|
||||
const struct block *block)
|
||||
{
|
||||
struct static_link_htab_entry *entry;
|
||||
struct static_link_htab_entry lookup_entry;
|
||||
if (auto iter = objfile->static_links.find (block);
|
||||
iter != objfile->static_links.end ())
|
||||
return iter->second;
|
||||
|
||||
if (objfile->static_links == NULL)
|
||||
return NULL;
|
||||
lookup_entry.block = block;
|
||||
entry = ((struct static_link_htab_entry *)
|
||||
htab_find (objfile->static_links.get (), &lookup_entry));
|
||||
if (entry == NULL)
|
||||
return NULL;
|
||||
|
||||
gdb_assert (entry->block == block);
|
||||
return entry->static_link;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "jit.h"
|
||||
#include "quick-symbol.h"
|
||||
#include <forward_list>
|
||||
#include "gdbsupport/unordered_map.h"
|
||||
|
||||
struct htab;
|
||||
struct objfile_data;
|
||||
@@ -855,7 +856,8 @@ public:
|
||||
Very few blocks have a static link, so it's more memory efficient to
|
||||
store these here rather than in struct block. Static links must be
|
||||
allocated on the objfile's obstack. */
|
||||
htab_up static_links;
|
||||
gdb::unordered_map<const block *, const dynamic_prop *>
|
||||
static_links;
|
||||
|
||||
/* JIT-related data for this objfile, if the objfile is a JITer;
|
||||
that is, it produces JITed objfiles. */
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "gdbsupport/unordered_set.h"
|
||||
#include "objfiles.h"
|
||||
#include "symtab.h"
|
||||
#include "language.h"
|
||||
@@ -27,7 +28,6 @@
|
||||
#include "stack.h"
|
||||
#include "source.h"
|
||||
#include "annotate.h"
|
||||
#include "hashtab.h"
|
||||
#include "demangle.h"
|
||||
#include "mi/mi-cmds.h"
|
||||
#include "python-internal.h"
|
||||
@@ -731,25 +731,37 @@ py_print_args (PyObject *filter,
|
||||
return EXT_LANG_BT_OK;
|
||||
}
|
||||
|
||||
using levels_printed_hash = gdb::unordered_set<frame_info *>;
|
||||
|
||||
/* Print a single frame to the designated output stream, detecting
|
||||
whether the output is MI or console, and formatting the output
|
||||
according to the conventions of that protocol. FILTER is the
|
||||
frame-filter associated with this frame. FLAGS is an integer
|
||||
describing the various print options. The FLAGS variables is
|
||||
described in "apply_frame_filter" function. ARGS_TYPE is an
|
||||
enumerator describing the argument format. OUT is the output
|
||||
stream to print, INDENT is the level of indention for this frame
|
||||
(in the case of elided frames), and LEVELS_PRINTED is a hash-table
|
||||
containing all the frames level that have already been printed.
|
||||
If a frame level has been printed, do not print it again (in the
|
||||
case of elided frames). Returns EXT_LANG_BT_ERROR on error, with any
|
||||
GDB exceptions converted to a Python exception, or EXT_LANG_BT_OK
|
||||
on success. It can also throw an exception RETURN_QUIT. */
|
||||
according to the conventions of that protocol.
|
||||
|
||||
FILTER is the frame-filter associated with this frame.
|
||||
|
||||
FLAGS is an integer describing the various print options. The FLAGS
|
||||
variables is described in "apply_frame_filter" function.
|
||||
|
||||
ARGS_TYPE is an enumerator describing the argument format.
|
||||
|
||||
OUT is the output stream to print to.
|
||||
|
||||
INDENT is the level of indention for this frame (in the case of elided
|
||||
frames).
|
||||
|
||||
LEVELS_PRINTED is a hash-table containing all the frames for which the
|
||||
level has already been printed. If a level has been printed, do not print
|
||||
it again (in the case of elided frames).
|
||||
|
||||
Returns EXT_LANG_BT_ERROR on error, with any GDB exceptions converted to a
|
||||
Python exception, or EXT_LANG_BT_OK on success. It can also throw an
|
||||
exception RETURN_QUIT. */
|
||||
|
||||
static enum ext_lang_bt_status
|
||||
py_print_frame (PyObject *filter, frame_filter_flags flags,
|
||||
enum ext_lang_frame_args args_type,
|
||||
struct ui_out *out, int indent, htab_t levels_printed)
|
||||
struct ui_out *out, int indent,
|
||||
levels_printed_hash &levels_printed)
|
||||
{
|
||||
int has_addr = 0;
|
||||
CORE_ADDR address = 0;
|
||||
@@ -859,23 +871,18 @@ py_print_frame (PyObject *filter, frame_filter_flags flags,
|
||||
&& (location_print
|
||||
|| (out->is_mi_like_p () && (print_frame_info || print_args))))
|
||||
{
|
||||
struct frame_info **slot;
|
||||
int level;
|
||||
|
||||
slot = (frame_info **) htab_find_slot (levels_printed,
|
||||
frame.get(), INSERT);
|
||||
|
||||
level = frame_relative_level (frame);
|
||||
|
||||
/* Check if this frame has already been printed (there are cases
|
||||
where elided synthetic dummy-frames have to 'borrow' the frame
|
||||
architecture from the eliding frame. If that is the case, do
|
||||
not print 'level', but print spaces. */
|
||||
if (*slot == frame)
|
||||
not print the level, but print spaces. */
|
||||
bool inserted = levels_printed.insert (frame.get ()).second;
|
||||
|
||||
if (!inserted)
|
||||
out->field_skip ("level");
|
||||
else
|
||||
{
|
||||
*slot = frame.get ();
|
||||
int level = frame_relative_level (frame);
|
||||
|
||||
annotate_frame_begin (print_level ? level : 0,
|
||||
gdbarch, address);
|
||||
out->text ("#");
|
||||
@@ -1197,10 +1204,7 @@ gdbpy_apply_frame_filter (const struct extension_language_defn *extlang,
|
||||
if (iterable == Py_None)
|
||||
return EXT_LANG_BT_NO_FILTERS;
|
||||
|
||||
htab_up levels_printed (htab_create (20,
|
||||
htab_hash_pointer,
|
||||
htab_eq_pointer,
|
||||
NULL));
|
||||
levels_printed_hash levels_printed;
|
||||
|
||||
while (true)
|
||||
{
|
||||
@@ -1232,7 +1236,7 @@ gdbpy_apply_frame_filter (const struct extension_language_defn *extlang,
|
||||
try
|
||||
{
|
||||
success = py_print_frame (item.get (), flags, args_type, out, 0,
|
||||
levels_printed.get ());
|
||||
levels_printed);
|
||||
}
|
||||
catch (const gdb_exception_error &except)
|
||||
{
|
||||
|
||||
@@ -1174,15 +1174,13 @@ struct typy_deleter
|
||||
operating on. */
|
||||
gdbpy_enter enter_py;
|
||||
|
||||
htab_up copied_types = create_copied_types_hash ();
|
||||
copied_types_hash_t copied_types;
|
||||
|
||||
while (obj)
|
||||
{
|
||||
type_object *next = obj->next;
|
||||
|
||||
htab_empty (copied_types.get ());
|
||||
|
||||
obj->type = copy_type_recursive (obj->type, copied_types.get ());
|
||||
obj->type = copy_type_recursive (obj->type, copied_types);
|
||||
|
||||
obj->next = NULL;
|
||||
obj->prev = NULL;
|
||||
|
||||
@@ -233,7 +233,8 @@ valpy_init (PyObject *self, PyObject *args, PyObject *kwds)
|
||||
each. */
|
||||
void
|
||||
gdbpy_preserve_values (const struct extension_language_defn *extlang,
|
||||
struct objfile *objfile, htab_t copied_types)
|
||||
struct objfile *objfile,
|
||||
copied_types_hash_t &copied_types)
|
||||
{
|
||||
value_object *iter;
|
||||
|
||||
|
||||
@@ -474,7 +474,7 @@ extern enum ext_lang_bt_status gdbpy_apply_frame_filter
|
||||
struct ui_out *out, int frame_low, int frame_high);
|
||||
extern void gdbpy_preserve_values (const struct extension_language_defn *,
|
||||
struct objfile *objfile,
|
||||
htab_t copied_types);
|
||||
copied_types_hash_t &copied_types);
|
||||
extern enum ext_lang_bp_stop gdbpy_breakpoint_cond_says_stop
|
||||
(const struct extension_language_defn *, struct breakpoint *);
|
||||
extern int gdbpy_breakpoint_has_cond (const struct extension_language_defn *,
|
||||
|
||||
@@ -2537,7 +2537,7 @@ reread_symbols (int from_tty)
|
||||
objfile->sect_index_text = -1;
|
||||
objfile->compunit_symtabs = NULL;
|
||||
objfile->template_symbols = NULL;
|
||||
objfile->static_links.reset (nullptr);
|
||||
objfile->static_links.clear ();
|
||||
|
||||
/* obstack_init also initializes the obstack so it is
|
||||
empty. We could use obstack_specify_allocation but
|
||||
|
||||
30
gdb/symtab.c
30
gdb/symtab.c
@@ -396,17 +396,10 @@ linetable_entry::pc (const struct objfile *objfile) const
|
||||
call_site *
|
||||
compunit_symtab::find_call_site (CORE_ADDR pc) const
|
||||
{
|
||||
if (m_call_site_htab == nullptr)
|
||||
return nullptr;
|
||||
|
||||
CORE_ADDR delta = this->objfile ()->text_section_offset ();
|
||||
unrelocated_addr unrelocated_pc = (unrelocated_addr) (pc - delta);
|
||||
|
||||
struct call_site call_site_local (unrelocated_pc, nullptr, nullptr);
|
||||
void **slot
|
||||
= htab_find_slot (m_call_site_htab, &call_site_local, NO_INSERT);
|
||||
if (slot != nullptr)
|
||||
return (call_site *) *slot;
|
||||
auto it = m_call_site_htab->find (static_cast<unrelocated_addr> (pc - delta));
|
||||
if (it != m_call_site_htab->end ())
|
||||
return it->second;
|
||||
|
||||
/* See if the arch knows another PC we should try. On some
|
||||
platforms, GCC emits a DWARF call site that is offset from the
|
||||
@@ -416,22 +409,20 @@ compunit_symtab::find_call_site (CORE_ADDR pc) const
|
||||
if (pc == new_pc)
|
||||
return nullptr;
|
||||
|
||||
unrelocated_pc = (unrelocated_addr) (new_pc - delta);
|
||||
call_site new_call_site_local (unrelocated_pc, nullptr, nullptr);
|
||||
slot = htab_find_slot (m_call_site_htab, &new_call_site_local, NO_INSERT);
|
||||
if (slot == nullptr)
|
||||
return nullptr;
|
||||
it = m_call_site_htab->find (static_cast<unrelocated_addr> (new_pc - delta));
|
||||
if (it != m_call_site_htab->end ())
|
||||
return it->second;
|
||||
|
||||
return (call_site *) *slot;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* See symtab.h. */
|
||||
|
||||
void
|
||||
compunit_symtab::set_call_site_htab (htab_up call_site_htab)
|
||||
compunit_symtab::set_call_site_htab (call_site_htab_t &&call_site_htab)
|
||||
{
|
||||
gdb_assert (m_call_site_htab == nullptr);
|
||||
m_call_site_htab = call_site_htab.release ();
|
||||
m_call_site_htab = new call_site_htab_t (std::move (call_site_htab));
|
||||
}
|
||||
|
||||
/* See symtab.h. */
|
||||
@@ -500,8 +491,7 @@ void
|
||||
compunit_symtab::finalize ()
|
||||
{
|
||||
this->forget_cached_source_info ();
|
||||
if (m_call_site_htab != nullptr)
|
||||
htab_delete (m_call_site_htab);
|
||||
delete m_call_site_htab;
|
||||
}
|
||||
|
||||
/* The relocated address of the minimal symbol, using the section
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include "dwarf2/call-site.h"
|
||||
#include "gdbsupport/gdb_vecs.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "gdbsupport/gdb_obstack.h"
|
||||
@@ -1957,7 +1958,7 @@ struct compunit_symtab
|
||||
symtab *primary_filetab () const;
|
||||
|
||||
/* Set m_call_site_htab. */
|
||||
void set_call_site_htab (htab_up call_site_htab);
|
||||
void set_call_site_htab (call_site_htab_t &&call_site_htab);
|
||||
|
||||
/* Find call_site info for PC. */
|
||||
call_site *find_call_site (CORE_ADDR pc) const;
|
||||
@@ -2024,7 +2025,7 @@ struct compunit_symtab
|
||||
unsigned int m_epilogue_unwind_valid : 1;
|
||||
|
||||
/* struct call_site entries for this compilation unit or NULL. */
|
||||
htab_t m_call_site_htab;
|
||||
call_site_htab_t *m_call_site_htab;
|
||||
|
||||
/* The macro table for this symtab. Like the blockvector, this
|
||||
is shared between different symtabs in a given compilation unit.
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "arch-utils.h"
|
||||
#include "cli/cli-cmds.h"
|
||||
#include "gdbsupport/unordered_set.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "reggroups.h"
|
||||
#include "target.h"
|
||||
@@ -30,7 +31,6 @@
|
||||
#include "osabi.h"
|
||||
|
||||
#include "gdbsupport/gdb_obstack.h"
|
||||
#include "hashtab.h"
|
||||
#include "inferior.h"
|
||||
#include <algorithm>
|
||||
#include "completer.h"
|
||||
@@ -1042,16 +1042,12 @@ tdesc_use_registers (struct gdbarch *gdbarch,
|
||||
data->arch_regs = std::move (early_data->arch_regs);
|
||||
|
||||
/* Build up a set of all registers, so that we can assign register
|
||||
numbers where needed. The hash table expands as necessary, so
|
||||
the initial size is arbitrary. */
|
||||
htab_up reg_hash (htab_create (37, htab_hash_pointer, htab_eq_pointer,
|
||||
NULL));
|
||||
numbers where needed. */
|
||||
gdb::unordered_set<tdesc_reg *> reg_hash;
|
||||
for (const tdesc_feature_up &feature : target_desc->features)
|
||||
for (const tdesc_reg_up ® : feature->registers)
|
||||
{
|
||||
void **slot = htab_find_slot (reg_hash.get (), reg.get (), INSERT);
|
||||
|
||||
*slot = reg.get ();
|
||||
reg_hash.insert (reg.get ());
|
||||
/* Add reggroup if its new. */
|
||||
if (!reg->group.empty ())
|
||||
if (reggroup_find (gdbarch, reg->group.c_str ()) == NULL)
|
||||
@@ -1064,7 +1060,7 @@ tdesc_use_registers (struct gdbarch *gdbarch,
|
||||
architecture. */
|
||||
for (const tdesc_arch_reg &arch_reg : data->arch_regs)
|
||||
if (arch_reg.reg != NULL)
|
||||
htab_remove_elt (reg_hash.get (), arch_reg.reg);
|
||||
reg_hash.erase (arch_reg.reg);
|
||||
|
||||
/* Assign numbers to the remaining registers and add them to the
|
||||
list of registers. The new numbers are always above gdbarch_num_regs.
|
||||
@@ -1082,7 +1078,7 @@ tdesc_use_registers (struct gdbarch *gdbarch,
|
||||
{
|
||||
for (const tdesc_feature_up &feature : target_desc->features)
|
||||
for (const tdesc_reg_up ® : feature->registers)
|
||||
if (htab_find (reg_hash.get (), reg.get ()) != NULL)
|
||||
if (reg_hash.contains (reg.get ()))
|
||||
{
|
||||
int regno = unk_reg_cb (gdbarch, feature.get (),
|
||||
reg->name.c_str (), num_regs);
|
||||
@@ -1093,7 +1089,7 @@ tdesc_use_registers (struct gdbarch *gdbarch,
|
||||
data->arch_regs.emplace_back (nullptr, nullptr);
|
||||
data->arch_regs[regno] = tdesc_arch_reg (reg.get (), NULL);
|
||||
num_regs = regno + 1;
|
||||
htab_remove_elt (reg_hash.get (), reg.get ());
|
||||
reg_hash.erase (reg.get ());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1105,7 +1101,7 @@ tdesc_use_registers (struct gdbarch *gdbarch,
|
||||
unnumbered registers. */
|
||||
for (const tdesc_feature_up &feature : target_desc->features)
|
||||
for (const tdesc_reg_up ® : feature->registers)
|
||||
if (htab_find (reg_hash.get (), reg.get ()) != NULL)
|
||||
if (reg_hash.contains (reg.get ()))
|
||||
{
|
||||
data->arch_regs.emplace_back (reg.get (), nullptr);
|
||||
num_regs++;
|
||||
|
||||
@@ -78,10 +78,18 @@ proc do_check_holder {name {flags ""} {show_typedefs 1} {show_methods 1}
|
||||
proc do_check_typedef_holder {name {flags ""} {show_typedefs 1} {show_methods 1}
|
||||
{raw 0}} {
|
||||
|
||||
set contents {
|
||||
{ field public "double a;" }
|
||||
{ field public "ns::scoped_double b;" }
|
||||
{ field public "global_double c;" }
|
||||
if {$raw} {
|
||||
set contents {
|
||||
{ field public "double a;" }
|
||||
{ field public "ns::scoped_double b;" }
|
||||
{ field public "global_double c;" }
|
||||
}
|
||||
} else {
|
||||
set contents {
|
||||
{ field public "class_double a;" }
|
||||
{ field public "class_double b;" }
|
||||
{ field public "class_double c;" }
|
||||
}
|
||||
}
|
||||
|
||||
if {$show_typedefs} {
|
||||
@@ -89,8 +97,13 @@ proc do_check_typedef_holder {name {flags ""} {show_typedefs 1} {show_methods 1}
|
||||
}
|
||||
|
||||
if {$show_methods} {
|
||||
lappend contents { method private "double method1(ns::scoped_double);" }
|
||||
lappend contents { method private "double method2(global_double);" }
|
||||
if {$raw} {
|
||||
lappend contents { method private "double method1(ns::scoped_double);" }
|
||||
lappend contents { method private "double method2(global_double);" }
|
||||
} else {
|
||||
lappend contents { method private "class_double method1(class_double);" }
|
||||
lappend contents { method private "class_double method2(class_double);" }
|
||||
}
|
||||
}
|
||||
|
||||
if {$raw} {
|
||||
|
||||
@@ -261,7 +261,8 @@ proc test_python_helper {} {
|
||||
}
|
||||
|
||||
# Test the htab_t pretty-printer.
|
||||
gdb_test -prompt $outer_prompt_re "print all_bfds" "htab_t with ${::decimal} elements = \\{${::hex}.*\\}"
|
||||
gdb_test -prompt $outer_prompt_re "print varobj_table" \
|
||||
"htab_t with ${::decimal} elements"
|
||||
|
||||
# Test the intrusive_list pretty-printer. A bug occured in the
|
||||
# pretty-printer for lists with more than one element. Verify that
|
||||
|
||||
108
gdb/typeprint.c
108
gdb/typeprint.c
@@ -194,49 +194,19 @@ print_offset_data::finish (struct type *type, int level,
|
||||
|
||||
|
||||
|
||||
/* A hash function for a typedef_field. */
|
||||
|
||||
static hashval_t
|
||||
hash_typedef_field (const void *p)
|
||||
{
|
||||
const struct decl_field *tf = (const struct decl_field *) p;
|
||||
|
||||
return htab_hash_string (TYPE_SAFE_NAME (tf->type));
|
||||
}
|
||||
|
||||
/* An equality function for a typedef field. */
|
||||
|
||||
static int
|
||||
eq_typedef_field (const void *a, const void *b)
|
||||
{
|
||||
const struct decl_field *tfa = (const struct decl_field *) a;
|
||||
const struct decl_field *tfb = (const struct decl_field *) b;
|
||||
|
||||
return types_equal (tfa->type, tfb->type);
|
||||
}
|
||||
|
||||
/* See typeprint.h. */
|
||||
|
||||
void
|
||||
typedef_hash_table::recursively_update (struct type *t)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (t); ++i)
|
||||
for (int i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (t); ++i)
|
||||
{
|
||||
struct decl_field *tdef = &TYPE_TYPEDEF_FIELD (t, i);
|
||||
void **slot;
|
||||
|
||||
slot = htab_find_slot (m_table.get (), tdef, INSERT);
|
||||
/* Only add a given typedef name once. Really this shouldn't
|
||||
happen; but it is safe enough to do the updates breadth-first
|
||||
and thus use the most specific typedef. */
|
||||
if (*slot == NULL)
|
||||
*slot = tdef;
|
||||
decl_field *child_type = &TYPE_TYPEDEF_FIELD (t, i);
|
||||
m_table.emplace (child_type->type, child_type);
|
||||
}
|
||||
|
||||
/* Recurse into superclasses. */
|
||||
for (i = 0; i < TYPE_N_BASECLASSES (t); ++i)
|
||||
for (int i = 0; i < TYPE_N_BASECLASSES (t); ++i)
|
||||
recursively_update (TYPE_BASECLASS (t, i));
|
||||
}
|
||||
|
||||
@@ -250,7 +220,6 @@ typedef_hash_table::add_template_parameters (struct type *t)
|
||||
for (i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (t); ++i)
|
||||
{
|
||||
struct decl_field *tf;
|
||||
void **slot;
|
||||
|
||||
/* We only want type-valued template parameters in the hash. */
|
||||
if (TYPE_TEMPLATE_ARGUMENT (t, i)->aclass () != LOC_TYPEDEF)
|
||||
@@ -260,45 +229,10 @@ typedef_hash_table::add_template_parameters (struct type *t)
|
||||
tf->name = TYPE_TEMPLATE_ARGUMENT (t, i)->linkage_name ();
|
||||
tf->type = TYPE_TEMPLATE_ARGUMENT (t, i)->type ();
|
||||
|
||||
slot = htab_find_slot (m_table.get (), tf, INSERT);
|
||||
if (*slot == NULL)
|
||||
*slot = tf;
|
||||
m_table.emplace (tf->type, tf);
|
||||
}
|
||||
}
|
||||
|
||||
/* See typeprint.h. */
|
||||
|
||||
typedef_hash_table::typedef_hash_table ()
|
||||
: m_table (htab_create_alloc (10, hash_typedef_field, eq_typedef_field,
|
||||
NULL, xcalloc, xfree))
|
||||
{
|
||||
}
|
||||
|
||||
/* Helper function for typedef_hash_table::copy. */
|
||||
|
||||
static int
|
||||
copy_typedef_hash_element (void **slot, void *nt)
|
||||
{
|
||||
htab_t new_table = (htab_t) nt;
|
||||
void **new_slot;
|
||||
|
||||
new_slot = htab_find_slot (new_table, *slot, INSERT);
|
||||
if (*new_slot == NULL)
|
||||
*new_slot = *slot;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* See typeprint.h. */
|
||||
|
||||
typedef_hash_table::typedef_hash_table (const typedef_hash_table &table)
|
||||
{
|
||||
m_table.reset (htab_create_alloc (10, hash_typedef_field, eq_typedef_field,
|
||||
NULL, xcalloc, xfree));
|
||||
htab_traverse_noresize (table.m_table.get (), copy_typedef_hash_element,
|
||||
m_table.get ());
|
||||
}
|
||||
|
||||
/* Look up the type T in the global typedef hash. If it is found,
|
||||
return the typedef name. If it is not found, apply the
|
||||
type-printers, if any, given by start_script_type_printers and return the
|
||||
@@ -308,29 +242,21 @@ const char *
|
||||
typedef_hash_table::find_global_typedef (const struct type_print_options *flags,
|
||||
struct type *t)
|
||||
{
|
||||
void **slot;
|
||||
struct decl_field tf, *new_tf;
|
||||
|
||||
if (flags->global_typedefs == NULL)
|
||||
return NULL;
|
||||
|
||||
tf.name = NULL;
|
||||
tf.type = t;
|
||||
|
||||
slot = htab_find_slot (flags->global_typedefs->m_table.get (), &tf, INSERT);
|
||||
if (*slot != NULL)
|
||||
{
|
||||
new_tf = (struct decl_field *) *slot;
|
||||
return new_tf->name;
|
||||
}
|
||||
if (auto it = flags->global_typedefs->m_table.find (t);
|
||||
it != flags->global_typedefs->m_table.end ())
|
||||
return it->second->name;
|
||||
|
||||
/* Put an entry into the hash table now, in case
|
||||
apply_ext_lang_type_printers recurses. */
|
||||
new_tf = XOBNEW (&flags->global_typedefs->m_storage, struct decl_field);
|
||||
decl_field *new_tf
|
||||
= XOBNEW (&flags->global_typedefs->m_storage, struct decl_field);
|
||||
new_tf->name = NULL;
|
||||
new_tf->type = t;
|
||||
|
||||
*slot = new_tf;
|
||||
flags->global_typedefs->m_table.emplace (new_tf->type, new_tf);
|
||||
|
||||
gdb::unique_xmalloc_ptr<char> applied
|
||||
= apply_ext_lang_type_printers (flags->global_printers, t);
|
||||
@@ -350,15 +276,9 @@ typedef_hash_table::find_typedef (const struct type_print_options *flags,
|
||||
{
|
||||
if (flags->local_typedefs != NULL)
|
||||
{
|
||||
struct decl_field tf, *found;
|
||||
|
||||
tf.name = NULL;
|
||||
tf.type = t;
|
||||
htab_t table = flags->local_typedefs->m_table.get ();
|
||||
found = (struct decl_field *) htab_find (table, &tf);
|
||||
|
||||
if (found != NULL)
|
||||
return found->name;
|
||||
if (auto iter = flags->local_typedefs->m_table.find (t);
|
||||
iter != flags->local_typedefs->m_table.end ())
|
||||
return iter->second->name;
|
||||
}
|
||||
|
||||
return find_global_typedef (flags, t);
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#define TYPEPRINT_H
|
||||
|
||||
#include "gdbsupport/gdb_obstack.h"
|
||||
#include "gdbsupport/unordered_set.h"
|
||||
#include "gdbtypes.h"
|
||||
|
||||
enum language;
|
||||
struct ui_file;
|
||||
@@ -123,10 +125,12 @@ class typedef_hash_table
|
||||
public:
|
||||
|
||||
/* Create a new typedef-lookup hash table. */
|
||||
typedef_hash_table ();
|
||||
typedef_hash_table () = default;
|
||||
|
||||
/* Copy a typedef hash. */
|
||||
typedef_hash_table (const typedef_hash_table &);
|
||||
typedef_hash_table (const typedef_hash_table &other)
|
||||
: m_table (other.m_table)
|
||||
{}
|
||||
|
||||
typedef_hash_table &operator= (const typedef_hash_table &) = delete;
|
||||
|
||||
@@ -149,9 +153,24 @@ private:
|
||||
static const char *find_global_typedef (const struct type_print_options *flags,
|
||||
struct type *t);
|
||||
|
||||
struct hash
|
||||
{
|
||||
std::size_t operator() (type *type) const noexcept
|
||||
{
|
||||
/* Use check_typedef: the hash must agree with equals, and types_equal
|
||||
strips typedefs. */
|
||||
return htab_hash_string (TYPE_SAFE_NAME (check_typedef (type)));
|
||||
}
|
||||
};
|
||||
|
||||
struct eq
|
||||
{
|
||||
bool operator() (type *lhs, type *rhs) const noexcept
|
||||
{ return types_equal (lhs, rhs); }
|
||||
};
|
||||
|
||||
/* The actual hash table. */
|
||||
htab_up m_table;
|
||||
gdb::unordered_map<type *, decl_field *, hash, eq> m_table;
|
||||
|
||||
/* Storage for typedef_field objects that must be synthesized. */
|
||||
auto_obstack m_storage;
|
||||
|
||||
17
gdb/value.c
17
gdb/value.c
@@ -2468,7 +2468,7 @@ add_internal_function (gdb::unique_xmalloc_ptr<char> &&name,
|
||||
}
|
||||
|
||||
void
|
||||
value::preserve (struct objfile *objfile, htab_t copied_types)
|
||||
value::preserve (struct objfile *objfile, copied_types_hash_t &copied_types)
|
||||
{
|
||||
if (m_type->objfile_owner () == objfile)
|
||||
m_type = copy_type_recursive (m_type, copied_types);
|
||||
@@ -2481,7 +2481,7 @@ value::preserve (struct objfile *objfile, htab_t copied_types)
|
||||
|
||||
static void
|
||||
preserve_one_internalvar (struct internalvar *var, struct objfile *objfile,
|
||||
htab_t copied_types)
|
||||
copied_types_hash_t &copied_types)
|
||||
{
|
||||
switch (var->kind)
|
||||
{
|
||||
@@ -2504,7 +2504,7 @@ preserve_one_internalvar (struct internalvar *var, struct objfile *objfile,
|
||||
|
||||
static void
|
||||
preserve_one_varobj (struct varobj *varobj, struct objfile *objfile,
|
||||
htab_t copied_types)
|
||||
copied_types_hash_t &copied_types)
|
||||
{
|
||||
if (varobj->type->is_objfile_owned ()
|
||||
&& varobj->type->objfile_owner () == objfile)
|
||||
@@ -2528,22 +2528,21 @@ preserve_values (struct objfile *objfile)
|
||||
{
|
||||
/* Create the hash table. We allocate on the objfile's obstack, since
|
||||
it is soon to be deleted. */
|
||||
htab_up copied_types = create_copied_types_hash ();
|
||||
copied_types_hash_t copied_types;
|
||||
|
||||
for (const value_ref_ptr &item : value_history)
|
||||
item->preserve (objfile, copied_types.get ());
|
||||
item->preserve (objfile, copied_types);
|
||||
|
||||
for (auto &pair : internalvars)
|
||||
preserve_one_internalvar (&pair.second, objfile, copied_types.get ());
|
||||
preserve_one_internalvar (&pair.second, objfile, copied_types);
|
||||
|
||||
/* For the remaining varobj, check that none has type owned by OBJFILE. */
|
||||
all_root_varobjs ([&copied_types, objfile] (struct varobj *varobj)
|
||||
{
|
||||
preserve_one_varobj (varobj, objfile,
|
||||
copied_types.get ());
|
||||
preserve_one_varobj (varobj, objfile, copied_types);
|
||||
});
|
||||
|
||||
preserve_ext_lang_values (objfile, copied_types.get ());
|
||||
preserve_ext_lang_values (objfile, copied_types);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
#include "extension.h"
|
||||
#include "gdbsupport/gdb_ref_ptr.h"
|
||||
#include "gmp-utils.h"
|
||||
#include "gdbtypes.h"
|
||||
|
||||
struct block;
|
||||
struct expression;
|
||||
struct regcache;
|
||||
struct symbol;
|
||||
struct type;
|
||||
struct ui_file;
|
||||
struct language_defn;
|
||||
struct value_print_options;
|
||||
@@ -593,7 +593,7 @@ public:
|
||||
|
||||
/* Update this value before discarding OBJFILE. COPIED_TYPES is
|
||||
used to prevent cycles / duplicates. */
|
||||
void preserve (struct objfile *objfile, htab_t copied_types);
|
||||
void preserve (struct objfile *objfile, copied_types_hash_t &copied_types);
|
||||
|
||||
/* Unpack a bitfield of BITSIZE bits found at BITPOS in the object
|
||||
at VALADDR + EMBEDDEDOFFSET that has the type of DEST_VAL and
|
||||
|
||||
2032
gdbsupport/unordered_dense.h
Normal file
2032
gdbsupport/unordered_dense.h
Normal file
File diff suppressed because it is too large
Load Diff
37
gdbsupport/unordered_map.h
Normal file
37
gdbsupport/unordered_map.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef GDBSUPPORT_UNORDERED_MAP_H
|
||||
#define GDBSUPPORT_UNORDERED_MAP_H
|
||||
|
||||
#include "unordered_dense.h"
|
||||
|
||||
namespace gdb
|
||||
{
|
||||
|
||||
template<typename Key,
|
||||
typename T,
|
||||
typename Hash = ankerl::unordered_dense::hash<Key>,
|
||||
typename KeyEqual = std::equal_to<Key>>
|
||||
using unordered_map
|
||||
= ankerl::unordered_dense::map
|
||||
<Key, T, Hash, KeyEqual, std::allocator<std::pair<Key, T>>,
|
||||
ankerl::unordered_dense::bucket_type::standard>;
|
||||
|
||||
} /* namespace gdb */
|
||||
|
||||
#endif /* GDBSUPPORT_UNORDERED_MAP_H */
|
||||
36
gdbsupport/unordered_set.h
Normal file
36
gdbsupport/unordered_set.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/* Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef GDBSUPPORT_UNORDERED_SET_H
|
||||
#define GDBSUPPORT_UNORDERED_SET_H
|
||||
|
||||
#include "unordered_dense.h"
|
||||
|
||||
namespace gdb
|
||||
{
|
||||
|
||||
template<typename Key,
|
||||
typename Hash = ankerl::unordered_dense::hash<Key>,
|
||||
typename KeyEqual = std::equal_to<Key>>
|
||||
using unordered_set
|
||||
= ankerl::unordered_dense::set
|
||||
<Key, Hash, KeyEqual, std::allocator<Key>,
|
||||
ankerl::unordered_dense::bucket_type::standard>;
|
||||
|
||||
} /* namespace gdb */
|
||||
|
||||
#endif /* GDBSUPPORT_UNORDERED_SET_H */
|
||||
Reference in New Issue
Block a user