[Note that the test doesn't currently work, because build_executable_from_specs
doesn't like relative src names for some reason. However, to be a good
test it really needs a relative name due to
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91888. I will work on this
once I get some feedback on the general idea of this patch.]
This implements this DWARF feature request:
http://dwarfstd.org/ShowIssue.php?issue=171130.2
With reproducible builds and with build output caching, it is
desirable to have the build output be independent of the
build environment. GCC's -fdebug-prefix-map allows setting
the comp dir to a different value. But the obvious choice,
i.e. ".", has the downside that GCC will not find DWOs/
source code when $PWD is outside of the build output directory.
So, this patch allows specifying something like
-fdebug-prefix-map=/output/dir=\$ORIGIN, and GDB will find things
correctly, even when $PWD is not the output directory.
---
gdb/dwarf2read.c | 41 ++++++++++++++++---
.../gdb.dwarf2/fission-origin-comp-dir.c | 11 +++++
.../gdb.dwarf2/fission-origin-comp-dir.exp | 39 ++++++++++++++++++
3 files changed, 86 insertions(+), 5 deletions(-)
create mode 100644 gdb/testsuite/gdb.dwarf2/fission-origin-comp-dir.c
create mode 100644 gdb/testsuite/gdb.dwarf2/fission-origin-comp-dir.exp
@@ -88,6 +88,7 @@
#include <cmath>
#include <set>
#include <forward_list>
+#include <regex>
#include "rust-lang.h"
#include "gdbsupport/pathstuff.h"
@@ -1775,6 +1776,8 @@ static const char *dwarf_bool_name (unsigned int);
static const char *dwarf_type_encoding_name (unsigned int);
+static const char *dwarf2_comp_dir (struct die_info *die, struct dwarf2_cu *cu);
+
static struct die_info *sibling_die (struct die_info *);
static void dump_die_shallow (struct ui_file *, int indent, struct die_info *);
@@ -7211,6 +7214,7 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data *this_cu,
high_pc = NULL;
ranges = NULL;
comp_dir = NULL;
+ const char *comp_dir_str = NULL;
if (stub_comp_unit_die != NULL)
{
@@ -7221,7 +7225,7 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data *this_cu,
low_pc = dwarf2_attr (stub_comp_unit_die, DW_AT_low_pc, cu);
high_pc = dwarf2_attr (stub_comp_unit_die, DW_AT_high_pc, cu);
ranges = dwarf2_attr (stub_comp_unit_die, DW_AT_ranges, cu);
- comp_dir = dwarf2_attr (stub_comp_unit_die, DW_AT_comp_dir, cu);
+ comp_dir_str = dwarf2_comp_dir (stub_comp_unit_die, cu);
/* There should be a DW_AT_addr_base attribute here (if needed).
We need the value before we can process DW_FORM_GNU_addr_index
@@ -7239,13 +7243,15 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data *this_cu,
cu->ranges_base = DW_UNSND (attr);
}
else if (stub_comp_dir != NULL)
+ comp_dir_str = stub_comp_dir;
+ if (comp_dir_str != nullptr)
{
/* Reconstruct the comp_dir attribute to simplify the code below. */
comp_dir = XOBNEW (&cu->comp_unit_obstack, struct attribute);
comp_dir->name = DW_AT_comp_dir;
comp_dir->form = DW_FORM_string;
DW_STRING_IS_CANONICAL (comp_dir) = 0;
- DW_STRING (comp_dir) = stub_comp_dir;
+ DW_STRING (comp_dir) = comp_dir_str;
}
/* Set up for reading the DWO CU/TU. */
@@ -7388,7 +7394,7 @@ lookup_dwo_unit (struct dwarf2_per_cu_data *this_cu,
/* Yeah, we look dwo_name up again, but it simplifies the code. */
dwo_name = dwarf2_dwo_name (comp_unit_die, cu);
- comp_dir = dwarf2_string_attr (comp_unit_die, DW_AT_comp_dir, cu);
+ comp_dir = dwarf2_comp_dir (comp_unit_die, cu);
if (this_cu->is_debug_types)
{
@@ -8024,7 +8030,7 @@ process_psymtab_comp_unit_reader (const struct die_reader_specs *reader,
pst = create_partial_symtab (per_cu, filename);
/* This must be done before calling dwarf2_build_include_psymtabs. */
- pst->dirname = dwarf2_string_attr (comp_unit_die, DW_AT_comp_dir, cu);
+ pst->dirname = dwarf2_comp_dir (comp_unit_die, cu);
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
@@ -11414,7 +11420,7 @@ find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu)
/* Find the filename. Do not use dwarf2_name here, since the filename
is not a source language identifier. */
res.name = dwarf2_string_attr (die, DW_AT_name, cu);
- res.comp_dir = dwarf2_string_attr (die, DW_AT_comp_dir, cu);
+ res.comp_dir = dwarf2_comp_dir (die, cu);
if (res.comp_dir == NULL
&& producer_is_gcc_lt_4_3 (cu) && res.name != NULL
@@ -20181,6 +20187,31 @@ dwarf2_string_attr (struct die_info *die, unsigned int name, struct dwarf2_cu *c
return str;
}
+/* Returns the DW_AT_comp_dir attribute, with $ORIGIN replaced as necessary.
+ Returns the empty string if there is no DW_AT_comp_dir attribute. */
+static const char *
+dwarf2_comp_dir (struct die_info *die, struct dwarf2_cu *cu)
+{
+ static const char origin_str[] = "$ORIGIN";
+ static constexpr size_t origin_str_len = sizeof(origin_str) - 1;
+
+ const char* comp_dir = dwarf2_string_attr (die, DW_AT_comp_dir, cu);
+ if (comp_dir == nullptr)
+ return nullptr;
+
+ std::string comp_dir_str = comp_dir;
+ if (comp_dir_str.substr (0, origin_str_len) != origin_str)
+ return comp_dir;
+
+ struct objfile *objfile = cu->per_cu->dwarf2_per_objfile->objfile;
+ std::string replaced
+ = ldirname (objfile_name (objfile)) + comp_dir_str.substr (origin_str_len);
+ char *alloc = (char *) obstack_alloc (&objfile->objfile_obstack,
+ replaced.length () + 1);
+ memcpy (alloc, replaced.c_str (), replaced.length () + 1);
+ return alloc;
+}
+
/* Return the dwo name or NULL if not present. If present, it is in either
DW_AT_GNU_dwo_name or DW_AT_dwo_name atrribute. */
static const char *
new file mode 100644
@@ -0,0 +1,11 @@
+static int func2(void) {
+ return 42;
+}
+
+int
+main (void)
+{
+ int val = func2();
+ return val;
+}
+
new file mode 100644
@@ -0,0 +1,39 @@
+# Copyright 2013-2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2.
+if ![dwarf2_support] {
+ return 0
+}
+
+standard_testfile
+
+set pwd [exec pwd -P]
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile \
+ [list additional_flags=-gsplit-dwarf additional_flags=-fdebug-prefix-map=$pwd=\\\$ORIGIN]] } {
+ return -1
+}
+
+clean_restart $binfile
+gdb_reinitialize_dir "/NoNeXiStInG"
+
+runto_main
+
+gdb_test_no_output "next"
+gdb_test "p val" "42"
+gdb_test "break func2" "Breakpoint .*"