Add VGP_(setup_redirects) to the platform specific layers and use
it to setup vsyscall redirects on amd64 and the _dl_sysinfo_int80
redirect on x86.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3503 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_redir.c b/coregrind/vg_redir.c
index 5da9d38..a76760d 100644
--- a/coregrind/vg_redir.c
+++ b/coregrind/vg_redir.c
@@ -132,6 +132,76 @@
    return from_resolved(redir) && to_resolved(redir);
 }
 
+static void add_resolved(CodeRedirect *redir)
+{
+   switch(redir->type) {
+   case R_REDIRECT:
+      if (VG_(clo_trace_redir)) {
+         VG_(message)(Vg_DebugMsg, "  redir resolved (%s:%s=%p -> ",
+                      redir->from_lib, redir->from_sym, redir->from_addr);
+         VG_(message)(Vg_DebugMsg, "                  %s:%s=%p)",
+                      redir->to_lib, redir->to_sym, redir->to_addr);
+      }
+
+      if (VG_(search_transtab)(NULL, (Addr64)redir->from_addr, False)) {
+         /* For some given (from, to) redir, the "from" function got
+            called before the .so containing "to" became available.  We
+            know this because there is already a translation for the
+            entry point of the original "from".  So the redirect will
+            never actually take effect unless that translation is
+            discarded.  
+
+            Note, we only really need to discard the first bb of the
+            old entry point, and so we avoid the problem of having to
+            figure out how big that bb was -- since it is at least 1
+            byte of original code, we can just pass 1 as the original
+            size to invalidate_translations() and it will indeed get
+            rid of the translation. 
+
+            Note, this is potentially expensive -- discarding
+            translations causes complete unchaining.  
+         */
+         if (VG_(clo_verbosity) > 2 && VG_(clo_trace_redir)) {
+            VG_(message)(Vg_UserMsg,   
+                         "Discarding translation due to redirect of already called function" );
+            VG_(message)(Vg_UserMsg,
+                         "   %s (%p -> %p)",
+                         redir->from_sym, redir->from_addr, redir->to_addr );
+         }
+         VG_(discard_translations)((Addr64)redir->from_addr, 1);
+      }
+
+      {
+         CodeRedirect *r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &redir->from_addr);
+
+         if (r == NULL)
+            VG_(SkipList_Insert)(&sk_resolved_redir, redir);
+         else {
+            /* XXX leak redir */
+            if (VG_(clo_trace_redir))
+               VG_(message)(Vg_DebugMsg, "  redir %s:%s:%p->%s:%s:%p duplicated\n",
+                            redir->from_lib, redir->from_sym, redir->from_addr,
+                            redir->to_lib, redir->to_sym, redir->to_addr);
+         }
+      }
+      break;
+
+   case R_WRAPPER:
+      if (VG_(clo_trace_redir)) {
+         VG_(message)(Vg_DebugMsg, "  wrapper resolved (%s:%s=%p -> wrapper)",
+                      redir->from_lib, redir->from_sym, redir->from_addr);
+      }
+
+      /* XXX redir leaked */
+      //VG_(wrap_function)(redir->from_addr, redir->wrapper);
+      break;
+
+   case R_CLIENT_WRAPPER:
+      VG_(core_panic)("not implemented");
+      break;
+   }
+}
+
 /* Resolve a redir using si if possible, and add it to the resolved
    list */
 Bool VG_(resolve_redir)(CodeRedirect *redir, const SegInfo *si)
@@ -186,74 +256,7 @@
 		  redir->from_lib, redir->from_sym, redir->from_addr, 
 		  redir->to_lib, redir->to_sym, redir->to_addr);
 
-   if (resolved) {
-      switch(redir->type) {
-      case R_REDIRECT:
-	 if (VG_(clo_trace_redir)) {
-	    VG_(message)(Vg_DebugMsg, "  redir resolved (%s:%s=%p -> ",
-			 redir->from_lib, redir->from_sym, redir->from_addr);
-	    VG_(message)(Vg_DebugMsg, "                  %s:%s=%p)",
-			 redir->to_lib, redir->to_sym, redir->to_addr);
-	 }
-
-	 if (VG_(search_transtab)(NULL, (Addr64)redir->from_addr, False)) {
-	    /* For some given (from, to) redir, the "from" function got
-	       called before the .so containing "to" became available.  We
-	       know this because there is already a translation for the
-	       entry point of the original "from".  So the redirect will
-	       never actually take effect unless that translation is
-	       discarded.  
-
-	       Note, we only really need to discard the first bb of the
-	       old entry point, and so we avoid the problem of having to
-	       figure out how big that bb was -- since it is at least 1
-	       byte of original code, we can just pass 1 as the original
-	       size to invalidate_translations() and it will indeed get
-	       rid of the translation. 
-
-	       Note, this is potentially expensive -- discarding
-	       translations causes complete unchaining.  
-	    */
-	    if (VG_(clo_verbosity) > 2 && VG_(clo_trace_redir)) {
-	       VG_(message)(Vg_UserMsg,   
-			    "Discarding translation due to redirect of already called function" );
-	       VG_(message)(Vg_UserMsg,
-			    "   %s (%p -> %p)",
-			    redir->from_sym, redir->from_addr, redir->to_addr );
-	    }
-	    VG_(discard_translations)((Addr64)redir->from_addr, 1);
-	 }
-
-	 {
-	    CodeRedirect *r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &redir->from_addr);
-
-	    if (r == NULL)
-	       VG_(SkipList_Insert)(&sk_resolved_redir, redir);
-	    else {
-	       /* XXX leak redir */
-	       if (VG_(clo_trace_redir))
-		  VG_(message)(Vg_DebugMsg, "  redir %s:%s:%p->%s:%s:%p duplicated\n",
-			       redir->from_lib, redir->from_sym, redir->from_addr,
-			       redir->to_lib, redir->to_sym, redir->to_addr);
-	    }
-	 }
-	 break;
-
-      case R_WRAPPER:
-	 if (VG_(clo_trace_redir)) {
-	    VG_(message)(Vg_DebugMsg, "  wrapper resolved (%s:%s=%p -> wrapper)",
-			 redir->from_lib, redir->from_sym, redir->from_addr);
-	 }
-
-	 /* XXX redir leaked */
-	 //VG_(wrap_function)(redir->from_addr, redir->wrapper);
-	 break;
-
-      case R_CLIENT_WRAPPER:
-	 VG_(core_panic)("not implemented");
-	 break;
-      }
-   }
+   if (resolved) add_resolved(redir);
 
    return resolved;
 }
@@ -285,8 +288,8 @@
 }
 
 /* Redirect a lib/symbol reference to a function at lib/symbol */
-static void add_redirect_sym(const Char *from_lib, const Char *from_sym,
-			     const Char *to_lib, const Char *to_sym)
+static void add_redirect_sym_to_sym(const Char *from_lib, const Char *from_sym,
+				    const Char *to_lib, const Char *to_sym)
 {
    CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
 
@@ -315,8 +318,8 @@
 }
 
 /* Redirect a lib/symbol reference to a function at addr */
-void VG_(add_redirect_addr)(const Char *from_lib, const Char *from_sym,
-			    Addr to_addr)
+void VG_(add_redirect_sym_to_addr)(const Char *from_lib, const Char *from_sym,
+				   Addr to_addr)
 {
    CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
 
@@ -330,6 +333,11 @@
    redir->to_sym = NULL;
    redir->to_addr = to_addr;
 
+   if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
+      VG_(message)(Vg_UserMsg, 
+                   "REDIRECT %s(%s) to %p",
+                   from_lib, from_sym, to_addr);
+
     /* Check against all existing segments to see if this redirection
        can be resolved immediately */
    if (!VG_(resolve_redir_allsegs)(redir)) {
@@ -339,6 +347,29 @@
    }
 }
 
+/* Redirect a function at from_addr to a function at to_addr */
+void VG_(add_redirect_addr_to_addr)(Addr from_addr, Addr to_addr)
+{
+   CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
+
+   redir->type = R_REDIRECT;
+
+   redir->from_lib = NULL;
+   redir->from_sym = NULL;
+   redir->from_addr = from_addr;
+
+   redir->to_lib = NULL;
+   redir->to_sym = NULL;
+   redir->to_addr = to_addr;
+
+   if (VG_(clo_verbosity) >= 2 && VG_(clo_trace_redir))
+      VG_(message)(Vg_UserMsg, 
+                   "REDIRECT %p to %p",
+                   from_addr, to_addr);
+
+   add_resolved(redir);
+}
+
 CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
 			       const FuncWrapper *wrapper)
 {
@@ -371,45 +402,12 @@
    return redir;
 }
 
-/* HACK! This should be done properly (see ~/NOTES.txt) */
-#ifdef __amd64__
-/* Rerouted entry points for __NR_vgettimeofday and __NR_vtime.
-     96 == __NR_gettimeofday
-    201 == __NR_time
-*/
-static void amd64_linux_rerouted__vgettimeofday(void)
-{
-asm(
-"       movq    $96, %rax\n"
-"       syscall\n"
-);
-}
-
-static void amd64_linux_rerouted__vtime(void)
-{
-asm(
-"       movq    $201, %rax\n"
-"       syscall\n"
-);
-}
-#endif
-
 /* If address 'a' is being redirected, return the redirected-to
    address. */
 Addr VG_(code_redirect)(Addr a)
 {
    CodeRedirect* r;
 
-#ifdef __amd64__
-   /* HACK.  Reroute the amd64-linux vsyscalls.  This should be moved
-      out of here into an amd64-linux specific initialisation routine.
-   */
-   if (a == 0xFFFFFFFFFF600000ULL)
-      return (Addr)amd64_linux_rerouted__vgettimeofday;
-   if (a == 0xFFFFFFFFFF600400ULL)
-      return (Addr)amd64_linux_rerouted__vtime;
-#endif
-
    r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &a);
    if (r == NULL)
       return a;
@@ -421,41 +419,34 @@
 
 void VG_(setup_code_redirect_table) ( void )
 {
-   /* Redirect _dl_sysinfo_int80, which is glibc's default system call
-      routine, to the routine in our trampoline page so that the
-      special sysinfo unwind hack in vg_execontext.c will kick in.
-   */
-   VG_(add_redirect_addr)("soname:ld-linux.so.2", "_dl_sysinfo_int80",
-			  VG_(client_trampoline_code)+VG_(tramp_syscall_offset));
-   
    /* Overenthusiastic use of PLT bypassing by the glibc people also
       means we need to patch the following functions to our own
       implementations of said, in mac_replace_strmem.c.
     */
-   add_redirect_sym("soname:libc.so.6", "stpcpy",
-                    "*vgpreload_memcheck.so*", "stpcpy");
+   add_redirect_sym_to_sym("soname:libc.so.6", "stpcpy",
+                           "*vgpreload_memcheck.so*", "stpcpy");
 
-   add_redirect_sym("soname:libc.so.6", "strlen",
-                    "*vgpreload_memcheck.so*", "strlen");
+   add_redirect_sym_to_sym("soname:libc.so.6", "strlen",
+                           "*vgpreload_memcheck.so*", "strlen");
 
-   add_redirect_sym("soname:libc.so.6", "strnlen",
-                    "*vgpreload_memcheck.so*", "strnlen");
+   add_redirect_sym_to_sym("soname:libc.so.6", "strnlen",
+                           "*vgpreload_memcheck.so*", "strnlen");
 
-   add_redirect_sym("soname:ld-linux.so.2", "stpcpy",
-                    "*vgpreload_memcheck.so*", "stpcpy");
-   add_redirect_sym("soname:libc.so.6", "stpcpy",
-                    "*vgpreload_memcheck.so*", "stpcpy");
+   add_redirect_sym_to_sym("soname:ld-linux.so.2", "stpcpy",
+                           "*vgpreload_memcheck.so*", "stpcpy");
+   add_redirect_sym_to_sym("soname:libc.so.6", "stpcpy",
+                           "*vgpreload_memcheck.so*", "stpcpy");
 
-   add_redirect_sym("soname:libc.so.6", "strchr",
-                    "*vgpreload_memcheck.so*", "strchr");
-   add_redirect_sym("soname:ld-linux.so.2", "strchr",
-                    "*vgpreload_memcheck.so*", "strchr");
+   add_redirect_sym_to_sym("soname:libc.so.6", "strchr",
+                           "*vgpreload_memcheck.so*", "strchr");
+   add_redirect_sym_to_sym("soname:ld-linux.so.2", "strchr",
+                           "*vgpreload_memcheck.so*", "strchr");
 
-   add_redirect_sym("soname:libc.so.6", "strchrnul",
-                    "*vgpreload_memcheck.so*", "glibc232_strchrnul");
+   add_redirect_sym_to_sym("soname:libc.so.6", "strchrnul",
+                           "*vgpreload_memcheck.so*", "glibc232_strchrnul");
 
-   add_redirect_sym("soname:libc.so.6", "rawmemchr",
-                    "*vgpreload_memcheck.so*", "glibc232_rawmemchr");
+   add_redirect_sym_to_sym("soname:libc.so.6", "rawmemchr",
+                           "*vgpreload_memcheck.so*", "glibc232_rawmemchr");
 }