]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Allow the user to specify precise-exception behaviour for translations
authorJulian Seward <jseward@acm.org>
Thu, 5 Feb 2015 12:59:46 +0000 (12:59 +0000)
committerJulian Seward <jseward@acm.org>
Thu, 5 Feb 2015 12:59:46 +0000 (12:59 +0000)
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

cachegrind/cg_main.c
callgrind/main.c
coregrind/m_main.c
coregrind/m_options.c
coregrind/m_translate.c
include/pub_tool_options.h
massif/ms_main.c
none/tests/cmdline2.stdout.exp

index 7f2c7e555b79e4cd156d21363d9857f246e6aac9..dcc6220c420daa9efcb22be3a64fc98ca6d73c67 100644 (file)
@@ -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);
index 26e5c5dc964e93cd4399628d938900e6b9d4eb97..d4b3679b703efac24741a1f17357ed42a0410f1d 100644 (file)
@@ -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.
 
index 96ebe3e6bb36c8f22185e4be3808f41bed7da6ff..51ada98a18b125ef5fd0c03fd4bd5ef18d7175e2 100644 (file)
@@ -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=<number>     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));
 
    //--------------------------------------------------------------
index 1238ca1cadf275e164b573ac6711198eeab5a62e..f9183e32612dc35e039aa2956340770d38674363 100644 (file)
 
 
 /* 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};
index 8a8f5aa244e4f02c6e8cdfb36d98887018323e91..8eb85b0c6c987b2f535aeb3c6e88059b4125f04b 100644 (file)
 /*--- 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;
index c9f8559855422c44bd7646924749ee1bc7c9c249..e6dee237085e5cc8fb848907d8282153e8b40c7b 100644 (file)
     }) \
    )
 
+// 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);
index 01daaf0416ee513f7f2d4f1d475e7199dcc51c60..24fb18f646e6ae6ed69635455bd1b60e3450a3bf 100644 (file)
@@ -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.
index bccb28d9617784185ee513d0e9745848d4648194..2654de1d7b7e93d7bf740df16844353ba98a541c 100644 (file)
@@ -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=<number>     show translation for basic block associated