Blob Blame History Raw
From f3521f1d69312eb476c53eea06ee1187844efe18 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mark@klomp.org>
Date: Sat, 9 Dec 2017 23:01:29 +0100
Subject: [PATCH] Fix gnu debug alt file resolving.

The path to the alt file is relative to the actual debug file.
Make sure that we got the real file, not a (build-id) symlink.
---
 coregrind/m_debuginfo/readelf.c | 57 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 55 insertions(+), 2 deletions(-)

diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c
index e612250..2d52322 100644
--- a/coregrind/m_debuginfo/readelf.c
+++ b/coregrind/m_debuginfo/readelf.c
@@ -33,6 +33,7 @@
 
 #include "pub_core_basics.h"
 #include "pub_core_vki.h"
+#include "pub_core_vkiscnums.h"
 #include "pub_core_debuginfo.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcprint.h"
@@ -40,6 +41,7 @@
 #include "pub_core_machine.h"      /* VG_ELF_CLASS */
 #include "pub_core_options.h"
 #include "pub_core_oset.h"
+#include "pub_core_syscall.h"
 #include "pub_core_tooliface.h"    /* VG_(needs) */
 #include "pub_core_xarray.h"
 #include "priv_misc.h"             /* dinfo_zalloc/free/strdup */
@@ -1527,6 +1529,51 @@ static Bool check_compression(ElfXX_Shdr* h, DiSlice* s) {
     return True;
 }
 
+/* Helper function to get the readlink path. Returns NULL on error.
+   Otherwise the result needs to be released with dinfo_free.
+*/
+static HChar* readlink_path (const HChar *path)
+{
+   SizeT bufsiz = VG_(strlen)(path);
+   HChar *buf = ML_(dinfo_strdup)("readlink_path.strdup", path);
+   UInt   tries = 8;
+
+   while (tries > 0) {
+      SysRes res;
+#if defined(VGP_arm64_linux)
+      res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD,
+                                              (UWord)path, (UWord)buf, bufsiz);
+#elif defined(VGO_linux) || defined(VGO_darwin)
+      res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
+#elif defined(VGO_solaris)
+      res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path,
+                             (UWord)buf, bufsiz);
+#else
+#       error Unknown OS
+#endif
+   if (sr_isError(res))
+      return NULL;
+
+   SSizeT r = sr_Res(res);
+   if (r < 0) break;
+      if (r == bufsiz) {  // buffer too small; increase and retry
+         bufsiz *= 2 + 16;
+         buf = ML_(dinfo_realloc)("readlink_path.realloc", buf, bufsiz);
+         tries--;
+         continue;
+      }
+      buf[r] = '\0';
+      break;
+   }
+
+   if (tries == 0) { // We tried, but weird long path?
+      ML_(dinfo_free)(buf);
+      return NULL;
+   }
+
+  return buf;
+}
+
 /* The central function for reading ELF debug info.  For the
    object/exe specified by the DebugInfo, find ELF sections, then read
    the symbols, line number info, file name info, CFA (stack-unwind
@@ -2926,8 +2973,12 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di )
                                 (debugaltlink_escn.szB - buildid_offset)
                                 * 2 + 1);
 
-         /* The altfile might be relative to the debug file or main file. */
+         /* The altfile might be relative to the debug file or main file.
+	    Make sure that we got the real file, not a symlink.  */
          HChar *dbgname = di->fsm.dbgname ? di->fsm.dbgname : di->fsm.filename;
+         HChar* rdbgname = readlink_path (dbgname);
+         if (rdbgname == NULL)
+            rdbgname = ML_(dinfo_strdup)("rdbgname", dbgname);
 
          for (j = 0; j < debugaltlink_escn.szB - buildid_offset; j++)
             VG_(sprintf)(
@@ -2937,9 +2988,11 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di )
                                         + buildid_offset + j));
 
          /* See if we can find a matching debug file */
-         aimg = find_debug_file( di, dbgname, altbuildid,
+         aimg = find_debug_file( di, rdbgname, altbuildid,
                                  altfile_str_m, 0, True );
 
+         ML_(dinfo_free)(rdbgname);
+
          if (altfile_str_m)
             ML_(dinfo_free)(altfile_str_m);
          ML_(dinfo_free)(altbuildid);
-- 
1.8.3.1