]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Merge r6132:
authorJulian Seward <jseward@acm.org>
Tue, 17 Oct 2006 01:39:30 +0000 (01:39 +0000)
committerJulian Seward <jseward@acm.org>
Tue, 17 Oct 2006 01:39:30 +0000 (01:39 +0000)
Minor changes for redirection on AIX.  The only significant change is
that it now checks for, warns about and disallows, attempts to
redirect to, or wrap with, a function for which no TOC pointer can be
found, since that would be really asking for trouble (a segfault).

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@6269

coregrind/m_redir.c
include/pub_tool_redir.h

index a0bacf002c1077bd106f46811c13d8490384a178..693401c7cfe671dff11f8e10879b8cd71be67c2f 100644 (file)
@@ -43,7 +43,7 @@
 #include "pub_core_trampoline.h"
 #include "pub_core_transtab.h"
 #include "pub_core_tooliface.h"    // VG_(needs).malloc_replacement
-#include "pub_tool_machine.h"      // VG_(fnptr_to_fnentry)
+#include "pub_core_machine.h"      // VG_(fnptr_to_fnentry)
 #include "pub_core_aspacemgr.h"    // VG_(am_find_nsegment)
 #include "pub_core_clientstate.h"  // VG_(client___libc_freeres_wrapper)
 #include "pub_core_demangle.h"     // VG_(maybe_Z_demangle)
@@ -269,6 +269,7 @@ static void*  symtab_alloc(SizeT);
 static void   symtab_free(void*);
 static HChar* symtab_strdup(HChar*);
 static Bool   is_plausible_guest_addr(Addr);
+static Bool   is_aix5_glink_idiom(Addr);
 
 static void   show_redir_state ( HChar* who );
 static void   show_active ( HChar* left, Active* act );
@@ -300,19 +301,23 @@ void generate_and_add_actives (
 
 void VG_(redir_notify_new_SegInfo)( SegInfo* newsi )
 {
-   Bool     ok, isWrap;
-   Int      i, nsyms;
-   Spec*    specList;
-   Spec*    spec;
-   TopSpec* ts;
-   TopSpec* newts;
-   HChar*   sym_name;
-   Addr     sym_addr;
-   HChar    demangled_sopatt[N_DEMANGLED];
-   HChar    demangled_fnpatt[N_DEMANGLED];
-
+   Bool         ok, isWrap;
+   Int          i, nsyms;
+   Spec*        specList;
+   Spec*        spec;
+   TopSpec*     ts;
+   TopSpec*     newts;
+   HChar*       sym_name;
+   Addr         sym_addr, sym_toc;
+   HChar        demangled_sopatt[N_DEMANGLED];
+   HChar        demangled_fnpatt[N_DEMANGLED];
+   Bool         check_ppcTOCs = False;
    const UChar* newsi_soname;
 
+#  if defined(VG_PLAT_USES_PPCTOC)
+   check_ppcTOCs = True;
+#  endif
+
    vg_assert(newsi);
    newsi_soname = VG_(seginfo_soname)(newsi);
    vg_assert(newsi_soname != NULL);
@@ -328,15 +333,23 @@ void VG_(redir_notify_new_SegInfo)( SegInfo* newsi )
 
    nsyms = VG_(seginfo_syms_howmany)( newsi );
    for (i = 0; i < nsyms; i++) {
-      VG_(seginfo_syms_getidx)( newsi, i, &sym_addr, NULL, &sym_name );
+      VG_(seginfo_syms_getidx)( newsi, i, &sym_addr, &sym_toc, 
+                                          NULL, &sym_name );
       ok = VG_(maybe_Z_demangle)( sym_name, demangled_sopatt, N_DEMANGLED,
-                                 demangled_fnpatt, N_DEMANGLED, &isWrap );
+                                  demangled_fnpatt, N_DEMANGLED, &isWrap );
       if (!ok) {
          /* It's not a full-scale redirect, but perhaps it is a load-notify
             fn?  Let the load-notify department see it. */
          handle_maybe_load_notifier( newsi_soname, sym_name, sym_addr );
          continue; 
       }
+      if (check_ppcTOCs && sym_toc == 0) {
+         /* This platform uses toc pointers, but none could be found
+            for this symbol, so we can't safely redirect/wrap to it.
+            Just skip it; we'll make a second pass over the symbols in
+            the following loop, and complain at that point. */
+         continue;
+      }
       spec = symtab_alloc(sizeof(Spec));
       vg_assert(spec);
       spec->from_sopatt = symtab_strdup(demangled_sopatt);
@@ -352,6 +365,35 @@ void VG_(redir_notify_new_SegInfo)( SegInfo* newsi )
       specList = spec;
    }
 
+   if (check_ppcTOCs) {
+      for (i = 0; i < nsyms; i++) {
+         VG_(seginfo_syms_getidx)( newsi, i, &sym_addr, &sym_toc, 
+                                             NULL, &sym_name );
+         ok = VG_(maybe_Z_demangle)( sym_name, demangled_sopatt, N_DEMANGLED,
+                                     demangled_fnpatt, N_DEMANGLED, &isWrap );
+         if (!ok)
+            /* not a redirect.  Ignore. */
+            continue;
+         if (sym_toc != 0)
+            /* has a valid toc pointer.  Ignore. */
+            continue;
+
+         for (spec = specList; spec; spec = spec->next) 
+            if (0 == VG_(strcmp)(spec->from_sopatt, demangled_sopatt)
+                && 0 == VG_(strcmp)(spec->from_fnpatt, demangled_fnpatt))
+               break;
+         if (spec)
+          /* a redirect to some other copy of that symbol, which does have
+              a TOC value, already exists */
+          continue;
+
+         /* Complain */
+         VG_(message)(Vg_DebugMsg,
+                      "WARNING: no TOC ptr for redir/wrap to %s %s",
+                      demangled_sopatt, demangled_fnpatt);
+      }
+   }
+
    /* Ok.  Now specList holds the list of specs from the SegInfo. 
       Build a new TopSpec, but don't add it to topSpecs yet. */
    newts = symtab_alloc(sizeof(TopSpec));
@@ -384,7 +426,7 @@ void VG_(redir_notify_new_SegInfo)( SegInfo* newsi )
          generate_and_add_actives( specList,    newts,
                                    ts->seginfo, ts );
    }
-       
+
    /* Case (2) */
    for (ts = topSpecs; ts; ts = ts->next) {
       generate_and_add_actives( ts->specs, ts, 
@@ -445,7 +487,18 @@ void generate_and_add_actives (
       of trashing the caches less. */
    nsyms = VG_(seginfo_syms_howmany)( si );
    for (i = 0; i < nsyms; i++) {
-      VG_(seginfo_syms_getidx)( si, i, &sym_addr, NULL, &sym_name );
+      VG_(seginfo_syms_getidx)( si, i, &sym_addr, NULL, NULL, &sym_name );
+
+      /* On AIX, we cannot redirect calls to a so-called glink
+         function for reasons which are not obvious - something to do
+         with saving r2 across the call.  Not a problem, as we don't
+         want to anyway; presumably it is the target of the glink we
+         need to redirect.  Hence just spot them and ignore them.
+         They are always of a very specific (more or less
+         ABI-mandated) form. */
+      if (is_aix5_glink_idiom(sym_addr))
+         continue;
+
       for (sp = specs; sp; sp = sp->next) {
          if (!sp->mark)
             continue; /* soname doesn't match */
@@ -785,6 +838,12 @@ void VG_(redir_initialise) ( void )
 
    }
 
+#  elif defined(VGP_ppc32_aix5)
+   /* nothing so far */
+
+#  elif defined(VGP_ppc64_aix5)
+   /* nothing so far */
+
 #  else
 #    error Unknown platform
 #  endif
@@ -817,12 +876,48 @@ static HChar* symtab_strdup(HChar* str)
    in m_translate. */
 static Bool is_plausible_guest_addr(Addr a)
 {
-   NSegment* seg = VG_(am_find_nsegment)(a);
+   NSegment const* seg = VG_(am_find_nsegment)(a);
    return seg != NULL
           && (seg->kind == SkAnonC || seg->kind == SkFileC)
           && (seg->hasX || seg->hasR); /* crude x86-specific hack */
 }
 
+/* A function which spots AIX 'glink' functions.  A 'glink' function
+   is a stub function which has something to do with AIX-style dynamic
+   linking, and jumps to the real target (with which it typically
+   shares the same name).  See also comment where this function is
+   used (above). */
+static Bool is_aix5_glink_idiom ( Addr sym_addr )
+{
+#  if defined(VGP_ppc32_aix5)
+   UInt* w = (UInt*)sym_addr;
+   if (VG_IS_4_ALIGNED(w)
+       && is_plausible_guest_addr((Addr)(w+0))
+       && is_plausible_guest_addr((Addr)(w+6))
+       && (w[0] & 0xFFFF0000) == 0x81820000 /* lwz r12,func@toc(r2) */
+       && w[1] == 0x90410014                /* stw r2,20(r1) */
+       && w[2] == 0x800c0000                /* lwz r0,0(r12) */
+       && w[3] == 0x804c0004                /* lwz r2,4(r12) */
+       && w[4] == 0x7c0903a6                /* mtctr r0 */
+       && w[5] == 0x4e800420                /* bctr */
+       && w[6] == 0x00000000                /* illegal */)
+      return True;
+#  elif defined(VGP_ppc64_aix5)
+   UInt* w = (UInt*)sym_addr;
+   if (VG_IS_4_ALIGNED(w)
+       && is_plausible_guest_addr((Addr)(w+0))
+       && is_plausible_guest_addr((Addr)(w+6))
+       && (w[0] & 0xFFFF0000) == 0xE9820000 /* ld  r12,func@toc(r2) */
+       && w[1] == 0xF8410028                /* std r2,40(r1) */
+       && w[2] == 0xE80C0000                /* ld  r0,0(r12) */
+       && w[3] == 0xE84C0008                /* ld  r2,8(r12) */
+       && w[4] == 0x7c0903a6                /* mtctr r0 */
+       && w[5] == 0x4e800420                /* bctr */
+       && w[6] == 0x00000000                /* illegal */)
+      return True;
+#  endif
+   return False;
+}
 
 /*------------------------------------------------------------*/
 /*--- NOTIFY-ON-LOAD FUNCTIONS                             ---*/
@@ -866,7 +961,7 @@ void handle_maybe_load_notifier( const UChar* soname,
 static void show_spec ( HChar* left, Spec* spec )
 {
    VG_(message)(Vg_DebugMsg, 
-                  "%s%18s %30s %s-> 0x%08llx",
+                  "%s%25s %30s %s-> 0x%08llx",
                   left,
                   spec->from_sopatt, spec->from_fnpatt,
                   spec->isWrap ? "W" : "R",
@@ -884,7 +979,7 @@ static void show_active ( HChar* left, Active* act )
    ok = VG_(get_fnname_w_offset)(act->to_addr, name2, 64);
    if (!ok) VG_(strcpy)(name2, "???");
 
-   VG_(message)(Vg_DebugMsg, "%s0x%08llx (%10s) %s-> 0x%08llx %s", 
+   VG_(message)(Vg_DebugMsg, "%s0x%08llx (%20s) %s-> 0x%08llx %s", 
                              left, 
                              (ULong)act->from_addr, name1,
                              act->isWrap ? "W" : "R",
index f3fc471318dfbf30beaabecdecdf139654844eeb..21f3c30ab85e942346a220365df0a47df98e0040 100644 (file)
      _         -->  Zu    (underscore)
      -         -->  Zh    (hyphen)
      (space)   -->  Zs    (space)
-     @         -  ZA    (at)
+     @         -->  ZA    (at)
      Z         -->  ZZ    (Z)
+     (         -->  ZL    (left)
+     )         -->  ZR    (right)
 
    Everything else is left unchanged.
 */
    changed accordingly.  NOTE: duplicates
    I_{WRAP,REPLACE}_SONAME_FNNAME_Z{U,Z} in valgrind.h. */
 
-#define VG_REPLACE_FUNCTION_ZU(soname,fnname) _vgrZU_##soname##_##fnname
-#define VG_REPLACE_FUNCTION_ZZ(soname,fnname) _vgrZZ_##soname##_##fnname
+/* Use an extra level of macroisation so as to ensure the soname/fnname
+   args are fully macro-expanded before pasting them together. */
+#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd
+
+#define VG_REPLACE_FUNCTION_ZU(soname,fnname) VG_CONCAT4(_vgrZU_,soname,_,fnname)
+#define VG_REPLACE_FUNCTION_ZZ(soname,fnname) VG_CONCAT4(_vgrZZ_,soname,_,fnname)
+
+#define VG_WRAP_FUNCTION_ZU(soname,fnname) VG_CONCAT4(_vgwZU_,soname,_,fnname)
+#define VG_WRAP_FUNCTION_ZZ(soname,fnname) VG_CONCAT4(_vgwZZ_,soname,_,fnname)
 
-#define VG_WRAP_FUNCTION_ZU(soname,fnname) _vgwZU_##soname##_##fnname
-#define VG_WRAP_FUNCTION_ZZ(soname,fnname) _vgwZZ_##soname##_##fnname
 
 #endif   // __PUB_TOOL_REDIR_H