From db21c241913f6a96aee708d3b581ede6429af98d Mon Sep 17 00:00:00 2001 From: Ivo Raisr Date: Thu, 12 Jan 2017 11:28:20 +0000 Subject: [PATCH] Fix a bug when --log-file output isn't split when a program forks. Patch loosely based on idea by Timur Iskhodzhanov . Fixes BZ#162848 git-svn-id: svn://svn.valgrind.org/valgrind/trunk@16200 --- NEWS | 1 + coregrind/m_coredump/coredump-elf.c | 4 +- coregrind/m_coredump/coredump-solaris.c | 4 +- coregrind/m_libcprint.c | 523 ++++++++++++++++++++- coregrind/m_main.c | 592 ++---------------------- coregrind/m_options.c | 5 +- coregrind/m_syswrap/syswrap-generic.c | 12 - coregrind/m_syswrap/syswrap-linux.c | 11 - coregrind/m_syswrap/syswrap-solaris.c | 11 - coregrind/pub_core_libcprint.h | 26 +- coregrind/pub_core_options.h | 9 +- 11 files changed, 589 insertions(+), 609 deletions(-) diff --git a/NEWS b/NEWS index b684a300d1..1f51292446 100644 --- a/NEWS +++ b/NEWS @@ -81,6 +81,7 @@ To see details of a given bug, visit https://bugs.kde.org/show_bug.cgi?id=XXXXXX where XXXXXX is the bug number as listed below. +162848 --log-file output isn't split when a program forks 342040 Valgrind mishandles clone with CLONE_VFORK | CLONE_VM that clones to a different stack. 348616 Wine/valgrind: noted but unhandled ioctl 0x5390 [..] (DVD_READ_STRUCT) diff --git a/coregrind/m_coredump/coredump-elf.c b/coregrind/m_coredump/coredump-elf.c index 65fd9ca25c..44869d5f5e 100644 --- a/coregrind/m_coredump/coredump-elf.c +++ b/coregrind/m_coredump/coredump-elf.c @@ -597,10 +597,10 @@ void make_elf_coredump(ThreadId tid, const vki_siginfo_t *si, ULong max_size) Addr *seg_starts; Int n_seg_starts; - if (VG_(clo_log_fname_expanded) != NULL) { + if (VG_(clo_log_fname_unexpanded) != NULL) { coreext = ".core"; basename = VG_(expand_file_name)("--log-file", - VG_(clo_log_fname_expanded)); + VG_(clo_log_fname_unexpanded)); } vg_assert(coreext); diff --git a/coregrind/m_coredump/coredump-solaris.c b/coregrind/m_coredump/coredump-solaris.c index 337edc6c48..2bf839f303 100644 --- a/coregrind/m_coredump/coredump-solaris.c +++ b/coregrind/m_coredump/coredump-solaris.c @@ -866,10 +866,10 @@ void VG_(make_coredump)(ThreadId tid, const vki_siginfo_t *si, const HChar *coreext = ""; Int core_fd; - if (VG_(clo_log_fname_expanded) != NULL) { + if (VG_(clo_log_fname_unexpanded) != NULL) { coreext = ".core"; basename = VG_(expand_file_name)("--log-file", - VG_(clo_log_fname_expanded)); + VG_(clo_log_fname_unexpanded)); } vg_assert(coreext != NULL); diff --git a/coregrind/m_libcprint.c b/coregrind/m_libcprint.c index ce2c038257..e3fda00a67 100644 --- a/coregrind/m_libcprint.c +++ b/coregrind/m_libcprint.c @@ -31,6 +31,7 @@ #include "pub_core_basics.h" #include "pub_core_vki.h" +#include "pub_core_vkiscnums.h" #include "pub_core_debuglog.h" #include "pub_core_gdbserver.h" // VG_(gdb_printf) #include "pub_core_libcbase.h" @@ -39,10 +40,276 @@ #include "pub_core_libcprint.h" #include "pub_core_libcproc.h" // VG_(getpid)(), VG_(read_millisecond_timer() #include "pub_core_mallocfree.h" // VG_(malloc) +#include "pub_core_machine.h" // VG_(machine_get_VexArchInfo) #include "pub_core_options.h" #include "pub_core_clreq.h" // For RUNNING_ON_VALGRIND +#include "pub_core_clientstate.h" +#include "pub_core_syscall.h" // VG_(strerror) +#include "pub_core_tooliface.h" // VG_(details) +/*====================================================================*/ +/*=== Printing the preamble ===*/ +/*====================================================================*/ + +// Print the argument, escaping any chars that require it. +static void umsg_arg(const HChar *arg) +{ + SizeT len = VG_(strlen)(arg); + const HChar *special = " \\<>"; + for (UInt i = 0; i < len; i++) { + if (VG_(strchr)(special, arg[i])) { + VG_(umsg)("\\"); // escape with a backslash if necessary + } + VG_(umsg)("%c", arg[i]); + } +} + +// Send output to the XML-stream and escape any XML meta-characters. +static void xml_arg(const HChar *arg) +{ + VG_(printf_xml)("%pS", arg); +} + +// Write the name and value of log file qualifiers to the xml file. +// We can safely assume here that the format string is well-formed. +// It has been checked earlier in VG_(expand_file_name) when processing +// command line options. +static void print_file_vars(const HChar *format) +{ + UInt i = 0; + + while (format[i]) { + if (format[i] == '%') { + // We saw a '%'. What's next... + i++; + if ('q' == format[i]) { + i++; + if ('{' == format[i]) { + // Get the env var name, print its contents. + UInt begin_qualname = ++i; + while (True) { + if ('}' == format[i]) { + UInt qualname_len = i - begin_qualname; + HChar qualname[qualname_len + 1]; + VG_(strncpy)(qualname, format + begin_qualname, + qualname_len); + qualname[qualname_len] = '\0'; + HChar *qual = VG_(getenv)(qualname); + i++; + VG_(printf_xml)(" %pS " + "%pS \n", + qualname, qual); + break; + } + i++; + } + } + } + } else { + i++; + } + } +} + +/* Ok, the logging sink is running now. Print a suitable preamble. + If logging to file or a socket, write details of parent PID and + command line args, to help people trying to interpret the + results of a run which encompasses multiple processes. */ +void VG_(print_preamble)(Bool logging_to_fd) +{ + const HChar *xpre = VG_(clo_xml) ? " " : ""; + const HChar *xpost = VG_(clo_xml) ? "" : ""; + UInt (*umsg_or_xml)( const HChar *, ... ) + = VG_(clo_xml) ? VG_(printf_xml) : VG_(umsg); + void (*umsg_or_xml_arg)( const HChar *) = VG_(clo_xml) ? xml_arg : umsg_arg; + + vg_assert( VG_(args_for_client) ); + vg_assert( VG_(args_for_valgrind) ); + vg_assert( VG_(clo_toolname) ); + + if (VG_(clo_xml)) { + VG_(printf_xml)("\n"); + VG_(printf_xml)("\n"); + VG_(printf_xml)("\n"); + VG_(printf_xml)("\n"); + VG_(printf_xml)("4\n"); + VG_(printf_xml)("%s\n", VG_(clo_toolname)); + VG_(printf_xml)("\n"); + } + + if (VG_(clo_xml) || VG_(clo_verbosity) > 0) { + + if (VG_(clo_xml)) + VG_(printf_xml)("\n"); + + /* Tool details */ + umsg_or_xml(VG_(clo_xml) ? "%s%pS%pS%pS, %pS%s\n" : "%s%s%s%s, %s%s\n", + xpre, + VG_(details).name, + NULL == VG_(details).version ? "" : "-", + NULL == VG_(details).version ? "" : VG_(details).version, + VG_(details).description, + xpost); + + if (VG_(strlen)(VG_(clo_toolname)) >= 4 && + VG_STREQN(4, VG_(clo_toolname), "exp-")) { + umsg_or_xml("%sNOTE: This is an Experimental-Class Valgrind Tool%s\n", + xpre, xpost); + } + + umsg_or_xml(VG_(clo_xml) ? "%s%pS%s\n" : "%s%s%s\n", + xpre, VG_(details).copyright_author, xpost); + + /* Core details */ + umsg_or_xml( + "%sUsing Valgrind-%s and LibVEX; rerun with -h for copyright info%s\n", + xpre, VERSION, xpost); + + // Print the command line. At one point we wrapped at 80 chars and + // printed a '\' as a line joiner, but that makes it hard to cut and + // paste the command line (because of the "==pid==" prefixes), so we now + // favour utility and simplicity over aesthetics. + umsg_or_xml("%sCommand: ", xpre); + umsg_or_xml_arg(VG_(args_the_exename)); + + for (UInt i = 0; i < VG_(sizeXA)( VG_(args_for_client)); i++) { + HChar *s = *(HChar **)VG_(indexXA)( VG_(args_for_client), i); + umsg_or_xml(" "); + umsg_or_xml_arg(s); + } + umsg_or_xml("%s\n", xpost); + + if (VG_(clo_xml)) + VG_(printf_xml)("\n"); + } + + // Print the parent PID, and other stuff, if necessary. + if (!VG_(clo_xml) && VG_(clo_verbosity) > 0 && !logging_to_fd) { + VG_(umsg)("Parent PID: %d\n", VG_(getppid)()); + } else if (VG_(clo_xml)) { + VG_(printf_xml)("\n"); + VG_(printf_xml)("%d\n", VG_(getpid)()); + VG_(printf_xml)("%d\n", VG_(getppid)()); + VG_(printf_xml)("%pS\n", VG_(clo_toolname)); + if (VG_(clo_xml_fname_unexpanded) != NULL) + print_file_vars(VG_(clo_xml_fname_unexpanded)); + if (VG_(clo_xml_user_comment)) { + /* Note: the user comment itself is XML and is therefore to + be passed through verbatim (%s) rather than escaped (%pS). */ + VG_(printf_xml)("%s\n", + VG_(clo_xml_user_comment)); + } + VG_(printf_xml)("\n"); + VG_(printf_xml)("\n"); + + VG_(printf_xml)(" \n"); + if (VG_(name_of_launcher)) + VG_(printf_xml)(" %pS\n", VG_(name_of_launcher)); + else + VG_(printf_xml)(" %pS\n", "(launcher name unknown)"); + for (UInt i = 0; i < VG_(sizeXA)( VG_(args_for_valgrind) ); i++) { + VG_(printf_xml)( + " %pS\n", + *(HChar **) VG_(indexXA)( VG_(args_for_valgrind), i)); + } + VG_(printf_xml)(" \n"); + + VG_(printf_xml)(" \n"); + VG_(printf_xml)(" %pS\n", VG_(args_the_exename)); + for (UInt i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) { + VG_(printf_xml)( + " %pS\n", + *(HChar **) VG_(indexXA)( VG_(args_for_client), i)); + } + VG_(printf_xml)(" \n"); + + VG_(printf_xml)("\n"); + } + + // Last thing in the preamble is a blank line. + if (VG_(clo_xml)) + VG_(printf_xml)("\n"); + else if (VG_(clo_verbosity) > 0) + VG_(umsg)("\n"); + + if (VG_(clo_verbosity) > 1) { +# if defined(VGO_linux) + SysRes fd; +# endif + VexArch vex_arch; + VexArchInfo vex_archinfo; + if (!logging_to_fd) + VG_(message)(Vg_DebugMsg, "\n"); + VG_(message)(Vg_DebugMsg, "Valgrind options:\n"); + for (UInt i = 0; i < VG_(sizeXA)( VG_(args_for_valgrind) ); i++) { + VG_(message)(Vg_DebugMsg, + " %s\n", + *(HChar **) VG_(indexXA)( VG_(args_for_valgrind), i)); + } + +# if defined(VGO_linux) + VG_(message)(Vg_DebugMsg, "Contents of /proc/version:\n"); + fd = VG_(open)("/proc/version", VKI_O_RDONLY, 0); + if (sr_isError(fd)) { + VG_(message)(Vg_DebugMsg, " can't open /proc/version\n"); + } else { + const SizeT bufsiz = 255; + HChar version_buf[bufsiz+1]; + VG_(message)(Vg_DebugMsg, " "); + Int n, fdno = sr_Res(fd); + do { + n = VG_(read)(fdno, version_buf, bufsiz); + if (n < 0) { + VG_(message)(Vg_DebugMsg, " error reading /proc/version\n"); + break; + } + version_buf[n] = '\0'; + VG_(message)(Vg_DebugMsg, "%s", version_buf); + } while (n == bufsiz); + VG_(message)(Vg_DebugMsg, "\n"); + VG_(close)(fdno); + } +# elif defined(VGO_darwin) + VG_(message)(Vg_DebugMsg, "Output from sysctl({CTL_KERN,KERN_VERSION}):\n"); + /* Note: preferable to use sysctlbyname("kern.version", kernelVersion, &len, NULL, 0) + however that syscall is OS X 10.10+ only. */ + Int mib[] = {CTL_KERN, KERN_VERSION}; + SizeT len; + VG_(sysctl)(mib, sizeof(mib)/sizeof(Int), NULL, &len, NULL, 0); + HChar *kernelVersion = VG_(malloc)("main.pp.1", len); + VG_(sysctl)(mib, sizeof(mib)/sizeof(Int), kernelVersion, &len, NULL, 0); + VG_(message)(Vg_DebugMsg, " %s\n", kernelVersion); + VG_(free)( kernelVersion ); +# elif defined(VGO_solaris) + /* There is no /proc/version file on Solaris so we try to get some + system information using the uname(2) syscall. */ + struct vki_utsname uts; + VG_(message)(Vg_DebugMsg, "System information:\n"); + SysRes res = VG_(do_syscall1)(__NR_uname, (UWord)&uts); + if (sr_isError(res)) + VG_(message)(Vg_DebugMsg, " uname() failed\n"); + else + VG_(message)(Vg_DebugMsg, " %s %s %s %s\n", + uts.sysname, uts.release, uts.version, uts.machine); +# endif + + VG_(machine_get_VexArchInfo)(&vex_arch, &vex_archinfo); + VG_(message)( + Vg_DebugMsg, + "Arch and hwcaps: %s, %s, %s\n", + LibVEX_ppVexArch ( vex_arch ), + LibVEX_ppVexEndness ( vex_archinfo.endness ), + LibVEX_ppVexHwCaps ( vex_arch, vex_archinfo.hwcaps ) + ); + VG_(message)(Vg_DebugMsg, + "Page sizes: currently %u, max supported %u\n", + (UInt) VKI_PAGE_SIZE, (UInt) VKI_MAX_PAGE_SIZE); + VG_(message)(Vg_DebugMsg, + "Valgrind library directory: %s\n", VG_(libdir)); + } +} + /* --------------------------------------------------------------------- Writing to file or a socket ------------------------------------------------------------------ */ @@ -54,19 +321,260 @@ After startup, the gdbserver monitor command might temporarily set the fd of log_output_sink to -2 to indicate that output is to be given to gdb rather than output to the startup fd */ -OutputSink VG_(log_output_sink) = { 2, False }; /* 2 = stderr */ -OutputSink VG_(xml_output_sink) = { -1, False }; /* disabled */ - +OutputSink VG_(log_output_sink) = { 2, VgLogTo_Fd, NULL }; /* 2 = stderr */ +OutputSink VG_(xml_output_sink) = { -1, VgLogTo_Fd, NULL }; /* disabled */ + +static void revert_sink_to_stderr ( OutputSink *sink ) +{ + sink->fd = 2; /* stderr */ + sink->type = VgLogTo_Fd; + VG_(free)(sink->fsname_expanded); + sink->fsname_expanded = NULL; +} + +static Int prepare_sink_fd(const HChar *clo_fname_unexpanded, OutputSink *sink, + Bool is_xml) +{ + vg_assert(clo_fname_unexpanded != NULL); + vg_assert(VG_(strlen)(clo_fname_unexpanded) <= 900); /* paranoia */ + + // Nb: we overwrite an existing file of this name without asking + // any questions. + HChar *logfilename = VG_(expand_file_name)( + (is_xml) ? "--xml-file" : "--log-file", + clo_fname_unexpanded); + SysRes sres = VG_(open)(logfilename, + VKI_O_CREAT|VKI_O_WRONLY|VKI_O_TRUNC, + VKI_S_IRUSR|VKI_S_IWUSR|VKI_S_IRGRP|VKI_S_IROTH); + if (!sr_isError(sres)) { + Int fd = sr_Res(sres); + sink->fsname_expanded = logfilename; + sink->type = VgLogTo_File; + return fd; + } else { + VG_(fmsg)("Cannot create %s file '%s': %s\n", + (is_xml) ? "XML" : "log", logfilename, + VG_(strerror)(sr_Err(sres))); + VG_(exit)(1); + /*NOTREACHED*/ + } +} + +static Int prepare_sink_socket(const HChar *clo_fname_unexpanded, + OutputSink *sink, Bool is_xml) +{ + vg_assert(clo_fname_unexpanded != NULL); + vg_assert(VG_(strlen)(clo_fname_unexpanded) <= 900); /* paranoia */ + + Int fd = VG_(connect_via_socket)(clo_fname_unexpanded); + if (fd == -1) { + VG_(fmsg)("Invalid %s spec of '%s'\n", + (is_xml) ? "--xml-socket" : "--log-socket", + clo_fname_unexpanded); + VG_(exit)(1); + /*NOTREACHED*/ + } + if (fd == -2) { + VG_(umsg)("Failed to connect to %slogging server '%s'.\n" + "%s will be sent to stderr instead.\n", + (is_xml) ? "XML " : "", + (is_xml) ? "XML output" : "Logging messages", + clo_fname_unexpanded); + /* We don't change anything here. */ + vg_assert(sink->fd == 2); + vg_assert(sink->type == VgLogTo_Fd); + return 2; + } else { + vg_assert(fd > 0); + sink->type = VgLogTo_Socket; + return fd; + } +} + +static void finalize_sink_fd(OutputSink *sink, Int new_fd, Bool is_xml) +{ + // Move new_fd into the safe range, so it doesn't conflict with any app fds. + Int safe_fd = VG_(fcntl)(new_fd, VKI_F_DUPFD, VG_(fd_hard_limit)); + if (safe_fd < 0) { + VG_(message)(Vg_UserMsg, "Valgrind: failed to move %s file descriptor " + "into safe range, using stderr\n", + (is_xml) ? "XML" : "log"); + revert_sink_to_stderr(sink); + } else { + VG_(fcntl)(safe_fd, VKI_F_SETFD, VKI_FD_CLOEXEC); + sink->fd = safe_fd; + } +} + +/* Re-opens an output file sink when exanded file name differs from what we + have now. Returns 'True' if the sink was reopened */ +static Bool reopen_sink_if_needed(const HChar *clo_fname_unexpanded, + OutputSink *sink, Bool is_xml) +{ + if (sink->type == VgLogTo_File) { + /* Try to expand --log|xml-file again and see if it differs from what + we have now. */ + HChar *logfilename = VG_(expand_file_name)( + (is_xml) ? "--xml-file" : "--log-file", + clo_fname_unexpanded); + if (VG_(strcmp)(logfilename, sink->fsname_expanded) != 0) { + Int fd = prepare_sink_fd(clo_fname_unexpanded, sink, is_xml); + finalize_sink_fd(sink, fd, is_xml); + return True; + } + VG_(free)(logfilename); + } + + return False; +} + +void VG_(logging_atfork_child)(ThreadId tid) +{ + /* If --child-silent-after-fork=yes was specified, set the output file + descriptors to 'impossible' values. This is noticed by + send_bytes_to_logging_sink(), which duly stops writing any further + output. */ + if (VG_(clo_child_silent_after_fork)) { + if (VG_(log_output_sink).type != VgLogTo_Socket) { + VG_(log_output_sink).fd = -1; + VG_(log_output_sink).type = VgLogTo_Fd; + } + if (VG_(xml_output_sink).type != VgLogTo_Socket) { + VG_(xml_output_sink).fd = -1; + VG_(xml_output_sink).type = VgLogTo_Fd; + } + } else { + if (reopen_sink_if_needed(VG_(clo_log_fname_unexpanded), + &VG_(log_output_sink), False) || + reopen_sink_if_needed(VG_(clo_xml_fname_unexpanded), + &VG_(xml_output_sink), True)) { + VG_(print_preamble)(VG_(log_output_sink).type != VgLogTo_File); + } + } +} + +/* Initializes normal log and xml sinks (of type fd, file, or socket). + Any problem encountered is considered a hard error and causes V. to exit. + + Comments on how the logging options are handled: + + User can specify: + --log-fd= for a fd to write to (default setting, fd = 2) + --log-file= for a file name to write to + --log-socket= for a socket to write to + + As a result of examining these and doing relevant socket/file + opening, a final fd is established. This is stored in + VG_(log_output_sink) in m_libcprint. Also, if --log-file=STR was + specified, then it is stored in VG_(clo_log_fname_unexpanded), in m_options. + And then STR, after expansion of %p and %q templates within + it, is stored in VG_(log_output_sink), just in case anybody wants to know + what it is. + + When printing, VG_(log_output_sink) is consulted to find the + fd to send output to. + + Exactly analogous actions are undertaken for the XML output + channel, with the one difference that the default fd is -1, meaning + the channel is disabled by default. */ +void VG_(init_log_xml_sinks)(VgLogTo log_to, VgLogTo xml_to, + Int /*initial*/log_fd, Int /*initial*/xml_fd) +{ + // VG_(clo_log_fd) is used by all the messaging. It starts as 2 (stderr) + // and we cannot change it until we know what we are changing it to is ok. + + /* Start setting up logging now. After this is done, VG_(log_output_sink) + and (if relevant) VG_(xml_output_sink) should be connected to whatever + sink has been selected, and we indiscriminately chuck stuff into it + without worrying what the nature of it is. + Oh the wonder of Unix streams. */ + + vg_assert(VG_(log_output_sink).fd == 2 /* stderr */); + vg_assert(VG_(log_output_sink).type == VgLogTo_Fd); + vg_assert(VG_(log_output_sink).fsname_expanded == NULL); + + vg_assert(VG_(xml_output_sink).fd == -1 /* disabled */); + vg_assert(VG_(xml_output_sink).type == VgLogTo_Fd); + vg_assert(VG_(xml_output_sink).fsname_expanded == NULL); + + /* --- set up the normal text output channel --- */ + switch (log_to) { + case VgLogTo_Fd: + vg_assert(VG_(clo_log_fname_unexpanded) == NULL); + break; + + case VgLogTo_File: + log_fd = prepare_sink_fd(VG_(clo_log_fname_unexpanded), + &VG_(log_output_sink), False); + break; + + case VgLogTo_Socket: + log_fd = prepare_sink_socket(VG_(clo_log_fname_unexpanded), + &VG_(log_output_sink), False); + break; + } + + /* --- set up the XML output channel --- */ + switch (xml_to) { + case VgLogTo_Fd: + vg_assert(VG_(clo_xml_fname_unexpanded) == NULL); + break; + + case VgLogTo_File: + xml_fd = prepare_sink_fd(VG_(clo_xml_fname_unexpanded), + &VG_(xml_output_sink), True); + break; + + case VgLogTo_Socket: + log_fd = prepare_sink_socket(VG_(clo_xml_fname_unexpanded), + &VG_(xml_output_sink), True); + break; + } + + /* If we've got this far, and XML mode was requested, but no XML + output channel appears to have been specified, just stop. We + could continue, and XML output will simply vanish into nowhere, + but that is likely to confuse the hell out of users, which is + distinctly Ungood. */ + if (VG_(clo_xml) && xml_fd == -1) { + VG_(fmsg_bad_option)( + "--xml=yes, but no XML destination specified", + "--xml=yes has been specified, but there is no XML output\n" + "destination. You must specify an XML output destination\n" + "using --xml-fd, --xml-file or --xml-socket.\n" + ); + } + + // Finalise the output fds: the log fd .. + if (log_fd >= 0) { + finalize_sink_fd(&VG_(log_output_sink), log_fd, False); + } else { + // If they said --log-fd=-1, don't print anything. Plausible for use in + // regression testing suites that use client requests to count errors. + VG_(log_output_sink).fd = -1; + VG_(log_output_sink).type = VgLogTo_Fd; + } + + // Finalise the output fds: and the XML fd .. + if (xml_fd >= 0) { + finalize_sink_fd(&VG_(xml_output_sink), xml_fd, True); + } else { + // If they said --xml-fd=-1, don't print anything. Plausible for use in + // regression testing suites that use client requests to count errors. + VG_(xml_output_sink).fd = -1; + VG_(xml_output_sink).type = VgLogTo_Fd; + } +} + /* Do the low-level send of a message to the logging sink. */ static void send_bytes_to_logging_sink ( OutputSink* sink, const HChar* msg, Int nbytes ) { - if (sink->is_socket) { + if (sink->type == VgLogTo_Socket) { Int rc = VG_(write_socket)( sink->fd, msg, nbytes ); if (rc == -1) { // For example, the listener process died. Switch back to stderr. - sink->is_socket = False; - sink->fd = 2; + revert_sink_to_stderr(sink); VG_(write)( sink->fd, msg, nbytes ); } } else { @@ -557,8 +1065,7 @@ UInt VG_(message) ( VgMsgKind kind, const HChar* format, ... ) static void revert_to_stderr ( void ) { - VG_(log_output_sink).fd = 2; /* stderr */ - VG_(log_output_sink).is_socket = False; + revert_sink_to_stderr(&VG_(log_output_sink)); } /* VG_(message) variants with hardwired first argument. */ diff --git a/coregrind/m_main.c b/coregrind/m_main.c index 66e9c4a869..fe92e5da0e 100644 --- a/coregrind/m_main.c +++ b/coregrind/m_main.c @@ -31,7 +31,6 @@ #include "vgversion.h" #include "pub_core_basics.h" #include "pub_core_vki.h" -#include "pub_core_vkiscnums.h" #include "pub_core_threadstate.h" #include "pub_core_xarray.h" #include "pub_core_clientstate.h" @@ -51,7 +50,6 @@ #include "pub_core_libcproc.h" #include "pub_core_libcsignal.h" #include "pub_core_sbprofile.h" -#include "pub_core_syscall.h" // VG_(strerror) #include "pub_core_mach.h" #include "pub_core_machine.h" #include "pub_core_mallocfree.h" @@ -314,7 +312,7 @@ static void usage_NORETURN ( Bool debug_help ) // Ensure the message goes to stdout VG_(log_output_sink).fd = 1; - VG_(log_output_sink).is_socket = False; + VG_(log_output_sink).type = VgLogTo_Fd; if (VG_(needs).malloc_replacement) { VG_(sprintf)(default_alignment, "%d", VG_MIN_MALLOC_SZB); @@ -363,7 +361,7 @@ static void usage_NORETURN ( Bool debug_help ) - show the version string, if requested (-v) - extract any request for help (--help, -h, --help-debug) - - get the toolname (--tool=) + - set VG_(toolname) (--tool=) - set VG_(clo_max_stackframe) (--max-stackframe=) - set VG_(clo_main_stacksize) (--main-stacksize=) - set VG_(clo_sim_hints) (--sim-hints=) @@ -374,8 +372,7 @@ static void usage_NORETURN ( Bool debug_help ) main_process_cmd_line_options has to handle but ignore the ones we have handled here. */ -static void early_process_cmd_line_options ( /*OUT*/Int* need_help, - /*OUT*/const HChar** tool ) +static void early_process_cmd_line_options ( /*OUT*/Int* need_help ) { UInt i; HChar* str; @@ -403,7 +400,7 @@ static void early_process_cmd_line_options ( /*OUT*/Int* need_help, // The tool has already been determined, but we need to know the name // here. - else if VG_STR_CLO(str, "--tool", *tool) {} + 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 @@ -427,7 +424,7 @@ static void early_process_cmd_line_options ( /*OUT*/Int* need_help, if (need_version) { // Nb: the version string goes to stdout. VG_(log_output_sink).fd = 1; - VG_(log_output_sink).is_socket = False; + VG_(log_output_sink).type = VgLogTo_Fd; if (VG_(clo_verbosity) <= 1) VG_(printf)("valgrind-" VERSION "\n"); else @@ -440,53 +437,13 @@ static void early_process_cmd_line_options ( /*OUT*/Int* need_help, } /* The main processing for command line options. See comments above - on early_process_cmd_line_options. - - Comments on how the logging options are handled: - - User can specify: - --log-fd= for a fd to write to (default setting, fd = 2) - --log-file= for a file name to write to - --log-socket= for a socket to write to - - As a result of examining these and doing relevant socket/file - opening, a final fd is established. This is stored in - VG_(log_output_sink) in m_libcprint. Also, if --log-file=STR was - specified, then STR, after expansion of %p and %q templates within - it, is stored in VG_(clo_log_fname_expanded), in m_options, just in - case anybody wants to know what it is. - - When printing, VG_(log_output_sink) is consulted to find the - fd to send output to. - - Exactly analogous actions are undertaken for the XML output - channel, with the one difference that the default fd is -1, meaning - the channel is disabled by default. -*/ + on early_process_cmd_line_options. */ static -void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd, - /*OUT*/const HChar** xml_fname_unexpanded, - const HChar* toolname ) +void main_process_cmd_line_options( void ) { - // VG_(clo_log_fd) is used by all the messaging. It starts as 2 (stderr) - // and we cannot change it until we know what we are changing it to is - // ok. So we have tmp_log_fd to hold the tmp fd prior to that point. - SysRes sres; - Int i, tmp_log_fd, tmp_xml_fd; - Int toolname_len = VG_(strlen)(toolname); + Int i; + Int toolname_len = VG_(strlen)(VG_(clo_toolname)); const HChar* tmp_str; // Used in a couple of places. - enum { - VgLogTo_Fd, - VgLogTo_File, - VgLogTo_Socket - } log_to = VgLogTo_Fd, // Where is logging output to be sent? - xml_to = VgLogTo_Fd; // Where is XML output to be sent? - - /* Temporarily holds the string STR specified with - --{log,xml}-{name,socket}=STR. 'fs' stands for - file-or-socket. */ - const HChar* log_fsname_unexpanded = NULL; - const HChar* xml_fsname_unexpanded = NULL; /* Whether the user has explicitly provided --sigill-diagnostics. If not explicitly given depends on general verbosity setting. */ @@ -494,9 +451,11 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd, /* Log to stderr by default, but usage message goes to stdout. XML output is initially disabled. */ - tmp_log_fd = 2; - tmp_xml_fd = -1; - + 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; + /* Check for sane path in ./configure --prefix=... */ if (VG_LIBDIR[0] != '/') VG_(err_config_error)("Please use absolute paths in " @@ -536,7 +495,7 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd, // eg. "--memcheck:verbose". if (*colon == ':') { if (VG_STREQN(2, arg, "--") && - VG_STREQN(toolname_len, arg+2, toolname) && + VG_STREQN(toolname_len, arg+2, VG_(clo_toolname)) && VG_STREQN(1, arg+2+toolname_len, ":")) { // Prefix matches, convert "--toolname:foo" to "--foo". @@ -780,24 +739,24 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd, else if VG_INT_CLO(arg, "--log-fd", tmp_log_fd) { log_to = VgLogTo_Fd; - log_fsname_unexpanded = NULL; + VG_(clo_log_fname_unexpanded) = NULL; } else if VG_INT_CLO(arg, "--xml-fd", tmp_xml_fd) { xml_to = VgLogTo_Fd; - xml_fsname_unexpanded = NULL; + VG_(clo_xml_fname_unexpanded) = NULL; } - else if VG_STR_CLO(arg, "--log-file", log_fsname_unexpanded) { + 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", xml_fsname_unexpanded) { + 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", log_fsname_unexpanded) { + 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", xml_fsname_unexpanded) { + else if VG_STR_CLO(arg, "--xml-socket", VG_(clo_xml_fname_unexpanded)) { xml_to = VgLogTo_Socket; } @@ -1031,197 +990,13 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd, have to generate any other command-line-related error messages. (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.) - - So set up logging now. After this is done, VG_(log_output_sink) - and (if relevant) VG_(xml_output_sink) should be connected to - whatever sink has been selected, and we indiscriminately chuck - stuff into it without worrying what the nature of it is. Oh the - wonder of Unix streams. */ - - vg_assert(VG_(log_output_sink).fd == 2 /* stderr */); - vg_assert(VG_(log_output_sink).is_socket == False); - vg_assert(VG_(clo_log_fname_expanded) == NULL); - - vg_assert(VG_(xml_output_sink).fd == -1 /* disabled */); - vg_assert(VG_(xml_output_sink).is_socket == False); - vg_assert(VG_(clo_xml_fname_expanded) == NULL); - - /* --- set up the normal text output channel --- */ - - switch (log_to) { - - case VgLogTo_Fd: - vg_assert(log_fsname_unexpanded == NULL); - break; - - case VgLogTo_File: { - HChar* logfilename; - - vg_assert(log_fsname_unexpanded != NULL); - vg_assert(VG_(strlen)(log_fsname_unexpanded) <= 900); /* paranoia */ - - // Nb: we overwrite an existing file of this name without asking - // any questions. - logfilename = VG_(expand_file_name)("--log-file", - log_fsname_unexpanded); - sres = VG_(open)(logfilename, - VKI_O_CREAT|VKI_O_WRONLY|VKI_O_TRUNC, - VKI_S_IRUSR|VKI_S_IWUSR|VKI_S_IRGRP|VKI_S_IROTH); - if (!sr_isError(sres)) { - tmp_log_fd = sr_Res(sres); - VG_(clo_log_fname_expanded) = logfilename; - } else { - VG_(fmsg)("can't create log file '%s': %s\n", - logfilename, VG_(strerror)(sr_Err(sres))); - VG_(exit)(1); - /*NOTREACHED*/ - } - break; - } - - case VgLogTo_Socket: { - vg_assert(log_fsname_unexpanded != NULL); - vg_assert(VG_(strlen)(log_fsname_unexpanded) <= 900); /* paranoia */ - tmp_log_fd = VG_(connect_via_socket)( log_fsname_unexpanded ); - if (tmp_log_fd == -1) { - VG_(fmsg)("Invalid --log-socket spec of '%s'\n", - log_fsname_unexpanded); - VG_(exit)(1); - /*NOTREACHED*/ - } - if (tmp_log_fd == -2) { - VG_(umsg)("failed to connect to logging server '%s'.\n" - "Log messages will sent to stderr instead.\n", - log_fsname_unexpanded ); - - /* We don't change anything here. */ - vg_assert(VG_(log_output_sink).fd == 2); - tmp_log_fd = 2; - } else { - vg_assert(tmp_log_fd > 0); - VG_(log_output_sink).is_socket = True; - } - break; - } - } - - /* --- set up the XML output channel --- */ - - switch (xml_to) { - - case VgLogTo_Fd: - vg_assert(xml_fsname_unexpanded == NULL); - break; - - case VgLogTo_File: { - HChar* xmlfilename; - - vg_assert(xml_fsname_unexpanded != NULL); - vg_assert(VG_(strlen)(xml_fsname_unexpanded) <= 900); /* paranoia */ - - // Nb: we overwrite an existing file of this name without asking - // any questions. - xmlfilename = VG_(expand_file_name)("--xml-file", - xml_fsname_unexpanded); - sres = VG_(open)(xmlfilename, - VKI_O_CREAT|VKI_O_WRONLY|VKI_O_TRUNC, - VKI_S_IRUSR|VKI_S_IWUSR|VKI_S_IRGRP|VKI_S_IROTH); - if (!sr_isError(sres)) { - tmp_xml_fd = sr_Res(sres); - VG_(clo_xml_fname_expanded) = xmlfilename; - *xml_fname_unexpanded = xml_fsname_unexpanded; - } else { - VG_(fmsg)("can't create XML file '%s': %s\n", - xmlfilename, VG_(strerror)(sr_Err(sres))); - VG_(exit)(1); - /*NOTREACHED*/ - } - break; - } - - case VgLogTo_Socket: { - vg_assert(xml_fsname_unexpanded != NULL); - vg_assert(VG_(strlen)(xml_fsname_unexpanded) <= 900); /* paranoia */ - tmp_xml_fd = VG_(connect_via_socket)( xml_fsname_unexpanded ); - if (tmp_xml_fd == -1) { - VG_(fmsg)("Invalid --xml-socket spec of '%s'\n", - xml_fsname_unexpanded ); - VG_(exit)(1); - /*NOTREACHED*/ - } - if (tmp_xml_fd == -2) { - VG_(umsg)("failed to connect to XML logging server '%s'.\n" - "XML output will sent to stderr instead.\n", - xml_fsname_unexpanded); - /* We don't change anything here. */ - vg_assert(VG_(xml_output_sink).fd == 2); - tmp_xml_fd = 2; - } else { - vg_assert(tmp_xml_fd > 0); - VG_(xml_output_sink).is_socket = True; - } - break; - } - } + opts.) */ + VG_(init_log_xml_sinks)(log_to, xml_to, tmp_log_fd, tmp_xml_fd); - /* If we've got this far, and XML mode was requested, but no XML - output channel appears to have been specified, just stop. We - could continue, and XML output will simply vanish into nowhere, - but that is likely to confuse the hell out of users, which is - distinctly Ungood. */ - if (VG_(clo_xml) && tmp_xml_fd == -1) { - VG_(fmsg_bad_option)( - "--xml=yes, but no XML destination specified", - "--xml=yes has been specified, but there is no XML output\n" - "destination. You must specify an XML output destination\n" - "using --xml-fd, --xml-file or --xml-socket.\n" - ); - } - - // Finalise the output fds: the log fd .. - - if (tmp_log_fd >= 0) { - // Move log_fd into the safe range, so it doesn't conflict with - // any app fds. - tmp_log_fd = VG_(fcntl)(tmp_log_fd, VKI_F_DUPFD, VG_(fd_hard_limit)); - if (tmp_log_fd < 0) { - VG_(message)(Vg_UserMsg, "valgrind: failed to move logfile fd " - "into safe range, using stderr\n"); - VG_(log_output_sink).fd = 2; // stderr - VG_(log_output_sink).is_socket = False; - } else { - VG_(log_output_sink).fd = tmp_log_fd; - VG_(fcntl)(VG_(log_output_sink).fd, VKI_F_SETFD, VKI_FD_CLOEXEC); - } - } else { - // If they said --log-fd=-1, don't print anything. Plausible for use in - // regression testing suites that use client requests to count errors. - VG_(log_output_sink).fd = -1; - VG_(log_output_sink).is_socket = False; - } - - // Finalise the output fds: and the XML fd .. - - if (tmp_xml_fd >= 0) { - // Move xml_fd into the safe range, so it doesn't conflict with - // any app fds. - tmp_xml_fd = VG_(fcntl)(tmp_xml_fd, VKI_F_DUPFD, VG_(fd_hard_limit)); - if (tmp_xml_fd < 0) { - VG_(message)(Vg_UserMsg, "valgrind: failed to move XML file fd " - "into safe range, using stderr\n"); - VG_(xml_output_sink).fd = 2; // stderr - VG_(xml_output_sink).is_socket = False; - } else { - VG_(xml_output_sink).fd = tmp_xml_fd; - VG_(fcntl)(VG_(xml_output_sink).fd, VKI_F_SETFD, VKI_FD_CLOEXEC); - } - } else { - // If they said --xml-fd=-1, don't print anything. Plausible for use in - // regression testing suites that use client requests to count errors. - VG_(xml_output_sink).fd = -1; - VG_(xml_output_sink).is_socket = False; - } + /* Register child at-fork handler which will take care of handling + --child-silent-after-fork clo and also reopening output sinks for forked + children, if requested via --log|xml-file= options. */ + VG_(atfork)(NULL, NULL, VG_(logging_atfork_child)); // Suppressions related stuff @@ -1235,294 +1010,6 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd, VG_(sprintf)(buf, "%s/%s", VG_(libdir), default_supp); VG_(addToXA)(VG_(clo_suppressions), &buf); } - - *logging_to_fd = log_to == VgLogTo_Fd || log_to == VgLogTo_Socket; -} - -// Write the name and value of log file qualifiers to the xml file. -// We can safely assume here that the format string is well-formed. -// It has been checked earlier in VG_(expand_file_name) when processing -// command line options. -static void print_file_vars(const HChar* format) -{ - Int i = 0; - - while (format[i]) { - if (format[i] == '%') { - // We saw a '%'. What's next... - i++; - if ('q' == format[i]) { - i++; - if ('{' == format[i]) { - // Get the env var name, print its contents. - HChar* qual; - Int begin_qualname = ++i; - while (True) { - if ('}' == format[i]) { - Int qualname_len = i - begin_qualname; - HChar qualname[qualname_len + 1]; - VG_(strncpy)(qualname, format + begin_qualname, - qualname_len); - qualname[qualname_len] = '\0'; - qual = VG_(getenv)(qualname); - i++; - VG_(printf_xml)(" %pS " - "%pS \n", - qualname, qual); - break; - } - i++; - } - } - } - } else { - i++; - } - } -} - - -/*====================================================================*/ -/*=== Printing the preamble ===*/ -/*====================================================================*/ - -// Print the argument, escaping any chars that require it. -static void umsg_arg(const HChar* arg) -{ - SizeT len = VG_(strlen)(arg); - const HChar* special = " \\<>"; - Int i; - for (i = 0; i < len; i++) { - if (VG_(strchr)(special, arg[i])) { - VG_(umsg)("\\"); // escape with a backslash if necessary - } - VG_(umsg)("%c", arg[i]); - } -} - -// Send output to the XML-stream and escape any XML meta-characters. -static void xml_arg(const HChar* arg) -{ - VG_(printf_xml)("%pS", arg); -} - -/* Ok, the logging sink is running now. Print a suitable preamble. - If logging to file or a socket, write details of parent PID and - command line args, to help people trying to interpret the - results of a run which encompasses multiple processes. */ -static void print_preamble ( Bool logging_to_fd, - const HChar* xml_fname_unexpanded, - const HChar* toolname ) -{ - Int i; - const HChar* xpre = VG_(clo_xml) ? " " : ""; - const HChar* xpost = VG_(clo_xml) ? "" : ""; - UInt (*umsg_or_xml)( const HChar*, ... ) - = VG_(clo_xml) ? VG_(printf_xml) : VG_(umsg); - - void (*umsg_or_xml_arg)( const HChar* ) - = VG_(clo_xml) ? xml_arg : umsg_arg; - - vg_assert( VG_(args_for_client) ); - vg_assert( VG_(args_for_valgrind) ); - vg_assert( toolname ); - - if (VG_(clo_xml)) { - VG_(printf_xml)("\n"); - VG_(printf_xml)("\n"); - VG_(printf_xml)("\n"); - VG_(printf_xml)("\n"); - VG_(printf_xml)("4\n"); - VG_(printf_xml)("%s\n", toolname); - VG_(printf_xml)("\n"); - } - - if (VG_(clo_xml) || VG_(clo_verbosity) > 0) { - - if (VG_(clo_xml)) - VG_(printf_xml)("\n"); - - /* Tool details */ - umsg_or_xml( VG_(clo_xml) ? "%s%pS%pS%pS, %pS%s\n" : "%s%s%s%s, %s%s\n", - xpre, - VG_(details).name, - NULL == VG_(details).version ? "" : "-", - NULL == VG_(details).version - ? "" : VG_(details).version, - VG_(details).description, - xpost ); - - if (VG_(strlen)(toolname) >= 4 && VG_STREQN(4, toolname, "exp-")) { - umsg_or_xml( - "%sNOTE: This is an Experimental-Class Valgrind Tool%s\n", - xpre, xpost - ); - } - - umsg_or_xml( VG_(clo_xml) ? "%s%pS%s\n" : "%s%s%s\n", - xpre, VG_(details).copyright_author, xpost ); - - /* Core details */ - umsg_or_xml( - "%sUsing Valgrind-%s and LibVEX; rerun with -h for copyright info%s\n", - xpre, VERSION, xpost - ); - - // Print the command line. At one point we wrapped at 80 chars and - // printed a '\' as a line joiner, but that makes it hard to cut and - // paste the command line (because of the "==pid==" prefixes), so we now - // favour utility and simplicity over aesthetics. - umsg_or_xml("%sCommand: ", xpre); - umsg_or_xml_arg(VG_(args_the_exename)); - - for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) { - HChar* s = *(HChar**)VG_(indexXA)( VG_(args_for_client), i ); - umsg_or_xml(" "); - umsg_or_xml_arg(s); - } - umsg_or_xml("%s\n", xpost); - - if (VG_(clo_xml)) - VG_(printf_xml)("\n"); - } - - // Print the parent PID, and other stuff, if necessary. - if (!VG_(clo_xml) && VG_(clo_verbosity) > 0 && !logging_to_fd) { - VG_(umsg)("Parent PID: %d\n", VG_(getppid)()); - } - else - if (VG_(clo_xml)) { - VG_(printf_xml)("\n"); - VG_(printf_xml)("%d\n", VG_(getpid)()); - VG_(printf_xml)("%d\n", VG_(getppid)()); - VG_(printf_xml)("%pS\n", toolname); - if (xml_fname_unexpanded) - print_file_vars(xml_fname_unexpanded); - if (VG_(clo_xml_user_comment)) { - /* Note: the user comment itself is XML and is therefore to - be passed through verbatim (%s) rather than escaped - (%pS). */ - VG_(printf_xml)("%s\n", - VG_(clo_xml_user_comment)); - } - VG_(printf_xml)("\n"); - VG_(printf_xml)("\n"); - - VG_(printf_xml)(" \n"); - if (VG_(name_of_launcher)) - VG_(printf_xml)(" %pS\n", - VG_(name_of_launcher)); - else - VG_(printf_xml)(" %pS\n", - "(launcher name unknown)"); - for (i = 0; i < VG_(sizeXA)( VG_(args_for_valgrind) ); i++) { - VG_(printf_xml)( - " %pS\n", - * (HChar**) VG_(indexXA)( VG_(args_for_valgrind), i ) - ); - } - VG_(printf_xml)(" \n"); - - VG_(printf_xml)(" \n"); - VG_(printf_xml)(" %pS\n", - VG_(args_the_exename)); - for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) { - VG_(printf_xml)( - " %pS\n", - * (HChar**) VG_(indexXA)( VG_(args_for_client), i ) - ); - } - VG_(printf_xml)(" \n"); - - VG_(printf_xml)("\n"); - } - - // Last thing in the preamble is a blank line. - if (VG_(clo_xml)) - VG_(printf_xml)("\n"); - else if (VG_(clo_verbosity) > 0) - VG_(umsg)("\n"); - - if (VG_(clo_verbosity) > 1) { -# if defined(VGO_linux) - SysRes fd; -# endif - VexArch vex_arch; - VexArchInfo vex_archinfo; - if (!logging_to_fd) - VG_(message)(Vg_DebugMsg, "\n"); - VG_(message)(Vg_DebugMsg, "Valgrind options:\n"); - for (i = 0; i < VG_(sizeXA)( VG_(args_for_valgrind) ); i++) { - VG_(message)(Vg_DebugMsg, - " %s\n", - * (HChar**) VG_(indexXA)( VG_(args_for_valgrind), i )); - } - -# if defined(VGO_linux) - VG_(message)(Vg_DebugMsg, "Contents of /proc/version:\n"); - fd = VG_(open) ( "/proc/version", VKI_O_RDONLY, 0 ); - if (sr_isError(fd)) { - VG_(message)(Vg_DebugMsg, " can't open /proc/version\n"); - } else { - const SizeT bufsiz = 255; - HChar version_buf[bufsiz+1]; - VG_(message)(Vg_DebugMsg, " "); - Int n, fdno = sr_Res(fd); - do { - n = VG_(read)(fdno, version_buf, bufsiz); - if (n < 0) { - VG_(message)(Vg_DebugMsg, " error reading /proc/version\n"); - break; - } - version_buf[n] = '\0'; - VG_(message)(Vg_DebugMsg, "%s", version_buf); - } while (n == bufsiz); - VG_(message)(Vg_DebugMsg, "\n"); - VG_(close)(fdno); - } -# elif defined(VGO_darwin) - VG_(message)(Vg_DebugMsg, "Output from sysctl({CTL_KERN,KERN_VERSION}):\n"); - /* Note: preferable to use sysctlbyname("kern.version", kernelVersion, &len, NULL, 0) - however that syscall is OS X 10.10+ only. */ - Int mib[] = {CTL_KERN, KERN_VERSION}; - SizeT len; - VG_(sysctl)(mib, sizeof(mib)/sizeof(Int), NULL, &len, NULL, 0); - HChar *kernelVersion = VG_(malloc)("main.pp.1", len); - VG_(sysctl)(mib, sizeof(mib)/sizeof(Int), kernelVersion, &len, NULL, 0); - VG_(message)(Vg_DebugMsg, " %s\n", kernelVersion); - VG_(free)( kernelVersion ); -# elif defined(VGO_solaris) - /* There is no /proc/version file on Solaris so we try to get some - system information using the uname(2) syscall. */ - { - struct vki_utsname uts; - - VG_(message)(Vg_DebugMsg, "System information:\n"); - SysRes res = VG_(do_syscall1)(__NR_uname, (UWord)&uts); - if (sr_isError(res)) - VG_(message)(Vg_DebugMsg, " uname() failed\n"); - else - VG_(message)(Vg_DebugMsg, " %s %s %s %s\n", - uts.sysname, uts.release, uts.version, uts.machine); - } -# endif - - VG_(machine_get_VexArchInfo)( &vex_arch, &vex_archinfo ); - VG_(message)( - Vg_DebugMsg, - "Arch and hwcaps: %s, %s, %s\n", - LibVEX_ppVexArch ( vex_arch ), - LibVEX_ppVexEndness ( vex_archinfo.endness ), - LibVEX_ppVexHwCaps ( vex_arch, vex_archinfo.hwcaps ) - ); - VG_(message)( - Vg_DebugMsg, - "Page sizes: currently %d, max supported %d\n", - (Int)VKI_PAGE_SIZE, (Int)VKI_MAX_PAGE_SIZE - ); - VG_(message)(Vg_DebugMsg, - "Valgrind library directory: %s\n", VG_(libdir)); - } } @@ -1643,11 +1130,8 @@ void shutdown_actions_NORETURN( ThreadId tid, static Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) { - const HChar* toolname = "memcheck"; // default to Memcheck Int need_help = 0; // 0 = no, 1 = --help, 2 = --help-debug ThreadId tid_main = VG_INVALID_THREADID; - Bool logging_to_fd = False; - const HChar* xml_fname_unexpanded = NULL; Int loglevel, i; XArray* addr2dihandle = NULL; @@ -1914,15 +1398,15 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) //-------------------------------------------------------------- VG_(debugLog)(1, "main", "(early_) Process Valgrind's command line options\n"); - early_process_cmd_line_options(&need_help, &toolname); + early_process_cmd_line_options(&need_help); // BEGIN HACK - vg_assert(toolname != NULL); + vg_assert(VG_(clo_toolname) != NULL); vg_assert(VG_(clo_read_inline_info) == False); # if !defined(VGO_darwin) - if (0 == VG_(strcmp)(toolname, "memcheck") - || 0 == VG_(strcmp)(toolname, "helgrind") - || 0 == VG_(strcmp)(toolname, "drd")) { + if (0 == VG_(strcmp)(VG_(clo_toolname), "memcheck") + || 0 == VG_(strcmp)(VG_(clo_toolname), "helgrind") + || 0 == VG_(strcmp)(VG_(clo_toolname), "drd")) { /* Change the default setting. Later on (just below) main_process_cmd_line_options should pick up any user-supplied setting for it and will override the default @@ -1944,7 +1428,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) // // Set up client's environment // p: set-libdir [for VG_(libdir)] - // p: early_process_cmd_line_options [for toolname] + // p: early_process_cmd_line_options [for VG_(clo_toolname)] // // Setup client stack, eip, and VG_(client_arg[cv]) // p: load_client() [for 'info'] @@ -1963,7 +1447,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) # if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) the_iicii.argv = argv; the_iicii.envp = envp; - the_iicii.toolname = toolname; + the_iicii.toolname = VG_(clo_toolname); # else # error "Unknown platform" # endif @@ -2120,8 +1604,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) VG_(debugLog)(1, "main", "(main_) Process Valgrind's command line options, " "setup logging\n"); - main_process_cmd_line_options ( &logging_to_fd, &xml_fname_unexpanded, - toolname ); + main_process_cmd_line_options(); //-------------------------------------------------------------- // Zeroise the millisecond counter by doing a first read of it. @@ -2133,11 +1616,10 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) // Print the preamble // p: tl_pre_clo_init [for 'VG_(details).name' and friends] // p: main_process_cmd_line_options() - // [for VG_(clo_verbosity), VG_(clo_xml), - // logging_to_fd, xml_fname_unexpanded] + // [for VG_(clo_verbosity), VG_(clo_xml)] //-------------------------------------------------------------- VG_(debugLog)(1, "main", "Print the preamble...\n"); - print_preamble(logging_to_fd, xml_fname_unexpanded, toolname); + VG_(print_preamble)(VG_(log_output_sink).type != VgLogTo_File); VG_(debugLog)(1, "main", "...finished the preamble\n"); //-------------------------------------------------------------- diff --git a/coregrind/m_options.c b/coregrind/m_options.c index 591e40e7d9..04808ce954 100644 --- a/coregrind/m_options.c +++ b/coregrind/m_options.c @@ -45,6 +45,7 @@ /* Define, and set defaults. */ +const HChar *VG_(clo_toolname) = "memcheck"; // default to Memcheck VexControl VG_(clo_vex_control); VexRegisterUpdates VG_(clo_px_file_backed) = VexRegUpd_INVALID; @@ -79,8 +80,8 @@ Bool VG_(clo_trace_children) = False; const HChar* VG_(clo_trace_children_skip) = NULL; const HChar* VG_(clo_trace_children_skip_by_arg) = NULL; Bool VG_(clo_child_silent_after_fork) = False; -const HChar* VG_(clo_log_fname_expanded) = NULL; -const HChar* VG_(clo_xml_fname_expanded) = NULL; +const HChar *VG_(clo_log_fname_unexpanded) = NULL; +const HChar *VG_(clo_xml_fname_unexpanded) = NULL; Bool VG_(clo_time_stamp) = False; Int VG_(clo_input_fd) = 0; /* stdin */ Bool VG_(clo_default_supp) = True; diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c index 31eca3df77..d6cda89a0c 100644 --- a/coregrind/m_syswrap/syswrap-generic.c +++ b/coregrind/m_syswrap/syswrap-generic.c @@ -3301,18 +3301,6 @@ PRE(sys_fork) /* restore signal mask */ VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL); - - /* If --child-silent-after-fork=yes was specified, set the - output file descriptors to 'impossible' values. This is - noticed by send_bytes_to_logging_sink in m_libcprint.c, which - duly stops writing any further output. */ - if (VG_(clo_child_silent_after_fork)) { - if (!VG_(log_output_sink).is_socket) - VG_(log_output_sink).fd = -1; - if (!VG_(xml_output_sink).is_socket) - VG_(xml_output_sink).fd = -1; - } - } else { VG_(do_atfork_parent)(tid); diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c index aa596ed227..03064aa37d 100644 --- a/coregrind/m_syswrap/syswrap-linux.c +++ b/coregrind/m_syswrap/syswrap-linux.c @@ -788,17 +788,6 @@ static SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags, /* restore signal mask */ VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL); - - /* If --child-silent-after-fork=yes was specified, set the - output file descriptors to 'impossible' values. This is - noticed by send_bytes_to_logging_sink in m_libcprint.c, which - duly stops writing any further output. */ - if (VG_(clo_child_silent_after_fork)) { - if (!VG_(log_output_sink).is_socket) - VG_(log_output_sink).fd = -1; - if (!VG_(xml_output_sink).is_socket) - VG_(xml_output_sink).fd = -1; - } } else if (!sr_isError(res) && sr_Res(res) > 0) { diff --git a/coregrind/m_syswrap/syswrap-solaris.c b/coregrind/m_syswrap/syswrap-solaris.c index 2070fc4641..25aa9bf9b7 100644 --- a/coregrind/m_syswrap/syswrap-solaris.c +++ b/coregrind/m_syswrap/syswrap-solaris.c @@ -6624,17 +6624,6 @@ PRE(sys_forksys) if (RESHI) { VG_(do_atfork_child)(tid); - /* If --child-silent-after-fork=yes was specified, set the output file - descriptors to 'impossible' values. This is noticed by - send_bytes_to_logging_sink() in m_libcprint.c, which duly stops - writing any further output. */ - if (VG_(clo_child_silent_after_fork)) { - if (!VG_(log_output_sink).is_socket) - VG_(log_output_sink).fd = -1; - if (!VG_(xml_output_sink).is_socket) - VG_(xml_output_sink).fd = -1; - } - /* vfork */ if (ARG1 == 2) VG_(close)(fds[1]); diff --git a/coregrind/pub_core_libcprint.h b/coregrind/pub_core_libcprint.h index 7b2d4a8130..71d66d2032 100644 --- a/coregrind/pub_core_libcprint.h +++ b/coregrind/pub_core_libcprint.h @@ -38,16 +38,36 @@ #include "pub_tool_libcprint.h" -/* An output file descriptor wrapped up with a Bool indicating whether - or not the fd is a socket. */ typedef - struct { Int fd; Bool is_socket; } + enum { + VgLogTo_Fd, + VgLogTo_File, + VgLogTo_Socket + } + VgLogTo; + +/* An output file descriptor wrapped up with its type and expanded name. */ +typedef + struct { + Int fd; + VgLogTo type; + HChar *fsname_expanded; // 'fs' stands for file or socket + } OutputSink; /* And the destinations for normal and XML output. */ extern OutputSink VG_(log_output_sink); extern OutputSink VG_(xml_output_sink); +/* Initializes normal log and xml sinks (of type fd, file, or socket). + Any problem encountered is considered a hard error and causes V. to exit. */ +extern void VG_(init_log_xml_sinks)(VgLogTo log_to, VgLogTo xml_to, + Int /*initial*/log_fd, Int /*initial*/xml_fd); + +extern void VG_(print_preamble)(Bool logging_to_fd); + +extern void VG_(logging_atfork_child)(ThreadId tid); + /* Get the elapsed wallclock time since startup into buf which has size bufsize. The function will assert if bufsize is not large enough. Upon return, buf will contain the zero-terminated wallclock time as diff --git a/coregrind/pub_core_options.h b/coregrind/pub_core_options.h index f249cfad21..ba2712776b 100644 --- a/coregrind/pub_core_options.h +++ b/coregrind/pub_core_options.h @@ -39,6 +39,9 @@ #include "pub_tool_options.h" #include "pub_core_xarray.h" +/* Valgrind tool name. Defaults to "memcheck". */ +extern const HChar *VG_(clo_toolname); + /* Should we stop collecting errors if too many appear? default: YES */ extern Bool VG_(clo_error_limit); /* Alternative exit code to hand to parent if errors were found. @@ -117,9 +120,9 @@ extern const HChar* VG_(clo_trace_children_skip_by_arg); extern Bool VG_(clo_child_silent_after_fork); /* If the user specified --log-file=STR and/or --xml-file=STR, these - hold STR after expansion of the %p and %q templates. */ -extern const HChar* VG_(clo_log_fname_expanded); -extern const HChar* VG_(clo_xml_fname_expanded); + hold STR before expansion. */ +extern const HChar *VG_(clo_log_fname_unexpanded); +extern const HChar *VG_(clo_xml_fname_unexpanded); /* Add timestamps to log messages? default: NO */ extern Bool VG_(clo_time_stamp); -- 2.47.2