161 lines
5.6 KiB
Diff
161 lines
5.6 KiB
Diff
commit be82bb5f9dfecd854c53eda321d1914f28f19790
|
|
Author: Mark Wielaard <mark@klomp.org>
|
|
Date: Sat Dec 9 23:01:29 2017 +0100
|
|
|
|
Fix gnu debug alt file resolving.
|
|
|
|
https://bugs.kde.org/show_bug.cgi?id=387773
|
|
|
|
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.
|
|
Also handle the case where a debug or alt file is an absolute path.
|
|
|
|
diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c
|
|
index e612250..c19ff21 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 */
|
|
@@ -1323,6 +1325,12 @@ DiImage* find_debug_file( struct _DebugInfo* di,
|
|
+ (extrapath ? VG_(strlen)(extrapath) : 0)
|
|
+ (serverpath ? VG_(strlen)(serverpath) : 0));
|
|
|
|
+ if (debugname[0] == '/') {
|
|
+ VG_(sprintf)(debugpath, "%s", debugname);
|
|
+ dimg = open_debug_file(debugpath, buildid, crc, rel_ok, NULL);
|
|
+ if (dimg != NULL) goto dimg_ok;
|
|
+ }
|
|
+
|
|
VG_(sprintf)(debugpath, "%s/%s", objdir, debugname);
|
|
dimg = open_debug_file(debugpath, buildid, crc, rel_ok, NULL);
|
|
if (dimg != NULL) goto dimg_ok;
|
|
@@ -1527,6 +1535,56 @@ static Bool check_compression(ElfXX_Shdr* h, DiSlice* s) {
|
|
return True;
|
|
}
|
|
|
|
+/* Helper function to get the readlink path. Returns a copy of path if the
|
|
+ file wasn't a symbolic link. Returns NULL on error. Unless NULL is
|
|
+ returned 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 = 6;
|
|
+
|
|
+ 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)) {
|
|
+ if (sr_Err(res) == VKI_EINVAL)
|
|
+ return buf; // It wasn't a symbolic link, return the strdup result.
|
|
+ ML_(dinfo_free)(buf);
|
|
+ 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 +2984,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 +2999,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);
|
|
|
|
diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c
|
|
index c19ff212b..70c28e629 100644
|
|
--- a/coregrind/m_debuginfo/readelf.c
|
|
+++ b/coregrind/m_debuginfo/readelf.c
|
|
@@ -1582,6 +1582,24 @@ static HChar* readlink_path (const HChar *path)
|
|
return NULL;
|
|
}
|
|
|
|
+ if (buf[0] == '/')
|
|
+ return buf;
|
|
+
|
|
+ /* Relative path, add link dir. */
|
|
+ HChar *linkdirptr;
|
|
+ SizeT linkdir_len = VG_(strlen)(path);
|
|
+ if ((linkdirptr = VG_(strrchr)(path, '/')) != NULL)
|
|
+ linkdir_len -= VG_(strlen)(linkdirptr + 1);
|
|
+
|
|
+ SizeT buflen = VG_(strlen)(buf);
|
|
+ SizeT needed = linkdir_len + buflen + 1;
|
|
+ if (bufsiz < needed)
|
|
+ buf = ML_(dinfo_realloc)("readlink_path.linkdir", buf, needed);
|
|
+
|
|
+ VG_(memmove)(buf + linkdir_len, buf, buflen);
|
|
+ VG_(memcpy)(buf, path, linkdir_len);
|
|
+ buf[needed - 1] = '\0';
|
|
+
|
|
return buf;
|
|
}
|
|
|
|
|