Moved stage2.c into vg_main.c. Merged main() and VG_(main)(); VG_(main)()
no longer exists. One advantage of this is that global
variables/structures needed for communicating between the two can be made
local. Also, the order in which things happen has been simplified.
This is mostly just a big refactoring. Startup is now a fair bit easier to
understand. Dependencies between the various startup stages are fairly well
documented in comments. Also, --help and --version now work properly --
eg. --help gives tool-specific help if --tool was specified. There is still
some parts where things could be reordered and/or simplified, and where the
dependencies aren't clear. These are marked with 'XXX'.
One new feature was added: ability to read options from ~/.valgrindrc and
./.valgrindrc. Part of this is support for specifying tool-specific options
in the form --toolname:tool-specific-option.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2222 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index 94587ff..4a3ecf8 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -39,7 +39,6 @@
valgrind_LDADD=
stage2_SOURCES = \
- stage2.c \
ume.c \
x86/ume_entry.S \
x86/ume_go.c \
diff --git a/coregrind/docs/coregrind_core.html b/coregrind/docs/coregrind_core.html
index a558eea..6baf039 100644
--- a/coregrind/docs/coregrind_core.html
+++ b/coregrind/docs/coregrind_core.html
@@ -475,11 +475,6 @@
valgrind --tool=<i>tool_name</i> [options-for-Valgrind] your-prog [options for your-prog]
</pre>
-<p>Note that Valgrind also reads options from the environment variable
-<code>$VALGRIND_OPTS</code>, and processes them before the command-line
-options. Options for the Valgrind core may be freely mixed with those
-for the selected tool.
-
<p>Valgrind's default settings succeed in giving reasonable behaviour
in most cases. We group the available options by rough categories.
@@ -711,10 +706,7 @@
etc, return 4-byte aligned addresses. These are suitable for
any accesses on x86 processors.
Some programs might however assume that <code>malloc</code> et
- al return 8- or more aligned memory.
- These programs are broken and should be fixed, but
- if this is impossible for whatever reason the alignment can be
- increased using this parameter. The supplied value must be
+ al return 8- or more aligned memory. The supplied value must be
between 4 and 4096 inclusive, and must be a power of two.</li><br><p>
<li><code>--sloppy-malloc=no</code> [default]<br>
@@ -940,6 +932,33 @@
<p>
</ul>
+<h4>Setting default options</h4>
+
+<p>Note that Valgrind also reads options from three places:
+<ul>
+<li>The file <code>~/.valgrindrc</code>
+<li>The environment variable <code>$VALGRIND_OPTS</code>
+<li>The file <code>./.valgrindrc</code>
+</ul>
+These are processed in the given order, before the command-line options.
+Options processed later override those processed earlier; for example,
+options in <code>./.valgrindrc</code> will take precedence over those in
+<code>~/.valgrindrc</code>. The first two are particularly useful for
+setting the default tool to use.
+<p>
+Any tool-specific options put in <code>$VALGRIND_OPTS</code> or the
+<code>.valgrindrc</code> files should be prefixed with the tool name and
+a colon. For example, if you want Memcheck to always do leak checking,
+you can put the following entry in <code>~/.valgrindrc</code>:
+
+<pre>
+ --memcheck:leak-check=yes
+</pre>
+
+This will be ignored if any tool other than Memcheck is run.
+Without the <code>memcheck:</code> part, this will cause problems if you
+select other tools that don't understand <code>--leak-check=yes</code>.
+
<a name="clientreq"></a>
<h3>2.7 The Client Request mechanism</h3>
@@ -1151,7 +1170,7 @@
<p>The translator/instrumentor has a lot of assertions in it. They
are permanently enabled, and I have no plans to disable them. If one
-of these breaks, please mail me!
+of these breaks, please mail us!
<p>If you get an assertion failure on the expression
<code>chunkSane(ch)</code> in <code>vg_free()</code> in
diff --git a/coregrind/stage1.c b/coregrind/stage1.c
index 7056784..1b91f84 100644
--- a/coregrind/stage1.c
+++ b/coregrind/stage1.c
@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------*/
-/*--- Startup: stage 1 stage1.c ---*/
+/*--- Startup: preliminaries stage1.c ---*/
/*--------------------------------------------------------------------*/
/*
diff --git a/coregrind/ume.c b/coregrind/ume.c
index 2a12f01..d0a5f5a 100644
--- a/coregrind/ume.c
+++ b/coregrind/ume.c
@@ -590,8 +590,11 @@
}
info->argv0 = strdup(interp);
- if (arg != NULL && *arg != '\0')
+ assert(NULL != info->argv0);
+ if (arg != NULL && *arg != '\0') {
info->argv1 = strdup(arg);
+ assert(NULL != info->argv1);
+ }
if (info->argv && info->argv[0] != NULL)
info->argv[0] = (char *)name;
diff --git a/coregrind/ume.h b/coregrind/ume.h
index a1647dd..286e356 100644
--- a/coregrind/ume.h
+++ b/coregrind/ume.h
@@ -57,10 +57,10 @@
addr_t brkbase; /* base address of brk segment */
/* these are the extra args added by #! scripts */
- char *argv0; /* the interpreter name */
- char *argv1; /* the args for the interpreter */
+ char *argv0; /* INPUT: the interpreter name */
+ char *argv1; /* INPUT: the args for the interpreter */
- char **argv; /* the original argv */
+ char **argv; /* INPUT: the original argv */
};
int do_exec(const char *exe, struct exeinfo *info);
diff --git a/coregrind/vg_dispatch.S b/coregrind/vg_dispatch.S
index 225e1ff..997bf17 100644
--- a/coregrind/vg_dispatch.S
+++ b/coregrind/vg_dispatch.S
@@ -109,8 +109,8 @@
If %ebp has any other value, we panic.
*/
- cmpl $VG_(baseBlock), %ebp
- jnz dispatch_exceptional
+ /*cmpl $VG_(baseBlock), %ebp*/
+ /*jnz dispatch_exceptional*/
/* fall into main loop */
diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h
index 120b18d..006de0f 100644
--- a/coregrind/vg_include.h
+++ b/coregrind/vg_include.h
@@ -1369,44 +1369,6 @@
Exports of vg_main.c
------------------------------------------------------------------ */
-/* structure used for transporting values from stage2 into Valgrind
- proper */
-typedef struct {
- Addr client_esp; /* initial client ESP */
- Addr client_eip; /* initial client EIP */
- Char **client_envp; /* client envp */
- UInt *client_auxv; /* client auxv */
- Addr client_brkbase; /* initial value of brk */
-
- Int argc; /* Valgrind's argc/argv */
- Char **argv;
- const Char *libdir; /* library directory */
-
- Int vgexecfd; /* fd of our own (stage1) executable */
- Int clexecfd; /* fd of the client executable */
-
- Addr client_base; /* start of client address space */
- Addr client_end; /* end of client address space */
- Addr client_mapbase; /* base address of !MAP_FIXED mappings */
- Addr clstk_base; /* lowest address of client stack */
- Addr clstk_end; /* highest address of client stack */
- Addr cl_tramp_code; /* syscall+signal trampoline code */
-
- Addr shadow_base; /* start of skin's shadow memory */
- Addr shadow_end; /* end of skin's shadow memory */
-
- Addr vg_base; /* start of Valgrind's memory */
- Addr vg_mmap_end; /* end of Valgrind's mmap area */
- Addr vg_end; /* end of Valgrind's memory */
-} KickstartParams;
-
-/* Entrypoint for kickstart */
-typedef void (kickstart_main_t)(const KickstartParams *kp,
- void (*tool_init)(void), void *tool_dlhandle);
-extern kickstart_main_t VG_(main);
-
-extern void VG_(usage)(void);
-
/* Is this a SSE/SSE2-capable CPU? If so, we had better save/restore
the SSE state all over the place. This is set up very early, in
vg_startup.S. We have to determine it early since we can't even
@@ -1446,13 +1408,15 @@
extern const Char *VG_(libdir);
/* A structure used as an intermediary when passing the simulated
- CPU's state to some assembly fragments, particularly system calls.
- Stuff is copied from baseBlock to here, the assembly magic runs,
- and then the inverse copy is done. Alignment: the SSE state must
- be 16-byte aligned. We ask for the whole struct to be 16-byte
- aligned, and the SSE state starts at the 6+8+1+1th == 16th word,
- so it too must be 16-byte aligned. Consequence: change this struct
- only _very carefully_ ! See also above comment re masking MXCSR.
+ CPU's state to VG_(switch_to_real_CPU)(), for --stop-after=yes.
+ Stuff is copied from baseBlock to here, because it's much easier
+ to copy the state into the real registers from this structure than
+ the baseBlock, because it's layout is simpler.
+ Alignment: the SSE state must be 16-byte aligned. We ask for the whole
+ struct to be 16-byte aligned, and the SSE state starts at the 6+8+1+1th
+ == 16th word, so it too must be 16-byte aligned. Consequence: change
+ this struct only _very carefully_ ! See also above comment re masking
+ MXCSR.
*/
__attribute__ ((aligned (16)))
extern UInt VG_(m_state_static) [6 /* segment regs, Intel order */
@@ -1462,10 +1426,6 @@
+ VG_SIZE_OF_SSESTATE_W /* SSE state */
];
-/* Handy fns for doing the copy back and forth. */
-extern void VG_(copy_baseBlock_to_m_state_static) ( void );
-extern void VG_(copy_m_state_static_to_baseBlock) ( void );
-
/* Determine if %esp adjustment must be noted */
extern Bool VG_(need_to_handle_esp_assignment) ( void );
@@ -1484,19 +1444,11 @@
extern Int VG_(vg_argc);
extern Char **VG_(vg_argv);
-/* Holds client's %esp at the point we gained control. From this the
- client's argc, argv and envp are deduced. */
-extern Addr VG_(esp_at_startup);
-
/* Indicates presence, and holds address of client's sysinfo page, a
feature of some modern kernels used to provide vsyscalls, etc. */
extern Bool VG_(sysinfo_page_exists);
extern Addr VG_(sysinfo_page_addr);
-/* Walk through a colon separated list variable, removing entries
- which match pattern. */
-extern void VG_(mash_colon_env)(Char *varp, const Char *pattern);
-
/* Something of a function looking for a home ... start up GDB. */
extern void VG_(start_GDB) ( Int tid );
@@ -1633,8 +1585,6 @@
extern Bool VG_(seg_contains)(const Segment *s, Addr ptr, UInt size);
extern Bool VG_(seg_overlaps)(const Segment *s, Addr ptr, UInt size);
-extern void VG_(init_memory) ( void );
-
extern __attribute__((regparm(1)))
void VG_(unknown_esp_update) ( Addr new_ESP );
diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c
index 4dda086..11b80d4 100644
--- a/coregrind/vg_main.c
+++ b/coregrind/vg_main.c
@@ -1,7 +1,6 @@
/*--------------------------------------------------------------------*/
-/*--- C startup stuff, reached from vg_startup.S. ---*/
-/*--- vg_main.c ---*/
+/*--- Startup: the real stuff vg_main.c ---*/
/*--------------------------------------------------------------------*/
/*
@@ -29,121 +28,92 @@
The GNU General Public License is contained in the file COPYING.
*/
-#include "vg_include.h"
+#define _FILE_OFFSET_BITS 64
+#include "vg_include.h"
+#include "ume.h"
+#include "ume_arch.h"
+#include "ume_archdefs.h"
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/ptrace.h>
#include <sys/signal.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <unistd.h>
+#ifndef AT_SYSINFO
+#define AT_SYSINFO 32
+#endif /* AT_SYSINFO */
+
+#ifndef AT_SYSINFO_EHDR
+#define AT_SYSINFO_EHDR 33
+#endif /* AT_SYSINFO_EHDR */
+
+#ifndef AT_SECURE
+#define AT_SECURE 23 /* secure mode boolean */
+#endif /* AT_SECURE */
+
+/* Amount to reserve for Valgrind's internal heap */
+#define VALGRIND_HEAPSIZE (128*1024*1024)
+
+/* Amount to reserve for Valgrind's internal mappings */
+#define VALGRIND_MAPSIZE (128*1024*1024)
+
+/* redzone gap between client address space and shadow */
+#define REDZONE_SIZE (1 * 1024*1024)
+
+/* size multiple for client address space */
+#define CLIENT_SIZE_MULTIPLE (64 * 1024*1024)
+
+#define ISSPACE(cc) ((cc) == ' ' || (cc) == '\t' || (cc) == '\n')
+
+/*====================================================================*/
+/*=== Global entities not referenced from generated code ===*/
+/*====================================================================*/
+
/* ---------------------------------------------------------------------
- Compute offsets into baseBlock. See comments in vg_include.h.
+ Startup stuff
------------------------------------------------------------------ */
+/* linker-defined base address */
+extern char kickstart_base;
-/* The variables storing offsets. */
-
-#define INVALID_OFFSET (-1)
-
-Int VGOFF_(m_eax) = INVALID_OFFSET;
-Int VGOFF_(m_ecx) = INVALID_OFFSET;
-Int VGOFF_(m_edx) = INVALID_OFFSET;
-Int VGOFF_(m_ebx) = INVALID_OFFSET;
-Int VGOFF_(m_esp) = INVALID_OFFSET;
-Int VGOFF_(m_ebp) = INVALID_OFFSET;
-Int VGOFF_(m_esi) = INVALID_OFFSET;
-Int VGOFF_(m_edi) = INVALID_OFFSET;
-Int VGOFF_(m_eflags) = INVALID_OFFSET;
-Int VGOFF_(m_dflag) = INVALID_OFFSET;
-Int VGOFF_(m_ssestate) = INVALID_OFFSET;
-Int VGOFF_(ldt) = INVALID_OFFSET;
-Int VGOFF_(tls) = INVALID_OFFSET;
-Int VGOFF_(m_cs) = INVALID_OFFSET;
-Int VGOFF_(m_ss) = INVALID_OFFSET;
-Int VGOFF_(m_ds) = INVALID_OFFSET;
-Int VGOFF_(m_es) = INVALID_OFFSET;
-Int VGOFF_(m_fs) = INVALID_OFFSET;
-Int VGOFF_(m_gs) = INVALID_OFFSET;
-Int VGOFF_(m_eip) = INVALID_OFFSET;
-Int VGOFF_(spillslots) = INVALID_OFFSET;
-Int VGOFF_(sh_eax) = INVALID_OFFSET;
-Int VGOFF_(sh_ecx) = INVALID_OFFSET;
-Int VGOFF_(sh_edx) = INVALID_OFFSET;
-Int VGOFF_(sh_ebx) = INVALID_OFFSET;
-Int VGOFF_(sh_esp) = INVALID_OFFSET;
-Int VGOFF_(sh_ebp) = INVALID_OFFSET;
-Int VGOFF_(sh_esi) = INVALID_OFFSET;
-Int VGOFF_(sh_edi) = INVALID_OFFSET;
-Int VGOFF_(sh_eflags) = INVALID_OFFSET;
-
-Int VGOFF_(helper_idiv_64_32) = INVALID_OFFSET;
-Int VGOFF_(helper_div_64_32) = INVALID_OFFSET;
-Int VGOFF_(helper_idiv_32_16) = INVALID_OFFSET;
-Int VGOFF_(helper_div_32_16) = INVALID_OFFSET;
-Int VGOFF_(helper_idiv_16_8) = INVALID_OFFSET;
-Int VGOFF_(helper_div_16_8) = INVALID_OFFSET;
-Int VGOFF_(helper_imul_32_64) = INVALID_OFFSET;
-Int VGOFF_(helper_mul_32_64) = INVALID_OFFSET;
-Int VGOFF_(helper_imul_16_32) = INVALID_OFFSET;
-Int VGOFF_(helper_mul_16_32) = INVALID_OFFSET;
-Int VGOFF_(helper_imul_8_16) = INVALID_OFFSET;
-Int VGOFF_(helper_mul_8_16) = INVALID_OFFSET;
-Int VGOFF_(helper_CLD) = INVALID_OFFSET;
-Int VGOFF_(helper_STD) = INVALID_OFFSET;
-Int VGOFF_(helper_get_dirflag) = INVALID_OFFSET;
-Int VGOFF_(helper_CLC) = INVALID_OFFSET;
-Int VGOFF_(helper_STC) = INVALID_OFFSET;
-Int VGOFF_(helper_shldl) = INVALID_OFFSET;
-Int VGOFF_(helper_shldw) = INVALID_OFFSET;
-Int VGOFF_(helper_shrdl) = INVALID_OFFSET;
-Int VGOFF_(helper_shrdw) = INVALID_OFFSET;
-Int VGOFF_(helper_IN) = INVALID_OFFSET;
-Int VGOFF_(helper_OUT) = INVALID_OFFSET;
-Int VGOFF_(helper_RDTSC) = INVALID_OFFSET;
-Int VGOFF_(helper_CPUID) = INVALID_OFFSET;
-Int VGOFF_(helper_BSWAP) = INVALID_OFFSET;
-Int VGOFF_(helper_bsf) = INVALID_OFFSET;
-Int VGOFF_(helper_bsr) = INVALID_OFFSET;
-Int VGOFF_(helper_fstsw_AX) = INVALID_OFFSET;
-Int VGOFF_(helper_SAHF) = INVALID_OFFSET;
-Int VGOFF_(helper_LAHF) = INVALID_OFFSET;
-Int VGOFF_(helper_DAS) = INVALID_OFFSET;
-Int VGOFF_(helper_DAA) = INVALID_OFFSET;
-Int VGOFF_(helper_cmpxchg8b) = INVALID_OFFSET;
-Int VGOFF_(helper_undefined_instruction) = INVALID_OFFSET;
-
-/* MAX_NONCOMPACT_HELPERS can be increased easily. If MAX_COMPACT_HELPERS is
- * increased too much, they won't really be compact any more... */
-#define MAX_COMPACT_HELPERS 8
-#define MAX_NONCOMPACT_HELPERS 50
-
-UInt VG_(n_compact_helpers) = 0;
-UInt VG_(n_noncompact_helpers) = 0;
-
-Addr VG_(compact_helper_addrs) [MAX_COMPACT_HELPERS];
-Int VG_(compact_helper_offsets)[MAX_COMPACT_HELPERS];
-Addr VG_(noncompact_helper_addrs) [MAX_NONCOMPACT_HELPERS];
-Int VG_(noncompact_helper_offsets)[MAX_NONCOMPACT_HELPERS];
-
-/* This is the actual defn of baseblock. */
-UInt VG_(baseBlock)[VG_BASEBLOCK_WORDS];
-
-/* Client address space */
-Addr VG_(client_base); /* client address space limits */
+/* Client address space, lowest to highest (see top of ume.c) */
+Addr VG_(client_base); /* client address space limits */
Addr VG_(client_end);
Addr VG_(client_mapbase);
Addr VG_(client_trampoline_code);
Addr VG_(clstk_base);
Addr VG_(clstk_end);
-Addr VG_(brk_base); /* start of brk */
-Addr VG_(brk_limit); /* current brk */
-Addr VG_(shadow_base); /* skin's shadow memory */
+
+Addr VG_(brk_base); /* start of brk */
+Addr VG_(brk_limit); /* current brk */
+
+Addr VG_(shadow_base); /* skin's shadow memory */
Addr VG_(shadow_end);
-Addr VG_(valgrind_base); /* valgrind's address range */
-Addr VG_(valgrind_mmap_end); /* valgrind's mmaps are between valgrind_base and here */
+
+Addr VG_(valgrind_base); /* valgrind's address range */
+Addr VG_(valgrind_mmap_end); /* valgrind's mmaps are between valgrind_base and here */
Addr VG_(valgrind_end);
+/* This is set early to indicate whether this CPU has the
+ SSE/fxsave/fxrestor features. */
+Bool VG_(have_ssestate);
+
+/* Indicates presence, and holds address of client's sysinfo page, a
+ feature of some modern kernels used to provide vsyscalls, etc. */
+Bool VG_(sysinfo_page_exists) = False;
+Addr VG_(sysinfo_page_addr) = 0;
+
/* stage1 (main) executable */
Int VG_(vgexecfd) = -1;
@@ -166,314 +136,16 @@
/* Maximum allowed application-visible file descriptor */
Int VG_(max_fd) = -1;
-/* Words. */
-static Int baB_off = 0;
-
-/* jmp_buf for fatal signals */
-Int VG_(fatal_sigNo) = -1;
-Bool VG_(fatal_signal_set) = False;
-jmp_buf VG_(fatal_signal_jmpbuf);
-
-/* Returns the offset, in words. */
-static Int alloc_BaB ( Int words )
-{
- Int off = baB_off;
- baB_off += words;
- if (baB_off >= VG_BASEBLOCK_WORDS)
- VG_(core_panic)( "alloc_BaB: baseBlock is too small");
-
- return off;
-}
-
-/* Align offset, in *bytes* */
-static void align_BaB ( UInt align )
-{
- vg_assert(2 == align || 4 == align || 8 == align || 16 == align);
- baB_off += (align-1);
- baB_off &= ~(align-1);
-}
-
-/* Allocate 1 word in baseBlock and set it to the given value. */
-static Int alloc_BaB_1_set ( Addr a )
-{
- Int off = alloc_BaB(1);
- VG_(baseBlock)[off] = (UInt)a;
- return off;
-}
-
-/* Registers a function in compact_helper_addrs; compact_helper_offsets is
- filled in later. */
-void VG_(register_compact_helper)(Addr a)
-{
- if (MAX_COMPACT_HELPERS <= VG_(n_compact_helpers)) {
- VG_(printf)("Can only register %d compact helpers\n",
- MAX_COMPACT_HELPERS);
- VG_(core_panic)("Too many compact helpers registered");
- }
- VG_(compact_helper_addrs)[VG_(n_compact_helpers)] = a;
- VG_(n_compact_helpers)++;
-}
-
-/* Registers a function in noncompact_helper_addrs; noncompact_helper_offsets
- * is filled in later.
- */
-void VG_(register_noncompact_helper)(Addr a)
-{
- if (MAX_NONCOMPACT_HELPERS <= VG_(n_noncompact_helpers)) {
- VG_(printf)("Can only register %d non-compact helpers\n",
- MAX_NONCOMPACT_HELPERS);
- VG_(printf)("Try increasing MAX_NON_COMPACT_HELPERS\n");
- VG_(core_panic)("Too many non-compact helpers registered");
- }
- VG_(noncompact_helper_addrs)[VG_(n_noncompact_helpers)] = a;
- VG_(n_noncompact_helpers)++;
-}
-
-/* Allocate offsets in baseBlock for the skin helpers */
-static
-void assign_helpers_in_baseBlock(UInt n, Int offsets[], Addr addrs[])
-{
- UInt i;
- for (i = 0; i < n; i++)
- offsets[i] = alloc_BaB_1_set( addrs[i] );
-}
-
-Bool VG_(need_to_handle_esp_assignment)(void)
-{
- return ( VG_(defined_new_mem_stack_4)() ||
- VG_(defined_die_mem_stack_4)() ||
- VG_(defined_new_mem_stack_8)() ||
- VG_(defined_die_mem_stack_8)() ||
- VG_(defined_new_mem_stack_12)() ||
- VG_(defined_die_mem_stack_12)() ||
- VG_(defined_new_mem_stack_16)() ||
- VG_(defined_die_mem_stack_16)() ||
- VG_(defined_new_mem_stack_32)() ||
- VG_(defined_die_mem_stack_32)() ||
- VG_(defined_new_mem_stack)() ||
- VG_(defined_die_mem_stack)()
- );
-}
-
-/* Here we assign actual offsets. It's important to get the most
- popular referents within 128 bytes of the start, so we can take
- advantage of short addressing modes relative to %ebp. Popularity
- of offsets was measured on 22 Feb 02 running a KDE application, and
- the slots rearranged accordingly, with a 1.5% reduction in total
- size of translations. */
-static void vg_init_baseBlock ( void )
-{
- /* Those with offsets under 128 are carefully chosen. */
-
- /* WORD offsets in this column */
- /* 0 */ VGOFF_(m_eax) = alloc_BaB(1);
- /* 1 */ VGOFF_(m_ecx) = alloc_BaB(1);
- /* 2 */ VGOFF_(m_edx) = alloc_BaB(1);
- /* 3 */ VGOFF_(m_ebx) = alloc_BaB(1);
- /* 4 */ VGOFF_(m_esp) = alloc_BaB(1);
- /* 5 */ VGOFF_(m_ebp) = alloc_BaB(1);
- /* 6 */ VGOFF_(m_esi) = alloc_BaB(1);
- /* 7 */ VGOFF_(m_edi) = alloc_BaB(1);
- /* 8 */ VGOFF_(m_eflags) = alloc_BaB(1);
-
- if (VG_(needs).shadow_regs) {
- /* 9 */ VGOFF_(sh_eax) = alloc_BaB(1);
- /* 10 */ VGOFF_(sh_ecx) = alloc_BaB(1);
- /* 11 */ VGOFF_(sh_edx) = alloc_BaB(1);
- /* 12 */ VGOFF_(sh_ebx) = alloc_BaB(1);
- /* 13 */ VGOFF_(sh_esp) = alloc_BaB(1);
- /* 14 */ VGOFF_(sh_ebp) = alloc_BaB(1);
- /* 15 */ VGOFF_(sh_esi) = alloc_BaB(1);
- /* 16 */ VGOFF_(sh_edi) = alloc_BaB(1);
- /* 17 */ VGOFF_(sh_eflags) = alloc_BaB(1);
- }
-
- /* 9,10,11 or 18,19,20... depends on number whether shadow regs are used
- * and on compact helpers registered */
-
- /* Make these most-frequently-called specialised ones compact, if they
- are used. */
- if (VG_(defined_new_mem_stack_4)())
- VG_(register_compact_helper)( (Addr) VG_(tool_interface).track_new_mem_stack_4);
-
- if (VG_(defined_die_mem_stack_4)())
- VG_(register_compact_helper)( (Addr) VG_(tool_interface).track_die_mem_stack_4);
-
- /* (9 or 18) + n_compact_helpers */
- /* Allocate slots for compact helpers */
- assign_helpers_in_baseBlock(VG_(n_compact_helpers),
- VG_(compact_helper_offsets),
- VG_(compact_helper_addrs));
-
- /* (9/10 or 18/19) + n_compact_helpers */
- VGOFF_(m_eip) = alloc_BaB(1);
-
- /* There are currently 24 spill slots */
- /* (11+/20+ .. 32+/43+) + n_compact_helpers. This can overlap the magic
- * boundary at >= 32 words, but most spills are to low numbered spill
- * slots, so the ones above the boundary don't see much action. */
- VGOFF_(spillslots) = alloc_BaB(VG_MAX_SPILLSLOTS);
-
- /* I gave up counting at this point. Since they're above the
- short-amode-boundary, there's no point. */
-
- VGOFF_(m_dflag) = alloc_BaB(1);
-
- /* The FPU/SSE state. This _must_ be 16-byte aligned. */
- align_BaB(16);
- VGOFF_(m_ssestate) = alloc_BaB(VG_SIZE_OF_SSESTATE_W);
- vg_assert(
- ( ((UInt)(& VG_(baseBlock)[VGOFF_(m_ssestate)]))
- % 16 )
- == 0
- );
-
- /* This thread's LDT and TLS pointers, and segment registers. */
- VGOFF_(ldt) = alloc_BaB(1);
- VGOFF_(tls) = alloc_BaB(1);
- VGOFF_(m_cs) = alloc_BaB(1);
- VGOFF_(m_ss) = alloc_BaB(1);
- VGOFF_(m_ds) = alloc_BaB(1);
- VGOFF_(m_es) = alloc_BaB(1);
- VGOFF_(m_fs) = alloc_BaB(1);
- VGOFF_(m_gs) = alloc_BaB(1);
-
- VG_(register_noncompact_helper)( (Addr) & VG_(do_useseg) );
-
-#define REG(kind, size) \
- if (VG_(defined_##kind##_mem_stack##size)()) \
- VG_(register_noncompact_helper)( \
- (Addr) VG_(tool_interface).track_##kind##_mem_stack##size );
-
- REG(new, _8);
- REG(new, _12);
- REG(new, _16);
- REG(new, _32);
- REG(new, );
- REG(die, _8);
- REG(die, _12);
- REG(die, _16);
- REG(die, _32);
- REG(die, );
-#undef REG
-
- if (VG_(need_to_handle_esp_assignment)())
- VG_(register_noncompact_helper)((Addr) VG_(unknown_esp_update));
-
- /* Helper functions. */
- VGOFF_(helper_idiv_64_32)
- = alloc_BaB_1_set( (Addr) & VG_(helper_idiv_64_32));
- VGOFF_(helper_div_64_32)
- = alloc_BaB_1_set( (Addr) & VG_(helper_div_64_32));
- VGOFF_(helper_idiv_32_16)
- = alloc_BaB_1_set( (Addr) & VG_(helper_idiv_32_16));
- VGOFF_(helper_div_32_16)
- = alloc_BaB_1_set( (Addr) & VG_(helper_div_32_16));
- VGOFF_(helper_idiv_16_8)
- = alloc_BaB_1_set( (Addr) & VG_(helper_idiv_16_8));
- VGOFF_(helper_div_16_8)
- = alloc_BaB_1_set( (Addr) & VG_(helper_div_16_8));
-
- VGOFF_(helper_imul_32_64)
- = alloc_BaB_1_set( (Addr) & VG_(helper_imul_32_64));
- VGOFF_(helper_mul_32_64)
- = alloc_BaB_1_set( (Addr) & VG_(helper_mul_32_64));
- VGOFF_(helper_imul_16_32)
- = alloc_BaB_1_set( (Addr) & VG_(helper_imul_16_32));
- VGOFF_(helper_mul_16_32)
- = alloc_BaB_1_set( (Addr) & VG_(helper_mul_16_32));
- VGOFF_(helper_imul_8_16)
- = alloc_BaB_1_set( (Addr) & VG_(helper_imul_8_16));
- VGOFF_(helper_mul_8_16)
- = alloc_BaB_1_set( (Addr) & VG_(helper_mul_8_16));
-
- VGOFF_(helper_CLD)
- = alloc_BaB_1_set( (Addr) & VG_(helper_CLD));
- VGOFF_(helper_STD)
- = alloc_BaB_1_set( (Addr) & VG_(helper_STD));
- VGOFF_(helper_get_dirflag)
- = alloc_BaB_1_set( (Addr) & VG_(helper_get_dirflag));
-
- VGOFF_(helper_CLC)
- = alloc_BaB_1_set( (Addr) & VG_(helper_CLC));
- VGOFF_(helper_STC)
- = alloc_BaB_1_set( (Addr) & VG_(helper_STC));
-
- VGOFF_(helper_shldl)
- = alloc_BaB_1_set( (Addr) & VG_(helper_shldl));
- VGOFF_(helper_shldw)
- = alloc_BaB_1_set( (Addr) & VG_(helper_shldw));
- VGOFF_(helper_shrdl)
- = alloc_BaB_1_set( (Addr) & VG_(helper_shrdl));
- VGOFF_(helper_shrdw)
- = alloc_BaB_1_set( (Addr) & VG_(helper_shrdw));
-
- VGOFF_(helper_RDTSC)
- = alloc_BaB_1_set( (Addr) & VG_(helper_RDTSC));
- VGOFF_(helper_CPUID)
- = alloc_BaB_1_set( (Addr) & VG_(helper_CPUID));
-
- VGOFF_(helper_bsf)
- = alloc_BaB_1_set( (Addr) & VG_(helper_bsf));
- VGOFF_(helper_bsr)
- = alloc_BaB_1_set( (Addr) & VG_(helper_bsr));
-
- VGOFF_(helper_fstsw_AX)
- = alloc_BaB_1_set( (Addr) & VG_(helper_fstsw_AX));
- VGOFF_(helper_SAHF)
- = alloc_BaB_1_set( (Addr) & VG_(helper_SAHF));
- VGOFF_(helper_LAHF)
- = alloc_BaB_1_set( (Addr) & VG_(helper_LAHF));
- VGOFF_(helper_DAS)
- = alloc_BaB_1_set( (Addr) & VG_(helper_DAS));
- VGOFF_(helper_DAA)
- = alloc_BaB_1_set( (Addr) & VG_(helper_DAA));
- VGOFF_(helper_IN)
- = alloc_BaB_1_set( (Addr) & VG_(helper_IN));
- VGOFF_(helper_OUT)
- = alloc_BaB_1_set( (Addr) & VG_(helper_OUT));
- VGOFF_(helper_cmpxchg8b)
- = alloc_BaB_1_set( (Addr) & VG_(helper_cmpxchg8b));
-
- VGOFF_(helper_undefined_instruction)
- = alloc_BaB_1_set( (Addr) & VG_(helper_undefined_instruction));
-
- /* Allocate slots for noncompact helpers */
- assign_helpers_in_baseBlock(VG_(n_noncompact_helpers),
- VG_(noncompact_helper_offsets),
- VG_(noncompact_helper_addrs));
-
-
- /* Initialise slots that require it */
- VG_(copy_m_state_static_to_baseBlock)();
-
- /* Pretend the root thread has a completely empty LDT to start with. */
- VG_(baseBlock)[VGOFF_(ldt)] = (UInt)NULL;
-
- /* Pretend the root thread has no TLS array for now. */
- VG_(baseBlock)[VGOFF_(tls)] = (UInt)NULL;
-
- /* Initialise shadow regs */
- if (VG_(needs).shadow_regs) {
- VG_(baseBlock)[VGOFF_(sh_esp)] =
- VG_(baseBlock)[VGOFF_(sh_ebp)] =
- VG_(baseBlock)[VGOFF_(sh_eax)] =
- VG_(baseBlock)[VGOFF_(sh_ecx)] =
- VG_(baseBlock)[VGOFF_(sh_edx)] =
- VG_(baseBlock)[VGOFF_(sh_ebx)] =
- VG_(baseBlock)[VGOFF_(sh_esi)] =
- VG_(baseBlock)[VGOFF_(sh_edi)] = 0;
- VG_(baseBlock)[VGOFF_(sh_eflags)] = 0;
- VG_TRACK( post_regs_write_init );
- }
-}
-
+/* As deduced from esp_at_startup, the client's argc, argv[] and
+ envp[] as extracted from the client's stack at startup-time. */
+Int VG_(client_argc);
+Char** VG_(client_argv);
+Char** VG_(client_envp);
/* ---------------------------------------------------------------------
- Global entities which are not referenced from generated code.
+ Running stuff
------------------------------------------------------------------ */
-
-/* Ditto our signal delivery stack. */
+/* Our signal delivery stack. */
UInt VG_(sigstack)[VG_SIGSTACK_SIZE_W];
/* Saving stuff across system calls. */
@@ -481,9 +153,13 @@
UInt VG_(real_sse_state_saved_over_syscall)[VG_SIZE_OF_SSESTATE_W];
Addr VG_(esp_saved_over_syscall);
-/* Counts downwards in vg_run_innerloop. */
-UInt VG_(dispatch_ctr);
+/* jmp_buf for fatal signals */
+Int VG_(fatal_sigNo) = -1;
+Bool VG_(fatal_signal_set) = False;
+jmp_buf VG_(fatal_signal_jmpbuf);
+/* Counts downwards in VG_(run_innerloop). */
+UInt VG_(dispatch_ctr);
/* 64-bit counter for the number of basic blocks done. */
ULong VG_(bbs_done);
@@ -493,23 +169,23 @@
/* This is the ThreadId of the last thread the scheduler ran. */
ThreadId VG_(last_run_tid) = 0;
+/* Tell the logging mechanism whether we are logging to a file
+ descriptor or a socket descriptor. */
+Bool VG_(logging_to_filedes) = True;
+
+/* This Bool is needed by wrappers in vg_clientmalloc.c to decide how
+ to behave. Initially we say False. */
+Bool VG_(running_on_simd_CPU) = False;
+
/* This is the argument to __NR_exit() supplied by the first thread to
call that syscall. We eventually pass that to __NR_exit() for
real. */
Int VG_(exitcode) = 0;
-/* Tell the logging mechanism whether we are logging to a file
- descriptor or a socket descriptor. */
-Bool VG_(logging_to_filedes) = True;
-/* This is set early to inidicate whether this CPU has the
- SSE/fxsave/fxrestor features. */
-Bool VG_(have_ssestate);
-
-
-/* ---------------------------------------------------------------------
- Counters, for informational purposes only.
- ------------------------------------------------------------------ */
+/*====================================================================*/
+/*=== Counters, for profiling purposes only ===*/
+/*====================================================================*/
/* Number of lookups which miss the fast tt helper. */
UInt VG_(tt_fast_misses) = 0;
@@ -558,9 +234,1132 @@
UInt VG_(num_scheduling_events_MAJOR) = 0;
-/* ---------------------------------------------------------------------
- Values derived from command-line options.
- ------------------------------------------------------------------ */
+static __inline__ Int safe_idiv(Int a, Int b)
+{
+ return (b == 0 ? 0 : a / b);
+}
+
+static void show_counts ( void )
+{
+ VG_(message)(Vg_DebugMsg,
+ " TT/TC: %d tc sectors discarded.",
+ VG_(number_of_tc_discards) );
+ VG_(message)(Vg_DebugMsg,
+ " %d chainings, %d unchainings.",
+ VG_(bb_enchain_count), VG_(bb_dechain_count) );
+ VG_(message)(Vg_DebugMsg,
+ "translate: new %d (%d -> %d; ratio %d:10)",
+ VG_(overall_in_count),
+ VG_(overall_in_osize),
+ VG_(overall_in_tsize),
+ safe_idiv(10*VG_(overall_in_tsize), VG_(overall_in_osize)));
+ VG_(message)(Vg_DebugMsg,
+ " discard %d (%d -> %d; ratio %d:10).",
+ VG_(overall_out_count),
+ VG_(overall_out_osize),
+ VG_(overall_out_tsize),
+ safe_idiv(10*VG_(overall_out_tsize), VG_(overall_out_osize)));
+ VG_(message)(Vg_DebugMsg,
+ " dispatch: %llu jumps (bb entries), of which %u (%lu%%) were unchained.",
+ VG_(bbs_done),
+ VG_(unchained_jumps_done),
+ ((ULong)(100) * (ULong)(VG_(unchained_jumps_done)))
+ / ( VG_(bbs_done)==0 ? 1 : VG_(bbs_done) )
+ );
+
+ VG_(message)(Vg_DebugMsg,
+ " %d/%d major/minor sched events. %d tt_fast misses.",
+ VG_(num_scheduling_events_MAJOR),
+ VG_(num_scheduling_events_MINOR),
+ VG_(tt_fast_misses));
+
+ VG_(message)(Vg_DebugMsg,
+ "reg-alloc: %d t-req-spill, "
+ "%d+%d orig+spill uis, %d total-reg-r.",
+ VG_(translations_needing_spill),
+ VG_(uinstrs_prealloc),
+ VG_(uinstrs_spill),
+ VG_(total_reg_rank) );
+ VG_(message)(Vg_DebugMsg,
+ " sanity: %d cheap, %d expensive checks.",
+ VG_(sanity_fast_count),
+ VG_(sanity_slow_count) );
+ VG_(print_ccall_stats)();
+}
+
+
+/*====================================================================*/
+/*=== Miscellaneous global functions ===*/
+/*====================================================================*/
+
+/* Start GDB and get it to attach to this process. Called if the user
+ requests this service after an error has been shown, so she can
+ poke around and look at parameters, memory, etc. You can't
+ meaningfully get GDB to continue the program, though; to continue,
+ quit GDB. */
+void VG_(start_GDB) ( Int tid )
+{
+ Int pid;
+
+ if ((pid = fork()) == 0) {
+ ptrace(PTRACE_TRACEME, 0, NULL, NULL);
+ VG_(kkill)(VG_(getpid)(), VKI_SIGSTOP);
+
+ } else if (pid > 0) {
+ struct user_regs_struct regs;
+ Int status;
+ Int res;
+
+ if (VG_(is_running_thread)( tid )) {
+ regs.xcs = VG_(baseBlock)[VGOFF_(m_cs)];
+ regs.xss = VG_(baseBlock)[VGOFF_(m_ss)];
+ regs.xds = VG_(baseBlock)[VGOFF_(m_ds)];
+ regs.xes = VG_(baseBlock)[VGOFF_(m_es)];
+ regs.xfs = VG_(baseBlock)[VGOFF_(m_fs)];
+ regs.xgs = VG_(baseBlock)[VGOFF_(m_gs)];
+ regs.eax = VG_(baseBlock)[VGOFF_(m_eax)];
+ regs.ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
+ regs.ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
+ regs.edx = VG_(baseBlock)[VGOFF_(m_edx)];
+ regs.esi = VG_(baseBlock)[VGOFF_(m_esi)];
+ regs.edi = VG_(baseBlock)[VGOFF_(m_edi)];
+ regs.ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
+ regs.esp = VG_(baseBlock)[VGOFF_(m_esp)];
+ regs.eflags = VG_(baseBlock)[VGOFF_(m_eflags)];
+ regs.eip = VG_(baseBlock)[VGOFF_(m_eip)];
+ } else {
+ ThreadState* tst = & VG_(threads)[ tid ];
+
+ regs.xcs = tst->m_cs;
+ regs.xss = tst->m_ss;
+ regs.xds = tst->m_ds;
+ regs.xes = tst->m_es;
+ regs.xfs = tst->m_fs;
+ regs.xgs = tst->m_gs;
+ regs.eax = tst->m_eax;
+ regs.ebx = tst->m_ebx;
+ regs.ecx = tst->m_ecx;
+ regs.edx = tst->m_edx;
+ regs.esi = tst->m_esi;
+ regs.edi = tst->m_edi;
+ regs.ebp = tst->m_ebp;
+ regs.esp = tst->m_esp;
+ regs.eflags = tst->m_eflags;
+ regs.eip = tst->m_eip;
+ }
+
+ if ((res = VG_(waitpid)(pid, &status, 0)) == pid &&
+ WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP &&
+ ptrace(PTRACE_SETREGS, pid, NULL, ®s) == 0 &&
+ ptrace(PTRACE_DETACH, pid, NULL, SIGSTOP) == 0) {
+ UChar buf[VG_(strlen)(VG_(clo_GDB_path)) + 100];
+
+ VG_(sprintf)(buf, "%s -nw /proc/%d/fd/%d %d",
+ VG_(clo_GDB_path), VG_(main_pid), VG_(clexecfd), pid);
+ VG_(message)(Vg_UserMsg, "starting GDB with cmd: %s", buf);
+ res = VG_(system)(buf);
+ if (res == 0) {
+ VG_(message)(Vg_UserMsg, "");
+ VG_(message)(Vg_UserMsg,
+ "GDB has detached. Valgrind regains control. We continue.");
+ } else {
+ VG_(message)(Vg_UserMsg, "Apparently failed!");
+ VG_(message)(Vg_UserMsg, "");
+ }
+ }
+
+ VG_(kkill)(pid, VKI_SIGKILL);
+ VG_(waitpid)(pid, &status, 0);
+ }
+}
+
+
+/* Print some helpful-ish text about unimplemented things, and give
+ up. */
+void VG_(unimplemented) ( Char* msg )
+{
+ VG_(message)(Vg_UserMsg, "");
+ VG_(message)(Vg_UserMsg,
+ "Valgrind detected that your program requires");
+ VG_(message)(Vg_UserMsg,
+ "the following unimplemented functionality:");
+ VG_(message)(Vg_UserMsg, " %s", msg);
+ VG_(message)(Vg_UserMsg,
+ "This may be because the functionality is hard to implement,");
+ VG_(message)(Vg_UserMsg,
+ "or because no reasonable program would behave this way,");
+ VG_(message)(Vg_UserMsg,
+ "or because nobody has yet needed it. In any case, let us know at");
+ VG_(message)(Vg_UserMsg,
+ "%s and/or try to work around the problem, if you can.", VG_BUGS_TO);
+ VG_(message)(Vg_UserMsg,
+ "");
+ VG_(message)(Vg_UserMsg,
+ "Valgrind has to exit now. Sorry. Bye!");
+ VG_(message)(Vg_UserMsg,
+ "");
+ VG_(pp_sched_status)();
+ VG_(exit)(1);
+}
+
+Addr VG_(get_stack_pointer) ( void )
+{
+ return VG_(baseBlock)[VGOFF_(m_esp)];
+}
+
+/* Debugging thing .. can be called from assembly with OYNK macro. */
+void VG_(oynk) ( Int n )
+{
+ OINK(n);
+}
+
+/* Initialize the PID and PGRP of scheduler LWP; this is also called
+ in any new children after fork. */
+static void newpid(ThreadId unused)
+{
+ /* PID of scheduler LWP */
+ VG_(main_pid) = VG_(getpid)();
+ VG_(main_pgrp) = VG_(getpgrp)();
+}
+
+/*====================================================================*/
+/*=== Check we were launched by stage 1 ===*/
+/*====================================================================*/
+
+/* Look for our AUXV table */
+static void scan_auxv(void)
+{
+ const struct ume_auxv *auxv = find_auxv((int *)ume_exec_esp);
+ int found = 0;
+
+ for (; auxv->a_type != AT_NULL; auxv++)
+ switch(auxv->a_type) {
+ case AT_UME_PADFD:
+ as_setpadfd(auxv->u.a_val);
+ found |= 1;
+ break;
+
+ case AT_UME_EXECFD:
+ VG_(vgexecfd) = auxv->u.a_val;
+ found |= 2;
+ break;
+ }
+
+ if ( ! (1|2) ) {
+ fprintf(stderr, "stage2 must be launched by stage1\n");
+ exit(127);
+ }
+}
+
+
+/*====================================================================*/
+/*=== Address space determination ===*/
+/*====================================================================*/
+
+/* Pad client space so it doesn't get filled in before the right time */
+static void layout_client_space(Addr argc_addr)
+{
+ VG_(client_base) = CLIENT_BASE;
+ VG_(valgrind_mmap_end) = (addr_t)&kickstart_base; /* end of V's mmaps */
+ VG_(valgrind_base) = VG_(valgrind_mmap_end) - VALGRIND_MAPSIZE;
+ VG_(valgrind_end) = ROUNDUP(argc_addr, 0x10000); /* stack */
+
+ if (0)
+ printf("client base: %x\n"
+ "valgrind base--end: %x--%x (%x)\n"
+ "valgrind mmap end: %x\n\n",
+ VG_(client_base),
+ VG_(valgrind_base), VG_(valgrind_end),
+ VG_(valgrind_end) - VG_(valgrind_base),
+ VG_(valgrind_mmap_end));
+
+ as_pad((void *)VG_(client_base), (void *)VG_(valgrind_base));
+}
+
+static void layout_remaining_space(float ratio)
+{
+ /* This tries to give the client as large as possible address space while
+ * taking into account the tool's shadow needs. */
+ addr_t client_size = ROUNDDN((VG_(valgrind_base) - REDZONE_SIZE) / (1. + ratio),
+ CLIENT_SIZE_MULTIPLE);
+ addr_t shadow_size = PGROUNDUP(client_size * ratio);
+
+ VG_(client_end) = VG_(client_base) + client_size;
+ VG_(client_mapbase) = PGROUNDDN((client_size/4)*3); /* where !FIXED mmap goes */
+ VG_(client_trampoline_code) = VG_(client_end) - VKI_BYTES_PER_PAGE;
+
+ VG_(shadow_base) = VG_(client_end) + REDZONE_SIZE;
+ VG_(shadow_end) = VG_(shadow_base) + shadow_size;
+
+ if (0)
+ printf("client base--end: %x--%x (%x)\n"
+ "client mapbase: %x\n"
+ "shadow base--end: %x--%x (%x)\n\n",
+ VG_(client_base), VG_(client_end), client_size,
+ VG_(client_mapbase),
+ VG_(shadow_base), VG_(shadow_end), shadow_size);
+
+ // Ban redzone
+ mmap((void *)VG_(client_end), REDZONE_SIZE, PROT_NONE,
+ MAP_FIXED|MAP_ANON|MAP_PRIVATE, -1, 0);
+
+ // Make client hole
+ munmap((void*)VG_(client_base), client_size);
+
+ // Map shadow memory.
+ // Initially all inaccessible, incrementally initialized as it is used
+ if (shadow_size != 0)
+ mmap((char *)VG_(shadow_base), shadow_size, PROT_NONE,
+ MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0);
+}
+
+/*====================================================================*/
+/*=== Command line setup ===*/
+/*====================================================================*/
+
+/* Nb: malloc'd memory never freed -- kept throughout like argv, envp */
+static char* get_file_clo(char* dir)
+{
+# define FLEN 512
+ Int fd, n;
+ struct stat s1;
+ char* f_clo = NULL;
+ char filename[FLEN];
+
+ snprintf(filename, FLEN, "%s/.valgrindrc", ( NULL == dir ? "" : dir ) );
+ fd = VG_(open)(filename, 0, VKI_S_IRUSR);
+ if ( fd > 0 ) {
+ if ( 0 == fstat(fd, &s1) ) {
+ f_clo = malloc(s1.st_size+1);
+ vg_assert(f_clo);
+ n = read(fd, f_clo, s1.st_size);
+ if (n == -1) n = 0;
+ f_clo[n] = '\0';
+ }
+ close(fd);
+ }
+ return f_clo;
+# undef FLEN
+}
+
+static Int count_args(char* s)
+{
+ Int n = 0;
+ if (s) {
+ char* cp = s;
+ while (True) {
+ // We have alternating sequences: blanks, non-blanks, blanks...
+ // count the non-blanks sequences.
+ while ( ISSPACE(*cp) ) cp++;
+ if ( !*cp ) break;
+ n++;
+ while ( !ISSPACE(*cp) && *cp ) cp++;
+ }
+ }
+ return n;
+}
+
+/* add args out of environment, skipping multiple spaces and -- args */
+static char** copy_args( char* s, char** to )
+{
+ if (s) {
+ char* cp = s;
+ while (True) {
+ // We have alternating sequences: blanks, non-blanks, blanks...
+ // copy the non-blanks sequences, and add terminating '\0'
+ while ( ISSPACE(*cp) ) cp++;
+ if ( !*cp ) break;
+ *to++ = cp;
+ while ( !ISSPACE(*cp) && *cp ) cp++;
+ if ( *cp ) *cp++ = '\0'; // terminate if necessary
+ if (VG_STREQ(to[-1], "--")) to--; // undo any '--' arg
+ }
+ }
+ return to;
+}
+
+// Augment command line with arguments from environment and .valgrindrc
+// files.
+static void augment_command_line(Int* vg_argc_inout, char*** vg_argv_inout)
+{
+ int vg_argc = *vg_argc_inout;
+ char** vg_argv = *vg_argv_inout;
+
+ char* env_clo = getenv(VALGRINDOPTS);
+ char* f1_clo = get_file_clo( getenv("HOME") );
+ char* f2_clo = get_file_clo(".");
+
+ /* copy any extra args from file or environment, if present */
+ if ( (env_clo && *env_clo) || (f1_clo && *f1_clo) || (f2_clo && *f2_clo) ) {
+ /* ' ' separated extra options */
+ char **from;
+ char **to;
+ int env_arg_count, f1_arg_count, f2_arg_count;
+
+ env_arg_count = count_args(env_clo);
+ f1_arg_count = count_args(f1_clo);
+ f2_arg_count = count_args(f2_clo);
+
+ if (0)
+ printf("extra-argc=%d %d %d\n",
+ env_arg_count, f1_arg_count, f2_arg_count);
+
+ /* +2: +1 for null-termination, +1 for added '--' */
+ from = vg_argv;
+ vg_argv = malloc( (vg_argc + env_arg_count + f1_arg_count
+ + f2_arg_count + 2) * sizeof(char **));
+ to = vg_argv;
+
+ /* copy argv[0] */
+ *to++ = *from++;
+
+ /* Copy extra args from env var and file, in the order: ~/.valgrindrc,
+ * $VALGRIND_OPTS, ./.valgrindrc -- more local options are put later
+ * to override less local ones. */
+ to = copy_args(f1_clo, to);
+ to = copy_args(env_clo, to);
+ to = copy_args(f2_clo, to);
+
+ /* copy original arguments, stopping at command or -- */
+ while (*from) {
+ if (**from != '-')
+ break;
+ if (VG_STREQ(*from, "--")) {
+ from++; /* skip -- */
+ break;
+ }
+ *to++ = *from++;
+ }
+
+ /* add -- */
+ *to++ = "--";
+
+ vg_argc = to - vg_argv;
+
+ /* copy rest of original command line, then NULL */
+ while (*from) *to++ = *from++;
+ *to = NULL;
+ }
+
+ *vg_argc_inout = vg_argc;
+ *vg_argv_inout = vg_argv;
+}
+
+static void get_command_line( int argc, char** argv,
+ Int* vg_argc_out, Char*** vg_argv_out,
+ char*** cl_argv_out )
+{
+ int vg_argc;
+ char** vg_argv;
+ char** cl_argv;
+ char* env_clo = getenv(VALGRINDCLO);
+
+ if (env_clo != NULL && *env_clo != '\0') {
+ char *cp;
+ char **cpp;
+
+ /* OK, we're getting all our arguments from the environment - the
+ entire command line belongs to the client (including argv[0]) */
+ vg_argc = 1; /* argv[0] */
+ for (cp = env_clo; *cp; cp++)
+ if (*cp == '\01')
+ vg_argc++;
+
+ vg_argv = malloc(sizeof(char **) * (vg_argc + 1));
+
+ cpp = vg_argv;
+
+ *cpp++ = "valgrind"; /* nominal argv[0] */
+ *cpp++ = env_clo;
+
+ for (cp = env_clo; *cp; cp++) {
+ if (*cp == '\01') {
+ *cp++ = '\0'; /* chop it up in place */
+ *cpp++ = cp;
+ }
+ }
+ *cpp = NULL;
+ cl_argv = argv;
+
+ } else {
+ /* Count the arguments on the command line. */
+ vg_argv = argv;
+
+ for (vg_argc = 1; vg_argc < argc; vg_argc++) {
+ if (argv[vg_argc][0] != '-') /* exe name */
+ break;
+ if (VG_STREQ(argv[vg_argc], "--")) { /* dummy arg */
+ vg_argc++;
+ break;
+ }
+ }
+ cl_argv = &argv[vg_argc];
+
+ /* Get extra args from VALGRIND_OPTS and .valgrindrc files.
+ * Note we don't do this if getting args from VALGRINDCLO. */
+ augment_command_line(&vg_argc, &vg_argv);
+ }
+
+ if (0) {
+ Int i;
+ for (i = 0; i < vg_argc; i++)
+ printf("vg_argv[%d]=\"%s\"\n", i, vg_argv[i]);
+ }
+
+ *vg_argc_out = vg_argc;
+ *vg_argv_out = (Char**)vg_argv;
+ *cl_argv_out = cl_argv;
+}
+
+
+/*====================================================================*/
+/*=== Environment and stack setup ===*/
+/*====================================================================*/
+
+/* Scan a colon-separated list, and call a function on each element.
+ The string must be mutable, because we insert a temporary '\0', but
+ the string will end up unmodified. (*func) should return 1 if it
+ doesn't need to see any more.
+*/
+static void scan_colsep(char *colsep, int (*func)(const char *))
+{
+ char *cp, *entry;
+ int end;
+
+ if (colsep == NULL ||
+ *colsep == '\0')
+ return;
+
+ entry = cp = colsep;
+
+ do {
+ end = (*cp == '\0');
+
+ if (*cp == ':' || *cp == '\0') {
+ char save = *cp;
+
+ *cp = '\0';
+ if ((*func)(entry))
+ end = 1;
+ *cp = save;
+ entry = cp+1;
+ }
+ cp++;
+ } while(!end);
+}
+
+/* Prepare the client's environment. This is basically a copy of our
+ environment, except:
+ 1. LD_LIBRARY_PATH=$VALGRINDLIB:$LD_LIBRARY_PATH
+ 2. LD_PRELOAD=$VALGRINDLIB/vg_inject.so:($VALGRINDLIB/vgpreload_TOOL.so:)?$LD_PRELOAD
+
+ If any of these is missing, then it is added.
+
+ Yummy. String hacking in C.
+
+ If this needs to handle any more variables it should be hacked
+ into something table driven.
+ */
+static char **fix_environment(char **origenv, const char *preload)
+{
+ static const char inject_so[] = "vg_inject.so";
+ static const char ld_library_path[] = "LD_LIBRARY_PATH=";
+ static const char ld_preload[] = "LD_PRELOAD=";
+ static const char valgrind_clo[] = VALGRINDCLO "=";
+ static const int ld_library_path_len = sizeof(ld_library_path)-1;
+ static const int ld_preload_len = sizeof(ld_preload)-1;
+ static const int valgrind_clo_len = sizeof(valgrind_clo)-1;
+ int ld_preload_done = 0;
+ int ld_library_path_done = 0;
+ char *inject_path;
+ int inject_path_len;
+ int vgliblen = strlen(VG_(libdir));
+ char **cpp;
+ char **ret;
+ int envc;
+ const int preloadlen = (preload == NULL) ? 0 : strlen(preload);
+
+ /* Find the vg_inject.so; also make room for the tool preload
+ library */
+ inject_path_len = sizeof(inject_so) + vgliblen + preloadlen + 16;
+ inject_path = malloc(inject_path_len);
+
+ if (preload)
+ snprintf(inject_path, inject_path_len, "%s/%s:%s",
+ VG_(libdir), inject_so, preload);
+ else
+ snprintf(inject_path, inject_path_len, "%s/%s",
+ VG_(libdir), inject_so);
+
+ /* Count the original size of the env */
+ envc = 0; /* trailing NULL */
+ for (cpp = origenv; cpp && *cpp; cpp++)
+ envc++;
+
+ /* Allocate a new space */
+ ret = malloc(sizeof(char *) * (envc+3+1)); /* 3 new entries + NULL */
+
+ /* copy it over */
+ for (cpp = ret; *origenv; )
+ *cpp++ = *origenv++;
+ *cpp = NULL;
+
+ vg_assert(envc == (cpp - ret));
+
+ /* Walk over the new environment, mashing as we go */
+ for (cpp = ret; cpp && *cpp; cpp++) {
+ if (memcmp(*cpp, ld_library_path, ld_library_path_len) == 0) {
+ int done = 0;
+ int contains(const char *p) {
+ if (VG_STREQ(p, VG_(libdir))) {
+ done = 1;
+ return 1;
+ }
+ return 0;
+ }
+
+ /* If the LD_LIBRARY_PATH already contains libdir, then don't
+ bother adding it again, even if it isn't the first (it
+ seems that the Java runtime will keep reexecing itself
+ unless its paths are at the front of LD_LIBRARY_PATH) */
+ scan_colsep(*cpp + ld_library_path_len, contains);
+
+ if (!done) {
+ int len = strlen(*cpp) + vgliblen*2 + 16;
+ char *cp = malloc(len);
+
+ snprintf(cp, len, "%s%s:%s",
+ ld_library_path, VG_(libdir),
+ (*cpp)+ld_library_path_len);
+
+ *cpp = cp;
+ }
+
+ ld_library_path_done = 1;
+ } else if (memcmp(*cpp, ld_preload, ld_preload_len) == 0) {
+ int len = strlen(*cpp) + inject_path_len;
+ char *cp = malloc(len);
+
+ snprintf(cp, len, "%s%s:%s",
+ ld_preload, inject_path, (*cpp)+ld_preload_len);
+
+ *cpp = cp;
+
+ ld_preload_done = 1;
+ } else if (memcmp(*cpp, valgrind_clo, valgrind_clo_len) == 0) {
+ *cpp = "";
+ }
+ }
+
+ /* Add the missing bits */
+
+ if (!ld_library_path_done) {
+ int len = ld_library_path_len + vgliblen*2 + 16;
+ char *cp = malloc(len);
+
+ snprintf(cp, len, "%s%s", ld_library_path, VG_(libdir));
+
+ ret[envc++] = cp;
+ }
+
+ if (!ld_preload_done) {
+ int len = ld_preload_len + inject_path_len;
+ char *cp = malloc(len);
+
+ snprintf(cp, len, "%s%s",
+ ld_preload, inject_path);
+
+ ret[envc++] = cp;
+ }
+
+ ret[envc] = NULL;
+
+ return ret;
+}
+
+extern char **environ; /* our environment */
+//#include <error.h>
+
+/* Add a string onto the string table, and return its address */
+static char *copy_str(char **tab, const char *str)
+{
+ char *cp = *tab;
+ char *orig = cp;
+
+ while(*str)
+ *cp++ = *str++;
+ *cp++ = '\0';
+
+ if (0)
+ printf("copied %p \"%s\" len %d\n",
+ orig, orig, cp-orig);
+
+ *tab = cp;
+
+ return orig;
+}
+
+/*
+ This sets up the client's initial stack, containing the args,
+ environment and aux vector.
+
+ The format of the stack is:
+
+ higher address +-----------------+
+ | Trampoline code |
+ +-----------------+
+ | |
+ : string table :
+ | |
+ +-----------------+
+ | AT_NULL |
+ - -
+ | auxv |
+ +-----------------+
+ | NULL |
+ - -
+ | envp |
+ +-----------------+
+ | NULL |
+ - -
+ | argv |
+ +-----------------+
+ | argc |
+ lower address +-----------------+ <- esp
+ | undefined |
+ : :
+ */
+static Addr setup_client_stack(char **orig_argv, char **orig_envp,
+ const struct exeinfo *info,
+ UInt** client_auxv)
+{
+ char **cpp;
+ char *strtab; /* string table */
+ char *stringbase;
+ addr_t *ptr;
+ struct ume_auxv *auxv;
+ const struct ume_auxv *orig_auxv;
+ const struct ume_auxv *cauxv;
+ unsigned stringsize; /* total size of strings in bytes */
+ unsigned auxsize; /* total size of auxv in bytes */
+ int argc; /* total argc */
+ int envc; /* total number of env vars */
+ unsigned stacksize; /* total client stack size */
+ addr_t cl_esp; /* client stack base (initial esp) */
+
+ /* use our own auxv as a prototype */
+ orig_auxv = find_auxv(ume_exec_esp);
+
+ /* ==================== compute sizes ==================== */
+
+ /* first of all, work out how big the client stack will be */
+ stringsize = 0;
+
+ /* paste on the extra args if the loader needs them (ie, the #!
+ interpreter and its argument) */
+ argc = 0;
+ if (info->argv0 != NULL) {
+ argc++;
+ stringsize += strlen(info->argv0) + 1;
+ }
+ if (info->argv1 != NULL) {
+ argc++;
+ stringsize += strlen(info->argv1) + 1;
+ }
+
+ /* now scan the args we're given... */
+ for (cpp = orig_argv; *cpp; cpp++) {
+ argc++;
+ stringsize += strlen(*cpp) + 1;
+ }
+
+ /* ...and the environment */
+ envc = 0;
+ for (cpp = orig_envp; cpp && *cpp; cpp++) {
+ envc++;
+ stringsize += strlen(*cpp) + 1;
+ }
+
+ /* now, how big is the auxv? */
+ auxsize = sizeof(*auxv); /* there's always at least one entry: AT_NULL */
+ for (cauxv = orig_auxv; cauxv->a_type != AT_NULL; cauxv++) {
+ if (cauxv->a_type == AT_PLATFORM)
+ stringsize += strlen(cauxv->u.a_ptr) + 1;
+ auxsize += sizeof(*cauxv);
+ }
+
+ /* OK, now we know how big the client stack is */
+ stacksize =
+ sizeof(int) + /* argc */
+ sizeof(char **)*argc + /* argv */
+ sizeof(char **) + /* terminal NULL */
+ sizeof(char **)*envc + /* envp */
+ sizeof(char **) + /* terminal NULL */
+ auxsize + /* auxv */
+ ROUNDUP(stringsize, sizeof(int)) +/* strings (aligned) */
+ VKI_BYTES_PER_PAGE; /* page for trampoline code */
+
+ /* cl_esp is the client's stack pointer */
+ cl_esp = VG_(client_end) - stacksize;
+ cl_esp = ROUNDDN(cl_esp, 16); /* make stack 16 byte aligned */
+
+ if (0)
+ printf("stringsize=%d auxsize=%d stacksize=%d\n",
+ stringsize, auxsize, stacksize);
+
+
+ /* base of the string table (aligned) */
+ stringbase = strtab = (char *)(VG_(client_trampoline_code) - ROUNDUP(stringsize, sizeof(int)));
+
+ VG_(clstk_base) = PGROUNDDN(cl_esp);
+ VG_(clstk_end) = VG_(client_end);
+
+ /* ==================== allocate space ==================== */
+
+ /* allocate a stack - mmap enough space for the stack */
+ mmap((void *)PGROUNDDN(cl_esp),
+ VG_(client_end) - PGROUNDDN(cl_esp),
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
+
+
+ /* ==================== copy client stack ==================== */
+
+ ptr = (addr_t *)cl_esp;
+
+ /* --- argc --- */
+ *ptr++ = argc; /* client argc */
+
+ /* --- argv --- */
+ if (info->argv0) {
+ *ptr++ = (addr_t)copy_str(&strtab, info->argv0);
+ free(info->argv0);
+ }
+ if (info->argv1) {
+ *ptr++ = (addr_t)copy_str(&strtab, info->argv1);
+ free(info->argv1);
+ }
+ for (cpp = orig_argv; *cpp; ptr++, cpp++) {
+ *ptr = (addr_t)copy_str(&strtab, *cpp);
+ }
+ *ptr++ = 0;
+
+ /* --- envp --- */
+ VG_(client_envp) = (Char **)ptr;
+ for (cpp = orig_envp; cpp && *cpp; ptr++, cpp++)
+ *ptr = (addr_t)copy_str(&strtab, *cpp);
+ *ptr++ = 0;
+
+ /* --- auxv --- */
+ auxv = (struct ume_auxv *)ptr;
+ *client_auxv = (UInt *)auxv;
+
+ for (; orig_auxv->a_type != AT_NULL; auxv++, orig_auxv++) {
+ /* copy the entry... */
+ *auxv = *orig_auxv;
+
+ /* ...and fix up the copy */
+ switch(auxv->a_type) {
+ case AT_PHDR:
+ if (info->phdr == 0)
+ auxv->a_type = AT_IGNORE;
+ else
+ auxv->u.a_val = info->phdr;
+ break;
+
+ case AT_PHNUM:
+ if (info->phdr == 0)
+ auxv->a_type = AT_IGNORE;
+ else
+ auxv->u.a_val = info->phnum;
+ break;
+
+ case AT_BASE:
+ if (info->interp_base == 0)
+ auxv->a_type = AT_IGNORE;
+ else
+ auxv->u.a_val = info->interp_base;
+ break;
+
+ case AT_PLATFORM: /* points to a platform description string */
+ auxv->u.a_ptr = copy_str(&strtab, orig_auxv->u.a_ptr);
+ break;
+
+ case AT_ENTRY:
+ auxv->u.a_val = info->entry;
+ break;
+
+ case AT_IGNORE:
+ case AT_EXECFD:
+ case AT_PHENT:
+ case AT_PAGESZ:
+ case AT_FLAGS:
+ case AT_NOTELF:
+ case AT_UID:
+ case AT_EUID:
+ case AT_GID:
+ case AT_EGID:
+ case AT_CLKTCK:
+ case AT_HWCAP:
+ case AT_FPUCW:
+ case AT_DCACHEBSIZE:
+ case AT_ICACHEBSIZE:
+ case AT_UCACHEBSIZE:
+ /* All these are pointerless, so we don't need to do anything
+ about them. */
+ break;
+
+ case AT_SECURE:
+ /* If this is 1, then it means that this program is running
+ suid, and therefore the dynamic linker should be careful
+ about LD_PRELOAD, etc. However, since stage1 (the thing
+ the kernel actually execve's) should never be SUID, and we
+ need LD_PRELOAD/LD_LIBRARY_PATH to work for the client, we
+ set AT_SECURE to 0. */
+ auxv->u.a_val = 0;
+ break;
+
+ case AT_SYSINFO:
+ /* Leave this unmolested for now, but we'll update it later
+ when we set up the client trampoline code page */
+ break;
+
+ case AT_SYSINFO_EHDR:
+ /* Trash this, because we don't reproduce it */
+ auxv->a_type = AT_IGNORE;
+ break;
+
+ default:
+ /* stomp out anything we don't know about */
+ if (0)
+ printf("stomping auxv entry %d\n", auxv->a_type);
+ auxv->a_type = AT_IGNORE;
+ break;
+
+ }
+ }
+ *auxv = *orig_auxv;
+ vg_assert(auxv->a_type == AT_NULL);
+
+ vg_assert((strtab-stringbase) == stringsize);
+
+ return cl_esp;
+}
+
+/*====================================================================*/
+/*=== Find executable ===*/
+/*====================================================================*/
+
+static const char* find_executable(const char* exec)
+{
+ vg_assert(NULL != exec);
+ if (strchr(exec, '/') == NULL) {
+ /* no '/' - we need to search the path */
+ char *path = getenv("PATH");
+ int pathlen = path ? strlen(path) : 0;
+
+ int match_exe(const char *entry) {
+ char buf[pathlen + strlen(entry) + 3];
+
+ /* empty PATH element means . */
+ if (*entry == '\0')
+ entry = ".";
+
+ snprintf(buf, sizeof(buf), "%s/%s", entry, exec);
+
+ if (access(buf, R_OK|X_OK) == 0) {
+ exec = strdup(buf);
+ vg_assert(NULL != exec);
+ return 1;
+ }
+ return 0;
+ }
+ scan_colsep(path, match_exe);
+ }
+ return exec;
+}
+
+
+/*====================================================================*/
+/*=== Loading tools ===*/
+/*====================================================================*/
+
+static void list_tools(void)
+{
+ DIR *dir = opendir(VG_(libdir));
+ struct dirent *de;
+ int first = 1;
+
+ if (dir == NULL) {
+ fprintf(stderr, "Can't open %s: %s (installation problem?)\n",
+ VG_(libdir), strerror(errno));
+ return;
+ }
+
+ while((de = readdir(dir)) != NULL) {
+ int len = strlen(de->d_name);
+
+ /* look for vgskin_TOOL.so names */
+ if (len > (7+1+3) && /* "vgskin_" + at least 1-char toolname + ".so" */
+ strncmp(de->d_name, "vgskin_", 7) == 0 &&
+ VG_STREQ(de->d_name + len - 3, ".so")) {
+ if (first) {
+ printf("Available tools:\n");
+ first = 0;
+ }
+ de->d_name[len-3] = '\0';
+ printf("\t%s\n", de->d_name+7);
+ }
+ }
+
+ closedir(dir);
+
+ if (first)
+ printf("No tools available in \"%s\" (installation problem?)\n",
+ VG_(libdir));
+}
+
+
+/* Find and load a tool, and check it looks ok. Also looks to see if there's
+ * a matching vgpreload_*.so file, and returns its name in *preloadpath. */
+static void load_tool( const char *toolname, void** handle_out,
+ ToolInfo** toolinfo_out, char **preloadpath_out )
+{
+ Bool ok;
+ int len = strlen(VG_(libdir)) + strlen(toolname)*2 + 16;
+ char buf[len];
+ void* handle;
+ ToolInfo* toolinfo;
+ char* preloadpath = NULL;
+ Int* vg_malloc_redzonep;
+
+ // XXX: allowing full paths for --tool option -- does it make sense?
+ // Doesn't allow for vgpreload_<tool>.so.
+
+ if (strchr(toolname, '/') != 0) {
+ /* toolname contains '/', and so must be a pathname */
+ handle = dlopen(toolname, RTLD_NOW);
+ } else {
+ /* just try in the libdir */
+ snprintf(buf, len, "%s/vgskin_%s.so", VG_(libdir), toolname);
+ handle = dlopen(buf, RTLD_NOW);
+
+ if (handle != NULL) {
+ snprintf(buf, len, "%s/vgpreload_%s.so", VG_(libdir), toolname);
+ if (access(buf, R_OK) == 0) {
+ preloadpath = strdup(buf);
+ vg_assert(NULL != preloadpath);
+ }
+ }
+ }
+
+ ok = (NULL != handle);
+ if (!ok) {
+ fprintf(stderr, "Can't open tool \"%s\": %s\n", toolname, dlerror());
+ goto bad_load;
+ }
+
+ toolinfo = dlsym(handle, "vgSkin_tool_info");
+ ok = (NULL != toolinfo);
+ if (!ok) {
+ fprintf(stderr, "Tool \"%s\" doesn't define SK_(tool_info) - "
+ "add VG_DETERMINE_INTERFACE_VERSION?\n", toolname);
+ goto bad_load;
+ }
+
+ ok = (toolinfo->sizeof_ToolInfo == sizeof(*toolinfo) &&
+ toolinfo->interface_major_version == VG_CORE_INTERFACE_MAJOR_VERSION &&
+ toolinfo->sk_pre_clo_init != NULL);
+ if (!ok) {
+ fprintf(stderr, "Error:\n"
+ " Tool and core interface versions do not match.\n"
+ " Interface version used by core is: %d.%d (size %d)\n"
+ " Interface version used by tool is: %d.%d (size %d)\n"
+ " The major version numbers must match.\n",
+ VG_CORE_INTERFACE_MAJOR_VERSION,
+ VG_CORE_INTERFACE_MINOR_VERSION,
+ sizeof(*toolinfo),
+ toolinfo->interface_major_version,
+ toolinfo->interface_minor_version,
+ toolinfo->sizeof_ToolInfo);
+ fprintf(stderr, " You need to at least recompile, and possibly update,\n");
+ if (VG_CORE_INTERFACE_MAJOR_VERSION > toolinfo->interface_major_version)
+ fprintf(stderr, " your skin to work with this version of Valgrind.\n");
+ else
+ fprintf(stderr, " your version of Valgrind to work with this skin.\n");
+ goto bad_load;
+ }
+
+ // Set redzone size for V's allocator
+ vg_malloc_redzonep = dlsym(handle, STR(VG_(vg_malloc_redzone_szB)));
+ if ( NULL != vg_malloc_redzonep ) {
+ VG_(vg_malloc_redzone_szB) = *vg_malloc_redzonep;
+ }
+
+ vg_assert(NULL != handle && NULL != toolinfo);
+ *handle_out = handle;
+ *toolinfo_out = toolinfo;
+ *preloadpath_out = preloadpath;
+ return;
+
+
+ bad_load:
+ if (handle != NULL)
+ dlclose(handle);
+
+ fprintf(stderr, "Aborting: couldn't load tool\n");
+ list_tools();
+ exit(127);
+}
+
+/*====================================================================*/
+/*=== Loading the client ===*/
+/*====================================================================*/
+
+static void load_client(char* cl_argv[], const char* exec,
+ /*inout*/Bool* need_help,
+ /*out*/struct exeinfo* info, /*out*/Addr* client_eip)
+{
+ // If they didn't specify an executable with --exec, and didn't specify
+ // --help, then use client argv[0] (searching $PATH if necessary).
+ if (NULL == exec && !*need_help) {
+ if (cl_argv[0] == NULL ||
+ ( NULL == (exec = find_executable(cl_argv[0])) ) )
+ {
+ *need_help = True;
+ }
+ }
+
+ info->map_base = VG_(client_mapbase);
+ info->setbrk = False;
+
+ info->exe_base = VG_(client_base);
+ info->exe_end = VG_(client_end);
+ info->argv = cl_argv;
+
+ if (*need_help) {
+ VG_(clexecfd) = -1;
+ info->argv0 = NULL;
+ info->argv1 = NULL;
+ } else {
+ Int ret;
+ VG_(clexecfd) = VG_(open)(exec, O_RDONLY, VKI_S_IRUSR);
+ ret = do_exec(exec, info);
+ if (ret != 0) {
+ fprintf(stderr, "do_exec(%s) failed: %s\n", exec, strerror(ret));
+ exit(127);
+ }
+ }
+
+ /* Copy necessary bits of 'info' that were filled in */
+ *client_eip = info->init_eip;
+ VG_(brk_base) = VG_(brk_limit) = info->brkbase;
+}
+
+
+/*====================================================================*/
+/*=== Command-line: variables, processing ===*/
+/*====================================================================*/
/* Define, and set defaults. */
Bool VG_(clo_error_limit) = True;
@@ -613,27 +1412,6 @@
Bool VG_(clo_lowlat_syscalls) = False; /* low-latency syscalls */
Bool VG_(clo_lowlat_signals) = False; /* low-latency signals */
-/* This Bool is needed by wrappers in vg_clientmalloc.c to decide how
- to behave. Initially we say False. */
-Bool VG_(running_on_simd_CPU) = False;
-
-/* Holds client's %esp at the point we gained control. */
-Addr VG_(esp_at_startup);
-
-/* Indicates presence, and holds address of client's sysinfo page, a
- feature of some modern kernels used to provide vsyscalls, etc. */
-Bool VG_(sysinfo_page_exists) = False;
-Addr VG_(sysinfo_page_addr) = 0;
-
-/* As deduced from VG_(esp_at_startup), the client's argc, argv[] and
- envp[] as extracted from the client's stack at startup-time. */
-Int VG_(client_argc);
-Char** VG_(client_argv);
-Char** VG_(client_envp);
-
-/* ---------------------------------------------------------------------
- Processing of command-line options.
- ------------------------------------------------------------------ */
void VG_(bad_option) ( Char* opt )
{
@@ -656,13 +1434,13 @@
VG_(exit)(1);
}
-void VG_(usage) ( void )
+void usage ( void )
{
Char* usage1 =
-"usage: valgrind [options] prog-and-args\n"
+"usage: valgrind --tool=<toolname> [options] prog-and-args\n"
"\n"
" common user options for all Valgrind tools, with defaults in [ ]:\n"
-" --tool=<name> Use the Valgrind tool named <name> [memcheck]\n"
+" --tool=<name> Use the Valgrind tool named <name>\n"
" --help show this message\n"
" --version show version\n"
" -q --quiet run silently; only print error msgs\n"
@@ -725,7 +1503,7 @@
Char* usage3 =
"\n"
-" Extra options are read from env variable $VALGRIND_OPTS\n"
+" Extra options read from ~/.valgrindrc, $VALGRIND_OPTS, ./.valgrindrc\n"
"\n"
" Valgrind is Copyright (C) 2000-2004 Julian Seward\n"
" and licensed under the GNU General Public License, version 2.\n"
@@ -762,15 +1540,45 @@
VG_(exit)(1);
}
-
-static void process_cmd_line_options ( const KickstartParams *kp )
+static void pre_process_cmd_line_options
+ ( Bool* need_help, const char** tool, const char** exec )
{
- Int argc;
- Char **argv;
- Int i, eventually_logfile_fd;
- Int *auxp;
+ UInt i;
-# define ISSPACE(cc) ((cc) == ' ' || (cc) == '\t' || (cc) == '\n')
+ /* parse the options we have (only the options we care about now) */
+ for (i = 1; i < VG_(vg_argc); i++) {
+
+ if (strcmp(VG_(vg_argv)[i], "--version") == 0) {
+ printf("valgrind-" VERSION "\n");
+ exit(1);
+
+ } else if (strcmp(VG_(vg_argv)[i], "--help") == 0) {
+ *need_help = True;
+
+ } else if (strncmp(VG_(vg_argv)[i], "--tool=", 7) == 0 ||
+ strncmp(VG_(vg_argv)[i], "--skin=", 7) == 0) {
+ *tool = &VG_(vg_argv)[i][7];
+
+ } else if (strncmp(VG_(vg_argv)[i], "--exec=", 7) == 0) {
+ *exec = &VG_(vg_argv)[i][7];
+ }
+ }
+
+ /* If no tool specified, can give usage message without loading tool */
+ if (*tool == NULL) {
+ if (!need_help)
+ list_tools();
+ usage();
+ }
+}
+
+static void process_cmd_line_options
+ ( UInt* client_auxv, Addr esp_at_startup,
+ const char* toolname, Bool need_help )
+{
+ Int i, eventually_logfile_fd;
+ Int *auxp;
+ Int toolname_len = VG_(strlen)(toolname);
/* log to stderr by default, but usage message goes to stdout */
eventually_logfile_fd = 2;
@@ -784,7 +1592,7 @@
config_error("Please use absolute paths in "
"./configure --prefix=... or --libdir=...");
- for(auxp = kp->client_auxv; auxp[0] != VKI_AT_NULL; auxp += 2) {
+ for (auxp = client_auxv; auxp[0] != VKI_AT_NULL; auxp += 2) {
switch(auxp[0]) {
case VKI_AT_SYSINFO:
VG_(sysinfo_page_exists) = True;
@@ -794,149 +1602,168 @@
}
}
- VG_(client_envp) = kp->client_envp;
-
- argc = kp->argc;
- argv = kp->argv;
-
- VG_(vg_argc) = argc;
- VG_(vg_argv) = argv;
+ if (need_help)
+ usage();
/* We know the initial ESP is pointing at argc/argv */
- VG_(client_argc) = *(Int *)kp->client_esp;
- VG_(client_argv) = (Char **)(kp->client_esp + sizeof(Int));
+ VG_(client_argc) = *(Int *)esp_at_startup;
+ VG_(client_argv) = (Char **)(esp_at_startup + sizeof(Int));
- for (i = 1; i < argc; i++) {
+ for (i = 1; i < VG_(vg_argc); i++) {
+
+ Char* arg = VG_(vg_argv)[i];
+
+ // XXX: allow colons in options, for Josef
+
+ /* Look for matching "--toolname:foo" */
+ if (VG_(strstr)(arg, ":")) {
+ if (VG_CLO_STREQN(2, arg, "--") &&
+ VG_CLO_STREQN(toolname_len, arg+2, toolname) &&
+ VG_CLO_STREQN(1, arg+2+toolname_len, ":"))
+ {
+ // prefix matches, convert "--toolname:foo" to "--foo"
+ if (0)
+ VG_(printf)("tool-specific arg: %s\n", arg);
+ 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_CLO_STREQN(7, argv[i], "--tool=") ||
- VG_CLO_STREQN(7, argv[i], "--skin="))
+ if (VG_CLO_STREQN(7, arg, "--tool=") ||
+ VG_CLO_STREQN(7, arg, "--skin="))
continue;
- if (VG_CLO_STREQN(7, argv[i], "--exec="))
+ if (VG_CLO_STREQN(7, arg, "--exec="))
continue;
- if ( VG_CLO_STREQ(argv[i], "--"))
+ if ( VG_CLO_STREQ(arg, "--"))
continue;
- else if (VG_CLO_STREQ(argv[i], "-v") ||
- VG_CLO_STREQ(argv[i], "--verbose"))
+ else if (VG_CLO_STREQ(arg, "-v") ||
+ VG_CLO_STREQ(arg, "--verbose"))
VG_(clo_verbosity)++;
- else if (VG_CLO_STREQ(argv[i], "-q") ||
- VG_CLO_STREQ(argv[i], "--quiet"))
+ else if (VG_CLO_STREQ(arg, "-q") ||
+ VG_CLO_STREQ(arg, "--quiet"))
VG_(clo_verbosity)--;
- else if (VG_CLO_STREQ(argv[i], "--error-limit=yes"))
+ else if (VG_CLO_STREQ(arg, "--error-limit=yes"))
VG_(clo_error_limit) = True;
- else if (VG_CLO_STREQ(argv[i], "--error-limit=no"))
+ else if (VG_CLO_STREQ(arg, "--error-limit=no"))
VG_(clo_error_limit) = False;
- else if (VG_CLO_STREQ(argv[i], "--gdb-attach=yes"))
+ else if (VG_CLO_STREQ(arg, "--gdb-attach=yes"))
VG_(clo_GDB_attach) = True;
- else if (VG_CLO_STREQ(argv[i], "--gdb-attach=no"))
+ else if (VG_CLO_STREQ(arg, "--gdb-attach=no"))
VG_(clo_GDB_attach) = False;
- else if (VG_CLO_STREQN(11,argv[i], "--gdb-path="))
- VG_(clo_GDB_path) = &argv[i][11];
+ else if (VG_CLO_STREQN(11,arg, "--gdb-path="))
+ VG_(clo_GDB_path) = &arg[11];
- else if (VG_CLO_STREQ(argv[i], "--gen-suppressions=yes"))
+ else if (VG_CLO_STREQ(arg, "--gen-suppressions=yes"))
VG_(clo_gen_suppressions) = True;
- else if (VG_CLO_STREQ(argv[i], "--gen-suppressions=no"))
+ else if (VG_CLO_STREQ(arg, "--gen-suppressions=no"))
VG_(clo_gen_suppressions) = False;
- else if (VG_CLO_STREQ(argv[i], "--show-below-main=yes"))
+ else if (VG_CLO_STREQ(arg, "--show-below-main=yes"))
VG_(clo_show_below_main) = True;
- else if (VG_CLO_STREQ(argv[i], "--show-below-main=no"))
+ else if (VG_CLO_STREQ(arg, "--show-below-main=no"))
VG_(clo_show_below_main) = False;
- else if (VG_CLO_STREQ(argv[i], "--pointercheck=yes"))
+ else if (VG_CLO_STREQ(arg, "--pointercheck=yes"))
VG_(clo_pointercheck) = True;
- else if (VG_CLO_STREQ(argv[i], "--pointercheck=no"))
+ else if (VG_CLO_STREQ(arg, "--pointercheck=no"))
VG_(clo_pointercheck) = False;
- else if (VG_CLO_STREQ(argv[i], "--demangle=yes"))
+ else if (VG_CLO_STREQ(arg, "--demangle=yes"))
VG_(clo_demangle) = True;
- else if (VG_CLO_STREQ(argv[i], "--demangle=no"))
+ else if (VG_CLO_STREQ(arg, "--demangle=no"))
VG_(clo_demangle) = False;
- else if (VG_CLO_STREQ(argv[i], "--trace-children=yes"))
+ else if (VG_CLO_STREQ(arg, "--trace-children=yes"))
VG_(clo_trace_children) = True;
- else if (VG_CLO_STREQ(argv[i], "--trace-children=no"))
+ else if (VG_CLO_STREQ(arg, "--trace-children=no"))
VG_(clo_trace_children) = False;
- else if (VG_CLO_STREQ(argv[i], "--run-libc-freeres=yes"))
+ else if (VG_CLO_STREQ(arg, "--run-libc-freeres=yes"))
VG_(clo_run_libc_freeres) = True;
- else if (VG_CLO_STREQ(argv[i], "--run-libc-freeres=no"))
+ else if (VG_CLO_STREQ(arg, "--run-libc-freeres=no"))
VG_(clo_run_libc_freeres) = False;
- else if (VG_CLO_STREQ(argv[i], "--track-fds=yes"))
+ else if (VG_CLO_STREQ(arg, "--track-fds=yes"))
VG_(clo_track_fds) = True;
- else if (VG_CLO_STREQ(argv[i], "--track-fds=no"))
+ else if (VG_CLO_STREQ(arg, "--track-fds=no"))
VG_(clo_track_fds) = False;
- else if (VG_CLO_STREQN(15, argv[i], "--sanity-level="))
- VG_(sanity_level) = (Int)VG_(atoll)(&argv[i][15]);
+ else if (VG_CLO_STREQN(15, arg, "--sanity-level="))
+ VG_(sanity_level) = (Int)VG_(atoll)(&arg[15]);
- else if (VG_CLO_STREQN(13, argv[i], "--logfile-fd=")) {
+ else if (VG_CLO_STREQN(13, arg, "--logfile-fd=")) {
VG_(clo_log_to) = VgLogTo_Fd;
VG_(clo_logfile_name) = NULL;
- eventually_logfile_fd = (Int)VG_(atoll)(&argv[i][13]);
+ eventually_logfile_fd = (Int)VG_(atoll)(&arg[13]);
}
- else if (VG_CLO_STREQN(10, argv[i], "--logfile=")) {
+ else if (VG_CLO_STREQN(10, arg, "--logfile=")) {
VG_(clo_log_to) = VgLogTo_File;
- VG_(clo_logfile_name) = &argv[i][10];
+ VG_(clo_logfile_name) = &arg[10];
}
- else if (VG_CLO_STREQN(12, argv[i], "--logsocket=")) {
+ else if (VG_CLO_STREQN(12, arg, "--logsocket=")) {
VG_(clo_log_to) = VgLogTo_Socket;
- VG_(clo_logfile_name) = &argv[i][12];
+ VG_(clo_logfile_name) = &arg[12];
}
- else if (VG_CLO_STREQN(11, argv[i], "--input-fd="))
- VG_(clo_input_fd) = (Int)VG_(atoll)(&argv[i][11]);
+ else if (VG_CLO_STREQN(11, arg, "--input-fd="))
+ VG_(clo_input_fd) = (Int)VG_(atoll)(&arg[11]);
- else if (VG_CLO_STREQN(15, argv[i], "--suppressions=")) {
+ else if (VG_CLO_STREQN(15, arg, "--suppressions=")) {
if (VG_(clo_n_suppressions) >= VG_CLO_MAX_SFILES) {
VG_(message)(Vg_UserMsg, "Too many suppression files specified.");
VG_(message)(Vg_UserMsg,
"Increase VG_CLO_MAX_SFILES and recompile.");
- VG_(bad_option)(argv[i]);
+ VG_(bad_option)(arg);
}
- VG_(clo_suppressions)[VG_(clo_n_suppressions)] = &argv[i][15];
+ VG_(clo_suppressions)[VG_(clo_n_suppressions)] = &arg[15];
VG_(clo_n_suppressions)++;
}
- else if (VG_CLO_STREQ(argv[i], "--profile=yes"))
+ else if (VG_CLO_STREQ(arg, "--profile=yes"))
VG_(clo_profile) = True;
- else if (VG_CLO_STREQ(argv[i], "--profile=no"))
+ else if (VG_CLO_STREQ(arg, "--profile=no"))
VG_(clo_profile) = False;
- else if (VG_CLO_STREQ(argv[i], "--chain-bb=yes"))
+ else if (VG_CLO_STREQ(arg, "--chain-bb=yes"))
VG_(clo_chain_bb) = True;
- else if (VG_CLO_STREQ(argv[i], "--chain-bb=no"))
+ else if (VG_CLO_STREQ(arg, "--chain-bb=no"))
VG_(clo_chain_bb) = False;
- else if (VG_CLO_STREQ(argv[i], "--branchpred=yes"))
+ else if (VG_CLO_STREQ(arg, "--branchpred=yes"))
VG_(clo_branchpred) = True;
- else if (VG_CLO_STREQ(argv[i], "--branchpred=no"))
+ else if (VG_CLO_STREQ(arg, "--branchpred=no"))
VG_(clo_branchpred) = False;
- else if (VG_CLO_STREQ(argv[i], "--single-step=yes"))
+ else if (VG_CLO_STREQ(arg, "--single-step=yes"))
VG_(clo_single_step) = True;
- else if (VG_CLO_STREQ(argv[i], "--single-step=no"))
+ else if (VG_CLO_STREQ(arg, "--single-step=no"))
VG_(clo_single_step) = False;
- else if (VG_CLO_STREQ(argv[i], "--optimise=yes"))
+ else if (VG_CLO_STREQ(arg, "--optimise=yes"))
VG_(clo_optimise) = True;
- else if (VG_CLO_STREQ(argv[i], "--optimise=no"))
+ else if (VG_CLO_STREQ(arg, "--optimise=no"))
VG_(clo_optimise) = False;
/* "vwxyz" --> 000zyxwv (binary) */
- else if (VG_CLO_STREQN(16, argv[i], "--trace-codegen=")) {
+ else if (VG_CLO_STREQN(16, arg, "--trace-codegen=")) {
Int j;
- char* opt = & argv[i][16];
+ char* opt = & arg[16];
if (5 != VG_(strlen)(opt)) {
VG_(message)(Vg_UserMsg,
"--trace-codegen argument must have 5 digits");
- VG_(bad_option)(argv[i]);
+ VG_(bad_option)(arg);
}
for (j = 0; j < 5; j++) {
if ('0' == opt[j]) { /* do nothing */ }
@@ -944,85 +1771,80 @@
else {
VG_(message)(Vg_UserMsg, "--trace-codegen argument can only "
"contain 0s and 1s");
- VG_(bad_option)(argv[i]);
+ VG_(bad_option)(arg);
}
}
}
- else if (VG_CLO_STREQ(argv[i], "--trace-syscalls=yes"))
+ else if (VG_CLO_STREQ(arg, "--trace-syscalls=yes"))
VG_(clo_trace_syscalls) = True;
- else if (VG_CLO_STREQ(argv[i], "--trace-syscalls=no"))
+ else if (VG_CLO_STREQ(arg, "--trace-syscalls=no"))
VG_(clo_trace_syscalls) = False;
- else if (VG_CLO_STREQ(argv[i], "--trace-signals=yes"))
+ else if (VG_CLO_STREQ(arg, "--trace-signals=yes"))
VG_(clo_trace_signals) = True;
- else if (VG_CLO_STREQ(argv[i], "--trace-signals=no"))
+ else if (VG_CLO_STREQ(arg, "--trace-signals=no"))
VG_(clo_trace_signals) = False;
- else if (VG_CLO_STREQ(argv[i], "--trace-symtab=yes"))
+ else if (VG_CLO_STREQ(arg, "--trace-symtab=yes"))
VG_(clo_trace_symtab) = True;
- else if (VG_CLO_STREQ(argv[i], "--trace-symtab=no"))
+ else if (VG_CLO_STREQ(arg, "--trace-symtab=no"))
VG_(clo_trace_symtab) = False;
- else if (VG_CLO_STREQ(argv[i], "--trace-sched=yes"))
+ else if (VG_CLO_STREQ(arg, "--trace-sched=yes"))
VG_(clo_trace_sched) = True;
- else if (VG_CLO_STREQ(argv[i], "--trace-sched=no"))
+ else if (VG_CLO_STREQ(arg, "--trace-sched=no"))
VG_(clo_trace_sched) = False;
- else if (VG_CLO_STREQ(argv[i], "--trace-pthread=none"))
+ else if (VG_CLO_STREQ(arg, "--trace-pthread=none"))
VG_(clo_trace_pthread_level) = 0;
- else if (VG_CLO_STREQ(argv[i], "--trace-pthread=some"))
+ else if (VG_CLO_STREQ(arg, "--trace-pthread=some"))
VG_(clo_trace_pthread_level) = 1;
- else if (VG_CLO_STREQ(argv[i], "--trace-pthread=all"))
+ else if (VG_CLO_STREQ(arg, "--trace-pthread=all"))
VG_(clo_trace_pthread_level) = 2;
- else if (VG_CLO_STREQN(14, argv[i], "--weird-hacks="))
- VG_(clo_weird_hacks) = &argv[i][14];
+ else if (VG_CLO_STREQN(14, arg, "--weird-hacks="))
+ VG_(clo_weird_hacks) = &arg[14];
- else if (VG_CLO_STREQN(17, argv[i], "--signal-polltime="))
- VG_(clo_signal_polltime) = VG_(atoll)(&argv[i][17]);
+ else if (VG_CLO_STREQN(17, arg, "--signal-polltime="))
+ VG_(clo_signal_polltime) = VG_(atoll)(&arg[17]);
- else if (VG_CLO_STREQ(argv[i], "--lowlat-signals=yes"))
+ else if (VG_CLO_STREQ(arg, "--lowlat-signals=yes"))
VG_(clo_lowlat_signals) = True;
- else if (VG_CLO_STREQ(argv[i], "--lowlat-signals=no"))
+ else if (VG_CLO_STREQ(arg, "--lowlat-signals=no"))
VG_(clo_lowlat_signals) = False;
- else if (VG_CLO_STREQ(argv[i], "--lowlat-syscalls=yes"))
+ else if (VG_CLO_STREQ(arg, "--lowlat-syscalls=yes"))
VG_(clo_lowlat_syscalls) = True;
- else if (VG_CLO_STREQ(argv[i], "--lowlat-syscalls=no"))
+ else if (VG_CLO_STREQ(arg, "--lowlat-syscalls=no"))
VG_(clo_lowlat_syscalls) = False;
- else if (VG_CLO_STREQN(13, argv[i], "--stop-after="))
- VG_(clo_stop_after) = VG_(atoll)(&argv[i][13]);
+ else if (VG_CLO_STREQN(13, arg, "--stop-after="))
+ VG_(clo_stop_after) = VG_(atoll)(&arg[13]);
- else if (VG_CLO_STREQN(13, argv[i], "--dump-error="))
- VG_(clo_dump_error) = (Int)VG_(atoll)(&argv[i][13]);
+ else if (VG_CLO_STREQN(13, arg, "--dump-error="))
+ VG_(clo_dump_error) = (Int)VG_(atoll)(&arg[13]);
- else if (VG_CLO_STREQ(argv[i], "--wait-for-gdb=yes"))
+ else if (VG_CLO_STREQ(arg, "--wait-for-gdb=yes"))
VG_(clo_wait_for_gdb) = True;
- else if (VG_CLO_STREQ(argv[i], "--wait-for-gdb=no"))
+ else if (VG_CLO_STREQ(arg, "--wait-for-gdb=no"))
VG_(clo_wait_for_gdb) = False;
- else if (VG_CLO_STREQN(14, argv[i], "--num-callers=")) {
+ else if (VG_CLO_STREQN(14, arg, "--num-callers=")) {
/* Make sure it's sane. */
- VG_(clo_backtrace_size) = (Int)VG_(atoll)(&argv[i][14]);
+ VG_(clo_backtrace_size) = (Int)VG_(atoll)(&arg[14]);
if (VG_(clo_backtrace_size) < 1)
VG_(clo_backtrace_size) = 1;
if (VG_(clo_backtrace_size) >= VG_DEEPEST_BACKTRACE)
VG_(clo_backtrace_size) = VG_DEEPEST_BACKTRACE;
}
- else if (VG_(needs).command_line_options) {
- Bool ok = SK_(process_cmd_line_option)(argv[i]);
- if (!ok)
- VG_(usage)();
+ else if ( ! VG_(needs).command_line_options
+ || ! SK_(process_cmd_line_option)(arg) ) {
+ usage();
}
- else
- VG_(usage)();
}
-# undef ISSPACE
-
if (VG_(clo_verbosity) < 0)
VG_(clo_verbosity) = 0;
@@ -1061,7 +1883,7 @@
vg_assert(VG_(clo_logfile_name) != NULL);
vg_assert(VG_(strlen)(VG_(clo_logfile_name)) <= 900); /* paranoia */
- for(;;) {
+ for (;;) {
if (seq == 0)
VG_(sprintf)(logfilename, "%s.pid%d",
VG_(clo_logfile_name), pid );
@@ -1173,8 +1995,8 @@
VG_(message)(Vg_UserMsg, " %s", VG_(client_argv)[i]);
VG_(message)(Vg_UserMsg, "Startup, with flags:");
- for (i = 1; i < argc; i++) {
- VG_(message)(Vg_UserMsg, " %s", argv[i]);
+ for (i = 1; i < VG_(vg_argc); i++) {
+ VG_(message)(Vg_UserMsg, " %s", VG_(vg_argv)[i]);
}
}
@@ -1196,15 +2018,136 @@
" as it doesn't generate errors.");
}
+ VG_(bbs_to_go) = VG_(clo_stop_after);
}
-/* ---------------------------------------------------------------------
- Copying to/from m_state_static.
- ------------------------------------------------------------------ */
-/* See comment about this in vg_include.h. Change only with
- great care.
-*/
+/*====================================================================*/
+/*=== File descriptor setup ===*/
+/*====================================================================*/
+
+static void setup_file_descriptors(void)
+{
+ struct vki_rlimit rl;
+
+ /* Get the current file descriptor limits. */
+ if (VG_(getrlimit)(VKI_RLIMIT_NOFILE, &rl) < 0) {
+ rl.rlim_cur = 1024;
+ rl.rlim_max = 1024;
+ }
+
+ /* Work out where to move the soft limit to. */
+ if (rl.rlim_cur + VG_N_RESERVED_FDS <= rl.rlim_max) {
+ rl.rlim_cur = rl.rlim_cur + VG_N_RESERVED_FDS;
+ } else {
+ rl.rlim_cur = rl.rlim_max;
+ }
+
+ /* Reserve some file descriptors for our use. */
+ VG_(max_fd) = rl.rlim_cur - VG_N_RESERVED_FDS;
+
+ /* Update the soft limit. */
+ VG_(setrlimit)(VKI_RLIMIT_NOFILE, &rl);
+
+ if (VG_(vgexecfd) != -1)
+ VG_(vgexecfd) = VG_(safe_fd)( VG_(vgexecfd) );
+ if (VG_(clexecfd) != -1)
+ VG_(clexecfd) = VG_(safe_fd)( VG_(clexecfd) );
+}
+
+
+/*====================================================================*/
+/*=== m_state_static + baseBlock: definition, setup, copying ===*/
+/*====================================================================*/
+
+/* The variables storing offsets. */
+
+#define INVALID_OFFSET (-1)
+
+Int VGOFF_(m_eax) = INVALID_OFFSET;
+Int VGOFF_(m_ecx) = INVALID_OFFSET;
+Int VGOFF_(m_edx) = INVALID_OFFSET;
+Int VGOFF_(m_ebx) = INVALID_OFFSET;
+Int VGOFF_(m_esp) = INVALID_OFFSET;
+Int VGOFF_(m_ebp) = INVALID_OFFSET;
+Int VGOFF_(m_esi) = INVALID_OFFSET;
+Int VGOFF_(m_edi) = INVALID_OFFSET;
+Int VGOFF_(m_eflags) = INVALID_OFFSET;
+Int VGOFF_(m_dflag) = INVALID_OFFSET;
+Int VGOFF_(m_ssestate) = INVALID_OFFSET;
+Int VGOFF_(ldt) = INVALID_OFFSET;
+Int VGOFF_(tls) = INVALID_OFFSET;
+Int VGOFF_(m_cs) = INVALID_OFFSET;
+Int VGOFF_(m_ss) = INVALID_OFFSET;
+Int VGOFF_(m_ds) = INVALID_OFFSET;
+Int VGOFF_(m_es) = INVALID_OFFSET;
+Int VGOFF_(m_fs) = INVALID_OFFSET;
+Int VGOFF_(m_gs) = INVALID_OFFSET;
+Int VGOFF_(m_eip) = INVALID_OFFSET;
+Int VGOFF_(spillslots) = INVALID_OFFSET;
+Int VGOFF_(sh_eax) = INVALID_OFFSET;
+Int VGOFF_(sh_ecx) = INVALID_OFFSET;
+Int VGOFF_(sh_edx) = INVALID_OFFSET;
+Int VGOFF_(sh_ebx) = INVALID_OFFSET;
+Int VGOFF_(sh_esp) = INVALID_OFFSET;
+Int VGOFF_(sh_ebp) = INVALID_OFFSET;
+Int VGOFF_(sh_esi) = INVALID_OFFSET;
+Int VGOFF_(sh_edi) = INVALID_OFFSET;
+Int VGOFF_(sh_eflags) = INVALID_OFFSET;
+
+Int VGOFF_(helper_idiv_64_32) = INVALID_OFFSET;
+Int VGOFF_(helper_div_64_32) = INVALID_OFFSET;
+Int VGOFF_(helper_idiv_32_16) = INVALID_OFFSET;
+Int VGOFF_(helper_div_32_16) = INVALID_OFFSET;
+Int VGOFF_(helper_idiv_16_8) = INVALID_OFFSET;
+Int VGOFF_(helper_div_16_8) = INVALID_OFFSET;
+Int VGOFF_(helper_imul_32_64) = INVALID_OFFSET;
+Int VGOFF_(helper_mul_32_64) = INVALID_OFFSET;
+Int VGOFF_(helper_imul_16_32) = INVALID_OFFSET;
+Int VGOFF_(helper_mul_16_32) = INVALID_OFFSET;
+Int VGOFF_(helper_imul_8_16) = INVALID_OFFSET;
+Int VGOFF_(helper_mul_8_16) = INVALID_OFFSET;
+Int VGOFF_(helper_CLD) = INVALID_OFFSET;
+Int VGOFF_(helper_STD) = INVALID_OFFSET;
+Int VGOFF_(helper_get_dirflag) = INVALID_OFFSET;
+Int VGOFF_(helper_CLC) = INVALID_OFFSET;
+Int VGOFF_(helper_STC) = INVALID_OFFSET;
+Int VGOFF_(helper_shldl) = INVALID_OFFSET;
+Int VGOFF_(helper_shldw) = INVALID_OFFSET;
+Int VGOFF_(helper_shrdl) = INVALID_OFFSET;
+Int VGOFF_(helper_shrdw) = INVALID_OFFSET;
+Int VGOFF_(helper_IN) = INVALID_OFFSET;
+Int VGOFF_(helper_OUT) = INVALID_OFFSET;
+Int VGOFF_(helper_RDTSC) = INVALID_OFFSET;
+Int VGOFF_(helper_CPUID) = INVALID_OFFSET;
+Int VGOFF_(helper_BSWAP) = INVALID_OFFSET;
+Int VGOFF_(helper_bsf) = INVALID_OFFSET;
+Int VGOFF_(helper_bsr) = INVALID_OFFSET;
+Int VGOFF_(helper_fstsw_AX) = INVALID_OFFSET;
+Int VGOFF_(helper_SAHF) = INVALID_OFFSET;
+Int VGOFF_(helper_LAHF) = INVALID_OFFSET;
+Int VGOFF_(helper_DAS) = INVALID_OFFSET;
+Int VGOFF_(helper_DAA) = INVALID_OFFSET;
+Int VGOFF_(helper_cmpxchg8b) = INVALID_OFFSET;
+Int VGOFF_(helper_undefined_instruction) = INVALID_OFFSET;
+
+/* MAX_NONCOMPACT_HELPERS can be increased easily. If MAX_COMPACT_HELPERS is
+ * increased too much, they won't really be compact any more... */
+#define MAX_COMPACT_HELPERS 8
+#define MAX_NONCOMPACT_HELPERS 50
+
+UInt VG_(n_compact_helpers) = 0;
+UInt VG_(n_noncompact_helpers) = 0;
+
+Addr VG_(compact_helper_addrs) [MAX_COMPACT_HELPERS];
+Int VG_(compact_helper_offsets)[MAX_COMPACT_HELPERS];
+Addr VG_(noncompact_helper_addrs) [MAX_NONCOMPACT_HELPERS];
+Int VG_(noncompact_helper_offsets)[MAX_NONCOMPACT_HELPERS];
+
+/* This is the actual defn of baseblock. */
+UInt VG_(baseBlock)[VG_BASEBLOCK_WORDS];
+
+/* See comment about this in vg_include.h. Change only with great care. */
__attribute__ ((aligned (16)))
UInt VG_(m_state_static) [6 /* segment regs, Intel order */
+ 8 /* int regs, in Intel order */
@@ -1213,6 +2156,10 @@
+ VG_SIZE_OF_SSESTATE_W /* FPU state */
];
+/* Words. */
+static Int baB_off = 0;
+
+
UInt VG_(insertDflag)(UInt eflags, Int d)
{
vg_assert(d == 1 || d == -1);
@@ -1236,7 +2183,7 @@
return ret;
}
-void VG_(copy_baseBlock_to_m_state_static) ( void )
+static void copy_baseBlock_to_m_state_static( void )
{
Int i;
VG_(m_state_static)[ 0/4] = VG_(baseBlock)[VGOFF_(m_cs)];
@@ -1266,129 +2213,160 @@
}
-void VG_(copy_m_state_static_to_baseBlock) ( void )
+/* Returns the offset, in words. */
+static Int alloc_BaB ( Int words )
{
- Int i;
- VG_(baseBlock)[VGOFF_(m_cs)] = VG_(m_state_static)[ 0/4];
- VG_(baseBlock)[VGOFF_(m_ss)] = VG_(m_state_static)[ 4/4];
- VG_(baseBlock)[VGOFF_(m_ds)] = VG_(m_state_static)[ 8/4];
- VG_(baseBlock)[VGOFF_(m_es)] = VG_(m_state_static)[12/4];
- VG_(baseBlock)[VGOFF_(m_fs)] = VG_(m_state_static)[16/4];
- VG_(baseBlock)[VGOFF_(m_gs)] = VG_(m_state_static)[20/4];
+ Int off = baB_off;
+ baB_off += words;
+ if (baB_off >= VG_BASEBLOCK_WORDS)
+ VG_(core_panic)( "alloc_BaB: baseBlock is too small");
- VG_(baseBlock)[VGOFF_(m_eax)] = VG_(m_state_static)[24/4];
- VG_(baseBlock)[VGOFF_(m_ecx)] = VG_(m_state_static)[28/4];
- VG_(baseBlock)[VGOFF_(m_edx)] = VG_(m_state_static)[32/4];
- VG_(baseBlock)[VGOFF_(m_ebx)] = VG_(m_state_static)[36/4];
- VG_(baseBlock)[VGOFF_(m_esp)] = VG_(m_state_static)[40/4];
- VG_(baseBlock)[VGOFF_(m_ebp)] = VG_(m_state_static)[44/4];
- VG_(baseBlock)[VGOFF_(m_esi)] = VG_(m_state_static)[48/4];
- VG_(baseBlock)[VGOFF_(m_edi)] = VG_(m_state_static)[52/4];
-
- VG_(baseBlock)[VGOFF_(m_eflags)]
- = VG_(m_state_static)[56/4] & ~EFlagD;
- VG_(baseBlock)[VGOFF_(m_dflag)]
- = VG_(extractDflag)(VG_(m_state_static)[56/4]);
-
- VG_(baseBlock)[VGOFF_(m_eip)] = VG_(m_state_static)[60/4];
-
- for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++)
- VG_(baseBlock)[VGOFF_(m_ssestate) + i]
- = VG_(m_state_static)[64/4 + i];
+ return off;
}
-Addr VG_(get_stack_pointer) ( void )
+/* Align offset, in *bytes* */
+static void align_BaB ( UInt align )
{
- return VG_(baseBlock)[VGOFF_(m_esp)];
+ vg_assert(2 == align || 4 == align || 8 == align || 16 == align);
+ baB_off += (align-1);
+ baB_off &= ~(align-1);
}
-/* ---------------------------------------------------------------------
- Show accumulated counts.
- ------------------------------------------------------------------ */
-
-static __inline__ Int safe_idiv(Int a, Int b)
+/* Allocate 1 word in baseBlock and set it to the given value. */
+static Int alloc_BaB_1_set ( Addr a )
{
- return (b == 0 ? 0 : a / b);
+ Int off = alloc_BaB(1);
+ VG_(baseBlock)[off] = (UInt)a;
+ return off;
}
-static void vg_show_counts ( void )
+/* Registers a function in compact_helper_addrs; compact_helper_offsets is
+ filled in later. */
+void VG_(register_compact_helper)(Addr a)
{
- VG_(message)(Vg_DebugMsg,
- " TT/TC: %d tc sectors discarded.",
- VG_(number_of_tc_discards) );
- VG_(message)(Vg_DebugMsg,
- " %d chainings, %d unchainings.",
- VG_(bb_enchain_count), VG_(bb_dechain_count) );
- VG_(message)(Vg_DebugMsg,
- "translate: new %d (%d -> %d; ratio %d:10)",
- VG_(overall_in_count),
- VG_(overall_in_osize),
- VG_(overall_in_tsize),
- safe_idiv(10*VG_(overall_in_tsize), VG_(overall_in_osize)));
- VG_(message)(Vg_DebugMsg,
- " discard %d (%d -> %d; ratio %d:10).",
- VG_(overall_out_count),
- VG_(overall_out_osize),
- VG_(overall_out_tsize),
- safe_idiv(10*VG_(overall_out_tsize), VG_(overall_out_osize)));
- VG_(message)(Vg_DebugMsg,
- " dispatch: %llu jumps (bb entries), of which %u (%lu%%) were unchained.",
- VG_(bbs_done),
- VG_(unchained_jumps_done),
- ((ULong)(100) * (ULong)(VG_(unchained_jumps_done)))
- / ( VG_(bbs_done)==0 ? 1 : VG_(bbs_done) )
+ if (MAX_COMPACT_HELPERS <= VG_(n_compact_helpers)) {
+ VG_(printf)("Can only register %d compact helpers\n",
+ MAX_COMPACT_HELPERS);
+ VG_(core_panic)("Too many compact helpers registered");
+ }
+ VG_(compact_helper_addrs)[VG_(n_compact_helpers)] = a;
+ VG_(n_compact_helpers)++;
+}
+
+/* Registers a function in noncompact_helper_addrs; noncompact_helper_offsets
+ * is filled in later.
+ */
+void VG_(register_noncompact_helper)(Addr a)
+{
+ if (MAX_NONCOMPACT_HELPERS <= VG_(n_noncompact_helpers)) {
+ VG_(printf)("Can only register %d non-compact helpers\n",
+ MAX_NONCOMPACT_HELPERS);
+ VG_(printf)("Try increasing MAX_NON_COMPACT_HELPERS\n");
+ VG_(core_panic)("Too many non-compact helpers registered");
+ }
+ VG_(noncompact_helper_addrs)[VG_(n_noncompact_helpers)] = a;
+ VG_(n_noncompact_helpers)++;
+}
+
+/* Allocate offsets in baseBlock for the skin helpers */
+static
+void assign_helpers_in_baseBlock(UInt n, Int offsets[], Addr addrs[])
+{
+ UInt i;
+ for (i = 0; i < n; i++)
+ offsets[i] = alloc_BaB_1_set( addrs[i] );
+}
+
+Bool VG_(need_to_handle_esp_assignment)(void)
+{
+ return ( VG_(defined_new_mem_stack_4)() ||
+ VG_(defined_die_mem_stack_4)() ||
+ VG_(defined_new_mem_stack_8)() ||
+ VG_(defined_die_mem_stack_8)() ||
+ VG_(defined_new_mem_stack_12)() ||
+ VG_(defined_die_mem_stack_12)() ||
+ VG_(defined_new_mem_stack_16)() ||
+ VG_(defined_die_mem_stack_16)() ||
+ VG_(defined_new_mem_stack_32)() ||
+ VG_(defined_die_mem_stack_32)() ||
+ VG_(defined_new_mem_stack)() ||
+ VG_(defined_die_mem_stack)()
+ );
+}
+
+/* Here we assign actual offsets. It's important to get the most
+ popular referents within 128 bytes of the start, so we can take
+ advantage of short addressing modes relative to %ebp. Popularity
+ of offsets was measured on 22 Feb 02 running a KDE application, and
+ the slots rearranged accordingly, with a 1.5% reduction in total
+ size of translations. */
+static void init_baseBlock ( Addr client_eip, Addr esp_at_startup )
+{
+ /* Those with offsets under 128 are carefully chosen. */
+
+ /* WORD offsets in this column */
+ /* 0 */ VGOFF_(m_eax) = alloc_BaB_1_set(0);
+ /* 1 */ VGOFF_(m_ecx) = alloc_BaB_1_set(0);
+ /* 2 */ VGOFF_(m_edx) = alloc_BaB_1_set(0);
+ /* 3 */ VGOFF_(m_ebx) = alloc_BaB_1_set(0);
+ /* 4 */ VGOFF_(m_esp) = alloc_BaB_1_set(esp_at_startup);
+ /* 5 */ VGOFF_(m_ebp) = alloc_BaB_1_set(0);
+ /* 6 */ VGOFF_(m_esi) = alloc_BaB_1_set(0);
+ /* 7 */ VGOFF_(m_edi) = alloc_BaB_1_set(0);
+ /* 8 */ VGOFF_(m_eflags) = alloc_BaB_1_set(0);
+
+ if (VG_(needs).shadow_regs) {
+ /* 9 */ VGOFF_(sh_eax) = alloc_BaB_1_set(0);
+ /* 10 */ VGOFF_(sh_ecx) = alloc_BaB_1_set(0);
+ /* 11 */ VGOFF_(sh_edx) = alloc_BaB_1_set(0);
+ /* 12 */ VGOFF_(sh_ebx) = alloc_BaB_1_set(0);
+ /* 13 */ VGOFF_(sh_esp) = alloc_BaB_1_set(0);
+ /* 14 */ VGOFF_(sh_ebp) = alloc_BaB_1_set(0);
+ /* 15 */ VGOFF_(sh_esi) = alloc_BaB_1_set(0);
+ /* 16 */ VGOFF_(sh_edi) = alloc_BaB_1_set(0);
+ /* 17 */ VGOFF_(sh_eflags) = alloc_BaB_1_set(0);
+ VG_TRACK( post_regs_write_init );
+ }
+
+ /* 9,10,11 or 18,19,20... depends on number whether shadow regs are used
+ * and on compact helpers registered */
+
+ /* Make these most-frequently-called specialised ones compact, if they
+ are used. */
+ if (VG_(defined_new_mem_stack_4)())
+ VG_(register_compact_helper)( (Addr) VG_(tool_interface).track_new_mem_stack_4);
+
+ if (VG_(defined_die_mem_stack_4)())
+ VG_(register_compact_helper)( (Addr) VG_(tool_interface).track_die_mem_stack_4);
+
+ /* (9 or 18) + n_compact_helpers */
+ /* Allocate slots for compact helpers */
+ assign_helpers_in_baseBlock(VG_(n_compact_helpers),
+ VG_(compact_helper_offsets),
+ VG_(compact_helper_addrs));
+
+ /* (9/10 or 18/19) + n_compact_helpers */
+ VGOFF_(m_eip) = alloc_BaB_1_set(client_eip);
+
+ /* There are currently 24 spill slots */
+ /* (11+/20+ .. 32+/43+) + n_compact_helpers. This can overlap the magic
+ * boundary at >= 32 words, but most spills are to low numbered spill
+ * slots, so the ones above the boundary don't see much action. */
+ VGOFF_(spillslots) = alloc_BaB(VG_MAX_SPILLSLOTS);
+
+ /* I gave up counting at this point. Since they're above the
+ short-amode-boundary, there's no point. */
+
+ VGOFF_(m_dflag) = alloc_BaB_1_set(1); // 1 == forward D-flag
+
+ /* The FPU/SSE state. This _must_ be 16-byte aligned. Initial
+ state doesn't matter much, as long as it's not totally borked. */
+ align_BaB(16);
+ VGOFF_(m_ssestate) = alloc_BaB(VG_SIZE_OF_SSESTATE_W);
+ vg_assert(
+ 0 == ( ((UInt)(& VG_(baseBlock)[VGOFF_(m_ssestate)])) % 16 )
);
- VG_(message)(Vg_DebugMsg,
- " %d/%d major/minor sched events. %d tt_fast misses.",
- VG_(num_scheduling_events_MAJOR),
- VG_(num_scheduling_events_MINOR),
- VG_(tt_fast_misses));
-
- VG_(message)(Vg_DebugMsg,
- "reg-alloc: %d t-req-spill, "
- "%d+%d orig+spill uis, %d total-reg-r.",
- VG_(translations_needing_spill),
- VG_(uinstrs_prealloc),
- VG_(uinstrs_spill),
- VG_(total_reg_rank) );
- VG_(message)(Vg_DebugMsg,
- " sanity: %d cheap, %d expensive checks.",
- VG_(sanity_fast_count),
- VG_(sanity_slow_count) );
- VG_(print_ccall_stats)();
-}
-
-
-/* ---------------------------------------------------------------------
- Main!
- ------------------------------------------------------------------ */
-
-/* Initialize the PID and PGRP of scheduler LWP; this is also called
- in any new children after fork. */
-static void newpid(ThreadId unused)
-{
- /* PID of scheduler LWP */
- VG_(main_pid) = VG_(getpid)();
- VG_(main_pgrp) = VG_(getpgrp)();
-}
-
-/* Where we jump to once Valgrind has got control, and the real
- machine's state has been copied to the m_state_static. */
-
-void VG_(main) ( const KickstartParams *kp, void (*tool_init)(void), void *tool_dlhandle )
-{
- VgSchedReturnCode src;
- struct vki_rlimit rl;
-
- /* initial state */
- if (0)
- VG_(printf)("starting esp=%p eip=%p, esp=%p\n", kp->client_esp, kp->client_eip, &src);
- VG_(esp_at_startup) = kp->client_esp;
- VG_(memset)(&VG_(m_state_static), 0, sizeof(VG_(m_state_static)));
- VG_(m_state_static)[40/4] = kp->client_esp;
- VG_(m_state_static)[60/4] = kp->client_eip;
-
/* I assume that if we have SSE2 we also have SSE */
VG_(have_ssestate) =
VG_(cpu_has_feature)(VG_X86_FEAT_FXSR) &&
@@ -1397,29 +2375,17 @@
/* set up an initial FPU state (doesn't really matter what it is,
so long as it's somewhat valid) */
if (!VG_(have_ssestate))
- asm volatile("fwait; fnsave %0; fwait; frstor %0; fwait"
- : : "m" (VG_(m_state_static)[64/4]) : "cc", "memory");
+ asm volatile("fwait; fnsave %0; fwait; frstor %0; fwait"
+ :
+ : "m" (VG_(baseBlock)[VGOFF_(m_ssestate)])
+ : "cc", "memory");
else
- asm volatile("fwait; fxsave %0; fwait; andl $0xffbf, %1; fxrstor %0; fwait"
- : : "m" (VG_(m_state_static)[64/4]), "m" (VG_(m_state_static)[(64+24)/4]) : "cc", "memory");
-
- VG_(brk_base) = VG_(brk_limit) = kp->client_brkbase;
- VG_(client_base) = kp->client_base;
- VG_(client_end) = kp->client_end;
- VG_(client_mapbase) = kp->client_mapbase;
- VG_(clstk_base) = kp->clstk_base;
- VG_(clstk_end) = kp->clstk_end;
- vg_assert(VG_(clstk_end) == VG_(client_end));
-
- VG_(shadow_base) = kp->shadow_base;
- VG_(shadow_end) = kp->shadow_end;
- VG_(valgrind_base) = kp->vg_base;
- VG_(valgrind_mmap_end) = kp->vg_mmap_end;
- VG_(valgrind_end) = kp->vg_end;
-
- VG_(libdir) = kp->libdir;
-
- VG_(client_trampoline_code) = kp->cl_tramp_code;
+ asm volatile("fwait; fxsave %0; fwait; andl $0xffbf, %1;"
+ "fxrstor %0; fwait"
+ :
+ : "m" (VG_(baseBlock)[VGOFF_(m_ssestate)]),
+ "m" (VG_(baseBlock)[VGOFF_(m_ssestate)+(24/4)])
+ : "cc", "memory");
if (0) {
if (VG_(have_ssestate))
@@ -1428,144 +2394,103 @@
VG_(printf)("Looks like a MMX-only CPU\n");
}
- VG_(atfork)(NULL, NULL, newpid);
- newpid(VG_INVALID_THREADID);
+ /* LDT pointer: pretend the root thread has an empty LDT to start with. */
+ VGOFF_(ldt) = alloc_BaB_1_set((UInt)NULL);
- /* Get the current file descriptor limits. */
- if (VG_(getrlimit)(VKI_RLIMIT_NOFILE, &rl) < 0) {
- rl.rlim_cur = 1024;
- rl.rlim_max = 1024;
- }
+ /* TLS pointer: pretend the root thread has no TLS array for now. */
+ VGOFF_(tls) = alloc_BaB_1_set((UInt)NULL);
- /* Work out where to move the soft limit to. */
- if (rl.rlim_cur + VG_N_RESERVED_FDS <= rl.rlim_max) {
- rl.rlim_cur = rl.rlim_cur + VG_N_RESERVED_FDS;
- } else {
- rl.rlim_cur = rl.rlim_max;
- }
+ /* segment registers */
+ VGOFF_(m_cs) = alloc_BaB_1_set(0);
+ VGOFF_(m_ss) = alloc_BaB_1_set(0);
+ VGOFF_(m_ds) = alloc_BaB_1_set(0);
+ VGOFF_(m_es) = alloc_BaB_1_set(0);
+ VGOFF_(m_fs) = alloc_BaB_1_set(0);
+ VGOFF_(m_gs) = alloc_BaB_1_set(0);
- /* Reserve some file descriptors for our use. */
- VG_(max_fd) = rl.rlim_cur - VG_N_RESERVED_FDS;
+ VG_(register_noncompact_helper)( (Addr) & VG_(do_useseg) );
- /* Update the soft limit. */
- VG_(setrlimit)(VKI_RLIMIT_NOFILE, &rl);
+#define REG(kind, size) \
+ if (VG_(defined_##kind##_mem_stack##size)()) \
+ VG_(register_noncompact_helper)( \
+ (Addr) VG_(tool_interface).track_##kind##_mem_stack##size );
+ REG(new, _8);
+ REG(new, _12);
+ REG(new, _16);
+ REG(new, _32);
+ REG(new, );
+ REG(die, _8);
+ REG(die, _12);
+ REG(die, _16);
+ REG(die, _32);
+ REG(die, );
+#undef REG
- if (kp->vgexecfd != -1)
- VG_(vgexecfd) = VG_(safe_fd)(kp->vgexecfd);
- if (kp->clexecfd != -1)
- VG_(clexecfd) = VG_(safe_fd)(kp->clexecfd);
+ if (VG_(need_to_handle_esp_assignment)())
+ VG_(register_noncompact_helper)((Addr) VG_(unknown_esp_update));
- /* Read /proc/self/maps into a buffer. Must be before:
- - SK_(pre_clo_init)(): so that if it calls VG_(malloc)(), any mmap'd
- superblocks are not erroneously identified as being owned by the
- client, which would be bad.
- - init_memory(): that's where the buffer is parsed
- - init_tt_tc(): so the anonymous mmaps for the translation table and
- translation cache aren't identified as part of the client, which would
- waste > 20M of virtual address space, and be bad.
- */
- VG_(read_procselfmaps)();
+# define HELPER(name) \
+ VGOFF_(helper_##name) = alloc_BaB_1_set( (Addr) & VG_(helper_##name))
- /* Setup stuff that depends on the skin. Must be before:
- - vg_init_baseBlock(): to register helpers
- - process_cmd_line_options(): to register skin name and description,
- and turn on/off 'command_line_options' need
- - init_memory() (to setup memory event trackers).
- */
- (*tool_init)();
- VG_(tool_init_dlsym)(tool_dlhandle);
+ /* Helper functions. */
+ HELPER(idiv_64_32); HELPER(div_64_32);
+ HELPER(idiv_32_16); HELPER(div_32_16);
+ HELPER(idiv_16_8); HELPER(div_16_8);
- VG_(sanity_check_needs)();
+ HELPER(imul_32_64); HELPER(mul_32_64);
+ HELPER(imul_16_32); HELPER(mul_16_32);
+ HELPER(imul_8_16); HELPER(mul_8_16);
- /* Process Valgrind's command-line opts */
- process_cmd_line_options(kp);
+ HELPER(CLD); HELPER(STD);
+ HELPER(get_dirflag);
- /* Hook to delay things long enough so we can get the pid and
- attach GDB in another shell. */
- if (VG_(clo_wait_for_gdb)) {
- VG_(printf)("pid=%d\n", VG_(getpid)());
- /* do "jump *$eip" to skip this in gdb */
- VG_(do_syscall)(__NR_pause);
- }
+ HELPER(CLC); HELPER(STC);
- /* Do post command-line processing initialisation. Must be before:
- - vg_init_baseBlock(): to register any more helpers
- */
- SK_(post_clo_init)();
+ HELPER(shldl); HELPER(shldw);
+ HELPER(shrdl); HELPER(shrdw);
- /* Set up baseBlock offsets and copy the saved machine's state into it. */
- vg_init_baseBlock();
+ HELPER(RDTSC); HELPER(CPUID);
- /* Search for file descriptors that are inherited from our parent. */
- if (VG_(clo_track_fds))
- VG_(init_preopened_fds)();
+ HELPER(bsf); HELPER(bsr);
- /* Initialise the scheduler, and copy the client's state from
- baseBlock into VG_(threads)[1]. Must be before:
- - VG_(sigstartup_actions)()
- */
- VG_(scheduler_init)();
+ HELPER(fstsw_AX);
+ HELPER(SAHF); HELPER(LAHF);
+ HELPER(DAS); HELPER(DAA);
+ HELPER(IN); HELPER(OUT);
+ HELPER(cmpxchg8b);
- /* Set up the ProxyLWP machinery */
- VG_(proxy_init)();
+ HELPER(undefined_instruction);
- /* Initialise the signal handling subsystem, temporarily parking
- the saved blocking-mask in saved_sigmask. */
- VG_(sigstartup_actions)();
+# undef HELPER
- /* Perhaps we're profiling Valgrind? */
- if (VG_(clo_profile))
- VGP_(init_profiling)();
+ /* Allocate slots for noncompact helpers */
+ assign_helpers_in_baseBlock(VG_(n_noncompact_helpers),
+ VG_(noncompact_helper_offsets),
+ VG_(noncompact_helper_addrs));
+}
- /* Start calibration of our RDTSC-based clock. */
- VG_(start_rdtsc_calibration)();
- /* Parse /proc/self/maps to learn about startup segments. */
- VGP_PUSHCC(VgpInitMem);
- VG_(init_memory)();
- VGP_POPCC(VgpInitMem);
+/*====================================================================*/
+/*=== Setup pointercheck ===*/
+/*====================================================================*/
- /* Read the list of errors to suppress. This should be found in
- the file specified by vg_clo_suppressions. */
- if (VG_(needs).core_errors || VG_(needs).skin_errors)
- VG_(load_suppressions)();
-
- /* End calibration of our RDTSC-based clock, leaving it as long as
- we can. */
- VG_(end_rdtsc_calibration)();
-
- /* Initialise translation table and translation cache. */
- VG_(init_tt_tc)();
-
- if (VG_(clo_verbosity) == 1) {
- VG_(message)(Vg_UserMsg,
- "For more details, rerun with: -v");
- }
-
- /* Force a read of the debug info so that we can look for
- glibc entry points to intercept. */
- VG_(setup_code_redirect_table)();
-
- /* Now it is safe for malloc et al in vg_clientmalloc.c to act
- instrumented-ly. */
- if (VG_(clo_verbosity) > 0)
- VG_(message)(Vg_UserMsg, "");
-
- VG_(bbs_to_go) = VG_(clo_stop_after);
+static void setup_pointercheck(void)
+{
+ int ret;
if (VG_(clo_pointercheck)) {
- vki_modify_ldt_t ldt = { VG_POINTERCHECK_SEGIDX,
- VG_(client_base),
- (VG_(client_end)-VG_(client_base)) / VKI_BYTES_PER_PAGE,
- 1, /* 32 bit */
- 0, /* contents: data, RW, non-expanding */
- 0, /* not read-exec only */
- 1, /* limit in pages */
- 0, /* !seg not present */
- 1, /* usable */
+ vki_modify_ldt_t ldt = {
+ VG_POINTERCHECK_SEGIDX, // entry_number
+ VG_(client_base), // base_addr
+ (VG_(client_end)-VG_(client_base)) / VKI_BYTES_PER_PAGE, // limit
+ 1, // seg_32bit
+ 0, // contents: data, RW, non-expanding
+ 0, // ! read_exec_only
+ 1, // limit_in_pages
+ 0, // ! seg not present
+ 1, // useable
};
- Int ret = VG_(do_syscall)(__NR_modify_ldt, 1, &ldt, sizeof(ldt));
-
+ ret = VG_(do_syscall)(__NR_modify_ldt, 1, &ldt, sizeof(ldt));
if (ret < 0) {
VG_(message)(Vg_UserMsg,
"Warning: ignoring --pointercheck=yes, "
@@ -1573,306 +2498,83 @@
VG_(clo_pointercheck) = False;
}
}
-
- /* Run! */
- VG_(running_on_simd_CPU) = True;
- VGP_PUSHCC(VgpSched);
-
- if (__builtin_setjmp(&VG_(fatal_signal_jmpbuf)) == 0) {
- VG_(fatal_signal_set) = True;
- src = VG_(scheduler)();
- } else
- src = VgSrc_FatalSig;
-
- VGP_POPCC(VgpSched);
- VG_(running_on_simd_CPU) = False;
-
- if (VG_(clo_verbosity) > 0)
- VG_(message)(Vg_UserMsg, "");
-
- if (src == VgSrc_Deadlock) {
- VG_(message)(Vg_UserMsg,
- "Warning: pthread scheduler exited due to deadlock");
- }
-
- /* Print out file descriptor summary and stats. */
- if(VG_(clo_track_fds))
- VG_(fd_stats)();
-
- if (VG_(needs).core_errors || VG_(needs).skin_errors)
- VG_(show_all_errors)();
-
- SK_(fini)( VG_(exitcode) );
-
- VG_(do_sanity_checks)( True /*include expensive checks*/ );
-
- if (VG_(clo_verbosity) > 1)
- vg_show_counts();
-
- if (VG_(clo_verbosity) > 3)
- VG_(print_UInstr_histogram)();
-
- if (0) {
- VG_(message)(Vg_DebugMsg, "");
- VG_(message)(Vg_DebugMsg,
- "------ Valgrind's internal memory use stats follow ------" );
- VG_(mallocSanityCheckAll)();
- VG_(show_all_arena_stats)();
- VG_(message)(Vg_DebugMsg,
- "------ Valgrind's ExeContext management stats follow ------" );
- VG_(show_ExeContext_stats)();
- }
-
- if (VG_(clo_profile))
- VGP_(done_profiling)();
-
- VG_(shutdown_logging)();
-
- /* We're exiting, so nuke all the threads and clean up the proxy LWPs */
- vg_assert(src == VgSrc_FatalSig ||
- VG_(threads)[VG_(last_run_tid)].status == VgTs_Runnable ||
- VG_(threads)[VG_(last_run_tid)].status == VgTs_WaitJoiner);
- VG_(nuke_all_threads_except)(VG_INVALID_THREADID);
-
- /* Decide how to exit. This depends on what the scheduler
- returned. */
-
- switch (src) {
- case VgSrc_ExitSyscall: /* the normal way out */
- vg_assert(VG_(last_run_tid) > 0
- && VG_(last_run_tid) < VG_N_THREADS);
- VG_(proxy_shutdown)();
-
- /* The thread's %EBX at the time it did __NR_exit() will hold
- the arg to __NR_exit(), so we just do __NR_exit() with
- that arg. */
- VG_(exit)( VG_(exitcode) );
- /* NOT ALIVE HERE! */
- VG_(core_panic)("entered the afterlife in vg_main() -- ExitSyscall");
- break; /* what the hell :) */
-
- case VgSrc_Deadlock:
- /* Just exit now. No point in continuing. */
- VG_(proxy_shutdown)();
- VG_(exit)(0);
- VG_(core_panic)("entered the afterlife in vg_main() -- Deadlock");
- break;
-
- case VgSrc_BbsDone:
- /* Tricky; we have to try and switch back to the real CPU.
- This is all very dodgy and won't work at all in the
- presence of threads, or if the client happened to be
- running a signal handler. */
- /* Prepare to restore state to the real CPU. */
- VG_(sigshutdown_actions)();
- VG_(load_thread_state)(1 /* root thread */ );
- VG_(copy_baseBlock_to_m_state_static)();
-
- VG_(proxy_shutdown)();
-
- /* This pushes a return address on the simulator's stack,
- which is abandoned. We call vg_sigshutdown_actions() at
- the end of vg_switch_to_real_CPU(), so as to ensure that
- the original stack and machine state is restored before
- the real signal mechanism is restored. */
- VG_(switch_to_real_CPU)();
-
- case VgSrc_FatalSig:
- /* We were killed by a fatal signal, so replicate the effect */
- vg_assert(VG_(fatal_sigNo) != -1);
- VG_(kill_self)(VG_(fatal_sigNo));
- VG_(core_panic)("vg_main(): signal was supposed to be fatal");
- break;
-
- default:
- VG_(core_panic)("vg_main(): unexpected scheduler return code");
- }
}
+/*====================================================================*/
+/*=== Initialise program data/text, etc. ===*/
+/*====================================================================*/
-/* Debugging thing .. can be called from assembly with OYNK macro. */
-void VG_(oynk) ( Int n )
+static void build_valgrind_map_callback
+ ( Addr start, UInt size, Char rr, Char ww, Char xx,
+ UInt dev, UInt ino, ULong foffset, const UChar* filename )
{
- OINK(n);
+ UInt prot = 0;
+ UInt flags = SF_MMAP|SF_NOSYMS;
+ Bool is_stack_segment;
+
+ is_stack_segment =
+ (start == VG_(clstk_base) && (start+size) == VG_(clstk_end));
+
+ /* Only record valgrind mappings for now, without loading any
+ symbols. This is so we know where the free space is before we
+ start allocating more memory (note: heap is OK, it's just mmap
+ which is the problem here). */
+ if (start >= VG_(valgrind_base) && (start+size) <= VG_(valgrind_end)) {
+ flags |= SF_VALGRIND;
+ VG_(map_file_segment)(start, size, prot, flags, dev, ino, foffset, filename);
+ }
}
+// Global var used to pass local data to callback
+Addr esp_at_startup___global_arg = 0;
-/* Walk through a colon-separated environment variable, and remove the
- entries which matches file_pattern. It slides everything down over
- the removed entries, and pads the remaining space with '\0'. It
- modifies the entries in place (in the client address space), but it
- shouldn't matter too much, since we only do this just before an
- execve().
-
- This is also careful to mop up any excess ':'s, since empty strings
- delimited by ':' are considered to be '.' in a path.
-*/
-void VG_(mash_colon_env)(Char *varp, const Char *remove_pattern)
+static void build_segment_map_callback
+ ( Addr start, UInt size, Char rr, Char ww, Char xx,
+ UInt dev, UInt ino, ULong foffset, const UChar* filename )
{
- Char *const start = varp;
- Char *entry_start = varp;
- Char *output = varp;
+ UInt prot = 0;
+ UInt flags;
+ Bool is_stack_segment;
+ Addr r_esp;
- if (varp == NULL)
- return;
+ is_stack_segment
+ = (start == VG_(clstk_base) && (start+size) == VG_(clstk_end));
- while(*varp) {
- if (*varp == ':') {
- Char prev;
- Bool match;
+ if (rr == 'r') prot |= VKI_PROT_READ;
+ if (ww == 'w') prot |= VKI_PROT_WRITE;
+ if (xx == 'x') prot |= VKI_PROT_EXEC;
- /* This is a bit subtle: we want to match against the entry
- we just copied, because it may have overlapped with
- itself, junking the original. */
+ if (is_stack_segment)
+ flags = SF_STACK | SF_GROWDOWN;
+ else
+ flags = SF_EXEC|SF_MMAP;
- prev = *output;
- *output = '\0';
+ if (filename != NULL)
+ flags |= SF_FILE;
- match = VG_(string_match)(remove_pattern, entry_start);
+ if (start >= VG_(valgrind_base) && (start+size) <= VG_(valgrind_end))
+ flags |= SF_VALGRIND;
- *output = prev;
-
- if (match) {
- output = entry_start;
- varp++; /* skip ':' after removed entry */
- } else
- entry_start = output+1; /* entry starts after ':' */
- }
+ VG_(map_file_segment)(start, size, prot, flags, dev, ino, foffset, filename);
- *output++ = *varp++;
- }
+ if (VG_(is_client_addr)(start) && VG_(is_client_addr)(start+size-1))
+ VG_TRACK( new_mem_startup, start, size, rr=='r', ww=='w', xx=='x' );
- /* match against the last entry */
- if (VG_(string_match)(remove_pattern, entry_start)) {
- output = entry_start;
- if (output > start) {
- /* remove trailing ':' */
- output--;
- vg_assert(*output == ':');
- }
- }
-
- /* pad out the left-overs with '\0' */
- while(output < varp)
- *output++ = '\0';
-}
-
-/* Start GDB and get it to attach to this process. Called if the user
- requests this service after an error has been shown, so she can
- poke around and look at parameters, memory, etc. You can't
- meaningfully get GDB to continue the program, though; to continue,
- quit GDB. */
-void VG_(start_GDB) ( Int tid )
-{
- Int pid;
-
- if ((pid = fork()) == 0)
- {
- ptrace(PTRACE_TRACEME, 0, NULL, NULL);
- VG_(kkill)(VG_(getpid)(), VKI_SIGSTOP);
- }
- else if (pid > 0)
- {
- struct user_regs_struct regs;
- Int status;
- Int res;
-
- if (VG_(is_running_thread)( tid )) {
- regs.xcs = VG_(baseBlock)[VGOFF_(m_cs)];
- regs.xss = VG_(baseBlock)[VGOFF_(m_ss)];
- regs.xds = VG_(baseBlock)[VGOFF_(m_ds)];
- regs.xes = VG_(baseBlock)[VGOFF_(m_es)];
- regs.xfs = VG_(baseBlock)[VGOFF_(m_fs)];
- regs.xgs = VG_(baseBlock)[VGOFF_(m_gs)];
- regs.eax = VG_(baseBlock)[VGOFF_(m_eax)];
- regs.ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
- regs.ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
- regs.edx = VG_(baseBlock)[VGOFF_(m_edx)];
- regs.esi = VG_(baseBlock)[VGOFF_(m_esi)];
- regs.edi = VG_(baseBlock)[VGOFF_(m_edi)];
- regs.ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
- regs.esp = VG_(baseBlock)[VGOFF_(m_esp)];
- regs.eflags = VG_(baseBlock)[VGOFF_(m_eflags)];
- regs.eip = VG_(baseBlock)[VGOFF_(m_eip)];
- } else {
- ThreadState* tst = & VG_(threads)[ tid ];
-
- regs.xcs = tst->m_cs;
- regs.xss = tst->m_ss;
- regs.xds = tst->m_ds;
- regs.xes = tst->m_es;
- regs.xfs = tst->m_fs;
- regs.xgs = tst->m_gs;
- regs.eax = tst->m_eax;
- regs.ebx = tst->m_ebx;
- regs.ecx = tst->m_ecx;
- regs.edx = tst->m_edx;
- regs.esi = tst->m_esi;
- regs.edi = tst->m_edi;
- regs.ebp = tst->m_ebp;
- regs.esp = tst->m_esp;
- regs.eflags = tst->m_eflags;
- regs.eip = tst->m_eip;
- }
-
- if ((res = VG_(waitpid)(pid, &status, 0)) == pid &&
- WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP &&
- ptrace(PTRACE_SETREGS, pid, NULL, ®s) == 0 &&
- ptrace(PTRACE_DETACH, pid, NULL, SIGSTOP) == 0) {
- UChar buf[VG_(strlen)(VG_(clo_GDB_path)) + 100];
-
- VG_(sprintf)(buf, "%s -nw /proc/%d/fd/%d %d",
- VG_(clo_GDB_path), VG_(main_pid), VG_(clexecfd), pid);
- VG_(message)(Vg_UserMsg, "starting GDB with cmd: %s", buf);
- res = VG_(system)(buf);
- if (res == 0) {
- VG_(message)(Vg_UserMsg, "");
- VG_(message)(Vg_UserMsg,
- "GDB has detached. Valgrind regains control. We continue.");
- } else {
- VG_(message)(Vg_UserMsg, "Apparently failed!");
- VG_(message)(Vg_UserMsg, "");
- }
- }
-
- VG_(kkill)(pid, VKI_SIGKILL);
- VG_(waitpid)(pid, &status, 0);
+ /* If this is the stack segment mark all below %esp as noaccess. */
+ r_esp = esp_at_startup___global_arg;
+ vg_assert(0 != r_esp);
+ if (is_stack_segment) {
+ if (0)
+ VG_(message)(Vg_DebugMsg, "invalidating stack area: %x .. %x",
+ start,r_esp);
+ VG_TRACK( die_mem_stack, start, r_esp-start );
}
}
-/* Print some helpful-ish text about unimplemented things, and give
- up. */
-void VG_(unimplemented) ( Char* msg )
-{
- VG_(message)(Vg_UserMsg, "");
- VG_(message)(Vg_UserMsg,
- "Valgrind detected that your program requires");
- VG_(message)(Vg_UserMsg,
- "the following unimplemented functionality:");
- VG_(message)(Vg_UserMsg, " %s", msg);
- VG_(message)(Vg_UserMsg,
- "This may be because the functionality is hard to implement,");
- VG_(message)(Vg_UserMsg,
- "or because no reasonable program would behave this way,");
- VG_(message)(Vg_UserMsg,
- "or because nobody has yet needed it. In any case, let us know at");
- VG_(message)(Vg_UserMsg,
- "%s and/or try to work around the problem, if you can.", VG_BUGS_TO);
- VG_(message)(Vg_UserMsg,
- "");
- VG_(message)(Vg_UserMsg,
- "Valgrind has to exit now. Sorry. Bye!");
- VG_(message)(Vg_UserMsg,
- "");
- VG_(pp_sched_status)();
- VG_(exit)(1);
-}
-
-
-/* ---------------------------------------------------------------------
- Sanity check machinery (permanently engaged).
- ------------------------------------------------------------------ */
+/*====================================================================*/
+/*=== Sanity check machinery (permanently engaged) ===*/
+/*====================================================================*/
/* A fast sanity check -- suitable for calling circa once per
millisecond. */
@@ -1938,6 +2640,477 @@
}
VGP_POPCC(VgpCoreCheapSanity);
}
+
+
+/*====================================================================*/
+/*=== main() ===*/
+/*====================================================================*/
+
+int main(int argc, char **argv)
+{
+ char **cl_argv;
+ const char *tool = NULL;
+ const char *exec = NULL;
+ char *preload; /* tool-specific LD_PRELOAD .so */
+ char **env;
+ Bool need_help = False;
+ struct exeinfo info;
+ ToolInfo *toolinfo = NULL;
+ void *tool_dlhandle;
+ Addr client_eip;
+ Addr esp_at_startup; /* client's %esp at the point we gained control. */
+ UInt * client_auxv;
+ VgSchedReturnCode src;
+
+ //============================================================
+ // Nb: startup is complex. Prerequisites are shown at every step.
+ //
+ // *** Be very careful when messing with the order ***
+ //============================================================
+
+ //--------------------------------------------------------------
+ // Check we were launched by stage1
+ // p: n/a [must be first step]
+ //--------------------------------------------------------------
+ scan_auxv();
+
+ if (0) {
+ int prmap(void *start, void *end, const char *perm, off_t off,
+ int maj, int min, int ino) {
+ printf("mapping %10p-%10p %s %02x:%02x %d\n",
+ start, end, perm, maj, min, ino);
+ return True;
+ }
+ printf("========== main() ==========\n");
+ foreach_map(prmap);
+ }
+
+ //--------------------------------------------------------------
+ // Look for alternative libdir
+ // p: n/a
+ //--------------------------------------------------------------
+ { char *cp = getenv(VALGRINDLIB);
+ if (cp != NULL)
+ VG_(libdir) = cp;
+ }
+
+ //--------------------------------------------------------------
+ // Begin working out address space layout
+ // p: n/a
+ //--------------------------------------------------------------
+ layout_client_space( (Addr) & argc );
+
+ //--------------------------------------------------------------
+ // Get valgrind args + client args (inc. from VALGRIND_OPTS/.valgrindrc).
+ // Pre-process the command line.
+ // p: n/a
+ //--------------------------------------------------------------
+ get_command_line(argc, argv, &VG_(vg_argc), &VG_(vg_argv), &cl_argv);
+ pre_process_cmd_line_options(&need_help, &tool, &exec);
+
+ //==============================================================
+ // Nb: once a tool is specified, the tool.so must be loaded even if
+ // they specified --help or didn't specify a client program.
+ //==============================================================
+
+ //--------------------------------------------------------------
+ // With client padded out, map in tool
+ // p: layout_client_space() [for padding]
+ // p: set-libdir [for VG_(libdir)]
+ // p: pre_process_cmd_line_options() [for 'tool']
+ //--------------------------------------------------------------
+ load_tool(tool, &tool_dlhandle, &toolinfo, &preload);
+
+ //==============================================================
+ // Can use VG_(malloc)() and VG_(arena_malloc)() only after load_tool()
+ // -- redzone size is now set.
+ //==============================================================
+
+ //--------------------------------------------------------------
+ // Finalise address space layout
+ // p: layout_client_space(), load_tool() [for 'toolinfo']
+ //--------------------------------------------------------------
+ layout_remaining_space( toolinfo->shadow_ratio );
+
+ //--------------------------------------------------------------
+ // Load client executable, finding in $PATH if necessary
+ // p: layout_client_space() [so there's space]
+ // p: pre_process_cmd_line_options() [for 'exec', 'need_help']
+ // p: layout_remaining_space [so there's space]
+ //--------------------------------------------------------------
+ load_client(cl_argv, exec, /*inout*/&need_help, &info, &client_eip);
+
+ //--------------------------------------------------------------
+ // Everything in place, unpad us
+ // p: layout_remaining_space() [everything must be mapped in before now]
+ // p: load_client() [ditto]
+ //--------------------------------------------------------------
+ as_unpad((void *)VG_(shadow_end), (void *)~0);
+ as_closepadfile(); /* no more padding */
+
+ //--------------------------------------------------------------
+ // Set up client's environment
+ // p: set-libdir [for VG_(libdir)]
+ // p: load_tool() [for 'preload']
+ //--------------------------------------------------------------
+ env = fix_environment(environ, preload);
+
+ //--------------------------------------------------------------
+ // Setup client stack and eip
+ // p: load_client() [for 'info']
+ // p: fix_environment() [for 'env']
+ //--------------------------------------------------------------
+ esp_at_startup = setup_client_stack(cl_argv, env, &info, &client_auxv);
+
+ if (0)
+ printf("entry=%x client esp=%x vg_argc=%d brkbase=%x\n",
+ client_eip, esp_at_startup, VG_(vg_argc), VG_(brk_base));
+
+ //==============================================================
+ // Finished setting up operating environment. Now initialise
+ // Valgrind. (This is where the old VG_(main)() started.)
+ //==============================================================
+
+ //--------------------------------------------------------------
+ // Read /proc/self/maps into a buffer
+ // p: all memory layout, environment setup [so memory maps are right]
+ //--------------------------------------------------------------
+ VG_(read_procselfmaps)();
+
+ //--------------------------------------------------------------
+ // atfork
+ // p: n/a
+ //--------------------------------------------------------------
+ VG_(atfork)(NULL, NULL, newpid);
+ newpid(VG_INVALID_THREADID);
+
+ //--------------------------------------------------------------
+ // setup file descriptors
+ // p: n/a
+ //--------------------------------------------------------------
+ setup_file_descriptors();
+
+ //--------------------------------------------------------------
+ // Setup tool
+ // p: VG_(read_procselfmaps)() [so if sk_pre_clo_init calls
+ // VG_(malloc), any mmap'd superblocks aren't erroneously
+ // identified later as being owned by the client]
+ // XXX: is that necessary, now that we look for V's segments separately?
+ // XXX: alternatively, if sk_pre_clo_init does use VG_(malloc)(), is it
+ // wrong to ignore any segments that might add in parse_procselfmaps?
+ //--------------------------------------------------------------
+ (*toolinfo->sk_pre_clo_init)();
+ VG_(tool_init_dlsym)(tool_dlhandle);
+ VG_(sanity_check_needs)();
+
+ //--------------------------------------------------------------
+ // Process Valgrind's + tool's command-line options
+ // p: load_tool() [for 'tool']
+ // p: load_client() [for 'need_help']
+ // p: setup_file_descriptors() [for 'VG_(max_fd)']
+ // p: sk_pre_clo_init [to set 'command_line_options' need]
+ //--------------------------------------------------------------
+ process_cmd_line_options(client_auxv, esp_at_startup, tool, need_help);
+
+ //--------------------------------------------------------------
+ // Allow GDB attach
+ // p: 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)) {
+ VG_(printf)("pid=%d\n", VG_(getpid)());
+ /* do "jump *$eip" to skip this in gdb */
+ VG_(do_syscall)(__NR_pause);
+ }
+
+ //--------------------------------------------------------------
+ // Setup tool, post command-line processing
+ // p: process_cmd_line_options [tool assumes it]
+ //--------------------------------------------------------------
+ SK_(post_clo_init)();
+
+ //--------------------------------------------------------------
+ // Set up baseBlock, copy machine state (m_state_static)
+ // p: {pre,post}_clo_init() [for tool helper registration]
+ // load_client() [for 'client_eip']
+ // setup_client_stack() [for 'esp_at_startup']
+ //--------------------------------------------------------------
+ init_baseBlock(client_eip, esp_at_startup);
+
+ //--------------------------------------------------------------
+ // Search for file descriptors that are inherited from our parent
+ // p: process_cmd_line_options [for VG_(clo_track_fds)]
+ //--------------------------------------------------------------
+ if (VG_(clo_track_fds))
+ VG_(init_preopened_fds)();
+
+ //--------------------------------------------------------------
+ // Initialise the scheduler
+ // p: init_baseBlock() [baseBlock regs copied into VG_(threads)[1]]
+ // p: setup_file_descriptors() [else VG_(safe_fd)() breaks]
+ //--------------------------------------------------------------
+ VG_(scheduler_init)();
+
+ //--------------------------------------------------------------
+ // Set up the ProxyLWP machinery
+ // p: VG_(scheduler_init)()? [XXX: subtle dependency?]
+ // - subs: VG_(sigstartup_actions)()?
+ //--------------------------------------------------------------
+ VG_(proxy_init)();
+
+ //--------------------------------------------------------------
+ // Initialise the signal handling subsystem
+ // p: VG_(atfork)(NULL, NULL, newpid) [else problems with sigmasks]
+ // p: VG_(proxy_init)() [else breaks...]
+ //--------------------------------------------------------------
+ // Nb: temporarily parks the saved blocking-mask in saved_sigmask.
+ VG_(sigstartup_actions)();
+
+ //--------------------------------------------------------------
+ // Perhaps we're profiling Valgrind?
+ // p: process_cmd_line_options() [for VG_(clo_profile)]
+ // p: others?
+ //
+ // XXX: this seems to be broken? It always says the tool wasn't built
+ // for profiling; vg_profile.c's functions don't seem to be overriding
+ // vg_dummy_profile.c's?
+ //
+ // XXX: want this as early as possible. Looking for --profile
+ // in pre_process_cmd_line_options() could get it earlier.
+ //--------------------------------------------------------------
+ if (VG_(clo_profile))
+ VGP_(init_profiling)();
+
+ VGP_PUSHCC(VgpStartup);
+
+ //--------------------------------------------------------------
+ // Start calibration of our RDTSC-based clock
+ // p: n/a
+ //--------------------------------------------------------------
+ VG_(start_rdtsc_calibration)();
+
+ //--------------------------------------------------------------
+ // Reserve Valgrind's kickstart, heap and stack
+ // p: XXX ???
+ //--------------------------------------------------------------
+ VG_(map_segment)(VG_(valgrind_mmap_end),
+ VG_(valgrind_end)-VG_(valgrind_mmap_end),
+ VKI_PROT_NONE, SF_VALGRIND|SF_FIXED);
+
+ //--------------------------------------------------------------
+ // Identify Valgrind's segments
+ // p: read proc/self/maps
+ // p: VG_(map_segment) [XXX ???]
+ // p: sk_pre_clo_init() [to setup new_mem_startup tracker]
+ //--------------------------------------------------------------
+ VG_(parse_procselfmaps) ( build_valgrind_map_callback );
+
+ // XXX: I can't see why these two need to be separate; could they be
+ // folded together? If not, need a comment explaining why.
+ //
+ // XXX: can we merge reading and parsing of /proc/self/maps?
+ //
+ // XXX: can we dynamically allocate the /proc/self/maps buffer? (or mmap
+ // it?) Or does that disturb its contents...
+
+ //--------------------------------------------------------------
+ // Build segment map (all segments)
+ // p: setup_client_stack() [for 'esp_at_startup']
+ //--------------------------------------------------------------
+ esp_at_startup___global_arg = esp_at_startup;
+ VG_(parse_procselfmaps) ( build_segment_map_callback ); /* everything */
+ esp_at_startup___global_arg = 0;
+
+ //==============================================================
+ // Can only use VG_(map)() after VG_(map_segment)() [XXX ???]
+ //==============================================================
+
+ //--------------------------------------------------------------
+ // Build segment map (all segments)
+ // p: setup_client_stack() [for 'esp_at_startup']
+ //--------------------------------------------------------------
+ /* Initialize our trampoline page (which is also sysinfo stuff) */
+ VG_(memcpy)( (void *)VG_(client_trampoline_code),
+ &VG_(trampoline_code_start), VG_(trampoline_code_length) );
+ VG_(mprotect)( (void *)VG_(client_trampoline_code),
+ VG_(trampoline_code_length), VKI_PROT_READ|VKI_PROT_EXEC );
+
+ //--------------------------------------------------------------
+ // Read suppression file
+ // p: process_cmd_line_options() [for VG_(clo_suppressions)]
+ //--------------------------------------------------------------
+ if (VG_(needs).core_errors || VG_(needs).skin_errors)
+ VG_(load_suppressions)();
+
+ //--------------------------------------------------------------
+ // End calibrating our RDTSC-based clock, having waited a while.
+ // p: VG_(start_rdtsc_calibration)() [obviously]
+ //--------------------------------------------------------------
+ // Nb: Don't have to wait very long; it does pretty well even if
+ // start_rdtsc_calibration() is immediately before this.
+ VG_(end_rdtsc_calibration)();
+
+ //--------------------------------------------------------------
+ // Initialise translation table and translation cache
+ // p: read_procselfmaps [so the anonymous mmaps for the TT/TC
+ // aren't identified as part of the client, which would waste
+ // > 20M of virtual address space.]
+ //--------------------------------------------------------------
+ VG_(init_tt_tc)();
+
+ //--------------------------------------------------------------
+ // Read debug info to find glibc entry points to intercept
+ // p: parse_procselfmaps? [XXX for debug info?]
+ // p: init_tt_tc? [XXX ???]
+ //--------------------------------------------------------------
+ VG_(setup_code_redirect_table)();
+
+ //--------------------------------------------------------------
+ // Verbosity message
+ // p: end_rdtsc_calibration [so startup message is printed first]
+ //--------------------------------------------------------------
+ if (VG_(clo_verbosity) == 1)
+ VG_(message)(Vg_UserMsg, "For more details, rerun with: -v");
+ if (VG_(clo_verbosity) > 0)
+ VG_(message)(Vg_UserMsg, "");
+
+ //--------------------------------------------------------------
+ // Setup pointercheck
+ // p: process_cmd_line_options() [for VG_(clo_pointercheck)]
+ //--------------------------------------------------------------
+ setup_pointercheck();
+
+
+
+ //--------------------------------------------------------------
+ // Run!
+ //--------------------------------------------------------------
+ VG_(running_on_simd_CPU) = True;
+ VGP_POPCC(VgpStartup);
+ VGP_PUSHCC(VgpSched);
+
+ if (__builtin_setjmp(&VG_(fatal_signal_jmpbuf)) == 0) {
+ VG_(fatal_signal_set) = True;
+ src = VG_(scheduler)();
+ } else
+ src = VgSrc_FatalSig;
+
+ VGP_POPCC(VgpSched);
+ VG_(running_on_simd_CPU) = False;
+
+
+
+ //--------------------------------------------------------------
+ // Finalisation: cleanup, messages, etc. Order no so important, only
+ // affects what order the messages come.
+ //--------------------------------------------------------------
+ if (VG_(clo_verbosity) > 0)
+ VG_(message)(Vg_UserMsg, "");
+
+ if (src == VgSrc_Deadlock) {
+ VG_(message)(Vg_UserMsg,
+ "Warning: pthread scheduler exited due to deadlock");
+ }
+
+ /* Print out file descriptor summary and stats. */
+ if (VG_(clo_track_fds))
+ VG_(fd_stats)();
+
+ if (VG_(needs).core_errors || VG_(needs).skin_errors)
+ VG_(show_all_errors)();
+
+ SK_(fini)( VG_(exitcode) );
+
+ VG_(do_sanity_checks)( True /*include expensive checks*/ );
+
+ if (VG_(clo_verbosity) > 1)
+ show_counts();
+
+ if (VG_(clo_verbosity) > 3)
+ VG_(print_UInstr_histogram)();
+
+ if (0) {
+ VG_(message)(Vg_DebugMsg, "");
+ VG_(message)(Vg_DebugMsg,
+ "------ Valgrind's internal memory use stats follow ------" );
+ VG_(mallocSanityCheckAll)();
+ VG_(show_all_arena_stats)();
+ VG_(message)(Vg_DebugMsg,
+ "------ Valgrind's ExeContext management stats follow ------" );
+ VG_(show_ExeContext_stats)();
+ }
+
+ if (VG_(clo_profile))
+ VGP_(done_profiling)();
+
+ /* Must be after all messages are done */
+ VG_(shutdown_logging)();
+
+ /* We're exiting, so nuke all the threads and clean up the proxy LWPs */
+ vg_assert(src == VgSrc_FatalSig ||
+ VG_(threads)[VG_(last_run_tid)].status == VgTs_Runnable ||
+ VG_(threads)[VG_(last_run_tid)].status == VgTs_WaitJoiner);
+ VG_(nuke_all_threads_except)(VG_INVALID_THREADID);
+
+ //--------------------------------------------------------------
+ // Exit, according to the scheduler's return code
+ //--------------------------------------------------------------
+ switch (src) {
+ case VgSrc_ExitSyscall: /* the normal way out */
+ vg_assert(VG_(last_run_tid) > 0
+ && VG_(last_run_tid) < VG_N_THREADS);
+ VG_(proxy_shutdown)();
+
+ /* The thread's %EBX at the time it did __NR_exit() will hold
+ the arg to __NR_exit(), so we just do __NR_exit() with
+ that arg. */
+ VG_(exit)( VG_(exitcode) );
+ /* NOT ALIVE HERE! */
+ VG_(core_panic)("entered the afterlife in main() -- ExitSyscall");
+ break; /* what the hell :) */
+
+ case VgSrc_Deadlock:
+ /* Just exit now. No point in continuing. */
+ VG_(proxy_shutdown)();
+ VG_(exit)(0);
+ VG_(core_panic)("entered the afterlife in main() -- Deadlock");
+ break;
+
+ case VgSrc_BbsDone:
+ /* Tricky; we have to try and switch back to the real CPU.
+ This is all very dodgy and won't work at all in the
+ presence of threads, or if the client happened to be
+ running a signal handler. */
+ /* Prepare to restore state to the real CPU. */
+ VG_(sigshutdown_actions)();
+ VG_(load_thread_state)(1 /* root thread */ );
+ copy_baseBlock_to_m_state_static();
+
+ VG_(proxy_shutdown)();
+
+ /* This pushes a return address on the simulator's stack,
+ which is abandoned. We call vg_sigshutdown_actions() at
+ the end of vg_switch_to_real_CPU(), so as to ensure that
+ the original stack and machine state is restored before
+ the real signal mechanism is restored. */
+ VG_(switch_to_real_CPU)();
+
+ case VgSrc_FatalSig:
+ /* We were killed by a fatal signal, so replicate the effect */
+ vg_assert(VG_(fatal_sigNo) != -1);
+ VG_(kill_self)(VG_(fatal_sigNo));
+ VG_(core_panic)("main(): signal was supposed to be fatal");
+ break;
+
+ default:
+ VG_(core_panic)("main(): unexpected scheduler return code");
+ }
+
+ abort();
+}
+
+
/*--------------------------------------------------------------------*/
/*--- end vg_main.c ---*/
/*--------------------------------------------------------------------*/
diff --git a/coregrind/vg_memory.c b/coregrind/vg_memory.c
index 34299d8..7f5121b 100644
--- a/coregrind/vg_memory.c
+++ b/coregrind/vg_memory.c
@@ -397,12 +397,13 @@
(prot & (VKI_PROT_READ|VKI_PROT_EXEC)) == (VKI_PROT_READ|VKI_PROT_EXEC) &&
len >= VKI_BYTES_PER_PAGE &&
s->symtab == NULL &&
- VG_(is_object_file)((void *)addr)) {
+ VG_(is_object_file)((void *)addr))
+ {
+ s->symtab = VG_(read_seg_symbols)(s);
- s->symtab = VG_(read_seg_symbols)(s);
-
- if (s->symtab != NULL)
- s->flags |= SF_DYNLIB;
+ if (s->symtab != NULL) {
+ s->flags |= SF_DYNLIB;
+ }
} else if (flags & SF_MMAP) {
const SegInfo *info;
@@ -410,7 +411,8 @@
for(info = VG_(next_seginfo)(NULL);
info != NULL;
info = VG_(next_seginfo)(info)) {
- if (VG_(seg_overlaps)(s, VG_(seg_start)(info), VG_(seg_size)(info))) {
+ if (VG_(seg_overlaps)(s, VG_(seg_start)(info), VG_(seg_size)(info)))
+ {
s->symtab = (SegInfo *)info;
VG_(symtab_incref)((SegInfo *)info);
}
@@ -554,121 +556,6 @@
return VG_(SkipNode_Next)(&sk_segments, s);
}
-/*--------------------------------------------------------------*/
-/*--- Initialise program data/text etc on program startup. ---*/
-/*--------------------------------------------------------------*/
-
-static
-void build_valgrind_map_callback ( Addr start, UInt size,
- Char rr, Char ww, Char xx, UInt dev, UInt ino,
- ULong foffset, const UChar* filename )
-{
- UInt prot = 0;
- UInt flags;
- Bool is_stack_segment;
- Bool verbose = False || mem_debug; /* set to True for debugging */
-
- is_stack_segment = (start == VG_(clstk_base) && (start+size) == VG_(clstk_end));
-
- prot = 0;
- flags = SF_MMAP|SF_NOSYMS;
-
- if (start >= VG_(valgrind_base) && (start+size) <= VG_(valgrind_end))
- flags |= SF_VALGRIND;
-
- /* Only record valgrind mappings for now, without loading any
- symbols. This is so we know where the free space is before we
- start allocating more memory (note: heap is OK, it's just mmap
- which is the problem here). */
- if (flags & SF_VALGRIND) {
- if (verbose)
- VG_(printf)("adding segment %08p-%08p prot=%x flags=%4x filename=%s\n",
- start, start+size, prot, flags, filename);
-
- VG_(map_file_segment)(start, size, prot, flags, dev, ino, foffset, filename);
- }
-}
-
-static
-void build_segment_map_callback ( Addr start, UInt size,
- Char rr, Char ww, Char xx, UInt dev, UInt ino,
- ULong foffset, const UChar* filename )
-{
- UInt prot = 0;
- UInt flags;
- Bool is_stack_segment;
- Bool verbose = False || mem_debug; /* set to True for debugging */
- Addr r_esp;
-
- is_stack_segment = (start == VG_(clstk_base) && (start+size) == VG_(clstk_end));
-
- if (rr == 'r')
- prot |= VKI_PROT_READ;
- if (ww == 'w')
- prot |= VKI_PROT_WRITE;
- if (xx == 'x')
- prot |= VKI_PROT_EXEC;
-
-
- if (is_stack_segment)
- flags = SF_STACK | SF_GROWDOWN;
- else
- flags = SF_EXEC|SF_MMAP;
-
- if (filename != NULL)
- flags |= SF_FILE;
-
- if (start >= VG_(valgrind_base) && (start+size) <= VG_(valgrind_end))
- flags |= SF_VALGRIND;
-
- if (verbose)
- VG_(printf)("adding segment %08p-%08p prot=%x flags=%4x filename=%s\n",
- start, start+size, prot, flags, filename);
-
- VG_(map_file_segment)(start, size, prot, flags, dev, ino, foffset, filename);
-
- if (VG_(is_client_addr)(start) && VG_(is_client_addr)(start+size-1))
- VG_TRACK( new_mem_startup, start, size, rr=='r', ww=='w', xx=='x' );
-
- /* If this is the stack segment mark all below %esp as noaccess. */
- r_esp = VG_(m_state_static)[40/4];
- if (is_stack_segment) {
- if (0)
- VG_(message)(Vg_DebugMsg, "invalidating stack area: %x .. %x",
- start,r_esp);
- VG_TRACK( die_mem_stack, start, r_esp-start );
- }
-}
-
-
-/* 1. Records startup segments from /proc/pid/maps. Takes special note
- of the executable ones, because if they're munmap()ed we need to
- discard translations. Also checks there's no exe segment overlaps.
-
- Note that `read_from_file' is false; we read /proc/self/maps into a
- buffer at the start of VG_(main) so that any superblocks mmap'd by
- calls to VG_(malloc)() by SK_({pre,post}_clo_init) aren't erroneously
- thought of as being owned by the client.
- */
-void VG_(init_memory) ( void )
-{
- /* 1 */
- /* reserve Valgrind's kickstart, heap and stack */
- VG_(map_segment)(VG_(valgrind_mmap_end), VG_(valgrind_end)-VG_(valgrind_mmap_end),
- VKI_PROT_NONE, SF_VALGRIND|SF_FIXED);
-
- /* work out what's mapped where, and read interesting symtabs */
- VG_(parse_procselfmaps) ( build_valgrind_map_callback ); /* just Valgrind mappings */
- VG_(parse_procselfmaps) ( build_segment_map_callback ); /* everything */
-
- /* initialize our trampoline page (which is also sysinfo stuff) */
- VG_(memcpy)((void *)VG_(client_trampoline_code),
- &VG_(trampoline_code_start),
- VG_(trampoline_code_length));
- VG_(mprotect)((void *)VG_(client_trampoline_code), VG_(trampoline_code_length),
- VKI_PROT_READ|VKI_PROT_EXEC);
-}
-
/*------------------------------------------------------------*/
/*--- Tracking permissions around %esp changes. ---*/
/*------------------------------------------------------------*/
diff --git a/coregrind/vg_scheduler.c b/coregrind/vg_scheduler.c
index ce04d4d..418919d 100644
--- a/coregrind/vg_scheduler.c
+++ b/coregrind/vg_scheduler.c
@@ -581,8 +581,7 @@
/* Initialise the scheduler. Create a single "main" thread ready to
run, with special ThreadId of one. This is called at startup; the
- caller takes care to park the client's state is parked in
- VG_(baseBlock).
+ caller takes care to park the client's state in VG_(baseBlock).
*/
void VG_(scheduler_init) ( void )
{
diff --git a/coregrind/vg_syscalls.c b/coregrind/vg_syscalls.c
index b36245a..dd99a8b 100644
--- a/coregrind/vg_syscalls.c
+++ b/coregrind/vg_syscalls.c
@@ -153,6 +153,67 @@
return ret;
}
+/* Walk through a colon-separated environment variable, and remove the
+ entries which matches file_pattern. It slides everything down over
+ the removed entries, and pads the remaining space with '\0'. It
+ modifies the entries in place (in the client address space), but it
+ shouldn't matter too much, since we only do this just before an
+ execve().
+
+ This is also careful to mop up any excess ':'s, since empty strings
+ delimited by ':' are considered to be '.' in a path.
+*/
+static void mash_colon_env(Char *varp, const Char *remove_pattern)
+{
+ Char *const start = varp;
+ Char *entry_start = varp;
+ Char *output = varp;
+
+ if (varp == NULL)
+ return;
+
+ while(*varp) {
+ if (*varp == ':') {
+ Char prev;
+ Bool match;
+
+ /* This is a bit subtle: we want to match against the entry
+ we just copied, because it may have overlapped with
+ itself, junking the original. */
+
+ prev = *output;
+ *output = '\0';
+
+ match = VG_(string_match)(remove_pattern, entry_start);
+
+ *output = prev;
+
+ if (match) {
+ output = entry_start;
+ varp++; /* skip ':' after removed entry */
+ } else
+ entry_start = output+1; /* entry starts after ':' */
+ }
+
+ *output++ = *varp++;
+ }
+
+ /* match against the last entry */
+ if (VG_(string_match)(remove_pattern, entry_start)) {
+ output = entry_start;
+ if (output > start) {
+ /* remove trailing ':' */
+ output--;
+ vg_assert(*output == ':');
+ }
+ }
+
+ /* pad out the left-overs with '\0' */
+ while(output < varp)
+ *output++ = '\0';
+}
+
+
/* ---------------------------------------------------------------------
Doing mmap, munmap, mremap, mprotect
------------------------------------------------------------------ */
@@ -1808,13 +1869,13 @@
buf = VG_(arena_malloc)(VG_AR_CORE, VG_(strlen)(VG_(libdir)) + 20);
VG_(sprintf)(buf, "%s*/vg_inject.so", VG_(libdir));
- VG_(mash_colon_env)(ld_preload_str, buf);
+ mash_colon_env(ld_preload_str, buf);
VG_(sprintf)(buf, "%s*/vgpreload_*.so", VG_(libdir));
- VG_(mash_colon_env)(ld_preload_str, buf);
+ mash_colon_env(ld_preload_str, buf);
VG_(sprintf)(buf, "%s*", VG_(libdir));
- VG_(mash_colon_env)(ld_library_path_str, buf);
+ mash_colon_env(ld_library_path_str, buf);
VG_(env_unsetenv)(envp, VALGRINDCLO);
diff --git a/include/vg_skin.h.base b/include/vg_skin.h.base
index cf03145..dd61569 100644
--- a/include/vg_skin.h.base
+++ b/include/vg_skin.h.base
@@ -224,6 +224,7 @@
#define VGP_CORE_LIST \
/* These ones depend on the core */ \
VGP_PAIR(VgpUnc, "unclassified"), \
+ VGP_PAIR(VgpStartup, "startup"), \
VGP_PAIR(VgpRun, "running"), \
VGP_PAIR(VgpSched, "scheduler"), \
VGP_PAIR(VgpMalloc, "low-lev malloc/free"), \
@@ -237,7 +238,6 @@
VGP_PAIR(VgpLiveness, "liveness-analysis"), \
VGP_PAIR(VgpDoLRU, "do-lru"), \
VGP_PAIR(VgpSlowFindT, "slow-search-transtab"), \
- VGP_PAIR(VgpInitMem, "init-memory"), \
VGP_PAIR(VgpExeContext, "exe-context"), \
VGP_PAIR(VgpReadSyms, "read-syms"), \
VGP_PAIR(VgpSearchSyms, "search-syms"), \
@@ -288,12 +288,6 @@
/* Get the simulated %esp */
extern Addr VG_(get_stack_pointer) ( void );
-/* Detect if an address is within Valgrind's stack, Valgrind's
- m_state_static, or the VG_(threads) array. This is useful for
- memory leak detectors to rule out spurious pointers to a block. */
-extern Bool VG_(within_stack)(Addr a);
-extern Bool VG_(within_m_state_static_OR_threads)(Addr a);
-
/* Check if an address is 4-byte aligned */
#define IS_ALIGNED4_ADDR(aaa_p) (0 == (((UInt)(aaa_p)) & 3))
#define IS_ALIGNED8_ADDR(aaa_p) (0 == (((UInt)(aaa_p)) & 7))