Пример #1
0
/* 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;
}
Пример #2
0
void VG_(redir_notify_delete_SegInfo)( SegInfo* delsi )
{
   TopSpec* ts;
   TopSpec* tsPrev;
   Spec*    sp;
   Spec*    sp_next;
   OSet*    tmpSet;
   Active*  act;
   Bool     delMe;
   Addr*    addrP;

   vg_assert(delsi);

   /* Search for it, and make tsPrev point to the previous entry, if
      any. */
   tsPrev = NULL;
   ts     = topSpecs;
   while (True) {
     if (ts == NULL) break;
     if (ts->seginfo == delsi) break;
     tsPrev = ts;
     ts = ts->next;
   }

   vg_assert(ts); /* else we don't have the deleted SegInfo */
   vg_assert(ts->seginfo == delsi);

   /* Traverse the actives, copying the addresses of those we intend
      to delete into tmpSet. */
   tmpSet = VG_(OSet_Create)( 0/*keyOff*/, NULL/*fastCmp*/,
                              symtab_alloc, symtab_free);

   ts->mark = True;

   VG_(OSet_ResetIter)( activeSet );
   while ( (act = VG_(OSet_Next)(activeSet)) ) {
      delMe = act->parent_spec != NULL
              && act->parent_sym != NULL
              && act->parent_spec->seginfo != NULL
              && act->parent_sym->seginfo != NULL
              && (act->parent_spec->mark || act->parent_sym->mark);

      /* While we're at it, a bit of paranoia: delete any actives
         which don't have both feet in valid client executable areas.
         But don't delete hardwired-at-startup ones; these are denoted
         by having parent_spec or parent_sym being NULL.  */
      if ( (!delMe)
           && act->parent_spec != NULL
           && act->parent_sym  != NULL ) {
         if (!is_plausible_guest_addr(act->from_addr))
            delMe = True;
         if (!is_plausible_guest_addr(act->to_addr))
            delMe = True;
      }

      if (delMe) {
         addrP = VG_(OSet_AllocNode)( tmpSet, sizeof(Addr) );
         *addrP = act->from_addr;
         VG_(OSet_Insert)( tmpSet, addrP );
         /* While we have our hands on both the 'from' and 'to'
            of this Active, do paranoid stuff with tt/tc. */
         VG_(discard_translations)( (Addr64)act->from_addr, 1,
                                    "redir_del_SegInfo(from_addr)");
         VG_(discard_translations)( (Addr64)act->to_addr, 1,
                                    "redir_del_SegInfo(to_addr)");
      }
   }

   /* Now traverse tmpSet, deleting corresponding elements in
      activeSet. */
   VG_(OSet_ResetIter)( tmpSet );
   while ( (addrP = VG_(OSet_Next)(tmpSet)) ) {
      act = VG_(OSet_Remove)( activeSet, addrP );
      vg_assert(act);
      VG_(OSet_FreeNode)( activeSet, act );
   }

   VG_(OSet_Destroy)( tmpSet, NULL );

   /* The Actives set is now cleaned up.  Free up this TopSpec and
      everything hanging off it. */
   for (sp = ts->specs; sp; sp = sp_next) {
      if (sp->from_sopatt) symtab_free(sp->from_sopatt);
      if (sp->from_fnpatt) symtab_free(sp->from_fnpatt);
      sp_next = sp->next;
      symtab_free(sp);
   }

   if (tsPrev == NULL) {
      /* first in list */
      topSpecs = ts->next;
   } else {
      tsPrev->next = ts->next;
   }
   symtab_free(ts);

   if (VG_(clo_trace_redir))
      show_redir_state("after VG_(redir_notify_delete_SegInfo)");
}
Пример #3
0
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, 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);

   /* stay sane: we don't already have this. */
   for (ts = topSpecs; ts; ts = ts->next)
      vg_assert(ts->seginfo != newsi);

   /* scan this SegInfo's symbol table, pulling out and demangling
      any specs found */

   specList = NULL; /* the spec list we're building up */

   nsyms = VG_(seginfo_syms_howmany)( newsi );
   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) {
         /* 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);
      spec->from_fnpatt = symtab_strdup(demangled_fnpatt);
      vg_assert(spec->from_sopatt);
      vg_assert(spec->from_fnpatt);
      spec->to_addr = sym_addr;
      spec->isWrap = isWrap;
      /* check we're not adding manifestly stupid destinations */
      vg_assert(is_plausible_guest_addr(sym_addr));
      spec->next = specList;
      spec->mark = False; /* not significant */
      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));
   vg_assert(newts);
   newts->next    = NULL; /* not significant */
   newts->seginfo = newsi;
   newts->specs   = specList;
   newts->mark    = False; /* not significant */

   /* We now need to augment the active set with the following partial
      cross product:

      (1) actives formed by matching the new specs in specList against
          all symbols currently listed in topSpecs

      (2) actives formed by matching the new symbols in newsi against
          all specs currently listed in topSpecs

      (3) actives formed by matching the new symbols in newsi against
          the new specs in specList

      This is necessary in order to maintain the invariant that
      Actives contains all bindings generated by matching ALL specs in
      topSpecs against ALL symbols in topSpecs (that is, a cross
      product of ALL known specs against ALL known symbols).
   */
   /* Case (1) */
   for (ts = topSpecs; ts; ts = ts->next) {
      if (ts->seginfo)
         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, 
                                newsi,     newts );
   }

   /* Case (3) */
   generate_and_add_actives( specList, newts, 
                             newsi,    newts );

   /* Finally, add the new TopSpec. */
   newts->next = topSpecs;
   topSpecs = newts;

   if (VG_(clo_trace_redir))
      show_redir_state("after VG_(redir_notify_new_SegInfo)");
}
Пример #4
0
/* Add an act (passed by value; is copied here) and deal with
   conflicting bindings. */
static void maybe_add_active ( Active act )
{
   HChar*  what = NULL;
   Active* old;

   /* Complain and ignore manifestly bogus 'from' addresses.

      Kludge: because this can get called befor the trampoline area (a
      bunch of magic 'to' addresses) has its ownership changed from V
      to C, we can't check the 'to' address similarly.  Sigh.

      amd64-linux hack: the vsysinfo pages appear to have no
      permissions
         ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0
      so skip the check for them.  */
   if (!is_plausible_guest_addr(act.from_addr)
#      if defined(VGP_amd64_linux)
       && act.from_addr != 0xFFFFFFFFFF600000ULL
       && act.from_addr != 0xFFFFFFFFFF600400ULL
#      endif
      ) {
      what = "redirection from-address is in non-executable area";
      goto bad;
   }

   old = VG_(OSet_Lookup)( activeSet, &act.from_addr );
   if (old) {
      /* Dodgy.  Conflicting binding. */
      vg_assert(old->from_addr == act.from_addr);
      if (old->to_addr != act.to_addr) {
         /* we have to ignore it -- otherwise activeSet would contain
            conflicting bindings. */
         what = "new redirection conflicts with existing -- ignoring it";
         goto bad;
      } else {
         /* This appears to be a duplicate of an existing binding.
            Safe(ish) -- ignore. */
         /* XXXXXXXXXXX COMPLAIN if new and old parents differ */
      }
   } else {
      Active* a = VG_(OSet_AllocNode)(activeSet, sizeof(Active));
      vg_assert(a);
      *a = act;
      VG_(OSet_Insert)(activeSet, a);
      /* Now that a new from->to redirection is in force, we need to
         get rid of any translations intersecting 'from' in order that
         they get redirected to 'to'.  So discard them.  Just for
         paranoia (but, I believe, unnecessarily), discard 'to' as
         well. */
      VG_(discard_translations)( (Addr64)act.from_addr, 1,
                                 "redir_new_SegInfo(from_addr)");
      VG_(discard_translations)( (Addr64)act.to_addr, 1,
                                 "redir_new_SegInfo(to_addr)");
   }
   return;

  bad:
   vg_assert(what);
   if (VG_(clo_verbosity) > 1) {
      VG_(message)(Vg_UserMsg, "WARNING: %s", what);
      show_active(             "    new: ", &act);
   }
}
Пример #5
0
void VG_(redir_notify_new_DebugInfo)( DebugInfo* newdi )
{
   Bool         ok, isWrap;
   Int          i, nsyms, becTag, becPrio;
   Spec*        specList;
   Spec*        spec;
   TopSpec*     ts;
   TopSpec*     newts;
   UChar*       sym_name_pri;
   UChar**      sym_names_sec;
   Addr         sym_addr, sym_toc;
   HChar        demangled_sopatt[N_DEMANGLED];
   HChar        demangled_fnpatt[N_DEMANGLED];
   Bool         check_ppcTOCs = False;
   Bool         isText;
   const UChar* newdi_soname;

#  if defined(VG_PLAT_USES_PPCTOC)
   check_ppcTOCs = True;
#  endif

   vg_assert(newdi);
   newdi_soname = VG_(DebugInfo_get_soname)(newdi);
   vg_assert(newdi_soname != NULL);

#ifdef ENABLE_INNER
   {
      const UChar* newdi_filename = VG_(DebugInfo_get_filename)(newdi);
      const UChar* newdi_basename = VG_(basename) (newdi_filename);
      if (VG_(strncmp) (newdi_basename, "vgpreload_", 10) == 0) {
         struct vg_stat newdi_stat;
         SysRes newdi_res;
         Char in_vglib_filename[VKI_PATH_MAX];
         struct vg_stat in_vglib_stat;
         SysRes in_vglib_res;

         newdi_res = VG_(stat)(newdi_filename, &newdi_stat);
         
         VG_(strncpy) (in_vglib_filename, VG_(libdir), VKI_PATH_MAX);
         VG_(strncat) (in_vglib_filename, "/", VKI_PATH_MAX);
         VG_(strncat) (in_vglib_filename, newdi_basename, VKI_PATH_MAX);
         in_vglib_res = VG_(stat)(in_vglib_filename, &in_vglib_stat);

         if (!sr_isError(in_vglib_res)
             && !sr_isError(newdi_res)
             && (newdi_stat.dev != in_vglib_stat.dev 
                 || newdi_stat.ino != in_vglib_stat.ino)) {
            if ( VG_(clo_verbosity) > 1 ) {
               VG_(message)( Vg_DebugMsg,
                             "Skipping vgpreload redir in %s"
                             " (not from VALGRIND_LIB_INNER)\n",
                             newdi_filename);
            }
            return;
         } else {
            if ( VG_(clo_verbosity) > 1 ) {
               VG_(message)( Vg_DebugMsg,
                             "Executing vgpreload redir in %s"
                             " (from VALGRIND_LIB_INNER)\n",
                             newdi_filename);
            }
         }
      }
   }
#endif


   
   for (ts = topSpecs; ts; ts = ts->next)
      vg_assert(ts->seginfo != newdi);


   specList = NULL; 

   nsyms = VG_(DebugInfo_syms_howmany)( newdi );
   for (i = 0; i < nsyms; i++) {
      VG_(DebugInfo_syms_getidx)( newdi, i, &sym_addr, &sym_toc,
                                  NULL, &sym_name_pri, &sym_names_sec,
                                  &isText, NULL );
      
      UChar*  twoslots[2];
      UChar** names_init = alloc_symname_array(sym_name_pri, sym_names_sec,
                                               &twoslots[0]);
      UChar** names;
      for (names = names_init; *names; names++) {
         ok = VG_(maybe_Z_demangle)( *names,
                                     demangled_sopatt, N_DEMANGLED,
                                     demangled_fnpatt, N_DEMANGLED,
                                     &isWrap, &becTag, &becPrio );
         
         if (!isText)
            continue;
         if (!ok) {
            handle_maybe_load_notifier( newdi_soname, *names, sym_addr );
            continue; 
         }
         if (check_ppcTOCs && sym_toc == 0) {
            continue;
         }

         if (0 == VG_(strncmp) (demangled_sopatt, 
                                VG_SO_SYN_PREFIX, VG_SO_SYN_PREFIX_LEN)) {

            if (!VG_(clo_soname_synonyms))
               continue; 

            
            SizeT const sopatt_syn_len 
               = VG_(strlen)(demangled_sopatt+VG_SO_SYN_PREFIX_LEN);
            HChar const* last = VG_(clo_soname_synonyms);
            
            while (*last) {
               HChar const* first = last;
               last = advance_to_equal(first);
               
               if ((last - first) == sopatt_syn_len
                   && 0 == VG_(strncmp)(demangled_sopatt+VG_SO_SYN_PREFIX_LEN,
                                        first,
                                        sopatt_syn_len)) {
                  
                  first = last + 1;
                  last = advance_to_comma(first);
                  VG_(strncpy)(demangled_sopatt, first, last - first);
                  demangled_sopatt[last - first] = '\0';
                  break;
               }

               last = advance_to_comma(last);
               if (*last == ',')
                  last++;
            }
            
            
            if (0 == VG_(strncmp) (demangled_sopatt, 
                                   VG_SO_SYN_PREFIX, VG_SO_SYN_PREFIX_LEN))
               continue;
         }

         spec = dinfo_zalloc("redir.rnnD.1", sizeof(Spec));
         vg_assert(spec);
         spec->from_sopatt = dinfo_strdup("redir.rnnD.2", demangled_sopatt);
         spec->from_fnpatt = dinfo_strdup("redir.rnnD.3", demangled_fnpatt);
         vg_assert(spec->from_sopatt);
         vg_assert(spec->from_fnpatt);
         spec->to_addr = sym_addr;
         spec->isWrap = isWrap;
         spec->becTag = becTag;
         spec->becPrio = becPrio;
         
         vg_assert(is_plausible_guest_addr(sym_addr));
         spec->next = specList;
         spec->mark = False; 
         spec->done = False; 
         specList = spec;
      }
      free_symname_array(names_init, &twoslots[0]);
   }

   if (check_ppcTOCs) {
      for (i = 0; i < nsyms; i++) {
         VG_(DebugInfo_syms_getidx)( newdi, i, &sym_addr, &sym_toc,
                                     NULL, &sym_name_pri, &sym_names_sec,
                                     &isText, NULL );
         UChar*  twoslots[2];
         UChar** names_init = alloc_symname_array(sym_name_pri, sym_names_sec,
                                                  &twoslots[0]);
         UChar** names;
         for (names = names_init; *names; names++) {
            ok = isText
                 && VG_(maybe_Z_demangle)( 
                       *names, demangled_sopatt, N_DEMANGLED,
                       demangled_fnpatt, N_DEMANGLED, &isWrap, NULL, NULL );
            if (!ok)
               
               continue;
            if (sym_toc != 0)
               
               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)
               continue;

            
            VG_(message)(Vg_DebugMsg,
                         "WARNING: no TOC ptr for redir/wrap to %s %s\n",
                         demangled_sopatt, demangled_fnpatt);
         }
         free_symname_array(names_init, &twoslots[0]);
      }
   }

   newts = dinfo_zalloc("redir.rnnD.4", sizeof(TopSpec));
   vg_assert(newts);
   newts->next    = NULL; 
   newts->seginfo = newdi;
   newts->specs   = specList;
   newts->mark    = False; 

   
   for (ts = topSpecs; ts; ts = ts->next) {
      if (ts->seginfo)
         generate_and_add_actives( specList,    newts,
                                   ts->seginfo, ts );
   }

   
   for (ts = topSpecs; ts; ts = ts->next) {
      generate_and_add_actives( ts->specs, ts, 
                                newdi,     newts );
   }

   
   generate_and_add_actives( specList, newts, 
                             newdi,    newts );

   
   newts->next = topSpecs;
   topSpecs = newts;

   if (VG_(clo_trace_redir))
      show_redir_state("after VG_(redir_notify_new_DebugInfo)");

   handle_require_text_symbols(newdi);
}