void VG_(redir_initialise) ( void ) { // Assert that there are no SegInfos so far vg_assert( VG_(next_seginfo)(NULL) == NULL ); // Initialise active mapping. activeSet = VG_(OSet_Create)(offsetof(Active, from_addr), NULL, // Use fast comparison symtab_alloc, symtab_free); // The rest of this function just adds initial Specs. # if defined(VGP_x86_linux) /* If we're using memcheck, use this intercept right from the start, otherwise ld.so (glibc-2.3.5) makes a lot of noise. */ if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { add_hardwired_spec( "ld-linux.so.2", "index", (Addr)&VG_(x86_linux_REDIR_FOR_index) ); } # elif defined(VGP_amd64_linux) /* Redirect vsyscalls to local versions */ add_hardwired_active( 0xFFFFFFFFFF600000ULL, (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday) ); add_hardwired_active( 0xFFFFFFFFFF600400ULL, (Addr)&VG_(amd64_linux_REDIR_FOR_vtime) ); # elif defined(VGP_ppc32_linux) /* If we're using memcheck, use these intercepts right from the start, otherwise ld.so makes a lot of noise. */ if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { add_hardwired_spec( "ld.so.1", "strlen", (Addr)&VG_(ppc32_linux_REDIR_FOR_strlen) ); add_hardwired_spec( "ld.so.1", "strcmp", (Addr)&VG_(ppc32_linux_REDIR_FOR_strcmp) ); add_hardwired_spec( "ld.so.1", "index", (Addr)&VG_(ppc32_linux_REDIR_FOR_strchr) ); } # elif defined(VGP_ppc64_linux) /* If we're using memcheck, use these intercepts right from the start, otherwise ld.so makes a lot of noise. */ if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { add_hardwired_spec( "ld64.so.1", "strlen", (Addr)VG_(fnptr_to_fnentry)( &VG_(ppc64_linux_REDIR_FOR_strlen) ) ); add_hardwired_spec( "ld64.so.1", "index", (Addr)VG_(fnptr_to_fnentry)( &VG_(ppc64_linux_REDIR_FOR_strchr) ) ); } # elif defined(VGP_ppc32_aix5) /* nothing so far */ # elif defined(VGP_ppc64_aix5) /* nothing so far */ # else # error Unknown platform # endif if (VG_(clo_trace_redir)) show_redir_state("after VG_(redir_initialise)"); }
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)"); }
void VG_(redir_initialise) ( void ) { // Assert that there are no DebugInfos so far vg_assert( VG_(next_DebugInfo)(NULL) == NULL ); // Initialise active mapping. activeSet = VG_(OSetGen_Create)(offsetof(Active, from_addr), NULL, // Use fast comparison dinfo_zalloc, "redir.ri.1", dinfo_free); // The rest of this function just adds initial Specs. # if defined(VGP_x86_linux) /* If we're using memcheck, use this intercept right from the start, otherwise ld.so (glibc-2.3.5) makes a lot of noise. */ if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { add_hardwired_spec( "ld-linux.so.2", "index", (Addr)&VG_(x86_linux_REDIR_FOR_index), NULL ); } # elif defined(VGP_amd64_linux) /* Redirect vsyscalls to local versions */ add_hardwired_active( 0xFFFFFFFFFF600000ULL, (Addr)&VG_(amd64_linux_REDIR_FOR_vgettimeofday) ); add_hardwired_active( 0xFFFFFFFFFF600400ULL, (Addr)&VG_(amd64_linux_REDIR_FOR_vtime) ); /* If we're using memcheck, use these intercepts right from the start, otherwise ld.so makes a lot of noise. */ if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { add_hardwired_spec( "ld-linux-x86-64.so.2", "strlen", (Addr)&VG_(amd64_linux_REDIR_FOR_strlen), # if defined(GLIBC_2_2) || defined(GLIBC_2_3) || defined(GLIBC_2_4) \ || defined(GLIBC_2_5) || defined(GLIBC_2_6) || defined(GLIBC_2_7) \ || defined(GLIBC_2_8) || defined(GLIBC_2_9) NULL # else /* for glibc-2.10 and later, this is mandatory - can't sanely continue without it */ complain_about_stripped_glibc_ldso # endif ); } # elif defined(VGP_ppc32_linux) /* If we're using memcheck, use these intercepts right from the start, otherwise ld.so makes a lot of noise. */ if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { /* this is mandatory - can't sanely continue without it */ add_hardwired_spec( "ld.so.1", "strlen", (Addr)&VG_(ppc32_linux_REDIR_FOR_strlen), complain_about_stripped_glibc_ldso ); add_hardwired_spec( "ld.so.1", "strcmp", (Addr)&VG_(ppc32_linux_REDIR_FOR_strcmp), NULL /* not mandatory - so why bother at all? */ /* glibc-2.6.1 (openSUSE 10.3, ppc32) seems fine without it */ ); add_hardwired_spec( "ld.so.1", "index", (Addr)&VG_(ppc32_linux_REDIR_FOR_strchr), NULL /* not mandatory - so why bother at all? */ /* glibc-2.6.1 (openSUSE 10.3, ppc32) seems fine without it */ ); } # elif defined(VGP_ppc64_linux) /* If we're using memcheck, use these intercepts right from the start, otherwise ld.so makes a lot of noise. */ if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { /* this is mandatory - can't sanely continue without it */ add_hardwired_spec( "ld64.so.1", "strlen", (Addr)VG_(fnptr_to_fnentry)( &VG_(ppc64_linux_REDIR_FOR_strlen) ), complain_about_stripped_glibc_ldso ); add_hardwired_spec( "ld64.so.1", "index", (Addr)VG_(fnptr_to_fnentry)( &VG_(ppc64_linux_REDIR_FOR_strchr) ), NULL /* not mandatory - so why bother at all? */ /* glibc-2.5 (FC6, ppc64) seems fine without it */ ); } # elif defined(VGP_ppc32_aix5) /* nothing so far */ # elif defined(VGP_ppc64_aix5) /* nothing so far */ # elif defined(VGO_darwin) /* If we're using memcheck, use these intercepts right from the start, otherwise dyld makes a lot of noise. */ if (0==VG_(strcmp)("Memcheck", VG_(details).name)) { add_hardwired_spec("dyld", "strcmp", (Addr)&VG_(darwin_REDIR_FOR_strcmp), NULL); add_hardwired_spec("dyld", "strlen", (Addr)&VG_(darwin_REDIR_FOR_strlen), NULL); add_hardwired_spec("dyld", "strcat", (Addr)&VG_(darwin_REDIR_FOR_strcat), NULL); add_hardwired_spec("dyld", "strcpy", (Addr)&VG_(darwin_REDIR_FOR_strcpy), NULL); add_hardwired_spec("dyld", "strlcat", (Addr)&VG_(darwin_REDIR_FOR_strlcat), NULL); # if defined(VGP_amd64_darwin) // DDD: #warning fixme rdar://6166275 add_hardwired_spec("dyld", "arc4random", (Addr)&VG_(darwin_REDIR_FOR_arc4random), NULL); # endif } # else # error Unknown platform # endif if (VG_(clo_trace_redir)) show_redir_state("after VG_(redir_initialise)"); }
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)"); }
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); }