Tools should explain why an option is bad when using fmsg_bad_option.

Add an explanation of why an option was bad to fmsg_bad_option calls that
were just using "" as argument. Fixes bug #334802.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13975 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/NEWS b/NEWS
index a4f02a1..8b3fe0e 100644
--- a/NEWS
+++ b/NEWS
@@ -129,6 +129,7 @@
 334049  lzcnt fails silently (x86_32)
 334705  sendmsg and recvmsg should guard against bogus msghdr fields.
 334727  Build fails with -Werror=format-security
+334802  valgrind does not always explain why a given option is bad
 n-i-bz  Fix KVM_CREATE_IRQCHIP ioctl handling
 n-i-bz  s390x: Fix memory corruption for multithreaded applications
 n-i-bz  vex arm->IR: allow PC as basereg in some LDRD cases
diff --git a/cachegrind/cg_arch.c b/cachegrind/cg_arch.c
index 0b39c52..5a1e5a6 100644
--- a/cachegrind/cg_arch.c
+++ b/cachegrind/cg_arch.c
@@ -105,7 +105,7 @@
    return;
 
   bad:
-   VG_(fmsg_bad_option)(opt, "");
+   VG_(fmsg_bad_option)(opt, "Bad argument '%s'\n", optval);
 
   overflow:
    VG_(fmsg_bad_option)(opt,
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index ee83a22..a5fc5db 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -542,9 +542,12 @@
       else if VG_INT_CLO (arg, "--vgdb-poll",      VG_(clo_vgdb_poll)) {}
       else if VG_INT_CLO (arg, "--vgdb-error",     VG_(clo_vgdb_error)) {}
       else if VG_STR_CLO (arg, "--vgdb-stop-at", tmp_str) {
-         if (!VG_(parse_enum_set)("startup,exit,valgrindabexit", tmp_str,
+         const HChar event_set[] = "startup,exit,valgrindabexit";
+         if (!VG_(parse_enum_set)(event_set, tmp_str,
                                   &VG_(clo_vgdb_stop_at)))
-            VG_(fmsg_bad_option)(arg, "");
+            VG_(fmsg_bad_option)(arg,
+               "Bad event set '%s', should be a list containing '%s'\n",
+               tmp_str, event_set);
       }
       else if VG_STR_CLO (arg, "--vgdb-prefix",    VG_(clo_vgdb_prefix)) {
          VG_(arg_vgdb_prefix) = arg;
@@ -573,8 +576,8 @@
          else if (VG_(strcmp)(tmp_str, "no") == 0)
             VG_(clo_fair_sched) = disable_fair_sched;
          else
-            VG_(fmsg_bad_option)(arg, "");
-
+            VG_(fmsg_bad_option)(arg,
+               "Bad argument, should be 'yes', 'try' or 'no'\n");
       }
       else if VG_BOOL_CLO(arg, "--trace-sched",      VG_(clo_trace_sched)) {}
       else if VG_BOOL_CLO(arg, "--trace-signals",    VG_(clo_trace_signals)) {}
@@ -898,7 +901,8 @@
          chaos.  No big deal; dump_error is a flag for debugging V
          itself. */
       if (VG_(clo_dump_error) > 0) {
-         VG_(fmsg_bad_option)("--xml=yes together with --dump-error", "");
+         VG_(fmsg_bad_option)("--xml=yes",
+            "Cannot be used together with --dump-error");
       }
 
       /* Disable error limits (this might be a bad idea!) */
diff --git a/coregrind/m_options.c b/coregrind/m_options.c
index 7b8b141..de457ec 100644
--- a/coregrind/m_options.c
+++ b/coregrind/m_options.c
@@ -267,13 +267,7 @@
    return out;
 
   bad: {
-   HChar* opt =    // 2:  1 for the '=', 1 for the NUL.
-      VG_(malloc)( "options.efn.3",
-                   VG_(strlen)(option_name) + VG_(strlen)(format) + 2 );
-   VG_(strcpy)(opt, option_name);
-   VG_(strcat)(opt, "=");
-   VG_(strcat)(opt, format);
-   VG_(fmsg_bad_option)(opt, "");
+   VG_(fmsg_bad_option)(option_name, "Bad format '%s'\n", format);
   }
 }
 
diff --git a/include/pub_tool_options.h b/include/pub_tool_options.h
index 2ad1da8..af9eefc 100644
--- a/include/pub_tool_options.h
+++ b/include/pub_tool_options.h
@@ -80,7 +80,8 @@
       Long n = VG_(strtoll10)( val, &s ); \
       (qq_var) = n; \
       /* Check for non-numeralness, or overflow. */ \
-      if ('\0' != s[0] || (qq_var) != n) VG_(fmsg_bad_option)(qq_arg, ""); \
+      if ('\0' != s[0] || (qq_var) != n) VG_(fmsg_bad_option)(qq_arg, \
+                                  "Invalid integer value '%s'\n", val); \
       True; \
      }) \
     )
@@ -98,7 +99,8 @@
       /* for all the other macros in this file. */ \
       /* Check for non-numeralness, or overflow. */ \
       /* Nb: it will overflow if qq_var is unsigned and qq_val is negative! */ \
-      if ('\0' != s[0] || (qq_var) != n) VG_(fmsg_bad_option)(qq_arg, ""); \
+      if ('\0' != s[0] || (qq_var) != n) VG_(fmsg_bad_option)(qq_arg, \
+                                  "Invalid integer value '%s'\n", val); \
       /* Check bounds. */ \
       if ((qq_var) < (qq_lo) || (qq_var) > (qq_hi)) { \
          VG_(fmsg_bad_option)(qq_arg, \
@@ -128,7 +130,8 @@
       double n = VG_(strtod)( val, &s ); \
       (qq_var) = n; \
       /* Check for non-numeralness */ \
-      if ('\0' != s[0]) VG_(fmsg_bad_option)(qq_arg, ""); \
+      if ('\0' != s[0]) VG_(fmsg_bad_option)(qq_arg, \
+                            "Invalid double (decimal) value '%s'\n"); \
       True; \
      }) \
     )
diff --git a/massif/ms_main.c b/massif/ms_main.c
index d6a0d17..a6a3720 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -2483,8 +2483,8 @@
    // Check options.
    if (clo_pages_as_heap) {
       if (clo_stacks) {
-         VG_(fmsg_bad_option)(
-            "--pages-as-heap=yes together with --stacks=yes", "");
+         VG_(fmsg_bad_option)("--pages-as-heap=yes",
+            "Cannot be used together with --stacks=yes");
       }
    }
    if (!clo_heap) {