From 1db333787dc7d00ae720d8859000529224afacdc Mon Sep 17 00:00:00 2001 From: Paul Pluzhnikov Date: Wed, 18 Jan 2012 18:58:43 +0000 Subject: [PATCH] 2012-01-18 Paul Pluzhnikov Jan Kratochvil PR gdb/9538 * symfile.c (find_separate_debug_file): New function. (terminate_after_last_dir_separator): Likewise. (find_separate_debug_file_by_debuglink): Also try realpath. * configure.ac (AC_CHECK_FUNCS): Add lstat. * configure: Regenerate. * config.in: Regenerate. testsuite/ChangeLog: 2012-01-18 Paul Pluzhnikov PR gdb/9538 * gdb.base/sepdebug.exp: New test. --- gdb/ChangeLog | 11 ++ gdb/config.in | 3 + gdb/configure | 2 +- gdb/configure.ac | 2 +- gdb/symfile.c | 159 +++++++++++++++++++--------- gdb/testsuite/ChangeLog | 5 + gdb/testsuite/gdb.base/sepdebug.exp | 27 ++++- 7 files changed, 154 insertions(+), 55 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index d7bf88b665..120bcbc134 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,14 @@ +2012-01-18 Paul Pluzhnikov + Jan Kratochvil + + PR gdb/9538 + * symfile.c (find_separate_debug_file): New function. + (terminate_after_last_dir_separator): Likewise. + (find_separate_debug_file_by_debuglink): Also try realpath. + * configure.ac (AC_CHECK_FUNCS): Add lstat. + * configure: Regenerate. + * config.in: Regenerate. + 2012-01-18 Doug Evans * Makefile.in (TARGET_SYSTEM_ROOT, TARGET_SYSTEM_ROOT_DEFINE): Delete. diff --git a/gdb/config.in b/gdb/config.in index f1e6b9aed2..45c2c73ff0 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -263,6 +263,9 @@ /* Define to 1 if the system has the type `long long int'. */ #undef HAVE_LONG_LONG_INT +/* Define to 1 if you have the `lstat' function. */ +#undef HAVE_LSTAT + /* Define if has lwpid_t. */ #undef HAVE_LWPID_T diff --git a/gdb/configure b/gdb/configure index 5b2a6dd1e1..2ced763c10 100755 --- a/gdb/configure +++ b/gdb/configure @@ -12935,7 +12935,7 @@ for ac_func in canonicalize_file_name realpath getrusage getuid \ getgid pipe poll pread64 resize_term sbrk setpgid setpgrp setsid \ sigaction sigprocmask sigsetmask socketpair syscall \ ttrace wborder wresize setlocale iconvlist libiconvlist btowc \ - setrlimit getrlimit posix_madvise waitpid + setrlimit getrlimit posix_madvise waitpid lstat do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/gdb/configure.ac b/gdb/configure.ac index 652c0c601a..66844ed614 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -1067,7 +1067,7 @@ AC_CHECK_FUNCS([canonicalize_file_name realpath getrusage getuid \ getgid pipe poll pread64 resize_term sbrk setpgid setpgrp setsid \ sigaction sigprocmask sigsetmask socketpair syscall \ ttrace wborder wresize setlocale iconvlist libiconvlist btowc \ - setrlimit getrlimit posix_madvise waitpid]) + setrlimit getrlimit posix_madvise waitpid lstat]) AM_LANGINFO_CODESET # Check the return and argument types of ptrace. No canned test for diff --git a/gdb/symfile.c b/gdb/symfile.c index e9b6e7b000..7529196bbe 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -1441,63 +1441,48 @@ show_debug_file_directory (struct ui_file *file, int from_tty, #define DEBUG_SUBDIRECTORY ".debug" #endif -char * -find_separate_debug_file_by_debuglink (struct objfile *objfile) +/* Find a separate debuginfo file for OBJFILE, using DIR as the directory + where the original file resides (may not be the same as + dirname(objfile->name) due to symlinks), and DEBUGLINK as the file we are + looking for. Returns the name of the debuginfo, of NULL. */ + +static char * +find_separate_debug_file (const char *dir, + const char *canon_dir, + const char *debuglink, + unsigned long crc32, struct objfile *objfile) { - char *basename, *debugdir; - char *dir = NULL; - char *debugfile = NULL; - char *canon_name = NULL; - unsigned long crc32; + char *debugdir; + char *debugfile; int i; - basename = get_debug_link_info (objfile, &crc32); - - if (basename == NULL) - /* There's no separate debug info, hence there's no way we could - load it => no warning. */ - goto cleanup_return_debugfile; - - dir = xstrdup (objfile->name); - - /* Strip off the final filename part, leaving the directory name, - followed by a slash. The directory can be relative or absolute. */ - for (i = strlen(dir) - 1; i >= 0; i--) - { - if (IS_DIR_SEPARATOR (dir[i])) - break; - } - /* If I is -1 then no directory is present there and DIR will be "". */ - dir[i+1] = '\0'; - - /* Set I to max (strlen (canon_name), strlen (dir)). */ - canon_name = lrealpath (dir); + /* Set I to max (strlen (canon_dir), strlen (dir)). */ i = strlen (dir); - if (canon_name && strlen (canon_name) > i) - i = strlen (canon_name); + if (canon_dir != NULL && strlen (canon_dir) > i) + i = strlen (canon_dir); debugfile = xmalloc (strlen (debug_file_directory) + 1 + i + strlen (DEBUG_SUBDIRECTORY) + strlen ("/") - + strlen (basename) + + strlen (debuglink) + 1); /* First try in the same directory as the original file. */ strcpy (debugfile, dir); - strcat (debugfile, basename); + strcat (debugfile, debuglink); if (separate_debug_file_exists (debugfile, crc32, objfile)) - goto cleanup_return_debugfile; + return debugfile; /* Then try in the subdirectory named DEBUG_SUBDIRECTORY. */ strcpy (debugfile, dir); strcat (debugfile, DEBUG_SUBDIRECTORY); strcat (debugfile, "/"); - strcat (debugfile, basename); + strcat (debugfile, debuglink); if (separate_debug_file_exists (debugfile, crc32, objfile)) - goto cleanup_return_debugfile; + return debugfile; /* Then try in the global debugfile directories. @@ -1520,26 +1505,26 @@ find_separate_debug_file_by_debuglink (struct objfile *objfile) debugfile[debugdir_end - debugdir] = 0; strcat (debugfile, "/"); strcat (debugfile, dir); - strcat (debugfile, basename); + strcat (debugfile, debuglink); if (separate_debug_file_exists (debugfile, crc32, objfile)) - goto cleanup_return_debugfile; + return debugfile; /* If the file is in the sysroot, try using its base path in the global debugfile directory. */ - if (canon_name - && filename_ncmp (canon_name, gdb_sysroot, + if (canon_dir != NULL + && filename_ncmp (canon_dir, gdb_sysroot, strlen (gdb_sysroot)) == 0 - && IS_DIR_SEPARATOR (canon_name[strlen (gdb_sysroot)])) + && IS_DIR_SEPARATOR (canon_dir[strlen (gdb_sysroot)])) { memcpy (debugfile, debugdir, debugdir_end - debugdir); debugfile[debugdir_end - debugdir] = 0; - strcat (debugfile, canon_name + strlen (gdb_sysroot)); + strcat (debugfile, canon_dir + strlen (gdb_sysroot)); strcat (debugfile, "/"); - strcat (debugfile, basename); + strcat (debugfile, debuglink); if (separate_debug_file_exists (debugfile, crc32, objfile)) - goto cleanup_return_debugfile; + return debugfile; } debugdir = debugdir_end; @@ -1547,12 +1532,90 @@ find_separate_debug_file_by_debuglink (struct objfile *objfile) while (*debugdir != 0); xfree (debugfile); - debugfile = NULL; + return NULL; +} -cleanup_return_debugfile: - xfree (canon_name); - xfree (basename); - xfree (dir); +/* Modify PATH to contain only "directory/" part of PATH. + If there were no directory separators in PATH, PATH will be empty + string on return. */ + +static void +terminate_after_last_dir_separator (char *path) +{ + int i; + + /* Strip off the final filename part, leaving the directory name, + followed by a slash. The directory can be relative or absolute. */ + for (i = strlen(path) - 1; i >= 0; i--) + if (IS_DIR_SEPARATOR (path[i])) + break; + + /* If I is -1 then no directory is present there and DIR will be "". */ + path[i + 1] = '\0'; +} + +/* Find separate debuginfo for OBJFILE (using .gnu_debuglink section). + Returns pathname, or NULL. */ + +char * +find_separate_debug_file_by_debuglink (struct objfile *objfile) +{ + char *debuglink; + char *dir, *canon_dir; + char *debugfile; + unsigned long crc32; + struct cleanup *cleanups; + + debuglink = get_debug_link_info (objfile, &crc32); + + if (debuglink == NULL) + { + /* There's no separate debug info, hence there's no way we could + load it => no warning. */ + return NULL; + } + + dir = xstrdup (objfile->name); + cleanups = make_cleanup (xfree, dir); + terminate_after_last_dir_separator (dir); + canon_dir = lrealpath (dir); + + debugfile = find_separate_debug_file (dir, canon_dir, debuglink, + crc32, objfile); + xfree (canon_dir); + + if (debugfile == NULL) + { +#ifdef HAVE_LSTAT + /* For PR gdb/9538, try again with realpath (if different from the + original). */ + + struct stat st_buf; + + if (lstat (objfile->name, &st_buf) == 0 && S_ISLNK(st_buf.st_mode)) + { + char *symlink_dir; + + symlink_dir = lrealpath (objfile->name); + if (symlink_dir != NULL) + { + make_cleanup (xfree, symlink_dir); + terminate_after_last_dir_separator (symlink_dir); + if (strcmp (dir, symlink_dir) != 0) + { + /* Different directory, so try using it. */ + debugfile = find_separate_debug_file (symlink_dir, + symlink_dir, + debuglink, + crc32, + objfile); + } + } + } +#endif /* HAVE_LSTAT */ + } + + do_cleanups (cleanups); return debugfile; } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 131115b306..b4c0a4ba2b 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2012-01-18 Paul Pluzhnikov + + PR gdb/9538 + * gdb.base/sepdebug.exp: New test. + 2012-01-18 Pedro Alves * gdb.ada/mi_task_info.exp (-ada-task-info with no argument): diff --git a/gdb/testsuite/gdb.base/sepdebug.exp b/gdb/testsuite/gdb.base/sepdebug.exp index 5341bc9180..ba1047857a 100644 --- a/gdb/testsuite/gdb.base/sepdebug.exp +++ b/gdb/testsuite/gdb.base/sepdebug.exp @@ -41,7 +41,7 @@ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {deb # Note: the procedure gdb_gnu_strip_debug will produce an executable called # ${binfile}, which is just like the executable ($binfile) but without -# the debuginfo. Instead $binfile has a .gnudebuglink section which contains +# the debuginfo. Instead $binfile has a .gnu_debuglink section which contains # the name of a debuginfo only file. This file will be stored in the # gdb.base/ subdirectory. @@ -51,10 +51,27 @@ if [gdb_gnu_strip_debug $binfile] { return -1 } -gdb_exit -gdb_start -gdb_reinitialize_dir $srcdir/$subdir -gdb_load ${binfile} +# +# PR gdb/9538. Verify that symlinked executable still finds the separate +# debuginfo. +# +set old_subdir ${subdir} +set subdir ${subdir}/pr9538 + +# Cleanup any stale state. +remote_exec build "rm -rf ${subdir}" + +remote_exec build "mkdir ${subdir}" +remote_exec build "ln -s ${binfile} ${subdir}" +clean_restart ${testfile}${EXEEXT} +if { $gdb_file_cmd_debug_info != "debug" } then { + fail "No debug information found." +} + +# Restore subdir +set subdir ${old_subdir} + +clean_restart ${testfile}${EXEEXT} if { $gdb_file_cmd_debug_info != "debug" } then { fail "No debug information found." }