From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 14993 invoked by alias); 19 Mar 2002 16:12:45 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 14665 invoked from network); 19 Mar 2002 16:12:38 -0000 Received: from unknown (HELO dublin.ACT-Europe.FR) (212.157.227.154) by sources.redhat.com with SMTP; 19 Mar 2002 16:12:38 -0000 Received: from berlin.ACT-Europe.FR (berlin.int.act-europe.fr [10.10.0.169]) by dublin.ACT-Europe.FR (Postfix) with ESMTP id 8DA9A229FFF for ; Tue, 19 Mar 2002 17:12:37 +0100 (MET) Received: by berlin.ACT-Europe.FR (Postfix, from userid 507) id 38D46963; Tue, 19 Mar 2002 17:12:37 +0100 (CET) Date: Tue, 19 Mar 2002 08:12:00 -0000 From: Joel Brobecker To: gdb-patches@sources.redhat.com Subject: [RFC] gdb_realpath causes problems with GVD Message-ID: <20020319171236.D6465@act-europe.fr> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="cWoXeonUoKmBZSoM" Content-Disposition: inline User-Agent: Mutt/1.2.5i X-SW-Source: 2002-03/txt/msg00345.txt.bz2 --cWoXeonUoKmBZSoM Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 3173 Machine: x86-inux The problem appears when some of the files used to build the application are symbolic links and when GDB annotations are activated. For us, this happens when GVD, our graphical front-end, drives GDB. First, the context: In Ada, the filename associated to a unit need to follow a strict convention, and this convention is dictated by the compiler. For instance, the GNAT convention says that the spec of package Hello must be located in file hello.ads. But the Apex naming schemes says that it must be named hello.1.ada. The trouble starts when somebody wants to develop/navigate using Apex, while building and debugging using GNAT. In order to solve this naming issue, it has been decided to keep the Apex filenames, and to create one symbolic link per file which name follows GNAT naming scheme. So far, so good. Now, here is an example of this situation, where I replace Ada by C, which shows the problem we encountered. Supose we have directory called symlinks, in which we have one C file, called toto.C, and one symbolic link to this file called toto.c: << void break_me (void) { } int main (void) { break_me (); } >> We build the executable using the symlink: % gcc -g -o toto toto.c Let's debug toto to see what happens: << GNU gdb 2002-03-19-cvs [...] This GDB was configured as "i686-pc-linux-gnu"... (gdb) set annotate 1 (gdb) b break_me Breakpoint 1 at 0x804846b: file toto.c, line 4. (gdb) run Starting program: /bonn.a/brobecke/symlinks/toto Breakpoint 1, break_me () at toto.c:4 yy/bonn.a/brobecke/symlinks/toto.C:4:23:beg:0x804846b ^^^^^^ >> As you see, GDB has translated toto.c into toto.C. This translation causes GDB to think that the inferior stopped in a file named toto.C (which is not known to GDB, since the compiler used only toto.c). As a consequence, when the user tries to put breakpoints using the GVD, GVD issues the following break command (gdb) break toto.C:4 to which GDB answers No source file named toto.C The translation is performed by gdb_realpath. I searched the gdb-patches archives, and found the reason for this translation in a message from Tom Tromey. I think I found a way to keep the fix to his problem and then at the same time fix our issue: instead of canonicalizing the entire filename, I suggest that we only expand the directory prefix (ie the part returned by the "dirname" unix command). Here is a patch which implements this idea. I'd like to get your opinion on it. Ideally, I'll like to commit this change if it is ok. Here is the change log: 2002-03-19 Joel Brobecker * utils.c (gdb_canonicalize_path): New function. (gdb_realpath_fallback): New function. (gdb_realpath): Restrict the canonicalization to the directory prefix rather than canonicalizing the entire filename, to avoid returning a filename unknown to GDB when the file is actually a symbolic link. This change was tested BTW: I just a message requesting a change in the exact same function. I haven't integrated it yet, because I don't know if it will be accepted or not. If it is accepted, I can merge it and resubmit. Thanks, -- Joel --cWoXeonUoKmBZSoM Content-Type: text/plain; charset=us-ascii Content-Description: utils.c.diff Content-Disposition: attachment; filename=difs Content-length: 4450 Index: utils.c =================================================================== RCS file: /cvs/src/src/gdb/utils.c,v retrieving revision 1.70 diff -c -3 -p -r1.70 utils.c *** utils.c 2002/03/19 02:51:07 1.70 --- utils.c 2002/03/19 16:08:08 *************** string_to_core_addr (const char *my_stri *** 2531,2558 **** return addr; } - char * - gdb_realpath (const char *filename) - { #if defined(HAVE_REALPATH) # if defined (PATH_MAX) ! char buf[PATH_MAX]; # define USE_REALPATH # elif defined (MAXPATHLEN) ! char buf[MAXPATHLEN]; # define USE_REALPATH # elif defined (HAVE_UNISTD_H) && defined(HAVE_ALLOCA) ! char *buf = alloca ((size_t)pathconf ("/", _PC_PATH_MAX)); # define USE_REALPATH # endif #endif /* HAVE_REALPATH */ ! #if defined(USE_REALPATH) ! char *rp = realpath (filename, buf); ! return xstrdup (rp ? rp : filename); ! #elif defined(HAVE_CANONICALIZE_FILE_NAME) ! return canonicalize_file_name (filename); #else return xstrdup (filename); #endif } --- 2531,2640 ---- return addr; } #if defined(HAVE_REALPATH) # if defined (PATH_MAX) ! static const int max_rp_buffer_size = PATH_MAX; # define USE_REALPATH # elif defined (MAXPATHLEN) ! static const int max_rp_buffer_size = MAXPATHLEN; # define USE_REALPATH # elif defined (HAVE_UNISTD_H) && defined(HAVE_ALLOCA) ! static const int max_rp_buffer_size = pathconf ("/", _PC_PATH_MAX); # define USE_REALPATH # endif #endif /* HAVE_REALPATH */ + + /* + * gdb_canonicalize_path + * + * Sets RESOLVED_PATH to the canonicalized form of FILENAME, as realpath () + * does. If there is no error, it returns a pointer to the resolved path. + * Otherwise, returns null. + * + * Returns null on platforms where no canonicalization routine (such as + * realpath for instance) are available. + */ + static char * + gdb_canonicalize_path (const char *path, char *resolved_path) + { + #if defined (USE_REALPATH) + return realpath (path, resolved_path); + + #elif defined (HAVE_CANONICALIZE_FILE_NAME) + const char *canonicalized = canonicalize_file_name (path); + + if (!canonicalized) + return null; ! strcpy (resolved_path, canonicalized); ! return resolved_path; ! #else + return null; + + #endif + } + + /* + * gdb_realpath_fallback + * + * This is the fallback version of gdb_realpath when there is no + * canonicalization routine (such as realpath for instance) available. + * In this case, we simply return a copy of FILENAME. + */ + static char * + gdb_realpath_fallback (const char *filename) + { return xstrdup (filename); + } + + /* + * gdb_realpath + * + * Return a copy of FILENAME, with its directory prefix canonicalized, + * as for realpath() (see "man realpath" for more details on what + * this function does), or simply a copy of FILENAME on platforms + * where no canonicalization routine is available. + * + * We don't want to canonicalize the entire FILENAME, because + * the canonicalization routines used to perform the operation also + * expand symbolic links. If FILENAME is itself a link to another file, + * it can lead GDB to translate FILENAME into another filename that GDB + * does not know about. This can confuse graphical front-ends for GDB + * which, like GVD, rely on the filename displayed by GDB to get the + * current file:line location, for example. + */ + char * + gdb_realpath (const char *filename) + { + const char *base_name = lbasename (filename); + char *dir_name; + char *buf; + char *rp = NULL; + + #if !defined (USE_REALPATH) || !defined (HAVE_CANONICALIZE_FILE_NAME) + return gdb_realpath_fallback (filename); #endif + + /* If basename and filename are equal, then there is no path to + canonicalize. Just return a copy of filename */ + if (base_name == filename) + return xstrdup (filename); + + dir_name = alloca ((size_t) (base_name - filename + 1)); + strncpy (dir_name, filename, base_name - filename); + + /* Allocate enough space to contain the largest path possible returned + by realpath, plus the SLASH_STRING and the base_name */ + buf = alloca ((size_t) max_rp_buffer_size + + strlen (SLASH_STRING) + strlen (base_name)); + rp = gdb_canonicalize_path (dir_name, buf); + + if (rp == NULL) + return xstrdup (filename); + + strcat (buf, SLASH_STRING); + strcat (buf, base_name); + return xstrdup (buf); } + --cWoXeonUoKmBZSoM--