|
From: Nicholas N. <nj...@ca...> - 2004-07-15 12:59:53
|
CVS commit by nethercote:
Merged Valgrind's heap and stack. This has two main advantages:
1. It simplifies various things a bit.
2. Valgrind/tools will run out of memory later than currently in many
circumstances. This is good news esp. for Calltree.
Some things were going in V's 128MB heap, and some were going in V's 128MB map
segment. Now all these things are going into a single 256MB map segment.
stage2 has been moved down to 0xb0000000, the start of the 256MB map segment.
The .so files needed by it are placed at 0xb1000000 (that's the map_base).
This required some bootstrapping at startup for memory -- we need to allocate
memory to create the segments skip-list which lets us allocate memory...
solution was to make the first superblock allocated a special static one.
That's pretty simple and enough to get things going.
Removed vg_glibc.c which wasn't doing anything anyway.
Removed VG_(brk) and associated stuff, made all the things that were calling it
call VG_(mmap)() instead.
Removed VG_(valgrind_mmap_end) which was no longer needed.
Rejigged the startup order a bit as necessary.
Moved an important comment from ume.c to vg_main.c where it should be.
M +1 -2 Makefile.am 1.75
M +1 -1 stage1.c 1.13
M +0 -42 ume.c 1.11
M +0 -4 vg_include.h 1.201
M +97 -88 vg_main.c 1.169
M +31 -8 vg_malloc2.c 1.27
M +1 -1 vg_memory.c 1.59
M +4 -56 vg_mylibc.c 1.81
R vg_glibc.c 1.2
--- valgrind/coregrind/Makefile.am #1.74:1.75
@@ -53,5 +53,4 @@
vg_execontext.c \
vg_from_ucode.c \
- vg_glibc.c \
vg_hashtable.c \
vg_helpers.S \
@@ -82,5 +81,5 @@
stage2_DEPENDENCIES = $(srcdir)/valgrind.vs x86/stage2.lds
stage2_LDFLAGS=-Wl,--export-dynamic -Wl,-e,_ume_entry -g \
- -Wl,-defsym,kickstart_base=0xb8000000 \
+ -Wl,-defsym,kickstart_base=0xb0000000 \
-Wl,-T,x86/stage2.lds \
-Wl,-version-script $(srcdir)/valgrind.vs
--- valgrind/coregrind/stage1.c #1.12:1.13
@@ -180,5 +180,5 @@ static void hoops(void)
- something else?
*/
- info.map_base = 0xb0000000;
+ info.map_base = 0xb1000000;
info.argv = NULL;
--- valgrind/coregrind/ume.c #1.10:1.11
@@ -29,46 +29,4 @@
*/
-/*
- User-mode exec
-
- This bootstraps Valgrind. This code decides on the layout of the
- client and Valgrind address spaces, loads valgrind.so and the
- skin.so into the valgrind part, loads the client executable (and the
- dynamic linker, if necessary) into the client part, and calls into
- Valgrind proper.
-
- The code is careful not to allow spurious mappings to appear in the
- wrong parts of the address space. In particular, to make sure
- dlopen puts things in the right place, it will pad out the forbidden
- chunks of address space so that dlopen is forced to put things where
- we want them.
-
- The memory map it creates is:
-
- CLIENT_BASE +-------------------------+
- | client address space |
- : :
- : :
- | client stack |
- client_end +-------------------------+
- | redzone |
- shadow_base +-------------------------+
- | |
- : shadow memory for skins :
- | (may be 0 sized) |
- shadow_end +-------------------------+
- : gap (may be 0 sized) :
- valgrind_base +-------------------------+
- | valgrind .so files |
- | and mappings |
- valgrind_mmap_end -
- | kickstart executable |
- - -
- | valgrind heap vvvvvvvvv|
- valgrind_end - -
- | valgrind stack ^^^^^^^^^|
- +-------------------------+
- : kernel :
- */
#define _GNU_SOURCE
--- valgrind/coregrind/vg_include.h #1.200:1.201
@@ -1134,7 +1134,4 @@ __attribute__ ((__noreturn__))
extern void VG_(core_panic) ( Char* str );
-/* VG_(brk) not public so skins cannot screw with curr_dataseg_end */
-extern void* VG_(brk) ( void* end_data_segment );
-
/* Skins use VG_(strdup)() which doesn't expose ArenaId */
extern Char* VG_(arena_strdup) ( ArenaId aid, const Char* s);
@@ -1439,5 +1436,4 @@ extern Addr VG_(shadow_base); /* skin's
extern Addr VG_(shadow_end);
extern Addr VG_(valgrind_base); /* valgrind's address range */
-extern Addr VG_(valgrind_mmap_end);
extern Addr VG_(valgrind_end);
--- valgrind/coregrind/vg_main.c #1.168:1.169
@@ -75,7 +75,4 @@
#endif /* AT_SECURE */
-/* 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)
@@ -112,5 +109,4 @@ 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_end);
@@ -493,6 +489,5 @@ static void layout_client_space(Addr arg
{
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_base) = (addr_t)&kickstart_base;
VG_(valgrind_end) = ROUNDUP(argc_addr, 0x10000); /* stack */
@@ -531,5 +526,4 @@ static void layout_remaining_space(float
"shadow_end %8x (%dMB)\n"
"valgrind_base %8x (%dMB)\n"
- "valgrind_mmap_end %8x (%dMB)\n"
"valgrind_end %8x\n",
VG_(client_base), SEGSIZE(client_base, client_mapbase),
@@ -538,6 +532,5 @@ static void layout_remaining_space(float
VG_(shadow_base), SEGSIZE(shadow_base, shadow_end),
VG_(shadow_end), SEGSIZE(shadow_end, valgrind_base),
- VG_(valgrind_base), SEGSIZE(valgrind_base, valgrind_mmap_end),
- VG_(valgrind_mmap_end), SEGSIZE(valgrind_mmap_end, valgrind_end),
+ VG_(valgrind_base), SEGSIZE(valgrind_base, valgrind_end),
VG_(valgrind_end)
);
@@ -2640,4 +2633,51 @@ void VG_(do_sanity_checks) ( Bool force_
/*====================================================================*/
+/*
+ This code decides on the layout of the client and Valgrind address
+ spaces, loads valgrind.so and the skin.so into the valgrind part,
+ loads the client executable (and the dynamic linker, if necessary)
+ into the client part, and calls into Valgrind proper.
+
+ The code is careful not to allow spurious mappings to appear in the
+ wrong parts of the address space. In particular, to make sure
+ dlopen puts things in the right place, it will pad out the forbidden
+ chunks of address space so that dlopen is forced to put things where
+ we want them.
+
+ The memory map it creates is:
+
+ CLIENT_BASE +-------------------------+
+ | client address space |
+ : :
+ : :
+ | client stack |
+ client_end +-------------------------+
+ | redzone |
+ shadow_base +-------------------------+
+ | |
+ : shadow memory for skins :
+ | (may be 0 sized) |
+ shadow_end +-------------------------+
+ : gap (may be 0 sized) :
+ valgrind_base +-------------------------+
+ | kickstart executable |
+ | valgrind heap vvvvvvvvv| (barely used)
+ - -
+ | valgrind .so files |
+ | and mappings |
+ - -
+ | valgrind stack ^^^^^^^^^|
+ valgrind_end +-------------------------+
+ : kernel :
+
+ Nb: Before we can do general allocations with VG_(arena_malloc)() and
+ VG_(mmap)(), we need to build the segment skip-list, so we know where
+ we can put things. However, building that structure requires
+ allocating memory. So we need to a bootstrapping process. It's done
+ by making VG_(arena_malloc)() have a special static superblock that's
+ used for the first 1MB's worth of allocations. This is enough to
+ build the segment skip-list.
+*/
+
static int prmap(void *start, void *end, const char *perm, off_t off,
int maj, int min, int ino) {
@@ -2690,5 +2730,5 @@ int main(int argc, char **argv)
//--------------------------------------------------------------
// Check we were launched by stage1
- // p: n/a [must be first step]
+ // p: n/a
//--------------------------------------------------------------
scan_auxv();
@@ -2737,5 +2777,5 @@ int main(int argc, char **argv)
//==============================================================
// Can use VG_(malloc)() and VG_(arena_malloc)() only after load_tool()
- // -- redzone size is now set.
+ // -- redzone size is now set. This is checked by vg_malloc2.c.
//==============================================================
@@ -2786,10 +2826,4 @@ int main(int argc, char **argv)
//--------------------------------------------------------------
- // 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
@@ -2805,12 +2839,27 @@ int main(int argc, char **argv)
//--------------------------------------------------------------
- // 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?
+ // Read /proc/self/maps into a buffer
+ // p: all memory layout, environment setup [so memory maps are right]
+ //--------------------------------------------------------------
+ VG_(read_procselfmaps)();
+
+ //--------------------------------------------------------------
+ // Build segment map (Valgrind segments only)
+ // p: read proc/self/maps
+ // p: sk_pre_clo_init() [to setup new_mem_startup tracker]
+ //--------------------------------------------------------------
+ VG_(parse_procselfmaps) ( build_valgrind_map_callback );
+
+ //==============================================================
+ // Can use VG_(arena_malloc)() with non-CORE arena after segments set up
+ //==============================================================
+
+ //--------------------------------------------------------------
+ // Init tool: pre_clo_init, process cmd line, post_clo_init
// p: setup_client_stack() [for 'VG_(client_arg[cv]']
+ // p: load_tool() [for 'tool']
+ // p: setup_file_descriptors() [for 'VG_(fd_xxx_limit)']
+ // p: parse_procselfmaps [so VG segments are setup so tool can
+ // call VG_(malloc)]
//--------------------------------------------------------------
(*toolinfo->sk_pre_clo_init)();
@@ -2818,20 +2867,34 @@ int main(int argc, char **argv)
VG_(sanity_check_needs)();
- //--------------------------------------------------------------
// If --tool and --help/--help-debug was given, now give the core+tool
// help message
- // p: pre_clo_init()
- //--------------------------------------------------------------
if (need_help) {
usage(/*--help-debug?*/2 == need_help);
}
+ process_cmd_line_options(client_auxv, tool);
+
+ SK_(post_clo_init)();
//--------------------------------------------------------------
- // Process Valgrind's + tool's command-line options
- // p: load_tool() [for 'tool']
- // p: setup_file_descriptors() [for 'VG_(fd_xxx_limit)']
- // p: sk_pre_clo_init [to set 'command_line_options' need]
+ // Build segment map (all segments)
+ // p: setup_client_stack() [for 'esp_at_startup']
+ // p: init tool [for 'new_mem_startup']
//--------------------------------------------------------------
- process_cmd_line_options(client_auxv, tool);
+ esp_at_startup___global_arg = esp_at_startup;
+ VG_(parse_procselfmaps) ( build_segment_map_callback ); /* everything */
+ esp_at_startup___global_arg = 0;
+
+ //--------------------------------------------------------------
+ // Initialize our trampoline page (which is also sysinfo stuff)
+ // p: setup_client_stack() [for 'esp_at_startup']
+ //--------------------------------------------------------------
+ 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 );
+
+ //==============================================================
+ // Can use VG_(map)() after segments set up
+ //==============================================================
//--------------------------------------------------------------
@@ -2848,10 +2911,4 @@ int main(int argc, char **argv)
//--------------------------------------------------------------
- // Setup tool, post command-line processing
- // p: process_cmd_line_options [tool assumes it]
- //--------------------------------------------------------------
- SK_(post_clo_init)();
-
- //--------------------------------------------------------------
// Set up baseBlock
// p: {pre,post}_clo_init() [for tool helper registration]
@@ -2908,50 +2965,4 @@ int main(int argc, char **argv)
//--------------------------------------------------------------
- // 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)]
--- valgrind/coregrind/vg_malloc2.c #1.26:1.27
@@ -188,4 +188,6 @@ void* align_upwards ( void* p, Int align
/*------------------------------------------------------------*/
+#define CORE_ARENA_MIN_SZW 262144
+
/* The arena structures themselves. */
static Arena vg_arena[VG_N_ARENAS];
@@ -247,8 +249,14 @@ static
void ensure_mm_init ( void )
{
- Int client_rz_szW;
+ static Int client_rz_szW;
static Bool init_done = False;
- if (init_done) return;
+ if (init_done) {
+ // Make sure the client arena's redzone size never changes. Could
+ // happen if VG_(arena_malloc) was called too early, ie. before the
+ // tool was loaded.
+ vg_assert(client_rz_szW == VG_(vg_malloc_redzone_szB)/4);
+ return;
+ }
/* Use checked red zones (of various sizes) for our internal stuff,
@@ -259,5 +267,5 @@ void ensure_mm_init ( void )
zone words are unchanged. */
- arena_init ( &vg_arena[VG_AR_CORE], "core", 2, True, 262144, False );
+ arena_init ( &vg_arena[VG_AR_CORE], "core", 2, True, CORE_ARENA_MIN_SZW, False );
arena_init ( &vg_arena[VG_AR_TOOL], "tool", 2, True, 262144, False );
@@ -317,8 +325,14 @@ Bool VG_(is_inside_segment_mmapd_by_low_
/*------------------------------------------------------------*/
+// If not enough memory available, either aborts (for non-client memory)
+// or returns 0 (for client memory).
static
Superblock* newSuperblock ( Arena* a, Int cszW )
{
+ static Bool called_before = False;
+ static Word bootstrap_superblock[CORE_ARENA_MIN_SZW];
+ Int cszB;
Superblock* sb;
+
cszW += 2; /* Take into account sb->next and sb->n_words fields */
if (cszW < a->min_sblockW) cszW = a->min_sblockW;
@@ -325,8 +339,18 @@ Superblock* newSuperblock ( Arena* a, In
while ((cszW % VKI_WORDS_PER_PAGE) > 0) cszW++;
- if (a->clientmem) {
+ cszB = cszW * sizeof(Word);
+
+ if (!called_before) {
+ // First time we're called -- use the special static bootstrap
+ // superblock (see comment at top of main() for details).
+ called_before = True;
+ vg_assert(a == &vg_arena[VG_AR_CORE]);
+ vg_assert(CORE_ARENA_MIN_SZW*sizeof(Word) >= cszB);
+ sb = (Superblock*)bootstrap_superblock;
+
+ } else if (a->clientmem) {
// client allocation -- return 0 to client if it fails
sb = (Superblock *)
- VG_(client_alloc)(0, cszW * sizeof(Word),
+ VG_(client_alloc)(0, cszB,
VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC, 0);
if (NULL == sb) {
@@ -335,9 +359,8 @@ Superblock* newSuperblock ( Arena* a, In
} else {
// non-client allocation -- abort if it fails
- sb = VG_(get_memory_from_mmap) ( cszW * sizeof(Word),
- "newSuperblock" );
+ sb = VG_(get_memory_from_mmap) ( cszB, "newSuperblock" );
}
sb->n_payload_words = cszW - 2;
- a->bytes_mmaped += cszW * sizeof(Word);
+ a->bytes_mmaped += cszB;
if (0)
VG_(message)(Vg_DebugMsg, "newSuperblock, %d payload words",
--- valgrind/coregrind/vg_memory.c #1.58:1.59
@@ -494,5 +494,5 @@ Addr VG_(find_map_space)(Addr addr, UInt
Segment *s;
Addr ret;
- Addr limit = (for_client ? VG_(client_end) : VG_(valgrind_mmap_end));
+ Addr limit = (for_client ? VG_(client_end) : VG_(valgrind_end));
if (addr == 0)
--- valgrind/coregrind/vg_mylibc.c #1.80:1.81
@@ -373,52 +373,4 @@ Int VG_(nanosleep)( const struct vki_tim
}
-extern Char _end;
-Char *VG_(curbrk) = NULL;
-extern void *__curbrk; /* in glibc */
-
-void* VG_(brk) ( void* end_data_segment )
-{
- Addr end;
- Addr brkpage;
- Addr endpage;
-
- if (VG_(curbrk) == NULL) {
- VG_(curbrk) = &_end;
- __curbrk = (void *)VG_(curbrk);
- }
-
- end = (Addr)end_data_segment;
- brkpage = PGROUNDUP(VG_(curbrk));
- endpage = PGROUNDUP(end);
-
- if (0 && VG_(curbrk) != __curbrk)
- VG_(printf)("__curbrk changed unexpectedly: VG_(curbrk)=%p, __curbrk=%p\n",
- VG_(curbrk), __curbrk);
-
- if (0)
- VG_(printf)("brk(end_data_segment=%p); brkpage=%p endpage=%p end=%p curbrk=%p &_end=%p\n",
- end_data_segment, brkpage, endpage, end, VG_(curbrk), &_end);
-
- if (endpage < (Addr)&_end) {
- __curbrk = (void *)VG_(curbrk);
- return (void *)VG_(curbrk);
- }
-
- if (brkpage != endpage) {
- if (brkpage > endpage) {
- Int res = munmap_inner((void *)brkpage, brkpage-endpage);
- vg_assert(0 == res);
- } else {
- Addr res = mmap_inner((void *)brkpage, endpage-brkpage,
- VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
- VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, -1, 0);
- vg_assert((Addr)-1 != res);
- }
- }
- VG_(curbrk) = (Char *)__curbrk = end_data_segment;
-
- return end_data_segment;
-}
-
/* ---------------------------------------------------------------------
@@ -1676,14 +1628,10 @@ void* VG_(get_memory_from_mmap) ( Int nB
static UInt tot_alloc = 0;
void* p;
- Char *b = VG_(brk)(0);
-
- p = (void *)PGROUNDUP(b);
- b = VG_(brk)(p + PGROUNDUP(nBytes));
-
- if (b != (p + PGROUNDUP(nBytes)))
- p = (void *)-1;
+ p = VG_(mmap)(0, nBytes,
+ VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
+ VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 0, -1, 0);
if (p != ((void*)(-1))) {
- vg_assert(p >= (void *)VG_(valgrind_mmap_end) && p < (void *)VG_(valgrind_end));
+ vg_assert(p >= (void*)VG_(valgrind_base) && p < (void*)VG_(valgrind_end));
tot_alloc += (UInt)nBytes;
if (0)
|