Mark Wielaard 14e6c2
commit be82bb5f9dfecd854c53eda321d1914f28f19790
Mark Wielaard 14e6c2
Author: Mark Wielaard <mark@klomp.org>
Mark Wielaard 14e6c2
Date:   Sat Dec 9 23:01:29 2017 +0100
Mark Wielaard 6cc1e8
Mark Wielaard 14e6c2
    Fix gnu debug alt file resolving.
Mark Wielaard 14e6c2
    
Mark Wielaard 14e6c2
    https://bugs.kde.org/show_bug.cgi?id=387773
Mark Wielaard 14e6c2
    
Mark Wielaard 14e6c2
    The path to the alt file is relative to the actual debug file.
Mark Wielaard 14e6c2
    Make sure that we got the real file, not a (build-id) symlink.
Mark Wielaard 14e6c2
    Also handle the case where a debug or alt file is an absolute path.
Mark Wielaard 6cc1e8
Mark Wielaard 6cc1e8
diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c
Mark Wielaard 14e6c2
index e612250..c19ff21 100644
Mark Wielaard 6cc1e8
--- a/coregrind/m_debuginfo/readelf.c
Mark Wielaard 6cc1e8
+++ b/coregrind/m_debuginfo/readelf.c
Mark Wielaard 6cc1e8
@@ -33,6 +33,7 @@
Mark Wielaard 6cc1e8
 
Mark Wielaard 6cc1e8
 #include "pub_core_basics.h"
Mark Wielaard 6cc1e8
 #include "pub_core_vki.h"
Mark Wielaard 6cc1e8
+#include "pub_core_vkiscnums.h"
Mark Wielaard 6cc1e8
 #include "pub_core_debuginfo.h"
Mark Wielaard 6cc1e8
 #include "pub_core_libcbase.h"
Mark Wielaard 6cc1e8
 #include "pub_core_libcprint.h"
Mark Wielaard 6cc1e8
@@ -40,6 +41,7 @@
Mark Wielaard 6cc1e8
 #include "pub_core_machine.h"      /* VG_ELF_CLASS */
Mark Wielaard 6cc1e8
 #include "pub_core_options.h"
Mark Wielaard 6cc1e8
 #include "pub_core_oset.h"
Mark Wielaard 6cc1e8
+#include "pub_core_syscall.h"
Mark Wielaard 6cc1e8
 #include "pub_core_tooliface.h"    /* VG_(needs) */
Mark Wielaard 6cc1e8
 #include "pub_core_xarray.h"
Mark Wielaard 6cc1e8
 #include "priv_misc.h"             /* dinfo_zalloc/free/strdup */
Mark Wielaard 14e6c2
@@ -1323,6 +1325,12 @@ DiImage* find_debug_file( struct _DebugInfo* di,
Mark Wielaard 14e6c2
                      + (extrapath ? VG_(strlen)(extrapath) : 0)
Mark Wielaard 14e6c2
                      + (serverpath ? VG_(strlen)(serverpath) : 0));
Mark Wielaard 14e6c2
 
Mark Wielaard 14e6c2
+      if (debugname[0] == '/') {
Mark Wielaard 14e6c2
+         VG_(sprintf)(debugpath, "%s", debugname);
Mark Wielaard 14e6c2
+         dimg = open_debug_file(debugpath, buildid, crc, rel_ok, NULL);
Mark Wielaard 14e6c2
+         if (dimg != NULL) goto dimg_ok;
Mark Wielaard 14e6c2
+      }
Mark Wielaard 14e6c2
+
Mark Wielaard 14e6c2
       VG_(sprintf)(debugpath, "%s/%s", objdir, debugname);
Mark Wielaard 14e6c2
       dimg = open_debug_file(debugpath, buildid, crc, rel_ok, NULL);
Mark Wielaard 14e6c2
       if (dimg != NULL) goto dimg_ok;
Mark Wielaard 14e6c2
@@ -1527,6 +1535,56 @@ static Bool check_compression(ElfXX_Shdr* h, DiSlice* s) {
Mark Wielaard 6cc1e8
     return True;
Mark Wielaard 6cc1e8
 }
Mark Wielaard 6cc1e8
 
Mark Wielaard 14e6c2
+/* Helper function to get the readlink path. Returns a copy of path if the
Mark Wielaard 14e6c2
+   file wasn't a symbolic link. Returns NULL on error. Unless NULL is
Mark Wielaard 14e6c2
+   returned the result needs to be released with dinfo_free.
Mark Wielaard 6cc1e8
+*/
Mark Wielaard 6cc1e8
+static HChar* readlink_path (const HChar *path)
Mark Wielaard 6cc1e8
+{
Mark Wielaard 6cc1e8
+   SizeT bufsiz = VG_(strlen)(path);
Mark Wielaard 6cc1e8
+   HChar *buf = ML_(dinfo_strdup)("readlink_path.strdup", path);
Mark Wielaard 14e6c2
+   UInt   tries = 6;
Mark Wielaard 6cc1e8
+
Mark Wielaard 6cc1e8
+   while (tries > 0) {
Mark Wielaard 6cc1e8
+      SysRes res;
Mark Wielaard 6cc1e8
+#if defined(VGP_arm64_linux)
Mark Wielaard 6cc1e8
+      res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD,
Mark Wielaard 6cc1e8
+                                              (UWord)path, (UWord)buf, bufsiz);
Mark Wielaard 6cc1e8
+#elif defined(VGO_linux) || defined(VGO_darwin)
Mark Wielaard 6cc1e8
+      res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
Mark Wielaard 6cc1e8
+#elif defined(VGO_solaris)
Mark Wielaard 6cc1e8
+      res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path,
Mark Wielaard 6cc1e8
+                             (UWord)buf, bufsiz);
Mark Wielaard 6cc1e8
+#else
Mark Wielaard 6cc1e8
+#       error Unknown OS
Mark Wielaard 6cc1e8
+#endif
Mark Wielaard 14e6c2
+      if (sr_isError(res)) {
Mark Wielaard 14e6c2
+         if (sr_Err(res) == VKI_EINVAL)
Mark Wielaard 14e6c2
+            return buf; // It wasn't a symbolic link, return the strdup result.
Mark Wielaard 14e6c2
+         ML_(dinfo_free)(buf);
Mark Wielaard 14e6c2
+         return NULL;
Mark Wielaard 14e6c2
+      }
Mark Wielaard 6cc1e8
+
Mark Wielaard 14e6c2
+      SSizeT r = sr_Res(res);
Mark Wielaard 14e6c2
+      if (r < 0) break;
Mark Wielaard 6cc1e8
+      if (r == bufsiz) {  // buffer too small; increase and retry
Mark Wielaard 6cc1e8
+         bufsiz *= 2 + 16;
Mark Wielaard 6cc1e8
+         buf = ML_(dinfo_realloc)("readlink_path.realloc", buf, bufsiz);
Mark Wielaard 6cc1e8
+         tries--;
Mark Wielaard 6cc1e8
+         continue;
Mark Wielaard 6cc1e8
+      }
Mark Wielaard 6cc1e8
+      buf[r] = '\0';
Mark Wielaard 6cc1e8
+      break;
Mark Wielaard 6cc1e8
+   }
Mark Wielaard 6cc1e8
+
Mark Wielaard 6cc1e8
+   if (tries == 0) { // We tried, but weird long path?
Mark Wielaard 6cc1e8
+      ML_(dinfo_free)(buf);
Mark Wielaard 6cc1e8
+      return NULL;
Mark Wielaard 6cc1e8
+   }
Mark Wielaard 6cc1e8
+
Mark Wielaard 6cc1e8
+  return buf;
Mark Wielaard 6cc1e8
+}
Mark Wielaard 6cc1e8
+
Mark Wielaard 6cc1e8
 /* The central function for reading ELF debug info.  For the
Mark Wielaard 6cc1e8
    object/exe specified by the DebugInfo, find ELF sections, then read
Mark Wielaard 6cc1e8
    the symbols, line number info, file name info, CFA (stack-unwind
Mark Wielaard 14e6c2
@@ -2926,8 +2984,12 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di )
Mark Wielaard 6cc1e8
                                 (debugaltlink_escn.szB - buildid_offset)
Mark Wielaard 6cc1e8
                                 * 2 + 1);
Mark Wielaard 6cc1e8
 
Mark Wielaard 6cc1e8
-         /* The altfile might be relative to the debug file or main file. */
Mark Wielaard 6cc1e8
+         /* The altfile might be relative to the debug file or main file.
Mark Wielaard 6cc1e8
+	    Make sure that we got the real file, not a symlink.  */
Mark Wielaard 6cc1e8
          HChar *dbgname = di->fsm.dbgname ? di->fsm.dbgname : di->fsm.filename;
Mark Wielaard 6cc1e8
+         HChar* rdbgname = readlink_path (dbgname);
Mark Wielaard 6cc1e8
+         if (rdbgname == NULL)
Mark Wielaard 6cc1e8
+            rdbgname = ML_(dinfo_strdup)("rdbgname", dbgname);
Mark Wielaard 6cc1e8
 
Mark Wielaard 6cc1e8
          for (j = 0; j < debugaltlink_escn.szB - buildid_offset; j++)
Mark Wielaard 6cc1e8
             VG_(sprintf)(
Mark Wielaard 14e6c2
@@ -2937,9 +2999,11 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di )
Mark Wielaard 6cc1e8
                                         + buildid_offset + j));
Mark Wielaard 6cc1e8
 
Mark Wielaard 6cc1e8
          /* See if we can find a matching debug file */
Mark Wielaard 6cc1e8
-         aimg = find_debug_file( di, dbgname, altbuildid,
Mark Wielaard 6cc1e8
+         aimg = find_debug_file( di, rdbgname, altbuildid,
Mark Wielaard 6cc1e8
                                  altfile_str_m, 0, True );
Mark Wielaard 6cc1e8
 
Mark Wielaard 6cc1e8
+         ML_(dinfo_free)(rdbgname);
Mark Wielaard 6cc1e8
+
Mark Wielaard 6cc1e8
          if (altfile_str_m)
Mark Wielaard 6cc1e8
             ML_(dinfo_free)(altfile_str_m);
Mark Wielaard 6cc1e8
          ML_(dinfo_free)(altbuildid);
Mark Wielaard 275b4b
Mark Wielaard 275b4b
diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c
Mark Wielaard 275b4b
index c19ff212b..70c28e629 100644
Mark Wielaard 275b4b
--- a/coregrind/m_debuginfo/readelf.c
Mark Wielaard 275b4b
+++ b/coregrind/m_debuginfo/readelf.c
Mark Wielaard 275b4b
@@ -1582,6 +1582,24 @@ static HChar* readlink_path (const HChar *path)
Mark Wielaard 275b4b
       return NULL;
Mark Wielaard 275b4b
    }
Mark Wielaard 275b4b
 
Mark Wielaard 275b4b
+  if (buf[0] == '/')
Mark Wielaard 275b4b
+    return buf;
Mark Wielaard 275b4b
+
Mark Wielaard 275b4b
+  /* Relative path, add link dir.  */
Mark Wielaard 275b4b
+  HChar *linkdirptr;
Mark Wielaard 275b4b
+  SizeT linkdir_len = VG_(strlen)(path);
Mark Wielaard 275b4b
+  if ((linkdirptr = VG_(strrchr)(path, '/')) != NULL)
Mark Wielaard 275b4b
+    linkdir_len -= VG_(strlen)(linkdirptr + 1);
Mark Wielaard 275b4b
+
Mark Wielaard 275b4b
+  SizeT buflen = VG_(strlen)(buf);
Mark Wielaard 275b4b
+  SizeT needed = linkdir_len + buflen + 1;
Mark Wielaard 275b4b
+  if (bufsiz < needed)
Mark Wielaard 275b4b
+    buf = ML_(dinfo_realloc)("readlink_path.linkdir", buf, needed);
Mark Wielaard 275b4b
+
Mark Wielaard 275b4b
+  VG_(memmove)(buf + linkdir_len, buf, buflen);
Mark Wielaard 275b4b
+  VG_(memcpy)(buf, path, linkdir_len);
Mark Wielaard 275b4b
+  buf[needed - 1] = '\0';
Mark Wielaard 275b4b
+
Mark Wielaard 275b4b
   return buf;
Mark Wielaard 275b4b
 }
Mark Wielaard 275b4b
 
Mark Wielaard 275b4b