Hello Roland and others,

 

I found an issue with dwarf_getsrc_file() and its ability to support a combination of Windows and UNIX slashes (‘\\’ vs. ‘/’).  The problem occurs when I load an ELF file that was built on Windows and has relative paths to source files (i.e. “dir\\file.c”).  The logic in dwarf_getsrc_file() currently handles this as a basename path (is_basename is true).  In this case, it will compare “dir\\file.c” with basename(“dir/file.c”), which will always fail.  The fix for this is to check for the presence of either a ‘/’ or ‘\\’ in the filename passed into the function.

 

Once this is fixed, there’s still the issue of using a straight strcmp() to compare the paths, which fails because the separator is different (I always use ‘/’ as my separator on Linux – I haven’t found an easy way to determine which separator to use for a given ELF file, but maybe someone has a suggestion here and I could change my application code instead).  But it would be nice if libdw handled ELF files built on both Windows and Linux seamlessly.

 

I propose the changes below to fix these issues (note that this diff is against 0.142, but nothing has changed in this file since then).  I’m certain that this is not the most elegant way to solve the problem, so if someone wants to improve on this and get it into the trunk, that would be most excellent.

 

Please let me know if I can provide any additional information to help get this fixed.  Also, I will happily test out any fixes if that would be helpful.

 

Thanks for your time!
--Mike

 

diff --git a/libdw/dwarf_getsrc_file.c b/libdw/dwarf_getsrc_file.c

index bc612f6..dcdda68 100644

--- a/libdw/dwarf_getsrc_file.c

+++ b/libdw/dwarf_getsrc_file.c

@@ -59,6 +59,23 @@

 

 #include "libdwP.h"

 

+#include <stdio.h>

+

+int path_chr(char c)

+{

+  if(c == '\\')

+    return '/';

+  return c;

+}

+

+int path_strcmp (const char * p1, const char * p2)

+{

+  for(; path_chr(*p1) == path_chr(*p2); ++p1, ++p2)

+    if(*p1 == 0) {

+      return 0;

+    }

+  return *(unsigned char *)p1 < *(unsigned char *)p2 ? -1 : 1;

+}

 

 int

 dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column,

@@ -67,7 +84,8 @@ dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column,

   if (dbg == NULL)

     return -1;

 

-  bool is_basename = strchr (fname, '/') == NULL;

+  bool is_basename = (strchr (fname, '/') == NULL)

+    && (strchr(fname, '\\') == NULL);

 

   size_t max_match = *nsrcs ?: ~0u;

   size_t act_match = *nsrcs;

@@ -119,9 +137,9 @@ dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column,

              /* Match the name with the name the user provided.  */

              const char *fname2 = line->files->info[lastfile].name;

              if (is_basename)

-               lastmatch = strcmp (basename (fname2), fname) == 0;

+               lastmatch = path_strcmp (basename (fname2), fname) == 0;

              else

-               lastmatch = strcmp (fname2, fname) == 0;

+               lastmatch = path_strcmp (fname2, fname) == 0;

            }

          if (!lastmatch)

            continue;