* [PATCH v2 2/5] DWARF-5: .debug_names index producer
2017-06-18 19:32 [PATCH v2 0/5] DWARF-5: .debug_names index Jan Kratochvil
2017-06-18 19:32 ` [PATCH v2 4/5] Refactor: Move some generic code out of .gdb_index code Jan Kratochvil
2017-06-18 19:32 ` [PATCH v2 3/5] Code cleanup: dwarf2_initialize_objfile return value Jan Kratochvil
@ 2017-06-18 19:32 ` Jan Kratochvil
2017-06-18 19:32 ` [PATCH v2 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh Jan Kratochvil
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Jan Kratochvil @ 2017-06-18 19:32 UTC (permalink / raw)
To: gdb-patches; +Cc: Victor Leschuk
Hi,
there are two FIXME lines I do not have a real answer for.
Also I am not sure if the -dwarf-4 option for former .gdb_index should be named
that way. And contrib/gdb-add-index.sh (incl. cc-with-tweaks.sh) has no
commandline option for that -dwarf-4 GDB option.
Jan
gdb/ChangeLog
2017-05-26 Jan Kratochvil <jan.kratochvil@redhat.com>
* contrib/gdb-add-index.sh (index): Rename to ...
(index4): ... here.
(index5, debugstr, debugstrmerge, debugstrerr): New variables.
Support also .debug_names and .debug_str.
* dwarf2read.c: Include cmath, locale, set, list.
(INDEX_SUFFIX): Rename to ...
(INDEX4_SUFFIX): ... here.
(INDEX5_SUFFIX, DEBUG_STR_SUFFIX): New.
(data_buf::append_unsigned_leb128, data_buf::empty)
(data_buf::operator const char *, debug_names, check_dwarf64_offsets): New.
(write_gdbindex): New from write_psymtabs_to_index code.
(write_debug_names): New.
(write_psymtabs_to_index): New parameter is_dwarf5. Support
filename_str and out_file_str. Move code to write_gdbindex, possibly
call write_debug_names.
(save_gdb_index_command): New parameter -dwarf-4.
(_initialize_dwarf2_read): Document the new parameter -dwarf-4.
gdb/doc/ChangeLog
2017-05-26 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.texinfo (Index Files): Document .debug_names and -dwarf-4.
(Index Section Format): Mention .debug_names.
---
gdb/contrib/gdb-add-index.sh | 53 ++-
gdb/doc/gdb.texinfo | 22 +
gdb/dwarf2read.c | 803 +++++++++++++++++++++++++++++++++++++++++-
3 files changed, 841 insertions(+), 37 deletions(-)
diff --git a/gdb/contrib/gdb-add-index.sh b/gdb/contrib/gdb-add-index.sh
index 0cd4ce3..02b17f0 100755
--- a/gdb/contrib/gdb-add-index.sh
+++ b/gdb/contrib/gdb-add-index.sh
@@ -37,11 +37,15 @@ fi
dir="${file%/*}"
test "$dir" = "$file" && dir="."
-index="${file}.gdb-index"
+index4="${file}.gdb-index"
+index5="${file}.debug_names"
+debugstr="${file}.debug_str"
+debugstrmerge="${file}.debug_str.merge"
+debugstrerr="${file}.debug_str.err"
-rm -f $index
+rm -f $index4 $index5 $debugstr $debugstrmerge $debugstrerr
# Ensure intermediate index file is removed when we exit.
-trap "rm -f $index" 0
+trap "rm -f $index4 $index5 $debugstr $debugstrmerge $debugstrerr" 0
$GDB --batch -nx -iex 'set auto-load no' \
-ex "file $file" -ex "save gdb-index $dir" || {
@@ -57,9 +61,46 @@ $GDB --batch -nx -iex 'set auto-load no' \
# already stripped binary, it's a no-op.
status=0
-if test -f "$index"; then
- $OBJCOPY --add-section .gdb_index="$index" \
- --set-section-flags .gdb_index=readonly "$file" "$file"
+if test -f "$index4" -a -f "$index5"; then
+ echo "$myname: Both index types were created for $file" 1>&2
+ status=1
+elif test -f "$index4" -o -f "$index5"; then
+ if test -f "$index4"; then
+ index="$index4"
+ section=".gdb_index"
+ else
+ index="$index5"
+ section=".debug_names"
+ fi
+ debugstradd=false
+ debugstrupdate=false
+ if test -s "$debugstr"; then
+ if ! $OBJCOPY --dump-section .debug_str="$debugstrmerge" "$file" /dev/null \
+ 2>$debugstrerr; then
+ cat >&2 $debugstrerr
+ exit 1
+ fi
+ if grep -q "can't dump section '.debug_str' - it does not exist" \
+ $debugstrerr; then
+ debugstradd=true
+ else
+ debugstrupdate=true
+ cat >&2 $debugstrerr
+ fi
+ cat "$debugstr" >>"$debugstrmerge"
+ fi
+
+ $OBJCOPY --add-section $section="$index" \
+ --set-section-flags $section=readonly \
+ $(if $debugstradd; then \
+ echo --add-section .debug_str="$debugstrmerge"; \
+ echo --set-section-flags .debug_str=readonly; \
+ fi; \
+ if $debugstrupdate; then \
+ echo --update-section .debug_str="$debugstrmerge"; \
+ fi) \
+ "$file" "$file"
+
status=$?
else
echo "$myname: No index was created for $file" 1>&2
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c167a86..573c51b 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -19244,18 +19244,29 @@ using @command{objcopy}.
To create an index file, use the @code{save gdb-index} command:
@table @code
-@item save gdb-index @var{directory}
+@item save gdb-index [-dwarf-4] @var{directory}
@kindex save gdb-index
Create an index file for each symbol file currently known by
@value{GDBN}. Each file is named after its corresponding symbol file,
-with @samp{.gdb-index} appended, and is written into the given
-@var{directory}.
+with @samp{.debug_names} and @samp{.str} (or @samp{.gdb-index}
+from @code{-dwarf-4} option for older index consumers) appended, and is written
+into the given @var{directory}.
@end table
Once you have created an index file you can merge it into your symbol
file, here named @file{symfile}, using @command{objcopy}:
@smallexample
+$ objcopy --dump-section .debug_str=symfile.str.new symfile
+$ cat symfile.str >>symfile.str.new
+$ objcopy --add-section .debug_names=symfile.gdb-index \
+ --set-section-flags .debug_names=readonly \
+ --update-section .debug_str=symfile.str.new symfile symfile
+@end smallexample
+
+Or for @code{-dwarf-4}:
+
+@smallexample
$ objcopy --add-section .gdb_index=symfile.gdb-index \
--set-section-flags .gdb_index=readonly symfile symfile
@end smallexample
@@ -41702,7 +41713,10 @@ of blocks.
@cindex index section format
This section documents the index section that is created by @code{save
-gdb-index} (@pxref{Index Files}). The index section is
+gdb-index -dwarf-4} (@pxref{Index Files}). Currently preferred section is
+@code{.debug_names} as produced by the default @code{save gdb-index} command.
+@code{.debug_names} section is documented in official @code{DWARF-5}
+specification outside of this @value{GDBN} manual. The index section is
DWARF-specific; some knowledge of DWARF is assumed in this
description.
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index abe14b2..2b7990f 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -80,6 +80,10 @@
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
+#include <cmath>
+#include <locale>
+#include <set>
+#include <forward_list>
typedef struct symbol *symbolp;
DEF_VEC_P (symbolp);
@@ -2183,7 +2187,9 @@ attr_value_as_address (struct attribute *attr)
}
/* The suffix for an index file. */
-#define INDEX_SUFFIX ".gdb-index"
+#define INDEX4_SUFFIX ".gdb-index"
+#define INDEX5_SUFFIX ".debug_names"
+#define DEBUG_STR_SUFFIX ".debug_str"
/* Try to locate the sections we need for DWARF 2 debugging
information and return true if we have enough to do something.
@@ -23217,6 +23223,21 @@ public:
std::copy (cstr, cstr + size, grow (size));
}
+ /* Store INPUT as ULEB128 to the end of buffer. */
+ void append_unsigned_leb128 (ULONGEST input)
+ {
+ for (;;)
+ {
+ gdb_byte output (input & 0x7f);
+ input >>= 7;
+ if (input)
+ output |= 0x80;
+ append_data (output);
+ if (!input)
+ break;
+ }
+ }
+
/* Accept a host-format integer in VAL and append it to the buffer
as a target-format integer which is LEN bytes long. */
void append_uint (size_t len, bfd_endian byte_order, ULONGEST val)
@@ -23230,6 +23251,12 @@ public:
return m_vec.size ();
}
+ /* Return true iff the buffer has size zero. */
+ bool empty () const
+ {
+ return m_vec.empty ();
+ }
+
/* Write the buffer to FILE. */
void file_write (FILE *file) const
{
@@ -23383,6 +23410,12 @@ public:
return strcmp (m_cstr, other.m_cstr) == 0;
}
+ /* Returned string is only a reference with lifetime of this object. */
+ operator const char * () const
+ {
+ return m_cstr;
+ }
+
private:
friend class c_str_view_hasher;
const char *const m_cstr;
@@ -23751,34 +23784,572 @@ private:
FILE *m_file;
};
-/* Create an index file for OBJFILE in the directory DIR. */
-
-static void
-write_psymtabs_to_index (struct objfile *objfile, const char *dir)
+/* DWARF-5 .debug_names builder. */
+class debug_names
{
- if (dwarf2_per_objfile->using_index)
- error (_("Cannot use an index to create the index"));
+public:
+ debug_names (bool is_dwarf64, bfd_endian dwarf5_byte_order_)
+ : m_dwarf5_byte_order (dwarf5_byte_order_), m_dwarf32 (dwarf5_byte_order_),
+ m_dwarf64 (dwarf5_byte_order_),
+ m_dwarf (is_dwarf64 ? static_cast<dwarf &> (m_dwarf64)
+ : static_cast<dwarf &> (m_dwarf32)),
+ m_name_table_string_offs (m_dwarf.name_table_string_offs),
+ m_name_table_entry_offs (m_dwarf.name_table_entry_offs)
+ {
+ }
- if (VEC_length (dwarf2_section_info_def, dwarf2_per_objfile->types) > 1)
- error (_("Cannot make an index when the file has multiple .debug_types sections"));
+ /* Insert one symbol. */
+ void insert (const partial_symbol *psym, int cu_index, bool is_static)
+ {
+ const int dwarf_tag (psymbol_tag (psym));
+ if (!dwarf_tag)
+ return;
+ const char *const name (SYMBOL_SEARCH_NAME (psym));
+ const auto insertpair (m_name_to_value_set.emplace (c_str_view (name),
+ std::set<symbol_value> ()));
+ std::set<symbol_value> &value_set (insertpair.first->second);
+ value_set.emplace (symbol_value (dwarf_tag, cu_index, is_static));
+ }
- if (!objfile->psymtabs || !objfile->psymtabs_addrmap)
- return;
+ /* Build all the tables. All symbols must be already inserted.
+ This function does not call file_write, caller has to do it
+ afterwards. */
+ void build ()
+ {
+ /* Verify the build method has not be called twice. */
+ gdb_assert (m_abbrev_table.empty ());
+ const size_t name_count (m_name_to_value_set.size ());
+ m_bucket_table.resize
+ (std::pow (2, std::ceil (std::log2 (name_count * 4 / 3))));
+ m_hash_table.reserve (name_count);
+ m_name_table_string_offs.reserve (name_count);
+ m_name_table_entry_offs.reserve (name_count);
+
+ /* Map each hash of symbol to its name and value. */
+ class hash_it_pair
+ {
+ public:
+ uint32_t hash;
+ decltype (m_name_to_value_set)::const_iterator it;
+ };
+ std::vector<std::forward_list<hash_it_pair>> bucket_hash;
+ bucket_hash.resize (m_bucket_table.size ());
+ for (decltype (m_name_to_value_set)::const_iterator it =
+ m_name_to_value_set.cbegin ();
+ it != m_name_to_value_set.cend (); ++it)
+ {
+ const char *const name (it->first);
+ const unsigned char *const nameuc
+ (reinterpret_cast<const unsigned char *> (name));
+ const uint32_t hash (djb_hash (nameuc));
+ hash_it_pair hashitpair;
+ hashitpair.hash = hash;
+ hashitpair.it = it;
+ bucket_hash[hash % bucket_hash.size()].push_front
+ (std::move (hashitpair));
+ }
+ for (size_t bucket_ix = 0; bucket_ix < bucket_hash.size (); ++bucket_ix)
+ {
+ const std::forward_list<hash_it_pair> &hashitlist
+ (bucket_hash[bucket_ix]);
+ if (hashitlist.empty ())
+ continue;
+ uint32_t &bucket_slot (m_bucket_table[bucket_ix]);
+ /* The hashes array is indexed starting at 1. */
+ store_unsigned_integer (reinterpret_cast<gdb_byte *> (&bucket_slot),
+ sizeof (bucket_slot), m_dwarf5_byte_order,
+ m_hash_table.size () + 1);
+ for (const hash_it_pair &hashitpair : hashitlist)
+ {
+ m_hash_table.push_back (0);
+ store_unsigned_integer (reinterpret_cast<gdb_byte *>
+ (&m_hash_table.back ()),
+ sizeof (m_hash_table.back ()),
+ m_dwarf5_byte_order, hashitpair.hash);
+ const c_str_view &name (hashitpair.it->first);
+ const std::set<symbol_value> &value_set (hashitpair.it->second);
+ m_name_table_string_offs.push_back_reorder
+ (m_debugstrlookup.lookup (name));
+ m_name_table_entry_offs.push_back_reorder (m_entry_pool.size ());
+ gdb_assert (!value_set.empty ());
+ for (const symbol_value &value : value_set)
+ {
+ int &idx (m_indexkey_to_idx[index_key (value.dwarf_tag,
+ value.is_static)]);
+ if (!idx) {
+ idx = m_idx_next++;
+ m_abbrev_table.append_unsigned_leb128 (idx);
+ m_abbrev_table.append_unsigned_leb128 (value.dwarf_tag);
+ m_abbrev_table.append_unsigned_leb128 (DW_IDX_compile_unit);
+ m_abbrev_table.append_unsigned_leb128 (DW_FORM_udata);
+ m_abbrev_table.append_unsigned_leb128 (value.is_static
+ ? DW_IDX_GNU_static
+ : DW_IDX_GNU_external);
+ m_abbrev_table.append_unsigned_leb128 (DW_FORM_flag_present);
+
+ /* Terminate attributes list. */
+ m_abbrev_table.append_unsigned_leb128 (0);
+ m_abbrev_table.append_unsigned_leb128 (0);
+ }
- struct stat st;
- if (stat (objfile_name (objfile), &st) < 0)
- perror_with_name (objfile_name (objfile));
+ m_entry_pool.append_unsigned_leb128 (idx);
+ m_entry_pool.append_unsigned_leb128 (value.cu_index);
+ }
- std::string filename (std::string (dir) + SLASH_STRING
- + lbasename (objfile_name (objfile)) + INDEX_SUFFIX);
+ /* Terminate the list of CUs. */
+ m_entry_pool.append_unsigned_leb128 (0);
+ }
+ }
+ gdb_assert (m_hash_table.size () == name_count);
- FILE *out_file = gdb_fopen_cloexec (filename.c_str (), "wb");
- if (!out_file)
- error (_("Can't open `%s' for writing"), filename.c_str ());
+ /* Terminate tags list. */
+ m_abbrev_table.append_unsigned_leb128 (0);
+ }
- file_closer close_out_file (out_file);
- gdb::unlinker unlink_file (filename.c_str ());
+ /* Return .debug_names bucket count.
+ It must be called only after calling build method. */
+ uint32_t bucket_count () const
+ {
+ /* Verify the build method has been already called. */
+ gdb_assert (!m_abbrev_table.empty ());
+ const uint32_t retval (m_bucket_table.size ());
+
+ /* Check for overflow; to use boost::numeric_cast. */
+ gdb_assert (retval == m_bucket_table.size ());
+ return retval;
+ }
+
+ /* Return .debug_names names count.
+ It must be called only after calling build method. */
+ uint32_t name_count () const
+ {
+ /* Verify the build method has been already called. */
+ gdb_assert (!m_abbrev_table.empty ());
+ const uint32_t retval (m_hash_table.size ());
+
+ /* Check for overflow; to use boost::numeric_cast. */
+ gdb_assert (retval == m_hash_table.size ());
+ return retval;
+ }
+
+ /* Return number of bytes of .debug_names abbreviation table.
+ It must be called only after calling build method. */
+ uint32_t abbrev_table_bytes () const
+ {
+ gdb_assert (!m_abbrev_table.empty ());
+ return m_abbrev_table.size ();
+ }
+
+ /* Recurse into all "included" dependencies and store their symbols as
+ if they appeared in this psymtab. */
+ void recursively_write_psymbols (struct objfile *objfile,
+ struct partial_symtab *psymtab,
+ std::unordered_set<partial_symbol *> &psyms_seen,
+ int cu_index)
+ {
+ int i;
+
+ for (i = 0; i < psymtab->number_of_dependencies; ++i)
+ if (psymtab->dependencies[i]->user != NULL)
+ recursively_write_psymbols (objfile, psymtab->dependencies[i],
+ psyms_seen, cu_index);
+
+ write_psymbols (psyms_seen,
+ objfile->global_psymbols.list + psymtab->globals_offset,
+ psymtab->n_global_syms, cu_index, false);
+ write_psymbols (psyms_seen,
+ objfile->static_psymbols.list + psymtab->statics_offset,
+ psymtab->n_static_syms, cu_index, true);
+ }
+
+ /* Return number of bytes the .debug_names section will have.
+ It must be called only after calling build method. */
+ size_t bytes () const
+ {
+ /* Verify the build method has been already called. */
+ gdb_assert (!m_abbrev_table.empty ());
+ size_t expected_bytes (0);
+ expected_bytes += m_bucket_table.size () * sizeof (m_bucket_table[0]);
+ expected_bytes += m_hash_table.size () * sizeof (m_hash_table[0]);
+ expected_bytes += m_name_table_string_offs.bytes ();
+ expected_bytes += m_name_table_entry_offs.bytes ();
+ expected_bytes += m_abbrev_table.size ();
+ expected_bytes += m_entry_pool.size ();
+ return expected_bytes;
+ }
+
+ /* Write .debug_names to FILE and .debug_str addition to FILE_STR.
+ It must be called only after calling build method. */
+ void file_write (FILE *file, FILE *file_str) const
+ {
+ /* Verify the build method has been already called. */
+ gdb_assert (!m_abbrev_table.empty ());
+ if (::fwrite (m_bucket_table.data (), sizeof (m_bucket_table[0]),
+ m_bucket_table.size (), file)
+ != m_bucket_table.size ())
+ error (_("couldn't write data to file"));
+ if (::fwrite (m_hash_table.data (), sizeof (m_hash_table[0]),
+ m_hash_table.size (), file)
+ != m_hash_table.size ())
+ error (_("couldn't write data to file"));
+ m_name_table_string_offs.file_write (file);
+ m_name_table_entry_offs.file_write (file);
+ m_abbrev_table.file_write (file);
+ m_entry_pool.file_write (file);
+ m_debugstrlookup.file_write (file_str);
+ }
+
+private:
+
+ /* Storage for symbol names mapping them to their .debug_str section
+ offsets. */
+ class debug_str_lookup
+ {
+ public:
+
+ /* Object costructor to be called for current DWARF2_PER_OBJFILE.
+ All .debug_str section strings are automatically stored. */
+ debug_str_lookup () : m_abfd (dwarf2_per_objfile->objfile->obfd)
+ {
+ dwarf2_read_section (dwarf2_per_objfile->objfile,
+ &dwarf2_per_objfile->str);
+ if (dwarf2_per_objfile->str.buffer == NULL)
+ return;
+ for (const gdb_byte *data = dwarf2_per_objfile->str.buffer;
+ data < (dwarf2_per_objfile->str.buffer
+ + dwarf2_per_objfile->str.size);)
+ {
+ const char *const s (reinterpret_cast<const char *> (data));
+ const auto insertpair
+ (m_str_table.emplace (c_str_view (s),
+ data - dwarf2_per_objfile->str.buffer));
+ if (!insertpair.second)
+ complaint (&symfile_complaints,
+ _("Duplicate string \"%s\" in "
+ ".debug_str section [in module %s]"),
+ s, bfd_get_filename (m_abfd));
+ data += strlen (s) + 1;
+ }
+ }
+
+ /* Return offset of symbol name S in .debug_str section. Add such
+ symbol to the section end if it does not exist there yet. */
+ size_t lookup (const char *s)
+ {
+ const auto it (m_str_table.find (c_str_view (s)));
+ if (it != m_str_table.end ())
+ return it->second;
+ const size_t offset (dwarf2_per_objfile->str.size
+ + m_str_add_buf.size ());
+ m_str_table.emplace (c_str_view (s), offset);
+ m_str_add_buf.append_cstr0 (s);
+ return offset;
+ }
+
+ /* Write appended end of .debug_str section to FILE. */
+ void file_write (FILE *file) const
+ {
+ m_str_add_buf.file_write (file);
+ }
+
+ private:
+ std::unordered_map<c_str_view, size_t, c_str_view_hasher> m_str_table;
+ bfd *const m_abfd;
+
+ /* Data to add at the end of .debug_str for new needed symbol names. */
+ data_buf m_str_add_buf;
+ };
+
+ /* Container to map used DWARF tags to their .debug_names abbreviation
+ tags. */
+ class index_key
+ {
+ public:
+ index_key (int dwarf_tag_, bool is_static_)
+ : dwarf_tag (dwarf_tag_), is_static (is_static_)
+ {
+ }
+ bool
+ operator == (const index_key &other) const
+ {
+ return dwarf_tag == other.dwarf_tag && is_static == other.is_static;
+ }
+ const int dwarf_tag;
+ const bool is_static;
+ };
+
+ /* Provide std::unordered_map::hasher for index_key. */
+ class index_key_hasher
+ {
+ public:
+ size_t
+ operator () (const index_key &key) const
+ {
+ return (std::hash<int>() (key.dwarf_tag) << 1) | key.is_static;
+ }
+ };
+
+ /* Parameters of one symbol entry. */
+ class symbol_value
+ {
+ public:
+ const int dwarf_tag, cu_index;
+ const bool is_static;
+ symbol_value (int dwarf_tag_, int cu_index_, bool is_static_)
+ : dwarf_tag (dwarf_tag_), cu_index (cu_index_), is_static (is_static_)
+ {
+ }
+ bool
+ operator < (const symbol_value &other) const
+ {
+#define X(n) \
+ do \
+ { \
+ if (n < other.n) \
+ return true; \
+ if (n > other.n) \
+ return false; \
+ } \
+ while (0)
+ X (dwarf_tag);
+ X (is_static);
+ X (cu_index);
+#undef X
+ return false;
+ }
+ };
+
+ /* Abstract base class to unify DWARF-32 and DWARF-64 name table output. */
+ class offset_vec
+ {
+ protected:
+ const bfd_endian dwarf5_byte_order;
+ public:
+ offset_vec (bfd_endian dwarf5_byte_order_)
+ : dwarf5_byte_order (dwarf5_byte_order_)
+ {
+ }
+
+ /* Call std::vector::reserve for NELEM elements. */
+ virtual void reserve (size_t nelem) = 0;
+
+ /* Call std::vector::push_back with store_unsigned_integer byte
+ reordering for ELEM. */
+ virtual void push_back_reorder (size_t elem) = 0;
+
+ /* Return expected output size in bytes. */
+ virtual size_t bytes () const = 0;
+
+ /* Write name table to FILE. */
+ virtual void file_write (FILE *file) const = 0;
+ };
+
+ /* Template to unify DWARF-32 and DWARF-64 output. */
+ template<class OffsetSize> class offset_vec_tmpl : public offset_vec
+ {
+ public:
+ offset_vec_tmpl (bfd_endian dwarf5_byte_order_)
+ : offset_vec (dwarf5_byte_order_)
+ {
+ }
+
+ /* Implement offset_vec::reserve. */
+ virtual void
+ reserve (size_t nelem) override
+ {
+ m_vec.reserve (nelem);
+ }
+
+ /* Implement offset_vec::push_back_reorder. */
+ virtual void
+ push_back_reorder (size_t elem) override
+ {
+ m_vec.push_back (elem);
+ /* Check for overflow. */
+ gdb_assert (m_vec.back () == elem);
+ store_unsigned_integer (reinterpret_cast<gdb_byte *> (&m_vec.back ()),
+ sizeof (m_vec.back ()), dwarf5_byte_order, elem);
+ }
+
+ /* Implement offset_vec::bytes. */
+ virtual size_t
+ bytes () const override
+ {
+ return m_vec.size () * sizeof (m_vec[0]);
+ }
+
+ /* Implement offset_vec::file_write. */
+ virtual void
+ file_write (FILE *file) const override
+ {
+ if (::fwrite (m_vec.data (), sizeof (m_vec[0]), m_vec.size (), file)
+ != m_vec.size ())
+ error (_("couldn't write data to file"));
+ }
+
+ private:
+ std::vector<OffsetSize> m_vec;
+ };
+
+ /* Base class to unify DWARF-32 and DWARF-64 .debug_names output
+ respecting name table width. */
+ class dwarf
+ {
+ public:
+ offset_vec &name_table_string_offs, &name_table_entry_offs;
+ dwarf (offset_vec &name_table_string_offs_,
+ offset_vec &name_table_entry_offs_)
+ : name_table_string_offs (name_table_string_offs_),
+ name_table_entry_offs (name_table_entry_offs_)
+ {
+ }
+ };
+
+ /* Template to unify DWARF-32 and DWARF-64 .debug_names output
+ respecting name table width. */
+ template<class OffsetSize> class dwarf_tmpl : public dwarf
+ {
+ public:
+ dwarf_tmpl (bfd_endian dwarf5_byte_order_)
+ : dwarf (m_name_table_string_offs, m_name_table_entry_offs),
+ m_name_table_string_offs (dwarf5_byte_order_),
+ m_name_table_entry_offs (dwarf5_byte_order_)
+ {
+ }
+ private:
+ offset_vec_tmpl<OffsetSize> m_name_table_string_offs,
+ m_name_table_entry_offs;
+ };
+
+ /* Symbol name hashing function as specified by DWARF-5. */
+ static uint32_t djb_hash (const unsigned char *str)
+ {
+ uint32_t hash = 5381;
+ while (int c = *str++)
+ {
+ /* FIXME: std::bad_cast for: std::tolower (c, std::locale::classic ())
+ FIXME: Is unicode supported for symbol names by GDB? */
+ hash = hash * 33 + tolower (c);
+ }
+ return hash;
+ }
+
+ /* Try to reconstruct original DWARF tag for given partial_symbol.
+ This function is not DWARF-5 compliant but it is sufficient for GDB
+ as a DWARF-5 index consumer. */
+ static int psymbol_tag (const struct partial_symbol *psym)
+ {
+ domain_enum domain = PSYMBOL_DOMAIN (psym);
+ enum address_class aclass = PSYMBOL_CLASS (psym);
+
+ switch (domain)
+ {
+ case VAR_DOMAIN:
+ switch (aclass)
+ {
+ case LOC_BLOCK:
+ return DW_TAG_subprogram;
+ case LOC_TYPEDEF:
+ return DW_TAG_typedef;
+ case LOC_COMPUTED:
+ case LOC_CONST_BYTES:
+ case LOC_OPTIMIZED_OUT:
+ case LOC_STATIC:
+ return DW_TAG_variable;
+ case LOC_CONST:
+ /* Note: It's currently impossible to recognize psyms as enum values
+ short of reading the type info. For now punt. */
+ return DW_TAG_variable;
+ default:
+ /* There are other LOC_FOO values that one might want to classify
+ as variables, but dwarf2read.c doesn't currently use them. */
+ return DW_TAG_variable;
+ }
+ case STRUCT_DOMAIN:
+ return DW_TAG_structure_type;
+ default:
+ return 0;
+ }
+ }
+
+ /* Call insert for all partial symbols and mark them in PSYMS_SEEN. */
+ void write_psymbols (std::unordered_set<partial_symbol *> &psyms_seen,
+ struct partial_symbol **psymp, int count, int cu_index,
+ bool is_static)
+ {
+ for (; count-- > 0; ++psymp)
+ {
+ struct partial_symbol *psym = *psymp;
+
+ if (SYMBOL_LANGUAGE (psym) == language_ada)
+ error (_("Ada is not currently supported by the index"));
+
+ /* Only add a given psymbol once. */
+ if (psyms_seen.insert (psym).second)
+ insert (psym, cu_index, is_static);
+ }
+ }
+
+ /* Store value of each symbol. */
+ std::unordered_map<c_str_view, std::set<symbol_value>, c_str_view_hasher>
+ m_name_to_value_set;
+
+ /* Tables of DWARF-5 .debug_names. They are in object file byte order. */
+ std::vector<uint32_t> m_bucket_table;
+ std::vector<uint32_t> m_hash_table;
+ const bfd_endian m_dwarf5_byte_order;
+ dwarf_tmpl<uint32_t> m_dwarf32;
+ dwarf_tmpl<uint64_t> m_dwarf64;
+ dwarf &m_dwarf;
+ offset_vec &m_name_table_string_offs, &m_name_table_entry_offs;
+ debug_str_lookup m_debugstrlookup;
+
+ /* Map each used .debug_names abbreviation tag parameters to its index
+ value. */
+ std::unordered_map<index_key, int, index_key_hasher> m_indexkey_to_idx;
+
+ /* Next unused .debug_names abbreviation tag for m_indexkey_to_idx. */
+ int m_idx_next = 1;
+
+ /* .debug_names abbreviation table. */
+ data_buf m_abbrev_table;
+
+ /* .debug_names entry pool. */
+ data_buf m_entry_pool;
+};
+
+/* Return iff any of the needed offsets does not fit into 32-bit
+ .debug_names section. */
+
+static bool
+check_dwarf64_offsets ()
+{
+ for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ {
+ const dwarf2_per_cu_data &per_cu (*dwarf2_per_objfile->all_comp_units[i]);
+
+ if (to_underlying (per_cu.sect_off) >= (static_cast<uint64_t> (1) << 32))
+ return true;
+ }
+ for (int i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
+ {
+ const signatured_type &sigtype (*dwarf2_per_objfile->all_type_units[i]);
+ const dwarf2_per_cu_data &per_cu (sigtype.per_cu);
+
+ if (to_underlying (per_cu.sect_off) >= (static_cast<uint64_t> (1) << 32))
+ return true;
+ }
+ return false;
+}
+
+/* Write new .gdb_index section for OBJFILE into OUT_FILE.
+ OUT_FILE_STR is unused.
+ Return how many bytes were expected to be written into OUT_FILE. */
+
+static size_t
+write_gdbindex (struct objfile *objfile, FILE *out_file, FILE *out_file_str)
+{
mapped_symtab symtab;
data_buf cu_list;
@@ -23896,8 +24467,172 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
symtab_vec.file_write (out_file);
constant_pool.file_write (out_file);
- /* We want to keep the file. */
+ return total_len;
+}
+
+/* Write new .debug_names section for OBJFILE into OUT_FILE,
+ write needed addition to .debug_str section to OUT_FILE_STR.
+ Return how many bytes were expected to be written into OUT_FILE. */
+
+static size_t
+write_debug_names (struct objfile *objfile, FILE *out_file, FILE *out_file_str)
+{
+ const bool dwarf5_is_dwarf64 (check_dwarf64_offsets ());
+ const int dwarf5_offset_size (dwarf5_is_dwarf64 ? 8 : 4);
+ const enum bfd_endian dwarf5_byte_order
+ (gdbarch_byte_order (get_objfile_arch (objfile)));
+
+ /* The CU list is already sorted, so we don't need to do additional
+ work here. Also, the debug_types entries do not appear in
+ all_comp_units, but only in their own hash table. */
+ data_buf cu_list;
+ debug_names nametable (dwarf5_is_dwarf64, dwarf5_byte_order);
+ std::unordered_set<partial_symbol *> psyms_seen;
+ for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ {
+ const dwarf2_per_cu_data *per_cu (dwarf2_per_objfile->all_comp_units[i]);
+ partial_symtab *psymtab = per_cu->v.psymtab;
+
+ /* CU of a shared file from 'dwz -m' may be unused by this main file.
+ It may be referenced from a local scope but in such case it does
+ not need to be present in .gdb_index. */
+ if (psymtab == NULL)
+ continue;
+
+ if (psymtab->user == NULL)
+ nametable.recursively_write_psymbols (objfile, psymtab, psyms_seen, i);
+
+ cu_list.append_uint (dwarf5_offset_size, dwarf5_byte_order,
+ to_underlying (per_cu->sect_off));
+ }
+ nametable.build ();
+
+ /* No addr_vec - DWARF-5 uses .debug_aranges genereated by GCC. */
+
+ data_buf types_cu_list;
+ for (int i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
+ {
+ const signatured_type &sigtype
+ (*dwarf2_per_objfile->all_type_units[i]);
+ const dwarf2_per_cu_data &per_cu (sigtype.per_cu);
+
+ types_cu_list.append_uint (dwarf5_offset_size, dwarf5_byte_order,
+ to_underlying (per_cu.sect_off));
+ }
+
+ const gdb_byte augmentation[] = { 'G', 'D', 'B', 0 };
+ const offset_type bytes_of_header ((dwarf5_is_dwarf64 ? 12 : 4)
+ + 2 + 2 + 7 * 4 + sizeof (augmentation));
+ size_t expected_bytes (0);
+ expected_bytes += bytes_of_header;
+ expected_bytes += cu_list.size ();
+ expected_bytes += types_cu_list.size ();
+ expected_bytes += nametable.bytes ();
+ data_buf header;
+
+ if (!dwarf5_is_dwarf64)
+ {
+ const uint64_t size64 (expected_bytes - 4);
+ gdb_assert (size64 < 0xfffffff0);
+ header.append_uint (4, dwarf5_byte_order, size64);
+ }
+ else
+ {
+ header.append_uint (4, dwarf5_byte_order, 0xffffffff);
+ header.append_uint (8, dwarf5_byte_order, expected_bytes - 12);
+ }
+
+ /* The version number. */
+ header.append_uint (2, dwarf5_byte_order, 5);
+
+ /* Padding. */
+ header.append_uint (2, dwarf5_byte_order, 0);
+
+ /* comp_unit_count - The number of CUs in the CU list. */
+ header.append_uint (4, dwarf5_byte_order, dwarf2_per_objfile->n_comp_units);
+
+ /* local_type_unit_count - The number of TUs
+ in the local TU list. */
+ header.append_uint (4, dwarf5_byte_order, dwarf2_per_objfile->n_type_units);
+
+ /* foreign_type_unit_count - The number of TUs
+ in the foreign TU list. */
+ header.append_uint (4, dwarf5_byte_order, 0);
+
+ /* bucket_count - The number of hash buckets
+ in the hash lookup table. */
+ header.append_uint (4, dwarf5_byte_order, nametable.bucket_count ());
+
+ /* name_count - The number of unique names in the index. */
+ header.append_uint (4, dwarf5_byte_order, nametable.name_count ());
+
+ /* abbrev_table_size - The size in bytes
+ of the abbreviations table. */
+ header.append_uint (4, dwarf5_byte_order, nametable.abbrev_table_bytes ());
+
+ /* augmentation_string_size - The size in bytes of the augmentation
+ string. This value is rounded up to a multiple of 4. */
+ static_assert (sizeof (augmentation) % 4 == 0);
+ header.append_uint (4, dwarf5_byte_order, sizeof (augmentation));
+ header.append_data (augmentation);
+
+ gdb_assert (header.size () == bytes_of_header);
+
+ header.file_write (out_file);
+ cu_list.file_write (out_file);
+ types_cu_list.file_write (out_file);
+ nametable.file_write (out_file, out_file_str);
+
+ return expected_bytes;
+}
+
+/* Create an index file for OBJFILE in the directory DIR. */
+
+static void
+write_psymtabs_to_index (struct objfile *objfile, const char *dir, bool is_dwarf5)
+{
+ if (dwarf2_per_objfile->using_index)
+ error (_("Cannot use an index to create the index"));
+
+ if (VEC_length (dwarf2_section_info_def, dwarf2_per_objfile->types) > 1)
+ error (_("Cannot make an index when the file has multiple .debug_types sections"));
+
+ if (!objfile->psymtabs || !objfile->psymtabs_addrmap)
+ return;
+
+ struct stat st;
+ if (stat (objfile_name (objfile), &st) < 0)
+ perror_with_name (objfile_name (objfile));
+
+ std::string filename (std::string (dir) + SLASH_STRING
+ + lbasename (objfile_name (objfile))
+ + (is_dwarf5 ? INDEX5_SUFFIX : INDEX4_SUFFIX));
+ std::string filename_str (std::string (dir) + SLASH_STRING
+ + lbasename (objfile_name (objfile))
+ + DEBUG_STR_SUFFIX);
+
+ FILE *out_file = gdb_fopen_cloexec (filename.c_str (), "wb");
+ if (!out_file)
+ error (_("Can't open `%s' for writing"), filename.c_str ());
+ file_closer close_out_file (out_file);
+ gdb::unlinker unlink_file (filename.c_str ());
+
+ FILE *out_file_str = gdb_fopen_cloexec (filename_str.c_str (), "wb");
+ if (!out_file_str)
+ error (_("Can't open `%s' for writing"), filename_str.c_str ());
+ file_closer close_out_file_str (out_file_str);
+ gdb::unlinker unlink_file_str (filename_str.c_str ());
+
+ const size_t total_len ((is_dwarf5 ? write_debug_names : write_gdbindex)
+ (objfile, out_file, out_file_str));
+ const auto out_file_size (ftell (out_file));
+ if (out_file_size == -1)
+ error (_("Can't get `%s' size"), filename.c_str ());
+ gdb_assert (out_file_size == total_len);
+
+ /* We want to keep the files. */
unlink_file.keep ();
+ unlink_file_str.keep ();
}
/* Implementation of the `save gdb-index' command.
@@ -23906,12 +24641,26 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
GDB manual. Any changes here must be documented there. */
static void
-save_gdb_index_command (char *arg, int from_tty)
+save_gdb_index_command (char *arg_entry, int from_tty)
{
struct objfile *objfile;
+ const char dwarf4space[] = "-dwarf-4 ";
+ bool is_dwarf5 (true);
+ const char *arg = arg_entry;
+
+ if (!arg)
+ arg = "";
+
+ arg = skip_spaces_const (arg);
+ if (strncmp (arg, dwarf4space, strlen (dwarf4space)) == 0)
+ {
+ is_dwarf5 = false;
+ arg += strlen (dwarf4space);
+ arg = skip_spaces_const (arg);
+ }
- if (!arg || !*arg)
- error (_("usage: save gdb-index DIRECTORY"));
+ if (!*arg)
+ error (_("usage: save gdb-index [-dwarf-4] DIRECTORY"));
ALL_OBJFILES (objfile)
{
@@ -23929,7 +24678,7 @@ save_gdb_index_command (char *arg, int from_tty)
TRY
{
- write_psymtabs_to_index (objfile, arg);
+ write_psymtabs_to_index (objfile, arg, is_dwarf5);
}
CATCH (except, RETURN_MASK_ERROR)
{
@@ -24063,7 +24812,7 @@ Warning: This option must be enabled before gdb reads the file."),
c = add_cmd ("gdb-index", class_files, save_gdb_index_command,
_("\
Save a gdb-index file.\n\
-Usage: save gdb-index DIRECTORY"),
+Usage: save gdb-index [-dwarf-4] DIRECTORY"),
&save_cmdlist);
set_cmd_completer (c, filename_completer);
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 5/5] DWARF-5: .debug_names index consumer
2017-06-18 19:32 [PATCH v2 0/5] DWARF-5: .debug_names index Jan Kratochvil
` (3 preceding siblings ...)
2017-06-18 19:32 ` [PATCH v2 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh Jan Kratochvil
@ 2017-06-18 19:33 ` Jan Kratochvil
2017-06-19 20:56 ` obsolete: [PATCH v2 0/5] DWARF-5: .debug_names index Jan Kratochvil
5 siblings, 0 replies; 7+ messages in thread
From: Jan Kratochvil @ 2017-06-18 19:33 UTC (permalink / raw)
To: gdb-patches; +Cc: Victor Leschuk
Hi,
it is not regression-free against no-index but it is regression-free against
.gdb_index. That is because .gdb_index is not regression-free against
no-index.
Some testcases needed to be updated as they were missing .debug_aranges.
While that does not matter for no-index (as GDB builds the mapping internally
during dwarf2_build_psymtabs_hard) and neither for .gdb_index (as GDB uses that
internally built mapping which it stores into .gdb_index) it does matter for
.debug_names as that simply assumes existing .debug_aranges from GCC.
I tried some performance checking but the index handling speed is negligible
compared to the CU expansion associated with it. .debug_names looked even as
a bit faster to me than .gdb_index which rather surprised me but I did not
investigate it more.
Jan
gdb/ChangeLog
2017-05-26 Jan Kratochvil <jan.kratochvil@redhat.com>
* defs.h (elf_sym_fns_debug_names): New declaration.
* dwarf2read.c (mapped_debug_names): New.
(struct dwarf2_per_objfile): Add debug_names, debug_aranges and
debug_names_table.
(dwarf2_elf_names): Add debug_names and debug_aranges.
(struct dwz_file): Add debug_names.
(dwarf2_locate_sections): Add debug_names and debug_aranges.
(locate_dwz_sections): Add debug_names.
(create_signatured_type_table_from_debug_names)
(create_addrmap_from_aranges): New.
(dwarf2_read_index): Update function comment.
(read_debug_names_from_section, create_cus_from_debug_names_list)
(create_cus_from_debug_names, dwarf2_read_debug_names): New.
(dwarf5_djb_hash): Function renamed from DebugNamesNameTable::djb_hash.
(dw2_debug_names_iterator): New.
(read_indirect_string_at_offset): New declaration.
(mapped_debug_names::namei_to_name)
(dw2_debug_names_iterator::find_vec_in_debug_names)
(dw2_debug_names_iterator::find_vec_in_debug_names)
(dw2_debug_names_iterator::next, dw2_debug_names_lookup_symbol)
(dw2_debug_names_dump, dw2_debug_names_expand_symtabs_for_function)
(dw2_debug_names_expand_symtabs_matching, dwarf2_debug_names_functions):
New.
(dwarf2_initialize_objfile): Return also elf_sym_fns_debug_names.
(dwarf2_free_objfile): Delete also debug_names_table;
(debug_names::djb_hash): Rename it to dwarf5_djb_hash.
(debug_names::build): Update djb_hash caller.
* elfread.c (elf_sym_fns_debug_names): New.
* psymtab.h (dwarf2_debug_names_functions): New declaration.
* symfile.h (struct dwarf2_debug_sections): Add debug_names and
debug_aranges.
* xcoffread.c (dwarf2_xcoff_names): Add debug_names and debug_aranges.
gdb/testsuite/ChangeLog
2017-05-26 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.base/maint.exp (check for .gdb_index): Check also for
.debug_names.
* gdb.dlang/watch-loc.c (.debug_aranges): New.
* gdb.dwarf2/dw2-case-insensitive-debug.S: Likewise.
* gdb.dwarf2/gdb-index.exp (check if index present, .gdb_index used)
(.gdb_index used after symbol reloading): Support also .debug_names.
* gdb.mi/dw2-ref-missing-frame-func.c (.debug_aranges): New.
---
gdb/defs.h | 1
gdb/dwarf2read.c | 1474 +++++++++++++++++---
gdb/elfread.c | 17
gdb/psymtab.h | 1
gdb/symfile.h | 2
gdb/testsuite/gdb.base/maint.exp | 7
gdb/testsuite/gdb.dlang/watch-loc.c | 19
.../gdb.dwarf2/dw2-case-insensitive-debug.S | 17
gdb/testsuite/gdb.dwarf2/gdb-index.exp | 7
gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c | 20
gdb/xcoffread.c | 2
11 files changed, 1378 insertions(+), 189 deletions(-)
diff --git a/gdb/defs.h b/gdb/defs.h
index 516c234..7916b99 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -762,6 +762,7 @@ extern void initialize_inferiors (void);
extern const struct sym_fns elf_sym_fns_lazy_psyms;
extern const struct sym_fns elf_sym_fns_gdb_index;
+extern const struct sym_fns elf_sym_fns_debug_names;
/* * Special block numbers */
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 3137d2f..56aa3ea 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -211,6 +211,41 @@ struct mapped_index
const char *constant_pool;
};
+/* A description of the mapped .debug_names.
+ Uninitialized map has CU_COUNT 0. */
+class mapped_debug_names
+{
+public:
+ bfd_endian dwarf5_byte_order;
+ bool dwarf5_is_dwarf64;
+ uint8_t offset_size;
+ uint32_t cu_count = 0;
+ uint32_t tu_count, bucket_count, name_count;
+ const gdb_byte *cu_table_reordered, *tu_table_reordered;
+ const uint32_t *bucket_table_reordered, *hash_table_reordered;
+ const gdb_byte *name_table_string_offs_reordered;
+ const gdb_byte *name_table_entry_offs_reordered;
+ const gdb_byte *entry_pool;
+ class index_val
+ {
+ public:
+ ULONGEST dwarf_tag;
+ class attr
+ {
+ public:
+ /* Attribute name DW_IDX_*. */
+ ULONGEST dw_idx;
+ /* Attribute form DW_FORM_*. */
+ ULONGEST form;
+ /* Value if FORM is DW_FORM_implicit_const. */
+ LONGEST implicit_const;
+ };
+ std::vector<attr> attr_vec;
+ };
+ std::unordered_map<ULONGEST, index_val> abbrev_map;
+ const char *namei_to_name (uint32_t namei) const;
+};
+
typedef struct dwarf2_per_cu_data *dwarf2_per_cu_ptr;
DEF_VEC_P (dwarf2_per_cu_ptr);
@@ -243,6 +278,8 @@ struct dwarf2_per_objfile
struct dwarf2_section_info frame;
struct dwarf2_section_info eh_frame;
struct dwarf2_section_info gdb_index;
+ struct dwarf2_section_info debug_names;
+ struct dwarf2_section_info debug_aranges;
VEC (dwarf2_section_info_def) *types;
@@ -308,6 +345,9 @@ struct dwarf2_per_objfile
/* The mapped index, or NULL if .gdb_index is missing or not being used. */
struct mapped_index *index_table;
+ /* The mapped index, or NULL if .debug_names is missing or not being used. */
+ mapped_debug_names *debug_names_table;
+
/* When using index_table, this keeps track of all quick_file_names entries.
TUs typically share line table entries with a CU, so we maintain a
separate table of all line table entries to support the sharing.
@@ -358,6 +398,8 @@ static const struct dwarf2_debug_sections dwarf2_elf_names =
{ ".debug_frame", ".zdebug_frame" },
{ ".eh_frame", NULL },
{ ".gdb_index", ".zgdb_index" },
+ { ".debug_names", ".zdebug_names" },
+ { ".debug_aranges", ".zdebug_aranges" },
23
};
@@ -1019,6 +1061,7 @@ struct dwz_file
struct dwarf2_section_info line;
struct dwarf2_section_info macro;
struct dwarf2_section_info gdb_index;
+ struct dwarf2_section_info debug_names;
/* The dwz's BFD. */
bfd *dwz_bfd;
@@ -2424,6 +2467,16 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *vnames)
dwarf2_per_objfile->gdb_index.s.section = sectp;
dwarf2_per_objfile->gdb_index.size = bfd_get_section_size (sectp);
}
+ else if (section_is_p (sectp->name, &names->debug_names))
+ {
+ dwarf2_per_objfile->debug_names.s.section = sectp;
+ dwarf2_per_objfile->debug_names.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->debug_aranges))
+ {
+ dwarf2_per_objfile->debug_aranges.s.section = sectp;
+ dwarf2_per_objfile->debug_aranges.size = bfd_get_section_size (sectp);
+ }
if ((bfd_get_section_flags (abfd, sectp) & (SEC_LOAD | SEC_ALLOC))
&& bfd_section_vma (abfd, sectp) == 0)
@@ -2620,6 +2673,11 @@ locate_dwz_sections (bfd *abfd, asection *sectp, void *arg)
dwz_file->gdb_index.s.section = sectp;
dwz_file->gdb_index.size = bfd_get_section_size (sectp);
}
+ else if (section_is_p (sectp->name, &dwarf2_elf_names.debug_names))
+ {
+ dwz_file->debug_names.s.section = sectp;
+ dwz_file->debug_names.size = bfd_get_section_size (sectp);
+ }
}
/* Open the separate '.dwz' debug file, if needed. Return NULL if
@@ -3071,6 +3129,66 @@ create_signatured_type_table_from_index (struct objfile *objfile,
dwarf2_per_objfile->signatured_types = sig_types_hash;
}
+/* Create the signatured type hash table from .debug_names. */
+
+static void
+create_signatured_type_table_from_debug_names (struct objfile *objfile,
+ const mapped_debug_names &map,
+ struct dwarf2_section_info *section,
+ struct dwarf2_section_info *abbrev_section)
+{
+ uint32_t i;
+ htab_t sig_types_hash;
+
+ dwarf2_read_section (objfile, section);
+ dwarf2_read_section (objfile, abbrev_section);
+
+ dwarf2_per_objfile->n_type_units
+ = dwarf2_per_objfile->n_allocated_type_units
+ = map.tu_count;
+ dwarf2_per_objfile->all_type_units =
+ XNEWVEC (struct signatured_type *, dwarf2_per_objfile->n_type_units);
+
+ sig_types_hash = allocate_signatured_type_table (objfile);
+
+ for (i = 0; i < map.tu_count; ++i)
+ {
+ struct signatured_type *sig_type;
+ ULONGEST signature;
+ void **slot;
+ cu_offset type_offset_in_tu;
+
+ sect_offset sect_off
+ = (sect_offset) extract_unsigned_integer
+ (map.tu_table_reordered + i * map.offset_size, map.offset_size,
+ map.dwarf5_byte_order);
+
+ comp_unit_head cu_header;
+ read_and_check_comp_unit_head (&cu_header, section, abbrev_section,
+ section->buffer + to_underlying (sect_off),
+ rcuh_kind::TYPE);
+
+ sig_type = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct signatured_type);
+ sig_type->signature = cu_header.signature;
+ sig_type->type_offset_in_tu = cu_header.type_cu_offset_in_tu;
+ sig_type->per_cu.is_debug_types = 1;
+ sig_type->per_cu.section = section;
+ sig_type->per_cu.sect_off = sect_off;
+ sig_type->per_cu.objfile = objfile;
+ sig_type->per_cu.v.quick
+ = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct dwarf2_per_cu_quick_data);
+
+ slot = htab_find_slot (sig_types_hash, sig_type, INSERT);
+ *slot = sig_type;
+
+ dwarf2_per_objfile->all_type_units[i] = sig_type;
+ }
+
+ dwarf2_per_objfile->signatured_types = sig_types_hash;
+}
+
/* Read the address map data from the mapped index, and use it to
populate the objfile's psymtabs_addrmap. */
@@ -3129,6 +3247,176 @@ create_addrmap_from_index (struct objfile *objfile, struct mapped_index *index)
do_cleanups (cleanup);
}
+/* Read the address map data from DWARF-5 .debug_aranges, and use it to
+ populate the objfile's psymtabs_addrmap. */
+
+static void
+create_addrmap_from_aranges (struct objfile *objfile,
+ struct dwarf2_section_info *section)
+{
+ bfd *abfd = objfile->obfd;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ const gdb_byte *iter, *end;
+ struct obstack temp_obstack;
+ struct addrmap *mutable_map;
+ struct cleanup *cleanup;
+ const CORE_ADDR baseaddr (ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile)));
+
+ obstack_init (&temp_obstack);
+ cleanup = make_cleanup_obstack_free (&temp_obstack);
+ mutable_map = addrmap_create_mutable (&temp_obstack);
+
+ std::unordered_map<sect_offset,
+ dwarf2_per_cu_data *> debug_info_offset_to_per_cu;
+ for (int cui = 0; cui < dwarf2_per_objfile->n_comp_units; ++cui)
+ {
+ dwarf2_per_cu_data *per_cu (dw2_get_cutu (cui));
+ const auto insertpair
+ (debug_info_offset_to_per_cu.emplace (per_cu->sect_off, per_cu));
+ if (!insertpair.second)
+ {
+ warning (_("Section .debug_aranges in %s has duplicate "
+ "debug_info_offset %u, ignoring .debug_aranges."),
+ objfile_name (objfile), to_underlying (per_cu->sect_off));
+ do_cleanups (cleanup);
+ return;
+ }
+ }
+
+ dwarf2_read_section (objfile, section);
+
+ const bfd_endian dwarf5_byte_order
+ (gdbarch_byte_order (get_objfile_arch (objfile)));
+
+ const gdb_byte *addr (section->buffer);
+
+ while (addr < section->buffer + section->size)
+ {
+ const gdb_byte *const entry_addr (addr);
+ unsigned int bytes_read;
+
+ const LONGEST entry_length (read_initial_length (abfd, addr,
+ &bytes_read));
+ addr += bytes_read;
+ const gdb_byte *const entry_end (addr + entry_length);
+ const bool dwarf5_is_dwarf64 (bytes_read != 4);
+ const uint8_t offset_size (dwarf5_is_dwarf64 ? 8 : 4);
+ if (addr + entry_length > section->buffer + section->size)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "length %s exceeds section length %s, "
+ "ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ plongest (bytes_read + entry_length),
+ pulongest (section->size));
+ do_cleanups (cleanup);
+ return;
+ }
+
+ /* The version number. */
+ const uint16_t version (read_2_bytes (abfd, addr));
+ addr += 2;
+ if (version != 2)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "has unsupported version %d, ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ version);
+ do_cleanups (cleanup);
+ return;
+ }
+
+ const uint64_t debug_info_offset
+ (extract_unsigned_integer (addr, offset_size, dwarf5_byte_order));
+ addr += offset_size;
+ const auto per_cu_it
+ (debug_info_offset_to_per_cu.find (sect_offset (debug_info_offset)));
+ if (per_cu_it == debug_info_offset_to_per_cu.cend ())
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "debug_info_offset %s does not exists, "
+ "ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ pulongest (debug_info_offset));
+ do_cleanups (cleanup);
+ return;
+ }
+ dwarf2_per_cu_data *const per_cu (per_cu_it->second);
+
+ const uint8_t address_size (*addr++);
+ if (address_size < 1 || address_size > 8)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "address_size %u is invalid, ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ address_size);
+ do_cleanups (cleanup);
+ return;
+ }
+
+ const uint8_t segment_selector_size (*addr++);
+ if (segment_selector_size != 0)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "segment_selector_size %u is not supported, "
+ "ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ segment_selector_size);
+ do_cleanups (cleanup);
+ return;
+ }
+
+ /* Must pad to an alignment boundary that is twice the address size.
+ It is undocumented by the DWARF standard but GCC does use it. */
+ for (size_t padding = ((-(addr - section->buffer))
+ & (2 * address_size - 1));
+ padding > 0; padding--)
+ if (*addr++ != 0)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "padding is not zero, ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer);
+ do_cleanups (cleanup);
+ return;
+ }
+
+ for (;;)
+ {
+ if (addr + 2 * address_size > entry_end)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "address list is not properly terminated, "
+ "ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer);
+ do_cleanups (cleanup);
+ return;
+ }
+ ULONGEST start (extract_unsigned_integer (addr, address_size,
+ dwarf5_byte_order));
+ addr += address_size;
+ ULONGEST length (extract_unsigned_integer (addr, address_size,
+ dwarf5_byte_order));
+ addr += address_size;
+ if (start == 0 && length == 0)
+ break;
+ if (start == 0 && !dwarf2_per_objfile->has_section_at_zero)
+ {
+ /* Symbol was eliminated due to a COMDAT group. */
+ continue;
+ }
+ ULONGEST end (start + length);
+ start = gdbarch_adjust_dwarf2_addr (gdbarch, start + baseaddr);
+ end = gdbarch_adjust_dwarf2_addr (gdbarch, end + baseaddr);
+ addrmap_set_empty (mutable_map, start, end - 1, per_cu);
+ }
+ }
+
+ objfile->psymtabs_addrmap = addrmap_create_fixed (mutable_map,
+ &objfile->objfile_obstack);
+ do_cleanups (cleanup);
+}
+
/* The hash function for strings in the mapped index. This is the same as
SYMBOL_HASH_NEXT, but we keep a separate copy to maintain control over the
implementation. This is necessary because the hash function is tied to the
@@ -3345,8 +3633,7 @@ to use the section anyway."),
return 1;
}
-
-/* Read the index file. If everything went ok, initialize the "quick"
+/* Read .gdb_index. If everything went ok, initialize the "quick"
elements of all the CUs and return 1. Otherwise, return 0. */
static int
@@ -3422,97 +3709,408 @@ dwarf2_read_index (struct objfile *objfile)
return 1;
}
-/* A helper for the "quick" functions which sets the global
- dwarf2_per_objfile according to OBJFILE. */
+/* A helper function that reads the .debug_names from SECTION and fills
+ in MAP. FILENAME is the name of the file containing the section;
+ it is used for error reporting.
-static void
-dw2_setup (struct objfile *objfile)
-{
- dwarf2_per_objfile = ((struct dwarf2_per_objfile *)
- objfile_data (objfile, dwarf2_objfile_data_key));
- gdb_assert (dwarf2_per_objfile);
-}
+ CU_LIST, CU_LIST_ELEMENTS, TYPES_LIST, and TYPES_LIST_ELEMENTS are
+ out parameters that are filled in with information about the CU and
+ TU lists in the section.
-/* die_reader_func for dw2_get_file_names. */
+ Returns true if all went well, false otherwise. */
-static void
-dw2_get_file_names_reader (const struct die_reader_specs *reader,
- const gdb_byte *info_ptr,
- struct die_info *comp_unit_die,
- int has_children,
- void *data)
+static bool
+read_debug_names_from_section (struct objfile *objfile,
+ const char *filename,
+ struct dwarf2_section_info *section,
+ mapped_debug_names &map)
{
- struct dwarf2_cu *cu = reader->cu;
- struct dwarf2_per_cu_data *this_cu = cu->per_cu;
- struct objfile *objfile = dwarf2_per_objfile->objfile;
- struct dwarf2_per_cu_data *lh_cu;
- struct attribute *attr;
+ const gdb_byte *addr, *abbrev_table_start;
+ offset_type *metadata;
int i;
- void **slot;
- struct quick_file_names *qfn;
+ unsigned int bytes_read;
+ LONGEST length;
+ uint16_t version, padding;
+ uint32_t foreign_tu_count;
+ uint32_t abbrev_table_size, augmentation_string_size;
- gdb_assert (! this_cu->is_debug_types);
+ if (dwarf2_section_empty_p (section))
+ return false;
- /* Our callers never want to match partial units -- instead they
- will match the enclosing full CU. */
- if (comp_unit_die->tag == DW_TAG_partial_unit)
+ /* Older elfutils strip versions could keep the section in the main
+ executable while splitting it for the separate debug info file. */
+ if ((get_section_flags (section) & SEC_HAS_CONTENTS) == 0)
+ return false;
+
+ dwarf2_read_section (objfile, section);
+
+ map.dwarf5_byte_order = gdbarch_byte_order (get_objfile_arch (objfile));
+
+ addr = section->buffer;
+
+ bfd *const abfd (get_section_bfd_owner (section));
+ length = read_initial_length (abfd, addr, &bytes_read);
+ addr += bytes_read;
+ map.dwarf5_is_dwarf64 = bytes_read != 4;
+ map.offset_size = map.dwarf5_is_dwarf64 ? 8 : 4;
+ if (bytes_read + length != section->size)
+ {
+ /* There may be multiple per-CU indices. */
+ warning (_("Section .debug_names in %s length %s does not match "
+ "section length %s, ignoring .debug_names."),
+ filename, plongest (bytes_read + length),
+ pulongest (section->size));
+ return false;
+ }
+
+ /* The version number. */
+ version = read_2_bytes (abfd, addr);
+ addr += 2;
+ if (version != 5)
{
- this_cu->v.quick->no_file_data = 1;
- return;
+ warning (_("Section .debug_names in %s has unsupported version %d, "
+ "ignoring .debug_names."),
+ filename, version);
+ return false;
}
- lh_cu = this_cu;
- slot = NULL;
+ /* Padding. */
+ padding = read_2_bytes (abfd, addr);
+ addr += 2;
+ if (padding != 0)
+ {
+ warning (_("Section .debug_names in %s has unsupported padding %d, "
+ "ignoring .debug_names."),
+ filename, padding);
+ return false;
+ }
- line_header_up lh;
- sect_offset line_offset {};
+ /* comp_unit_count - The number of CUs in the CU list. */
+ map.cu_count = read_4_bytes (abfd, addr);
+ addr += 4;
- attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, cu);
- if (attr)
+ /* local_type_unit_count - The number of TUs
+ in the local TU list. */
+ map.tu_count = read_4_bytes (abfd, addr);
+ addr += 4;
+
+ /* foreign_type_unit_count - The number of TUs
+ in the foreign TU list. */
+ foreign_tu_count = read_4_bytes (abfd, addr);
+ addr += 4;
+ if (foreign_tu_count != 0)
{
- struct quick_file_names find_entry;
+ warning (_("Section .debug_names in %s has unsupported %lu foreign TUs, "
+ "ignoring .debug_names."),
+ filename, static_cast<unsigned long> (foreign_tu_count));
+ return false;
+ }
- line_offset = (sect_offset) DW_UNSND (attr);
+ /* bucket_count - The number of hash buckets
+ in the hash lookup table. */
+ map.bucket_count = read_4_bytes (abfd, addr);
+ addr += 4;
- /* We may have already read in this line header (TU line header sharing).
- If we have we're done. */
- find_entry.hash.dwo_unit = cu->dwo_unit;
- find_entry.hash.line_sect_off = line_offset;
- slot = htab_find_slot (dwarf2_per_objfile->quick_file_names_table,
- &find_entry, INSERT);
- if (*slot != NULL)
+ /* name_count - The number of unique names in the index. */
+ map.name_count = read_4_bytes (abfd, addr);
+ addr += 4;
+
+ /* abbrev_table_size - The size in bytes
+ of the abbreviations table. */
+ abbrev_table_size = read_4_bytes (abfd, addr);
+ addr += 4;
+
+ /* augmentation_string_size - The size in bytes of the augmentation
+ string. This value is rounded up to a multiple of 4. */
+ augmentation_string_size = read_4_bytes (abfd, addr);
+ addr += 4;
+ augmentation_string_size += (-augmentation_string_size) & 3;
+ addr += augmentation_string_size;
+
+ /* List of CUs */
+ map.cu_table_reordered = addr;
+ addr += map.cu_count * map.offset_size;
+
+ /* List of Local TUs */
+ map.tu_table_reordered = addr;
+ addr += map.tu_count * map.offset_size;
+
+ /* Hash Lookup Table */
+ map.bucket_table_reordered = reinterpret_cast<const uint32_t *> (addr);
+ addr += map.bucket_count * 4;
+ map.hash_table_reordered = reinterpret_cast<const uint32_t *> (addr);
+ addr += map.name_count * 4;
+
+ /* Name Table */
+ map.name_table_string_offs_reordered = addr;
+ addr += map.name_count * map.offset_size;
+ map.name_table_entry_offs_reordered = addr;
+ addr += map.name_count * map.offset_size;
+
+ abbrev_table_start = addr;
+ for (;;)
+ {
+ unsigned int bytes_read;
+ const ULONGEST index_num (read_unsigned_leb128 (abfd, addr, &bytes_read));
+ addr += bytes_read;
+ if (index_num == 0)
+ break;
+
+ const auto insertpair (map.abbrev_map.emplace (index_num,
+ mapped_debug_names::index_val ()));
+ if (!insertpair.second)
{
- lh_cu->v.quick->file_names = (struct quick_file_names *) *slot;
- return;
+ warning (_("Section .debug_names in %s has duplicate index %s, "
+ "ignoring .debug_names."),
+ filename, pulongest (index_num));
+ return false;
}
+ mapped_debug_names::index_val &indexval (insertpair.first->second);
+ indexval.dwarf_tag = read_unsigned_leb128 (abfd, addr, &bytes_read);
+ addr += bytes_read;
- lh = dwarf_decode_line_header (line_offset, cu);
+ for (;;)
+ {
+ mapped_debug_names::index_val::attr attr;
+ attr.dw_idx = read_unsigned_leb128 (abfd, addr, &bytes_read);
+ addr += bytes_read;
+ attr.form = read_unsigned_leb128 (abfd, addr, &bytes_read);
+ addr += bytes_read;
+ if (attr.form == DW_FORM_implicit_const)
+ {
+ attr.implicit_const = read_signed_leb128 (abfd, addr,
+ &bytes_read);
+ addr += bytes_read;
+ }
+ if (attr.dw_idx == 0 && attr.form == 0)
+ break;
+ indexval.attr_vec.push_back (std::move (attr));
+ }
}
- if (lh == NULL)
+ if (addr != abbrev_table_start + abbrev_table_size)
{
- lh_cu->v.quick->no_file_data = 1;
- return;
+ warning (_("Section .debug_names in %s has abbreviation_table "
+ "of size %zu vs. written as %u, ignoring .debug_names."),
+ filename, addr - abbrev_table_start, abbrev_table_size);
+ return false;
}
+ map.entry_pool = addr;
- qfn = XOBNEW (&objfile->objfile_obstack, struct quick_file_names);
- qfn->hash.dwo_unit = cu->dwo_unit;
- qfn->hash.line_sect_off = line_offset;
- gdb_assert (slot != NULL);
- *slot = qfn;
-
- file_and_directory fnd = find_file_and_directory (comp_unit_die, cu);
-
- qfn->num_file_names = lh->file_names.size ();
- qfn->file_names =
- XOBNEWVEC (&objfile->objfile_obstack, const char *, lh->file_names.size ());
- for (i = 0; i < lh->file_names.size (); ++i)
- qfn->file_names[i] = file_full_name (i + 1, lh.get (), fnd.comp_dir);
- qfn->real_names = NULL;
-
- lh_cu->v.quick->file_names = qfn;
+ return true;
}
-/* A helper for the "quick" functions which attempts to read the line
+/* A helper for create_cus_from_index that handles a given list of
+ CUs. */
+
+static void
+create_cus_from_debug_names_list (struct objfile *objfile,
+ const mapped_debug_names &map,
+ dwarf2_section_info §ion,
+ int is_dwz, int base_offset)
+{
+ sect_offset sect_off_prev;
+ for (uint32_t i = 0; i <= map.cu_count; ++i)
+ {
+ sect_offset sect_off_next;
+ if (i < map.cu_count)
+ sect_off_next = (sect_offset) extract_unsigned_integer
+ (map.cu_table_reordered + i * map.offset_size, map.offset_size,
+ map.dwarf5_byte_order);
+ else
+ sect_off_next = (sect_offset) section.size;
+ if (i >= 1)
+ {
+ const ULONGEST length (sect_off_next - sect_off_prev);
+ dwarf2_per_objfile->all_comp_units[base_offset + (i - 1)] =
+ create_cu_from_index_list (objfile, §ion, is_dwz,
+ sect_off_prev, length);
+ }
+ sect_off_prev = sect_off_next;
+ }
+}
+
+/* Read the CU list from the mapped index, and use it to create all
+ the CU objects for this objfile. */
+
+static void
+create_cus_from_debug_names (struct objfile *objfile,
+ const mapped_debug_names &map,
+ const mapped_debug_names &dwz_map)
+{
+ struct dwz_file *dwz;
+
+ dwarf2_per_objfile->n_comp_units = map.cu_count + dwz_map.cu_count;
+ dwarf2_per_objfile->all_comp_units =
+ XOBNEWVEC (&objfile->objfile_obstack, struct dwarf2_per_cu_data *,
+ dwarf2_per_objfile->n_comp_units);
+
+ create_cus_from_debug_names_list (objfile, map, dwarf2_per_objfile->info,
+ 0 /* is_dwz */, 0 /* base_offset */);
+
+ if (dwz_map.cu_count == 0)
+ return;
+
+ dwz = dwarf2_get_dwz_file ();
+ create_cus_from_debug_names_list (objfile, dwz_map, dwz->info, 1 /* is_dwz */,
+ map.cu_count /* base_offset */);
+}
+
+/* Read .debug_names. If everything went ok, initialize the "quick"
+ elements of all the CUs and return true. Otherwise, return false. */
+
+static bool
+dwarf2_read_debug_names (struct objfile *objfile)
+{
+ mapped_debug_names local_map, dwz_map;
+ const gdb_byte *dwz_list = NULL;
+ offset_type dwz_list_elements = 0;
+ struct dwz_file *dwz;
+
+ if (!read_debug_names_from_section (objfile, objfile_name (objfile),
+ &dwarf2_per_objfile->debug_names,
+ local_map))
+ return false;
+
+ /* Don't use the index if it's empty. */
+ if (local_map.name_count == 0)
+ return false;
+
+ /* If there is a .dwz file, read it so we can get its CU list as
+ well. */
+ dwz = dwarf2_get_dwz_file ();
+ if (dwz != NULL)
+ {
+ if (!read_debug_names_from_section (objfile,
+ bfd_get_filename (dwz->dwz_bfd),
+ &dwz->debug_names, dwz_map))
+ {
+ warning (_("could not read '.debug_names' section from %s; skipping"),
+ bfd_get_filename (dwz->dwz_bfd));
+ return false;
+ }
+ }
+
+ create_cus_from_debug_names (objfile, local_map, dwz_map);
+
+ if (local_map.tu_count != 0)
+ {
+ struct dwarf2_section_info *section;
+
+ /* We can only handle a single .debug_types when we have an
+ index. */
+ if (VEC_length (dwarf2_section_info_def, dwarf2_per_objfile->types) != 1)
+ return false;
+
+ section = VEC_index (dwarf2_section_info_def,
+ dwarf2_per_objfile->types, 0);
+
+ create_signatured_type_table_from_debug_names (objfile, local_map,
+ section,
+ &dwarf2_per_objfile->abbrev);
+ }
+
+ create_addrmap_from_aranges (objfile, &dwarf2_per_objfile->debug_aranges);
+
+ dwarf2_per_objfile->debug_names_table = new mapped_debug_names;
+ *dwarf2_per_objfile->debug_names_table = std::move (local_map);
+ dwarf2_per_objfile->using_index = 1;
+ dwarf2_per_objfile->quick_file_names_table =
+ create_quick_file_names_table (dwarf2_per_objfile->n_comp_units);
+
+ return true;
+}
+
+/* A helper for the "quick" functions which sets the global
+ dwarf2_per_objfile according to OBJFILE. */
+
+static void
+dw2_setup (struct objfile *objfile)
+{
+ dwarf2_per_objfile = ((struct dwarf2_per_objfile *)
+ objfile_data (objfile, dwarf2_objfile_data_key));
+ gdb_assert (dwarf2_per_objfile);
+}
+
+/* die_reader_func for dw2_get_file_names. */
+
+static void
+dw2_get_file_names_reader (const struct die_reader_specs *reader,
+ const gdb_byte *info_ptr,
+ struct die_info *comp_unit_die,
+ int has_children,
+ void *data)
+{
+ struct dwarf2_cu *cu = reader->cu;
+ struct dwarf2_per_cu_data *this_cu = cu->per_cu;
+ struct objfile *objfile = dwarf2_per_objfile->objfile;
+ struct dwarf2_per_cu_data *lh_cu;
+ struct attribute *attr;
+ int i;
+ void **slot;
+ struct quick_file_names *qfn;
+
+ gdb_assert (! this_cu->is_debug_types);
+
+ /* Our callers never want to match partial units -- instead they
+ will match the enclosing full CU. */
+ if (comp_unit_die->tag == DW_TAG_partial_unit)
+ {
+ this_cu->v.quick->no_file_data = 1;
+ return;
+ }
+
+ lh_cu = this_cu;
+ slot = NULL;
+
+ line_header_up lh;
+ sect_offset line_offset {};
+
+ attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, cu);
+ if (attr)
+ {
+ struct quick_file_names find_entry;
+
+ line_offset = (sect_offset) DW_UNSND (attr);
+
+ /* We may have already read in this line header (TU line header sharing).
+ If we have we're done. */
+ find_entry.hash.dwo_unit = cu->dwo_unit;
+ find_entry.hash.line_sect_off = line_offset;
+ slot = htab_find_slot (dwarf2_per_objfile->quick_file_names_table,
+ &find_entry, INSERT);
+ if (*slot != NULL)
+ {
+ lh_cu->v.quick->file_names = (struct quick_file_names *) *slot;
+ return;
+ }
+
+ lh = dwarf_decode_line_header (line_offset, cu);
+ }
+ if (lh == NULL)
+ {
+ lh_cu->v.quick->no_file_data = 1;
+ return;
+ }
+
+ qfn = XOBNEW (&objfile->objfile_obstack, struct quick_file_names);
+ qfn->hash.dwo_unit = cu->dwo_unit;
+ qfn->hash.line_sect_off = line_offset;
+ gdb_assert (slot != NULL);
+ *slot = qfn;
+
+ file_and_directory fnd = find_file_and_directory (comp_unit_die, cu);
+
+ qfn->num_file_names = lh->file_names.size ();
+ qfn->file_names =
+ XOBNEWVEC (&objfile->objfile_obstack, const char *, lh->file_names.size ());
+ for (i = 0; i < lh->file_names.size (); ++i)
+ qfn->file_names[i] = file_full_name (i + 1, lh.get (), fnd.comp_dir);
+ qfn->real_names = NULL;
+
+ lh_cu->v.quick->file_names = qfn;
+}
+
+/* A helper for the "quick" functions which attempts to read the line
table for THIS_CU. */
static struct quick_file_names *
@@ -4232,163 +4830,677 @@ dw2_expand_symtabs_matching
if (cu_index >= (dwarf2_per_objfile->n_comp_units
+ dwarf2_per_objfile->n_type_units))
{
- complaint (&symfile_complaints,
- _(".gdb_index entry has bad CU index"
- " [in module %s]"), objfile_name (objfile));
- continue;
+ complaint (&symfile_complaints,
+ _(".gdb_index entry has bad CU index"
+ " [in module %s]"), objfile_name (objfile));
+ continue;
+ }
+
+ per_cu = dw2_get_cutu (cu_index);
+ dw2_expand_symtabs_matching_one (per_cu, file_matcher,
+ expansion_notify);
+ }
+ }
+}
+
+/* A helper for dw2_find_pc_sect_compunit_symtab which finds the most specific
+ symtab. */
+
+static struct compunit_symtab *
+recursively_find_pc_sect_compunit_symtab (struct compunit_symtab *cust,
+ CORE_ADDR pc)
+{
+ int i;
+
+ if (COMPUNIT_BLOCKVECTOR (cust) != NULL
+ && blockvector_contains_pc (COMPUNIT_BLOCKVECTOR (cust), pc))
+ return cust;
+
+ if (cust->includes == NULL)
+ return NULL;
+
+ for (i = 0; cust->includes[i]; ++i)
+ {
+ struct compunit_symtab *s = cust->includes[i];
+
+ s = recursively_find_pc_sect_compunit_symtab (s, pc);
+ if (s != NULL)
+ return s;
+ }
+
+ return NULL;
+}
+
+static struct compunit_symtab *
+dw2_find_pc_sect_compunit_symtab (struct objfile *objfile,
+ struct bound_minimal_symbol msymbol,
+ CORE_ADDR pc,
+ struct obj_section *section,
+ int warn_if_readin)
+{
+ struct dwarf2_per_cu_data *data;
+ struct compunit_symtab *result;
+
+ dw2_setup (objfile);
+
+ if (!objfile->psymtabs_addrmap)
+ return NULL;
+
+ data = (struct dwarf2_per_cu_data *) addrmap_find (objfile->psymtabs_addrmap,
+ pc);
+ if (!data)
+ return NULL;
+
+ if (warn_if_readin && data->v.quick->compunit_symtab)
+ warning (_("(Internal error: pc %s in read in CU, but not in symtab.)"),
+ paddress (get_objfile_arch (objfile), pc));
+
+ result
+ = recursively_find_pc_sect_compunit_symtab (dw2_instantiate_symtab (data),
+ pc);
+ gdb_assert (result != NULL);
+ return result;
+}
+
+static void
+dw2_map_symbol_filenames (struct objfile *objfile, symbol_filename_ftype *fun,
+ void *data, int need_fullname)
+{
+ int i;
+ htab_up visited (htab_create_alloc (10, htab_hash_pointer, htab_eq_pointer,
+ NULL, xcalloc, xfree));
+
+ dw2_setup (objfile);
+
+ /* The rule is CUs specify all the files, including those used by
+ any TU, so there's no need to scan TUs here.
+ We can ignore file names coming from already-expanded CUs. */
+
+ for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ {
+ struct dwarf2_per_cu_data *per_cu = dw2_get_cutu (i);
+
+ if (per_cu->v.quick->compunit_symtab)
+ {
+ void **slot = htab_find_slot (visited.get (),
+ per_cu->v.quick->file_names,
+ INSERT);
+
+ *slot = per_cu->v.quick->file_names;
+ }
+ }
+
+ for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ {
+ int j;
+ struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
+ struct quick_file_names *file_data;
+ void **slot;
+
+ /* We only need to look at symtabs not already expanded. */
+ if (per_cu->v.quick->compunit_symtab)
+ continue;
+
+ file_data = dw2_get_file_names (per_cu);
+ if (file_data == NULL)
+ continue;
+
+ slot = htab_find_slot (visited.get (), file_data, INSERT);
+ if (*slot)
+ {
+ /* Already visited. */
+ continue;
+ }
+ *slot = file_data;
+
+ for (j = 0; j < file_data->num_file_names; ++j)
+ {
+ const char *this_real_name;
+
+ if (need_fullname)
+ this_real_name = dw2_get_real_path (objfile, file_data, j);
+ else
+ this_real_name = NULL;
+ (*fun) (file_data->file_names[j], this_real_name, data);
+ }
+ }
+}
+
+static int
+dw2_has_symbols (struct objfile *objfile)
+{
+ return 1;
+}
+
+const struct quick_symbol_functions dwarf2_gdb_index_functions =
+{
+ dw2_has_symbols,
+ dw2_find_last_source_symtab,
+ dw2_forget_cached_source_info,
+ dw2_map_symtabs_matching_filename,
+ dw2_lookup_symbol,
+ dw2_print_stats,
+ dw2_dump,
+ dw2_relocate,
+ dw2_expand_symtabs_for_function,
+ dw2_expand_all_symtabs,
+ dw2_expand_symtabs_with_fullname,
+ dw2_map_matching_symbols,
+ dw2_expand_symtabs_matching,
+ dw2_find_pc_sect_compunit_symtab,
+ dw2_map_symbol_filenames
+};
+
+/* Symbol name hashing function as specified by DWARF-5. */
+
+static uint32_t
+dwarf5_djb_hash (const unsigned char *str)
+{
+ uint32_t hash = 5381;
+ while (int c = *str++)
+ {
+ /* FIXME: std::bad_cast for: std::tolower (c, std::locale::classic ())
+ FIXME: Is unicode supported for symbol names by GDB? */
+ hash = hash * 33 + tolower (c);
+ }
+ return hash;
+}
+
+/* Struct used to manage iterating over all CUs looking for a symbol
+ for .debug_names. */
+
+class dw2_debug_names_iterator
+{
+private:
+ /* The internalized form of .debug_names. */
+ const mapped_debug_names ↦
+ /* If true, only look for symbols that match BLOCK_INDEX. */
+ const bool want_specific_block = false;
+ /* One of GLOBAL_BLOCK or STATIC_BLOCK.
+ Unused if !WANT_SPECIFIC_BLOCK - FIRST_LOCAL_BLOCK is an invalid value. */
+ const block_enum block_index = FIRST_LOCAL_BLOCK;
+ /* The kind of symbol we're looking for. */
+ const domain_enum domain = UNDEF_DOMAIN;
+ const search_domain search = ALL_DOMAIN;
+ /* The list of CUs from the index entry of the symbol,
+ or NULL if not found. */
+ const gdb_byte *addr;
+ static const gdb_byte *find_vec_in_debug_names
+ (const mapped_debug_names &map, const char *name);
+ static const gdb_byte *find_vec_in_debug_names
+ (const mapped_debug_names &map, uint32_t namei);
+public:
+
+ /* If WANT_SPECIFIC_BLOCK is non-zero, only look for symbols
+ in block BLOCK_INDEX. Otherwise BLOCK_INDEX is ignored. */
+ dw2_debug_names_iterator
+ (const mapped_debug_names &map_, bool want_specific_block_,
+ block_enum block_index_, domain_enum domain_, const char *name)
+ : map (map_), want_specific_block (want_specific_block_),
+ block_index (block_index_), domain (domain_),
+ addr (find_vec_in_debug_names (map, name))
+ {
+ }
+
+ dw2_debug_names_iterator
+ (const mapped_debug_names &map_, search_domain search_, uint32_t namei)
+ : map (map_), search (search_), addr (find_vec_in_debug_names (map, namei))
+ {
+ }
+
+ /* Return the next matching CU or NULL if there are no more. */
+ dwarf2_per_cu_data *next ();
+};
+
+static const char *read_indirect_string_at_offset (bfd *abfd,
+ LONGEST str_offset);
+
+const char *
+mapped_debug_names::namei_to_name (uint32_t namei) const
+{
+ const ULONGEST namei_string_offs
+ (extract_unsigned_integer ((name_table_string_offs_reordered
+ + namei * offset_size), offset_size,
+ dwarf5_byte_order));
+ return read_indirect_string_at_offset
+ (dwarf2_per_objfile->objfile->obfd, namei_string_offs);
+}
+
+/* Find a slot in .debug_names for the object named NAME.
+ If NAME is found, return pointer to its pool data.
+ If NAME cannot be found, return NULL. */
+
+const gdb_byte *
+dw2_debug_names_iterator::find_vec_in_debug_names
+ (const mapped_debug_names &map, const char *name)
+{
+ struct cleanup *back_to = make_cleanup (null_cleanup, 0);
+ int (*cmp) (const char *, const char *);
+
+ if (current_language->la_language == language_cplus
+ || current_language->la_language == language_fortran
+ || current_language->la_language == language_d)
+ {
+ /* NAME is already canonical. Drop any qualifiers as .gdb_index does
+ not contain any. */
+
+ if (strchr (name, '(') != NULL)
+ {
+ char *without_params = cp_remove_params (name);
+
+ if (without_params != NULL)
+ {
+ make_cleanup (xfree, without_params);
+ name = without_params;
+ }
+ }
+ }
+
+ cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp);
+
+ const uint32_t full_hash
+ (dwarf5_djb_hash (reinterpret_cast<const unsigned char *> (name)));
+ uint32_t namei
+ (extract_unsigned_integer (reinterpret_cast<const gdb_byte *>
+ (map.bucket_table_reordered
+ + (full_hash % map.bucket_count)), 4,
+ map.dwarf5_byte_order));
+ if (namei == 0)
+ {
+ do_cleanups (back_to);
+ return NULL;
+ }
+ --namei;
+ if (namei >= map.name_count)
+ {
+ complaint (&symfile_complaints,
+ _("Wrong .debug_names with name index %u but name_count=%u "
+ "[in module %s]"),
+ namei, map.name_count,
+ objfile_name (dwarf2_per_objfile->objfile));
+ do_cleanups (back_to);
+ return NULL;
+ }
+ for (;;)
+ {
+ const uint32_t namei_full_hash
+ (extract_unsigned_integer (reinterpret_cast<const gdb_byte *>
+ (map.hash_table_reordered + namei), 4,
+ map.dwarf5_byte_order));
+ if (full_hash % map.bucket_count != namei_full_hash % map.bucket_count)
+ {
+ do_cleanups (back_to);
+ return NULL;
+ }
+
+ if (full_hash == namei_full_hash)
+ {
+ const char *const namei_string (map.namei_to_name (namei));
+
+#if 0 /* An expensive sanity check. */
+ if (namei_full_hash != dwarf5_djb_hash
+ (reinterpret_cast<const unsigned char *> (namei_string)))
+ {
+ complaint (&symfile_complaints,
+ _("Wrong .debug_names hash for string at index %u "
+ "[in module %s]"),
+ namei, objfile_name (dwarf2_per_objfile->objfile));
+ do_cleanups (back_to);
+ return NULL;
+ }
+#endif
+
+ if (cmp (namei_string, name) == 0)
+ {
+ const ULONGEST namei_entry_offs
+ (extract_unsigned_integer ((map.name_table_entry_offs_reordered
+ + namei * map.offset_size),
+ map.offset_size, map.dwarf5_byte_order));
+ do_cleanups (back_to);
+ return map.entry_pool + namei_entry_offs;
}
+ }
- per_cu = dw2_get_cutu (cu_index);
- dw2_expand_symtabs_matching_one (per_cu, file_matcher,
- expansion_notify);
+ ++namei;
+ if (namei >= map.name_count)
+ {
+ do_cleanups (back_to);
+ return NULL;
}
}
}
-/* A helper for dw2_find_pc_sect_compunit_symtab which finds the most specific
- symtab. */
-
-static struct compunit_symtab *
-recursively_find_pc_sect_compunit_symtab (struct compunit_symtab *cust,
- CORE_ADDR pc)
+const gdb_byte *
+dw2_debug_names_iterator::find_vec_in_debug_names
+ (const mapped_debug_names &map, uint32_t namei)
{
- int i;
+ if (namei >= map.name_count)
+ {
+ complaint (&symfile_complaints,
+ _("Wrong .debug_names with name index %u but name_count=%u "
+ "[in module %s]"),
+ namei, map.name_count,
+ objfile_name (dwarf2_per_objfile->objfile));
+ return NULL;
+ }
+ const ULONGEST namei_entry_offs
+ (extract_unsigned_integer ((map.name_table_entry_offs_reordered
+ + namei * map.offset_size),
+ map.offset_size, map.dwarf5_byte_order));
+ return map.entry_pool + namei_entry_offs;
+}
- if (COMPUNIT_BLOCKVECTOR (cust) != NULL
- && blockvector_contains_pc (COMPUNIT_BLOCKVECTOR (cust), pc))
- return cust;
+/* See dw2_debug_names_iterator. */
- if (cust->includes == NULL)
+dwarf2_per_cu_data *
+dw2_debug_names_iterator::next ()
+{
+ if (addr == NULL)
+ return NULL;
+ bfd *const abfd (dwarf2_per_objfile->objfile->obfd);
+ unsigned int bytes_read;
+ const ULONGEST abbrev (read_unsigned_leb128 (abfd, addr, &bytes_read));
+ addr += bytes_read;
+ if (abbrev == 0)
return NULL;
+ const auto indexval_it (map.abbrev_map.find (abbrev));
+ if (indexval_it == map.abbrev_map.cend ())
+ {
+ complaint (&symfile_complaints,
+ _("Wrong .debug_names undefined abbrev code %s "
+ "[in module %s]"),
+ pulongest (abbrev), objfile_name (dwarf2_per_objfile->objfile));
+ return NULL;
+ }
+ const mapped_debug_names::index_val &indexval (indexval_it->second);
+ bool have_is_static (false);
+ bool is_static;
+ dwarf2_per_cu_data *per_cu (NULL);
+ for (const mapped_debug_names::index_val::attr &attr : indexval.attr_vec)
+ {
+ ULONGEST ull;
+ switch (attr.form)
+ {
+ case DW_FORM_implicit_const:
+ ull = attr.implicit_const;
+ break;
+ case DW_FORM_flag_present:
+ ull = 1;
+ break;
+ case DW_FORM_udata:
+ ull = read_unsigned_leb128 (abfd, addr, &bytes_read);
+ addr += bytes_read;
+ break;
+ default:
+ complaint (&symfile_complaints,
+ _("Unsupported .debug_names form %s [in module %s]"),
+ dwarf_form_name (attr.form),
+ objfile_name (dwarf2_per_objfile->objfile));
+ return NULL;
+ }
+ switch (attr.dw_idx)
+ {
+ case DW_IDX_compile_unit:
+ /* Don't crash on bad data. */
+ if (ull >= (dwarf2_per_objfile->n_comp_units
+ + dwarf2_per_objfile->n_type_units))
+ {
+ complaint (&symfile_complaints,
+ _(".gdb_index entry has bad CU index %s"
+ " [in module %s]"),
+ pulongest (ull),
+ objfile_name (dwarf2_per_objfile->objfile));
+ continue;
+ }
+ per_cu = dw2_get_cutu (ull);
+ break;
+ case DW_IDX_GNU_static:
+ have_is_static = true;
+ is_static = true;
+ break;
+ case DW_IDX_GNU_external:
+ have_is_static = true;
+ is_static = false;
+ break;
+ }
+ }
- for (i = 0; cust->includes[i]; ++i)
+ /* Skip if already read in. */
+ if (per_cu->v.quick->compunit_symtab)
+ return next ();
+
+ /* Check static vs global. */
+ if (have_is_static)
{
- struct compunit_symtab *s = cust->includes[i];
+ const bool want_static (block_index != GLOBAL_BLOCK);
+ if (want_specific_block && want_static != is_static)
+ return next ();
+ }
- s = recursively_find_pc_sect_compunit_symtab (s, pc);
- if (s != NULL)
- return s;
+ /* Match dw2_symtab_iter_next, symbol_kind
+ and DebugNamesNameTable::psymbol_tag. */
+ switch (domain)
+ {
+ case VAR_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case DW_TAG_variable:
+ case DW_TAG_subprogram:
+ /* Some types are also in VAR_DOMAIN. */
+ case DW_TAG_typedef:
+ case DW_TAG_structure_type:
+ break;
+ default:
+ return next ();
+ }
+ break;
+ case STRUCT_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case DW_TAG_typedef:
+ case DW_TAG_structure_type:
+ break;
+ default:
+ return next ();
+ }
+ break;
+ case LABEL_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case 0:
+ case DW_TAG_variable:
+ break;
+ default:
+ return next ();
+ }
+ break;
+ default:
+ break;
}
- return NULL;
+ /* Match dw2_expand_symtabs_matching, symbol_kind
+ and DebugNamesNameTable::psymbol_tag. */
+ switch (search)
+ {
+ case VARIABLES_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case DW_TAG_variable:
+ break;
+ default:
+ return next ();
+ }
+ break;
+ case FUNCTIONS_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case DW_TAG_subprogram:
+ break;
+ default:
+ return next ();
+ }
+ break;
+ case TYPES_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case DW_TAG_typedef:
+ case DW_TAG_structure_type:
+ break;
+ default:
+ return next ();
+ }
+ break;
+ default:
+ break;
+ }
+
+ return per_cu;
}
static struct compunit_symtab *
-dw2_find_pc_sect_compunit_symtab (struct objfile *objfile,
- struct bound_minimal_symbol msymbol,
- CORE_ADDR pc,
- struct obj_section *section,
- int warn_if_readin)
+dw2_debug_names_lookup_symbol (struct objfile *objfile, int block_index_int,
+ const char *name, domain_enum domain)
{
- struct dwarf2_per_cu_data *data;
- struct compunit_symtab *result;
-
+ const block_enum block_index (static_cast<block_enum> (block_index_int));
dw2_setup (objfile);
- if (!objfile->psymtabs_addrmap)
- return NULL;
+ const auto &mapp (dwarf2_per_objfile->debug_names_table);
+ if (!mapp)
+ {
+ /* index is NULL if OBJF_READNOW. */
+ return NULL;
+ }
+ const auto &map (*mapp);
- data = (struct dwarf2_per_cu_data *) addrmap_find (objfile->psymtabs_addrmap,
- pc);
- if (!data)
- return NULL;
+ dw2_debug_names_iterator iter (map, 1 /* want_specific_block */, block_index,
+ domain, name);
- if (warn_if_readin && data->v.quick->compunit_symtab)
- warning (_("(Internal error: pc %s in read in CU, but not in symtab.)"),
- paddress (get_objfile_arch (objfile), pc));
+ struct compunit_symtab *stab_best = NULL;
+ struct dwarf2_per_cu_data *per_cu;
+ while ((per_cu = iter.next ()) != NULL)
+ {
+ struct symbol *sym, *with_opaque = NULL;
+ struct compunit_symtab *stab = dw2_instantiate_symtab (per_cu);
+ const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (stab);
+ struct block *block = BLOCKVECTOR_BLOCK (bv, block_index);
- result
- = recursively_find_pc_sect_compunit_symtab (dw2_instantiate_symtab (data),
- pc);
- gdb_assert (result != NULL);
- return result;
+ sym = block_find_symbol (block, name, domain,
+ block_find_non_opaque_type_preferred,
+ &with_opaque);
+
+ /* Some caution must be observed with overloaded functions
+ and methods, since the index will not contain any overload
+ information (but NAME might contain it). */
+
+ if (sym != NULL
+ && strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0)
+ return stab;
+ if (with_opaque != NULL
+ && strcmp_iw (SYMBOL_SEARCH_NAME (with_opaque), name) == 0)
+ stab_best = stab;
+
+ /* Keep looking through other CUs. */
+ }
+
+ return stab_best;
}
+/* This dumps minimal information about .debug_names.
+ It is called via "mt print objfiles".
+ One use is to verify .debug_names has been loaded by the
+ gdb.dwarf2/gdb-index.exp testcase. */
+
static void
-dw2_map_symbol_filenames (struct objfile *objfile, symbol_filename_ftype *fun,
- void *data, int need_fullname)
+dw2_debug_names_dump (struct objfile *objfile)
{
- int i;
- htab_up visited (htab_create_alloc (10, htab_hash_pointer, htab_eq_pointer,
- NULL, xcalloc, xfree));
-
dw2_setup (objfile);
+ gdb_assert (dwarf2_per_objfile->using_index);
+ printf_filtered (".debug_names:");
+ if (dwarf2_per_objfile->debug_names_table)
+ printf_filtered (" exists\n");
+ else
+ printf_filtered (" faked for \"readnow\"\n");
+ printf_filtered ("\n");
+}
- /* The rule is CUs specify all the files, including those used by
- any TU, so there's no need to scan TUs here.
- We can ignore file names coming from already-expanded CUs. */
+static void
+dw2_debug_names_expand_symtabs_for_function (struct objfile *objfile,
+ const char *func_name)
+{
+ struct mapped_index *index;
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ dw2_setup (objfile);
+
+ /* dwarf2_per_objfile->debug_names_table is NULL if OBJF_READNOW. */
+ if (dwarf2_per_objfile->debug_names_table)
{
- struct dwarf2_per_cu_data *per_cu = dw2_get_cutu (i);
+ const mapped_debug_names &map (*dwarf2_per_objfile->debug_names_table);
- if (per_cu->v.quick->compunit_symtab)
- {
- void **slot = htab_find_slot (visited.get (),
- per_cu->v.quick->file_names,
- INSERT);
+ /* Note: It doesn't matter what we pass for block_index here. */
+ dw2_debug_names_iterator iter (map, 0 /* want_specific_block */,
+ GLOBAL_BLOCK, VAR_DOMAIN, func_name);
- *slot = per_cu->v.quick->file_names;
- }
+ struct dwarf2_per_cu_data *per_cu;
+ while ((per_cu = iter.next ()) != NULL)
+ dw2_instantiate_symtab (per_cu);
}
+}
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+static void
+dw2_debug_names_expand_symtabs_matching
+ (struct objfile *objfile,
+ gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
+ gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
+ gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
+ enum search_domain kind)
+{
+ dw2_setup (objfile);
+
+ /* debug_names_table is NULL if OBJF_READNOW. */
+ if (!dwarf2_per_objfile->debug_names_table)
+ return;
+ const mapped_debug_names &map (*dwarf2_per_objfile->debug_names_table);
+
+ dw_expand_symtabs_matching_file_matcher (file_matcher);
+
+ for (uint32_t namei = 0; namei < map.name_count; ++namei)
{
- int j;
- struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
- struct quick_file_names *file_data;
- void **slot;
+ const char *name;
+ offset_type *vec, vec_len, vec_idx;
+ int global_seen = 0;
- /* We only need to look at symtabs not already expanded. */
- if (per_cu->v.quick->compunit_symtab)
- continue;
+ QUIT;
- file_data = dw2_get_file_names (per_cu);
- if (file_data == NULL)
+ const char *const namei_string (map.namei_to_name (namei));
+ if (!symbol_matcher (namei_string))
continue;
- slot = htab_find_slot (visited.get (), file_data, INSERT);
- if (*slot)
- {
- /* Already visited. */
- continue;
- }
- *slot = file_data;
-
- for (j = 0; j < file_data->num_file_names; ++j)
- {
- const char *this_real_name;
+ /* The name was matched, now expand corresponding CUs that were
+ marked. */
+ dw2_debug_names_iterator iter (map, kind, namei);
- if (need_fullname)
- this_real_name = dw2_get_real_path (objfile, file_data, j);
- else
- this_real_name = NULL;
- (*fun) (file_data->file_names[j], this_real_name, data);
- }
+ struct dwarf2_per_cu_data *per_cu;
+ while ((per_cu = iter.next ()) != NULL)
+ dw2_expand_symtabs_matching_one (per_cu, file_matcher,
+ expansion_notify);
}
}
-static int
-dw2_has_symbols (struct objfile *objfile)
-{
- return 1;
-}
-
-const struct quick_symbol_functions dwarf2_gdb_index_functions =
+const struct quick_symbol_functions dwarf2_debug_names_functions =
{
dw2_has_symbols,
dw2_find_last_source_symtab,
dw2_forget_cached_source_info,
dw2_map_symtabs_matching_filename,
- dw2_lookup_symbol,
+ dw2_debug_names_lookup_symbol,
dw2_print_stats,
- dw2_dump,
+ dw2_debug_names_dump,
dw2_relocate,
- dw2_expand_symtabs_for_function,
+ dw2_debug_names_expand_symtabs_for_function,
dw2_expand_all_symtabs,
dw2_expand_symtabs_with_fullname,
dw2_map_matching_symbols,
- dw2_expand_symtabs_matching,
+ dw2_debug_names_expand_symtabs_matching,
dw2_find_pc_sect_compunit_symtab,
dw2_map_symbol_filenames
};
@@ -4428,6 +5540,9 @@ dwarf2_initialize_objfile (struct objfile *objfile)
return elf_sym_fns_gdb_index;
}
+ if (dwarf2_read_debug_names (objfile))
+ return elf_sym_fns_debug_names;
+
if (dwarf2_read_index (objfile))
return elf_sym_fns_gdb_index;
@@ -22913,6 +24028,8 @@ dwarf2_free_objfile (struct objfile *objfile)
htab_delete (dwarf2_per_objfile->line_header_hash);
/* Everything else should be on the objfile obstack. */
+
+ delete dwarf2_per_objfile->debug_names_table;
}
/* A set of CU "per_cu" pointer, DIE offset, and GDB type pointer.
@@ -23881,7 +24998,7 @@ public:
const char *const name (it->first);
const unsigned char *const nameuc
(reinterpret_cast<const unsigned char *> (name));
- const uint32_t hash (djb_hash (nameuc));
+ const uint32_t hash (dwarf5_djb_hash (nameuc));
hash_it_pair hashitpair;
hashitpair.hash = hash;
hashitpair.it = it;
@@ -24261,19 +25378,6 @@ private:
m_name_table_entry_offs;
};
- /* Symbol name hashing function as specified by DWARF-5. */
- static uint32_t djb_hash (const unsigned char *str)
- {
- uint32_t hash = 5381;
- while (int c = *str++)
- {
- /* FIXME: std::bad_cast for: std::tolower (c, std::locale::classic ())
- FIXME: Is unicode supported for symbol names by GDB? */
- hash = hash * 33 + tolower (c);
- }
- return hash;
- }
-
/* Try to reconstruct original DWARF tag for given partial_symbol.
This function is not DWARF-5 compliant but it is sufficient for GDB
as a DWARF-5 index consumer. */
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 9ae0432..6f992d7 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -1431,6 +1431,23 @@ const struct sym_fns elf_sym_fns_gdb_index =
&dwarf2_gdb_index_functions
};
+/* The same as elf_sym_fns, but not registered and uses the
+ DWARF-specific .debug_names index rather than psymtab. */
+const struct sym_fns elf_sym_fns_debug_names =
+{
+ elf_new_init, /* init anything gbl to entire symab */
+ elf_symfile_init, /* read initial info, setup for sym_red() */
+ elf_symfile_read, /* read a symbol file into symtab */
+ NULL, /* sym_read_psymbols */
+ elf_symfile_finish, /* finished with file, cleanup */
+ default_symfile_offsets, /* Translate ext. to int. relocatin */
+ elf_symfile_segments, /* Get segment information from a file. */
+ NULL,
+ default_symfile_relocate, /* Relocate a debug section. */
+ &elf_probe_fns, /* sym_probe_fns */
+ &dwarf2_debug_names_functions
+};
+
/* STT_GNU_IFUNC resolver vector to be installed to gnu_ifunc_fns_p. */
static const struct gnu_ifunc_fns elf_gnu_ifunc_fns =
diff --git a/gdb/psymtab.h b/gdb/psymtab.h
index f0c9ae7..17ceb22 100644
--- a/gdb/psymtab.h
+++ b/gdb/psymtab.h
@@ -33,6 +33,7 @@ extern struct bcache *psymbol_bcache_get_bcache (struct psymbol_bcache *);
extern const struct quick_symbol_functions psym_functions;
extern const struct quick_symbol_functions dwarf2_gdb_index_functions;
+extern const struct quick_symbol_functions dwarf2_debug_names_functions;
/* Ensure that the partial symbols for OBJFILE have been loaded. If
VERBOSE is non-zero, then this will print a message when symbols
diff --git a/gdb/symfile.h b/gdb/symfile.h
index 8e51d41..847358f 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -606,6 +606,8 @@ struct dwarf2_debug_sections {
struct dwarf2_section_names frame;
struct dwarf2_section_names eh_frame;
struct dwarf2_section_names gdb_index;
+ struct dwarf2_section_names debug_names;
+ struct dwarf2_section_names debug_aranges;
/* This field has no meaning, but exists solely to catch changes to
this structure which are not reflected in some instance. */
int sentinel;
diff --git a/gdb/testsuite/gdb.base/maint.exp b/gdb/testsuite/gdb.base/maint.exp
index 782a21c..8e79451 100644
--- a/gdb/testsuite/gdb.base/maint.exp
+++ b/gdb/testsuite/gdb.base/maint.exp
@@ -91,8 +91,11 @@ if ![runto_main] then {
# If we're using .gdb_index there will be no psymtabs.
set have_gdb_index 0
-gdb_test_multiple "maint info sections .gdb_index" "check for .gdb_index" {
- -re ": .gdb_index.*$gdb_prompt $" {
+gdb_test_multiple "maint info sections .gdb_index .debug_names" "check for .gdb_index" {
+ -re ": \\.gdb_index .*\r\n$gdb_prompt $" {
+ set have_gdb_index 1
+ }
+ -re ": \\.debug_names .*\r\n$gdb_prompt $" {
set have_gdb_index 1
}
-re ".*$gdb_prompt $" {
diff --git a/gdb/testsuite/gdb.dlang/watch-loc.c b/gdb/testsuite/gdb.dlang/watch-loc.c
index 0ffc377..a1f3caa 100644
--- a/gdb/testsuite/gdb.dlang/watch-loc.c
+++ b/gdb/testsuite/gdb.dlang/watch-loc.c
@@ -34,3 +34,22 @@ main (void)
return _Dmain ();
}
+// .gdb_index contained this map but .debug_names is generated by GDB
+// while it depends on .debug_aranges generated by GCC.
+asm (
+" .pushsection .debug_aranges,\"\",@progbits \n"
+" .4byte .Laranges_end - .Laranges_start \n" // Length of Address Ranges Info
+".Laranges_start: \n"
+" .2byte 0x2 \n" // DWARF Version
+" .4byte 0 \n" // .Ldebug_info0 - Offset of Compilation Unit Info
+" .byte 4 \n" // Size of Address
+" .byte 0 \n" // Size of Segment Descriptor
+" .2byte 0 \n" // Pad to 16 byte boundary
+" .2byte 0 \n"
+" .4byte _Dmain \n" // Address
+" .4byte 0x1000 \n" // Length
+" .4byte 0 \n"
+" .4byte 0 \n"
+".Laranges_end: \n"
+" .popsection \n"
+);
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S b/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S
index 3bbd725..5a968bd 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S
+++ b/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S
@@ -57,6 +57,23 @@
.byte 0 /* End of children of CU */
.Lcu1_end:
+ // .gdb_index contained this map but .debug_names is generated by GDB
+ // while it depends on .debug_aranges generated by GCC.
+ .section .debug_aranges,"",@progbits
+ .4byte .Laranges_end - .Laranges_start // Length of Address Ranges Info
+.Laranges_start:
+ .2byte 0x2 // DWARF Version
+ .4byte 0 // .Ldebug_info0 - Offset of Compilation Unit Info
+ .byte PTRBITS / 8 // Size of Address
+ .byte 0 // Size of Segment Descriptor
+ .2byte 0 // Pad to 16 byte boundary
+ .2byte 0
+ PTRBYTE cu_text_start // Address
+ PTRBYTE 0x1000 // cu_text_end - cu_text_start // Length
+ PTRBYTE 0
+ PTRBYTE 0
+.Laranges_end:
+
/* Abbrev table */
.section .debug_abbrev
.Labbrev1_begin:
diff --git a/gdb/testsuite/gdb.dwarf2/gdb-index.exp b/gdb/testsuite/gdb.dwarf2/gdb-index.exp
index c925b1e..54725cd 100644
--- a/gdb/testsuite/gdb.dwarf2/gdb-index.exp
+++ b/gdb/testsuite/gdb.dwarf2/gdb-index.exp
@@ -67,6 +67,9 @@ gdb_test_multiple "mt print objfiles ${testfile}" $test {
-re "gdb_index.*${gdb_prompt} $" {
set binfile_with_index $binfile
}
+ -re "debug_names.*${gdb_prompt} $" {
+ set binfile_with_index $binfile
+ }
-re "Psymtabs.*${gdb_prompt} $" {
set binfile_with_index [add_gdb_index $binfile]
if { ${binfile_with_index} == "" } {
@@ -80,7 +83,7 @@ gdb_test_multiple "mt print objfiles ${testfile}" $test {
clean_restart ${binfile_with_index}
gdb_test "mt print objfiles ${testfile}" \
- "gdb_index.*" \
+ "(gdb_index|debug_names).*" \
".gdb_index used"
# Make gdb re-read symbols and see if .gdb_index still gets used.
@@ -98,5 +101,5 @@ if ![runto_main] {
return -1
}
gdb_test "mt print objfiles ${testfile}" \
- "gdb_index.*" \
+ "(gdb_index|debug_names).*" \
".gdb_index used after symbol reloading"
diff --git a/gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c b/gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c
index 0c2a153..bf1fea6 100644
--- a/gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c
+++ b/gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c
@@ -52,3 +52,23 @@ asm ("func_loopfb_end:");
asm (".globl cu_text_end");
asm ("cu_text_end:");
+
+// .gdb_index contained this map but .debug_names is generated by GDB
+// while it depends on .debug_aranges generated by GCC.
+asm (
+" .pushsection .debug_aranges,\"\",@progbits \n"
+" .4byte .Laranges_end - .Laranges_start \n" // Length of Address Ranges Info
+".Laranges_start: \n"
+" .2byte 0x2 \n" // DWARF Version
+" .4byte 0 \n" // .Ldebug_info0 - Offset of Compilation Unit Info
+" .byte 4 \n" // Size of Address
+" .byte 0 \n" // Size of Segment Descriptor
+" .2byte 0 \n" // Pad to 16 byte boundary
+" .2byte 0 \n"
+" .4byte cu_text_start \n" // Address
+" .4byte cu_text_end - cu_text_start \n" // Length
+" .4byte 0 \n"
+" .4byte 0 \n"
+".Laranges_end: \n"
+" .popsection \n"
+);
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 138f941..e6298b4 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -174,6 +174,8 @@ static const struct dwarf2_debug_sections dwarf2_xcoff_names = {
{ ".dwframe", NULL },
{ NULL, NULL }, /* eh_frame */
{ NULL, NULL }, /* gdb_index */
+ { NULL, NULL }, /* debug_names */
+ { NULL, NULL }, /* debug_aranges */
23
};
^ permalink raw reply [flat|nested] 7+ messages in thread