diff options
-rw-r--r-- | gdb/ChangeLog | 23 | ||||
-rw-r--r-- | gdb/dwarf-index-cache.c | 31 | ||||
-rw-r--r-- | gdb/dwarf-index-write.c | 272 | ||||
-rw-r--r-- | gdb/dwarf-index-write.h | 13 | ||||
-rw-r--r-- | gdb/dwarf2read.c | 32 | ||||
-rw-r--r-- | gdb/dwarf2read.h | 38 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gdb/testsuite/gdb.dwarf2/gdb-index.exp | 15 |
8 files changed, 280 insertions, 150 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 1cf2b9bcdc8..ef62a4e6295 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,26 @@ +2019-06-16 Simon Marchi <simon.marchi@polymtl.ca> + + PR gdb/24445 + * dwarf-index-write.h (write_psymtabs_to_index): Add + dwz_basename parameter. + * dwarf-index-write.c (write_gdbindex): Move file writing to + write_gdbindex_1. Change return type void. + (assert_file_size): Move up, remove filename parameter. + (write_gdbindex_1): New function. + (write_debug_names): Change return type to void, call + assert_file_size. + (struct index_wip_file): New struct. + (write_psymtabs_to_index): Add dwz_basename parameter. Move + file logic to index_wip_file. Write index for dwz file if + needed. + (save_gdb_index_command): Pass basename of dwz file, if present. + * dwarf-index-cache.c (index_cache::store): Obtain and pass + build-id of dwz file, if present. + * dwarf2read.c (struct dwz_file): Move to dwarf2read.h. + (dwarf2_get_dwz_file): Likewise. + * dwarf2read.h (struct dwz_file): Move from dwarf2read.c. + (dwarf2_get_dwz_file): Likewise. + 2019-06-16 Tom Tromey <tom@tromey.com> * coffread.c (process_coff_symbol): Use xstrdup. diff --git a/gdb/dwarf-index-cache.c b/gdb/dwarf-index-cache.c index 7222f0528d7..d0179014935 100644 --- a/gdb/dwarf-index-cache.c +++ b/gdb/dwarf-index-cache.c @@ -93,6 +93,7 @@ index_cache::store (struct dwarf2_per_objfile *dwarf2_per_objfile) if (!enabled ()) return; + /* Get build id of objfile. */ const bfd_build_id *build_id = build_id_bfd_get (obj->obfd); if (build_id == nullptr) { @@ -102,14 +103,35 @@ index_cache::store (struct dwarf2_per_objfile *dwarf2_per_objfile) return; } + std::string build_id_str = build_id_to_string (build_id); + + /* Get build id of dwz file, if present. */ + gdb::optional<std::string> dwz_build_id_str; + const dwz_file *dwz = dwarf2_get_dwz_file (dwarf2_per_objfile); + const char *dwz_build_id_ptr = NULL; + + if (dwz != nullptr) + { + const bfd_build_id *dwz_build_id = build_id_bfd_get (dwz->dwz_bfd.get ()); + + if (dwz_build_id == nullptr) + { + if (debug_index_cache) + printf_unfiltered ("index cache: dwz objfile %s has no build id\n", + dwz->filename ()); + return; + } + + dwz_build_id_str = build_id_to_string (dwz_build_id); + dwz_build_id_ptr = dwz_build_id_str->c_str (); + } + if (m_dir.empty ()) { warning (_("The index cache directory name is empty, skipping store.")); return; } - std::string build_id_str = build_id_to_string (build_id); - try { /* Try to create the containing directory. */ @@ -122,12 +144,13 @@ index_cache::store (struct dwarf2_per_objfile *dwarf2_per_objfile) if (debug_index_cache) printf_unfiltered ("index cache: writing index cache for objfile %s\n", - objfile_name (obj)); + objfile_name (obj)); /* Write the index itself to the directory, using the build id as the filename. */ write_psymtabs_to_index (dwarf2_per_objfile, m_dir.c_str (), - build_id_str.c_str (), dw_index_kind::GDB_INDEX); + build_id_str.c_str (), dwz_build_id_ptr, + dw_index_kind::GDB_INDEX); } catch (const gdb_exception_error &except) { diff --git a/gdb/dwarf-index-write.c b/gdb/dwarf-index-write.c index 8734f99212d..9979ae44402 100644 --- a/gdb/dwarf-index-write.c +++ b/gdb/dwarf-index-write.c @@ -1289,15 +1289,81 @@ psyms_seen_size (struct dwarf2_per_objfile *dwarf2_per_objfile) return psyms_count / 4; } -/* Write new .gdb_index section for OBJFILE into OUT_FILE. - Return how many bytes were expected to be written into OUT_FILE. */ +/* Assert that FILE's size is EXPECTED_SIZE. Assumes file's seek + position is at the end of the file. */ -static size_t -write_gdbindex (struct dwarf2_per_objfile *dwarf2_per_objfile, FILE *out_file) +static void +assert_file_size (FILE *file, size_t expected_size) +{ + const auto file_size = ftell (file); + if (file_size == -1) + perror_with_name (("ftell")); + gdb_assert (file_size == expected_size); +} + +/* Write a gdb index file to OUT_FILE from all the sections passed as + arguments. */ + +static void +write_gdbindex_1 (FILE *out_file, + const data_buf &cu_list, + const data_buf &types_cu_list, + const data_buf &addr_vec, + const data_buf &symtab_vec, + const data_buf &constant_pool) +{ + data_buf contents; + const offset_type size_of_header = 6 * sizeof (offset_type); + offset_type total_len = size_of_header; + + /* The version number. */ + contents.append_data (MAYBE_SWAP (8)); + + /* The offset of the CU list from the start of the file. */ + contents.append_data (MAYBE_SWAP (total_len)); + total_len += cu_list.size (); + + /* The offset of the types CU list from the start of the file. */ + contents.append_data (MAYBE_SWAP (total_len)); + total_len += types_cu_list.size (); + + /* The offset of the address table from the start of the file. */ + contents.append_data (MAYBE_SWAP (total_len)); + total_len += addr_vec.size (); + + /* The offset of the symbol table from the start of the file. */ + contents.append_data (MAYBE_SWAP (total_len)); + total_len += symtab_vec.size (); + + /* The offset of the constant pool from the start of the file. */ + contents.append_data (MAYBE_SWAP (total_len)); + total_len += constant_pool.size (); + + gdb_assert (contents.size () == size_of_header); + + contents.file_write (out_file); + cu_list.file_write (out_file); + types_cu_list.file_write (out_file); + addr_vec.file_write (out_file); + symtab_vec.file_write (out_file); + constant_pool.file_write (out_file); + + assert_file_size (out_file, total_len); +} + +/* Write contents of a .gdb_index section for OBJFILE into OUT_FILE. + If OBJFILE has an associated dwz file, write contents of a .gdb_index + section for that dwz file into DWZ_OUT_FILE. If OBJFILE does not have an + associated dwz file, DWZ_OUT_FILE must be NULL. */ + +static void +write_gdbindex (struct dwarf2_per_objfile *dwarf2_per_objfile, FILE *out_file, + FILE *dwz_out_file) { struct objfile *objfile = dwarf2_per_objfile->objfile; mapped_symtab symtab; - data_buf cu_list; + data_buf objfile_cu_list; + data_buf dwz_cu_list; /* While we're scanning CU's create a table that maps a psymtab pointer (which is what addrmap records) to its index (which is what is recorded @@ -1331,6 +1397,10 @@ write_gdbindex (struct dwarf2_per_objfile *dwarf2_per_objfile, FILE *out_file) const auto insertpair = cu_index_htab.emplace (psymtab, i); gdb_assert (insertpair.second); + /* The all_comp_units list contains CUs read from the objfile as well as + from the eventual dwz file. We need to place the entry in the + corresponding index. */ + data_buf &cu_list = per_cu->is_dwz ? dwz_cu_list : objfile_cu_list; cu_list.append_uint (8, BFD_ENDIAN_LITTLE, to_underlying (per_cu->sect_off)); cu_list.append_uint (8, BFD_ENDIAN_LITTLE, per_cu->length); @@ -1361,43 +1431,13 @@ write_gdbindex (struct dwarf2_per_objfile *dwarf2_per_objfile, FILE *out_file) data_buf symtab_vec, constant_pool; write_hash_table (&symtab, symtab_vec, constant_pool); - data_buf contents; - const offset_type size_of_contents = 6 * sizeof (offset_type); - offset_type total_len = size_of_contents; - - /* The version number. */ - contents.append_data (MAYBE_SWAP (8)); - - /* The offset of the CU list from the start of the file. */ - contents.append_data (MAYBE_SWAP (total_len)); - total_len += cu_list.size (); - - /* The offset of the types CU list from the start of the file. */ - contents.append_data (MAYBE_SWAP (total_len)); - total_len += types_cu_list.size (); + write_gdbindex_1(out_file, objfile_cu_list, types_cu_list, addr_vec, + symtab_vec, constant_pool); - /* The offset of the address table from the start of the file. */ - contents.append_data (MAYBE_SWAP (total_len)); - total_len += addr_vec.size (); - - /* The offset of the symbol table from the start of the file. */ - contents.append_data (MAYBE_SWAP (total_len)); - total_len += symtab_vec.size (); - - /* The offset of the constant pool from the start of the file. */ - contents.append_data (MAYBE_SWAP (total_len)); - total_len += constant_pool.size (); - - gdb_assert (contents.size () == size_of_contents); - - contents.file_write (out_file); - cu_list.file_write (out_file); - types_cu_list.file_write (out_file); - addr_vec.file_write (out_file); - symtab_vec.file_write (out_file); - constant_pool.file_write (out_file); - - return total_len; + if (dwz_out_file != NULL) + write_gdbindex_1 (dwz_out_file, dwz_cu_list, {}, {}, {}, {}); + else + gdb_assert (dwz_cu_list.empty ()); } /* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension. */ @@ -1407,7 +1447,7 @@ static const gdb_byte dwarf5_gdb_augmentation[] = { 'G', 'D', 'B', 0 }; 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 +static void write_debug_names (struct dwarf2_per_objfile *dwarf2_per_objfile, FILE *out_file, FILE *out_file_str) { @@ -1528,26 +1568,69 @@ write_debug_names (struct dwarf2_per_objfile *dwarf2_per_objfile, types_cu_list.file_write (out_file); nametable.file_write (out_file, out_file_str); - return expected_bytes; + assert_file_size (out_file, expected_bytes); } -/* Assert that FILE's size is EXPECTED_SIZE. Assumes file's seek - position is at the end of the file. */ +/* This represents an index file being written (work-in-progress). -static void -assert_file_size (FILE *file, const char *filename, size_t expected_size) + The data is initially written to a temporary file. When the finalize method + is called, the file is closed and moved to its final location. + + On failure (if this object is being destroyed with having called finalize), + the temporary file is closed and deleted. */ + +struct index_wip_file { - const auto file_size = ftell (file); - if (file_size == -1) - error (_("Can't get `%s' size"), filename); - gdb_assert (file_size == expected_size); -} + index_wip_file (const char *dir, const char *basename, + const char *suffix) + { + filename = (std::string (dir) + SLASH_STRING + basename + + suffix); + + filename_temp = make_temp_filename (filename); + + scoped_fd out_file_fd (gdb_mkostemp_cloexec (filename_temp.data (), + O_BINARY)); + if (out_file_fd.get () == -1) + perror_with_name (("mkstemp")); + + out_file = out_file_fd.to_file ("wb"); + + if (out_file == nullptr) + error (_("Can't open `%s' for writing"), filename_temp.data ()); + + unlink_file.emplace (filename_temp.data ()); + } + + void finalize () + { + /* We want to keep the file. */ + unlink_file->keep (); + + /* Close and move the str file in place. */ + unlink_file.reset (); + if (rename (filename_temp.data (), filename.c_str ()) != 0) + perror_with_name (("rename")); + } + + std::string filename; + gdb::char_vector filename_temp; + + /* Order matters here; we want FILE to be closed before + FILENAME_TEMP is unlinked, because on MS-Windows one cannot + delete a file that is still open. So, we wrap the unlinker in an + optional and emplace it once we know the file name. */ + gdb::optional<gdb::unlinker> unlink_file; + + gdb_file_up out_file; +}; /* See dwarf-index-write.h. */ void write_psymtabs_to_index (struct dwarf2_per_objfile *dwarf2_per_objfile, const char *dir, const char *basename, + const char *dwz_basename, dw_index_kind index_kind) { struct objfile *objfile = dwarf2_per_objfile->objfile; @@ -1566,74 +1649,33 @@ write_psymtabs_to_index (struct dwarf2_per_objfile *dwarf2_per_objfile, if (stat (objfile_name (objfile), &st) < 0) perror_with_name (objfile_name (objfile)); - std::string filename (std::string (dir) + SLASH_STRING + basename - + (index_kind == dw_index_kind::DEBUG_NAMES - ? INDEX5_SUFFIX : INDEX4_SUFFIX)); - gdb::char_vector filename_temp = make_temp_filename (filename); + const char *index_suffix = (index_kind == dw_index_kind::DEBUG_NAMES + ? INDEX5_SUFFIX : INDEX4_SUFFIX); - /* Order matters here; we want FILE to be closed before - FILENAME_TEMP is unlinked, because on MS-Windows one cannot - delete a file that is still open. So, we wrap the unlinker in an - optional and emplace it once we know the file name. */ - gdb::optional<gdb::unlinker> unlink_file; - scoped_fd out_file_fd (gdb_mkostemp_cloexec (filename_temp.data (), - O_BINARY)); - if (out_file_fd.get () == -1) - perror_with_name (("mkstemp")); + index_wip_file objfile_index_wip (dir, basename, index_suffix); + gdb::optional<index_wip_file> dwz_index_wip; - gdb_file_up out_file = out_file_fd.to_file ("wb"); - if (out_file == nullptr) - error (_("Can't open `%s' for writing"), filename_temp.data ()); - - unlink_file.emplace (filename_temp.data ()); + if (dwz_basename != NULL) + dwz_index_wip.emplace (dir, dwz_basename, index_suffix); if (index_kind == dw_index_kind::DEBUG_NAMES) { - std::string filename_str (std::string (dir) + SLASH_STRING - + basename + DEBUG_STR_SUFFIX); - gdb::char_vector filename_str_temp = make_temp_filename (filename_str); - - /* As above, arrange to unlink the file only after the file - descriptor has been closed. */ - gdb::optional<gdb::unlinker> unlink_file_str; - scoped_fd out_file_str_fd - (gdb_mkostemp_cloexec (filename_str_temp.data (), O_BINARY)); - if (out_file_str_fd.get () == -1) - perror_with_name (("mkstemp")); - - gdb_file_up out_file_str = out_file_str_fd.to_file ("wb"); - if (out_file_str == nullptr) - error (_("Can't open `%s' for writing"), filename_str_temp.data ()); - - unlink_file_str.emplace (filename_str_temp.data ()); - - const size_t total_len - = write_debug_names (dwarf2_per_objfile, out_file.get (), - out_file_str.get ()); - assert_file_size (out_file.get (), filename_temp.data (), total_len); - - /* We want to keep the file .debug_str file too. */ - unlink_file_str->keep (); - - /* Close and move the str file in place. */ - out_file_str.reset (); - if (rename (filename_str_temp.data (), filename_str.c_str ()) != 0) - perror_with_name (("rename")); + index_wip_file str_wip_file (dir, basename, DEBUG_STR_SUFFIX); + + write_debug_names (dwarf2_per_objfile, objfile_index_wip.out_file.get (), + str_wip_file.out_file.get ()); + + str_wip_file.finalize (); } else - { - const size_t total_len - = write_gdbindex (dwarf2_per_objfile, out_file.get ()); - assert_file_size (out_file.get (), filename_temp.data (), total_len); - } + write_gdbindex (dwarf2_per_objfile, objfile_index_wip.out_file.get (), + (dwz_index_wip.has_value () + ? dwz_index_wip->out_file.get () : NULL)); - /* We want to keep the file. */ - unlink_file->keep (); + objfile_index_wip.finalize (); - /* Close and move the file in place. */ - out_file.reset (); - if (rename (filename_temp.data (), filename.c_str ()) != 0) - perror_with_name (("rename")); + if (dwz_index_wip.has_value ()) + dwz_index_wip->finalize (); } /* Implementation of the `save gdb-index' command. @@ -1678,8 +1720,14 @@ save_gdb_index_command (const char *arg, int from_tty) try { const char *basename = lbasename (objfile_name (objfile)); + const dwz_file *dwz = dwarf2_get_dwz_file (dwarf2_per_objfile); + const char *dwz_basename = NULL; + + if (dwz != NULL) + dwz_basename = lbasename (dwz->filename ()); + write_psymtabs_to_index (dwarf2_per_objfile, arg, basename, - index_kind); + dwz_basename, index_kind); } catch (const gdb_exception_error &except) { diff --git a/gdb/dwarf-index-write.h b/gdb/dwarf-index-write.h index b1d1180c8e3..a8874c86438 100644 --- a/gdb/dwarf-index-write.h +++ b/gdb/dwarf-index-write.h @@ -23,12 +23,17 @@ #include "symfile.h" #include "dwarf2read.h" -/* Create an index file for OBJFILE in the directory DIR. BASENAME is the - desired filename, minus the extension, which gets added by this function - based on INDEX_KIND. */ +/* Create index files for OBJFILE in the directory DIR. + + An index file is created for OBJFILE itself, and is created for its + associated dwz file, if it has one. + + BASENAME is the desired filename base for OBJFILE's index. An extension + derived from INDEX_KIND is added to this base name. DWZ_BASENAME is the + same, but for the dwz file's index. */ extern void write_psymtabs_to_index (struct dwarf2_per_objfile *dwarf2_per_objfile, const char *dir, - const char *basename, dw_index_kind index_kind); + const char *basename, const char *dwz_basename, dw_index_kind index_kind); #endif /* DWARF_INDEX_WRITE_H */ diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 4cf9fcfa218..a51ae49e870 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -875,32 +875,6 @@ struct dwp_file asection **elf_sections = nullptr; }; -/* This represents a '.dwz' file. */ - -struct dwz_file -{ - dwz_file (gdb_bfd_ref_ptr &&bfd) - : dwz_bfd (std::move (bfd)) - { - } - - /* A dwz file can only contain a few sections. */ - struct dwarf2_section_info abbrev {}; - struct dwarf2_section_info info {}; - struct dwarf2_section_info str {}; - 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. */ - gdb_bfd_ref_ptr dwz_bfd; - - /* If we loaded the index from an external file, this contains the - resources associated to the open file, memory mapping, etc. */ - std::unique_ptr<index_cache_resource> index_cache_res; -}; - /* Struct used to pass misc. parameters to read_die_and_children, et al. which are used for both .debug_info and .debug_types dies. All parameters here are unchanging for the life of the call. This @@ -2668,11 +2642,9 @@ locate_dwz_sections (bfd *abfd, asection *sectp, void *arg) } } -/* Open the separate '.dwz' debug file, if needed. Return NULL if - there is no .gnu_debugaltlink section in the file. Error if there - is such a section but the file cannot be found. */ +/* See dwarf2read.h. */ -static struct dwz_file * +struct dwz_file * dwarf2_get_dwz_file (struct dwarf2_per_objfile *dwarf2_per_objfile) { const char *filename; diff --git a/gdb/dwarf2read.h b/gdb/dwarf2read.h index 732654348a8..e8658950e36 100644 --- a/gdb/dwarf2read.h +++ b/gdb/dwarf2read.h @@ -405,4 +405,42 @@ DEF_VEC_P (sig_type_ptr); ULONGEST read_unsigned_leb128 (bfd *, const gdb_byte *, unsigned int *); +/* This represents a '.dwz' file. */ + +struct dwz_file +{ + dwz_file (gdb_bfd_ref_ptr &&bfd) + : dwz_bfd (std::move (bfd)) + { + } + + const char *filename () const + { + return bfd_get_filename (this->dwz_bfd); + } + + /* A dwz file can only contain a few sections. */ + struct dwarf2_section_info abbrev {}; + struct dwarf2_section_info info {}; + struct dwarf2_section_info str {}; + 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. */ + gdb_bfd_ref_ptr dwz_bfd; + + /* If we loaded the index from an external file, this contains the + resources associated to the open file, memory mapping, etc. */ + std::unique_ptr<index_cache_resource> index_cache_res; +}; + +/* Open the separate '.dwz' debug file, if needed. Return NULL if + there is no .gnu_debugaltlink section in the file. Error if there + is such a section but the file cannot be found. */ + +extern struct dwz_file *dwarf2_get_dwz_file + (struct dwarf2_per_objfile *dwarf2_per_objfile); + #endif /* DWARF2READ_H */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 543865765a2..d1558f37894 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-06-16 Tom de Vries <tdevries@suse.de> + + PR gdb/24445 + * gdb.dwarf2/gdb-index.exp (add_gdb_index): Update dwz file with + generated index. + 2019-06-16 Andrew Burgess <andrew.burgess@embecosm.com> PR gdb/24686 diff --git a/gdb/testsuite/gdb.dwarf2/gdb-index.exp b/gdb/testsuite/gdb.dwarf2/gdb-index.exp index 410e59684f3..6fca3c61299 100644 --- a/gdb/testsuite/gdb.dwarf2/gdb-index.exp +++ b/gdb/testsuite/gdb.dwarf2/gdb-index.exp @@ -34,8 +34,11 @@ if { [prepare_for_testing "failed to prepare" "${testfile}" \ proc add_gdb_index { program } { set index_file ${program}.gdb-index + set dwz ${program}.dwz + set dwz_index_file ${dwz}.gdb-index verbose -log "index_file: ${index_file}" remote_file host delete ${index_file} + remote_file host delete ${dwz_index_file} gdb_test_no_output "save gdb-index [file dirname ${index_file}]" \ "save gdb-index for file [file tail ${program}]" @@ -55,6 +58,18 @@ proc add_gdb_index { program } { if {[run_on_host "objcopy" [gdb_find_objcopy] "--remove-section .gdb_index --add-section .gdb_index=$index_file --set-section-flags .gdb_index=readonly ${program} ${program_with_index}"]} { return "" } + + if { [remote_file host exists ${dwz_index_file}] } { + # We're modifying $dwz in place, otherwise we'd have to update + # .gnu_debugaltlink in $program. + set args [join [list "--remove-section .gdb_index" \ + " --add-section .gdb_index=$dwz_index_file" \ + " --set-section-flags .gdb_index=readonly $dwz"]] + if {[run_on_host "objcopy" [gdb_find_objcopy] "$args"]} { + return "" + } + } + return ${program_with_index} } |