+2019-09-17 Mike Gulick <mgulick@mathworks.com>
+
+ * source.c (prepare_path_for_appending): New function.
+ (openp): Make use of new function.
+ (find_and_open_source): Search for the compilation directory and
+ source file as a relative path beneath the directory search path.
+
2019-09-17 Andrew Burgess <andrew.burgess@embecosm.com>
* source-cache.c (source_cache::get_line_charpos): Catch
+2019-09-17 Andrew Burgess <andrew.burgess@embecosm.com>
+
+ * gdb.texinfo (Source Path): Additional text to better describe
+ how the source path directory list is used when searching for
+ source files.
+
2019-09-12 Philippe Waroquiers <philippe.waroquiers@skynet.be>
* gdb.texinfo (Ada Tasks): Tell the task name is printed, update
in the list, until it finds a file with the desired name.
For example, suppose an executable references the file
-@file{/usr/src/foo-1.0/lib/foo.c}, and our source path is
-@file{/mnt/cross}. The file is first looked up literally; if this
-fails, @file{/mnt/cross/usr/src/foo-1.0/lib/foo.c} is tried; if this
-fails, @file{/mnt/cross/foo.c} is opened; if this fails, an error
-message is printed. @value{GDBN} does not look up the parts of the
+@file{/usr/src/foo-1.0/lib/foo.c}, does not record a compilation
+directory, and the @dfn{source path} is @file{/mnt/cross}.
+@value{GDBN} would look for the source file in the following
+locations:
+
+@enumerate
+
+@item @file{/usr/src/foo-1.0/lib/foo.c}
+@item @file{/mnt/cross/usr/src/foo-1.0/lib/foo.c}
+@item @file{/mnt/cross/foo.c}
+
+@end enumerate
+
+If the source file is not present at any of the above locations then
+an error is printed. @value{GDBN} does not look up the parts of the
source file name, such as @file{/mnt/cross/src/foo-1.0/lib/foo.c}.
Likewise, the subdirectories of the source path are not searched: if
the source path is @file{/mnt/cross}, and the binary refers to
@file{/mnt/cross/usr/src/foo-1.0/lib}.
Plain file names, relative file names with leading directories, file
-names containing dots, etc.@: are all treated as described above; for
-instance, if the source path is @file{/mnt/cross}, and the source file
-is recorded as @file{../lib/foo.c}, @value{GDBN} would first try
-@file{../lib/foo.c}, then @file{/mnt/cross/../lib/foo.c}, and after
-that---@file{/mnt/cross/foo.c}.
+names containing dots, etc.@: are all treated as described above,
+except that non-absolute file names are not looked up literally. If
+the @dfn{source path} is @file{/mnt/cross}, the source file is
+recorded as @file{../lib/foo.c}, and no compilation directory is
+recorded, then @value{GDBN} will search in the following locations:
+
+@enumerate
+
+@item @file{/mnt/cross/../lib/foo.c}
+@item @file{/mnt/cross/foo.c}
+
+@end enumerate
+
+@kindex cdir
+@kindex cwd
+@vindex $cdir@r{, convenience variable}
+@vindex $cwd@r{, convenience variable}
+@cindex compilation directory
+@cindex current directory
+@cindex working directory
+@cindex directory, current
+@cindex directory, compilation
+The @dfn{source path} will always include two special entries
+@samp{$cdir} and @samp{$cwd}, these refer to the compilation directory
+(if one is recorded) and the current working directory respectively.
+
+@samp{$cdir} causes @value{GDBN} to search within the compilation
+directory, if one is recorded in the debug information. If no
+compilation directory is recorded in the debug information then
+@samp{$cdir} is ignored.
+
+@samp{$cwd} is not the same as @samp{.}---the former tracks the
+current working directory as it changes during your @value{GDBN}
+session, while the latter is immediately expanded to the current
+directory at the time you add an entry to the source path.
+
+If a compilation directory is recorded in the debug information, and
+@value{GDBN} has not found the source file after the first search
+using @dfn{source path}, then @value{GDBN} will combine the
+compilation directory and the filename, and then search for the source
+file again using the @dfn{source path}.
+
+For example, if the executable records the source file as
+@file{/usr/src/foo-1.0/lib/foo.c}, the compilation directory is
+recorded as @file{/project/build}, and the @dfn{source path} is
+@file{/mnt/cross:$cdir:$cwd} while the current working directory of
+the @value{GDBN} session is @file{/home/user}, then @value{GDBN} will
+search for the source file in the following loctions:
+
+@enumerate
+
+@item @file{/usr/src/foo-1.0/lib/foo.c}
+@item @file{/mnt/cross/usr/src/foo-1.0/lib/foo.c}
+@item @file{/project/build/usr/src/foo-1.0/lib/foo.c}
+@item @file{/home/user/usr/src/foo-1.0/lib/foo.c}
+@item @file{/mnt/cross/project/build/usr/src/foo-1.0/lib/foo.c}
+@item @file{/project/build/project/build/usr/src/foo-1.0/lib/foo.c}
+@item @file{/home/user/project/build/usr/src/foo-1.0/lib/foo.c}
+@item @file{/mnt/cross/foo.c}
+@item @file{/project/build/foo.c}
+@item @file{/home/user/foo.c}
+
+@end enumerate
+
+If the file name in the previous example had been recorded in the
+executable as a relative path rather than an absolute path, then the
+first look up would not have occurred, but all of the remaining steps
+would be similar.
+
+When searching for source files on MS-DOS and MS-Windows, where
+absolute paths start with a drive letter (e.g.
+@file{C:/project/foo.c}), @value{GDBN} will remove the drive letter
+from the file name before appending it to a search directory from
+@dfn{source path}; for instance if the executable references the
+source file @file{C:/project/foo.c} and @dfn{source path} is set to
+@file{D:/mnt/cross}, then @value{GDBN} will search in the following
+locations for the source file:
+
+@enumerate
+
+@item @file{C:/project/foo.c}
+@item @file{D:/mnt/cross/project/foo.c}
+@item @file{D:/mnt/cross/foo.c}
+
+@end enumerate
Note that the executable search path is @emph{not} used to locate the
source files.
@kindex directory
@kindex dir
-When you start @value{GDBN}, its source path includes only @samp{cdir}
-and @samp{cwd}, in that order.
+When you start @value{GDBN}, its source path includes only @samp{$cdir}
+and @samp{$cwd}, in that order.
To add other directories, use the @code{directory} command.
The search path is used to find both program source files and @value{GDBN}
whitespace. You may specify a directory that is already in the source
path; this moves it forward, so @value{GDBN} searches it sooner.
-@kindex cdir
-@kindex cwd
-@vindex $cdir@r{, convenience variable}
-@vindex $cwd@r{, convenience variable}
-@cindex compilation directory
-@cindex current directory
-@cindex working directory
-@cindex directory, current
-@cindex directory, compilation
-You can use the string @samp{$cdir} to refer to the compilation
-directory (if one is recorded), and @samp{$cwd} to refer to the current
-working directory. @samp{$cwd} is not the same as @samp{.}---the former
-tracks the current working directory as it changes during your @value{GDBN}
-session, while the latter is immediately expanded to the current
-directory at the time you add an entry to the source path.
+The special strings @samp{$cdir} (to refer to the compilation
+directory, if one is recorded), and @samp{$cwd} (to refer to the
+current working directory) can also be included in the list of
+directories @var{dirname}. Though these will already be in the source
+path they will be moved forward in the list so @value{GDBN} searches
+them sooner.
@item directory
Reset the source path to its default value (@samp{$cdir:$cwd} on Unix systems). This requires confirmation.
}
\f
+/* Helper function to remove characters from the start of PATH so that
+ PATH can then be appended to a directory name. We remove leading drive
+ letters (for dos) as well as leading '/' characters and './'
+ sequences. */
+
+const char *
+prepare_path_for_appending (const char *path)
+{
+ /* For dos paths, d:/foo -> /foo, and d:foo -> foo. */
+ if (HAS_DRIVE_SPEC (path))
+ path = STRIP_DRIVE_SPEC (path);
+
+ const char *old_path;
+ do
+ {
+ old_path = path;
+
+ /* /foo => foo, to avoid multiple slashes that Emacs doesn't like. */
+ while (IS_DIR_SEPARATOR(path[0]))
+ path++;
+
+ /* ./foo => foo */
+ while (path[0] == '.' && IS_DIR_SEPARATOR (path[1]))
+ path += 2;
+ }
+ while (old_path != path);
+
+ return path;
+}
+
/* Open a file named STRING, searching path PATH (dir names sep by some char)
using mode MODE in the calls to open. You cannot use this function to
create files (O_CREAT).
goto done;
}
- /* For dos paths, d:/foo -> /foo, and d:foo -> foo. */
- if (HAS_DRIVE_SPEC (string))
- string = STRIP_DRIVE_SPEC (string);
-
- /* /foo => foo, to avoid multiple slashes that Emacs doesn't like. */
- while (IS_DIR_SEPARATOR(string[0]))
- string++;
-
- /* ./foo => foo */
- while (string[0] == '.' && IS_DIR_SEPARATOR (string[1]))
- string += 2;
+ /* Remove characters from the start of PATH that we don't need when PATH
+ is appended to a directory name. */
+ string = prepare_path_for_appending (string);
alloclen = strlen (path) + strlen (string) + 2;
filename = (char *) alloca (alloclen);
openp_flags flags = OPF_SEARCH_IN_PATH;
if (basenames_may_differ)
flags |= OPF_RETURN_REALPATH;
+
+ /* Try to locate file using filename. */
result = openp (path, flags, filename, OPEN_MODE, fullname);
+ if (result < 0 && dirname != NULL)
+ {
+ /* Remove characters from the start of PATH that we don't need when
+ PATH is appended to a directory name. */
+ const char *filename_start = prepare_path_for_appending (filename);
+
+ /* Try to locate file using compilation dir + filename. This is
+ helpful if part of the compilation directory was removed,
+ e.g. using gcc's -fdebug-prefix-map, and we have added the missing
+ prefix to source_path. */
+ std::string cdir_filename (dirname);
+
+ /* Remove any trailing directory separators. */
+ while (IS_DIR_SEPARATOR (cdir_filename.back ()))
+ cdir_filename.pop_back ();
+
+ /* Add our own directory separator. */
+ cdir_filename.append (SLASH_STRING);
+ cdir_filename.append (filename_start);
+
+ result = openp (path, flags, cdir_filename.c_str (), OPEN_MODE,
+ fullname);
+ }
if (result < 0)
{
/* Didn't work. Try using just the basename. */
+2019-09-17 Andrew Burgess <andrew.burgess@embecosm.com>
+
+ * gdb.base/source-dir.exp: Add extra test for mapped compilation
+ directory.
+
2019-09-17 Andrew Burgess <andrew.burgess@embecosm.com>
* gdb.base/list-missing-source.exp: New file.
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 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/>. */
+
+int
+main ()
+{
+ return 0;
+}
standard_testfile
-gdb_start
+# Take a list of directories DIRS, and return a regular expression
+# that will match against the output of the 'directory' command
+# assuming that DIRS are all of the directories that should appear in
+# the results.
+proc search_dir_list { dirs } {
+ set output "\r\nSource directories searched: "
+ append output [join $dirs "\[:;\]"]
-set foo "/nOtExStInG"
+ return ${output}
+}
-gdb_test "directory $foo/a $foo/b $foo/c" "\r\nSource directories searched: $foo/a\[:;\]$foo/b\[:;\]$foo/c\[:;\]\\\$cdir\[:;\]\\\$cwd"
-gdb_test "directory $foo/b $foo/d $foo/c" "\r\nSource directories searched: $foo/b\[:;\]$foo/d\[:;\]$foo/c\[:;\]$foo/a\[:;\]\\\$cdir\[:;\]\\\$cwd"
+# Check that adding directories to the search path changes the order
+# in which directories are searched.
+proc test_changing_search_directory {} {
+ gdb_start
+
+ set foo "/nOtExStInG"
+
+ gdb_test "directory $foo/a $foo/b $foo/c" \
+ [search_dir_list [list \
+ "$foo/a" \
+ "$foo/b" \
+ "$foo/c" \
+ "\\\$cdir" \
+ "\\\$cwd"]]
+ gdb_test "directory $foo/b $foo/d $foo/c" \
+ [search_dir_list [list \
+ "$foo/b" \
+ "$foo/d" \
+ "$foo/c" \
+ "$foo/a" \
+ "\\\$cdir" \
+ "\\\$cwd"]]
+ gdb_exit
+}
+
+# Test that the compilation directory can also be extended with a
+# prefix from the directory search path in order to find source files.
+proc test_truncated_comp_dir {} {
+ global srcfile srcdir subdir binfile
+ global decimal
+
+ # When we run this test the current directory will be something
+ # like this:
+ # /some/path/to/gdb/build/testsuite/
+ # We are going to copy the source file out of the source tree into
+ # a location like this:
+ # /some/path/to/gdb/build/testsuite/output/gdb.base/soure-dir/
+ #
+ # We will then switch to this directory and compile the source
+ # file, however, we will ask GCC to remove this prefix from the
+ # compilation directory in the debug info:
+ # /some/path/to/gdb/build/testsuite/output/
+ #
+ # As a result the debug information will look like this:
+ #
+ # DW_AT_name : source-dir.c
+ # DW_AT_comp_dir : /gdb.base/source-dir
+ #
+ # Finally we switch back to this directory:
+ # /some/path/to/gdb/build/testsuite/
+ #
+ # and start GDB. There was a time when GDB would be unable to
+ # find the source file no matter what we added to the directory
+ # search path, this should now be fixed.
+
+ set original_dir [pwd]
+ set working_dir [standard_output_file ""]
+ cd ${working_dir}
+
+ set strip_dir [file normalize "${working_dir}/../.."]
+
+ set new_srcfile [standard_output_file ${srcfile}]
+ set fd [open "$new_srcfile" w]
+ puts $fd "int
+ main ()
+ {
+ return 0;
+ }"
+ close $fd
+
+ set options \
+ "debug additional_flags=-fdebug-prefix-map=${strip_dir}="
+ if { [gdb_compile "${srcfile}" "${binfile}" \
+ executable ${options}] != "" } {
+ untested "failed to compile"
+ return -1
+ }
+
+ cd ${original_dir}
+
+ clean_restart ${binfile}
+
+ gdb_test_no_output "set directories \$cdir:\$cwd"
+ gdb_test "show directories" \
+ "\r\nSource directories searched: \\\$cdir\[:;\]\\\$cwd"
+
+ if ![runto_main] then {
+ fail "can't run to main"
+ return 0
+ }
+
+ gdb_test "info source" \
+ [multi_line \
+ "Current source file is ${srcfile}" \
+ "Compilation directory is \[^\n\r\]+" \
+ "Source language is c." \
+ "Producer is \[^\n\r\]+" \
+ "Compiled with DWARF $decimal debugging format." \
+ "Does not include preprocessor macro info." ] \
+ "info source before setting directory search list"
+
+ gdb_test "dir $strip_dir" \
+ [search_dir_list [list \
+ "$strip_dir" \
+ "\\\$cdir" \
+ "\\\$cwd"]]
+ gdb_test "list" [multi_line \
+ "1\[ \t\]+int" \
+ "2\[ \t\]+main \\(\\)" \
+ "3\[ \t\]+\\{" \
+ "4\[ \t\]+return 0;" \
+ "5\[ \t\]+\\}" ]
+
+ gdb_test "info source" \
+ [multi_line \
+ "Current source file is ${srcfile}" \
+ "Compilation directory is \[^\n\r\]+" \
+ "Located in ${new_srcfile}" \
+ "Contains 5 lines." \
+ "Source language is c." \
+ "Producer is \[^\n\r\]+" \
+ "\[^\n\r\]+" \
+ "\[^\n\r\]+" ] \
+ "info source after setting directory search list"
+}
+
+test_changing_search_directory
+test_truncated_comp_dir