From 3a803036f719b048cb22630c530dbc012f7f53f9 Mon Sep 17 00:00:00 2001 From: Philippe Waroquiers Date: Wed, 21 Aug 2019 14:33:39 +0200 Subject: [PATCH] Allow the user to change a set of command line options during execution. This patch changes the option parsing framework to allow a set of core or tool (currently only memcheck) options to be changed dynamically. Here is a summary of the new functionality (extracted from NEWS): * It is now possible to dynamically change the value of many command line options while your program (or its children) are running under Valgrind. To have the list of dynamically changeable options, run valgrind --help-dyn-options You can change the options from the shell by using vgdb to launch the monitor command "v.clo ...". The same monitor command can be used from a gdb connected to the valgrind gdbserver. Your program can also change the dynamically changeable options using the client request VALGRIND_CLO_CHANGE(option). Here is a brief description of the code changes. * the command line options parsing macros are now checking a 'parsing' mode to decide if the given option must be handled or not. (more about the parsing mode below). * the 'main' command option parsing code has been split in a function 'process_option' that can be called now by: - early_process_cmd_line_options (looping over args, calling process_option in mode "Early") - main_process_cmd_line_options (looping over args, calling process_option in mode "Processing") - the new function VG_(process_dynamic_option) called from gdbserver or from VALGRIND_CLO_CHANGE (calling process_option in mode "Dynamic" or "Help") * So, now, during startup, process_option is called twice for each arg: - once during Early phase - once during normal Processing Then process_option can then be called again during execution. So, the parsing mode is defined so that the option parsing code behaves differently (e.g. allows or not to handle the option) depending on the mode. // Command line option parsing happens in the following modes: // cloE : Early processing, used by coregrind m_main.c to parse the // command line options that must be handled early on. // cloP : Processing, used by coregrind and tools during startup, when // doing command line options Processing. // clodD : Dynamic, used to dynamically change options after startup. // A subset of the command line options can be changed dynamically // after startup. // cloH : Help, special mode to produce the list of dynamically changeable // options for --help-dyn-options. typedef enum { cloE = 1, cloP = 2, cloD = 4, cloH = 8 } Clo_Mode; The option parsing macros in pub_tool_options.h have now all a new variant *_CLOM with the mode(s) in which the given option is accepted. The old variant is kept and calls the new variant with mode cloP. The function VG_(check_clom) in the macro compares the current mode with the modes allowed for the option, and returns True if qq_arg should be further processed. For example: // String argument, eg. --foo=yes or --foo=no (VG_(check_clom) \ (qq_mode, qq_arg, qq_option, \ VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) && \ ({const HChar* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ if VG_STREQ(val, "yes") (qq_var) = True; \ else if VG_STREQ(val, "no") (qq_var) = False; \ else VG_(fmsg_bad_option)(qq_arg, "Invalid boolean value '%s'" \ " (should be 'yes' or 'no')\n", val); \ True; })) VG_BOOL_CLOM(cloP, qq_arg, qq_option, qq_var) To make an option dynamically excutable, it is typically enough to replace VG_BOOL_CLO(...) by VG_BOOL_CLOM(cloPD, ...) For example: - else if VG_BOOL_CLO(arg, "--show-possibly-lost", tmp_show) { + else if VG_BOOL_CLOM(cloPD, arg, "--show-possibly-lost", tmp_show) { cloPD means the option value is set/changed during the main command Processing (P) and Dynamically during execution (D). Note that the 'body/further processing' of a command is only executed when the option is recognised and the current parsing mode is ok for this option. --- NEWS | 15 + coregrind/m_errormgr.c | 13 +- coregrind/m_gdbserver/m_gdbserver.c | 8 +- coregrind/m_gdbserver/server.c | 145 +-- coregrind/m_libcprint.c | 29 +- coregrind/m_main.c | 1192 ++++++++++---------- coregrind/m_options.c | 75 ++ coregrind/m_scheduler/scheduler.c | 9 +- coregrind/m_signals.c | 2 +- coregrind/pub_core_errormgr.h | 4 + coregrind/pub_core_libcprint.h | 4 +- coregrind/pub_core_options.h | 3 + docs/xml/manual-core-adv.xml | 17 + docs/xml/manual-core.xml | 68 ++ exp-sgcheck/pc_common.c | 3 + gdbserver_tests/mchelp.stdoutB.exp | 4 + gdbserver_tests/mssnapshot.stderrB.exp | 2 + helgrind/hg_main.c | 2 +- include/pub_tool_gdbserver.h | 10 - include/pub_tool_libcprint.h | 4 +- include/pub_tool_options.h | 315 ++++-- include/valgrind.h | 12 + memcheck/mc_main.c | 120 +- memcheck/tests/Makefile.am | 1 + memcheck/tests/nanoleak_dynsupp.stderr.exp | 0 memcheck/tests/nanoleak_dynsupp.vgtest | 2 + memcheck/tests/nanoleak_supp.c | 11 +- none/tests/cmdline1.stdout.exp | 1 + none/tests/cmdline2.stdout.exp | 1 + 29 files changed, 1225 insertions(+), 847 deletions(-) create mode 100644 memcheck/tests/nanoleak_dynsupp.stderr.exp create mode 100644 memcheck/tests/nanoleak_dynsupp.vgtest diff --git a/NEWS b/NEWS index e4fdd9499a..07624d4be2 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,18 @@ support for X86/macOS 10.13 and AMD64/macOS 10.13. * ==================== CORE CHANGES =================== +* It is now possible to dynamically change the value of many command + line options while your program (or its children) are running under + Valgrind. + To have the list of dynamically changeable options, run + "valgrind --help-dyn-options". + You can change the options from the shell by using vgdb to launch + the monitor command "v.clo ...". + The same monitor command can be used from a gdb connected + to the valgrind gdbserver. + Your program can also change the dynamically changeable options using + the client request VALGRIND_CLO_CHANGE(option). + * ==================== TOOL CHANGES ==================== * DHAT: @@ -25,6 +37,9 @@ support for X86/macOS 10.13 and AMD64/macOS 10.13. * Memcheck: + - Several memcheck options are now dynamically changeable. + Use valgrind --help-dyn-options to list them. + * ==================== OTHER CHANGES ==================== * New and modified GDB server monitor features: diff --git a/coregrind/m_errormgr.c b/coregrind/m_errormgr.c index 8613f650f8..52505ba5b2 100644 --- a/coregrind/m_errormgr.c +++ b/coregrind/m_errormgr.c @@ -74,6 +74,7 @@ static Error* errors = NULL; suppressions file. Note that the list gets rearranged as a result of the searches done by is_suppressible_error(). */ static Supp* suppressions = NULL; +static Bool load_suppressions_called = False; /* Running count of unsuppressed errors detected. */ static UInt n_errs_found = 0; @@ -524,7 +525,7 @@ void do_actions_on_error(const Error* err, Bool allow_db_attach) /* if user wants to debug from a certain error nr, then wait for gdb/vgdb */ if (VG_(clo_vgdb) != Vg_VgdbNo && allow_db_attach - && VG_(dyn_vgdb_error) <= n_errs_shown) { + && VG_(clo_vgdb_error) <= n_errs_shown) { VG_(umsg)("(action on error) vgdb me ... \n"); VG_(gdbserver)( err->tid ); VG_(umsg)("Continuing ...\n"); @@ -1470,7 +1471,7 @@ static void load_one_suppressions_file ( Int clo_suppressions_i ) VG_(umsg)("FATAL: in suppressions file \"%s\" near line %d:\n", filename, lineno ); VG_(umsg)(" %s\n", err_str ); - + VG_(close)(fd); VG_(umsg)("exiting now.\n"); VG_(exit)(1); @@ -1478,11 +1479,19 @@ static void load_one_suppressions_file ( Int clo_suppressions_i ) # undef BOMB } +void VG_(add_suppression_file)(const HChar *filename) +{ + HChar *f = VG_(strdup)("errormgr.addsup", filename); + VG_(addToXA)(VG_(clo_suppressions), &f); + if (load_suppressions_called) + load_one_suppressions_file( VG_(sizeXA)(VG_(clo_suppressions)) - 1 ); +} void VG_(load_suppressions) ( void ) { Int i; suppressions = NULL; + load_suppressions_called = True; for (i = 0; i < VG_(sizeXA)(VG_(clo_suppressions)); i++) { if (VG_(clo_verbosity) > 1) { VG_(dmsg)("Reading suppressions file: %s\n", diff --git a/coregrind/m_gdbserver/m_gdbserver.c b/coregrind/m_gdbserver/m_gdbserver.c index 49e8ca2ef1..e0238bd072 100644 --- a/coregrind/m_gdbserver/m_gdbserver.c +++ b/coregrind/m_gdbserver/m_gdbserver.c @@ -48,8 +48,6 @@ #include "server.h" -Int VG_(dyn_vgdb_error); - /* forward declarations */ VG_REGPARM(1) void VG_(helperc_CallDebugger) ( HWord iaddr ); @@ -601,9 +599,9 @@ Bool VG_(gdbserver_stop_at) (VgdbStopAt stopat) void VG_(gdbserver_prerun_action) (ThreadId tid) { - // Using VG_(dyn_vgdb_error) allows the user to control if gdbserver + // Using VG_(clo_vgdb_error) allows the user to control if gdbserver // stops after a fork. - if (VG_(dyn_vgdb_error) == 0 + if (VG_(clo_vgdb_error) == 0 || VgdbStopAtiS(VgdbStopAt_Startup, VG_(clo_vgdb_stop_at))) { /* The below call allows gdb to attach at startup before the first guest instruction is executed. */ @@ -1570,6 +1568,6 @@ void VG_(gdbserver_status_output)(void) nr_gdbserved_addresses, nr_watchpoints, - VG_(dyn_vgdb_error), + VG_(clo_vgdb_error), hostvisibility ? "yes" : "no"); } diff --git a/coregrind/m_gdbserver/server.c b/coregrind/m_gdbserver/server.c index d11584c1b5..a2cb2b2971 100644 --- a/coregrind/m_gdbserver/server.c +++ b/coregrind/m_gdbserver/server.c @@ -154,7 +154,7 @@ void VG_(print_all_stats) (Bool memory_stats, Bool tool_stats) { if (memory_stats) { VG_(message)(Vg_DebugMsg, "\n"); - VG_(message)(Vg_DebugMsg, + VG_(message)(Vg_DebugMsg, "------ Valgrind's internal memory use stats follow ------\n" ); VG_(sanity_check_malloc_all)(); VG_(message) @@ -181,7 +181,7 @@ void VG_(print_all_stats) (Bool memory_stats, Bool tool_stats) If command is recognised, return 1 else return 0. Note that in case of ambiguous command, 1 is returned. - *sink_wanted_at_return is modified if one of the commands + *sink_wanted_at_return is modified if one of the commands 'v.set *_output' is handled. */ static @@ -205,12 +205,12 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) starts with the same 3 first letters as an already existing command. This ensures a shorter abbreviation for the user. */ switch (VG_(keyword_id) ("help v.set v.info v.wait v.kill v.translate" - " v.do", + " v.do v.clo", wcmd, kwd_report_duplicated_matches)) { case -2: ret = 1; break; - case -1: + case -1: break; case 0: /* help */ ret = 1; @@ -236,6 +236,8 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) " v.info n_errs_found [msg] : show the nr of errors found so far and the given msg\n" " v.info open_fds : show open file descriptors (only if --track-fds=yes)\n" " v.kill : kill the Valgrind process\n" +" v.clo ... : changes one or more dynamic command line options\n" +" with no clo_option, show the dynamically changeable options.\n" " v.set gdb_output : set valgrind output to gdb\n" " v.set log_output : set valgrind output to log\n" " v.set mixed_output : set valgrind output to log, interactive output to gdb\n" @@ -262,12 +264,12 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) case 1: /* v.set */ ret = 1; wcmd = strtok_r (NULL, " ", &ssaveptr); - switch (kwdid = VG_(keyword_id) + switch (kwdid = VG_(keyword_id) ("vgdb-error debuglog merge-recursive-frames" " gdb_output log_output mixed_output hostvisibility", wcmd, kwd_report_all)) { case -2: - case -1: + case -1: break; case 0: /* vgdb-error */ case 1: /* debuglog */ @@ -285,8 +287,8 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) VG_(gdb_printf) ("missing or malformed integer value\n"); } else if (kwdid == 0) { VG_(printf) ("vgdb-error value changed from %d to %d\n", - VG_(dyn_vgdb_error), int_value); - VG_(dyn_vgdb_error) = int_value; + VG_(clo_vgdb_error), int_value); + VG_(clo_vgdb_error) = int_value; } else if (kwdid == 1) { VG_(printf) ("debuglog value changed from %d to %d\n", VG_(debugLog_getLevel)(), int_value); @@ -323,7 +325,7 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) switch (VG_(keyword_id) ("yes no", wcmd, kwd_report_all)) { case -2: case -1: break; - case 0: + case 0: hostvisibility = True; break; case 1: @@ -335,7 +337,7 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) hostvisibility = True; } if (hostvisibility) { - const DebugInfo *tooldi + const DebugInfo *tooldi = VG_(find_DebugInfo) (cur_ep, (Addr)handle_gdb_valgrind_command); /* Normally, we should always find the tooldi. In case we do not, suggest a 'likely somewhat working' address: */ @@ -346,11 +348,11 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) = tooldi ? VG_(am_find_nsegment) (VG_(DebugInfo_get_text_avma) (tooldi)) : NULL; - VG_(gdb_printf) + VG_(gdb_printf) ("Enabled access to Valgrind memory/status by GDB\n" "If not yet done, tell GDB which valgrind file(s) to use, " "typically:\n" - "add-symbol-file %s %p\n", + "add-symbol-file %s %p\n", toolseg ? VG_(am_get_filename)(toolseg) : "
e.g.", (void*)tool_text_start); @@ -365,12 +367,12 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) case 2: /* v.info */ { ret = 1; wcmd = strtok_r (NULL, " ", &ssaveptr); - switch (kwdid = VG_(keyword_id) + switch (kwdid = VG_(keyword_id) ("all_errors n_errs_found last_error gdbserver_status memory" " scheduler stats open_fds exectxt location unwind", wcmd, kwd_report_all)) { case -2: - case -1: + case -1: break; case 0: // all_errors // A verbosity of minimum 2 is needed to show the errors. @@ -380,7 +382,7 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) VG_(printf) ("n_errs_found %u n_errs_shown %u (vgdb-error %d) %s\n", VG_(get_n_errs_found) (), VG_(get_n_errs_shown) (), - VG_(dyn_vgdb_error), + VG_(clo_vgdb_error), wordn (mon, 3)); break; case 2: // last_error @@ -400,7 +402,7 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) switch (VG_(keyword_id) ("aspacemgr", wcmd, kwd_report_all)) { case -2: case -1: break; - case 0: + case 0: VG_(am_show_nsegments) (0, "gdbserver v.info memory aspacemgr"); break; default: vg_assert (0); @@ -435,17 +437,17 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) break; case 9: { /* location */ /* Note: we prefer 'v.info location' and not 'v.info address' as - v.info address is inconsistent with the GDB (native) + v.info address is inconsistent with the GDB (native) command 'info address' which gives the address for a symbol. GDB equivalent command of 'v.info location' is 'info symbol'. */ Addr address; SizeT dummy_sz = 0x1234; - if (VG_(strtok_get_address_and_size) (&address, + if (VG_(strtok_get_address_and_size) (&address, &dummy_sz, &ssaveptr)) { // If tool provides location information, use that. if (VG_(needs).info_location) { VG_TDICT_CALL(tool_info_location, cur_ep, address); - } + } // If tool does not provide location info, use the common one. // Also use the common to compare with tool when debug log is set. if (!VG_(needs).info_location || VG_(debugLog_getLevel)() > 0 ) { @@ -462,7 +464,7 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) case 10: { /* unwind */ Addr address; SizeT sz = 1; - if (VG_(strtok_get_address_and_size) (&address, + if (VG_(strtok_get_address_and_size) (&address, &sz, &ssaveptr)) { VG_(ppUnwindInfo) (address, address + sz - 1); } @@ -491,7 +493,7 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) case 5: { /* v.translate */ Addr address; SizeT verbosity = 0x20; - + ret = 1; if (VG_(strtok_get_address_and_size) (&address, &verbosity, &ssaveptr)) { @@ -503,7 +505,7 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) int vex_verbosity = verbosity & 0xff; VG_(log_output_sink).fd = initial_valgrind_sink.fd; if ((verbosity & 0x100) && !single_stepping_on_entry) { - valgrind_set_single_stepping(True); + valgrind_set_single_stepping(True); // to force gdbserver instrumentation. } # if defined(VGA_arm) @@ -514,7 +516,7 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/, address, - /*debugging*/True, + /*debugging*/True, (Int) vex_verbosity, /*bbs_done*/0, /*allow redir?*/True); @@ -547,6 +549,19 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return) } break; + case 7: /* v.clo */ + ret = 0; + for (wcmd = VG_(strtok_r)(NULL, " ", &ssaveptr); + wcmd != NULL; + wcmd = VG_(strtok_r)(NULL, " ", &ssaveptr)) { + ret++; + VG_(process_dynamic_option) (cloD, wcmd); + } + if (ret == 0) + VG_(list_dynamic_options) (); + ret = 1; + break; + default: vg_assert (0); } @@ -591,16 +606,16 @@ int handle_gdb_monitor_command (char *mon) if (VG_(needs).client_requests) { /* If the tool reports an error when handling a monitor command, we need to avoid calling gdbserver during this command - handling. So, we temporarily set VG_(dyn_vgdb_error) to + handling. So, we temporarily set VG_(clo_vgdb_error) to a huge value to ensure m_errormgr.c does not call gdbserver. */ - Int save_dyn_vgdb_error = VG_(dyn_vgdb_error); + Int save_clo_vgdb_error = VG_(clo_vgdb_error); UWord arg[2]; - VG_(dyn_vgdb_error) = 999999999; + VG_(clo_vgdb_error) = 999999999; arg[0] = (UWord) VG_USERREQ__GDB_MONITOR_COMMAND; arg[1] = (UWord) mon; VG_TDICT_CALL(tool_handle_client_request, VG_(running_tid), arg, &tool_ret); - VG_(dyn_vgdb_error) = save_dyn_vgdb_error; + VG_(clo_vgdb_error) = save_clo_vgdb_error; } VG_(message_flush) (); @@ -679,7 +694,7 @@ void handle_set (char *arg_own_buf, int *new_packet_len_p) CORE_ADDR sig; for (i = 0; i < TARGET_SIGNAL_LAST; i++) pass_signals[i] = 0; - + from = arg_own_buf + 13; while (from < end) { to = strchr(from, ';'); @@ -733,7 +748,7 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) CORE_ADDR lm; CORE_ADDR offset; struct thread_info *ti; - + from = arg_own_buf + 12; to = strchr(from, ','); *to = 0; @@ -744,7 +759,7 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) from = to + 1; to = end; decode_address (&lm, from, to - from); - dlog(2, "qGetTLSAddr thread %lu offset %p lm %p\n", + dlog(2, "qGetTLSAddr thread %lu offset %p lm %p\n", gdb_id, (void*)offset, (void*)lm); ti = gdb_id_to_thread (gdb_id); @@ -763,25 +778,25 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) return; } } - + /* qRcmd, monitor command handling. */ if (strncmp ("qRcmd,", arg_own_buf, 6) == 0) { char *p = arg_own_buf + 6; int cmdlen = strlen(p)/2; char cmd[cmdlen+1]; - + if (unhexify (cmd, p, cmdlen) != cmdlen) { write_enn (arg_own_buf); return; } cmd[cmdlen] = '\0'; - + if (handle_gdb_monitor_command (cmd)) { write_ok (arg_own_buf); return; } else { /* cmd not recognised */ - VG_(gdb_printf) + VG_(gdb_printf) ("command '%s' not recognised\n" "In gdb, try 'monitor help'\n" "In a shell, try 'vgdb help'\n", @@ -796,7 +811,7 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) unsigned long gdb_id; struct thread_info *ti; ThreadState *tst; - + gdb_id = strtoul (&arg_own_buf[17], NULL, 16); ti = gdb_id_to_thread (gdb_id); if (ti != NULL) { @@ -812,12 +827,12 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) char status[len]; if (tst->thread_name) { VG_(snprintf) (status, sizeof(status), "tid %u %s %s", - tst->tid, + tst->tid, VG_(name_of_ThreadStatus)(tst->status), tst->thread_name); } else { VG_(snprintf) (status, sizeof(status), "tid %u %s", - tst->tid, + tst->tid, VG_(name_of_ThreadStatus)(tst->status)); } hexify (arg_own_buf, status, strlen(status)); @@ -849,7 +864,7 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) if (strcmp ("qfThreadInfo", arg_own_buf) == 0) { thread_ptr = all_threads.head; - VG_(sprintf) (arg_own_buf, "m%x", + VG_(sprintf) (arg_own_buf, "m%x", thread_to_gdb_id ((struct thread_info *)thread_ptr)); thread_ptr = thread_ptr->next; return; @@ -857,7 +872,7 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) if (strcmp ("qsThreadInfo", arg_own_buf) == 0) { if (thread_ptr != NULL) { - VG_(sprintf) (arg_own_buf, "m%x", + VG_(sprintf) (arg_own_buf, "m%x", thread_to_gdb_id ((struct thread_info *)thread_ptr)); thread_ptr = thread_ptr->next; return; @@ -881,7 +896,7 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) strcpy (arg_own_buf, "E00"); return; } - + if (strcmp (annex, "target.xml") == 0) { annex = valgrind_target_xml(VG_(clo_vgdb_shadow_registers)); if (annex != NULL && VG_(clo_vgdb_shadow_registers)) { @@ -912,7 +927,7 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) return; } doc_len = stat_doc.size; - + if (len > PBUFSIZ - POVERHSIZ) len = PBUFSIZ - POVERHSIZ; @@ -978,9 +993,9 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) *new_packet_len_p = write_qxfer_response (arg_own_buf, data, len, 1); else *new_packet_len_p = write_qxfer_response (arg_own_buf, data, n, 0); - + free (data); - + return; } @@ -998,14 +1013,14 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) strcpy (arg_own_buf, "E00"); return; } - + /* Reject any annex with invalid/unexpected pid */ if (strlen(annex) > 0) pid = strtoul (annex, NULL, 16); else pid = 0; if ((int)pid != VG_(getpid)() && pid != 0) { - VG_(sprintf) (arg_own_buf, + VG_(sprintf) (arg_own_buf, "E.Valgrind gdbserver pid is %d." " Cannot give info for pid %d", VG_(getpid)(), (int) pid); @@ -1017,7 +1032,7 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) data = malloc (len); if (!VG_(resolve_filename)(VG_(cl_exec_fd), &name)) { - VG_(sprintf) (arg_own_buf, + VG_(sprintf) (arg_own_buf, "E.Valgrind gdbserver could not" " resolve pid %d exec filename.", VG_(getpid)()); @@ -1037,9 +1052,9 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) *new_packet_len_p = write_qxfer_response (arg_own_buf, data, len, 1); else *new_packet_len_p = write_qxfer_response (arg_own_buf, data, n, 0); - + free (data); - + return; } @@ -1056,7 +1071,7 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) strcpy (arg_own_buf, "E00"); return; } - + if (len > PBUFSIZ - POVERHSIZ) len = PBUFSIZ - POVERHSIZ; @@ -1070,14 +1085,14 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) if (n < 0) write_enn (arg_own_buf); else if (n > len) - *new_packet_len_p = write_qxfer_response (arg_own_buf, + *new_packet_len_p = write_qxfer_response (arg_own_buf, (unsigned char *)&info, len, 1); else - *new_packet_len_p = write_qxfer_response (arg_own_buf, + *new_packet_len_p = write_qxfer_response (arg_own_buf, (unsigned char *)&info, n, 0); - + return; } @@ -1099,7 +1114,7 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) /* if a new gdb connects to us, we have to reset the register set to the normal register sets to allow this new gdb to decide to use or not the shadow registers. - + Note that the reset is only done for gdb that are sending qSupported packets. If a user first connected with a recent gdb using shadow registers and then with a very old gdb @@ -1197,7 +1212,7 @@ void server_main (void) unsigned char sig; int packet_len; int new_packet_len = -1; - + if (resume_reply_packet_needed) { /* Send the resume reply to reply to last GDB resume request. */ @@ -1255,7 +1270,7 @@ void server_main (void) case 'H': if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's') { unsigned long gdb_id, thread_id; - + gdb_id = strtoul (&own_buf[2], NULL, 16); thread_id = gdb_id_to_thread_id (gdb_id); if (thread_id == 0) { @@ -1271,7 +1286,7 @@ void server_main (void) } else if (own_buf[1] == 's') { step_thread = thread_id; } - + write_ok (own_buf); } else { /* Silently ignore it so that gdb can extend the protocol @@ -1310,7 +1325,7 @@ void server_main (void) reply is shown to the user. So, we do an error msg which both is accepted by gdb as an error msg and is readable by the user. */ - VG_(sprintf) + VG_(sprintf) (own_buf, "E.\n" "ERROR changing register %s regno %d\n" @@ -1323,7 +1338,7 @@ void server_main (void) if (VG_(clo_verbosity) > 1) VG_(umsg) ("%s\n", own_buf); } - break; + break; } case 'm': decode_m_packet (&own_buf[1], &mem_addr, &len); @@ -1379,13 +1394,13 @@ void server_main (void) CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16); int zlen = strtol (lenptr + 1, &dataptr, 16); char type = own_buf[1]; - + if (type < '0' || type > '4') { /* Watchpoint command type unrecognized. */ own_buf[0] = '\0'; } else { int res; - + res = valgrind_insert_watchpoint (type, addr, zlen); if (res == 0) write_ok (own_buf); @@ -1403,13 +1418,13 @@ void server_main (void) CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16); int zlen = strtol (lenptr + 1, &dataptr, 16); char type = own_buf[1]; - + if (type < '0' || type > '4') { /* Watchpoint command type unrecognized. */ own_buf[0] = '\0'; } else { int res; - + res = valgrind_remove_watchpoint (type, addr, zlen); if (res == 0) write_ok (own_buf); @@ -1426,7 +1441,7 @@ void server_main (void) break; case 'T': { unsigned long gdb_id, thread_id; - + gdb_id = strtoul (&own_buf[1], NULL, 16); thread_id = gdb_id_to_thread_id (gdb_id); if (thread_id == 0) { @@ -1464,7 +1479,7 @@ void server_main (void) putpkt_binary (own_buf, new_packet_len); else putpkt (own_buf); - + if (status == 'W') VG_(umsg) ("\nChild exited with status %d\n", zignal); if (status == 'X') @@ -1486,7 +1501,7 @@ void server_main (void) VG_(umsg) ("Remote side has terminated connection. " "GDBserver will reopen the connection.\n"); remote_finish (reset_after_error); - remote_open (VG_(clo_vgdb_prefix)); + remote_open (VG_(clo_vgdb_prefix)); myresume (0, 0); resume_reply_packet_needed = False; return; diff --git a/coregrind/m_libcprint.c b/coregrind/m_libcprint.c index fb08005cb6..022209a12b 100644 --- a/coregrind/m_libcprint.c +++ b/coregrind/m_libcprint.c @@ -1102,20 +1102,31 @@ void VG_(fmsg_bad_option) ( const HChar* opt, const HChar* format, ... ) { va_list vargs; va_start(vargs,format); - revert_to_stderr(); - VG_(message) (Vg_FailMsg, "Bad option: %s\n", opt); - VG_(vmessage)(Vg_FailMsg, format, vargs ); - VG_(message) (Vg_FailMsg, "Use --help for more information or consult the user manual.\n"); + Bool fatal = VG_(Clo_Mode)() & cloEP; + VgMsgKind mkind = fatal ? Vg_FailMsg : Vg_UserMsg; + + if (fatal) + revert_to_stderr(); + VG_(message) (mkind, "Bad option: %s\n", opt); + VG_(vmessage)(mkind, format, vargs ); + VG_(message) (mkind, "Use --help for more information or consult the user manual.\n"); va_end(vargs); - VG_(exit)(1); + if (fatal) + VG_(exit)(1); } void VG_(fmsg_unknown_option) ( const HChar* opt) { - revert_to_stderr(); - VG_(message) (Vg_FailMsg, "Unknown option: %s\n", opt); - VG_(message) (Vg_FailMsg, "Use --help for more information or consult the user manual.\n"); - VG_(exit)(1); + Bool fatal = VG_(Clo_Mode)() & cloEP; + VgMsgKind mkind = fatal ? Vg_FailMsg : Vg_UserMsg; + + if (fatal) + revert_to_stderr(); + + VG_(message) (mkind, "Unknown option: %s\n", opt); + VG_(message) (mkind, "Use --help for more information or consult the user manual.\n"); + if (fatal) + VG_(exit)(1); } UInt VG_(umsg) ( const HChar* format, ... ) diff --git a/coregrind/m_main.c b/coregrind/m_main.c index 0a07c06608..3d33dc76c4 100644 --- a/coregrind/m_main.c +++ b/coregrind/m_main.c @@ -7,7 +7,7 @@ This file is part of Valgrind, a dynamic binary instrumentation framework. - Copyright (C) 2000-2017 Julian Seward + Copyright (C) 2000-2017 Julian Seward jseward@acm.org This program is free software; you can redistribute it and/or @@ -66,7 +66,7 @@ #include "pub_core_inner.h" #if defined(ENABLE_INNER_CLIENT_REQUEST) #include "pub_core_clreq.h" -#endif +#endif /*====================================================================*/ @@ -75,13 +75,14 @@ // See pub_{core,tool}_options.h for explanations of all these. -static void usage_NORETURN ( Bool debug_help ) +// need_help: 0 = no, 1 = --help-dyn-options, 2 = --help 3 = --help-debug +static void usage_NORETURN ( int need_help ) { - /* 'usage1' contains a %s + /* 'usage1' contains a %s - for the name of the GDB executable - for the name of vgdb's path prefix which must be supplied when they are VG_(printf)'d. */ - const HChar usage1[] = + const HChar usage1[] = "usage: valgrind [options] prog-and-args\n" "\n" " tool-selection option, with default in [ ]:\n" @@ -90,6 +91,7 @@ static void usage_NORETURN ( Bool debug_help ) " basic user options for all Valgrind tools, with defaults in [ ]:\n" " -h --help show this message\n" " --help-debug show this message, plus debugging options\n" +" --help-dyn-options show the dynamically changeable options\n" " --version show version\n" " -q --quiet run silently; only print error msgs\n" " -v --verbose be more verbose -- show misc extra info\n" @@ -210,7 +212,7 @@ static void usage_NORETURN ( Bool debug_help ) " --aspace-minaddr=0xPP avoid mapping memory below 0xPP [guessed]\n" " --valgrind-stacksize= size of valgrind (host) thread's stack\n" " (in bytes) [" - VG_STRINGIFY(VG_DEFAULT_STACK_ACTIVE_SZB) + VG_STRINGIFY(VG_DEFAULT_STACK_ACTIVE_SZB) "]\n" " --show-emwarns=no|yes show warnings about emulation limits? [no]\n" " --require-text-symbol=:sonamepattern:symbolpattern abort run if the\n" @@ -233,7 +235,7 @@ static void usage_NORETURN ( Bool debug_help ) " handle [%d]\n" "\n"; - const HChar usage2[] = + const HChar usage2[] = "\n" " debugging options for all Valgrind tools:\n" " -d show verbose debugging output\n" @@ -317,6 +319,19 @@ static void usage_NORETURN ( Bool debug_help ) " Bug reports, feedback, admiration, abuse, etc, to: %s.\n" "\n"; + const HChar dyn_usage[] = +"Some command line settings are \"dynamic\", meaning they can be changed\n" +"while Valgrind is running, like this:\n" +" From the shell, using vgdb. Example:\n" +" $ vgdb \"v.clo --trace-children=yes --child-silent-after-fork=no\"\n" +" From a gdb attached to the valgrind gdbserver. Example:\n" +" (gdb) monitor v.clo --trace-children=yes --child-silent-after-fork=no\"\n" +" From your program, using a client request. Example:\n" +" #include \n" +" VALGRIND_CLO_CHANGE(\"--trace-children=yes\");\n" +" VALGRIND_CLO_CHANGE(\"--child-silent-after-fork=no\");\n\n"; + + HChar default_alignment[30]; // large enough HChar default_redzone_size[30]; // large enough @@ -331,46 +346,535 @@ static void usage_NORETURN ( Bool debug_help ) VG_(strcpy)(default_alignment, "not used by this tool"); VG_(strcpy)(default_redzone_size, "not used by this tool"); } - /* 'usage1' a type as described after each arg. */ - VG_(printf)(usage1, - VG_(clo_vgdb_error) /* int */, - default_alignment /* char* */, - default_redzone_size /* char* */, - VG_(clo_vgdb_poll) /* int */, - VG_(vgdb_prefix_default)() /* char* */, - N_SECTORS_DEFAULT /* int */, - MAX_THREADS_DEFAULT /* int */ - ); - if (VG_(details).name) { + if (need_help > 1) + /* 'usage1' a type as described after each arg. */ + VG_(printf)(usage1, + VG_(clo_vgdb_error) /* int */, + default_alignment /* char* */, + default_redzone_size /* char* */, + VG_(clo_vgdb_poll) /* int */, + VG_(vgdb_prefix_default)() /* char* */, + N_SECTORS_DEFAULT /* int */, + MAX_THREADS_DEFAULT /* int */ + ); + if (need_help > 1 && VG_(details).name) { VG_(printf)(" user options for %s:\n", VG_(details).name); if (VG_(needs).command_line_options) VG_TDICT_CALL(tool_print_usage); else VG_(printf)(" (none)\n"); } - if (debug_help) { + if (need_help == 1) { + VG_(printf)(dyn_usage); + VG_(list_dynamic_options) (); + VG_(printf)("valgrind: Use --help for more information.\n"); + } + + if (need_help > 2) { VG_(printf)("%s", usage2); if (VG_(details).name) { VG_(printf)(" debugging options for %s:\n", VG_(details).name); - + if (VG_(needs).command_line_options) VG_TDICT_CALL(tool_print_debug_usage); else VG_(printf)(" (none)\n"); } } - VG_(printf)(usage3, VG_(details).name, VG_(details).copyright_author, - VG_BUGS_TO); + if (need_help > 1) + VG_(printf)(usage3, VG_(details).name, VG_(details).copyright_author, + VG_BUGS_TO); VG_(exit)(0); } +struct process_option_state { + /* Whether the user has asked for --version/--help. */ + Int need_version; + Int need_help; + + /* Whether the user has explicitly provided --sigill-diagnostics + or --show-error-list. + If not explicitly given depends on general verbosity setting. */ + Bool sigill_diag_set; + Bool show_error_list_set; + + /* Log to stderr by default, but usage message goes to stdout. XML + output is initially disabled. */ + VgLogTo log_to; // Where is logging output to be sent? + VgLogTo xml_to; // Where is XML output to be sent? + Int tmp_log_fd; + Int tmp_xml_fd; +}; + +static void process_option (Clo_Mode mode, + HChar *arg, struct process_option_state *pos) +{ + const HChar* tmp_str; // Used in a couple of places. + Int toolname_len = VG_(strlen)(VG_(clo_toolname)); + HChar* colon = arg; + UInt ix = 0; + + /* 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*/ }; + + VG_(set_Clo_Mode) (mode); + + // Look for a colon in the option name. + while (*colon && *colon != ':' && *colon != '=') + colon++; + + // Does it have the form "--toolname:foo"? We have to do it at the start + // in case someone has combined a prefix with a core-specific option, + // eg. "--memcheck:verbose". + if (*colon == ':') { + if (VG_STREQN(2, arg, "--") && + VG_STREQN(toolname_len, arg+2, VG_(clo_toolname)) && + VG_STREQN(1, arg+2+toolname_len, ":")) { + // Prefix matches, convert "--toolname:foo" to "--foo". + // Two things to note: + // - We cannot modify the option in-place. If we did, and then + // a child was spawned with --trace-children=yes, the + // now-non-prefixed option would be passed and could screw up + // the child. + // - We create copies, and never free them. Why? Non-prefixed + // options hang around forever, so tools need not make copies + // of strings within them. We need to have the same behaviour + // for prefixed options. The pointer to the copy will be lost + // once we leave this function (although a tool may keep a + // pointer into it), but the space wasted is insignificant. + // (In bug #142197, the copies were being freed, which caused + // problems for tools that reasonably assumed that arguments + // wouldn't disappear on them.) + if (0) + VG_(printf)("tool-specific arg: %s\n", arg); + arg = VG_(strdup)("main.mpclo.1", arg + toolname_len + 1); + arg[0] = '-'; + arg[1] = '-'; + + } else { + // prefix doesn't match, declare it as recognised and skip this arg + VG_(set_Clo_Recognised) (); + return; + } + } + + if VG_XACT_CLOM(cloE, arg, "--version", pos->need_version, 1) {} + else if (VG_STREQ_CLOM(cloED, arg, "-v") || + VG_STREQ_CLOM(cloED, arg, "--verbose")) + VG_(clo_verbosity)++; + else if (VG_STREQ_CLOM(cloED, arg, "-q") || + VG_STREQ_CLOM(cloED, arg, "--quiet")) + VG_(clo_verbosity)--; + else if VG_XACT_CLOM(cloE, arg, "--help-dyn-options", pos->need_help, 1) {} + else if VG_XACT_CLOM(cloE, arg, "-h", pos->need_help, 2) {} + else if VG_XACT_CLOM(cloE, arg, "--help", pos->need_help, 2) {} + else if VG_XACT_CLOM(cloE, arg, "--help-debug", pos->need_help, 3) {} + + // The tool has already been determined, but we need to know the name + // here. + else if VG_STR_CLOM(cloE, arg, "--tool", VG_(clo_toolname)) {} + + // Set up VG_(clo_max_stackframe) and VG_(clo_main_stacksize). + // These are needed by VG_(ii_create_image), which happens + // before main_process_cmd_line_options(). + else if VG_INT_CLOM(cloE, arg, "--max-stackframe", VG_(clo_max_stackframe)) {} + else if VG_INT_CLOM(cloE, arg, "--main-stacksize", VG_(clo_main_stacksize)) {} + + // Set up VG_(clo_max_threads); needed for VG_(tl_pre_clo_init) + else if VG_INT_CLOM(cloE, arg, "--max-threads", VG_(clo_max_threads)) {} + + // Set up VG_(clo_sim_hints). This is needed a.o. for an inner + // running in an outer, to have "no-inner-prefix" enabled + // as early as possible. + else if VG_USETX_CLOM (cloE, arg, "--sim-hints", + "lax-ioctls,lax-doors,fuse-compatible," + "enable-outer,no-inner-prefix," + "no-nptl-pthread-stackcache,fallback-llsc", + VG_(clo_sim_hints)) {} + + else if VG_STREQN_CLOM(0, 20, arg, "--command-line-only=") {} // m_commandline.c + else if VG_STREQ(arg, "--") {} + else if VG_STREQ_CLOM(cloD, arg, "-d") // pre-early + Dynamic + VG_(debugLog_startup) (VG_(debugLog_getLevel)() + 1, + "dynamic option change"); + else if VG_STREQN_CLOM(0, 15, arg, "--profile-heap=") {} // pre-early + else if VG_STREQN_CLOM(0, 20, arg, "--core-redzone-size=") {} // pre-early + else if VG_STREQN_CLOM(0, 15, arg, "--redzone-size=") {} // pre-early + else if VG_STREQN_CLOM(0, 17, arg, "--aspace-minaddr=") {} // pre-early + + else if VG_BINT_CLOM(cloE, arg, "--valgrind-stacksize", + VG_(clo_valgrind_stacksize), + 2*VKI_PAGE_SIZE, 10*VG_DEFAULT_STACK_ACTIVE_SZB) + VG_(clo_valgrind_stacksize) = VG_PGROUNDUP(VG_(clo_valgrind_stacksize)); + + /* Obsolete options. Report an error and exit */ + else if VG_STREQN(34, arg, "--vex-iropt-precise-memory-exns=no") { + VG_(fmsg_bad_option) + (arg, + "--vex-iropt-precise-memory-exns is obsolete\n" + "Use --vex-iropt-register-updates=unwindregs-at-mem-access instead\n"); + } + else if VG_STREQN(35, arg, "--vex-iropt-precise-memory-exns=yes") { + VG_(fmsg_bad_option) + (arg, + "--vex-iropt-precise-memory-exns is obsolete\n" + "Use --vex-iropt-register-updates=allregs-at-mem-access instead\n" + " (or --vex-iropt-register-updates=allregs-at-each-insn)\n"); + } + + /* These options are new, not yet handled by + early_process_cmd_line_options. */ + else if VG_BOOL_CLO(arg, "--sigill-diagnostics", VG_(clo_sigill_diag)) + pos->sigill_diag_set = True; + + else if VG_BOOL_CLOM(cloPD, arg, "--stats", VG_(clo_stats)) {} + else if VG_BOOL_CLO(arg, "--xml", VG_(clo_xml)) + VG_(debugLog_setXml)(VG_(clo_xml)); + + else if VG_XACT_CLOM(cloPD, arg, "--vgdb=no", VG_(clo_vgdb), Vg_VgdbNo) {} + else if VG_XACT_CLOM(cloPD, arg, "--vgdb=yes", VG_(clo_vgdb), Vg_VgdbYes) {} + else if VG_XACT_CLOM(cloPD, 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_default + = VG_(clo_px_file_backed) + = VexRegUpdAllregsAtEachInsn; + } + else if VG_INT_CLOM (cloPD, arg, "--vgdb-poll", VG_(clo_vgdb_poll)) {} + else if VG_INT_CLOM (cloPD, arg, "--vgdb-error", VG_(clo_vgdb_error)) {} + else if VG_USET_CLOM (cloPD, arg, "--vgdb-stop-at", + "startup,exit,valgrindabexit", + VG_(clo_vgdb_stop_at)) {} + else if VG_STR_CLO (arg, "--vgdb-prefix", VG_(clo_vgdb_prefix)) { + VG_(arg_vgdb_prefix) = arg; + } + else if VG_BOOL_CLO(arg, "--vgdb-shadow-registers", + VG_(clo_vgdb_shadow_registers)) {} + else if VG_BOOL_CLO(arg, "--demangle", VG_(clo_demangle)) {} + else if VG_STR_CLO (arg, "--soname-synonyms",VG_(clo_soname_synonyms)) {} + else if VG_BOOL_CLO(arg, "--error-limit", VG_(clo_error_limit)) {} + else if VG_BOOL_CLO(arg, "--exit-on-first-error", VG_(clo_exit_on_first_error)) {} + else if VG_INT_CLO (arg, "--error-exitcode", VG_(clo_error_exitcode)) {} + else if VG_STR_CLOM (cloPD, arg, "--error-markers", tmp_str) { + Int m; + const HChar *startpos = tmp_str; + const HChar *nextpos; + for (m = 0; + VG_(Clo_Mode)() != cloE + && m < sizeof(VG_(clo_error_markers)) + /sizeof(VG_(clo_error_markers)[0]); + m++) { + /* Release previous value if clo given multiple times. */ + VG_(free)(VG_(clo_error_markers)[m]); + VG_(clo_error_markers)[m] = NULL; + + nextpos = VG_(strchr)(startpos, ','); + if (!nextpos) + nextpos = startpos + VG_(strlen)(startpos); + if (startpos != nextpos) { + VG_(clo_error_markers)[m] + = VG_(malloc)("main.mpclo.2", nextpos - startpos + 1); + VG_(memcpy)(VG_(clo_error_markers)[m], startpos, + nextpos - startpos); + VG_(clo_error_markers)[m][nextpos - startpos] = '\0'; + } + startpos = *nextpos ? nextpos + 1 : nextpos; + } + } + else if VG_BOOL_CLOM(cloPD, arg, "--show-error-list", VG_(clo_show_error_list)) { + pos->show_error_list_set = True; } + else if (VG_STREQ_CLOM(cloPD, arg, "-s")) { + VG_(clo_show_error_list) = True; + pos->show_error_list_set = True; + } + else if VG_BOOL_CLO(arg, "--show-emwarns", VG_(clo_show_emwarns)) {} + + else if VG_BOOL_CLO(arg, "--run-libc-freeres", VG_(clo_run_libc_freeres)) {} + else if VG_BOOL_CLO(arg, "--run-cxx-freeres", VG_(clo_run_cxx_freeres)) {} + else if VG_BOOL_CLOM(cloPD, arg, "--show-below-main", VG_(clo_show_below_main)) {} + else if VG_BOOL_CLO(arg, "--keep-debuginfo", VG_(clo_keep_debuginfo)) {} + else if VG_BOOL_CLOM(cloPD, arg, "--time-stamp", VG_(clo_time_stamp)) {} + else if VG_BOOL_CLO(arg, "--track-fds", VG_(clo_track_fds)) {} + else if VG_BOOL_CLOM(cloPD, arg, "--trace-children", VG_(clo_trace_children)) {} + else if VG_BOOL_CLOM(cloPD, arg, "--child-silent-after-fork", + VG_(clo_child_silent_after_fork)) {} + else if VG_STR_CLO(arg, "--fair-sched", tmp_str) { + if (VG_(Clo_Mode)() != cloP) + ; + else if (VG_(strcmp)(tmp_str, "yes") == 0) + VG_(clo_fair_sched) = enable_fair_sched; + else if (VG_(strcmp)(tmp_str, "try") == 0) + VG_(clo_fair_sched) = try_fair_sched; + else if (VG_(strcmp)(tmp_str, "no") == 0) + VG_(clo_fair_sched) = disable_fair_sched; + else + VG_(fmsg_bad_option)(arg, + "Bad argument, should be 'yes', 'try' or 'no'\n"); + } + else if VG_BOOL_CLOM(cloPD, arg, "--trace-sched", VG_(clo_trace_sched)) {} + else if VG_BOOL_CLOM(cloPD, arg, "--trace-signals", VG_(clo_trace_signals)) {} + else if VG_BOOL_CLOM(cloPD, arg, "--trace-symtab", VG_(clo_trace_symtab)) {} + else if VG_STR_CLO (arg, "--trace-symtab-patt", VG_(clo_trace_symtab_patt)) {} + else if VG_BOOL_CLOM(cloPD, arg, "--trace-cfi", VG_(clo_trace_cfi)) {} + else if VG_XACT_CLOM(cloPD, arg, "--debug-dump=syms", VG_(clo_debug_dump_syms), + True) {} + else if VG_XACT_CLOM(cloPD, arg, "--debug-dump=line", VG_(clo_debug_dump_line), + True) {} + else if VG_XACT_CLOM(cloPD, arg, "--debug-dump=frames", + VG_(clo_debug_dump_frames), True) {} + else if VG_BOOL_CLOM(cloPD, arg, "--trace-redir", VG_(clo_trace_redir)) {} + + else if VG_BOOL_CLOM(cloPD, arg, "--trace-syscalls", VG_(clo_trace_syscalls)) {} + else if VG_BOOL_CLOM(cloE, arg, "--wait-for-gdb", VG_(clo_wait_for_gdb)) { + //-------------------------------------------------------------- + // Allow GDB attach + // p: logging + //-------------------------------------------------------------- + /* Hook to delay things long enough so we can get the pid and + attach GDB in another shell. */ + if (VG_(clo_wait_for_gdb)) { + const int ms = 8000; // milliseconds + VG_(debugLog)(1, "main", "Wait for GDB during %d ms\n", ms); + VG_(printf)("pid=%d, entering delay %d ms loop\n", VG_(getpid)(), ms); + VG_(poll)(NULL, 0, ms); + } + } + + else if VG_BOOL_CLOM(cloPD, arg, "--sym-offsets", VG_(clo_sym_offsets)) {} + else if VG_BINT_CLOM(cloPD, arg, "--progress-interval", + VG_(clo_progress_interval), 0, 3600) {} + else if VG_BOOL_CLO(arg, "--read-inline-info", VG_(clo_read_inline_info)) {} + else if VG_BOOL_CLO(arg, "--read-var-info", VG_(clo_read_var_info)) {} + + else if VG_INT_CLO (arg, "--dump-error", VG_(clo_dump_error)) {} + else if VG_INT_CLO (arg, "--input-fd", VG_(clo_input_fd)) {} + else if VG_INT_CLO (arg, "--sanity-level", VG_(clo_sanity_level)) {} + else if VG_BINT_CLO(arg, "--num-callers", VG_(clo_backtrace_size), 1, + VG_DEEPEST_BACKTRACE) {} + else if VG_BINT_CLO(arg, "--num-transtab-sectors", + VG_(clo_num_transtab_sectors), + MIN_N_SECTORS, MAX_N_SECTORS) {} + else if VG_BINT_CLO(arg, "--avg-transtab-entry-size", + VG_(clo_avg_transtab_entry_size), + 50, 5000) {} + else if VG_BINT_CLOM(cloPD, arg, "--merge-recursive-frames", + VG_(clo_merge_recursive_frames), 0, + VG_DEEPEST_BACKTRACE) {} + + else if VG_XACT_CLO(arg, "--smc-check=none", + VG_(clo_smc_check), Vg_SmcNone) {} + else if VG_XACT_CLO(arg, "--smc-check=stack", + VG_(clo_smc_check), 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_USETX_CLO (arg, "--kernel-variant", + "bproc," + "android-no-hw-tls," + "android-gpu-sgx5xx," + "android-gpu-adreno3xx", + VG_(clo_kernel_variant)) {} + + else if VG_BOOL_CLO(arg, "--dsymutil", VG_(clo_dsymutil)) {} + + else if VG_STR_CLO (arg, "--trace-children-skip", + VG_(clo_trace_children_skip)) {} + else if VG_STR_CLO (arg, "--trace-children-skip-by-arg", + VG_(clo_trace_children_skip_by_arg)) {} + + else if VG_BINT_CLOM(cloPD, arg, "--vex-iropt-verbosity", + VG_(clo_vex_control).iropt_verbosity, 0, 10) {} + else if VG_BINT_CLO(arg, "--vex-iropt-level", + VG_(clo_vex_control).iropt_level, 0, 2) {} + else if VG_BINT_CLO(arg, "--vex-regalloc-version", + VG_(clo_vex_control).regalloc_version, 2, 3) {} + + else if (VG_STRINDEX_CLO(arg, "--vex-iropt-register-updates", + pxStrings, ix) + || 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_BINT_CLO(arg, "--vex-iropt-unroll-thresh", + VG_(clo_vex_control).iropt_unroll_thresh, 0, 400) {} + else if VG_BINT_CLO(arg, "--vex-guest-max-insns", + VG_(clo_vex_control).guest_max_insns, 1, 100) {} + else if VG_BINT_CLO(arg, "--vex-guest-chase-thresh", + VG_(clo_vex_control).guest_chase_thresh, 0, 99) {} + else if VG_BOOL_CLO(arg, "--vex-guest-chase-cond", + VG_(clo_vex_control).guest_chase_cond) {} + + else if VG_INT_CLO(arg, "--log-fd", pos->tmp_log_fd) { + pos->log_to = VgLogTo_Fd; + VG_(clo_log_fname_unexpanded) = NULL; + } + else if VG_INT_CLO(arg, "--xml-fd", pos->tmp_xml_fd) { + pos->xml_to = VgLogTo_Fd; + VG_(clo_xml_fname_unexpanded) = NULL; + } + + else if VG_STR_CLO(arg, "--log-file", VG_(clo_log_fname_unexpanded)) { + pos->log_to = VgLogTo_File; + } + else if VG_STR_CLO(arg, "--xml-file", VG_(clo_xml_fname_unexpanded)) { + pos->xml_to = VgLogTo_File; + } + + else if VG_STR_CLO(arg, "--log-socket", VG_(clo_log_fname_unexpanded)) { + pos->log_to = VgLogTo_Socket; + } + else if VG_STR_CLO(arg, "--xml-socket", VG_(clo_xml_fname_unexpanded)) { + pos->xml_to = VgLogTo_Socket; + } + + else if VG_STR_CLO(arg, "--debuginfo-server", + VG_(clo_debuginfo_server)) {} + + else if VG_BOOL_CLO(arg, "--allow-mismatched-debuginfo", + VG_(clo_allow_mismatched_debuginfo)) {} + + else if VG_STR_CLO(arg, "--xml-user-comment", + VG_(clo_xml_user_comment)) {} + + else if VG_BOOL_CLO(arg, "--default-suppressions", + VG_(clo_default_supp)) {} + + else if VG_STR_CLOM(cloPD, arg, "--suppressions", tmp_str) { + VG_(add_suppression_file)(tmp_str); + } + + else if VG_STR_CLO (arg, "--fullpath-after", tmp_str) { + VG_(addToXA)(VG_(clo_fullpath_after), &tmp_str); + } + + else if VG_STR_CLO (arg, "--extra-debuginfo-path", + VG_(clo_extra_debuginfo_path)) {} + + else if VG_STR_CLO(arg, "--require-text-symbol", tmp_str) { + /* String needs to be of the form C?*C?*, where C is any + character, but is the same both times. Having it in this + form facilitates finding the boundary between the sopatt + and the fnpatt just by looking for the second occurrence + of C, without hardwiring any assumption about what C + is. */ + HChar patt[7]; + Bool ok = True; + ok = tmp_str && VG_(strlen)(tmp_str) > 0; + if (ok) { + patt[0] = patt[3] = tmp_str[0]; + patt[1] = patt[4] = '?'; + patt[2] = patt[5] = '*'; + patt[6] = 0; + ok = VG_(string_match)(patt, tmp_str); + } + if (!ok) { + VG_(fmsg_bad_option)(arg, + "Invalid --require-text-symbol= specification.\n"); + } + VG_(addToXA)(VG_(clo_req_tsyms), &tmp_str); + } + + /* "stuvwxyz" --> stuvwxyz (binary) */ + else if VG_STR_CLOM(cloPD, arg, "--trace-flags", tmp_str) { + Int j; + if (8 != VG_(strlen)(tmp_str)) { + VG_(fmsg_bad_option)(arg, + "--trace-flags argument must have 8 digits\n"); + } + for (j = 0; j < 8; j++) { + if ('0' == tmp_str[j]) { /* do nothing */ } + else if ('1' == tmp_str[j]) VG_(clo_trace_flags) |= (1 << (7-j)); + else { + VG_(fmsg_bad_option)(arg, + "--trace-flags argument can only contain 0s and 1s\n"); + } + } + } + + else if VG_INT_CLOM (cloPD, arg, "--trace-notbelow", VG_(clo_trace_notbelow)) {} + + else if VG_INT_CLOM (cloPD, arg, "--trace-notabove", VG_(clo_trace_notabove)) {} + + /* "stuvwxyz" --> stuvwxyz (binary) */ + else if VG_STR_CLOM(cloPD, arg, "--profile-flags", tmp_str) { + Int j; + if (8 != VG_(strlen)(tmp_str)) { + VG_(fmsg_bad_option)(arg, + "--profile-flags argument must have 8 digits\n"); + } + for (j = 0; j < 8; j++) { + if ('0' == tmp_str[j]) { /* do nothing */ } + else if ('1' == tmp_str[j]) VG_(clo_profyle_flags) |= (1 << (7-j)); + else { + VG_(fmsg_bad_option)(arg, + "--profile-flags argument can only contain 0s and 1s\n"); + } + } + VG_(clo_profyle_sbs) = True; + } + + else if VG_INT_CLO (arg, "--profile-interval", + VG_(clo_profyle_interval)) {} + + else if VG_XACT_CLOM(cloPD, arg, "--gen-suppressions=no", + VG_(clo_gen_suppressions), 0) {} + else if VG_XACT_CLOM(cloPD, arg, "--gen-suppressions=yes", + VG_(clo_gen_suppressions), 1) {} + else if VG_XACT_CLOM(cloPD, arg, "--gen-suppressions=all", + VG_(clo_gen_suppressions), 2) {} + + else if VG_BINT_CLO(arg, "--unw-stack-scan-thresh", + VG_(clo_unw_stack_scan_thresh), 0, 100) {} + else if VG_BINT_CLO(arg, "--unw-stack-scan-frames", + VG_(clo_unw_stack_scan_frames), 0, 32) {} + + else if VG_XACT_CLO(arg, "--resync-filter=no", + VG_(clo_resync_filter), 0) {} + else if VG_XACT_CLO(arg, "--resync-filter=yes", + VG_(clo_resync_filter), 1) {} + else if VG_XACT_CLO(arg, "--resync-filter=verbose", + VG_(clo_resync_filter), 2) {} + + else if ( VG_(Clo_Mode)() != cloE // tool does not have Early options + && !VG_(Clo_Recognised) () + && (! VG_(needs).command_line_options + || ! VG_TDICT_CALL(tool_process_cmd_line_option, arg) )) { + if (VG_(Clo_Mode)() == cloH) + ; + else if (VG_(Clo_Mode)() == cloP && !VG_(Clo_Recognised) ()) + VG_(fmsg_unknown_option)(arg); + else if (VG_(Clo_Mode)() == cloD && !VG_(Clo_Recognised) ()) + VG_(umsg)("Ignoring dynamic change to unrecognised option %s\n", arg); + } +} + +void VG_(process_dynamic_option) (Clo_Mode mode, HChar *value) +{ + process_option (mode, value, NULL); + // This is not supposed to change values in process_option_state, + // so we can give a NULL. +} + /* Peer at previously set up VG_(args_for_valgrind) and do some minimal command line processing that must happen early on: - show the version string, if requested (-v) - - extract any request for help (--help, -h, --help-debug) + - extract any request for help (-h --help, --help-dyn-options, --help-debug) - set VG_(toolname) (--tool=) - set VG_(clo_max_stackframe) (--max-stackframe=) - set VG_(clo_main_stacksize) (--main-stacksize=) @@ -386,7 +890,8 @@ static void early_process_cmd_line_options ( /*OUT*/Int* need_help ) { UInt i; HChar* str; - Int need_version = 0; + struct process_option_state pos + = {0, 0, False, False, VgLogTo_Fd, VgLogTo_Fd, 2, -1}; vg_assert( VG_(args_for_valgrind) ); @@ -395,43 +900,10 @@ static void early_process_cmd_line_options ( /*OUT*/Int* need_help ) str = * (HChar**) VG_(indexXA)( VG_(args_for_valgrind), i ); vg_assert(str); + process_option (cloE, str, &pos); + } - if VG_XACT_CLO(str, "--version", need_version, 1) {} - else if (VG_STREQ(str, "-v") || - VG_STREQ(str, "--verbose")) - VG_(clo_verbosity)++; - else if (VG_STREQ(str, "-q") || - VG_STREQ(str, "--quiet")) - VG_(clo_verbosity)--; - else if VG_XACT_CLO(str, "--help", *need_help, *need_help+1) {} - else if VG_XACT_CLO(str, "-h", *need_help, *need_help+1) {} - - else if VG_XACT_CLO(str, "--help-debug", *need_help, *need_help+2) {} - - // The tool has already been determined, but we need to know the name - // here. - else if VG_STR_CLO(str, "--tool", VG_(clo_toolname)) {} - - // Set up VG_(clo_max_stackframe) and VG_(clo_main_stacksize). - // These are needed by VG_(ii_create_image), which happens - // before main_process_cmd_line_options(). - else if VG_INT_CLO(str, "--max-stackframe", VG_(clo_max_stackframe)) {} - else if VG_INT_CLO(str, "--main-stacksize", VG_(clo_main_stacksize)) {} - - // Set up VG_(clo_max_threads); needed for VG_(tl_pre_clo_init) - else if VG_INT_CLO(str, "--max-threads", VG_(clo_max_threads)) {} - - // Set up VG_(clo_sim_hints). This is needed a.o. for an inner - // running in an outer, to have "no-inner-prefix" enabled - // as early as possible. - else if VG_USETX_CLO (str, "--sim-hints", - "lax-ioctls,lax-doors,fuse-compatible," - "enable-outer,no-inner-prefix," - "no-nptl-pthread-stackcache,fallback-llsc", - VG_(clo_sim_hints)) {} - } - - if (need_version) { + if (pos.need_version) { // Nb: the version string goes to stdout. VG_(log_output_sink).fd = 1; VG_(log_output_sink).type = VgLogTo_Fd; @@ -442,6 +914,8 @@ static void early_process_cmd_line_options ( /*OUT*/Int* need_help ) VG_(exit)(0); } + *need_help = pos.need_help; + /* For convenience */ VG_N_THREADS = VG_(clo_max_threads); @@ -456,25 +930,12 @@ static void early_process_cmd_line_options ( /*OUT*/Int* need_help ) static void main_process_cmd_line_options( void ) { - Int i; - Int toolname_len = VG_(strlen)(VG_(clo_toolname)); - const HChar* tmp_str; // Used in a couple of places. - - /* Whether the user has explicitly provided --sigill-diagnostics - or --show-error-list. - If not explicitly given depends on general verbosity setting. */ - Bool sigill_diag_set = False; - Bool show_error_list_set = False; - - /* Log to stderr by default, but usage message goes to stdout. XML - output is initially disabled. */ - VgLogTo log_to = VgLogTo_Fd; // Where is logging output to be sent? - VgLogTo xml_to = VgLogTo_Fd; // Where is XML output to be sent? - Int tmp_log_fd = 2; - Int tmp_xml_fd = -1; + Int i; + struct process_option_state pos + = {0, 0, False, False, VgLogTo_Fd, VgLogTo_Fd, 2, -1}; /* Check for sane path in ./configure --prefix=... */ - if (VG_LIBDIR[0] != '/') + if (VG_LIBDIR[0] != '/') VG_(err_config_error)("Please use absolute paths in " "./configure --prefix=... or --libdir=...\n"); @@ -487,423 +948,16 @@ void main_process_cmd_line_options( void ) 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 != '=') - colon++; - - // Does it have the form "--toolname:foo"? We have to do it at the start - // in case someone has combined a prefix with a core-specific option, - // eg. "--memcheck:verbose". - if (*colon == ':') { - if (VG_STREQN(2, arg, "--") && - VG_STREQN(toolname_len, arg+2, VG_(clo_toolname)) && - VG_STREQN(1, arg+2+toolname_len, ":")) - { - // Prefix matches, convert "--toolname:foo" to "--foo". - // Two things to note: - // - We cannot modify the option in-place. If we did, and then - // a child was spawned with --trace-children=yes, the - // now-non-prefixed option would be passed and could screw up - // the child. - // - We create copies, and never free them. Why? Non-prefixed - // options hang around forever, so tools need not make copies - // of strings within them. We need to have the same behaviour - // for prefixed options. The pointer to the copy will be lost - // once we leave this function (although a tool may keep a - // pointer into it), but the space wasted is insignificant. - // (In bug #142197, the copies were being freed, which caused - // problems for tools that reasonably assumed that arguments - // wouldn't disappear on them.) - if (0) - VG_(printf)("tool-specific arg: %s\n", arg); - arg = VG_(strdup)("main.mpclo.1", arg + toolname_len + 1); - arg[0] = '-'; - arg[1] = '-'; - - } else { - // prefix doesn't match, skip to next arg - continue; - } - } - - /* Ignore these options - they've already been handled */ - if VG_STREQN( 7, arg, "--tool=") {} - else if VG_STREQN(20, arg, "--command-line-only=") {} - else if VG_STREQ( arg, "--") {} - else if VG_STREQ( arg, "-d") {} - else if VG_STREQ( arg, "-q") {} - else if VG_STREQ( arg, "--quiet") {} - else if VG_STREQ( arg, "-v") {} - else if VG_STREQ( arg, "--verbose") {} - else if VG_STREQN(17, arg, "--max-stackframe=") {} - else if VG_STREQN(17, arg, "--main-stacksize=") {} - else if VG_STREQN(14, arg, "--max-threads=") {} - else if VG_STREQN(12, arg, "--sim-hints=") {} - else if VG_STREQN(15, arg, "--profile-heap=") {} - else if VG_STREQN(20, arg, "--core-redzone-size=") {} - else if VG_STREQN(15, arg, "--redzone-size=") {} - else if VG_STREQN(17, arg, "--aspace-minaddr=") {} - - else if VG_BINT_CLO(arg, "--valgrind-stacksize", - VG_(clo_valgrind_stacksize), - 2*VKI_PAGE_SIZE, 10*VG_DEFAULT_STACK_ACTIVE_SZB) - {VG_(clo_valgrind_stacksize) - = VG_PGROUNDUP(VG_(clo_valgrind_stacksize));} - - /* Obsolete options. Report an error and exit */ - else if VG_STREQN(34, arg, "--vex-iropt-precise-memory-exns=no") { - VG_(fmsg_bad_option) - (arg, - "--vex-iropt-precise-memory-exns is obsolete\n" - "Use --vex-iropt-register-updates=unwindregs-at-mem-access instead\n"); - } - else if VG_STREQN(35, arg, "--vex-iropt-precise-memory-exns=yes") { - VG_(fmsg_bad_option) - (arg, - "--vex-iropt-precise-memory-exns is obsolete\n" - "Use --vex-iropt-register-updates=allregs-at-mem-access instead\n" - " (or --vex-iropt-register-updates=allregs-at-each-insn)\n"); - } - - /* These options are new, not yet handled by - early_process_cmd_line_options. */ - else if VG_BOOL_CLO(arg, "--sigill-diagnostics", VG_(clo_sigill_diag)) - sigill_diag_set = True; - - else if VG_BOOL_CLO(arg, "--stats", VG_(clo_stats)) {} - else if VG_BOOL_CLO(arg, "--xml", VG_(clo_xml)) - VG_(debugLog_setXml)(VG_(clo_xml)); - - else if VG_XACT_CLO(arg, "--vgdb=no", VG_(clo_vgdb), Vg_VgdbNo) {} - else if VG_XACT_CLO(arg, "--vgdb=yes", VG_(clo_vgdb), Vg_VgdbYes) {} - 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_default - = VG_(clo_px_file_backed) - = VexRegUpdAllregsAtEachInsn; - } - 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_USET_CLO (arg, "--vgdb-stop-at", - "startup,exit,valgrindabexit", - VG_(clo_vgdb_stop_at)) {} - else if VG_STR_CLO (arg, "--vgdb-prefix", VG_(clo_vgdb_prefix)) { - VG_(arg_vgdb_prefix) = arg; - } - else if VG_BOOL_CLO(arg, "--vgdb-shadow-registers", - VG_(clo_vgdb_shadow_registers)) {} - else if VG_BOOL_CLO(arg, "--demangle", VG_(clo_demangle)) {} - else if VG_STR_CLO (arg, "--soname-synonyms",VG_(clo_soname_synonyms)) {} - else if VG_BOOL_CLO(arg, "--error-limit", VG_(clo_error_limit)) {} - else if VG_BOOL_CLO(arg, "--exit-on-first-error", VG_(clo_exit_on_first_error)) {} - else if VG_INT_CLO (arg, "--error-exitcode", VG_(clo_error_exitcode)) {} - else if VG_STR_CLO (arg, "--error-markers", tmp_str) { - Int m; - const HChar *startpos = tmp_str; - const HChar *nextpos; - for (m = 0; - m < sizeof(VG_(clo_error_markers)) - /sizeof(VG_(clo_error_markers)[0]); - m++) { - /* Release previous value if clo given multiple times. */ - VG_(free)(VG_(clo_error_markers)[m]); - VG_(clo_error_markers)[m] = NULL; - - nextpos = VG_(strchr)(startpos, ','); - if (!nextpos) - nextpos = startpos + VG_(strlen)(startpos); - if (startpos != nextpos) { - VG_(clo_error_markers)[m] - = VG_(malloc)("main.mpclo.2", nextpos - startpos + 1); - VG_(memcpy)(VG_(clo_error_markers)[m], startpos, - nextpos - startpos); - VG_(clo_error_markers)[m][nextpos - startpos] = '\0'; - } - startpos = *nextpos ? nextpos + 1 : nextpos; - } - } - else if VG_BOOL_CLO(arg, "--show-error-list", VG_(clo_show_error_list)) { - show_error_list_set = True; } - else if (VG_STREQ(arg, "-s")) { - VG_(clo_show_error_list) = True; - show_error_list_set = True; - } - else if VG_BOOL_CLO(arg, "--show-emwarns", VG_(clo_show_emwarns)) {} - - else if VG_BOOL_CLO(arg, "--run-libc-freeres", VG_(clo_run_libc_freeres)) {} - else if VG_BOOL_CLO(arg, "--run-cxx-freeres", VG_(clo_run_cxx_freeres)) {} - else if VG_BOOL_CLO(arg, "--show-below-main", VG_(clo_show_below_main)) {} - else if VG_BOOL_CLO(arg, "--keep-debuginfo", VG_(clo_keep_debuginfo)) {} - else if VG_BOOL_CLO(arg, "--time-stamp", VG_(clo_time_stamp)) {} - else if VG_BOOL_CLO(arg, "--track-fds", VG_(clo_track_fds)) {} - else if VG_BOOL_CLO(arg, "--trace-children", VG_(clo_trace_children)) {} - else if VG_BOOL_CLO(arg, "--child-silent-after-fork", - VG_(clo_child_silent_after_fork)) {} - else if VG_STR_CLO(arg, "--fair-sched", tmp_str) { - if (VG_(strcmp)(tmp_str, "yes") == 0) - VG_(clo_fair_sched) = enable_fair_sched; - else if (VG_(strcmp)(tmp_str, "try") == 0) - VG_(clo_fair_sched) = try_fair_sched; - else if (VG_(strcmp)(tmp_str, "no") == 0) - VG_(clo_fair_sched) = disable_fair_sched; - else - 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)) {} - else if VG_BOOL_CLO(arg, "--trace-symtab", VG_(clo_trace_symtab)) {} - else if VG_STR_CLO (arg, "--trace-symtab-patt", VG_(clo_trace_symtab_patt)) {} - else if VG_BOOL_CLO(arg, "--trace-cfi", VG_(clo_trace_cfi)) {} - else if VG_XACT_CLO(arg, "--debug-dump=syms", VG_(clo_debug_dump_syms), - True) {} - else if VG_XACT_CLO(arg, "--debug-dump=line", VG_(clo_debug_dump_line), - True) {} - else if VG_XACT_CLO(arg, "--debug-dump=frames", - VG_(clo_debug_dump_frames), True) {} - else if VG_BOOL_CLO(arg, "--trace-redir", VG_(clo_trace_redir)) {} - - else if VG_BOOL_CLO(arg, "--trace-syscalls", VG_(clo_trace_syscalls)) {} - else if VG_BOOL_CLO(arg, "--wait-for-gdb", VG_(clo_wait_for_gdb)) {} - else if VG_BOOL_CLO(arg, "--sym-offsets", VG_(clo_sym_offsets)) {} - else if VG_BINT_CLO(arg, "--progress-interval", - VG_(clo_progress_interval), 0, 3600) {} - else if VG_BOOL_CLO(arg, "--read-inline-info", VG_(clo_read_inline_info)) {} - else if VG_BOOL_CLO(arg, "--read-var-info", VG_(clo_read_var_info)) {} - - else if VG_INT_CLO (arg, "--dump-error", VG_(clo_dump_error)) {} - else if VG_INT_CLO (arg, "--input-fd", VG_(clo_input_fd)) {} - else if VG_INT_CLO (arg, "--sanity-level", VG_(clo_sanity_level)) {} - else if VG_BINT_CLO(arg, "--num-callers", VG_(clo_backtrace_size), 1, - VG_DEEPEST_BACKTRACE) {} - else if VG_BINT_CLO(arg, "--num-transtab-sectors", - VG_(clo_num_transtab_sectors), - MIN_N_SECTORS, MAX_N_SECTORS) {} - else if VG_BINT_CLO(arg, "--avg-transtab-entry-size", - VG_(clo_avg_transtab_entry_size), - 50, 5000) {} - else if VG_BINT_CLO(arg, "--merge-recursive-frames", - VG_(clo_merge_recursive_frames), 0, - VG_DEEPEST_BACKTRACE) {} - - else if VG_XACT_CLO(arg, "--smc-check=none", - VG_(clo_smc_check), Vg_SmcNone) {} - else if VG_XACT_CLO(arg, "--smc-check=stack", - VG_(clo_smc_check), 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_USETX_CLO (arg, "--kernel-variant", - "bproc," - "android-no-hw-tls," - "android-gpu-sgx5xx," - "android-gpu-adreno3xx", - VG_(clo_kernel_variant)) {} - - else if VG_BOOL_CLO(arg, "--dsymutil", VG_(clo_dsymutil)) {} - - else if VG_STR_CLO (arg, "--trace-children-skip", - VG_(clo_trace_children_skip)) {} - else if VG_STR_CLO (arg, "--trace-children-skip-by-arg", - VG_(clo_trace_children_skip_by_arg)) {} - - else if VG_BINT_CLO(arg, "--vex-iropt-verbosity", - VG_(clo_vex_control).iropt_verbosity, 0, 10) {} - else if VG_BINT_CLO(arg, "--vex-iropt-level", - VG_(clo_vex_control).iropt_level, 0, 2) {} - else if VG_BINT_CLO(arg, "--vex-regalloc-version", - VG_(clo_vex_control).regalloc_version, 2, 3) {} - - 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) {} - else if VG_BINT_CLO(arg, "--vex-guest-max-insns", - VG_(clo_vex_control).guest_max_insns, 1, 100) {} - else if VG_BINT_CLO(arg, "--vex-guest-chase-thresh", - VG_(clo_vex_control).guest_chase_thresh, 0, 99) {} - else if VG_BOOL_CLO(arg, "--vex-guest-chase-cond", - VG_(clo_vex_control).guest_chase_cond) {} - - else if VG_INT_CLO(arg, "--log-fd", tmp_log_fd) { - log_to = VgLogTo_Fd; - VG_(clo_log_fname_unexpanded) = NULL; - } - else if VG_INT_CLO(arg, "--xml-fd", tmp_xml_fd) { - xml_to = VgLogTo_Fd; - VG_(clo_xml_fname_unexpanded) = NULL; - } - - else if VG_STR_CLO(arg, "--log-file", VG_(clo_log_fname_unexpanded)) { - log_to = VgLogTo_File; - } - else if VG_STR_CLO(arg, "--xml-file", VG_(clo_xml_fname_unexpanded)) { - xml_to = VgLogTo_File; - } - - else if VG_STR_CLO(arg, "--log-socket", VG_(clo_log_fname_unexpanded)) { - log_to = VgLogTo_Socket; - } - else if VG_STR_CLO(arg, "--xml-socket", VG_(clo_xml_fname_unexpanded)) { - xml_to = VgLogTo_Socket; - } - - else if VG_STR_CLO(arg, "--debuginfo-server", - VG_(clo_debuginfo_server)) {} - - else if VG_BOOL_CLO(arg, "--allow-mismatched-debuginfo", - VG_(clo_allow_mismatched_debuginfo)) {} - - else if VG_STR_CLO(arg, "--xml-user-comment", - VG_(clo_xml_user_comment)) {} - - else if VG_BOOL_CLO(arg, "--default-suppressions", - VG_(clo_default_supp)) {} - - else if VG_STR_CLO(arg, "--suppressions", tmp_str) { - VG_(addToXA)(VG_(clo_suppressions), &tmp_str); - } - - else if VG_STR_CLO (arg, "--fullpath-after", tmp_str) { - VG_(addToXA)(VG_(clo_fullpath_after), &tmp_str); - } - - else if VG_STR_CLO (arg, "--extra-debuginfo-path", - VG_(clo_extra_debuginfo_path)) {} - - else if VG_STR_CLO(arg, "--require-text-symbol", tmp_str) { - /* String needs to be of the form C?*C?*, where C is any - character, but is the same both times. Having it in this - form facilitates finding the boundary between the sopatt - and the fnpatt just by looking for the second occurrence - of C, without hardwiring any assumption about what C - is. */ - HChar patt[7]; - Bool ok = True; - ok = tmp_str && VG_(strlen)(tmp_str) > 0; - if (ok) { - patt[0] = patt[3] = tmp_str[0]; - patt[1] = patt[4] = '?'; - patt[2] = patt[5] = '*'; - patt[6] = 0; - ok = VG_(string_match)(patt, tmp_str); - } - if (!ok) { - VG_(fmsg_bad_option)(arg, - "Invalid --require-text-symbol= specification.\n"); - } - VG_(addToXA)(VG_(clo_req_tsyms), &tmp_str); - } - - /* "stuvwxyz" --> stuvwxyz (binary) */ - else if VG_STR_CLO(arg, "--trace-flags", tmp_str) { - Int j; - if (8 != VG_(strlen)(tmp_str)) { - VG_(fmsg_bad_option)(arg, - "--trace-flags argument must have 8 digits\n"); - } - for (j = 0; j < 8; j++) { - if ('0' == tmp_str[j]) { /* do nothing */ } - else if ('1' == tmp_str[j]) VG_(clo_trace_flags) |= (1 << (7-j)); - else { - VG_(fmsg_bad_option)(arg, - "--trace-flags argument can only contain 0s and 1s\n"); - } - } - } - - else if VG_INT_CLO (arg, "--trace-notbelow", VG_(clo_trace_notbelow)) {} - - else if VG_INT_CLO (arg, "--trace-notabove", VG_(clo_trace_notabove)) {} - - /* "stuvwxyz" --> stuvwxyz (binary) */ - else if VG_STR_CLO(arg, "--profile-flags", tmp_str) { - Int j; - if (8 != VG_(strlen)(tmp_str)) { - VG_(fmsg_bad_option)(arg, - "--profile-flags argument must have 8 digits\n"); - } - for (j = 0; j < 8; j++) { - if ('0' == tmp_str[j]) { /* do nothing */ } - else if ('1' == tmp_str[j]) VG_(clo_profyle_flags) |= (1 << (7-j)); - else { - VG_(fmsg_bad_option)(arg, - "--profile-flags argument can only contain 0s and 1s\n"); - } - } - VG_(clo_profyle_sbs) = True; - } - - else if VG_INT_CLO (arg, "--profile-interval", - VG_(clo_profyle_interval)) {} - - else if VG_XACT_CLO(arg, "--gen-suppressions=no", - VG_(clo_gen_suppressions), 0) {} - else if VG_XACT_CLO(arg, "--gen-suppressions=yes", - VG_(clo_gen_suppressions), 1) {} - else if VG_XACT_CLO(arg, "--gen-suppressions=all", - VG_(clo_gen_suppressions), 2) {} - - else if VG_BINT_CLO(arg, "--unw-stack-scan-thresh", - VG_(clo_unw_stack_scan_thresh), 0, 100) {} - else if VG_BINT_CLO(arg, "--unw-stack-scan-frames", - VG_(clo_unw_stack_scan_frames), 0, 32) {} - - else if VG_XACT_CLO(arg, "--resync-filter=no", - VG_(clo_resync_filter), 0) {} - else if VG_XACT_CLO(arg, "--resync-filter=yes", - VG_(clo_resync_filter), 1) {} - else if VG_XACT_CLO(arg, "--resync-filter=verbose", - VG_(clo_resync_filter), 2) {} - - else if ( ! VG_(needs).command_line_options - || ! VG_TDICT_CALL(tool_process_cmd_line_option, arg) ) { - VG_(fmsg_unknown_option)(arg); - } + process_option (cloP, arg, &pos); } - /* END command-line processing loop */ + /* END command-line processing loop. From now on, only dynamically + changeable options will have an effect. */ + VG_(set_Clo_Mode)(cloD); /* Notify about deprecated features here. */ @@ -920,16 +974,16 @@ void main_process_cmd_line_options( void ) if (VG_(clo_vex_control).guest_chase_thresh < 0) VG_(clo_vex_control).guest_chase_thresh = 0; - + /* Check various option values */ if (VG_(clo_verbosity) < 0) VG_(clo_verbosity) = 0; - if (!sigill_diag_set) + if (!pos.sigill_diag_set) VG_(clo_sigill_diag) = (VG_(clo_verbosity) > 0); - if (!show_error_list_set) { + if (!pos.show_error_list_set) { if (VG_(clo_xml)) VG_(clo_show_error_list) = VG_(clo_verbosity) >= 1; else @@ -954,9 +1008,7 @@ void main_process_cmd_line_options( void ) } } - VG_(dyn_vgdb_error) = VG_(clo_vgdb_error); - - if (VG_(clo_gen_suppressions) > 0 && + if (VG_(clo_gen_suppressions) > 0 && !VG_(needs).core_errors && !VG_(needs).tool_errors) { VG_(fmsg_bad_option)("--gen-suppressions=yes", "Can't use --gen-suppressions= with %s\n" @@ -970,7 +1022,7 @@ void main_process_cmd_line_options( void ) # if !defined(VGO_darwin) if (VG_(clo_resync_filter) != 0) { - VG_(fmsg_bad_option)("--resync-filter=yes or =verbose", + VG_(fmsg_bad_option)("--resync-filter=yes or =verbose", "--resync-filter= is only available on MacOS X.\n"); /*NOTREACHED*/ } @@ -981,7 +1033,7 @@ void main_process_cmd_line_options( void ) if (VG_(clo_xml) && !VG_(needs).xml_output) { VG_(clo_xml) = False; VG_(fmsg_bad_option)("--xml=yes", - "%s does not support XML output.\n", VG_(details).name); + "%s does not support XML output.\n", VG_(details).name); /*NOTREACHED*/ } @@ -990,7 +1042,7 @@ void main_process_cmd_line_options( void ) /* If we've been asked to emit XML, mash around various other options so as to constrain the output somewhat, and to remove - any need for user input during the run. + any need for user input during the run. */ if (VG_(clo_xml)) { @@ -1032,7 +1084,8 @@ void main_process_cmd_line_options( void ) (So far we should be still attached to stderr, so we can show on the terminal any problems to do with processing command line opts.) */ - VG_(init_log_xml_sinks)(log_to, xml_to, tmp_log_fd, tmp_xml_fd); + VG_(init_log_xml_sinks)(pos.log_to, pos.xml_to, + pos.tmp_log_fd, pos.tmp_xml_fd); /* Register child at-fork handler which will take care of handling --child-silent-after-fork clo and also reopening output sinks for forked @@ -1043,13 +1096,13 @@ void main_process_cmd_line_options( void ) if (VG_(clo_default_supp) && (VG_(needs).core_errors || VG_(needs).tool_errors)) { - /* If we haven't reached the max number of suppressions, load - the default one. */ + /* If loading default is enabled, add it to the supp list. */ static const HChar default_supp[] = "default.supp"; Int len = VG_(strlen)(VG_(libdir)) + 1 + sizeof(default_supp); HChar *buf = VG_(malloc)("main.mpclo.3", len); VG_(sprintf)(buf, "%s/%s", VG_(libdir), default_supp); - VG_(addToXA)(VG_(clo_suppressions), &buf); + VG_(add_suppression_file)(buf); + VG_(free)(buf); } } @@ -1082,7 +1135,7 @@ static void setup_file_descriptors(void) # endif if (show) - VG_(printf)("fd limits: host, before: cur %llu max %llu\n", + VG_(printf)("fd limits: host, before: cur %llu max %llu\n", (ULong)rl.rlim_cur, (ULong)rl.rlim_max); /* Work out where to move the soft limit to. */ @@ -1154,11 +1207,11 @@ typedef struct { Addr a; ULong ull; } Addr_n_ULong; /* --- Forwards decls to do with shutdown --- */ -static void final_tidyup(ThreadId tid); +static void final_tidyup(ThreadId tid); /* Do everything which needs doing when the last thread exits */ -static -void shutdown_actions_NORETURN( ThreadId tid, +static +void shutdown_actions_NORETURN( ThreadId tid, VgSchedReturnCode tids_schedretcode ); /* --- end of Forwards decls to do with shutdown --- */ @@ -1171,7 +1224,7 @@ void shutdown_actions_NORETURN( ThreadId tid, static Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) { - Int need_help = 0; // 0 = no, 1 = --help, 2 = --help-debug + Int need_help; ThreadId tid_main = VG_INVALID_THREADID; Int loglevel, i; XArray* addr2dihandle = NULL; @@ -1186,7 +1239,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) // Once that's done, we can relax a bit. // //============================================================ - + /* This is needed to make VG_(getenv) usable early. */ VG_(client_envp) = (HChar**)envp; @@ -1202,7 +1255,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) // Start up the logging mechanism // p: none //-------------------------------------------------------------- - /* Start the debugging-log system ASAP. First find out how many + /* Start the debugging-log system ASAP. First find out how many "-d"s were specified. This is a pre-scan of the command line. Also get --profile-heap=yes, --core-redzone-size, --redzone-size --aspace-minaddr which are needed by the time we start up dynamic @@ -1213,12 +1266,12 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) if (argv[i][0] != '-') break; if VG_STREQ(argv[i], "--") break; if VG_STREQ(argv[i], "-d") loglevel++; - if VG_BOOL_CLO(argv[i], "--profile-heap", VG_(clo_profile_heap)) {} - if VG_BINT_CLO(argv[i], "--core-redzone-size", VG_(clo_core_redzone_size), + if VG_BOOL_CLOM(cloE, argv[i], "--profile-heap", VG_(clo_profile_heap)) {} + if VG_BINT_CLOM(cloE, argv[i], "--core-redzone-size", VG_(clo_core_redzone_size), 0, MAX_CLO_REDZONE_SZB) {} - if VG_BINT_CLO(argv[i], "--redzone-size", VG_(clo_redzone_size), + if VG_BINT_CLOM(cloE, argv[i], "--redzone-size", VG_(clo_redzone_size), 0, MAX_CLO_REDZONE_SZB) {} - if VG_STR_CLO(argv[i], "--aspace-minaddr", tmp_str) { + if VG_STR_CLOM(cloE, argv[i], "--aspace-minaddr", tmp_str) { Bool ok = VG_(parse_Addr) (&tmp_str, &VG_(clo_aspacem_minAddr)); if (!ok) VG_(fmsg_bad_option)(argv[i], "Invalid address\n"); @@ -1232,7 +1285,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) /* ... and start the debug logger. Now we can safely emit logging messages all through startup. */ VG_(debugLog_startup)(loglevel, "Stage 2 (main)"); - VG_(debugLog)(1, "main", "Welcome to Valgrind version " + VG_(debugLog)(1, "main", "Welcome to Valgrind version " VERSION " debug logging\n"); //-------------------------------------------------------------- @@ -1242,7 +1295,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) VG_(debugLog)(1, "main", "Checking current stack is plausible\n"); { HChar* limLo = (HChar*)(&VG_(interim_stack).bytes[0]); HChar* limHi = limLo + sizeof(VG_(interim_stack)); - HChar* volatile + HChar* volatile aLocal = (HChar*)&limLo; /* any auto local will do */ /* Re "volatile": Apple clang version 4.0 (tags/Apple/clang-421.0.57) (based on LLVM 3.1svn)" appeared @@ -1329,7 +1382,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) VG_(di_initialise)(); //-------------------------------------------------------------- - // Look for alternative libdir + // Look for alternative libdir { HChar *cp = VG_(getenv)(VALGRIND_LIB); if (cp != NULL) VG_(libdir) = cp; @@ -1362,7 +1415,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) VG_(getrlimit)(VKI_RLIMIT_STACK, &VG_(client_rlimit_stack)); //-------------------------------------------------------------- - // Figure out what sort of CPU we're on, and whether it is + // Figure out what sort of CPU we're on, and whether it is // able to run V. /* The vex_archinfo structure is passed down later to the client * to verify the HW info settings are consistent. @@ -1389,7 +1442,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) VG_(debugLog)( 1, "main", "... arch = %s, hwcaps = %s\n", LibVEX_ppVexArch ( vex_arch ), - LibVEX_ppVexHwCaps ( vex_arch, vex_archinfo.hwcaps ) + LibVEX_ppVexHwCaps ( vex_arch, vex_archinfo.hwcaps ) ); } @@ -1403,7 +1456,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) //============================================================ // Command line argument handling order: - // * If --help/--help-debug are present, show usage message + // * If --help/--help-debug are present, show usage message // (including the tool-specific usage) // * (If no --tool option given, default to Memcheck) // * Then, if client is missing, abort with error msg @@ -1421,13 +1474,13 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) if (0) { for (i = 0; i < VG_(sizeXA)( VG_(args_for_valgrind) ); i++) VG_(printf)( - "varg %s\n", + "varg %s\n", * (HChar**) VG_(indexXA)( VG_(args_for_valgrind), i ) ); VG_(printf)(" exe %s\n", VG_(args_the_exename)); for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) VG_(printf)( - "carg %s\n", + "carg %s\n", * (HChar**) VG_(indexXA)( VG_(args_for_client), i ) ); } @@ -1481,7 +1534,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) // p: fix_environment() [for 'env'] // // Setup client data (brk) segment. Initially a 1-page segment - // which abuts a shrinkable reservation. + // which abuts a shrinkable reservation. // p: load_client() [for 'info' and hence VG_(brk_base)] // // p: _start_in_C (for zeroing out the_iicii and putting some @@ -1590,7 +1643,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) VG_(write)(fd, VG_(client_auxv), client_auxv_len); /* Don't bother to seek the file back to the start; instead do - it every time a copy of it is given out (by PRE(sys_open)). + it every time a copy of it is given out (by PRE(sys_open)). That is probably more robust across fork() etc. */ /* Now delete it, but hang on to the fd. */ @@ -1639,7 +1692,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) //-------------------------------------------------------------- VG_(debugLog)(1, "main", "Print help and quit, if requested\n"); if (need_help) { - usage_NORETURN(/*--help-debug?*/need_help >= 2); + usage_NORETURN(need_help); } //-------------------------------------------------------------- @@ -1705,19 +1758,6 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) VG_(debugLog)(1, "main", "Initialise redirects\n"); VG_(redir_initialise)(); - //-------------------------------------------------------------- - // Allow GDB attach - // p: main_process_cmd_line_options() [for VG_(clo_wait_for_gdb)] - //-------------------------------------------------------------- - /* Hook to delay things long enough so we can get the pid and - attach GDB in another shell. */ - if (VG_(clo_wait_for_gdb)) { - const int ms = 8000; // milliseconds - VG_(debugLog)(1, "main", "Wait for GDB during %d ms\n", ms); - VG_(printf)("pid=%d, entering delay %d ms loop\n", VG_(getpid)(), ms); - VG_(poll)(NULL, 0, ms); - } - //-------------------------------------------------------------- // Search for file descriptors that are inherited from our parent // p: main_process_cmd_line_options [for VG_(clo_track_fds)] @@ -1785,7 +1825,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) seg_starts = VG_(get_segment_starts)( SkFileC, &n_seg_starts ); vg_assert(seg_starts && n_seg_starts >= 0); - /* show them all to the debug info reader. + /* show them all to the debug info reader. Don't read from V segments (unlike Linux) */ // GrP fixme really? for (i = 0; i < n_seg_starts; i++) { @@ -1813,7 +1853,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) "transfer ownership V -> C of 0x%llx .. 0x%llx\n", (ULong)co_start, (ULong)co_endPlus-1 ); - change_ownership_v_c_OK + change_ownership_v_c_OK = VG_(am_change_ownership_v_to_c)( co_start, co_endPlus - co_start ); vg_assert(change_ownership_v_c_OK); } @@ -1841,7 +1881,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) && tid_main != VG_INVALID_THREADID); /* Tell the tool about tid_main */ VG_TRACK( pre_thread_ll_create, VG_INVALID_THREADID, tid_main ); - + //-------------------------------------------------------------- // Tell the tool about the initial client memory permissions // p: aspacem @@ -1849,7 +1889,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) // p: setup_client_stack // p: setup_client_dataseg // - // For each segment we tell the client about, look up in + // For each segment we tell the client about, look up in // addr2dihandle as created above, to see if there's a debuginfo // handle associated with the segment, that we can hand along // to the tool, to be helpful. @@ -1873,14 +1913,14 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) /* Show client segments to the tool */ for (i = 0; i < n_seg_starts; i++) { Word j, n; - NSegment const* seg + NSegment const* seg = VG_(am_find_nsegment)( seg_starts[i] ); vg_assert(seg); vg_assert(seg->kind == SkFileC || seg->kind == SkAnonC || seg->kind == SkShmC); vg_assert(seg->start == seg_starts[i]); { - VG_(debugLog)(2, "main", + VG_(debugLog)(2, "main", "tell tool about %010lx-%010lx %c%c%c\n", seg->start, seg->end, seg->hasR ? 'r' : '-', @@ -1897,7 +1937,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) } } vg_assert(j >= 0 && j <= n); - VG_TRACK( new_mem_startup, seg->start, seg->end+1-seg->start, + VG_TRACK( new_mem_startup, seg->start, seg->end+1-seg->start, seg->hasR, seg->hasW, seg->hasX, /* and the retrieved debuginfo handle, if any */ j < n @@ -1912,7 +1952,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) /* Also do the initial stack permissions. */ { SSizeT inaccessible_len; - NSegment const* seg + NSegment const* seg = VG_(am_find_nsegment)( the_iifii.initial_client_SP ); vg_assert(seg); vg_assert(seg->kind == SkAnonC); @@ -1924,22 +1964,22 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) is required (VG_STACK_REDZONE_SZB). setup_client_stack() will have allocated an extra page if a red zone is required, to be on the safe side. */ - inaccessible_len = the_iifii.initial_client_SP - VG_STACK_REDZONE_SZB + inaccessible_len = the_iifii.initial_client_SP - VG_STACK_REDZONE_SZB - seg->start; vg_assert(inaccessible_len >= 0); if (inaccessible_len > 0) - VG_TRACK( die_mem_stack, - seg->start, + VG_TRACK( die_mem_stack, + seg->start, inaccessible_len ); VG_(debugLog)(2, "main", "mark stack inaccessible %010lx-%010lx\n", - seg->start, + seg->start, the_iifii.initial_client_SP-1 - VG_STACK_REDZONE_SZB); } /* Also the assembly helpers. */ VG_TRACK( new_mem_startup, (Addr)&VG_(trampoline_stuff_start), - (Addr)&VG_(trampoline_stuff_end) + (Addr)&VG_(trampoline_stuff_end) - (Addr)&VG_(trampoline_stuff_start), False, /* readable? */ False, /* writable? */ @@ -1976,13 +2016,13 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) // p: setup_client_stack //-------------------------------------------------------------- VG_(debugLog)(1, "main", "Initialise scheduler (phase 2)\n"); - { NSegment const* seg + { NSegment const* seg = VG_(am_find_nsegment)( the_iifii.initial_client_SP ); vg_assert(seg); vg_assert(seg->kind == SkAnonC); vg_assert(the_iifii.initial_client_SP >= seg->start); vg_assert(the_iifii.initial_client_SP <= seg->end); - VG_(scheduler_init_phase2)( tid_main, + VG_(scheduler_init_phase2)( tid_main, seg->end, the_iifii.clstack_max_size ); } @@ -2073,19 +2113,19 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) We enter here holding The Lock. For the case VgSrc_ExitProcess we must never release it, because to do so would allow other threads to continue after the system is ostensibly shut down. So we must - go to our grave, so to speak, holding the lock. + go to our grave, so to speak, holding the lock. In fact, there is never any point in releasing the lock at this point - we have it, we're shutting down the entire system, and for the case VgSrc_ExitProcess doing so positively causes trouble. - So don't. + So don't. The final_tidyup call makes a bit of a nonsense of the ExitProcess case, since it will run __gnu_cxx::__freeres and libc_freeres functions, thus allowing other lurking threads to run again. Hmm. */ -static -void shutdown_actions_NORETURN( ThreadId tid, +static +void shutdown_actions_NORETURN( ThreadId tid, VgSchedReturnCode tids_schedretcode ) { VG_(debugLog)(1, "main", "entering VG_(shutdown_actions_NORETURN)\n"); @@ -2228,11 +2268,11 @@ void shutdown_actions_NORETURN( ThreadId tid, return code. In short, if the (last) thread exited by calling sys_exit, do likewise; if the (last) thread stopped due to a fatal signal, terminate the entire system with that same fatal signal. */ - VG_(debugLog)(1, "core_os", + VG_(debugLog)(1, "core_os", "VG_(terminate_NORETURN)(tid=%u) schedretcode %s" " os_state.exit_code %ld fatalsig %d\n", tid, VG_(name_of_VgSchedReturnCode)(tids_schedretcode), - VG_(threads)[tid].os_state.exitcode, + VG_(threads)[tid].os_state.exitcode, VG_(threads)[tid].os_state.fatalsig); switch (tids_schedretcode) { @@ -2240,7 +2280,7 @@ void shutdown_actions_NORETURN( ThreadId tid, case VgSrc_ExitProcess: /* the normal way out (Darwin) */ /* Change the application return code to user's return code, if an error was found */ - if (VG_(clo_error_exitcode) > 0 + if (VG_(clo_error_exitcode) > 0 && VG_(get_n_errs_found)() > 0) { VG_(client_exit)( VG_(clo_error_exitcode) ); } else { @@ -2273,7 +2313,7 @@ void shutdown_actions_NORETURN( ThreadId tid, /* -------------------- */ -/* Final clean-up before terminating the process. +/* Final clean-up before terminating the process. Clean up the client by calling __gnu_cxx::__freeres() (if requested) and __libc_freeres() (if requested). */ @@ -2305,9 +2345,9 @@ static void final_tidyup(ThreadId tid) Addr r2 = VG_(get_tocptr)(VG_(current_DiEpoch)(), freeres_wrapper); if (r2 == 0) { - VG_(message)(Vg_UserMsg, + VG_(message)(Vg_UserMsg, "Caught __NR_exit, but can't run __gnu_cxx::__freeres()\n"); - VG_(message)(Vg_UserMsg, + VG_(message)(Vg_UserMsg, " or __libc_freeres() since cannot establish TOC pointer " "for it.\n"); return; @@ -2326,7 +2366,7 @@ static void final_tidyup(ThreadId tid) VG_(message)(Vg_DebugMsg, "Caught __NR_exit; running %s wrapper\n", msgs[to_run - 1]); } - + /* Set thread context to point to freeres_wrapper. ppc64be-linux note: freeres_wrapper gives us the real function entry point, not a fn descriptor, so can use it @@ -2453,7 +2493,7 @@ static void final_tidyup(ThreadId tid) following code is irrelevant. However, this is not the intended mode of use. The plan is to - avoid linking against glibc, by giving gcc the flags + avoid linking against glibc, by giving gcc the flags -nodefaultlibs -lgcc -nostartfiles at startup. From this derive two requirements: @@ -2606,7 +2646,7 @@ asm("\n" /* install it, and collect the original one */ "\txchgl %eax, %esp\n" /* call _start_in_C_linux, passing it the startup %esp */ - "\tmovl %eax, (%esp)\n" + "\tmovl %eax, (%esp)\n" "\tcall _start_in_C_linux\n" "\thlt\n" ".previous\n" @@ -2844,8 +2884,8 @@ asm("\n" "\tbal 1f\n" "\tnop\n" - - "1:\n" + + "1:\n" "\tlui $28, %hi(_gp_disp)\n" "\taddiu $28, $28, %lo(_gp_disp)\n" @@ -2858,7 +2898,7 @@ asm("\n" "\tli $10, "VG_STRINGIFY(VG_STACK_GUARD_SZB)"\n" "\tli $11, "VG_STRINGIFY(VG_DEFAULT_STACK_ACTIVE_SZB)"\n" - + "\taddu $9, $9, $10\n" "\taddu $9, $9, $11\n" "\tli $12, 0xFFFFFFF0\n" @@ -2867,13 +2907,13 @@ asm("\n" VG_DEFAULT_STACK_ACTIVE_SZB rounded down to the nearest 16-byte boundary. And $29 is the original SP. Set the SP to t1 and call _start_in_C, passing it the initial SP. */ - + "\tmove $4, $29\n" // a0 <- $sp (_start_in_C first arg) "\tmove $29, $9\n" // $sp <- t1 (new sp) - + "\tlui $25, %hi(_start_in_C_linux)\n" "\taddiu $25, %lo(_start_in_C_linux)\n" - + "\tbal _start_in_C_linux\n" "\tbreak 0x7\n" ".previous\n" @@ -3238,7 +3278,7 @@ value). The divisor is parameter v. The value returned is the quotient. Max line length is 57, to fit in hacker.book. */ -static Int nlz32(UInt x) +static Int nlz32(UInt x) { Int n; if (x == 0) return(32); @@ -3353,7 +3393,7 @@ and similar names are used here. Max line length is 57, to fit in hacker.book. */ -static Int nlz64(ULong x) +static Int nlz64(ULong x) { Int n; if (x == 0) return(64); @@ -3561,9 +3601,9 @@ Long __moddi3 (Long u, Long v) * Negative values all become zero. */ -/* Assumption: double is a IEEE 64 bit floating point type +/* Assumption: double is a IEEE 64 bit floating point type * du_int is a 64 bit integral type - * value in double is representable in du_int or is negative + * value in double is representable in du_int or is negative * (no range checking performed) */ @@ -3624,10 +3664,10 @@ __fixunsdfdi(double a) #if defined(VGO_darwin) && DARWIN_VERS >= DARWIN_10_10 /* Builds on MacOSX 10.10+ seem to need this for some reason. */ -/* extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) +/* extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import)); I haven't a clue what the return value means, so just return 0. - Looks like none of the generated uses in the tree look at the + Looks like none of the generated uses in the tree look at the return value anyway. */ UWord voucher_mach_msg_set ( UWord arg1 ); diff --git a/coregrind/m_options.c b/coregrind/m_options.c index ff47bd74f6..09fda56fe9 100644 --- a/coregrind/m_options.c +++ b/coregrind/m_options.c @@ -40,6 +40,47 @@ // See pub_{core,tool}_options.h for explanations of all these. +static Clo_Mode clo_mode = cloE; +static Bool clo_recognised = False; + +void VG_(set_Clo_Mode) (Clo_Mode mode) +{ + clo_mode = mode; + clo_recognised = False; +} +Clo_Mode VG_(Clo_Mode) (void) +{ + return clo_mode; +} + +void VG_(set_Clo_Recognised) (void) +{ + clo_recognised = True; +} + +Bool VG_(Clo_Recognised) (void) +{ + return clo_recognised; +} + +Bool VG_(check_clom) (Clo_Mode modes, const HChar* arg, const HChar* option, + Bool recognised) +{ + Bool res = recognised && (modes & VG_(Clo_Mode)()); + Bool dynamic = cloD == VG_(Clo_Mode)(); + + if (recognised) { + VG_(set_Clo_Recognised) (); + if (dynamic && !res) + VG_(umsg)("Cannot change %s option dynamically\n", option); + else if (dynamic && VG_(clo_verbosity) >= 1) + VG_(umsg)("Handling new value %s for option %s\n", arg, option); + } + if (cloH == VG_(Clo_Mode)() && (cloD & modes)) + VG_(list_clo)(option); + + return res; +} /* Define, and set defaults. */ @@ -316,9 +357,43 @@ HChar* VG_(expand_file_name)(const HChar* option_name, const HChar* format) HChar opt[VG_(strlen)(option_name) + VG_(strlen)(format) + 2]; VG_(sprintf)(opt, "%s=%s", option_name, format); VG_(fmsg_bad_option)(opt, "%s", message); + VG_(exit)(1); // Cannot continue + /*NOTREACHED*/ } } +static int col = 0; +void VG_(list_clo)(const HChar *qq_option) +{ + int len = VG_(strlen)(qq_option); + if (col + len + 1 > 80) { + VG_(printf)("\n"); + col = 0; + } + + if (col == 0) { + VG_(printf)(" "); + col += 4; + } else { + VG_(printf)(" "); + col += 1; + } + VG_(printf)("%s", qq_option); + col += len; +} +void VG_(list_dynamic_options) (void) +{ + HChar dummy[40]; + + VG_(sprintf)(dummy, "%s", ""); + VG_(printf)(" dynamically changeable options:\n"); + VG_(process_dynamic_option) (cloH, dummy); + if (col > 0) { + VG_(printf)("\n"); + col = 0; + } +} + /*====================================================================*/ /*=== --trace-children= support ===*/ /*====================================================================*/ diff --git a/coregrind/m_scheduler/scheduler.c b/coregrind/m_scheduler/scheduler.c index 04c9fd4557..4c42b216b7 100644 --- a/coregrind/m_scheduler/scheduler.c +++ b/coregrind/m_scheduler/scheduler.c @@ -1322,10 +1322,6 @@ VgSchedReturnCode VG_(scheduler) ( ThreadId tid ) else VG_(disable_vgdb_poll) (); - vg_assert (VG_(dyn_vgdb_error) == VG_(clo_vgdb_error)); - /* As we are initializing, VG_(dyn_vgdb_error) can't have been - changed yet. */ - VG_(gdbserver_prerun_action) (1); } else { VG_(disable_vgdb_poll) (); @@ -2115,6 +2111,11 @@ void do_client_request ( ThreadId tid ) SET_CLREQ_RETVAL( tid, VG_(get_n_errs_found)() ); break; + case VG_USERREQ__CLO_CHANGE: + VG_(process_dynamic_option) (cloD, (HChar *)arg[1]); + SET_CLREQ_RETVAL( tid, 0 ); /* return value is meaningless */ + break; + case VG_USERREQ__LOAD_PDB_DEBUGINFO: VG_(di_notify_pdb_debuginfo)( arg[1], arg[2], arg[3], arg[4] ); SET_CLREQ_RETVAL( tid, 0 ); /* return value is meaningless */ diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c index 008fff98b1..a316ed8735 100644 --- a/coregrind/m_signals.c +++ b/coregrind/m_signals.c @@ -1908,7 +1908,7 @@ static void default_action(const vki_siginfo_t *info, ThreadId tid) } if (VG_(clo_vgdb) != Vg_VgdbNo - && VG_(dyn_vgdb_error) <= VG_(get_n_errs_shown)() + 1) { + && VG_(clo_vgdb_error) <= VG_(get_n_errs_shown)() + 1) { /* Note: we add + 1 to n_errs_shown as the fatal signal was not reported through error msg, and so was not counted. */ VG_(gdbserver_report_fatal_signal) (info, tid); diff --git a/coregrind/pub_core_errormgr.h b/coregrind/pub_core_errormgr.h index 496d6fb341..e3208a8139 100644 --- a/coregrind/pub_core_errormgr.h +++ b/coregrind/pub_core_errormgr.h @@ -47,6 +47,10 @@ typedef } CoreErrorKind; +/* Add a new suppression file in the list of supp files. + If VG_(load_suppressions) was already called, also load it. */ +extern void VG_(add_suppression_file) (const HChar *filename); + extern void VG_(load_suppressions) ( void ); // if verbosity == 0, print nothing. diff --git a/coregrind/pub_core_libcprint.h b/coregrind/pub_core_libcprint.h index 08e0bc54bd..7d5c0d416f 100644 --- a/coregrind/pub_core_libcprint.h +++ b/coregrind/pub_core_libcprint.h @@ -85,8 +85,8 @@ __attribute__((noreturn)) extern void VG_(err_config_error) ( const HChar* format, ... ); /* Called by main_process_cmd_line_options to indicate an unrecognised - command line option. */ -__attribute__((noreturn)) + command line option. + It shutdowns the system if Clo_Mode is cloE or cloP.*/ extern void VG_(fmsg_unknown_option) ( const HChar *opt ); #endif // __PUB_CORE_LIBCPRINT_H diff --git a/coregrind/pub_core_options.h b/coregrind/pub_core_options.h index 5dc5ddea41..136c0ff6e0 100644 --- a/coregrind/pub_core_options.h +++ b/coregrind/pub_core_options.h @@ -379,6 +379,9 @@ extern UInt VG_(clo_kernel_variant); .dSYM directories as necessary? */ extern Bool VG_(clo_dsymutil); +/* Outputs the list of dynamically changeable options. */ +extern void VG_(list_dynamic_options) (void); + /* Should we trace into this child executable (across execve etc) ? This involves considering --trace-children=, --trace-children-skip=, --trace-children-skip-by-arg=, and the name diff --git a/docs/xml/manual-core-adv.xml b/docs/xml/manual-core-adv.xml index 2d2fda06e5..11afbeb931 100644 --- a/docs/xml/manual-core-adv.xml +++ b/docs/xml/manual-core-adv.xml @@ -240,6 +240,15 @@ tool-specific macros). + + VALGRIND_CLO_CHANGE(option): + + Changes the value of a dynamically changeable option (a string). + See . + + + + VALGRIND_STACK_REGISTER(start, end): @@ -1358,6 +1367,14 @@ client request. This only works if was given at Valgrind startup. + + + v.clo <clo_option>... changes one or more + dynamic command line options. If no clo_option is given, lists the + dynamically changeable options. See + . + + v.set {gdb_output | log_output | diff --git a/docs/xml/manual-core.xml b/docs/xml/manual-core.xml index 141a13cd0c..8d24616a0e 100644 --- a/docs/xml/manual-core.xml +++ b/docs/xml/manual-core.xml @@ -2759,6 +2759,74 @@ don't understand + +Dynamically Changing Options + +The value of some command line options can be changed dynamically + while your program is running under Valgrind. + +The dynamically changeable options of the valgrind core and a given + tool can be listed using option + --help-dyn-options, for example: + + +The dynamic options can be changed the following ways: + + + + From the shell, using vgdb and the monitor command + v.clo: + + +Note: you must use double quotes around the monitor command to avoid + vgdb interpreting the valgrind options as its own options. + + + + From gdb, using the the monitor command + v.clo: + + + + + From your program, using the client request + VALGRIND_CLO_CHANGE(option): + + + + + Dynamically changeable options can be used in various circumstances, + such as changing the valgrind behaviour during execution, loading + suppression files as part of shared library initialisation, change or + set valgrind options in child processes, ... + + + + diff --git a/exp-sgcheck/pc_common.c b/exp-sgcheck/pc_common.c index b760e35219..fdad042013 100644 --- a/exp-sgcheck/pc_common.c +++ b/exp-sgcheck/pc_common.c @@ -63,6 +63,9 @@ Bool sg_clo_enable_sg_checks = True; /* user visible */ Bool pc_process_cmd_line_options(const HChar* arg) { + if (VG_(Clo_Mode)() != cloP) + return False; + if VG_BOOL_CLO(arg, "--partial-loads-ok", h_clo_partial_loads_ok) {} /* else if VG_BOOL_CLO(arg, "--lossage-check", h_clo_lossage_check) {} */ else if VG_BOOL_CLO(arg, "--enable-sg-checks", sg_clo_enable_sg_checks) {} diff --git a/gdbserver_tests/mchelp.stdoutB.exp b/gdbserver_tests/mchelp.stdoutB.exp index 9fd12caef5..d962e67870 100644 --- a/gdbserver_tests/mchelp.stdoutB.exp +++ b/gdbserver_tests/mchelp.stdoutB.exp @@ -7,6 +7,8 @@ general valgrind monitor commands: v.info n_errs_found [msg] : show the nr of errors found so far and the given msg v.info open_fds : show open file descriptors (only if --track-fds=yes) v.kill : kill the Valgrind process + v.clo ... : changes one or more dynamic command line options + with no clo_option, show the dynamically changeable options. v.set gdb_output : set valgrind output to gdb v.set log_output : set valgrind output to log v.set mixed_output : set valgrind output to log, interactive output to gdb @@ -64,6 +66,8 @@ general valgrind monitor commands: v.info n_errs_found [msg] : show the nr of errors found so far and the given msg v.info open_fds : show open file descriptors (only if --track-fds=yes) v.kill : kill the Valgrind process + v.clo ... : changes one or more dynamic command line options + with no clo_option, show the dynamically changeable options. v.set gdb_output : set valgrind output to gdb v.set log_output : set valgrind output to log v.set mixed_output : set valgrind output to log, interactive output to gdb diff --git a/gdbserver_tests/mssnapshot.stderrB.exp b/gdbserver_tests/mssnapshot.stderrB.exp index ab38c133c4..067303ef14 100644 --- a/gdbserver_tests/mssnapshot.stderrB.exp +++ b/gdbserver_tests/mssnapshot.stderrB.exp @@ -8,6 +8,8 @@ general valgrind monitor commands: v.info n_errs_found [msg] : show the nr of errors found so far and the given msg v.info open_fds : show open file descriptors (only if --track-fds=yes) v.kill : kill the Valgrind process + v.clo ... : changes one or more dynamic command line options + with no clo_option, show the dynamically changeable options. v.set gdb_output : set valgrind output to gdb v.set log_output : set valgrind output to log v.set mixed_output : set valgrind output to log, interactive output to gdb diff --git a/helgrind/hg_main.c b/helgrind/hg_main.c index d8845715a2..ddf582f84b 100644 --- a/helgrind/hg_main.c +++ b/helgrind/hg_main.c @@ -5960,7 +5960,7 @@ static void hg_post_clo_init ( void ) VG_(message)(Vg_UserMsg, "helgrind --delta-stacktrace=yes only works with " "--vex-guest-chase-thresh=0\n" - "=> (re-setting it to 0\n"); + "=> (re-setting it to 0)\n"); VG_(clo_vex_control).guest_chase_thresh = 0; } diff --git a/include/pub_tool_gdbserver.h b/include/pub_tool_gdbserver.h index 2a56b595af..bf03add078 100644 --- a/include/pub_tool_gdbserver.h +++ b/include/pub_tool_gdbserver.h @@ -53,16 +53,6 @@ //-------------------------------------------------------------------- extern void VG_(gdbserver) ( ThreadId tid ); -/* VG_(dyn_vgdb_error) gets its initial value from - VG_(clo_vgdb_error). It can be changed after initial command - processing in order to enable/disable the call to VG_(gdbserver) in - m_errormgr.c. The main reasons to change the below is either - because the user updates it via a monitor command or to - (temporarily) avoid calling gdbserver for error reporting during - monitor command handling. -*/ -extern Int VG_(dyn_vgdb_error); - /* defines the various kinds of breakpoints that gdbserver might ask to insert/remove. Note that the below matches the gdbserver protocol definition. The level of support diff --git a/include/pub_tool_libcprint.h b/include/pub_tool_libcprint.h index 793773af50..52c0f5764d 100644 --- a/include/pub_tool_libcprint.h +++ b/include/pub_tool_libcprint.h @@ -136,8 +136,8 @@ extern UInt VG_(fmsg)( const HChar* format, ... ) PRINTF_CHECK(1, 2); // because an option was unrecognised -- return 'False' from // VG_(tdict).tool_process_cmd_line_option) to indicate that -- use it if eg. // an option was given an inappropriate argument. This function prints an -// error message, then shuts down the entire system. -__attribute__((noreturn)) +// error message. It shuts down the entire system if the current parsing mode +// is cloE or cloP. extern void VG_(fmsg_bad_option) ( const HChar* opt, const HChar* format, ... ) PRINTF_CHECK(2, 3); diff --git a/include/pub_tool_options.h b/include/pub_tool_options.h index e92e9a4a5f..58fbf612dc 100644 --- a/include/pub_tool_options.h +++ b/include/pub_tool_options.h @@ -32,6 +32,56 @@ #include "pub_tool_basics.h" // for VG_ macro #include "libvex.h" // for VexControl +// Command line option parsing happens in the following modes: +// cloE : Early processing, used by coregrind m_main.c to parse the +// command line options that must be handled early on. +// cloP : Processing, used by coregrind and tools during startup, when +// doing command line options Processing. +// clodD : Dynamic, used to dynamically change options after startup. +// A subset of the command line options can be changed dynamically +// after startup. +// cloH : Help, special mode to produce the list of dynamically changeable +// options for --help-dyn-options. +typedef + enum { + cloE = 1, + cloP = 2, + cloD = 4, + cloH = 8 + } Clo_Mode; + +// Defines often used mode sets, e.g. for options used in several modes. +#define cloEP (cloE | cloP) +#define cloED (cloE | cloD) +#define cloPD (cloP | cloD) + +// Sets and gets the current option parsing mode. +// VG_(set_Clo_Mode) also resets the value of VG_(Clo_Recognised) to False. +void VG_(set_Clo_Mode) (Clo_Mode mode); + +Clo_Mode VG_(Clo_Mode) (void); + +// This is called by the various macros below to indicate that +// the currently parsed option has been recognised. +void VG_(set_Clo_Recognised) (void); +Bool VG_(Clo_Recognised) (void); + + +/* Once the system is started up, the dynamic options can be changed + (mode CloD) or listed (mode cloH) using the below. */ +void VG_(process_dynamic_option) (Clo_Mode mode, HChar *value); + +// Macros below are calling VG_(check_clom) to handle an option according +// to the current Clo_Mode. +// If recognised, it marks the option as recognised, and then returns True +// if the current mode matches the modes allowed for this option, +// False if option should not be processed according to current mode +// and qq_mode. +// It produces a warning if mode is cloD and cloD is not allowed by +// modes. If current mode is cloH, CHECK_CLOM calls VG_(list_clo) if cloD +// is allowed by modes. +Bool VG_(check_clom) (Clo_Mode modes, const HChar* arg, const HChar* option, + Bool recognised); // Higher-level command-line option recognisers; use in if/else chains. // Note that they assign a value to the 'qq_var' argument. So often they @@ -41,151 +91,206 @@ // // But if you want to do further checking or processing, you can do this: // -// if VG_STR_CLO(arg, "--foo", clo_foo) { } +// if VG_STR_CLO(arg, "--foo", clo_foo) { } +// +// The recognisers above are only modifying their argument in the relevant +// parsing mode (by default, only during cloP mode). +// If an option is handled during other modes than cloP, use the *M +// variants of the recognisers to specify the mode. // // They use GNU statement expressions to do the qq_var assignment within a // conditional expression. +// Used to produce the list of dynamically changeable options. +extern void VG_(list_clo)(const HChar *qq_option); + +// True if current option parsing mode matches qq_mode +// and the first qq_len characters of qq_arg match qq_option. +#define VG_STREQN_CLOM(qq_mode, qq_len, qq_arg, qq_option) \ + (VG_(check_clom) \ + (qq_mode, qq_arg, qq_option, \ + VG_STREQN(qq_len, qq_arg, qq_option))) + +// True if current option parsing mode matches qq_mode +// and qq_arg match qq_option. +#define VG_STREQ_CLOM(qq_mode, qq_arg, qq_option) \ + (VG_(check_clom) \ + (qq_mode, qq_arg, qq_option, \ + VG_STREQ(qq_arg, qq_option))) + // String argument, eg. --foo=yes or --foo=no +#define VG_BOOL_CLOM(qq_mode, qq_arg, qq_option, qq_var) \ + (VG_(check_clom) \ + (qq_mode, qq_arg, qq_option, \ + VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) && \ + ({Bool res = True; \ + const HChar* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ + if VG_STREQ(val, "yes") (qq_var) = True; \ + else if VG_STREQ(val, "no") (qq_var) = False; \ + else {VG_(fmsg_bad_option)(qq_arg, "Invalid boolean value '%s'" \ + " (should be 'yes' or 'no')\n", val); \ + res = False; } \ + res; })) + #define VG_BOOL_CLO(qq_arg, qq_option, qq_var) \ - (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \ - ({ \ - const HChar* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ - if VG_STREQ(val, "yes") (qq_var) = True; \ - else if VG_STREQ(val, "no") (qq_var) = False; \ - else VG_(fmsg_bad_option)(qq_arg, "Invalid boolean value '%s'" \ - " (should be 'yes' or 'no')\n", val); \ - True; \ - }) \ - ) + VG_BOOL_CLOM(cloP, qq_arg, qq_option, qq_var) // String argument, eg. --foo=bar +#define VG_STR_CLOM(qq_mode, qq_arg, qq_option, qq_var) \ + (VG_(check_clom) \ + (qq_mode, qq_arg, qq_option, \ + VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) && \ + ({const HChar* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ + (qq_var) = val; \ + True; })) + #define VG_STR_CLO(qq_arg, qq_option, qq_var) \ - (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \ - ({ \ - const HChar* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ - (qq_var) = val; \ - True; \ - }) \ - ) + VG_STR_CLOM(cloP, qq_arg, qq_option, qq_var) // UInt enum set arg, eg. --foo=fubar,bar,baz or --foo=none // or --foo=all (if qq_all is True) -#define VG_USETGEN_CLO(qq_arg, qq_option, qq_vals, qq_var, qq_all) \ - (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \ - ({ \ - const HChar* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ - if (!VG_(parse_enum_set)(qq_vals, \ - qq_all,/*allow_all*/ \ - val, \ - &(qq_var))) \ - VG_(fmsg_bad_option)(qq_arg, "%s is an invalid %s set\n", \ - val, qq_option+2); \ - True; \ - }) \ - ) +#define VG_USETGEN_CLOM(qq_mode, qq_arg, qq_option, qq_vals, qq_var, qq_all) \ + (VG_(check_clom) \ + (qq_mode, qq_arg, qq_option, \ + VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) && \ + ({Bool res = True; \ + const HChar* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ + if (!VG_(parse_enum_set)(qq_vals, \ + qq_all,/*allow_all*/ \ + val, \ + &(qq_var))) { \ + VG_(fmsg_bad_option)(qq_arg, "%s is an invalid %s set\n", \ + val, qq_option+2); \ + res = False; } \ + res; })) // UInt enum set arg, eg. --foo=fubar,bar,baz or --foo=none or --foo=all #define VG_USET_CLO(qq_arg, qq_option, qq_vals, qq_var) \ - VG_USETGEN_CLO((qq_arg), qq_option, (qq_vals), (qq_var), True) + VG_USETGEN_CLOM(cloP, (qq_arg), qq_option, (qq_vals), (qq_var), True) +#define VG_USET_CLOM(qq_mode, qq_arg, qq_option, qq_vals, qq_var) \ + VG_USETGEN_CLOM(qq_mode, (qq_arg), qq_option, (qq_vals), (qq_var), True) /* Same as VG_USET_CLO but not allowing --foo=all. To be used when some or all of the enum set are mutually eXclusive. */ #define VG_USETX_CLO(qq_arg, qq_option, qq_vals, qq_var) \ - VG_USETGEN_CLO((qq_arg), qq_option, (qq_vals), (qq_var), False) + VG_USETGEN_CLOM(cloP, (qq_arg), qq_option, (qq_vals), (qq_var), False) +#define VG_USETX_CLOM(qq_mode, qq_arg, qq_option, qq_vals, qq_var) \ + VG_USETGEN_CLOM(qq_mode, (qq_arg), qq_option, (qq_vals), (qq_var), False) // Unbounded integer arg, eg. --foo=10 +#define VG_INT_CLOM(qq_mode, qq_arg, qq_option, qq_var) \ + (VG_(check_clom) \ + (qq_mode, qq_arg, qq_option, \ + VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) && \ + ({Bool res = True; \ + const HChar* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ + HChar* s; \ + 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, \ + "Invalid integer value '%s'\n", val); \ + res = False; } \ + res; })) + #define VG_INT_CLO(qq_arg, qq_option, qq_var) \ - (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \ - ({ \ - const HChar* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ - HChar* s; \ - 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, \ - "Invalid integer value '%s'\n", val); \ - True; \ - }) \ - ) + VG_INT_CLOM(cloP, qq_arg, qq_option, qq_var) // Bounded integer arg, eg. --foo=10 ; if the value exceeds the bounds it // causes an abort. 'qq_base' can be 10 or 16. -#define VG_BINTN_CLO(qq_base, qq_arg, qq_option, qq_var, qq_lo, qq_hi) \ - (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \ - ({ \ - const HChar* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ - HChar* s; \ - Long n = VG_(strtoll##qq_base)( val, &s ); \ - (qq_var) = n; \ +#define VG_BINTN_CLOM(qq_mode, qq_base, qq_arg, qq_option, qq_var, qq_lo, qq_hi) \ + (VG_(check_clom) \ + (qq_mode, qq_arg, qq_option, \ + VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) && \ + ({Bool res = True; \ + const HChar* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ + HChar* s; \ + Long n = VG_(strtoll##qq_base)( val, &s ); \ + (qq_var) = n; \ /* MMM: separate the two cases, and explain the problem; likewise */ \ - /* for all the other macros in this file. */ \ - /* Check for non-numeralness, or overflow. */ \ + /* 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, \ - "Invalid integer value '%s'\n", val); \ - /* Check bounds. */ \ - if ((qq_var) < (qq_lo) || (qq_var) > (qq_hi)) { \ - VG_(fmsg_bad_option)(qq_arg, \ - "'%s' argument must be between %lld and %lld\n", \ - (qq_option), (Long)(qq_lo), (Long)(qq_hi)); \ - } \ - True; \ - }) \ - ) + if ('\0' != s[0] || (qq_var) != n) { \ + VG_(fmsg_bad_option)(qq_arg, \ + "Invalid integer value '%s'\n", val); \ + res = False; } \ + /* Check bounds. */ \ + if ((qq_var) < (qq_lo) || (qq_var) > (qq_hi)) { \ + VG_(fmsg_bad_option)(qq_arg, \ + "'%s' argument must be between %lld and %lld\n", \ + (qq_option), (Long)(qq_lo), (Long)(qq_hi)); \ + res = False; \ + } \ + res;})) // Bounded decimal integer arg, eg. --foo=100 #define VG_BINT_CLO(qq_arg, qq_option, qq_var, qq_lo, qq_hi) \ - VG_BINTN_CLO(10, (qq_arg), qq_option, (qq_var), (qq_lo), (qq_hi)) + VG_BINTN_CLOM(cloP, 10, (qq_arg), qq_option, (qq_var), (qq_lo), (qq_hi)) +#define VG_BINT_CLOM(qq_mode, qq_arg, qq_option, qq_var, qq_lo, qq_hi) \ + VG_BINTN_CLOM(qq_mode, 10, (qq_arg), qq_option, (qq_var), (qq_lo), (qq_hi)) // Bounded hexadecimal integer arg, eg. --foo=0x1fa8 #define VG_BHEX_CLO(qq_arg, qq_option, qq_var, qq_lo, qq_hi) \ - VG_BINTN_CLO(16, (qq_arg), qq_option, (qq_var), (qq_lo), (qq_hi)) + VG_BINTN_CLOM(cloP, 16, (qq_arg), qq_option, (qq_var), (qq_lo), (qq_hi)) // Double (decimal) arg, eg. --foo=4.6 // XXX: there's not VG_BDBL_CLO because we don't have a good way of printing // floats at the moment! -#define VG_DBL_CLO(qq_arg, qq_option, qq_var) \ - (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \ - ({ \ - const HChar* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ - HChar* s; \ - double n = VG_(strtod)( val, &s ); \ - (qq_var) = n; \ - /* Check for non-numeralness */ \ - if ('\0' != s[0]) VG_(fmsg_bad_option)(qq_arg, \ - "Invalid floating point value '%s'\n",val); \ - True; \ - }) \ - ) +#define VG_DBL_CLOM(qq_mode, qq_arg, qq_option, qq_var) \ + (VG_(check_clom) \ + (qq_mode, qq_arg, qq_option, \ + VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) && \ + ({Bool res = True; \ + const HChar* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \ + HChar* s; \ + double n = VG_(strtod)( val, &s ); \ + (qq_var) = n; \ + /* Check for non-numeralness */ \ + if ('\0' != s[0]) { \ + VG_(fmsg_bad_option)(qq_arg, \ + "Invalid floating point value '%s'\n",val); \ + res = False; } \ + res;})) + +#define VG_DBL_CLO( qq_arg, qq_option, qq_var) \ + VG_DBL_CLOM(cloP, qq_arg, qq_option, qq_var) // Arg whose value is denoted by the exact presence of the given string; // if it matches, qq_var is assigned the value in qq_val. +#define VG_XACT_CLOM(qq_mode, qq_arg, qq_option, qq_var, qq_val) \ + (VG_(check_clom) \ + (qq_mode, qq_arg, qq_option, \ + VG_STREQ((qq_arg), (qq_option))) && \ + ({(qq_var) = (qq_val); \ + True; })) + #define VG_XACT_CLO(qq_arg, qq_option, qq_var, qq_val) \ - (VG_STREQ((qq_arg), (qq_option)) && \ - ({ \ - (qq_var) = (qq_val); \ - True; \ - }) \ - ) + VG_XACT_CLOM(cloP, qq_arg, qq_option, qq_var, qq_val) // 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, \ +#define VG_STRINDEX_CLOM(qq_mode, qq_arg, qq_option, qq_strings, qq_ix) \ + (VG_(check_clom) \ + (qq_mode, qq_arg, qq_option, \ + VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) && \ + ({Bool res = True; \ + 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; \ - }) \ - ) + res = False; \ + } \ + res; })) + +#define VG_STRINDEX_CLO(qq_arg, qq_option, qq_strings, qq_ix) \ + VG_STRINDEX_CLOM(cloP, qq_arg, qq_option, qq_strings, qq_ix) /* Verbosity level: 0 = silent, 1 (default), > 1 = more verbose. */ extern Int VG_(clo_verbosity); @@ -194,9 +299,7 @@ extern Int VG_(clo_verbosity); extern Bool VG_(clo_stats); /* wait for vgdb/gdb after reporting that amount of error. - Note that this is the initial value provided from the command line. - The real value is maintained in VG_(dyn_vgdb_error) and - can be changed dynamically.*/ + Note that this value can be changed dynamically. */ extern Int VG_(clo_vgdb_error); /* If user has provided the --vgdb-prefix command line option, @@ -223,13 +326,13 @@ extern VexRegisterUpdates VG_(clo_px_file_backed); extern Int VG_(clo_redzone_size); -typedef - enum { +typedef + enum { Vg_XTMemory_None, // Do not do any xtree memory profiling. Vg_XTMemory_Allocs, // Currently allocated size xtree memory profiling Vg_XTMemory_Full, // Full profiling : Current allocated size, total // allocated size, nr of blocks, total freed size, ... - } + } VgXTMemory; // Tools that replace malloc can optionally implement memory profiling // following the value of VG_(clo_xtree_profile_memory) to produce a report @@ -256,7 +359,7 @@ extern Bool VG_(clo_keep_debuginfo); /* Used to expand file names. "option_name" is the option name, eg. "--log-file". 'format' is what follows, eg. "cachegrind.out.%p". In - 'format': + 'format': - "%p" is replaced with PID. - "%q{QUAL}" is replaced with the environment variable $QUAL. If $QUAL isn't set, we abort. If the "{QUAL}" part is malformed, we abort. diff --git a/include/valgrind.h b/include/valgrind.h index 815efa8938..663d433b50 100644 --- a/include/valgrind.h +++ b/include/valgrind.h @@ -6154,6 +6154,10 @@ typedef command. */ VG_USERREQ__GDB_MONITOR_COMMAND = 0x1202, + /* Allows the client program to change a dynamic command line + option. */ + VG_USERREQ__CLO_CHANGE = 0x1203, + /* These are useful and can be interpreted by any tool that tracks malloc() et al, by using vg_replace_malloc.c. */ VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301, @@ -6636,6 +6640,14 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...) command, 0, 0, 0, 0) +/* Change the value of a dynamic command line option. + Note that unknown or not dynamically changeable options + will cause a warning message to be output. */ +#define VALGRIND_CLO_CHANGE(option) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CLO_CHANGE, \ + option, 0, 0, 0, 0) + + #undef PLAT_x86_darwin #undef PLAT_amd64_darwin #undef PLAT_x86_win32 diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c index 414446240d..6685dff6dd 100644 --- a/memcheck/mc_main.c +++ b/memcheck/mc_main.c @@ -5981,51 +5981,48 @@ static Bool mc_process_cmd_line_options(const HChar* arg) --track-origins=. Reject the case --undef-value-errors=no --track-origins=yes as meaningless. */ - if (0 == VG_(strcmp)(arg, "--undef-value-errors=no")) { - if (MC_(clo_mc_level) == 3) { - goto bad_level; + if VG_BOOL_CLO(arg, "--undef-value-errors", tmp_show) { + if (tmp_show) { + if (MC_(clo_mc_level) == 1) + MC_(clo_mc_level) = 2; } else { - MC_(clo_mc_level) = 1; - return True; + if (MC_(clo_mc_level) == 3) { + goto bad_level; + } else { + MC_(clo_mc_level) = 1; + } } } - if (0 == VG_(strcmp)(arg, "--undef-value-errors=yes")) { - if (MC_(clo_mc_level) == 1) - MC_(clo_mc_level) = 2; - return True; - } - if (0 == VG_(strcmp)(arg, "--track-origins=no")) { + else if VG_BOOL_CLO(arg, "--track-origins", tmp_show) { + if (tmp_show) { + if (MC_(clo_mc_level) == 1) { + goto bad_level; + } else { + MC_(clo_mc_level) = 3; + } + } else { if (MC_(clo_mc_level) == 3) MC_(clo_mc_level) = 2; - return True; - } - if (0 == VG_(strcmp)(arg, "--track-origins=yes")) { - if (MC_(clo_mc_level) == 1) { - goto bad_level; - } else { - MC_(clo_mc_level) = 3; - return True; } } - - if VG_BOOL_CLO(arg, "--partial-loads-ok", MC_(clo_partial_loads_ok)) {} - else if VG_USET_CLO(arg, "--errors-for-leak-kinds", - MC_(parse_leak_kinds_tokens), - MC_(clo_error_for_leak_kinds)) {} - else if VG_USET_CLO(arg, "--show-leak-kinds", - MC_(parse_leak_kinds_tokens), - MC_(clo_show_leak_kinds)) {} - else if VG_USET_CLO(arg, "--leak-check-heuristics", - MC_(parse_leak_heuristics_tokens), - MC_(clo_leak_check_heuristics)) {} - else if (VG_BOOL_CLO(arg, "--show-reachable", tmp_show)) { + else if VG_BOOL_CLO(arg, "--partial-loads-ok", MC_(clo_partial_loads_ok)) {} + else if VG_USET_CLOM(cloPD, arg, "--errors-for-leak-kinds", + MC_(parse_leak_kinds_tokens), + MC_(clo_error_for_leak_kinds)) {} + else if VG_USET_CLOM(cloPD, arg, "--show-leak-kinds", + MC_(parse_leak_kinds_tokens), + MC_(clo_show_leak_kinds)) {} + else if VG_USET_CLOM(cloPD, arg, "--leak-check-heuristics", + MC_(parse_leak_heuristics_tokens), + MC_(clo_leak_check_heuristics)) {} + else if (VG_BOOL_CLOM(cloPD, arg, "--show-reachable", tmp_show)) { if (tmp_show) { MC_(clo_show_leak_kinds) = MC_(all_Reachedness)(); } else { MC_(clo_show_leak_kinds) &= ~R2S(Reachable); } } - else if VG_BOOL_CLO(arg, "--show-possibly-lost", tmp_show) { + else if VG_BOOL_CLOM(cloPD, arg, "--show-possibly-lost", tmp_show) { if (tmp_show) { MC_(clo_show_leak_kinds) |= R2S(Possible); } else { @@ -6033,35 +6030,35 @@ static Bool mc_process_cmd_line_options(const HChar* arg) } } else if VG_BOOL_CLO(arg, "--workaround-gcc296-bugs", - MC_(clo_workaround_gcc296_bugs)) {} + MC_(clo_workaround_gcc296_bugs)) {} - else if VG_BINT_CLO(arg, "--freelist-vol", MC_(clo_freelist_vol), - 0, 10*1000*1000*1000LL) {} + else if VG_BINT_CLOM(cloPD, arg, "--freelist-vol", MC_(clo_freelist_vol), + 0, 10*1000*1000*1000LL) {} - else if VG_BINT_CLO(arg, "--freelist-big-blocks", - MC_(clo_freelist_big_blocks), - 0, 10*1000*1000*1000LL) {} + else if VG_BINT_CLOM(cloPD, arg, "--freelist-big-blocks", + MC_(clo_freelist_big_blocks), + 0, 10*1000*1000*1000LL) {} - else if VG_XACT_CLO(arg, "--leak-check=no", - MC_(clo_leak_check), LC_Off) {} - else if VG_XACT_CLO(arg, "--leak-check=summary", - MC_(clo_leak_check), LC_Summary) {} - else if VG_XACT_CLO(arg, "--leak-check=yes", - MC_(clo_leak_check), LC_Full) {} - else if VG_XACT_CLO(arg, "--leak-check=full", - MC_(clo_leak_check), LC_Full) {} + else if VG_XACT_CLOM(cloPD, arg, "--leak-check=no", + MC_(clo_leak_check), LC_Off) {} + else if VG_XACT_CLOM(cloPD, arg, "--leak-check=summary", + MC_(clo_leak_check), LC_Summary) {} + else if VG_XACT_CLOM(cloPD, arg, "--leak-check=yes", + MC_(clo_leak_check), LC_Full) {} + else if VG_XACT_CLOM(cloPD, arg, "--leak-check=full", + MC_(clo_leak_check), LC_Full) {} else if VG_XACT_CLO(arg, "--leak-resolution=low", - MC_(clo_leak_resolution), Vg_LowRes) {} + MC_(clo_leak_resolution), Vg_LowRes) {} else if VG_XACT_CLO(arg, "--leak-resolution=med", - MC_(clo_leak_resolution), Vg_MedRes) {} + MC_(clo_leak_resolution), Vg_MedRes) {} else if VG_XACT_CLO(arg, "--leak-resolution=high", - MC_(clo_leak_resolution), Vg_HighRes) {} + MC_(clo_leak_resolution), Vg_HighRes) {} - else if VG_STR_CLO(arg, "--ignore-ranges", tmp_str) { + else if VG_STR_CLOM(cloPD, arg, "--ignore-ranges", tmp_str) { Bool ok = parse_ignore_ranges(tmp_str); if (!ok) { - VG_(message)(Vg_DebugMsg, + VG_(message)(Vg_DebugMsg, "ERROR: --ignore-ranges: " "invalid syntax, or end <= start in range\n"); return False; @@ -6077,9 +6074,9 @@ static Bool mc_process_cmd_line_options(const HChar* arg) tl_assert(key_min <= key_max); UWord limit = 0x4000000; /* 64M - entirely arbitrary limit */ if (key_max - key_min > limit && val == IAR_CommandLine) { - VG_(message)(Vg_DebugMsg, + VG_(message)(Vg_DebugMsg, "ERROR: --ignore-ranges: suspiciously large range:\n"); - VG_(message)(Vg_DebugMsg, + VG_(message)(Vg_DebugMsg, " 0x%lx-0x%lx (size %lu)\n", key_min, key_max, key_max - key_min + 1); return False; @@ -6088,7 +6085,7 @@ static Bool mc_process_cmd_line_options(const HChar* arg) } } - else if VG_STR_CLO(arg, "--ignore-range-below-sp", tmp_str) { + else if VG_STR_CLOM(cloPD, arg, "--ignore-range-below-sp", tmp_str) { /* This seems at first a bit weird, but: in order to imply a non-wrapped-around address range, the first offset needs to be larger than the second one. For example @@ -6100,26 +6097,26 @@ static Bool mc_process_cmd_line_options(const HChar* arg) // Ensure we used all the text after the '=' sign. if (ok && *tmp_str != 0) ok = False; if (!ok) { - VG_(message)(Vg_DebugMsg, + VG_(message)(Vg_DebugMsg, "ERROR: --ignore-range-below-sp: invalid syntax. " " Expected \"...=decimalnumber-decimalnumber\".\n"); return False; - } + } if (offs1 > 1000*1000 /*arbitrary*/ || offs2 > 1000*1000 /*ditto*/) { - VG_(message)(Vg_DebugMsg, + VG_(message)(Vg_DebugMsg, "ERROR: --ignore-range-below-sp: suspiciously large " "offset(s): %u and %u\n", offs1, offs2); return False; } if (offs1 <= offs2) { - VG_(message)(Vg_DebugMsg, + VG_(message)(Vg_DebugMsg, "ERROR: --ignore-range-below-sp: invalid offsets " "(the first must be larger): %u and %u\n", offs1, offs2); return False; } tl_assert(offs1 > offs2); if (offs1 - offs2 > 4096 /*arbitrary*/) { - VG_(message)(Vg_DebugMsg, + VG_(message)(Vg_DebugMsg, "ERROR: --ignore-range-below-sp: suspiciously large " "range: %u-%u (size %u)\n", offs1, offs2, offs1 - offs2); return False; @@ -6144,8 +6141,8 @@ static Bool mc_process_cmd_line_options(const HChar* arg) else if VG_XACT_CLO(arg, "--keep-stacktraces=none", MC_(clo_keep_stacktraces), KS_none) {} - else if VG_BOOL_CLO(arg, "--show-mismatched-frees", - MC_(clo_show_mismatched_frees)) {} + else if VG_BOOL_CLOM(cloPD, arg, "--show-mismatched-frees", + MC_(clo_show_mismatched_frees)) {} else if VG_XACT_CLO(arg, "--expensive-definedness-checks=no", MC_(clo_expensive_definedness_checks), EdcNO) {} @@ -6168,6 +6165,7 @@ static Bool mc_process_cmd_line_options(const HChar* arg) bad_level: VG_(fmsg_bad_option)(arg, "--track-origins=yes has no effect when --undef-value-errors=no.\n"); + return False; } static void mc_print_usage(void) diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am index 70b8adaf65..84b2a81cea 100644 --- a/memcheck/tests/Makefile.am +++ b/memcheck/tests/Makefile.am @@ -204,6 +204,7 @@ EXTRA_DIST = \ mismatches.stderr.exp mismatches.vgtest \ mmaptest.stderr.exp mmaptest.vgtest \ nanoleak_supp.stderr.exp nanoleak_supp.vgtest nanoleak.supp \ + nanoleak_dynsupp.stderr.exp nanoleak_dynsupp.vgtest \ nanoleak2.stderr.exp nanoleak2.vgtest \ new_nothrow.stderr.exp new_nothrow.vgtest \ new_override.stderr.exp new_override.stdout.exp new_override.vgtest \ diff --git a/memcheck/tests/nanoleak_dynsupp.stderr.exp b/memcheck/tests/nanoleak_dynsupp.stderr.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/memcheck/tests/nanoleak_dynsupp.vgtest b/memcheck/tests/nanoleak_dynsupp.vgtest new file mode 100644 index 0000000000..4765d07da7 --- /dev/null +++ b/memcheck/tests/nanoleak_dynsupp.vgtest @@ -0,0 +1,2 @@ +vgopts: --leak-check=yes -q +prog: nanoleak_supp nanoleak.supp diff --git a/memcheck/tests/nanoleak_supp.c b/memcheck/tests/nanoleak_supp.c index 7f5b0ee80a..d54e13c333 100644 --- a/memcheck/tests/nanoleak_supp.c +++ b/memcheck/tests/nanoleak_supp.c @@ -1,8 +1,13 @@ - +#include "../include/valgrind.h" #include - -int main ( void ) +#include +int main ( int argc, char** argv ) { + if (argc > 1) { + char option[200]; + sprintf(option, "--suppressions=%s", argv[1]); + VALGRIND_CLO_CHANGE(option); + } volatile int* a = malloc(1000); a[0] = 0; return a[0]; diff --git a/none/tests/cmdline1.stdout.exp b/none/tests/cmdline1.stdout.exp index 3855a033b9..4b98743a66 100644 --- a/none/tests/cmdline1.stdout.exp +++ b/none/tests/cmdline1.stdout.exp @@ -6,6 +6,7 @@ usage: valgrind [options] prog-and-args basic user options for all Valgrind tools, with defaults in [ ]: -h --help show this message --help-debug show this message, plus debugging options + --help-dyn-options show the dynamically changeable options --version show version -q --quiet run silently; only print error msgs -v --verbose be more verbose -- show misc extra info diff --git a/none/tests/cmdline2.stdout.exp b/none/tests/cmdline2.stdout.exp index 0d270390f5..cfa3060525 100644 --- a/none/tests/cmdline2.stdout.exp +++ b/none/tests/cmdline2.stdout.exp @@ -6,6 +6,7 @@ usage: valgrind [options] prog-and-args basic user options for all Valgrind tools, with defaults in [ ]: -h --help show this message --help-debug show this message, plus debugging options + --help-dyn-options show the dynamically changeable options --version show version -q --quiet run silently; only print error msgs -v --verbose be more verbose -- show misc extra info -- 2.47.2