Add a fourth --smc-check= variant, --smc-check=all-non-file. This

adds self-modifying-code checks to all guest code taken from mappings
which are not file backed, but omits checks in code from file backed
mappings.  This has the effect of giving complete smc-coverage of JIT
generated code -- since that is invariably generated into anonymous
mapped areas -- without burdening non-JIT generated code with such
checks.  Running Firefox 6, --smc-check=all-non-file reduces by a
factor of between 3 and 10 the number of translations requiring a self
check, compared to --smc-check=all.  These changes depend on the vex
interface changes in r2158.



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11798
This commit is contained in:
Julian Seward 2011-06-07 21:39:28 +00:00
parent 953f93f969
commit da49be7c14
7 changed files with 122 additions and 50 deletions

1
NEWS
View File

@ -4,6 +4,7 @@ Release 3.7.0 (???)
- Added the --mod-funcname option to cg_diff.
- Further reduction in overheads caused by --smc-check=all, especially
on 64-bit targets.
- new variant --smc-check=all-non-file
* IBM z/Architecture (s390x) running Linux
Valgrind can analyse 64-bit programs running on z/Architecture.

View File

@ -171,8 +171,10 @@ static void usage_NORETURN ( Bool debug_help )
" part of the path after 'string'. Allows removal\n"
" of path prefixes. Use this flag multiple times\n"
" to specify a set of prefixes to remove.\n"
" --smc-check=none|stack|all checks for self-modifying code: none,\n"
" only for code found in stacks, or all [stack]\n"
" --smc-check=none|stack|all|all-non-file [stack]\n"
" checks for self-modifying code: none, only for\n"
" code found in stacks, for all code, or for all\n"
" code except that from file-backed mappings\n"
" --read-var-info=yes|no read debug info on stack and global variables\n"
" and use it to print better error messages in\n"
" tools that make use of it (Memcheck, Helgrind,\n"
@ -519,6 +521,9 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd,
Vg_SmcStack);
else if VG_XACT_CLO(arg, "--smc-check=all", VG_(clo_smc_check),
Vg_SmcAll);
else if VG_XACT_CLO(arg, "--smc-check=all-non-file",
VG_(clo_smc_check),
Vg_SmcAllNonFile);
else if VG_STR_CLO (arg, "--kernel-variant", VG_(clo_kernel_variant)) {}

View File

@ -729,41 +729,87 @@ static Bool translations_allowable_from_seg ( NSegment const* seg )
}
/* Is a self-check required for a translation of a guest address
inside segment SEG when requested by thread TID ? */
/* Produce a bitmask stating which of the supplied extents needs a
self-check. See documentation of
VexTranslateArgs::needs_self_check for more details about the
return convention. */
static Bool self_check_required ( NSegment const* seg, ThreadId tid )
static UInt needs_self_check ( void* closureV,
VexGuestExtents* vge )
{
#if defined(VGO_darwin)
// GrP fixme hack - dyld i386 IMPORT gets rewritten
// to really do this correctly, we'd need to flush the
// translation cache whenever a segment became +WX
if (seg->hasX && seg->hasW) {
return True;
}
#endif
switch (VG_(clo_smc_check)) {
case Vg_SmcNone: return False;
case Vg_SmcAll: return True;
case Vg_SmcStack:
return seg
? (seg->start <= VG_(get_SP)(tid)
&& VG_(get_SP)(tid)+sizeof(Word)-1 <= seg->end)
: False;
break;
default:
vg_assert2(0, "unknown VG_(clo_smc_check) value");
VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
UInt i, bitset;
vg_assert(vge->n_used >= 1 && vge->n_used <= 3);
bitset = 0;
for (i = 0; i < vge->n_used; i++) {
Bool check = False;
Addr addr = (Addr)vge->base[i];
SizeT len = (SizeT)vge->len[i];
NSegment const* segA = NULL;
# if defined(VGO_darwin)
// GrP fixme hack - dyld i386 IMPORT gets rewritten.
// To really do this correctly, we'd need to flush the
// translation cache whenever a segment became +WX.
segA = VG_(am_find_nsegment)(addr);
if (segA && segA->hasX && segA->hasW)
check = True;
# endif
if (!check) {
switch (VG_(clo_smc_check)) {
case Vg_SmcNone:
/* never check (except as per Darwin hack above) */
break;
case Vg_SmcAll:
/* always check */
check = True;
break;
case Vg_SmcStack: {
/* check if the address is in the same segment as this
thread's stack pointer */
Addr sp = VG_(get_SP)(closure->tid);
if (!segA) {
segA = VG_(am_find_nsegment)(addr);
}
NSegment const* segSP = VG_(am_find_nsegment)(sp);
if (segA && segSP && segA == segSP)
check = True;
break;
}
case Vg_SmcAllNonFile: {
/* check if any part of the extent is not in a
file-mapped segment */
if (!segA) {
segA = VG_(am_find_nsegment)(addr);
}
if (segA && segA->kind == SkFileC && segA->start <= addr
&& (len == 0 || addr + len <= segA->end + 1)) {
/* in a file-mapped segment; skip the check */
} else {
check = True;
}
break;
}
default:
vg_assert(0);
}
}
if (check)
bitset |= (1 << i);
}
return bitset;
}
/* This is a callback passed to LibVEX_Translate. It stops Vex from
chasing into function entry points that we wish to redirect.
Chasing across them obviously defeats the redirect mechanism, with
bad effects for Memcheck, Addrcheck, and possibly others.
Also, we must stop Vex chasing into blocks for which we might want
to self checking.
bad effects for Memcheck, Helgrind, DRD, Massif, and possibly others.
*/
static Bool chase_into_ok ( void* closureV, Addr64 addr64 )
{
@ -1284,7 +1330,6 @@ Bool VG_(translate) ( ThreadId tid,
Addr64 addr;
T_Kind kind;
Int tmpbuf_used, verbosity, i;
Bool do_self_check;
Bool (*preamble_fn)(void*,IRSB*);
VexArch vex_arch;
VexArchInfo vex_archinfo;
@ -1392,9 +1437,6 @@ Bool VG_(translate) ( ThreadId tid,
return False;
}
/* Do we want a self-checking translation? */
do_self_check = self_check_required( seg, tid );
/* True if a debug trans., or if bit N set in VG_(clo_trace_codegen). */
verbosity = 0;
if (debugging_translation) {
@ -1509,7 +1551,7 @@ Bool VG_(translate) ( ThreadId tid,
vta.finaltidy = VG_(needs).final_IR_tidy_pass
? VG_(tdict).tool_final_IR_tidy_pass
: NULL;
vta.do_self_check = do_self_check;
vta.needs_self_check = needs_self_check;
vta.traceflags = verbosity;
/* Set up the dispatch-return info. For archs without a link
@ -1557,7 +1599,8 @@ Bool VG_(translate) ( ThreadId tid,
/* Sheesh. Finally, actually _do_ the translation! */
tres = LibVEX_Translate ( &vta );
vg_assert(tres == VexTransOK);
vg_assert(tres.status == VexTransOK);
vg_assert(tres.n_sc_extents >= 0 && tres.n_sc_extents <= 3);
vg_assert(tmpbuf_used <= N_TMPBUF);
vg_assert(tmpbuf_used > 0);
@ -1594,7 +1637,7 @@ Bool VG_(translate) ( ThreadId tid,
nraddr,
(Addr)(&tmpbuf[0]),
tmpbuf_used,
do_self_check );
tres.n_sc_extents > 0 );
} else {
VG_(add_to_unredir_transtab)( &vge,
nraddr,

View File

@ -228,7 +228,9 @@ typedef
Vg_SmcNone, // never generate self-checking translations
Vg_SmcStack, // generate s-c-t's for code found in stacks
// (this is the default)
Vg_SmcAll // make all translations self-checking.
Vg_SmcAll, // make all translations self-checking.
Vg_SmcAllNonFile // make all translations derived from
// non-file-backed memory self checking
}
VgSmc;

View File

@ -1444,7 +1444,7 @@ need to use these.</para>
<varlistentry id="opt.smc-check" xreflabel="--smc-check">
<term>
<option><![CDATA[--smc-check=<none|stack|all> [default: stack] ]]></option>
<option><![CDATA[--smc-check=<none|stack|all|all-non-file> [default: stack] ]]></option>
</term>
<listitem>
<para>This option controls Valgrind's detection of self-modifying
@ -1453,33 +1453,50 @@ need to use these.</para>
continue to execute the translations it made for the old code. This
will likely lead to incorrect behaviour and/or crashes.</para>
<para>Valgrind has three levels of self-modifying code detection:
<para>Valgrind has four levels of self-modifying code detection:
no detection, detect self-modifying code on the stack (which is used by
GCC to implement nested functions), or detect self-modifying code
everywhere. Note that the default option will catch the vast majority
GCC to implement nested functions), detect self-modifying code
everywhere, and detect self-modifying code everywhere except in
file-backed mappings.
Note that the default option will catch the vast majority
of cases. The main case it will not catch is programs such as JIT
compilers that dynamically generate code <emphasis>and</emphasis>
subsequently overwrite part or all of it. Running with
<varname>all</varname> will slow Valgrind down noticeably. Running with
<varname>all</varname> will slow Valgrind down noticeably.
Running with
<varname>none</varname> will rarely speed things up, since very little
code gets put on the stack for most programs. The
<function>VALGRIND_DISCARD_TRANSLATIONS</function> client request is
an alternative to <option>--smc-check=all</option> that requires more
effort but is much faster.
<function>VALGRIND_DISCARD_TRANSLATIONS</function> client
request is an alternative to <option>--smc-check=all</option>
that requires more programmer effort but allows Valgrind to run
your program faster, by telling it precisely when translations
need to be re-made.
<!-- commented out because it causes broken links in the man page
; see <xref
linkend="manual-core-adv.clientreq"/> for more details.
-->
</para>
<para><option>--smc-check=all-non-file</option> provides a
cheaper but more limited version
of <option>--smc-check=all</option>. It adds checks to any
translations that do not originate from file-backed memory
mappings. Typical applications that generate code, for example
JITs in web browsers, generate code into anonymous mmaped areas,
whereas the "fixed" code of the browser always lives in
file-backed mappings. <option>--smc-check=all-non-file</option>
takes advantage of this observation, limiting the overhead of
checking to code which is likely to be JIT generated.</para>
<para>Some architectures (including ppc32, ppc64 and ARM) require
programs which create code at runtime to flush the instruction
cache in between code generation and first use. Valgrind
observes and honours such instructions. Hence, on ppc32/Linux,
ppc64/Linux and ARM/Linux, Valgrind always provides complete, transparent
support for self-modifying code. It is only on platforms such as
x86/Linux, AMD64/Linux and x86/Darwin that you need to use this
option.</para>
x86/Linux, AMD64/Linux, x86/Darwin and AMD64/Darwin
that you need to use this option.</para>
</listitem>
</varlistentry>

View File

@ -57,8 +57,10 @@ usage: valgrind [options] prog-and-args
part of the path after 'string'. Allows removal
of path prefixes. Use this flag multiple times
to specify a set of prefixes to remove.
--smc-check=none|stack|all checks for self-modifying code: none,
only for code found in stacks, or all [stack]
--smc-check=none|stack|all|all-non-file [stack]
checks for self-modifying code: none, only for
code found in stacks, for all code, or for all
code except that from file-backed mappings
--read-var-info=yes|no read debug info on stack and global variables
and use it to print better error messages in
tools that make use of it (Memcheck, Helgrind,

View File

@ -57,8 +57,10 @@ usage: valgrind [options] prog-and-args
part of the path after 'string'. Allows removal
of path prefixes. Use this flag multiple times
to specify a set of prefixes to remove.
--smc-check=none|stack|all checks for self-modifying code: none,
only for code found in stacks, or all [stack]
--smc-check=none|stack|all|all-non-file [stack]
checks for self-modifying code: none, only for
code found in stacks, for all code, or for all
code except that from file-backed mappings
--read-var-info=yes|no read debug info on stack and global variables
and use it to print better error messages in
tools that make use of it (Memcheck, Helgrind,