[PATCH 2/2] Fix source file not found when part of the path does not exist but that a canonicalized path exists.

Antoine Tremblay antoine.tremblay@ericsson.com
Tue Mar 24 15:11:00 GMT 2015


ping..

On 02/03/2015 03:19 PM, Antoine Tremblay wrote:
> For example if you have an executable with debug symbols with a path that
> looks like /build-server/program/build/../file.c  and try to insert a
> breakpoint by using the CLI "b /build-server/program/file.c" gdb would fail
> to find that file.
>
> This patch makes gdb try to open a source file with its canonical path
> even if parts of that path do not exist.
>
> In this example when trying to open  /build-server/program/build/../file.c
> we search for /build-server/program/file.c. even if the "build" directory
> is not present on the system.
>
> Also, since in general we do not need the full uncanonicalised path
> to be present on the system and that we validate that the file exist
> after a call to gdb_realpath with a subsequent call to open,
> gdb_realpath was changed to accept that parts of the path or the whole
> path be missing from the system.
>
> This is done using canonicalize_filename_mode (filename, CAN_MISSING);
>
> To make this behavior easy to adapt to multiple situations inside gdb
> in the future, a new option to openp was added :
>
> OPF_TRY_REALPATH = 0x08
>
> This will try the canonicalized path when using the openp function.
> As used in find_and_open_source to allow this feature.
>
> Also added a small test case to verify the issue.
>
> gdb/ChangeLog:
>
> 	PR breakpoints/17497
> 	* defs.h: Add OPF_TRY_REALPATH.
> 	* source.c (openp): Add OPF_TRY_REALPATH option.
> 	(find_and_open_source): Use OPF_TRY_REALPATH option to find a file.
> 	* utils.c (gdb_realpath): Change canonicalize_file_name
> 	to canonicalize_filename_mode with CAN_MISSING flag.
>
> gdb/testsuite/ChangeLog:
>
> 	PR breakpoints/17497
> 	* gdb.base/Makefile.in: Add tryrealpath test.
> 	* gdb.base/break-canonical-path.c: New test.
> 	* gdb.base/break-canonical-path.exp: New file.
> ---
>   gdb/defs.h                                      |    7 +-
>   gdb/source.c                                    |   37 ++++++++--
>   gdb/testsuite/gdb.base/Makefile.in              |    4 +-
>   gdb/testsuite/gdb.base/break-canonical-path.c   |   22 ++++++
>   gdb/testsuite/gdb.base/break-canonical-path.exp |   83 +++++++++++++++++++++++
>   gdb/utils.c                                     |    3 +-
>   6 files changed, 146 insertions(+), 10 deletions(-)
>   create mode 100644 gdb/testsuite/gdb.base/break-canonical-path.c
>   create mode 100644 gdb/testsuite/gdb.base/break-canonical-path.exp
>
> diff --git a/gdb/defs.h b/gdb/defs.h
> index a1cd45f..fac9b2c 100644
> --- a/gdb/defs.h
> +++ b/gdb/defs.h
> @@ -310,9 +310,10 @@ extern const char *pc_prefix (CORE_ADDR);
>   /* From source.c */
>
>   /* See openp function definition for their description.  */
> -#define OPF_TRY_CWD_FIRST     0x01
> -#define OPF_SEARCH_IN_PATH    0x02
> -#define OPF_RETURN_REALPATH   0x04
> +#define OPF_TRY_CWD_FIRST   0x01
> +#define OPF_SEARCH_IN_PATH  0x02
> +#define OPF_RETURN_REALPATH 0x04
> +#define OPF_TRY_REALPATH    0x08
>
>   extern int openp (const char *, int, const char *, int, char **);
>
> diff --git a/gdb/source.c b/gdb/source.c
> index 574d9fa..1a3fbf9 100644
> --- a/gdb/source.c
> +++ b/gdb/source.c
> @@ -769,8 +769,18 @@ openp (const char *path, int opts, const char *string,
>
>         if (is_regular_file (string))
>   	{
> -	  filename = alloca (strlen (string) + 1);
> -	  strcpy (filename, string);
> +	  if (opts & OPF_TRY_REALPATH)
> +	    {
> +	      char *real_path = gdb_realpath (string);
> +	      filename = alloca (strlen (real_path) + 1);
> +	      strcpy (filename, real_path);
> +	      xfree (real_path);
> +	    }
> +	  else
> +	    {
> +	      filename = alloca (strlen (string) + 1);
> +	      strcpy (filename, string);
> +	    }
>   	  fd = gdb_open_cloexec (filename, mode, 0);
>   	  if (fd >= 0)
>   	    goto done;
> @@ -867,6 +877,25 @@ openp (const char *path, int opts, const char *string,
>         strcat (filename + len, SLASH_STRING);
>         strcat (filename, string);
>
> +      /* Try the canonical path. */
> +      if (opts & OPF_TRY_REALPATH)
> +	{
> +	  char *real_path;
> +	  int newlen;
> +
> +	  real_path = gdb_realpath (filename);
> +
> +	  /* First, realloc the filename buffer if too short.  */
> +	  newlen = len + strlen (real_path) + 1;
> +	  if (newlen > alloclen)
> +	    {
> +	      alloclen = newlen;
> +	      filename = alloca (alloclen);
> +	    }
> +	  strcpy (filename, real_path);
> +	  xfree (real_path);
> +	}
> +
>         if (is_regular_file (filename))
>   	{
>   	  fd = gdb_open_cloexec (filename, mode, 0);
> @@ -1083,8 +1112,8 @@ find_and_open_source (const char *filename,
>           }
>       }
>
> -  result = openp (path, OPF_SEARCH_IN_PATH | OPF_RETURN_REALPATH, filename,
> -		  OPEN_MODE, fullname);
> +  result = openp (path, OPF_SEARCH_IN_PATH | OPF_RETURN_REALPATH |
> +		  OPF_TRY_REALPATH, filename, OPEN_MODE, fullname);
>     if (result < 0)
>       {
>         /* Didn't work.  Try using just the basename.  */
> diff --git a/gdb/testsuite/gdb.base/Makefile.in b/gdb/testsuite/gdb.base/Makefile.in
> index dda3169..1c23bbd 100644
> --- a/gdb/testsuite/gdb.base/Makefile.in
> +++ b/gdb/testsuite/gdb.base/Makefile.in
> @@ -4,8 +4,8 @@ srcdir = @srcdir@
>   EXECUTABLES = a2-run advance all-types annota1 annota1-watch_thread_num \
>   	annota3 anon args arrayidx async attach attach-pie-misread \
>   	attach2 auxv bang\! bfp-test bigcore bitfields bitfields2 \
> -	break break-always break-entry break-interp-test breako2 \
> -	breakpoint-shadow break-on-linker-gcd-function \
> +	break break-always break-canonical-path break-entry break-interp-test \
> +	breako2 breakpoint-shadow break-on-linker-gcd-function \
>   	call-ar-st call-rt-st call-sc-t* call-signals \
>   	call-strs callexit callfuncs callfwmall charset checkpoint \
>   	chng-syms code_elim1 code_elim2 commands compiler completion complex \
> diff --git a/gdb/testsuite/gdb.base/break-canonical-path.c b/gdb/testsuite/gdb.base/break-canonical-path.c
> new file mode 100644
> index 0000000..7e362b2
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/break-canonical-path.c
> @@ -0,0 +1,22 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2015 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 (void)
> +{
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/break-canonical-path.exp b/gdb/testsuite/gdb.base/break-canonical-path.exp
> new file mode 100644
> index 0000000..511acaa
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/break-canonical-path.exp
> @@ -0,0 +1,83 @@
> +# Copyright (C) 2015 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/>.
> +
> +# This file tests if we can set a breakpoint provided our path is the
> +# canonicalized path of a longer path with some parts that are not
> +# present on the fs.
> +# See breakpoints/17497 for more information
> +
> +# main directory for compilation
> +set canonical_tmp_dir "break-canonical-path-tmp"
> +# this directory will be deleted before putting the breakpoint
> +set canonical_relative_dir "tmp"
> +set canonical_srcfile_basename "break-canonical-path.c"
> +
> +standard_testfile $canonical_tmp_dir/$canonical_relative_dir/../$canonical_srcfile_basename
> +
> +proc canonical_cleanup {rmsrcfile rmreldir rmtmpdir} {
> +    global subdir
> +    global canonical_tmp_dir
> +    global canonical_relative_dir
> +    global canonical_srcfile_basename
> +
> +    if { $rmsrcfile && [catch { file delete $subdir/$canonical_tmp_dir/$canonical_srcfile_basename }] } {
> +	print "file delete $subdir/$canonical_tmp_dir/$canonical_srcfile_basename failed"
> +    }
> +    if { $rmreldir && [catch { file delete  $subdir/$canonical_tmp_dir/$canonical_relative_dir }] } {
> +	print "file delete $subdir/$canonical_tmp_dir/$canonical_relative_dir failed"
> +    }
> +    if { $rmtmpdir && [catch { file delete  $subdir/$canonical_tmp_dir }] } {
> +	print "file delete $subdir/$canonical_tmp_di failed"
> +    }
> +}
> +
> +if [is_remote host] {
> +    unsupported "Compiling on a remote host does not support a filename with directory."
> +    return 0
> +}
> +
> +if [catch { file mkdir "$subdir/$canonical_tmp_dir/$canonical_relative_dir" }]  {
> +    untested "file mkdir $subdir/$canonical_tmp_dir/$canonical_relative_dir failed"
> +    canonical_cleanup false true true
> +    return 0
> +}
> +
> +if [catch { file copy $srcdir/$subdir/$canonical_srcfile_basename $subdir/$canonical_tmp_dir }] {
> +    untested "file copy $srcdir/$subdir/$srcfile_basename $subdir/$canonical_tmp_dir failed"
> +    canonical_cleanup false true true
> +    return 0
> +}
> +
> +#compile with the to be deleted directory so that it is in the debug info
> +set err [gdb_compile "$subdir/$srcfile" $binfile executable {debug}]
> +if { $err != "" } {
> +    untested "${srcfile} compilation failed"
> +    canonical_cleanup true true true
> +    return -1
> +}
> +
> +#remove the directory so that we can test after that we can break even if it's not there
> +#using the canonicalized version of the path
> +if [catch { file delete $subdir/$canonical_tmp_dir/$canonical_relative_dir }] {
> +    untested "rmdir  $subdir/$canonical_tmp_dir/$canonical_relative_dir failed"
> +    canonical_cleanup true true true
> +    return 0
> +}
> +
> +clean_restart ${testfile}
> +
> +gdb_breakpoint $subdir/$canonical_tmp_dir/$canonical_srcfile_basename:[gdb_get_line_number "main" $srcdir/$subdir/$canonical_srcfile_basename] {message}
> +
> +canonical_cleanup true true true
> diff --git a/gdb/utils.c b/gdb/utils.c
> index 909476b..c97ead3 100644
> --- a/gdb/utils.c
> +++ b/gdb/utils.c
> @@ -68,6 +68,7 @@
>   #include "gdb_usleep.h"
>   #include "interps.h"
>   #include "gdb_regex.h"
> +#include "canonicalize.h"
>
>   #if !HAVE_DECL_MALLOC
>   extern PTR malloc ();		/* ARI: PTR */
> @@ -2889,7 +2890,7 @@ gdb_realpath (const char *filename)
>     }
>   #else
>     {
> -    char *rp = canonicalize_file_name (filename);
> +    char *rp = canonicalize_filename_mode (filename, CAN_MISSING);
>
>       if (rp != NULL)
>         return rp;
>



More information about the Gdb-patches mailing list