diff --git a/coregrind/m_errormgr.c b/coregrind/m_errormgr.c index df05c20e2..79b2d15a3 100644 --- a/coregrind/m_errormgr.c +++ b/coregrind/m_errormgr.c @@ -251,11 +251,18 @@ static Bool eq_Error ( VgRes res, Error* e1, Error* e2 ) static void pp_Error ( Error* err, Bool printCount ) { - if (printCount) - VG_(message)(Vg_UserMsg, "Observed %d times:", err->count ); - if (err->tid > 0 && err->tid != last_tid_printed) { - VG_(message)(Vg_UserMsg, "Thread %d:", err->tid ); - last_tid_printed = err->tid; + if (VG_(clo_xml)) { + VG_(message)(Vg_UserMsg, ""); + VG_(message)(Vg_UserMsg, " %d", err->tid); + } + + if (!VG_(clo_xml)) { + if (printCount) + VG_(message)(Vg_UserMsg, "Observed %d times:", err->count ); + if (err->tid > 0 && err->tid != last_tid_printed) { + VG_(message)(Vg_UserMsg, "Thread %d:", err->tid ); + last_tid_printed = err->tid; + } } switch (err->ekind) { @@ -274,6 +281,9 @@ static void pp_Error ( Error* err, Bool printCount ) VG_(tool_panic)("unhandled error type"); } } + + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, ""); } /* Figure out if we want to perform a given action for this error, possibly @@ -629,6 +639,31 @@ Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, Char* s, /*--- Exported fns ---*/ /*------------------------------------------------------------*/ +/* Show the used suppressions. Returns False if no suppression + got used. */ +static Bool show_used_suppressions ( void ) +{ + Supp *su; + Bool any_supp; + + any_supp = False; + for (su = suppressions; su != NULL; su = su->next) { + if (su->count <= 0) + continue; + any_supp = True; + if (VG_(clo_xml)) { + VG_(message)(Vg_DebugMsg, + "%d%s", + su->count, su->sname); + } else { + VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count, su->sname); + } + } + + return any_supp; +} + + /* This is called not from generated code but from the scheduler */ void VG_(show_all_errors) ( void ) { @@ -652,6 +687,15 @@ void VG_(show_all_errors) ( void ) if (su->count > 0) n_supp_contexts++; } + + /* If we're printing XML, just show the suppressions and stop. + */ + if (VG_(clo_xml)) { + (void)show_used_suppressions(); + return; + } + + /* We only get here if not printing XML. */ VG_(message)(Vg_UserMsg, "ERROR SUMMARY: " "%d errors from %d contexts (suppressed: %d from %d)", @@ -691,13 +735,7 @@ void VG_(show_all_errors) ( void ) if (n_supp_contexts > 0) VG_(message)(Vg_DebugMsg, ""); - any_supp = False; - for (su = suppressions; su != NULL; su = su->next) { - if (su->count > 0) { - any_supp = True; - VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count, su->sname); - } - } + any_supp = show_used_suppressions(); if (n_err_contexts > 0) { if (any_supp) diff --git a/coregrind/m_options.c b/coregrind/m_options.c index 154cfbf6b..40f22512a 100644 --- a/coregrind/m_options.c +++ b/coregrind/m_options.c @@ -43,6 +43,7 @@ Char* VG_(clo_db_command) = GDB_PATH " -nw %f %p"; Int VG_(clo_gen_suppressions) = 0; Int VG_(clo_sanity_level) = 1; Int VG_(clo_verbosity) = 1; +Bool VG_(clo_xml) = False; Bool VG_(clo_demangle) = True; Bool VG_(clo_trace_children) = False; Int VG_(clo_log_fd) = 2; diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c index 2c56d6677..7dab5bed3 100644 --- a/coregrind/m_stacktrace.c +++ b/coregrind/m_stacktrace.c @@ -191,14 +191,26 @@ static void printIpDesc(UInt n, Addr ip) static UChar buf[VG_ERRTXT_LEN]; VG_(describe_IP)(ip, buf, VG_ERRTXT_LEN); - VG_(message)(Vg_UserMsg, " %s %s", ( n == 0 ? "at" : "by" ), buf); + + if (VG_(clo_xml)) { + VG_(message)(Vg_UserMsg, " %s", buf); + } else { + VG_(message)(Vg_UserMsg, " %s %s", ( n == 0 ? "at" : "by" ), buf); + } } /* Print a StackTrace. */ void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips ) { vg_assert( n_ips > 0 ); + + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, " "); + VG_(apply_StackTrace)( printIpDesc, ips, n_ips ); + + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, " "); } /* Get and immediately print a StackTrace. */ diff --git a/coregrind/m_translate.c b/coregrind/m_translate.c index fd5b286ab..ee20139a8 100644 --- a/coregrind/m_translate.c +++ b/coregrind/m_translate.c @@ -407,7 +407,7 @@ Bool VG_(translate) ( ThreadId tid, ok = VG_(get_fnname_w_offset)(redir, name2, 64); if (!ok) VG_(strcpy)(name2, "???"); VG_(message)(Vg_DebugMsg, - "TRANSLATE: 0x%llx (%s) redirected to 0x%llx (%s)", + "REDIR: 0x%llx (%s) redirected to 0x%llx (%s)", orig_addr, name1, redir, name2 ); } diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c index 23450d818..4120180a7 100644 --- a/coregrind/vg_main.c +++ b/coregrind/vg_main.c @@ -1392,6 +1392,12 @@ static void as_closepadfile(int padfile) vg_assert(0 == res); } +/*====================================================================*/ +/*=== Command-line: variables, processing, etc ===*/ +/*====================================================================*/ + +// See pub_{core,tool}_options.h for explanations of all these. + static void usage ( Bool debug_help ) { Char* usage1 = @@ -1404,6 +1410,7 @@ static void usage ( Bool debug_help ) " --version show version\n" " -q --quiet run silently; only print error msgs\n" " -v --verbose be more verbose, incl counts of errors\n" +" --xml=yes show errors as XML\n" " --trace-children=no|yes Valgrind-ise child processes? [no]\n" " --track-fds=no|yes track open file descriptors? [no]\n" " --time-stamp=no|yes add timestamps to log messages? [no]\n" @@ -1627,6 +1634,7 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname ) /* do nothing */ } + else VG_BOOL_CLO(arg, "--xml", VG_(clo_xml)) else VG_BOOL_CLO(arg, "--branchpred", VG_(clo_branchpred)) else VG_BOOL_CLO(arg, "--db-attach", VG_(clo_db_attach)) else VG_BOOL_CLO(arg, "--demangle", VG_(clo_demangle)) @@ -1798,6 +1806,29 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname ) VG_(bad_option)("--gen-suppressions="); } + /* 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. */ + if (VG_(clo_xml)) { + /* Disable suppression generation (requires user input) */ + VG_(clo_gen_suppressions) = 0; + /* Disable attaching to GDB (requires user input) */ + VG_(clo_db_attach) = False; + /* Set a known verbosity level */ + VG_(clo_verbosity) = 1; + /* Disable error limits (this might be a bad idea!) */ + VG_(clo_error_limit) = False; + /* Disable emulation warnings */ + VG_(clo_show_emwarns) = False; + /* Disable waiting for GDB to debug Valgrind */ + VG_(clo_wait_for_gdb) = False; + /* No file-descriptor leak checking yet */ + VG_(clo_track_fds) = False; + /* Also, we want to set options for the leak checker, but that + will have to be done in Memcheck's flag-handling code, not + here. */ + } + /* All non-logging-related options have been checked. If the logging option specified is ok, we can switch to it, as we know we won't have to generate any other command-line-related error messages. @@ -1914,6 +1945,16 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname ) } } + + /* Check that the requested tool actually supports XML output. */ + if (VG_(clo_xml) && 0 != VG_(strcmp)(toolname, "memcheck")) { + VG_(clo_xml) = False; + VG_(message)(Vg_UserMsg, + "Currently only Memcheck supports XML output."); + VG_(bad_option)("--xml=yes"); + /*NOTREACHED*/ + } + // Move log_fd into the safe range, so it doesn't conflict with any app fds. // XXX: this is more or less duplicating the behaviour of the calls to // VG_(safe_fd)() above, although this does not close the original fd. @@ -1932,27 +1973,43 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname ) command line args, to help people trying to interpret the results of a run which encompasses multiple processes. */ + if (VG_(clo_xml)) { + VG_(message)(Vg_UserMsg, ""); + VG_(message)(Vg_UserMsg, ""); + VG_(message)(Vg_UserMsg, ""); + VG_(message)(Vg_UserMsg, "1"); + VG_(message)(Vg_UserMsg, ""); + } + + HChar* xpre = VG_(clo_xml) ? "" : ""; + HChar* xpost = VG_(clo_xml) ? "" : ""; + if (VG_(clo_verbosity > 0)) { /* Tool details */ - VG_(message)(Vg_UserMsg, "%s%s%s, %s.", + VG_(message)(Vg_UserMsg, "%s%s%s%s, %s.%s", + xpre, VG_(details).name, NULL == VG_(details).version ? "" : "-", NULL == VG_(details).version ? (Char*)"" : VG_(details).version, - VG_(details).description); - VG_(message)(Vg_UserMsg, "%s", VG_(details).copyright_author); + VG_(details).description, + xpost); + VG_(message)(Vg_UserMsg, "%s%s%s", + xpre, VG_(details).copyright_author, xpost); /* Core details */ VG_(message)(Vg_UserMsg, - "Using LibVEX rev %s, a library for dynamic binary translation.", - LibVEX_Version() ); + "%sUsing LibVEX rev %s, a library for dynamic binary translation.%s", + xpre, LibVEX_Version(), xpost ); VG_(message)(Vg_UserMsg, - "Copyright (C) 2004-2005, and GNU GPL'd, by OpenWorks LLP."); + "%sCopyright (C) 2004-2005, and GNU GPL'd, by OpenWorks LLP.%s", + xpre, xpost ); VG_(message)(Vg_UserMsg, - "Using valgrind-%s, a dynamic binary instrumentation framework.", - VERSION); + "%sUsing valgrind-%s, a dynamic binary instrumentation framework.%s", + xpre, VERSION, xpost); VG_(message)(Vg_UserMsg, - "Copyright (C) 2000-2005, and GNU GPL'd, by Julian Seward et al."); + "%sCopyright (C) 2000-2005, and GNU GPL'd, by Julian Seward et al.%s", + xpre, xpost ); } if (VG_(clo_verbosity) > 0 && log_to != VgLogTo_Fd) { @@ -1963,6 +2020,17 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname ) for (i = 0; i < VG_(client_argc); i++) VG_(message)(Vg_UserMsg, " %s", VG_(client_argv)[i]); } + else + if (VG_(clo_xml)) { + VG_(message)(Vg_UserMsg, ""); + VG_(message)(Vg_UserMsg, "%d", VG_(getpid)()); + VG_(message)(Vg_UserMsg, "%d", VG_(getppid)()); + VG_(message)(Vg_UserMsg, ""); + VG_(message)(Vg_UserMsg, ""); + for (i = 0; i < VG_(client_argc); i++) + VG_(message)(Vg_UserMsg, " %s", VG_(client_argv)[i]); + VG_(message)(Vg_UserMsg, ""); + } if (VG_(clo_verbosity) > 1) { Int fd; @@ -1983,7 +2051,7 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname ) if (fd < 0) { VG_(message)(Vg_DebugMsg, " can't open /proc/version"); } else { - #define BUF_LEN 256 +# define BUF_LEN 256 Char version_buf[BUF_LEN]; Int n = VG_(read) ( fd, version_buf, BUF_LEN ); vg_assert(n <= BUF_LEN); @@ -1994,7 +2062,7 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname ) VG_(message)(Vg_DebugMsg, " (empty?)"); } VG_(close)(fd); - #undef BUF_LEN +# undef BUF_LEN } } @@ -2291,8 +2359,10 @@ void VG_(sanity_check_general) ( Bool force_expensive ) remains = VGA_(stack_unused)(tid); if (remains < VKI_PAGE_SIZE) - VG_(message)(Vg_DebugMsg, "WARNING: Thread %d is within %d bytes of running out of stack!", - tid, remains); + VG_(message)(Vg_DebugMsg, + "WARNING: Thread %d is within %d bytes " + "of running out of stack!", + tid, remains); } /* @@ -2726,7 +2796,7 @@ int main(int argc, char **argv, char **envp) // Verbosity message // p: end_rdtsc_calibration [so startup message is printed first] //-------------------------------------------------------------- - if (VG_(clo_verbosity) == 1) + if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) VG_(message)(Vg_UserMsg, "For more details, rerun with: -v"); if (VG_(clo_verbosity) > 0) VG_(message)(Vg_UserMsg, ""); @@ -2745,6 +2815,11 @@ int main(int argc, char **argv, char **envp) vg_assert(VG_(master_tid) == 1); + if (VG_(clo_xml)) { + VG_(message)(Vg_UserMsg, "RUNNING"); + VG_(message)(Vg_UserMsg, ""); + } + VG_(debugLog)(1, "main", "Running thread 1\n"); VGA_(main_thread_wrapper)(1); @@ -2780,6 +2855,11 @@ void VG_(shutdown_actions)(ThreadId tid) if (VG_(clo_verbosity) > 0) VG_(message)(Vg_UserMsg, ""); + if (VG_(clo_xml)) { + VG_(message)(Vg_UserMsg, "FINISHED"); + VG_(message)(Vg_UserMsg, ""); + } + /* Print out file descriptor summary and stats. */ if (VG_(clo_track_fds)) VG_(show_open_fds)(); @@ -2789,6 +2869,12 @@ void VG_(shutdown_actions)(ThreadId tid) VG_TDICT_CALL(tool_fini, 0/*exitcode*/); + if (VG_(clo_xml)) { + VG_(message)(Vg_UserMsg, ""); + VG_(message)(Vg_UserMsg, ""); + VG_(message)(Vg_UserMsg, ""); + } + VG_(sanity_check_general)( True /*include expensive checks*/ ); if (VG_(clo_verbosity) > 1) diff --git a/coregrind/vg_messages.c b/coregrind/vg_messages.c index ad5928f3d..fe4004c2e 100644 --- a/coregrind/vg_messages.c +++ b/coregrind/vg_messages.c @@ -59,7 +59,9 @@ UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs ) // Print the message count = 0; - count += VG_(printf) ("%s%c%c", pfx_s, c,c); + + if (!VG_(clo_xml)) + count += VG_(printf) ("%s%c%c", pfx_s, c,c); if (VG_(clo_time_stamp)) { struct timeval tv; @@ -75,7 +77,9 @@ UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs ) } } - count += VG_(printf) ("%d%c%c ", VG_(getpid)(), c,c); + if (!VG_(clo_xml)) + count += VG_(printf) ("%d%c%c ", VG_(getpid)(), c,c); + count += VG_(vprintf)(format, vargs); count += VG_(printf) ("\n"); return count; diff --git a/coregrind/vg_symtab2.c b/coregrind/vg_symtab2.c index a05f1308a..eb6a3f3a8 100644 --- a/coregrind/vg_symtab2.c +++ b/coregrind/vg_symtab2.c @@ -2436,7 +2436,7 @@ Char* VG_(describe_IP)(Addr eip, Char* buf, Int n_buf) buf[n] = '\0'; \ } UInt lineno; - UChar ibuf[20]; + UChar ibuf[50]; UInt n = 0; static UChar buf_fn[VG_ERRTXT_LEN]; static UChar buf_obj[VG_ERRTXT_LEN]; @@ -2445,29 +2445,62 @@ Char* VG_(describe_IP)(Addr eip, Char* buf, Int n_buf) Bool know_objname = VG_(get_objname)(eip, buf_obj, VG_ERRTXT_LEN); Bool know_srcloc = VG_(get_filename_linenum)(eip, buf_srcloc, VG_ERRTXT_LEN, &lineno); - VG_(sprintf)(ibuf,"0x%llx: ", (ULong)eip); - APPEND(ibuf); - if (know_fnname) { - APPEND(buf_fn); - if (!know_srcloc && know_objname) { - APPEND(" (in "); + + if (VG_(clo_xml)) { + + /* Print in XML format, dumping in as much info as we know. */ + APPEND(""); + VG_(sprintf)(ibuf,"0x%llx", (ULong)eip); + APPEND(ibuf); + if (know_objname) { + APPEND(""); + APPEND(buf_obj); + APPEND(""); + } + if (know_fnname) { + APPEND(""); + APPEND(buf_fn); + APPEND(""); + } + if (know_srcloc) { + APPEND(""); + APPEND(buf_srcloc); + APPEND(""); + APPEND(""); + VG_(sprintf)(ibuf,"%d",lineno); + APPEND(ibuf); + APPEND(""); + } + APPEND(""); + + } else { + + /* Print for humans to read */ + VG_(sprintf)(ibuf,"0x%llx: ", (ULong)eip); + APPEND(ibuf); + if (know_fnname) { + APPEND(buf_fn); + if (!know_srcloc && know_objname) { + APPEND(" (in "); + APPEND(buf_obj); + APPEND(")"); + } + } else if (know_objname && !know_srcloc) { + APPEND("(within "); APPEND(buf_obj); APPEND(")"); + } else { + APPEND("???"); } - } else if (know_objname && !know_srcloc) { - APPEND("(within "); - APPEND(buf_obj); - APPEND(")"); - } else { - APPEND("???"); - } - if (know_srcloc) { - APPEND(" ("); - APPEND(buf_srcloc); - APPEND(":"); - VG_(sprintf)(ibuf,"%d",lineno); - APPEND(ibuf); - APPEND(")"); + if (know_srcloc) { + APPEND(" ("); + APPEND(buf_srcloc); + APPEND(":"); + VG_(sprintf)(ibuf,"%d",lineno); + APPEND(ibuf); + APPEND(")"); + } + } return buf; diff --git a/include/pub_tool_options.h b/include/pub_tool_options.h index e321635bb..e27e158a9 100644 --- a/include/pub_tool_options.h +++ b/include/pub_tool_options.h @@ -61,10 +61,15 @@ } /* Verbosity level: 0 = silent, 1 (default), > 1 = more verbose. */ -extern Int VG_(clo_verbosity); +extern Int VG_(clo_verbosity); -/* Profile? */ -extern Bool VG_(clo_profile); +/* Profile? default: NO */ +extern Bool VG_(clo_profile); + +/* Emit all messages as XML? default: NO */ +/* If clo_xml is set, various other options are set in a non-default + way. See vg_main.c and mc_main.c. */ +extern Bool VG_(clo_xml); /* Call this if a recognised option was bad for some reason. Note: don't use it just because an option was unrecognised -- return 'False' diff --git a/memcheck/mac_leakcheck.c b/memcheck/mac_leakcheck.c index 38e6d49dd..d97730de5 100644 --- a/memcheck/mac_leakcheck.c +++ b/memcheck/mac_leakcheck.c @@ -184,40 +184,79 @@ static SizeT lc_scanned; static Bool (*lc_is_within_valid_secondary) (Addr addr); static Bool (*lc_is_valid_aligned_word) (Addr addr); -static const Char *str_lossmode(Reachedness lossmode) +static const HChar* str_lossmode ( Reachedness lossmode ) { - const Char *loss = "?"; - - switch(lossmode) { - case Unreached: loss = "definitely lost"; break; - case IndirectLeak: loss = "indirectly lost"; break; - case Interior: loss = "possibly lost"; break; - case Proper: loss = "still reachable"; break; + const HChar *loss = "?"; + switch (lossmode) { + case Unreached: loss = "definitely lost"; break; + case IndirectLeak: loss = "indirectly lost"; break; + case Interior: loss = "possibly lost"; break; + case Proper: loss = "still reachable"; break; } - return loss; } +static const HChar* xml_kind ( Reachedness lossmode ) +{ + const HChar *loss = "?"; + switch (lossmode) { + case Unreached: loss = "Leak_DefinitelyLost"; break; + case IndirectLeak: loss = "Leak_IndirectlyLost"; break; + case Interior: loss = "Leak_PossiblyLost"; break; + case Proper: loss = "Leak_StillReachable"; break; + } + return loss; +} + + /* Used for printing leak errors, avoids exposing the LossRecord type (which comes in as void*, requiring a cast. */ void MAC_(pp_LeakError)(void* vextra) { + HChar* xpre = VG_(clo_xml) ? " " : ""; + HChar* xpost = VG_(clo_xml) ? "" : ""; + LeakExtra* extra = (LeakExtra*)vextra; LossRecord* l = extra->lossRecord; const Char *loss = str_lossmode(l->loss_mode); - VG_(message)(Vg_UserMsg, ""); + if (VG_(clo_xml)) { + VG_(message)(Vg_UserMsg, " %s", xml_kind(l->loss_mode)); + } else { + VG_(message)(Vg_UserMsg, ""); + } + if (l->indirect_bytes) { VG_(message)(Vg_UserMsg, - "%d (%d direct, %d indirect) bytes in %d blocks are %s in loss record %d of %d", - l->total_bytes + l->indirect_bytes, - l->total_bytes, l->indirect_bytes, l->num_blocks, - loss, extra->n_this_record, extra->n_total_records); + "%s%d (%d direct, %d indirect) bytes in %d blocks" + " are %s in loss record %d of %d%s", + xpre, + l->total_bytes + l->indirect_bytes, + l->total_bytes, l->indirect_bytes, l->num_blocks, + loss, extra->n_this_record, extra->n_total_records, + xpost + ); + if (VG_(clo_xml)) { + VG_(message)(Vg_UserMsg, " %d", + l->total_bytes + l->indirect_bytes); + VG_(message)(Vg_UserMsg, " %d", + l->num_blocks); + } } else { - VG_(message)(Vg_UserMsg, - "%d bytes in %d blocks are %s in loss record %d of %d", - l->total_bytes, l->num_blocks, - loss, extra->n_this_record, extra->n_total_records); + VG_(message)( + Vg_UserMsg, + "%s%d bytes in %d blocks are %s in loss record %d of %d%s", + xpre, + l->total_bytes, l->num_blocks, + loss, extra->n_this_record, extra->n_total_records, + xpost + ); + if (VG_(clo_xml)) { + VG_(message)(Vg_UserMsg, " %d", + l->total_bytes); + VG_(message)(Vg_UserMsg, " %d", + l->num_blocks); + } } VG_(pp_ExeContext)(l->allocated_at); } @@ -612,14 +651,14 @@ void MAC_(do_detect_memory_leaks) ( if (lc_n_shadows == 0) { tl_assert(lc_shadows == NULL); - if (VG_(clo_verbosity) >= 1) { + if (VG_(clo_verbosity) >= 1 && !VG_(clo_xml)) { VG_(message)(Vg_UserMsg, "No malloc'd blocks -- no leaks are possible."); } return; } - if (VG_(clo_verbosity) > 0) + if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) VG_(message)(Vg_UserMsg, "searching for pointers to %d not-freed blocks.", lc_n_shadows ); @@ -650,7 +689,7 @@ void MAC_(do_detect_memory_leaks) ( /* Keep walking the heap until everything is found */ lc_do_leakcheck(-1); - if (VG_(clo_verbosity) > 0) + if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) VG_(message)(Vg_UserMsg, "checked %d bytes.", lc_scanned); blocks_leaked = MAC_(bytes_leaked) = 0; @@ -664,7 +703,7 @@ void MAC_(do_detect_memory_leaks) ( else make_summary(); - if (VG_(clo_verbosity) > 0) { + if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) { VG_(message)(Vg_UserMsg, ""); VG_(message)(Vg_UserMsg, "LEAK SUMMARY:"); VG_(message)(Vg_UserMsg, " definitely lost: %d bytes in %d blocks.", diff --git a/memcheck/mac_malloc_wrappers.c b/memcheck/mac_malloc_wrappers.c index 8119a02cd..21672934f 100644 --- a/memcheck/mac_malloc_wrappers.c +++ b/memcheck/mac_malloc_wrappers.c @@ -549,6 +549,8 @@ void MAC_(print_malloc_stats) ( void ) if (VG_(clo_verbosity) == 0) return; + if (VG_(clo_xml)) + return; /* Count memory still in use. */ VG_(HT_apply_to_all_nodes)(MAC_(malloc_list), malloc_stats_count_chunk, &ms); diff --git a/memcheck/mac_shared.c b/memcheck/mac_shared.c index 2fc4b3191..bcd440a74 100644 --- a/memcheck/mac_shared.c +++ b/memcheck/mac_shared.c @@ -222,23 +222,27 @@ Bool MAC_(eq_Error) ( VgRes res, Error* e1, Error* e2 ) void MAC_(pp_AddrInfo) ( Addr a, AddrInfo* ai ) { + HChar* xpre = VG_(clo_xml) ? " " : " "; + HChar* xpost = VG_(clo_xml) ? "" : ""; + switch (ai->akind) { case Stack: VG_(message)(Vg_UserMsg, - " Address 0x%lx is on thread %d's stack", - (ULong)a, ai->stack_tid); + "%sAddress 0x%llx is on thread %d's stack%s", + xpre, (ULong)a, ai->stack_tid, xpost); break; case Unknown: if (ai->maybe_gcc) { VG_(message)(Vg_UserMsg, - " Address 0x%lx is just below %%esp. Possibly a bug in GCC/G++", - (ULong)a); - VG_(message)(Vg_UserMsg, - " v 2.96 or 3.0.X. To suppress, use: --workaround-gcc296-bugs=yes"); + "%sAddress 0x%llx is just below the stack ptr. " + "To suppress, use: --workaround-gcc296-bugs=yes%s", + xpre, (ULong)a, xpost + ); } else { VG_(message)(Vg_UserMsg, - " Address 0x%lx is not stack'd, malloc'd or (recently) free'd", - (ULong)a); + "%sAddress 0x%llx " + "is not stack'd, malloc'd or (recently) free'd%s", + xpre, (ULong)a, xpost); } break; case Freed: case Mallocd: case UserG: case Mempool: { @@ -264,12 +268,14 @@ void MAC_(pp_AddrInfo) ( Addr a, AddrInfo* ai ) relative = "inside"; } VG_(message)(Vg_UserMsg, - " Address 0x%lx is %llu bytes %s a %s of size %d %s", + "%sAddress 0x%llx is %llu bytes %s a %s of size %d %s%s", + xpre, (ULong)a, (ULong)delta, relative, kind, ai->blksize, ai->akind==Mallocd ? "alloc'd" : ai->akind==Freed ? "free'd" - : "client-defined"); + : "client-defined", + xpost); VG_(pp_ExeContext)(ai->lastchange); break; } @@ -288,14 +294,26 @@ void MAC_(pp_shared_Error) ( Error* err ) { MAC_Error* err_extra = VG_(get_error_extra)(err); + HChar* xpre = VG_(clo_xml) ? " " : ""; + HChar* xpost = VG_(clo_xml) ? "" : ""; + switch (VG_(get_error_kind)(err)) { case FreeErr: - VG_(message)(Vg_UserMsg, "Invalid free() / delete / delete[]"); - /* fall through */ + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, " InvalidFree"); + VG_(message)(Vg_UserMsg, + "%sInvalid free() / delete / delete[]%s", + xpre, xpost); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + MAC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo); + break; + case FreeMismatchErr: - if (VG_(get_error_kind)(err) == FreeMismatchErr) - VG_(message)(Vg_UserMsg, - "Mismatched free() / delete / delete []"); + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, " MismatchedFree"); + VG_(message)(Vg_UserMsg, + "%sMismatched free() / delete / delete []%s", + xpre, xpost); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); MAC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo); break; @@ -303,16 +321,26 @@ void MAC_(pp_shared_Error) ( Error* err ) case AddrErr: switch (err_extra->axskind) { case ReadAxs: - VG_(message)(Vg_UserMsg, "Invalid read of size %d", - err_extra->size ); + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, " InvalidRead"); + VG_(message)(Vg_UserMsg, + "%sInvalid read of size %d%s", + xpre, err_extra->size, xpost ); break; case WriteAxs: - VG_(message)(Vg_UserMsg, "Invalid write of size %d", - err_extra->size ); + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, " InvalidWrite"); + VG_(message)(Vg_UserMsg, + "%sInvalid write of size %d%s", + xpre, err_extra->size, xpost ); break; case ExecAxs: - VG_(message)(Vg_UserMsg, "Jump to the invalid address " - "stated on the next line"); + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, " InvalidJump"); + VG_(message)(Vg_UserMsg, + "%sJump to the invalid address " + "stated on the next line%s", + xpre, xpost); break; default: VG_(tool_panic)("MAC_(pp_shared_Error)(axskind)"); @@ -323,16 +351,22 @@ void MAC_(pp_shared_Error) ( Error* err ) case OverlapErr: { OverlapExtra* ov_extra = (OverlapExtra*)VG_(get_error_extra)(err); + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, " Overlap"); if (ov_extra->len == -1) VG_(message)(Vg_UserMsg, - "Source and destination overlap in %s(%p, %p)", + "%sSource and destination overlap in %s(%p, %p)%s", + xpre, VG_(get_error_string)(err), - ov_extra->dst, ov_extra->src); + ov_extra->dst, ov_extra->src, + xpost); else VG_(message)(Vg_UserMsg, - "Source and destination overlap in %s(%p, %p, %d)", + "%sSource and destination overlap in %s(%p, %p, %d)%s", + xpre, VG_(get_error_string)(err), - ov_extra->dst, ov_extra->src, ov_extra->len); + ov_extra->dst, ov_extra->src, ov_extra->len, + xpost); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); break; } @@ -342,7 +376,10 @@ void MAC_(pp_shared_Error) ( Error* err ) } case IllegalMempoolErr: - VG_(message)(Vg_UserMsg, "Illegal memory pool address"); + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, " InvalidMemPool"); + VG_(message)(Vg_UserMsg, "%sIllegal memory pool address%s", + xpre, xpost); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); MAC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo); break; @@ -860,7 +897,7 @@ void MAC_(common_fini)(void (*leak_check)(ThreadId tid, LeakCheckMode mode)) { MAC_(print_malloc_stats)(); - if (VG_(clo_verbosity) == 1) { + if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) { if (MAC_(clo_leak_check) == LC_Off) VG_(message)(Vg_UserMsg, "For a detailed leak analysis, rerun with: --leak-check=yes"); diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c index d28c91fa1..32442142b 100644 --- a/memcheck/mc_main.c +++ b/memcheck/mc_main.c @@ -1313,11 +1313,18 @@ static void mc_pp_Error ( Error* err ) { MAC_Error* err_extra = VG_(get_error_extra)(err); + HChar* xpre = VG_(clo_xml) ? " " : ""; + HChar* xpost = VG_(clo_xml) ? "" : ""; + switch (VG_(get_error_kind)(err)) { case CoreMemErr: { Char* s = ( err_extra->isUnaddr ? "unaddressable" : "uninitialised" ); - VG_(message)(Vg_UserMsg, "%s contains %s byte(s)", - VG_(get_error_string)(err), s); + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, " CoreMemError"); + /* What the hell *is* a CoreMemError? jrs 2005-May-18 */ + VG_(message)(Vg_UserMsg, "%s%s contains %s byte(s)%s", + xpre, VG_(get_error_string)(err), s, xpost); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); break; @@ -1325,12 +1332,17 @@ static void mc_pp_Error ( Error* err ) case ValueErr: if (err_extra->size == 0) { - VG_(message)(Vg_UserMsg, - "Conditional jump or move depends on uninitialised value(s)"); + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, " UninitCondition"); + VG_(message)(Vg_UserMsg, "%sConditional jump or move depends" + " on uninitialised value(s)%s", + xpre, xpost); } else { - VG_(message)(Vg_UserMsg, - "Use of uninitialised value of size %d", - err_extra->size); + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, " UninitValue"); + VG_(message)(Vg_UserMsg, + "%sUse of uninitialised value of size %d%s", + xpre, err_extra->size, xpost); } VG_(pp_ExeContext)( VG_(get_error_where)(err) ); break; @@ -1341,8 +1353,10 @@ static void mc_pp_Error ( Error* err ) Char* s2 = ( err_extra->isUnaddr ? "unaddressable" : "uninitialised" ); if (isReg) tl_assert(!err_extra->isUnaddr); - VG_(message)(Vg_UserMsg, "Syscall param %s %s %s byte(s)", - VG_(get_error_string)(err), s1, s2); + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, " SyscallParam"); + VG_(message)(Vg_UserMsg, "%sSyscall param %s %s %s byte(s)%s", + xpre, VG_(get_error_string)(err), s1, s2, xpost); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); MAC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo); @@ -1351,8 +1365,11 @@ static void mc_pp_Error ( Error* err ) case UserErr: { Char* s = ( err_extra->isUnaddr ? "Unaddressable" : "Uninitialised" ); + if (VG_(clo_xml)) + VG_(message)(Vg_UserMsg, " ClientCheck"); VG_(message)(Vg_UserMsg, - "%s byte(s) found during client check request", s); + "%s%s byte(s) found during client check request%s", + xpre, s, xpost); VG_(pp_ExeContext)( VG_(get_error_where)(err) ); MAC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo); @@ -2426,6 +2443,13 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret ) static void mc_post_clo_init ( void ) { + /* If we've been asked to emit XML, mash around various other + options so as to constrain the output somewhat. */ + if (VG_(clo_xml)) { + /* Extract as much info as possible from the leak checker. */ + MAC_(clo_show_reachable) = True; + MAC_(clo_leak_check) = LC_Full; + } } static void mc_fini ( Int exitcode )