Re: [patch] GDB 7.2: new feature for "backtrace" that cuts path to file (remain filename)

Jan Kratochvil
2012-04-06T14:22:20Z

On Sun, 18 Mar 2012 19:34:54 +0100, Jan Kratochvil wrote:
> On Sun, 18 Mar 2012 19:30:17 +0100, iam ahal wrote:
> > I've included absolute filename option to my patch.
>
> Could you check FAILs of that testcase by me? There are probably some GDB
> bugs but I did not get back to it yet.

I have changed the patch functionality a bit primarily due to revert of the
patch as described in:
Re: [commit] Handle files without DW_AT_comp_dir
http://sourceware.org/ml/gdb-patches/2012-04/msg00105.html

Does it provide the functionality you need with this patch? If not, could you
provide your binary file and expected output?

No regressions on {x86_64,x86_64-m32,i686}-fedora17-linux-gnu.

Thanks,
Jan

gdb/
2012-04-06 Eldar Gaynetdinov <hal9000ed2k@gmail.com>
Jan Kratochvil <jan.kratochvil@redhat.com>

Add a new variable that controls a way in which filenames in
backtraces is displayed.
* NEWS (set backtrace filename-display): New entry.
* dwarf2read.c (find_file_and_directory): Remove *COMP_DIR guessing
from *NAME.
* frame.c: Include filenames.h and source.h.
(filename_display_basename, filename_display_relative)
(filename_display_absolute, filename_display_kind_names)
(filename_display_string, show_filename_display_string)
(get_filename_display_from_sal): New.
(_initialize_frame): Added initialization of 'filename-display'
variable.
* frame.h (get_filename_display_from_sal): Added declaration.
* stack.c (print_frame): Added new variable and calling of a new
function and condition with this variable. Changed third argument of
calling of a function.

gdb/doc/
2012-04-06 Eldar Gaynetdinov <hal9000ed2k@gmail.com>
Jan Kratochvil <jan.kratochvil@redhat.com>

* gdb.texinfo (Backtrace): Added description of 'filename-display'
variable in 'set/show backtrace' section.

gdb/testsuite/
2012-04-06 Jan Kratochvil <jan.kratochvil@redhat.com>

* gdb.dwarf2/dw2-dir-file-name.exp: New file.
* gdb.dwarf2/dw2-dir-file-name.c: New file.

--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -114,6 +114,10 @@ show breakpoint condition-evaluation
This option can improve debugger efficiency depending on the speed of the
target.

+set backtrace filename-display basename|relative|absolute
+show backtrace filename-display
+ Control the way in which filenames is displayed in backtraces.
+
* New remote packets

z0/z1 conditional breakpoints extension
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6301,6 +6301,27 @@ unlimited.
Display the current limit on backtrace levels.
@end table

+If backtraces isn't easy to read due to a long absolute filename record and
+you just want to see only a basename or a relative filename,
+you can change this behavior:
+
+@table @code
+@item set backtrace filename-display
+@itemx set backtrace filename-display relative
+@cindex backtrace filename-display
+Display a filename without the compilation directory part. This is the
+default.
+
+@item set backtrace filename-display basename
+Display only basename of a filename.
+
+@item set backtrace filename-display absolute
+Display an absolute filename.
+
+@item show backtrace filename-display
+Show the current way to display a filename in backtraces.
+@end table
+
@node Selection
@section Selecting a Frame

--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -5589,12 +5589,12 @@ find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu,
attr = dwarf2_attr (die, DW_AT_comp_dir, cu);
if (attr)
*comp_dir = DW_STRING (attr);
- else if (*name != NULL && IS_ABSOLUTE_PATH (*name))
+ else
{
- *comp_dir = ldirname (*name);
- if (*comp_dir != NULL)
- make_cleanup (xfree, *comp_dir);
+ /* Do not try to deduce DW_AT_comp_dir from absolute DW_AT_name, this
+ does not have to be the compilation directory. */
}
+
if (*comp_dir != NULL)
{
/* Irix 6.2 native cc prepends <machine>.: to the compilation
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -43,7 +43,9 @@
#include "gdbthread.h"
#include "block.h"
#include "inline-frame.h"
-#include "tracepoint.h"
+#include "tracepoint.h"
+#include "filenames.h"
+#include "source.h"

static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame);
static struct frame_info *get_prev_frame_raw (struct frame_info *this_frame);
@@ -135,6 +137,18 @@ struct frame_info
sufficient for now. */
static struct frame_info *frame_stash = NULL;

+/* Possible values of 'set backtrace filename-display'. */
+static const char filename_display_basename[] = "basename";
+static const char filename_display_relative[] = "relative";
+static const char filename_display_absolute[] = "absolute";
+
+static const char *const filename_display_kind_names[] = {
+ filename_display_basename,
+ filename_display_relative,
+ filename_display_absolute,
+ NULL
+};
+
/* Add the following FRAME to the frame stash. */

static void
@@ -207,6 +221,16 @@ show_backtrace_limit (struct ui_file *file, int from_tty,
value);
}

+static const char *filename_display_string = filename_display_relative;
+
+static void
+show_filename_display_string (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file,
+ _("A filename is displayed in backtrace as \"%s\".\n"),
+ value);
+}

static void
fprint_field (struct ui_file *file, const char *name, int p, CORE_ADDR addr)
@@ -2140,6 +2164,28 @@ find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
(*sal) = find_pc_line (pc, notcurrent);
}

+/* See commentary in frame.h. */
+
+const char *
+get_filename_display_from_sal (const struct symtab_and_line *sal)
+{
+ const char *filename = sal->symtab->filename;
+
+ if (filename == NULL)
+ return NULL;
+ else if (filename_display_string == filename_display_basename)
+ return lbasename (filename);
+ else if (filename_display_string == filename_display_absolute)
+ {
+ const char *retval = symtab_to_fullname (sal->symtab);
+
+ if (retval != NULL)
+ return retval;
+ }
+
+ return filename;
+}
+
/* Per "frame.h", return the ``address'' of the frame. Code should
really be using get_frame_id(). */
CORE_ADDR
@@ -2499,6 +2545,21 @@ Zero is unlimited."),
&set_backtrace_cmdlist,
&show_backtrace_cmdlist);

+ add_setshow_enum_cmd ("filename-display", class_obscure,
+ filename_display_kind_names,
+ &filename_display_string, _("\
+Set how to display filenames in backtraces."), _("\
+Show how to display filenames in backtraces."), _("\
+filename-display can be:\n\
+ basename - display only basename of a filename\n\
+ relative - display a filename without the compilation directory part\n\
+ absolute - display an absolute filename\n\
+By default, as-recorded filename is displayed."),
+ NULL,
+ show_filename_display_string,
+ &set_backtrace_cmdlist,
+ &show_backtrace_cmdlist);
+
/* Debug this files internals. */
add_setshow_zinteger_cmd ("frame", class_maintenance, &frame_debug, _("\
Set frame debugging."), _("\
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -353,6 +353,12 @@ extern int get_frame_func_if_available (struct frame_info *fi, CORE_ADDR *);
extern void find_frame_sal (struct frame_info *frame,
struct symtab_and_line *sal);

+/* Returns filename without the compile directory part, basename or absolute
+ filename. It depends on 'set backtrace filename-display' value. */
+
+extern const char *
+ get_filename_display_from_sal (const struct symtab_and_line *sal);
+
/* Set the current source and line to the location given by frame
FRAME, if possible. When CENTER is true, adjust so the relevant
line is in the center of the next 'list'. */
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1179,11 +1179,13 @@ print_frame (struct frame_info *frame, int print_level,
ui_out_text (uiout, ")");
if (sal.symtab && sal.symtab->filename)
{
+ const char *filename_display = get_filename_display_from_sal (&sal);
+
annotate_frame_source_begin ();
ui_out_wrap_hint (uiout, " ");
ui_out_text (uiout, " at ");
annotate_frame_source_file ();
- ui_out_field_string (uiout, "file", sal.symtab->filename);
+ ui_out_field_string (uiout, "file", filename_display);
if (ui_out_is_mi_like_p (uiout))
{
const char *fullname = symtab_to_fullname (sal.symtab);
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-dir-file-name.c
@@ -0,0 +1,87 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2012 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/>. */
+
+volatile int v;
+
+static void
+marker (void)
+{
+ v++;
+}
+
+/* *R* marks possibly invalid compiler output as the first path component is
+ not absolute. Still DWARF-4 does not forbid such DWARF; GCC does not
+ produce it. */
+
+#define FUNCBLOCK \
+FUNC (compdir_missing__ldir_missing__file_basename) /*R*/\
+FUNC (compdir_missing__ldir_missing__file_relative) /*R*/\
+FUNC (compdir_missing__ldir_missing__file_absolute) \
+FUNC (compdir_missing__ldir_relative_file_basename) /*R*/\
+FUNC (compdir_missing__ldir_relative_file_relative) /*R*/\
+FUNC (compdir_missing__ldir_relative_file_absolute) /*R*/\
+FUNC (compdir_missing__ldir_absolute_file_basename) \
+FUNC (compdir_missing__ldir_absolute_file_relative) \
+FUNC (compdir_missing__ldir_absolute_file_absolute_same) \
+FUNC (compdir_missing__ldir_absolute_file_absolute_different) \
+FUNC (compdir_relative_ldir_missing__file_basename) /*R*/\
+FUNC (compdir_relative_ldir_missing__file_relative) /*R*/\
+FUNC (compdir_relative_ldir_missing__file_absolute) /*R*/\
+FUNC (compdir_relative_ldir_relative_file_basename) /*R*/\
+FUNC (compdir_relative_ldir_relative_file_relative) /*R*/\
+FUNC (compdir_relative_ldir_relative_file_absolute) /*R*/\
+FUNC (compdir_relative_ldir_absolute_file_basename) /*R*/\
+FUNC (compdir_relative_ldir_absolute_file_relative) /*R*/\
+FUNC (compdir_relative_ldir_absolute_file_absolute_same) /*R*/\
+FUNC (compdir_relative_ldir_absolute_file_absolute_different) /*R*/\
+FUNC (compdir_absolute_ldir_missing__file_basename) \
+FUNC (compdir_absolute_ldir_missing__file_relative) \
+FUNC (compdir_absolute_ldir_missing__file_absolute_same) \
+FUNC (compdir_absolute_ldir_missing__file_absolute_different) \
+FUNC (compdir_absolute_ldir_relative_file_basename) \
+FUNC (compdir_absolute_ldir_relative_file_relative) \
+FUNC (compdir_absolute_ldir_relative_file_absolute_same) \
+FUNC (compdir_absolute_ldir_relative_file_absolute_different) \
+FUNC (compdir_absolute_ldir_absolute_file_basename_same) \
+FUNC (compdir_absolute_ldir_absolute_file_basename_different) \
+FUNC (compdir_absolute_ldir_absolute_file_relative_same) \
+FUNC (compdir_absolute_ldir_absolute_file_relative_different) \
+FUNC (compdir_absolute_ldir_absolute_file_absolute_same) \
+FUNC (compdir_absolute_ldir_absolute_file_absolute_different)
+
+#define FUNC(name) \
+ asm (#name "_start: .globl " #name "_start\n"); \
+ static void \
+ name (void) \
+ { \
+ v++; \
+ } \
+ asm (#name "_end: .globl " #name "_end\n");
+FUNCBLOCK
+#undef FUNC
+
+int
+main (void)
+{
+
+#define FUNC(name) \
+ name ();
+FUNCBLOCK
+#undef FUNC
+
+ return 0;
+}
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-dir-file-name.exp
@@ -0,0 +1,403 @@
+# Copyright 2012 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 and use gas.
+if {![dwarf2_support]} {
+ return 0
+}
+
+set testfile "dw2-dir-file-name"
+set executable ${testfile}
+set binfile ${objdir}/${subdir}/${executable}
+set srcfile ${testfile}.c
+set asmsrcfile ${objdir}/${subdir}/${testfile}asm.S
+set asmobjfile ${objdir}/${subdir}/${testfile}asm.o
+set srcabsdir ${objdir}/${subdir}/${testfile}.d
+set srctmpfile tmp-${testfile}.c
+
+# $srcdir may be relative.
+if {[file pathtype $srcabsdir] != "absolute"} {
+ untested "objdir pathtype is not absolute"
+ return -1
+}
+
+set f [open $asmsrcfile "w"]
+puts $f "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */"
+
+proc out_cu { name cu_dir cu_name line_dir line_name } {
+ global f
+
+ puts -nonewline $f "\
+.L${name}_begin:
+ .4byte .L${name}_end - .L${name}_start /* Length of Compilation Unit */
+.L${name}_start:
+ .2byte 2 /* DWARF Version */
+ .4byte .Labbrev1_begin /* Offset into abbrev section */
+ .byte 4 /* Pointer size */
+"
+ if { $cu_dir != "" } {
+ puts $f " .uleb128 ABBREV_COMP_DIR_NAME /* Abbrev: DW_TAG_compile_unit */"
+ } else {
+ puts $f " .uleb128 ABBREV_NAME /* Abbrev: DW_TAG_compile_unit */"
+ }
+ puts -nonewline $f "\
+ .ascii \"GNU C\\0\" /* DW_AT_producer */
+ .byte 2 /* DW_AT_language (DW_LANG_C) */
+ .4byte .Lline_${name}_begin /* DW_AT_stmt_list */
+ .4byte ${name}_start /* DW_AT_low_pc */
+ .4byte ${name}_end /* DW_AT_high_pc */
+"
+ if { $cu_dir != "" } {
+ puts $f " .ascii $cu_dir /* DW_AT_comp_dir */"
+ }
+ puts -nonewline $f "\
+ .ascii $cu_name /* DW_AT_name */
+
+ .uleb128 3 /* Abbrev: DW_TAG_subprogram */
+ .asciz \"${name}\" /* DW_AT_name */
+ .4byte ${name}_start /* DW_AT_low_pc */
+ .4byte ${name}_end /* DW_AT_high_pc */
+
+ .byte 0 /* End of children of CU */
+.L${name}_end:
+"
+}
+
+proc out_line { name cu_dir cu_name line_dir line_name } {
+ global f
+
+ puts -nonewline $f "\
+.Lline_${name}_begin:
+ .4byte .Lline_${name}_end - .Lline_${name}_start /* Initial length */
+.Lline_${name}_start:
+ .2byte 2 /* Version */
+ .4byte .Lline_${name}_lines - .Lline_${name}_hdr /* header_length */
+.Lline_${name}_hdr:
+ .byte 1 /* Minimum insn length */
+ .byte 1 /* default_is_stmt */
+ .byte 1 /* line_base */
+ .byte 1 /* line_range */
+ .byte 4 /* opcode_base */
+
+ /* Standard lengths */
+ .byte 0
+ .byte 1
+ .byte 1
+
+ /* Include directories */
+"
+ if { $line_dir != "" } {
+ puts $f " .ascii $line_dir"
+ }
+ puts -nonewline $f "\
+ .byte 0
+
+ /* File names */
+ .ascii $line_name
+"
+ if { $line_dir != "" } {
+ puts $f " .uleb128 1"
+ } else {
+ puts $f " .uleb128 0"
+ }
+ puts -nonewline $f "\
+ .uleb128 0
+ .uleb128 0
+
+ .byte 0
+
+.Lline_${name}_lines:
+ .byte 3 /* DW_LNS_advance_line */
+ .sleb128 998 /* ... to 999 */
+ .byte 0 /* DW_LNE_set_address */
+ .uleb128 5
+ .byte 2
+ .4byte ${name}_start
+ .byte 1 /* DW_LNS_copy */
+ .byte 3 /* DW_LNS_advance_line */
+ .sleb128 1 /* ... to 1000 */
+ .byte 0 /* DW_LNE_set_address */
+ .uleb128 5
+ .byte 2
+ .4byte ${name}_end
+ .byte 1 /* DW_LNS_copy */
+ .byte 0 /* DW_LNE_end_of_sequence */
+ .uleb128 1
+ .byte 1
+.Lline_${name}_end:
+"
+}
+
+# IFSOME can be optionally _same or _different if >= 2 absolute directories are
+# provided. Then in the _different case the overriden directories have invalid
+# XDIR value.
+
+proc out_unit { func compdir ldir file ifsame } {
+ set name "compdir_${compdir}_ldir_${ldir}_file_${file}${ifsame}"
+
+ if { $compdir == "missing_" } {
+ set cu_dir {}
+ } elseif { $compdir == "relative" } {
+ set cu_dir {COMPDIR "\0"}
+ } elseif { $compdir == "absolute" } {
+ set cu_dir {BDIR "/" COMPDIR "\0"}
+ } else {
+ error "compdir $compdir"
+ }
+
+ if { $ldir == "missing_" } {
+ set line_dir {}
+ } elseif { $ldir == "relative" } {
+ set line_dir {LDIR "\0"}
+ } elseif { $ldir == "absolute" } {
+ set line_dir {BDIR "/" LDIR "\0"}
+ } else {
+ error "ldir $ldir"
+ }
+
+ if { $file == "basename" } {
+ set cu_name {FILE "\0"}
+ } elseif { $file == "relative" } {
+ set cu_name {FDIR "/" FILE "\0"}
+ } elseif { $file == "absolute" } {
+ set cu_name {BDIR "/" FILE "\0"}
+ } else {
+ error "file $file"
+ }
+ set line_name $cu_name
+
+ if { "$ifsame" == "_different" } {
+ if { $file == "absolute" } {
+ if { $ldir == "absolute" } {
+ set line_dir {XDIR "\0"}
+ }
+ if { $compdir == "absolute" } {
+ set cu_dir {XDIR "\0"}
+ }
+ } elseif { $ldir == "absolute" } {
+ if { $compdir == "absolute" } {
+ set cu_dir {XDIR "\0"}
+ }
+ } else {
+ error "not enough absolutes"
+ }
+ }
+
+ $func $name $cu_dir $cu_name $line_dir $line_name
+}
+
+proc out_diff { func compdir ldir file } {
+ set abscount 0
+ if { $compdir == "absolute" } {
+ incr abscount
+ }
+ if { $ldir == "absolute" } {
+ incr abscount
+ }
+ if { $file == "absolute" } {
+ incr abscount
+ }
+ if { $abscount <= 1 } {
+ out_unit $func $compdir $ldir $file ""
+ } else {
+ out_unit $func $compdir $ldir $file "_same"
+ out_unit $func $compdir $ldir $file "_different"
+ }
+}
+
+proc out_file { func compdir ldir } {
+ out_diff $func $compdir $ldir "basename"
+ out_diff $func $compdir $ldir "relative"
+ out_diff $func $compdir $ldir "absolute"
+}
+
+proc out_ldir { func compdir } {
+ out_file $func $compdir "missing_"
+ out_file $func $compdir "relative"
+ out_file $func $compdir "absolute"
+}
+
+proc out_compdir { func } {
+ out_ldir $func "missing_"
+ out_ldir $func "relative"
+ out_ldir $func "absolute"
+}
+
+puts -nonewline $f "\
+#define ABBREV_NAME 1
+#define ABBREV_COMP_DIR_NAME 2
+ .section .debug_info
+"
+out_compdir out_cu
+
+puts $f " .section .debug_line"
+out_compdir out_line
+
+puts -nonewline $f "\
+ .section .debug_abbrev
+.Labbrev1_begin:
+
+ .uleb128 ABBREV_NAME /* Abbrev code */
+ .uleb128 0x11 /* DW_TAG_compile_unit */
+ .byte 1 /* has_children */
+ .uleb128 0x25 /* DW_AT_producer */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x13 /* DW_AT_language */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x10 /* DW_AT_stmt_list */
+ .uleb128 0x6 /* DW_FORM_data4 */
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 ABBREV_COMP_DIR_NAME /* Abbrev code */
+ .uleb128 0x11 /* DW_TAG_compile_unit */
+ .byte 1 /* has_children */
+ .uleb128 0x25 /* DW_AT_producer */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x13 /* DW_AT_language */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x10 /* DW_AT_stmt_list */
+ .uleb128 0x6 /* DW_FORM_data4 */
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x1b /* DW_AT_comp_dir */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 3 /* Abbrev code */
+ .uleb128 0x2e /* DW_TAG_subprogram */
+ .byte 0 /* has_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+"
+
+close $f
+
+set opts {}
+# Base directory.
+lappend opts "additional_flags=-DBDIR=\"${srcabsdir}\""
+# Incorrect directory which should never be visible from GDB.
+lappend opts "additional_flags=-DXDIR=\"${srcabsdir}/xdir\""
+# CU's DW_AT_comp_dir.
+lappend opts "additional_flags=-DCOMPDIR=\"compdir\""
+# .debug_line's directory.
+lappend opts "additional_flags=-DLDIR=\"ldir\""
+# CU's DW_AT_name and .debug_line's filename relative directory, if needed.
+lappend opts "additional_flags=-DFDIR=\"fdir\""
+# CU's DW_AT_name and .debug_line's filename.
+lappend opts "additional_flags=-DFILE=\"${srctmpfile}\""
+
+if { [gdb_compile "${asmsrcfile} ${srcdir}/${subdir}/$srcfile" "${binfile}" executable $opts] != "" } {
+ untested "Cannot compile ${asmsrcfile} or $srcfile"
+ return -1
+}
+
+remote_exec host "sh -c \"rm -f ${srcabsdir}{/rdir,}{/xdir,}{/compdir,}{/ldir,}{/fdir,}/${srctmpfile}\""
+remote_exec host "sh -c \"rmdir ${srcabsdir}{/rdir,}{/xdir,}{/compdir,}{/ldir,}{/fdir,}\""
+remote_exec host "sh -c \"mkdir ${srcabsdir}{,/rdir}{,/xdir}{,/compdir}{,/ldir}{,/fdir}\""
+remote_exec host "sh -c \"for d in ${srcabsdir}{,/rdir}{,/xdir}{,/compdir}{,/ldir}{,/fdir};do cp ${srcdir}/${subdir}/${srcfile} \\\$d/${srctmpfile}; done\""
+
+clean_restart ${executable}
+
+if ![runto_main] {
+ return -1
+}
+
+gdb_test "cd ${srcabsdir}/rdir" "Working directory [string_to_regexp ${srcabsdir}]/rdir\\."
+
+proc test { func compdir filename } { with_test_prefix "$func" {
+ # Clear the GDB cache.
+ gdb_test_no_output "set directories" ""
+
+ if {$compdir == ""} {
+ set absolute "$filename"
+ } else {
+ set absolute "$compdir/$filename"
+ }
+ if {[string index $absolute 0] != "/"} {
+ error "not absolute"
+ }
+
+ gdb_breakpoint $func
+ gdb_continue_to_breakpoint $func "$func \\(\\) at .*"
+
+ gdb_test_no_output "set backtrace filename-display absolute"
+ verbose -log "expect: ${absolute}"
+ gdb_test "frame" " in $func \\(\\) at [string_to_regexp ${absolute}]:999" "absolute"
+
+ gdb_test_no_output "set backtrace filename-display basename"
+ verbose -log "expect: [file tail $filename]"
+ gdb_test "frame" " in $func \\(\\) at [string_to_regexp [file tail $filename]]:999" "basename"
+
+ gdb_test_no_output "set backtrace filename-display relative"
+ verbose -log "expect: $filename"
+ gdb_test "frame" " in $func \\(\\) at [string_to_regexp $filename]:999" "relative"
+}}
+
+set bdir "${srcabsdir}"
+set file "${srctmpfile}"
+test "compdir_missing__ldir_missing__file_basename" "$bdir/rdir" "$file"
+test "compdir_missing__ldir_missing__file_relative" "$bdir/rdir" "fdir/$file"
+test "compdir_missing__ldir_missing__file_absolute" "" "$bdir/$file"
+test "compdir_missing__ldir_relative_file_basename" "$bdir/rdir" "ldir/$file"
+test "compdir_missing__ldir_relative_file_relative" "$bdir/rdir" "ldir/fdir/$file"
+test "compdir_missing__ldir_relative_file_absolute" "" "$bdir/$file"
+test "compdir_missing__ldir_absolute_file_basename" "" "$bdir/ldir/$file"
+test "compdir_missing__ldir_absolute_file_relative" "" "$bdir/ldir/fdir/$file"
+test "compdir_missing__ldir_absolute_file_absolute_same" "" "$bdir/$file"
+test "compdir_missing__ldir_absolute_file_absolute_different" "" "$bdir/$file"
+test "compdir_relative_ldir_missing__file_basename" "$bdir/rdir/compdir" "$file"
+test "compdir_relative_ldir_missing__file_relative" "$bdir/rdir/compdir" "fdir/$file"
+test "compdir_relative_ldir_missing__file_absolute" "" "$bdir/$file"
+test "compdir_relative_ldir_relative_file_basename" "$bdir/rdir/compdir" "ldir/$file"
+test "compdir_relative_ldir_relative_file_relative" "$bdir/rdir/compdir" "ldir/fdir/$file"
+test "compdir_relative_ldir_relative_file_absolute" "" "$bdir/$file"
+test "compdir_relative_ldir_absolute_file_basename" "" "$bdir/ldir/$file"
+test "compdir_relative_ldir_absolute_file_relative" "" "$bdir/ldir/fdir/$file"
+test "compdir_relative_ldir_absolute_file_absolute_same" "" "$bdir/$file"
+test "compdir_relative_ldir_absolute_file_absolute_different" "" "$bdir/$file"
+test "compdir_absolute_ldir_missing__file_basename" "$bdir/compdir" "$file"
+test "compdir_absolute_ldir_missing__file_relative" "$bdir/compdir" "fdir/$file"
+test "compdir_absolute_ldir_missing__file_absolute_same" "" "$bdir/$file"
+test "compdir_absolute_ldir_missing__file_absolute_different" "" "$bdir/$file"
+test "compdir_absolute_ldir_relative_file_basename" "$bdir/compdir" "ldir/$file"
+test "compdir_absolute_ldir_relative_file_relative" "$bdir/compdir" "ldir/fdir/$file"
+test "compdir_absolute_ldir_relative_file_absolute_same" "" "$bdir/$file"
+test "compdir_absolute_ldir_relative_file_absolute_different" "" "$bdir/$file"
+test "compdir_absolute_ldir_absolute_file_basename_same" "" "$bdir/ldir/$file"
+test "compdir_absolute_ldir_absolute_file_relative_different" "" "$bdir/ldir/fdir/$file"
+test "compdir_absolute_ldir_absolute_file_absolute_same" "" "$bdir/$file"
+test "compdir_absolute_ldir_absolute_file_absolute_different" "" "$bdir/$file"