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);
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");
"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"
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.
" 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=<number> show translation for basic block associated\n"
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 != '=')
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)) {}
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) {}
# endif
// END HACK
- // Set default vex control params
+ // Set default vex control params.
LibVEX_default_VexControl(& VG_(clo_vex_control));
//--------------------------------------------------------------
/* 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};
/*--- 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 )
{
+ 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);
}
/*------------------------------------------------------------*/
return convention. */
static UInt needs_self_check ( void* closureV,
+ /*MAYBE_MOD*/VexRegisterUpdates* pxControl,
const VexGuestExtents* vge )
{
VgCallbackClosure* closure = (VgCallbackClosure*)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];
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;
}) \
)
+// 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);
/* 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);
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.
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=<number> show translation for basic block associated