Allow readlink to handle /proc/self/exe and /proc/<pid>/exe properly.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3048 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_syscalls.c b/coregrind/vg_syscalls.c
index 0ad289c..4b47203 100644
--- a/coregrind/vg_syscalls.c
+++ b/coregrind/vg_syscalls.c
@@ -4401,18 +4401,33 @@
    }
 }
 
-PRE(sys_readlink, 0)
+PRE(sys_readlink, Special)
 {
+   char name[25];
+
    PRINT("sys_readlink ( %p, %p, %llu )", arg1,arg2,(ULong)arg3);
    PRE_REG_READ3(long, "readlink",
                  const char *, path, char *, buf, int, bufsiz);
    PRE_MEM_RASCIIZ( "readlink(path)", arg1 );
    PRE_MEM_WRITE( "readlink(buf)", arg2,arg3 );
-}
 
-POST(sys_readlink)
-{
-   POST_MEM_WRITE( arg2, res );
+   /*
+    * Handle the single case where readlink failed reading /proc/self/exe.
+    */
+
+   VG_(sprintf)(name, "/proc/%d/exe", VG_(getpid)());
+   
+   if (VG_(strcmp)((Char *)arg1, name) == 0 ||
+      VG_(strcmp)((Char *)arg1, "/proc/self/exe") == 0) {
+      VG_(sprintf)(name, "/proc/self/fd/%d", VG_(clexecfd));
+      res = VG_(do_syscall)(SYSNO, name, arg2, arg3);
+   }
+   else {
+      res = VG_(do_syscall)(SYSNO, arg1, arg2, arg3);
+   }
+
+   if (res > 0)
+      POST_MEM_WRITE( arg2, res );
 }
 
 PRE(sys_readv, MayBlock)
diff --git a/coregrind/x86-linux/syscalls.c b/coregrind/x86-linux/syscalls.c
index 7152b08..31ef360 100644
--- a/coregrind/x86-linux/syscalls.c
+++ b/coregrind/x86-linux/syscalls.c
@@ -449,7 +449,7 @@
    GENX_(__NR_symlink,           sys_symlink),        // 83
    //   (__NR_oldlstat,          sys_lstat),          // 84 -- obsolete
 
-   GENXY(__NR_readlink,          sys_readlink),       // 85
+   GENX_(__NR_readlink,          sys_readlink),       // 85
    //   (__NR_uselib,            sys_uselib),         // 86 */Linux
    //   (__NR_swapon,            sys_swapon),         // 87 */Linux
    //   (__NR_reboot,            sys_reboot),         // 88 */Linux