From: Julian Seward Date: Thu, 5 Feb 2015 12:59:46 +0000 (+0000) Subject: Allow the user to specify precise-exception behaviour for translations X-Git-Tag: svn/VALGRIND_3_11_0~686 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=45a0fb5e692ba93ebd34a832973d5b3dc5568f8f;p=thirdparty%2Fvalgrind.git Allow the user to specify precise-exception behaviour for translations made from file-backed mappings (AOT code, basically) that is different from the default behaviour as specified by --vex-iropt-register-updates. New flag is --px-file-backed=, with the same possible args as --vex-iropt-register-updates has. Add a new flag --px-default, which is a short alias for --vex-iropt-register-updates. Add one line of stats output when --stats=yes, showing counts of how many translations have been made under each of the 4 different PX optimisation settings. No user-visible change if you don't use the new flags. Relies on VEX API change in r3084. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@14906 --- diff --git a/cachegrind/cg_main.c b/cachegrind/cg_main.c index 7f2c7e555b..dcc6220c42 100644 --- a/cachegrind/cg_main.c +++ b/cachegrind/cg_main.c @@ -1787,8 +1787,10 @@ static void cg_pre_clo_init(void) VG_(details_bug_reports_to) (VG_BUGS_TO); VG_(details_avg_translation_sizeB) ( 500 ); - VG_(clo_vex_control).iropt_register_updates + VG_(clo_vex_control).iropt_register_updates_default + = VG_(clo_px_file_backed) = VexRegUpdSpAtMemAccess; // overridable by the user. + VG_(basic_tool_funcs) (cg_post_clo_init, cg_instrument, cg_fini); diff --git a/callgrind/main.c b/callgrind/main.c index 26e5c5dc96..d4b3679b70 100644 --- a/callgrind/main.c +++ b/callgrind/main.c @@ -1965,7 +1965,7 @@ static void clg_start_client_code_callback ( ThreadId tid, ULong blocks_done ) static void CLG_(post_clo_init)(void) { - if (VG_(clo_vex_control).iropt_register_updates + if (VG_(clo_vex_control).iropt_register_updates_default != VexRegUpdSpAtMemAccess) { CLG_DEBUG(1, " Using user specified value for " "--vex-iropt-register-updates\n"); @@ -1975,6 +1975,15 @@ void CLG_(post_clo_init)(void) "sp-at-mem-access\n"); } + if (VG_(clo_px_file_backed) != VexRegUpdSpAtMemAccess) { + CLG_DEBUG(1, " Using user specified value for " + "--px-file-backed\n"); + } else { + CLG_DEBUG(1, + " Using default --px-file-backed=" + "sp-at-mem-access\n"); + } + if (VG_(clo_vex_control).iropt_unroll_thresh != 0) { VG_(message)(Vg_UserMsg, "callgrind only works with --vex-iropt-unroll-thresh=0\n" @@ -2034,8 +2043,10 @@ void CLG_(pre_clo_init)(void) VG_(details_bug_reports_to) (VG_BUGS_TO); VG_(details_avg_translation_sizeB) ( 500 ); - VG_(clo_vex_control).iropt_register_updates + VG_(clo_vex_control).iropt_register_updates_default + = VG_(clo_px_file_backed) = VexRegUpdSpAtMemAccess; // overridable by the user. + VG_(clo_vex_control).iropt_unroll_thresh = 0; // cannot be overriden. VG_(clo_vex_control).guest_chase_thresh = 0; // cannot be overriden. diff --git a/coregrind/m_main.c b/coregrind/m_main.c index 96ebe3e6bb..51ada98a18 100644 --- a/coregrind/m_main.c +++ b/coregrind/m_main.c @@ -246,26 +246,34 @@ static void usage_NORETURN ( Bool debug_help ) " Vex options for all Valgrind tools:\n" " --vex-iropt-verbosity=<0..9> [0]\n" " --vex-iropt-level=<0..2> [2]\n" -" --vex-iropt-register-updates=sp-at-mem-access\n" -" |unwindregs-at-mem-access\n" -" |allregs-at-mem-access\n" -" |allregs-at-each-insn [unwindregs-at-mem-access]\n" " --vex-iropt-unroll-thresh=<0..400> [120]\n" " --vex-guest-max-insns=<1..100> [50]\n" " --vex-guest-chase-thresh=<0..99> [10]\n" " --vex-guest-chase-cond=no|yes [no]\n" -" --trace-flags and --profile-flags values (omit the middle space):\n" -" 1000 0000 show conversion into IR\n" -" 0100 0000 show after initial opt\n" -" 0010 0000 show after instrumentation\n" -" 0001 0000 show after second opt\n" -" 0000 1000 show after tree building\n" -" 0000 0100 show selecting insns\n" -" 0000 0010 show after reg-alloc\n" -" 0000 0001 show final assembly\n" -" 0000 0000 show summary profile only\n" -" (Nb: you need --trace-notbelow and/or --trace-notabove\n" -" with --trace-flags for full details)\n" +" Precise exception control. Possible values for 'mode' are as follows\n" +" and specify the minimum set of registers guaranteed to be correct\n" +" immediately prior to memory access instructions:\n" +" sp-at-mem-access stack pointer only\n" +" unwindregs-at-mem-access registers needed for stack unwinding\n" +" allregs-at-mem-access all registers\n" +" allregs-at-each-insn all registers are always correct\n" +" Default value for all 3 following flags is [unwindregs-at-mem-access].\n" +" --vex-iropt-register-updates=mode setting to use by default\n" +" --px-default=mode synonym for --vex-iropt-register-updates\n" +" --px-file-backed=mode optional setting for file-backed (non-JIT) code\n" +" Tracing and profile control:\n" +" --trace-flags and --profile-flags values (omit the middle space):\n" +" 1000 0000 show conversion into IR\n" +" 0100 0000 show after initial opt\n" +" 0010 0000 show after instrumentation\n" +" 0001 0000 show after second opt\n" +" 0000 1000 show after tree building\n" +" 0000 0100 show selecting insns\n" +" 0000 0010 show after reg-alloc\n" +" 0000 0001 show final assembly\n" +" 0000 0000 show summary profile only\n" +" (Nb: you need --trace-notbelow and/or --trace-notabove\n" +" with --trace-flags for full details)\n" "\n" " debugging options for Valgrind tools that report errors\n" " --dump-error= show translation for basic block associated\n" @@ -469,12 +477,21 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd, VG_(clo_req_tsyms) = VG_(newXA)(VG_(malloc), "main.mpclo.6", VG_(free), sizeof(HChar *)); + /* Constants for parsing PX control flags. */ + const HChar* pxStrings[5] + = { "sp-at-mem-access", "unwindregs-at-mem-access", + "allregs-at-mem-access", "allregs-at-each-insn", NULL }; + const VexRegisterUpdates pxVals[5] + = { VexRegUpdSpAtMemAccess, VexRegUpdUnwindregsAtMemAccess, + VexRegUpdAllregsAtMemAccess, VexRegUpdAllregsAtEachInsn, 0/*inval*/ }; + /* BEGIN command-line processing loop */ for (i = 0; i < VG_(sizeXA)( VG_(args_for_valgrind) ); i++) { HChar* arg = * (HChar**) VG_(indexXA)( VG_(args_for_valgrind), i ); HChar* colon = arg; + UInt ix = 0; // Look for a colon in the option name. while (*colon && *colon != ':' && *colon != '=') @@ -564,7 +581,8 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd, else if VG_XACT_CLO(arg, "--vgdb=full", VG_(clo_vgdb), Vg_VgdbFull) { /* automatically updates register values at each insn with --vgdb=full */ - VG_(clo_vex_control).iropt_register_updates + VG_(clo_vex_control).iropt_register_updates_default + = VG_(clo_px_file_backed) = VexRegUpdAllregsAtEachInsn; } else if VG_INT_CLO (arg, "--vgdb-poll", VG_(clo_vgdb_poll)) {} @@ -687,22 +705,29 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd, else if VG_BINT_CLO(arg, "--vex-iropt-level", VG_(clo_vex_control).iropt_level, 0, 2) {} - else if VG_XACT_CLO(arg, - "--vex-iropt-register-updates=sp-at-mem-access", - VG_(clo_vex_control).iropt_register_updates, - VexRegUpdSpAtMemAccess) {} - else if VG_XACT_CLO(arg, - "--vex-iropt-register-updates=unwindregs-at-mem-access", - VG_(clo_vex_control).iropt_register_updates, - VexRegUpdUnwindregsAtMemAccess) {} - else if VG_XACT_CLO(arg, - "--vex-iropt-register-updates=allregs-at-mem-access", - VG_(clo_vex_control).iropt_register_updates, - VexRegUpdAllregsAtMemAccess) {} - else if VG_XACT_CLO(arg, - "--vex-iropt-register-updates=allregs-at-each-insn", - VG_(clo_vex_control).iropt_register_updates, - VexRegUpdAllregsAtEachInsn) {} + else if VG_STRINDEX_CLO(arg, "--vex-iropt-register-updates", + pxStrings, ix) { + vg_assert(ix < 4); + vg_assert(pxVals[ix] >= VexRegUpdSpAtMemAccess); + vg_assert(pxVals[ix] <= VexRegUpdAllregsAtEachInsn); + VG_(clo_vex_control).iropt_register_updates_default = pxVals[ix]; + } + else if VG_STRINDEX_CLO(arg, "--px-default", pxStrings, ix) { + // NB: --px-default is an alias for the hard-to-remember + // --vex-iropt-register-updates, hence the same logic. + vg_assert(ix < 4); + vg_assert(pxVals[ix] >= VexRegUpdSpAtMemAccess); + vg_assert(pxVals[ix] <= VexRegUpdAllregsAtEachInsn); + VG_(clo_vex_control).iropt_register_updates_default = pxVals[ix]; + } + else if VG_STRINDEX_CLO(arg, "--px-file-backed", pxStrings, ix) { + // Whereas --px-file-backed isn't + // the same flag as --vex-iropt-register-updates. + vg_assert(ix < 4); + vg_assert(pxVals[ix] >= VexRegUpdSpAtMemAccess); + vg_assert(pxVals[ix] <= VexRegUpdAllregsAtEachInsn); + VG_(clo_px_file_backed) = pxVals[ix]; + } else if VG_BINT_CLO(arg, "--vex-iropt-unroll-thresh", VG_(clo_vex_control).iropt_unroll_thresh, 0, 400) {} @@ -1855,7 +1880,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) # endif // END HACK - // Set default vex control params + // Set default vex control params. LibVEX_default_VexControl(& VG_(clo_vex_control)); //-------------------------------------------------------------- diff --git a/coregrind/m_options.c b/coregrind/m_options.c index 1238ca1cad..f9183e3261 100644 --- a/coregrind/m_options.c +++ b/coregrind/m_options.c @@ -43,7 +43,10 @@ /* Define, and set defaults. */ + VexControl VG_(clo_vex_control); +VexRegisterUpdates VG_(clo_px_file_backed) = VexRegUpd_INVALID; + Bool VG_(clo_error_limit) = True; Int VG_(clo_error_exitcode) = 0; HChar *VG_(clo_error_markers)[2] = {NULL, NULL}; diff --git a/coregrind/m_translate.c b/coregrind/m_translate.c index 8a8f5aa244..8eb85b0c6c 100644 --- a/coregrind/m_translate.c +++ b/coregrind/m_translate.c @@ -67,9 +67,14 @@ /*--- Stats ---*/ /*------------------------------------------------------------*/ -static UInt n_SP_updates_fast = 0; -static UInt n_SP_updates_generic_known = 0; -static UInt n_SP_updates_generic_unknown = 0; +static ULong n_SP_updates_fast = 0; +static ULong n_SP_updates_generic_known = 0; +static ULong n_SP_updates_generic_unknown = 0; + +static ULong n_PX_VexRegUpdSpAtMemAccess = 0; +static ULong n_PX_VexRegUpdUnwindregsAtMemAccess = 0; +static ULong n_PX_VexRegUpdAllregsAtMemAccess = 0; +static ULong n_PX_VexRegUpdAllregsAtEachInsn = 0; void VG_(print_translation_stats) ( void ) { @@ -77,21 +82,24 @@ void VG_(print_translation_stats) ( void ) + n_SP_updates_generic_unknown; if (n_SP_updates == 0) { VG_(message)(Vg_DebugMsg, "translate: no SP updates identified\n"); - return; + } else { + VG_(message)(Vg_DebugMsg, + "translate: fast SP updates identified: %'llu (%3.1f%%)\n", + n_SP_updates_fast, n_SP_updates_fast * 100.0 / n_SP_updates ); + + VG_(message)(Vg_DebugMsg, + "translate: generic_known SP updates identified: %'llu (%3.1f%%)\n", + n_SP_updates_generic_known, + n_SP_updates_generic_known * 100.0 / n_SP_updates ); + + VG_(message)(Vg_DebugMsg, + "translate: generic_unknown SP updates identified: %'llu (%3.1f%%)\n", + n_SP_updates_generic_unknown, + n_SP_updates_generic_unknown * 100.0 / n_SP_updates ); } - VG_(message)(Vg_DebugMsg, - "translate: fast SP updates identified: %'u (%3.1f%%)\n", - n_SP_updates_fast, n_SP_updates_fast * 100.0 / n_SP_updates ); - - VG_(message)(Vg_DebugMsg, - "translate: generic_known SP updates identified: %'u (%3.1f%%)\n", - n_SP_updates_generic_known, - n_SP_updates_generic_known * 100.0 / n_SP_updates ); VG_(message)(Vg_DebugMsg, - "translate: generic_unknown SP updates identified: %'u (%3.1f%%)\n", - n_SP_updates_generic_unknown, - n_SP_updates_generic_unknown * 100.0 / n_SP_updates ); + "translate: PX: SPonly %'llu, UnwRegs %'llu, AllRegs %'llu, AllRegsAllInsns %'llu\n", n_PX_VexRegUpdSpAtMemAccess, n_PX_VexRegUpdUnwindregsAtMemAccess, n_PX_VexRegUpdAllregsAtMemAccess, n_PX_VexRegUpdAllregsAtEachInsn); } /*------------------------------------------------------------*/ @@ -779,6 +787,7 @@ static Bool translations_allowable_from_seg ( NSegment const* seg, Addr addr ) return convention. */ static UInt needs_self_check ( void* closureV, + /*MAYBE_MOD*/VexRegisterUpdates* pxControl, const VexGuestExtents* vge ) { VgCallbackClosure* closure = (VgCallbackClosure*)closureV; @@ -787,6 +796,20 @@ static UInt needs_self_check ( void* closureV, vg_assert(vge->n_used >= 1 && vge->n_used <= 3); bitset = 0; + /* Will we need to do a second pass in order to compute a + revised *pxControl value? */ + Bool pxStatusMightChange + = /* "the user actually set it" */ + VG_(clo_px_file_backed) != VexRegUpd_INVALID + /* "and they set it to something other than the default. */ + && *pxControl != VG_(clo_px_file_backed); + + /* First, compute |bitset|, which specifies which extent(s) need a + self check. Whilst we're at it, note any NSegments that we get, + so as to reduce the number of calls required to + VG_(am_find_nsegment) in a possible second pass. */ + const NSegment const* segs[3] = { NULL, NULL, NULL }; + for (i = 0; i < vge->n_used; i++) { Bool check = False; Addr addr = vge->base[i]; @@ -844,6 +867,62 @@ static UInt needs_self_check ( void* closureV, if (check) bitset |= (1 << i); + + if (pxStatusMightChange && segA) { + vg_assert(i < sizeof(segs)/sizeof(segs[0])); + segs[i] = segA; + } + } + + /* Now, possibly do a second pass, to see if the PX status might + change. This can happen if the user specified value via + --px-file-backed= which is different from the default PX value + specified via --vex-iropt-register-updates (also known by the + shorter alias --px-default). */ + if (pxStatusMightChange) { + + Bool allFileBacked = True; + for (i = 0; i < vge->n_used; i++) { + Addr addr = vge->base[i]; + SizeT len = vge->len[i]; + NSegment const* segA = segs[i]; + if (!segA) { + /* If we don't have a cached value for |segA|, compute it now. */ + segA = VG_(am_find_nsegment)(addr); + } + vg_assert(segA); /* Can this ever fail? */ + if (segA && segA->kind == SkFileC && segA->start <= addr + && (len == 0 || addr + len <= segA->end + 1)) { + /* in a file-mapped segment */ + } else { + /* not in a file-mapped segment, or we can't figure out + where it is */ + allFileBacked = False; + break; + } + } + + /* So, finally, if all the extents are in file backed segments, perform + the user-specified PX change. */ + if (allFileBacked) { + *pxControl = VG_(clo_px_file_backed); + } + + } + + /* Update running PX stats, as it is difficult without these to + check that the system is behaving as expected. */ + switch (*pxControl) { + case VexRegUpdSpAtMemAccess: + n_PX_VexRegUpdSpAtMemAccess++; break; + case VexRegUpdUnwindregsAtMemAccess: + n_PX_VexRegUpdUnwindregsAtMemAccess++; break; + case VexRegUpdAllregsAtMemAccess: + n_PX_VexRegUpdAllregsAtMemAccess++; break; + case VexRegUpdAllregsAtEachInsn: + n_PX_VexRegUpdAllregsAtEachInsn++; break; + default: + vg_assert(0); } return bitset; diff --git a/include/pub_tool_options.h b/include/pub_tool_options.h index c9f8559855..e6dee23708 100644 --- a/include/pub_tool_options.h +++ b/include/pub_tool_options.h @@ -171,6 +171,24 @@ }) \ ) +// Arg that can be one of a set of strings, as specified in an NULL +// terminated array. Returns the index of the string in |qq_ix|, or +// aborts if not found. +#define VG_STRINDEX_CLO(qq_arg, qq_option, qq_strings, qq_ix) \ + (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \ + ({ \ + const HChar* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ + for (qq_ix = 0; (qq_strings)[qq_ix]; qq_ix++) { \ + if (VG_STREQ(val, (qq_strings)[qq_ix])) \ + break; \ + } \ + if ((qq_strings)[qq_ix] == NULL) \ + VG_(fmsg_bad_option)(qq_arg, \ + "Invalid string '%s' in '%s'\n", val, qq_arg); \ + True; \ + }) \ + ) + /* Verbosity level: 0 = silent, 1 (default), > 1 = more verbose. */ extern Int VG_(clo_verbosity); @@ -203,6 +221,7 @@ extern const HChar* VG_(clo_xml_user_comment); /* Vex iropt control. Tool-visible so tools can make Vex optimise less aggressively if that is needed (callgrind needs this). */ extern VexControl VG_(clo_vex_control); +extern VexRegisterUpdates VG_(clo_px_file_backed); /* Number of parents of a backtrace. Default: 12 */ extern Int VG_(clo_backtrace_size); diff --git a/massif/ms_main.c b/massif/ms_main.c index 01daaf0416..24fb18f646 100644 --- a/massif/ms_main.c +++ b/massif/ms_main.c @@ -2534,7 +2534,8 @@ static void ms_pre_clo_init(void) VG_(details_avg_translation_sizeB) ( 330 ); - VG_(clo_vex_control).iropt_register_updates + VG_(clo_vex_control).iropt_register_updates_default + = VG_(clo_px_file_backed) = VexRegUpdSpAtMemAccess; // overridable by the user. // Basic functions. diff --git a/none/tests/cmdline2.stdout.exp b/none/tests/cmdline2.stdout.exp index bccb28d961..2654de1d7b 100644 --- a/none/tests/cmdline2.stdout.exp +++ b/none/tests/cmdline2.stdout.exp @@ -159,26 +159,34 @@ usage: valgrind [options] prog-and-args Vex options for all Valgrind tools: --vex-iropt-verbosity=<0..9> [0] --vex-iropt-level=<0..2> [2] - --vex-iropt-register-updates=sp-at-mem-access - |unwindregs-at-mem-access - |allregs-at-mem-access - |allregs-at-each-insn [unwindregs-at-mem-access] --vex-iropt-unroll-thresh=<0..400> [120] --vex-guest-max-insns=<1..100> [50] --vex-guest-chase-thresh=<0..99> [10] --vex-guest-chase-cond=no|yes [no] - --trace-flags and --profile-flags values (omit the middle space): - 1000 0000 show conversion into IR - 0100 0000 show after initial opt - 0010 0000 show after instrumentation - 0001 0000 show after second opt - 0000 1000 show after tree building - 0000 0100 show selecting insns - 0000 0010 show after reg-alloc - 0000 0001 show final assembly - 0000 0000 show summary profile only - (Nb: you need --trace-notbelow and/or --trace-notabove - with --trace-flags for full details) + Precise exception control. Possible values for 'mode' are as follows + and specify the minimum set of registers guaranteed to be correct + immediately prior to memory access instructions: + sp-at-mem-access stack pointer only + unwindregs-at-mem-access registers needed for stack unwinding + allregs-at-mem-access all registers + allregs-at-each-insn all registers are always correct + Default value for all 3 following flags is [unwindregs-at-mem-access]. + --vex-iropt-register-updates=mode setting to use by default + --px-default=mode synonym for --vex-iropt-register-updates + --px-file-backed=mode optional setting for file-backed (non-JIT) code + Tracing and profile control: + --trace-flags and --profile-flags values (omit the middle space): + 1000 0000 show conversion into IR + 0100 0000 show after initial opt + 0010 0000 show after instrumentation + 0001 0000 show after second opt + 0000 1000 show after tree building + 0000 0100 show selecting insns + 0000 0010 show after reg-alloc + 0000 0001 show final assembly + 0000 0000 show summary profile only + (Nb: you need --trace-notbelow and/or --trace-notabove + with --trace-flags for full details) debugging options for Valgrind tools that report errors --dump-error= show translation for basic block associated