From: Julian Seward Date: Thu, 10 Mar 2005 23:59:00 +0000 (+0000) Subject: Merge in changes from the 2.4.0 line. This basically brings in the X-Git-Tag: svn/VALGRIND_3_0_0~1053 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0356d27ca6efc98d95ee7c99a10cad5c33fd6b70;p=thirdparty%2Fvalgrind.git Merge in changes from the 2.4.0 line. This basically brings in the overhaul of the thread support. Many things are now probably broken, but at least with --tool=none, simple and not-so-simple threaded and non-thread programs work. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3265 --- diff --git a/FAQ.txt b/FAQ.txt index 26a31d67df..665c919679 100644 --- a/FAQ.txt +++ b/FAQ.txt @@ -125,69 +125,6 @@ to a non-code address, in which case you'll get a SIGILL signal. Memcheck/Addrcheck may issue a warning just before this happens, but they might not if the jump happens to land in addressable memory. ------------------------------------------------------------------ - -3.4. My program dies like this: - - error: /lib/librt.so.1: symbol __pthread_clock_settime, version - GLIBC_PRIVATE not defined in file libpthread.so.0 with link time - reference - -This is a total swamp. Nevertheless there is a way out. It's a problem -which is not easy to fix. Really the problem is that /lib/librt.so.1 -refers to some symbols __pthread_clock_settime and -__pthread_clock_gettime in /lib/libpthread.so which are not intended to -be exported, ie they are private. - -Best solution is to ensure your program does not use /lib/librt.so.1. - -However .. since you're probably not using it directly, or even -knowingly, that's hard to do. You might instead be able to fix it by -playing around with coregrind/vg_libpthread.vs. Things to try: - -Remove this - - GLIBC_PRIVATE { - __pthread_clock_gettime; - __pthread_clock_settime; - }; - -or maybe remove this - - GLIBC_2.2.3 { - __pthread_clock_gettime; - __pthread_clock_settime; - } GLIBC_2.2; - -or maybe add this - - GLIBC_2.2.4 { - __pthread_clock_gettime; - __pthread_clock_settime; - } GLIBC_2.2; - - GLIBC_2.2.5 { - __pthread_clock_gettime; - __pthread_clock_settime; - } GLIBC_2.2; - -or some combination of the above. After each change you need to delete -coregrind/libpthread.so and do make && make install. - -I just don't know if any of the above will work. If you can find a -solution which works, I would be interested to hear it. - -To which someone replied: - - I deleted this: - - GLIBC_2.2.3 { - __pthread_clock_gettime; - __pthread_clock_settime; - } GLIBC_2.2; - - and it worked. - ----------------------------------------------------------------- 4. Valgrind behaves unexpectedly @@ -377,21 +314,6 @@ Unfortunately, Memcheck doesn't do bounds checking on static or stack arrays. We'd like to, but it's just not possible to do in a reasonable way that fits with how Memcheck works. Sorry. ------------------------------------------------------------------ - -5.3. My program dies with a segmentation fault, but Memcheck doesn't give - any error messages before it, or none that look related. - -One possibility is that your program accesses to memory with -inappropriate permissions set, such as writing to read-only memory. -Maybe your program is writing to a static string like this: - - char* s = "hello"; - s[0] = 'j'; - -or something similar. Writing to read-only memory can also apparently -make LinuxThreads behave strangely. - ----------------------------------------------------------------- 6. Miscellaneous diff --git a/Makefile.am b/Makefile.am index 48f0475a13..9a0ea4afcc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,15 +5,17 @@ include $(top_srcdir)/Makefile.all.am ## include must be first for tool.h ## addrcheck must come after memcheck, for mac_*.o -SUBDIRS = include coregrind . docs tests auxprogs \ - memcheck \ - addrcheck \ - cachegrind \ - corecheck \ - helgrind \ - massif \ - lackey \ - none +#TOOLS = memcheck \ +# addrcheck \ +# cachegrind \ +# corecheck \ +# massif \ +# lackey \ +# none +TOOLS = none + +SUBDIRS = include coregrind . docs tests auxprogs $(TOOLS) +DIST_SUBDIRS = $(SUBDIRS) helgrind SUPP_FILES = \ glibc-2.1.supp glibc-2.2.supp glibc-2.3.supp \ @@ -32,7 +34,7 @@ default.supp: $(SUPP_FILES) ## Preprend @PERL@ because tests/vg_regtest isn't executable regtest: check - @PERL@ tests/vg_regtest --all + @PERL@ tests/vg_regtest $(TOOLS) EXTRA_DIST = \ FAQ.txt \ @@ -40,14 +42,12 @@ EXTRA_DIST = \ README_DEVELOPERS \ README_PACKAGERS \ README_MISSING_SYSCALL_OR_IOCTL TODO \ - valgrind.spec.in valgrind.pc.in \ + valgrind.spec valgrind.spec.in valgrind.pc.in \ Makefile.all.am Makefile.tool.am Makefile.core-AM_CPPFLAGS.am \ Makefile.tool-inplace.am install-exec-hook: $(mkinstalldirs) $(DESTDIR)$(valdir) - rm -f $(DESTDIR)$(valdir)/libpthread.so.0 - $(LN_S) libpthread.so $(DESTDIR)$(valdir)/libpthread.so.0 all-local: mkdir -p $(inplacedir) diff --git a/Makefile.core-AM_CPPFLAGS.am b/Makefile.core-AM_CPPFLAGS.am index 03c313ff48..736bb22111 100644 --- a/Makefile.core-AM_CPPFLAGS.am +++ b/Makefile.core-AM_CPPFLAGS.am @@ -1,5 +1,7 @@ add_includes = -I$(top_builddir)/coregrind -I$(top_srcdir)/coregrind \ + -I$(top_srcdir) \ -I$(top_srcdir)/coregrind/$(VG_ARCH) \ + -I$(top_builddir)/coregrind/$(VG_ARCH) \ -I$(top_srcdir)/coregrind/$(VG_OS) \ -I$(top_srcdir)/coregrind/$(VG_PLATFORM) \ -I$(top_builddir)/include -I$(top_srcdir)/include \ @@ -9,5 +11,5 @@ add_includes = -I$(top_builddir)/coregrind -I$(top_srcdir)/coregrind \ -I@VEX_DIR@/pub AM_CPPFLAGS = $(add_includes) -AM_CCASFLAGS = $(add_includes) @ARCH_CORE_AM_CCASFLAGS@ +AM_CCASFLAGS = $(add_includes) @ARCH_CORE_AM_CCASFLAGS@ -Wa,-gstabs diff --git a/Makefile.tool-flags.am b/Makefile.tool-flags.am index 6b47ff6f89..32b3b85f6c 100644 --- a/Makefile.tool-flags.am +++ b/Makefile.tool-flags.am @@ -7,6 +7,6 @@ add_includes = -I$(top_builddir)/include -I$(top_srcdir)/include \ -I@VEX_DIR@/pub AM_CPPFLAGS = $(add_includes) -AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -g @ARCH_TOOL_AM_CFLAGS@ +AM_CFLAGS = $(WERROR) -Wmissing-prototypes -Winline -Wall -Wshadow -O -g @ARCH_TOOL_AM_CFLAGS@ AM_CCASFLAGS = $(add_includes) diff --git a/NOTES.txt b/NOTES.txt index f63f16c538..01cdb3bab4 100644 --- a/NOTES.txt +++ b/NOTES.txt @@ -70,4 +70,3 @@ did) and should be removed. Sockets: move the socketcall marshaller from vg_syscalls.c into x86-linux/syscalls.c; it is in the wrong place. -Tra La La diff --git a/README_PACKAGERS b/README_PACKAGERS index 7f220b1e2f..416bcf9240 100644 --- a/README_PACKAGERS +++ b/README_PACKAGERS @@ -51,28 +51,6 @@ of Valgrind. The following notes may save you some trouble. from valgrind. --- Try and ensure that the /usr/include/asm/unistd.h file on the - build machine contains an entry for all the system calls that - the kernels on the target machines can actually support. On my - Red Hat 7.2 (kernel 2.4.9) box the highest-numbered entry is - #define __NR_fcntl64 221 - but I have heard of 2.2 boxes where it stops at 179 or so. - - Reason for this is that at build time, support for syscalls - is compiled in -- or not -- depending on which of these __NR_* - symbols is defined. Problems arise when /usr/include/asm/unistd.h - fails to give an entry for a system call which is actually - available in the target kernel. In that case, valgrind will - abort if asked to handle such a syscall. This is despite the - fact that (usually) valgrind's sources actually contain the - code to deal with the syscall. - - Several people have reported having this problem. So, please - be aware of it. If it's useful, the syscall wrappers are - all done in vg_syscall_mem.c; you might want to have a little - look in there. - - -- Please test the final installation works by running it on something huge. I suggest checking that it can start and exit successfully both Mozilla-1.0 and OpenOffice.org 1.0. diff --git a/TODO b/TODO index a27c0e5397..738e509449 100644 --- a/TODO +++ b/TODO @@ -7,7 +7,7 @@ Wine. Desirable ~~~~~~~~~ -Stack: make return address into NoAccess ? +Stack: make return address into NoAccess ? Future diff --git a/addrcheck/ac_main.c b/addrcheck/ac_main.c index 73e0de41c8..af1a9c7da9 100644 --- a/addrcheck/ac_main.c +++ b/addrcheck/ac_main.c @@ -146,28 +146,43 @@ static void ac_fpu_ACCESS_check_SLOWLY ( Addr addr, SizeT size, Bool isWrite ); typedef struct { - UChar abits[8192]; + UChar abits[SECONDARY_SIZE / 8]; } AcSecMap; -static AcSecMap* primary_map[ /*65536*/ 262144 ]; -static AcSecMap distinguished_secondary_map; +static AcSecMap* primary_map[ /*PRIMARY_SIZE*/ PRIMARY_SIZE*4 ]; +static const AcSecMap distinguished_secondary_maps[2] = { + [ VGM_BIT_INVALID ] = { { [0 ... (SECONDARY_SIZE/8) - 1] = VGM_BYTE_INVALID } }, + [ VGM_BIT_VALID ] = { { [0 ... (SECONDARY_SIZE/8) - 1] = VGM_BYTE_VALID } }, +}; +#define N_SECONDARY_MAPS (sizeof(distinguished_secondary_maps)/sizeof(*distinguished_secondary_maps)) + +#define DSM_IDX(a) ((a) & 1) + +#define DSM(a) ((AcSecMap *)&distinguished_secondary_maps[DSM_IDX(a)]) + +#define DSM_NOTADDR DSM(VGM_BIT_INVALID) +#define DSM_ADDR DSM(VGM_BIT_VALID) static void init_shadow_memory ( void ) { - Int i; + Int i, a; - for (i = 0; i < 8192; i++) /* Invalid address */ - distinguished_secondary_map.abits[i] = VGM_BYTE_INVALID; + /* check construction of the distinguished secondaries */ + sk_assert(VGM_BIT_INVALID == 1); + sk_assert(VGM_BIT_VALID == 0); + + for(a = 0; a <= 1; a++) + sk_assert(distinguished_secondary_maps[DSM_IDX(a)].abits[0] == BIT_EXPAND(a)); /* These entries gradually get overwritten as the used address space expands. */ - for (i = 0; i < 65536; i++) - primary_map[i] = &distinguished_secondary_map; + for (i = 0; i < PRIMARY_SIZE; i++) + primary_map[i] = DSM_NOTADDR; /* These ones should never change; it's a bug in Valgrind if they do. */ - for (i = 65536; i < 262144; i++) - primary_map[i] = &distinguished_secondary_map; + for (i = PRIMARY_SIZE; i < PRIMARY_SIZE*4; i++) + primary_map[i] = DSM_NOTADDR; } /*------------------------------------------------------------*/ @@ -177,16 +192,14 @@ static void init_shadow_memory ( void ) /* Allocate and initialise a secondary map. */ static AcSecMap* alloc_secondary_map ( __attribute__ ((unused)) - Char* caller ) + Char* caller, + const AcSecMap *prototype) { AcSecMap* map; - UInt i; PROF_EVENT(10); - /* Mark all bytes as invalid access and invalid value. */ map = (AcSecMap *)VG_(shadow_alloc)(sizeof(AcSecMap)); - for (i = 0; i < 8192; i++) - map->abits[i] = VGM_BYTE_INVALID; /* Invalid address */ + VG_(memcpy)(map, prototype, sizeof(*map)); /* VG_(printf)("ALLOC_2MAP(%s)\n", caller ); */ return map; @@ -197,8 +210,8 @@ static AcSecMap* alloc_secondary_map ( __attribute__ ((unused)) static __inline__ UChar get_abit ( Addr a ) { - AcSecMap* sm = primary_map[a >> 16]; - UInt sm_off = a & 0xFFFF; + AcSecMap* sm = primary_map[PM_IDX(a)]; + UInt sm_off = SM_OFF(a); PROF_EVENT(20); # if 0 if (IS_DISTINGUISHED_SM(sm)) @@ -215,8 +228,8 @@ static /* __inline__ */ void set_abit ( Addr a, UChar abit ) UInt sm_off; PROF_EVENT(22); ENSURE_MAPPABLE(a, "set_abit"); - sm = primary_map[a >> 16]; - sm_off = a & 0xFFFF; + sm = primary_map[PM_IDX(a)]; + sm_off = SM_OFF(a); if (abit) BITARR_SET(sm->abits, sm_off); else @@ -235,8 +248,8 @@ static __inline__ UChar get_abits4_ALIGNED ( Addr a ) # ifdef VG_DEBUG_MEMORY tl_assert(IS_4_ALIGNED(a)); # endif - sm = primary_map[a >> 16]; - sm_off = a & 0xFFFF; + sm = primary_map[PM_IDX(a)]; + sm_off = SM_OFF(a); abits8 = sm->abits[sm_off >> 3]; abits8 >>= (a & 4 /* 100b */); /* a & 4 is either 0 or 4 */ abits8 &= 0x0F; @@ -282,14 +295,7 @@ void set_address_range_perms ( Addr a, SizeT len, UInt example_a_bit ) /* In order that we can charge through the address space at 8 bytes/main-loop iteration, make up some perms. */ - abyte8 = (example_a_bit << 7) - | (example_a_bit << 6) - | (example_a_bit << 5) - | (example_a_bit << 4) - | (example_a_bit << 3) - | (example_a_bit << 2) - | (example_a_bit << 1) - | (example_a_bit << 0); + abyte8 = BIT_EXPAND(example_a_bit); # ifdef VG_DEBUG_MEMORY /* Do it ... */ @@ -319,23 +325,51 @@ void set_address_range_perms ( Addr a, SizeT len, UInt example_a_bit ) } tl_assert((a % 8) == 0 && len > 0); - /* Once aligned, go fast. */ - while (True) { + /* Once aligned, go fast up to primary boundary. */ + for (; (a & SECONDARY_MASK) && len >= 8; a += 8, len -= 8) { PROF_EVENT(32); - if (len < 8) break; + + /* If the primary is already pointing to a distinguished map + with the same properties as we're trying to set, then leave + it that way. */ + if (primary_map[PM_IDX(a)] == DSM(example_a_bit)) + continue; ENSURE_MAPPABLE(a, "set_address_range_perms(fast)"); - sm = primary_map[a >> 16]; - sm_off = a & 0xFFFF; + sm = primary_map[PM_IDX(a)]; + sm_off = SM_OFF(a); sm->abits[sm_off >> 3] = abyte8; - a += 8; - len -= 8; } - if (len == 0) { - VGP_POPCC(VgpSetMem); - return; + /* Now set whole secondary maps to the right distinguished value. + + Note that if the primary already points to a non-distinguished + secondary, then don't replace the reference. That would just + leak memory. + */ + for(; len >= SECONDARY_SIZE; a += SECONDARY_SIZE, len -= SECONDARY_SIZE) { + sm = primary_map[PM_IDX(a)]; + + if (IS_DISTINGUISHED_SM(sm)) + primary_map[PM_IDX(a)] = DSM(example_a_bit); + else + VG_(memset)(sm->abits, abyte8, sizeof(sm->abits)); + } + + /* Now finished the remains. */ + for (; len >= 8; a += 8, len -= 8) { + PROF_EVENT(32); + + /* If the primary is already pointing to a distinguished map + with the same properties as we're trying to set, then leave + it that way. */ + if (primary_map[PM_IDX(a)] == DSM(example_a_bit)) + continue; + ENSURE_MAPPABLE(a, "set_address_range_perms(fast)"); + sm = primary_map[PM_IDX(a)]; + sm_off = SM_OFF(a); + sm->abits[sm_off >> 3] = abyte8; } - tl_assert((a % 8) == 0 && len > 0 && len < 8); + /* Finish the upper fragment. */ while (True) { @@ -379,8 +413,8 @@ void make_aligned_word_noaccess(Addr a) VGP_PUSHCC(VgpESPAdj); ENSURE_MAPPABLE(a, "make_aligned_word_noaccess"); - sm = primary_map[a >> 16]; - sm_off = a & 0xFFFF; + sm = primary_map[PM_IDX(a)]; + sm_off = SM_OFF(a); mask = 0x0F; mask <<= (a & 4 /* 100b */); /* a & 4 is either 0 or 4 */ /* mask now contains 1s where we wish to make address bits invalid (1s). */ @@ -397,8 +431,8 @@ void make_aligned_word_accessible(Addr a) VGP_PUSHCC(VgpESPAdj); ENSURE_MAPPABLE(a, "make_aligned_word_accessible"); - sm = primary_map[a >> 16]; - sm_off = a & 0xFFFF; + sm = primary_map[PM_IDX(a)]; + sm_off = SM_OFF(a); mask = 0x0F; mask <<= (a & 4 /* 100b */); /* a & 4 is either 0 or 4 */ /* mask now contains 1s where we wish to make address bits @@ -416,8 +450,8 @@ void make_aligned_doubleword_accessible(Addr a) VGP_PUSHCC(VgpESPAdj); ENSURE_MAPPABLE(a, "make_aligned_doubleword_accessible"); - sm = primary_map[a >> 16]; - sm_off = a & 0xFFFF; + sm = primary_map[PM_IDX(a)]; + sm_off = SM_OFF(a); sm->abits[sm_off >> 3] = VGM_BYTE_VALID; VGP_POPCC(VgpESPAdj); } @@ -430,8 +464,8 @@ void make_aligned_doubleword_noaccess(Addr a) VGP_PUSHCC(VgpESPAdj); ENSURE_MAPPABLE(a, "make_aligned_doubleword_noaccess"); - sm = primary_map[a >> 16]; - sm_off = a & 0xFFFF; + sm = primary_map[PM_IDX(a)]; + sm_off = SM_OFF(a); sm->abits[sm_off >> 3] = VGM_BYTE_INVALID; VGP_POPCC(VgpESPAdj); } @@ -619,15 +653,11 @@ void ac_new_mem_heap ( Addr a, SizeT len, Bool is_inited ) } static -void ac_set_perms (Addr a, SizeT len, Bool rr, Bool ww, Bool xx) +void ac_new_mem_mmap (Addr a, SizeT len, Bool rr, Bool ww, Bool xx) { DEBUG("ac_set_perms(%p, %u, rr=%u ww=%u, xx=%u)\n", a, len, rr, ww, xx); - if (rr || ww || xx) { - ac_make_accessible(a, len); - } else { - ac_make_noaccess(a, len); - } + ac_make_accessible(a, len); } static @@ -667,7 +697,7 @@ static __inline__ void ac_helperc_ACCESS4 ( Addr a, Bool isWrite ) # else UInt sec_no = rotateRight16(a) & 0x3FFFF; AcSecMap* sm = primary_map[sec_no]; - UInt a_off = (a & 0xFFFF) >> 3; + UInt a_off = (SM_OFF(a)) >> 3; UChar abits = sm->abits[a_off]; abits >>= (a & 4); abits &= 15; @@ -690,7 +720,7 @@ static __inline__ void ac_helperc_ACCESS2 ( Addr a, Bool isWrite ) # else UInt sec_no = rotateRight16(a) & 0x1FFFF; AcSecMap* sm = primary_map[sec_no]; - UInt a_off = (a & 0xFFFF) >> 3; + UInt a_off = (SM_OFF(a)) >> 3; PROF_EVENT(67); if (sm->abits[a_off] == VGM_BYTE_VALID) { /* Handle common case quickly. */ @@ -709,7 +739,7 @@ static __inline__ void ac_helperc_ACCESS1 ( Addr a, Bool isWrite ) # else UInt sec_no = shiftRight16(a); AcSecMap* sm = primary_map[sec_no]; - UInt a_off = (a & 0xFFFF) >> 3; + UInt a_off = (SM_OFF(a)) >> 3; PROF_EVENT(68); if (sm->abits[a_off] == VGM_BYTE_VALID) { /* Handle common case quickly. */ @@ -789,7 +819,7 @@ static void ac_ACCESS4_SLOWLY ( Addr a, Bool isWrite ) if (!MAC_(clo_partial_loads_ok) || ((a & 3) != 0) || (!a0ok && !a1ok && !a2ok && !a3ok)) { - MAC_(record_address_error)( VG_(get_current_tid)(), a, 4, isWrite ); + MAC_(record_address_error)( VG_(get_VCPU_tid)(), a, 4, isWrite ); return; } @@ -816,7 +846,7 @@ static void ac_ACCESS2_SLOWLY ( Addr a, Bool isWrite ) /* If an address error has happened, report it. */ if (aerr) { - MAC_(record_address_error)( VG_(get_current_tid)(), a, 2, isWrite ); + MAC_(record_address_error)( VG_(get_VCPU_tid)(), a, 2, isWrite ); } } @@ -830,7 +860,7 @@ static void ac_ACCESS1_SLOWLY ( Addr a, Bool isWrite) /* If an address error has happened, report it. */ if (aerr) { - MAC_(record_address_error)( VG_(get_current_tid)(), a, 1, isWrite ); + MAC_(record_address_error)( VG_(get_VCPU_tid)(), a, 1, isWrite ); } } @@ -864,8 +894,8 @@ void ac_fpu_ACCESS_check ( Addr addr, SizeT size, Bool isWrite ) if (!IS_4_ALIGNED(addr)) goto slow4; PROF_EVENT(91); /* Properly aligned. */ - sm = primary_map[addr >> 16]; - sm_off = addr & 0xFFFF; + sm = primary_map[PM_IDX(addr)]; + sm_off = SM_OFF(addr); a_off = sm_off >> 3; if (sm->abits[a_off] != VGM_BYTE_VALID) goto slow4; /* Properly aligned and addressible. */ @@ -881,14 +911,14 @@ void ac_fpu_ACCESS_check ( Addr addr, SizeT size, Bool isWrite ) /* Properly aligned. Do it in two halves. */ addr4 = addr + 4; /* First half. */ - sm = primary_map[addr >> 16]; - sm_off = addr & 0xFFFF; + sm = primary_map[PM_IDX(addr)]; + sm_off = SM_OFF(addr); a_off = sm_off >> 3; if (sm->abits[a_off] != VGM_BYTE_VALID) goto slow8; /* First half properly aligned and addressible. */ /* Second half. */ - sm = primary_map[addr4 >> 16]; - sm_off = addr4 & 0xFFFF; + sm = primary_map[PM_IDX(addr4)]; + sm_off = SM_OFF(addr4); a_off = sm_off >> 3; if (sm->abits[a_off] != VGM_BYTE_VALID) goto slow8; /* Second half properly aligned and addressible. */ @@ -947,7 +977,7 @@ void ac_fpu_ACCESS_check_SLOWLY ( Addr addr, SizeT size, Bool isWrite ) } if (aerr) { - MAC_(record_address_error)( VG_(get_current_tid)(), addr, size, isWrite ); + MAC_(record_address_error)( VG_(get_VCPU_tid)(), addr, size, isWrite ); } } @@ -1110,8 +1140,8 @@ IRBB* TL_(instrument)(IRBB* bb_in, VexGuestLayout* layout, IRType hWordTy ) static Bool ac_is_valid_64k_chunk ( UInt chunk_number ) { - tl_assert(chunk_number >= 0 && chunk_number < 65536); - if (IS_DISTINGUISHED_SM(primary_map[chunk_number])) { + tl_assert(chunk_number >= 0 && chunk_number < PRIMARY_SIZE); + if (primary_map[chunk_number] == DSM_NOTADDR) { /* Definitely not in use. */ return False; } else { @@ -1139,10 +1169,9 @@ Bool ac_is_valid_address ( Addr a ) /* Leak detector for this tool. We don't actually do anything, merely run the generic leak detector with suitable parameters for this tool. */ -static void ac_detect_memory_leaks ( ThreadId tid ) +static void ac_detect_memory_leaks ( LeakCheckMode mode ) { - MAC_(do_detect_memory_leaks) ( - tid, ac_is_valid_64k_chunk, ac_is_valid_address ); + MAC_(do_detect_memory_leaks) ( mode, ac_is_valid_64k_chunk, ac_is_valid_address ); } @@ -1160,15 +1189,17 @@ Bool TL_(expensive_sanity_check) ( void ) { Int i; +#if 0 /* Make sure nobody changed the distinguished secondary. */ for (i = 0; i < 8192; i++) if (distinguished_secondary_map.abits[i] != VGM_BYTE_INVALID) return False; +#endif /* Make sure that the upper 3/4 of the primary map hasn't been messed with. */ - for (i = 65536; i < 262144; i++) - if (primary_map[i] != & distinguished_secondary_map) + for (i = PRIMARY_SIZE; i < PRIMARY_SIZE*4; i++) + if (primary_map[i] != DSM_NOTADDR) return False; return True; @@ -1204,7 +1235,7 @@ Bool TL_(handle_client_request) ( ThreadId tid, UWord* arg, UWord *ret ) switch (arg[0]) { case VG_USERREQ__DO_LEAK_CHECK: - ac_detect_memory_leaks(tid); + ac_detect_memory_leaks(arg[1] ? LC_Summary : LC_Full); *ret = 0; /* return value is meaningless */ break; @@ -1294,10 +1325,9 @@ void TL_(pre_clo_init)(void) VG_(init_new_mem_startup) ( & ac_new_mem_startup ); VG_(init_new_mem_stack_signal) ( & ac_make_accessible ); VG_(init_new_mem_brk) ( & ac_make_accessible ); - VG_(init_new_mem_mmap) ( & ac_set_perms ); + VG_(init_new_mem_mmap) ( & ac_new_mem_mmap ); VG_(init_copy_mem_remap) ( & ac_copy_address_range_state ); - VG_(init_change_mem_mprotect) ( & ac_set_perms ); VG_(init_die_mem_stack_signal) ( & ac_make_noaccess ); VG_(init_die_mem_brk) ( & ac_make_noaccess ); diff --git a/addrcheck/tests/Makefile.am b/addrcheck/tests/Makefile.am index e4aa57ac30..4774c1cd70 100644 --- a/addrcheck/tests/Makefile.am +++ b/addrcheck/tests/Makefile.am @@ -1,6 +1,8 @@ + noinst_SCRIPTS = filter_stderr EXTRA_DIST = $(noinst_SCRIPTS) \ + addressable.vgtest addressable.stderr.exp addressable.stdout.exp \ badrw.stderr.exp badrw.vgtest \ fprw.stderr.exp fprw.vgtest \ overlap.stderr.exp overlap.stdout.exp overlap.vgtest \ diff --git a/cachegrind/cg_main.c b/cachegrind/cg_main.c index 5f370fca25..4f4c55bbaf 100644 --- a/cachegrind/cg_main.c +++ b/cachegrind/cg_main.c @@ -671,7 +671,7 @@ IRBB* TL_(instrument) ( IRBB* bb_in, VexGuestLayout* layout, IRType hWordTy ) /*--- Cache configuration ---*/ /*------------------------------------------------------------*/ -#define UNDEFINED_CACHE ((cache_t) { -1, -1, -1 }) +#define UNDEFINED_CACHE { -1, -1, -1 } static cache_t clo_I1_cache = UNDEFINED_CACHE; static cache_t clo_D1_cache = UNDEFINED_CACHE; diff --git a/cachegrind/x86/cg_arch.c b/cachegrind/x86/cg_arch.c index 81117b84f2..0cc918d372 100644 --- a/cachegrind/x86/cg_arch.c +++ b/cachegrind/x86/cg_arch.c @@ -245,50 +245,23 @@ Int AMD_cache_info(cache_t* I1c, cache_t* D1c, cache_t* L2c) return 0; } -static jmp_buf cpuid_jmpbuf; - -static -void cpuid_SIGILL_handler(int signum) -{ - __builtin_longjmp(cpuid_jmpbuf, 1); -} - static Int get_caches_from_CPUID(cache_t* I1c, cache_t* D1c, cache_t* L2c) { - Int level, res, ret; + Int level, ret; Char vendor_id[13]; - struct vki_sigaction sigill_new, sigill_saved; - - /* Install own SIGILL handler */ - sigill_new.ksa_handler = cpuid_SIGILL_handler; - sigill_new.sa_flags = 0; - sigill_new.sa_restorer = NULL; - res = VG_(sigemptyset)( &sigill_new.sa_mask ); tl_assert(res == 0); res = VG_(sigaction)( VKI_SIGILL, &sigill_new, &sigill_saved ); tl_assert(res == 0); - /* Trap for illegal instruction, in case it's a really old processor that - * doesn't support CPUID. */ - if (__builtin_setjmp(cpuid_jmpbuf) == 0) { - VG_(cpuid)(0, &level, (int*)&vendor_id[0], - (int*)&vendor_id[8], (int*)&vendor_id[4]); - vendor_id[12] = '\0'; - - /* Restore old SIGILL handler */ - res = VG_(sigaction)( VKI_SIGILL, &sigill_saved, NULL ); - tl_assert(res == 0); - - } else { + if (!VG_(has_cpuid)()) { VG_(message)(Vg_DebugMsg, "CPUID instruction not supported"); - - /* Restore old SIGILL handler */ - res = VG_(sigaction)( VKI_SIGILL, &sigill_saved, NULL ); - tl_assert(res == 0); return -1; } + VG_(cpuid)(0, &level, (int*)&vendor_id[0], + (int*)&vendor_id[8], (int*)&vendor_id[4]); + vendor_id[12] = '\0'; if (0 == level) { VG_(message)(Vg_DebugMsg, "CPUID level is 0, early Pentium?\n"); diff --git a/configure.in b/configure.in index 63df6192e0..15b4531f40 100644 --- a/configure.in +++ b/configure.in @@ -25,7 +25,7 @@ AC_ARG_WITH(vex, AC_SUBST(VEX_DIR) # Checks for programs. -CFLAGS="" +CFLAGS="-Wno-long-long" AC_PROG_LN_S AC_PROG_CC @@ -96,8 +96,8 @@ case "${host_cpu}" in AC_MSG_RESULT([ok (${host_cpu})]) VG_ARCH="x86" KICKSTART_BASE="0xb0000000" - ARCH_CORE_AM_CFLAGS="-fomit-frame-pointer @PREFERRED_STACK_BOUNDARY@ -DELFSZ=32" - ARCH_TOOL_AM_CFLAGS="-fomit-frame-pointer @PREFERRED_STACK_BOUNDARY@" + ARCH_CORE_AM_CFLAGS="@PREFERRED_STACK_BOUNDARY@ -DELFSZ=32" + ARCH_TOOL_AM_CFLAGS="@PREFERRED_STACK_BOUNDARY@" ARCH_CORE_AM_CCASFLAGS="" ;; @@ -268,21 +268,6 @@ case "${glibc}" in ;; esac -# APIs introduced in recent glibc versions - -AC_MSG_CHECKING([whether sched_param has a sched_priority member]) -AC_CACHE_VAL(vg_have_sched_priority, -[ -AC_TRY_COMPILE([#include ],[ -struct sched_param p; p.sched_priority=1;], -vg_have_sched_priority=yes, -vg_have_sched_priority=no) -]) -AC_MSG_RESULT($vg_have_sched_priority) -if test "$vg_have_sched_priority" = yes; then -AC_DEFINE([HAVE_SCHED_PRIORITY], 1, [pthread / sched_priority exists]) -fi - # We don't know how to detect the X client library version # (detecting the server version is easy, bu no help). So we # just use a hack: always include the suppressions for both @@ -314,19 +299,55 @@ CFLAGS=$safe_CFLAGS AC_SUBST(PREFERRED_STACK_BOUNDARY) +# does this compiler support -Wno-pointer-sign ? +AC_MSG_CHECKING([if gcc accepts -Wno-pointer-sign ]) + +safe_CFLAGS=$CFLAGS +CFLAGS="-Wno-pointer-sign" + +AC_TRY_COMPILE(, [ +int main () { return 0 ; } +], +[ +no_pointer_sign=yes +AC_MSG_RESULT([yes]) +], [ +no_pointer_sign=no +AC_MSG_RESULT([no]) +]) +CFLAGS=$safe_CFLAGS + +if test x$no_pointer_sign = xyes; then + CFLAGS="$CFLAGS -Wno-pointer-sign" +fi + +# Check for TLS support in the compiler and linker +AC_CACHE_CHECK([for TLS support], vg_cv_tls, + [AC_ARG_ENABLE(tls, [ --enable-tls platform supports TLS], + [vg_cv_tls=$enableval], + [AC_RUN_IFELSE([AC_LANG_PROGRAM([[static __thread int foo;]], + [[return foo;]])], + [vg_cv_tls=yes], + [vg_cv_tls=no])])]) + +if test "$vg_cv_tls" = yes; then +AC_DEFINE([HAVE_TLS], 1, [can use __thread to define thread-local variables]) +fi # Check for PIE support in the compiler and linker AC_CACHE_CHECK([for PIE support], vg_cv_pie, - [safe_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -fpie" - safe_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -pie" - AC_TRY_LINK([int foo;], - [], - [vg_cv_pie=yes], - [vg_cv_pie=no]) - CFLAGS=$safe_CFLAGS - LDFLAGS=$safe_LDFLAGS]) + [AC_ARG_ENABLE(pie, [ --enable-pie platform supports PIE linking], + [vg_cv_pie=$enableval], + [safe_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -fpie" + safe_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -pie" + AC_TRY_LINK([int foo;], + [], + [vg_cv_pie=yes], + [vg_cv_pie=no]) + CFLAGS=$safe_CFLAGS + LDFLAGS=$safe_LDFLAGS])]) if test "$vg_cv_pie" = yes; then AC_DEFINE([HAVE_PIE], 1, [can create position-independent executables]) fi @@ -342,7 +363,6 @@ AC_TYPE_UID_T AC_TYPE_OFF_T AC_TYPE_SIZE_T AC_HEADER_TIME -AC_CHECK_TYPES(__pthread_unwind_buf_t,,,[#include ]) # Checks for library functions. AC_FUNC_MEMCMP diff --git a/corecheck/tests/Makefile.am b/corecheck/tests/Makefile.am index 26cac4fdd4..18b48a5a28 100644 --- a/corecheck/tests/Makefile.am +++ b/corecheck/tests/Makefile.am @@ -30,7 +30,7 @@ EXTRA_DIST = $(noinst_SCRIPTS) \ pth_mutexspeed.stdout.exp pth_mutexspeed.vgtest \ pth_once.stderr.exp pth_once.stdout.exp pth_once.vgtest \ pth_rwlock.stderr.exp pth_rwlock.vgtest \ - sigkill.stderr.exp sigkill.vgtest \ + sigkill.stderr.exp sigkill.stderr.exp2 sigkill.vgtest \ res_search.stderr.exp res_search.stdout.exp res_search.vgtest \ vgprintf.stderr.exp vgprintf.stdout.exp vgprintf.vgtest diff --git a/corecheck/tests/as_mmap.stderr.exp b/corecheck/tests/as_mmap.stderr.exp index bc52d12630..345197ce82 100644 --- a/corecheck/tests/as_mmap.stderr.exp +++ b/corecheck/tests/as_mmap.stderr.exp @@ -1,7 +1,5 @@ 1 -Warning: client syscall mmap2 tried to modify addresses 0x........-0x........ -mmap @ 0x........ 2 3 4 diff --git a/corecheck/tests/as_mmap.stderr.exp2 b/corecheck/tests/as_mmap.stderr.exp2 index b40840b6c1..a9518b8363 100644 --- a/corecheck/tests/as_mmap.stderr.exp2 +++ b/corecheck/tests/as_mmap.stderr.exp2 @@ -1,7 +1,5 @@ 1 -Warning: client syscall old_mmap tried to modify addresses 0x........-0x........ -mmap @ 0x........ 2 3 4 diff --git a/corecheck/tests/fdleak_cmsg.c b/corecheck/tests/fdleak_cmsg.c index a6dccb1020..32c5d84f80 100644 --- a/corecheck/tests/fdleak_cmsg.c +++ b/corecheck/tests/fdleak_cmsg.c @@ -6,6 +6,7 @@ #include #include #include +#include char filea[24]; char fileb[24]; @@ -126,7 +127,10 @@ client () exit(1); } + again: if((size = recvmsg(s, &msg, 0)) == -1) { + if (errno == EINTR) + goto again; /* SIGCHLD from server exiting could interrupt */ perror("recvmsg"); exit(1); } diff --git a/corecheck/tests/fdleak_cmsg.stderr.exp b/corecheck/tests/fdleak_cmsg.stderr.exp index d4ad192098..8a7cd44646 100644 --- a/corecheck/tests/fdleak_cmsg.stderr.exp +++ b/corecheck/tests/fdleak_cmsg.stderr.exp @@ -3,19 +3,19 @@ FILE DESCRIPTORS: 7 open at exit. Open AF_UNIX socket .: /tmp/sock at 0x........: accept (in /...libc...) - by 0x........: main (fdleak_cmsg.c:170) + by 0x........: main (fdleak_cmsg.c:174) Open AF_UNIX socket .: /tmp/sock at 0x........: socket (in /...libc...) - by 0x........: main (fdleak_cmsg.c:170) + by 0x........: main (fdleak_cmsg.c:174) Open file descriptor .: /tmp/data2 at 0x........: open (in /...libc...) - by 0x........: main (fdleak_cmsg.c:170) + by 0x........: main (fdleak_cmsg.c:174) Open file descriptor .: /tmp/data1 at 0x........: open (in /...libc...) - by 0x........: main (fdleak_cmsg.c:170) + by 0x........: main (fdleak_cmsg.c:174) Open file descriptor .: . @@ -32,15 +32,15 @@ ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) FILE DESCRIPTORS: 6 open at exit. Open file descriptor .: /tmp/data2 at 0x........: recvmsg (in /...libc...) - by 0x........: main (fdleak_cmsg.c:174) + by 0x........: main (fdleak_cmsg.c:178) Open file descriptor .: /tmp/data1 at 0x........: recvmsg (in /...libc...) - by 0x........: main (fdleak_cmsg.c:174) + by 0x........: main (fdleak_cmsg.c:178) Open AF_UNIX socket .: at 0x........: socket (in /...libc...) - by 0x........: main (fdleak_cmsg.c:174) + by 0x........: main (fdleak_cmsg.c:178) Open file descriptor .: . diff --git a/corecheck/tests/fdleak_creat.stderr.exp b/corecheck/tests/fdleak_creat.stderr.exp index 66e60362a0..9817b8292e 100644 --- a/corecheck/tests/fdleak_creat.stderr.exp +++ b/corecheck/tests/fdleak_creat.stderr.exp @@ -4,7 +4,7 @@ FILE DESCRIPTORS: 4 open at exit. Open file descriptor .: /tmp/file at 0x........: creat (in /...libc...) - by 0x........: __libc_start_main (...libc...) + by 0x........: __libc_start_main (in /...libc...) by 0x........: ... Open file descriptor .: . diff --git a/corecheck/tests/fdleak_dup.stderr.exp b/corecheck/tests/fdleak_dup.stderr.exp index 0c54be6b06..480075761f 100644 --- a/corecheck/tests/fdleak_dup.stderr.exp +++ b/corecheck/tests/fdleak_dup.stderr.exp @@ -3,12 +3,12 @@ FILE DESCRIPTORS: 5 open at exit. Open file descriptor .: /dev/null at 0x........: dup (in /...libc...) - by 0x........: __libc_start_main (...libc...) + by 0x........: __libc_start_main (in /...libc...) by 0x........: ... Open file descriptor .: /dev/null at 0x........: open (in /...libc...) - by 0x........: __libc_start_main (...libc...) + by 0x........: __libc_start_main (in /...libc...) by 0x........: ... Open file descriptor .: . diff --git a/corecheck/tests/fdleak_dup2.stderr.exp b/corecheck/tests/fdleak_dup2.stderr.exp index 612b352e03..0548b64c96 100644 --- a/corecheck/tests/fdleak_dup2.stderr.exp +++ b/corecheck/tests/fdleak_dup2.stderr.exp @@ -3,17 +3,17 @@ FILE DESCRIPTORS: 6 open at exit. Open file descriptor .: /dev/null at 0x........: dup2 (in /...libc...) - by 0x........: __libc_start_main (...libc...) + by 0x........: __libc_start_main (in /...libc...) by 0x........: ... Open file descriptor .: /dev/null at 0x........: dup2 (in /...libc...) - by 0x........: __libc_start_main (...libc...) + by 0x........: __libc_start_main (in /...libc...) by 0x........: ... Open file descriptor .: /dev/null at 0x........: open (in /...libc...) - by 0x........: __libc_start_main (...libc...) + by 0x........: __libc_start_main (in /...libc...) by 0x........: ... Open file descriptor .: . diff --git a/corecheck/tests/fdleak_fcntl.stderr.exp b/corecheck/tests/fdleak_fcntl.stderr.exp index 89f059e0e2..bbd64e0015 100644 --- a/corecheck/tests/fdleak_fcntl.stderr.exp +++ b/corecheck/tests/fdleak_fcntl.stderr.exp @@ -7,7 +7,7 @@ Open file descriptor .: /dev/null Open file descriptor .: /dev/null at 0x........: open (in /...libc...) - by 0x........: __libc_start_main (...libc...) + by 0x........: __libc_start_main (in /...libc...) by 0x........: ... Open file descriptor .: . diff --git a/corecheck/tests/fdleak_open.stderr.exp b/corecheck/tests/fdleak_open.stderr.exp index 6fda89512a..63a7ff63b0 100644 --- a/corecheck/tests/fdleak_open.stderr.exp +++ b/corecheck/tests/fdleak_open.stderr.exp @@ -3,7 +3,7 @@ FILE DESCRIPTORS: 4 open at exit. Open file descriptor .: /dev/null at 0x........: open (in /...libc...) - by 0x........: __libc_start_main (...libc...) + by 0x........: __libc_start_main (in /...libc...) by 0x........: ... Open file descriptor .: . diff --git a/corecheck/tests/fdleak_pipe.stderr.exp b/corecheck/tests/fdleak_pipe.stderr.exp index 0ba67334fb..7d4bbdabb5 100644 --- a/corecheck/tests/fdleak_pipe.stderr.exp +++ b/corecheck/tests/fdleak_pipe.stderr.exp @@ -3,12 +3,12 @@ FILE DESCRIPTORS: 5 open at exit. Open file descriptor .: at 0x........: pipe (in /...libc...) - by 0x........: __libc_start_main (...libc...) + by 0x........: __libc_start_main (in /...libc...) by 0x........: ... Open file descriptor .: at 0x........: pipe (in /...libc...) - by 0x........: __libc_start_main (...libc...) + by 0x........: __libc_start_main (in /...libc...) by 0x........: ... Open file descriptor .: . diff --git a/corecheck/tests/fdleak_socketpair.stderr.exp b/corecheck/tests/fdleak_socketpair.stderr.exp index 87192dad18..79b389631a 100644 --- a/corecheck/tests/fdleak_socketpair.stderr.exp +++ b/corecheck/tests/fdleak_socketpair.stderr.exp @@ -3,12 +3,12 @@ FILE DESCRIPTORS: 5 open at exit. Open AF_UNIX socket .: at 0x........: socketpair (in /...libc...) - by 0x........: __libc_start_main (...libc...) + by 0x........: __libc_start_main (in /...libc...) by 0x........: ... Open AF_UNIX socket .: at 0x........: socketpair (in /...libc...) - by 0x........: __libc_start_main (...libc...) + by 0x........: __libc_start_main (in /...libc...) by 0x........: ... Open file descriptor .: . diff --git a/corecheck/tests/filter_fdleak b/corecheck/tests/filter_fdleak index f04b8f16b9..653be58864 100755 --- a/corecheck/tests/filter_fdleak +++ b/corecheck/tests/filter_fdleak @@ -12,15 +12,6 @@ sed "s/mac_replace_strmem.c:[0-9]*/mac_replace_strmem.c:.../" | $dir/../../tests/filter_test_paths | -# Anonymise paths like "(in /foo/bar/libc-baz.so)" -sed "s/(in \/.*libc.*)$/(in \/...libc...)/" | - -# Anonymise paths like "xxx (../sysdeps/unix/sysv/linux/quux.c:129)" -sed "s/(\.\.\/sysdeps\/unix\/sysv\/linux\/.*\.c:[0-9]*)$/(in \/...libc...)/" | - -# Anonymise paths like "__libc_start_main (../foo/bar/libc-quux.c:129)" -sed "s/__libc_\(.*\) (.*)$/__libc_\1 (...libc...)/" | - sed s/"^Open AF_UNIX socket [0-9]*: /Open AF_UNIX socket .: /" | sed s/"^Open \(AF_UNIX socket\|file descriptor\) [0-9]*: \/dev\/null/Open \\1 .: \/dev\/null/" | sed s/"^Open \(AF_UNIX socket\|file descriptor\) [0-9]*: \/tmp\/\(sock\|data1\|data2\|file\)\.[0-9]*/Open \\1 .: \/tmp\/\\2/" | diff --git a/corecheck/tests/pth_rwlock.stderr.exp b/corecheck/tests/pth_rwlock.stderr.exp index 67c7b3864f..d18786f806 100644 --- a/corecheck/tests/pth_rwlock.stderr.exp +++ b/corecheck/tests/pth_rwlock.stderr.exp @@ -1,12 +1,3 @@ -warning: Valgrind's pthread_cond_destroy is incomplete - (it doesn't check if the cond is waited on) - your program may misbehave as a result -warning: Valgrind's pthread_cond_destroy is incomplete - (it doesn't check if the cond is waited on) - your program may misbehave as a result -warning: Valgrind's pthread_cond_destroy is incomplete - (it doesn't check if the cond is waited on) - your program may misbehave as a result ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) diff --git a/corecheck/tests/sigkill.c b/corecheck/tests/sigkill.c index 4fefed3779..8a757f90b7 100644 --- a/corecheck/tests/sigkill.c +++ b/corecheck/tests/sigkill.c @@ -19,10 +19,10 @@ main (void) int i; int rc; for (i = 1; i <= 65; i++) { - // skip signals 32 and 33: some systems say "warning, ignored attempt + // skip signals 63 and 64: some systems say "warning, ignored attempt // to catch 32 because it's used internally by Valgrind", others say // "invalid argument". - if (i == 32 || i == 33) { + if (i == 63 || i == 64) { continue; } // different systems sa.sa_flags = 0; diff --git a/corecheck/tests/sigkill.stderr.exp b/corecheck/tests/sigkill.stderr.exp index 839d09bdb9..b71799ddac 100644 --- a/corecheck/tests/sigkill.stderr.exp +++ b/corecheck/tests/sigkill.stderr.exp @@ -96,6 +96,12 @@ getting signal 30: Success setting signal 31: Success getting signal 31: Success +setting signal 32: Success +getting signal 32: Success + +setting signal 33: Success +getting signal 33: Success + setting signal 34: Success getting signal 34: Success @@ -183,12 +189,6 @@ getting signal 61: Success setting signal 62: Success getting signal 62: Success -setting signal 63: Success -getting signal 63: Success - -setting signal 64: Success -getting signal 64: Success - setting signal 65: Warning: bad signal number 65 in sigaction() Invalid argument getting signal 65: Warning: bad signal number 65 in sigaction() diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am index 06b46f608b..be3d5da25b 100644 --- a/coregrind/Makefile.am +++ b/coregrind/Makefile.am @@ -10,7 +10,7 @@ DIST_SUBDIRS = $(VG_ARCH_ALL) $(VG_OS_ALL) $(VG_PLATFORM_ALL) demangle . AM_CPPFLAGS += -DVG_LIBDIR="\"$(valdir)"\" -I$(srcdir)/demangle \ -DKICKSTART_BASE=@KICKSTART_BASE@ \ -DVG_PLATFORM="\"$(VG_PLATFORM)"\" -AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -g @ARCH_CORE_AM_CFLAGS@ +AM_CFLAGS = $(WERROR) -Wmissing-prototypes -Winline -Wall -Wshadow -O -g @ARCH_CORE_AM_CFLAGS@ AM_CFLAGS += -fno-omit-frame-pointer default.supp: $(SUPP_FILES) @@ -20,7 +20,6 @@ bin_PROGRAMS = \ val_PROGRAMS = \ stage2 \ - libpthread.so \ vg_inject.so noinst_LIBRARIES = lib_replace_malloc.a @@ -34,12 +33,12 @@ noinst_HEADERS = \ vg_toolint.h EXTRA_DIST = \ - vg_libpthread.vs valgrind.vs \ + valgrind.vs \ gen_toolint.pl toolfuncs.def \ - gen_intercepts.pl vg_replace_malloc.c.base vg_intercept.c.base + gen_intercepts.pl vg_replace_malloc.c.base BUILT_SOURCES = vg_toolint.c vg_toolint.h -CLEANFILES = vg_toolint.c vg_toolint.h vg_replace_malloc.c vg_intercept.c +CLEANFILES = vg_toolint.c vg_toolint.h vg_replace_malloc.c valgrind_SOURCES = \ ume.c \ @@ -67,10 +66,12 @@ stage2_SOURCES = \ vg_mylibc.c \ vg_needs.c \ vg_procselfmaps.c \ - vg_proxylwp.c \ vg_dummy_profile.c \ vg_signals.c \ vg_symtab2.c \ + vg_threadmodel.c \ + vg_pthreadmodel.c \ + vg_redir.c \ vg_dwarf.c \ vg_stabs.c \ vg_skiplist.c \ @@ -111,10 +112,6 @@ endif stage2_LDADD= $(stage2_extra) -ldl -vg_intercept.c: $(srcdir)/gen_intercepts.pl $(srcdir)/vg_intercept.c.base - rm -f $@ - $(PERL) $(srcdir)/gen_intercepts.pl < $(srcdir)/vg_intercept.c.base > $@ - vg_replace_malloc.c: $(srcdir)/gen_intercepts.pl $(srcdir)/vg_replace_malloc.c.base rm -f $@ $(PERL) $(srcdir)/gen_intercepts.pl < $(srcdir)/vg_replace_malloc.c.base > $@ @@ -132,22 +129,9 @@ vg_toolint.h: $(srcdir)/gen_toolint.pl $(srcdir)/toolfuncs.def ./Makefile $(PERL) $(srcdir)/gen_toolint.pl proto < $(srcdir)/toolfuncs.def > $@ || rm -f $@ $(PERL) $(srcdir)/gen_toolint.pl struct < $(srcdir)/toolfuncs.def >> $@ || rm -f $@ -libpthread_so_SOURCES = \ - vg_libpthread.c \ - vg_libpthread_unimp.c \ - ${VG_ARCH}/libpthread.c \ - ${VG_PLATFORM}/syscall.S -libpthread_so_DEPENDENCIES = $(srcdir)/vg_libpthread.vs -libpthread_so_CFLAGS = $(AM_CFLAGS) -fpic -fno-omit-frame-pointer -libpthread_so_LDFLAGS = -Werror -fno-omit-frame-pointer -UVG_LIBDIR \ - -shared -ldl \ - -Wl,-version-script $(srcdir)/vg_libpthread.vs \ - -Wl,-z,nodelete \ - -Wl,--soname=libpthread.so.0 - -vg_inject_so_SOURCES = \ - vg_intercept.c +vg_inject_so_SOURCES = vg_intercept.c vg_inject_so_CFLAGS = $(AM_CFLAGS) -fpic +vg_inject_so_LDADD = -ldl vg_inject_so_LDFLAGS = \ -shared \ -Wl,--soname,vg_inject.so \ @@ -156,12 +140,12 @@ vg_inject_so_LDFLAGS = \ lib_replace_malloc_a_SOURCES = vg_replace_malloc.c lib_replace_malloc_a_CFLAGS = $(AM_CFLAGS) -fpic -fno-omit-frame-pointer -MANUAL_DEPS = $(noinst_HEADERS) $(include_HEADERS) $(inplacedir)/libpthread.so.0 +MANUAL_DEPS = $(noinst_HEADERS) $(include_HEADERS) all-local: mkdir -p $(inplacedir) for i in $(val_PROGRAMS); do \ - to=$(inplacedir)/$$(echo $$i | sed 's,libpthread.so,libpthread.so.0,'); \ + to=$(inplacedir)/$$i; \ rm -f $$$to; \ ln -sf ../$(subdir)/$$i $$to; \ done diff --git a/coregrind/core.h b/coregrind/core.h index a85b67cca3..d4ef229c2f 100644 --- a/coregrind/core.h +++ b/coregrind/core.h @@ -89,9 +89,9 @@ // Ugly: this is needed by linux/core_os.h typedef struct _ThreadState ThreadState; -#include "core_os.h" // OS-specific stuff, eg. linux/core_os.h #include "core_platform.h" // platform-specific stuff, // eg. x86-linux/core_platform.h +#include "core_os.h" // OS-specific stuff, eg. linux/core_os.h #include "valgrind.h" @@ -154,24 +154,8 @@ typedef struct _ThreadState ThreadState; #define VG_SCHEDULING_QUANTUM 50000 /* Number of file descriptors that Valgrind tries to reserve for - it's own use - two per thread plues a small number of extras. */ -#define VG_N_RESERVED_FDS (VG_N_THREADS*2 + 4) - -/* Stack size for a thread. We try and check that they do not go - beyond it. */ -#define VG_PTHREAD_STACK_SIZE (1 << 20) - -/* Number of entries in each thread's cleanup stack. */ -#define VG_N_CLEANUPSTACK 16 - -/* Number of entries in each thread's fork-handler stack. */ -#define VG_N_FORKHANDLERSTACK 4 - -/* Max number of callers for context in a suppression. */ -#define VG_N_SUPP_CALLERS 4 - -/* Numer of entries in each thread's signal queue. */ -#define VG_N_SIGNALQUEUE 8 + it's own use - just a small constant. */ +#define VG_N_RESERVED_FDS (10) /* Useful macros */ /* a - alignment - must be a power of 2 */ @@ -230,12 +214,6 @@ typedef VgLogTo_Socket } VgLogTo; -/* pid of main process */ -extern Int VG_(main_pid); - -/* pgrp of process (global to all threads) */ -extern Int VG_(main_pgrp); - /* Application-visible file descriptor limits */ extern Int VG_(fd_soft_limit); extern Int VG_(fd_hard_limit); @@ -301,11 +279,12 @@ extern Bool VG_(clo_trace_syscalls); extern Bool VG_(clo_trace_signals); /* DEBUG: print symtab details? default: NO */ extern Bool VG_(clo_trace_symtab); +/* DEBUG: print redirection details? default: NO */ +extern Bool VG_(clo_trace_redir); /* DEBUG: print thread scheduling events? default: NO */ extern Bool VG_(clo_trace_sched); -/* DEBUG: print pthread (mutex etc) events? default: 0 (none), 1 - (some), 2 (all) */ -extern Int VG_(clo_trace_pthread_level); +/* DEBUG: print pthreads calls? default: NO */ +extern Bool VG_(clo_trace_pthreads); /* Display gory details for the k'th most popular error. default: Infinity. */ extern Int VG_(clo_dump_error); @@ -313,13 +292,6 @@ extern Int VG_(clo_dump_error); extern Int VG_(clo_backtrace_size); /* Engage miscellaneous weird hacks needed for some progs. */ extern Char* VG_(clo_weird_hacks); -/* How often we should poll for signals, assuming we need to poll for - signals. */ -extern Int VG_(clo_signal_polltime); - -/* Low latency syscalls and signals */ -extern Bool VG_(clo_lowlat_syscalls); -extern Bool VG_(clo_lowlat_signals); /* Track open file descriptors? */ extern Bool VG_(clo_track_fds); @@ -337,13 +309,20 @@ extern Bool VG_(clo_show_below_main); /* Test each client pointer dereference to check it's within the client address space bounds */ extern Bool VG_(clo_pointercheck); +/* Model the pthread library */ +extern Bool VG_(clo_model_pthreads); /* HACK: Use hacked version of clone for Quadrics Elan3 drivers */ extern Bool VG_(clo_support_elan3); /* Set up the libc freeres wrapper */ -extern void VG_(intercept_libc_freeres_wrapper)(Addr); +extern void VGA_(intercept_libc_freeres_wrapper)(Addr); + +// Clean up the client by calling before the final reports +extern void VGA_(final_tidyup)(ThreadId tid); +// Arch-specific client requests +extern Bool VGA_(client_requests)(ThreadId tid, UWord *args); /* --------------------------------------------------------------------- Profiling stuff @@ -486,37 +465,16 @@ extern Bool VG_(is_empty_arena) ( ArenaId aid ); #define VG_USERREQ__MALLOC 0x2001 #define VG_USERREQ__FREE 0x2002 -/* (Fn, Arg): Create a new thread and run Fn applied to Arg in it. Fn - MUST NOT return -- ever. Eventually it will do either __QUIT or - __WAIT_JOINER. */ +/* Obsolete pthread-related requests */ #define VG_USERREQ__APPLY_IN_NEW_THREAD 0x3001 - -/* ( no-args ): calling thread disappears from the system forever. - Reclaim resources. */ #define VG_USERREQ__QUIT 0x3002 - -/* ( void* ): calling thread waits for joiner and returns the void* to - it. */ #define VG_USERREQ__WAIT_JOINER 0x3003 - -/* ( ThreadId, void** ): wait to join a thread. */ #define VG_USERREQ__PTHREAD_JOIN 0x3004 - -/* Set cancellation state and type for this thread. */ #define VG_USERREQ__SET_CANCELSTATE 0x3005 #define VG_USERREQ__SET_CANCELTYPE 0x3006 - -/* ( no-args ): Test if we are at a cancellation point. */ #define VG_USERREQ__TESTCANCEL 0x3007 - -/* ( ThreadId, &thread_exit_wrapper is the only allowable arg ): call - with this arg to indicate that a cancel is now pending for the - specified thread. */ #define VG_USERREQ__SET_CANCELPEND 0x3008 - -/* Set/get detach state for this thread. */ #define VG_USERREQ__SET_OR_GET_DETACH 0x3009 - #define VG_USERREQ__PTHREAD_GET_THREADID 0x300A #define VG_USERREQ__PTHREAD_MUTEX_LOCK 0x300B #define VG_USERREQ__PTHREAD_MUTEX_TIMEDLOCK 0x300C @@ -530,56 +488,39 @@ extern Bool VG_(is_empty_arena) ( ArenaId aid ); #define VG_USERREQ__PTHREAD_KEY_DELETE 0x3014 #define VG_USERREQ__PTHREAD_SETSPECIFIC_PTR 0x3015 #define VG_USERREQ__PTHREAD_GETSPECIFIC_PTR 0x3016 -#define VG_USERREQ__READ_MILLISECOND_TIMER 0x3017 #define VG_USERREQ__PTHREAD_SIGMASK 0x3018 -#define VG_USERREQ__SIGWAIT 0x3019 /* unused */ +#define VG_USERREQ__SIGWAIT 0x3019 #define VG_USERREQ__PTHREAD_KILL 0x301A #define VG_USERREQ__PTHREAD_YIELD 0x301B #define VG_USERREQ__PTHREAD_KEY_VALIDATE 0x301C - #define VG_USERREQ__CLEANUP_PUSH 0x3020 #define VG_USERREQ__CLEANUP_POP 0x3021 #define VG_USERREQ__GET_KEY_D_AND_S 0x3022 - #define VG_USERREQ__NUKE_OTHER_THREADS 0x3023 - -/* Ask how many signal handler returns have happened to this - thread. */ -#define VG_USERREQ__GET_N_SIGS_RETURNED 0x3024 /* unused */ - -/* Get/set entries for a thread's pthread_atfork stack. */ +#define VG_USERREQ__GET_N_SIGS_RETURNED 0x3024 #define VG_USERREQ__SET_FHSTACK_USED 0x3025 #define VG_USERREQ__GET_FHSTACK_USED 0x3026 #define VG_USERREQ__SET_FHSTACK_ENTRY 0x3027 #define VG_USERREQ__GET_FHSTACK_ENTRY 0x3028 - -/* Denote the finish of __libc_freeres_wrapper(). */ -#define VG_USERREQ__LIBC_FREERES_DONE 0x3029 - -/* Allocate RT signals */ #define VG_USERREQ__GET_SIGRT_MIN 0x302B #define VG_USERREQ__GET_SIGRT_MAX 0x302C #define VG_USERREQ__ALLOC_RTSIG 0x302D - -/* Hook for replace_malloc.o to get malloc functions */ #define VG_USERREQ__GET_MALLOCFUNCS 0x3030 - -/* Get stack information for a thread. */ #define VG_USERREQ__GET_STACK_INFO 0x3033 - -/* Cosmetic ... */ #define VG_USERREQ__GET_PTHREAD_TRACE_LEVEL 0x3101 -/* Log a pthread error from client-space. Cosmetic. */ #define VG_USERREQ__PTHREAD_ERROR 0x3102 + + +#define VG_USERREQ__READ_MILLISECOND_TIMER 0x3017 + /* Internal equivalent of VALGRIND_PRINTF . */ #define VG_USERREQ__INTERNAL_PRINTF 0x3103 /* Internal equivalent of VALGRIND_PRINTF_BACKTRACE . */ #define VG_USERREQ__INTERNAL_PRINTF_BACKTRACE 0x3104 -/* -In core_asm.h: -#define VG_USERREQ__SIGNAL_RETURNS 0x4001 -*/ +/* Denote the finish of __libc_freeres_wrapper(). + A synonym for exit. */ +#define VG_USERREQ__LIBC_FREERES_DONE 0x3029 #define VG_INTERCEPT_PREFIX "_vgi__" #define VG_INTERCEPT_PREFIX_LEN 6 @@ -618,110 +559,41 @@ struct vg_mallocfunc_info { extern Bool VG_(tl_malloc_called_by_scheduler); -/* --------------------------------------------------------------------- - Exports of vg_libpthread.c - ------------------------------------------------------------------ */ - -/* Replacements for pthread types, shared between vg_libpthread.c and - vg_scheduler.c. See comment in vg_libpthread.c above the other - vg_pthread_*_t types for a description of how these are used. */ - -struct _vg_pthread_fastlock -{ - long int __vg_status; /* "Free" or "taken" or head of waiting list */ - int __vg_spinlock; /* Used by compare_and_swap emulation. Also, - adaptive SMP lock stores spin count here. */ -}; - -typedef struct -{ - int __vg_m_reserved; /* Reserved for future use */ - int __vg_m_count; /* Depth of recursive locking */ - /*_pthread_descr*/ void* __vg_m_owner; /* Owner thread (if recursive or errcheck) */ - int __vg_m_kind; /* Mutex kind: fast, recursive or errcheck */ - struct _vg_pthread_fastlock __vg_m_lock; /* Underlying fast lock */ -} vg_pthread_mutex_t; - -typedef struct -{ - struct _vg_pthread_fastlock __vg_c_lock; /* Protect against concurrent access */ - /*_pthread_descr*/ void* __vg_c_waiting; /* Threads waiting on this condition */ - - // Nb: the following padding removed because it was missing from an - // earlier glibc, so the size test in the CONVERT macro was failing. - // --njn - - // Padding ensures the size is 48 bytes - /*char __vg_padding[48 - sizeof(struct _vg_pthread_fastlock) - - sizeof(void*) - sizeof(long long)]; - long long __vg_align;*/ -} vg_pthread_cond_t; - /* --------------------------------------------------------------------- Exports of vg_scheduler.c ------------------------------------------------------------------ */ +/* + Thread state machine: + + Empty -> Init -> Runnable <=> WaitSys/Yielding + ^ | + \---- Zombie -----/ + */ typedef enum ThreadStatus { VgTs_Empty, /* this slot is not in use */ - VgTs_Runnable, /* waiting to be scheduled */ - VgTs_WaitJoiner, /* waiting for someone to do join on me */ - VgTs_WaitJoinee, /* waiting for the thread I did join on */ - VgTs_WaitMX, /* waiting on a mutex */ - VgTs_WaitCV, /* waiting on a condition variable */ + VgTs_Init, /* just allocated */ + VgTs_Runnable, /* ready to run */ VgTs_WaitSys, /* waiting for a syscall to complete */ - VgTs_Sleeping, /* sleeping for a while */ + VgTs_Yielding, /* temporarily yielding the CPU */ + VgTs_Zombie, /* transient state just before exiting */ } ThreadStatus; +/* Return codes from the scheduler. */ typedef - enum CleanupType { - VgCt_None, /* this cleanup entry is not initialised */ - VgCt_Function, /* an old-style function pointer cleanup */ - VgCt_Longjmp /* a new-style longjmp based cleanup */ - } - CleanupType; - -/* Information on a thread's stack. */ -typedef - struct { - Addr base; - UInt size; - UInt guardsize; - } - StackInfo; - -/* An entry in a threads's cleanup stack. */ -typedef - struct { - CleanupType type; - union { - struct { - void (*fn)(void*); - void* arg; - } function; - struct { - void *ub; - int ctype; - } longjmp; - } data; - } - CleanupEntry; - -/* An entry in a thread's fork-handler stack. */ -typedef - struct { - void (*prepare)(void); - void (*parent)(void); - void (*child)(void); + enum { + VgSrc_None, /* not exiting yet */ + VgSrc_ExitSyscall, /* client called exit(). This is the normal + route out. */ + VgSrc_FatalSig /* Killed by the default action of a fatal + signal */ } - ForkHandlerEntry; - -typedef struct ProxyLWP ProxyLWP; + VgSchedReturnCode; -//typedef - struct _ThreadState { +struct _ThreadState { /* ThreadId == 0 (and hence vg_threads[0]) is NEVER USED. The thread identity is simply the index in vg_threads[]. ThreadId == 1 is the root thread and has the special property @@ -731,103 +603,45 @@ typedef struct ProxyLWP ProxyLWP; ALWAYS == the index in vg_threads[]. */ ThreadId tid; - /* Current scheduling status. - - Complications: whenever this is set to VgTs_WaitMX, you - should also set .m_edx to whatever the required return value - is for pthread_mutex_lock / pthread_cond_timedwait for when - the mutex finally gets unblocked. */ + /* Current scheduling status. */ ThreadStatus status; - /* When .status == WaitMX, points to the mutex I am waiting for. - When .status == WaitCV, points to the mutex associated with - the condition variable indicated by the .associated_cv field. - In all other cases, should be NULL. */ - vg_pthread_mutex_t* associated_mx; - - /* When .status == WaitCV, points to the condition variable I am - waiting for. In all other cases, should be NULL. */ - void* /*pthread_cond_t* */ associated_cv; - - /* If VgTs_Sleeping, this is when we should wake up, measured in - milliseconds as supplied by VG_(read_millisecond_timer). + /* This is set if the thread is in the process of exiting for any + reason. The precise details of the exit are in the OS-specific + state. */ + VgSchedReturnCode exitreason; - If VgTs_WaitCV, this indicates the time at which - pthread_cond_timedwait should wake up. If == 0xFFFFFFFF, - this means infinitely far in the future, viz, - pthread_cond_wait. */ - UInt awaken_at; - - /* If VgTs_WaitJoiner, return value, as generated by joinees. */ - void* joinee_retval; - - /* If VgTs_WaitJoinee, place to copy the return value to, and - the identity of the thread we're waiting for. */ - void** joiner_thread_return; - ThreadId joiner_jee_tid; - - /* If VgTs_WaitSys, this is the syscall we're currently running */ - Int syscallno; - - /* If VgTs_WaitSys, this is the syscall flags */ - UInt sys_flags; - - /* Details about this thread's proxy LWP */ - ProxyLWP *proxy; - - /* Whether or not detached. */ - Bool detached; - - /* Cancelability state and type. */ - Bool cancel_st; /* False==PTH_CANCEL_DISABLE; True==.._ENABLE */ - Bool cancel_ty; /* False==PTH_CANC_ASYNCH; True==..._DEFERRED */ - - /* Pointer to fn to call to do cancellation. Indicates whether - or not cancellation is pending. If NULL, not pending. Else - should be &thread_exit_wrapper(), indicating that - cancallation is pending. */ - void (*cancel_pend)(void*); - - /* The cleanup stack. */ - Int custack_used; - CleanupEntry custack[VG_N_CLEANUPSTACK]; - - /* A pointer to the thread's-specific-data. This is handled almost - entirely from vg_libpthread.c. We just provide hooks to get and - set this ptr. This is either NULL, indicating the thread has - read/written none of its specifics so far, OR points to a - void*[VG_N_THREAD_KEYS], allocated and deallocated in - vg_libpthread.c. */ - void** specifics_ptr; + /* Architecture-specific thread state. */ + ThreadArchState arch; /* This thread's blocked-signals mask. Semantics is that for a signal to be delivered to this thread, the signal must not be blocked by this signal mask. If more than one thread accepts a signal, then it will be delivered to one at random. If all threads block the signal, it will remain pending until either a - thread unblocks it or someone uses sigwaitsig/sigtimedwait. - - sig_mask reflects what the client told us its signal mask should - be, but isn't necessarily the current signal mask of the proxy - LWP: it may have more signals blocked because of signal - handling, or it may be different because of sigsuspend. - */ + thread unblocks it or someone uses sigwaitsig/sigtimedwait. */ vki_sigset_t sig_mask; - /* Effective signal mask. This is the mask which currently - applies; it may be different from sig_mask while a signal - handler is running. - */ - vki_sigset_t eff_sig_mask; - - /* Signal queue. This is used when the kernel doesn't route - signals properly in order to remember the signal information - while we are routing the signal. It is a circular queue with - insertions performed at the head and removals at the tail. - */ - vki_siginfo_t sigqueue[VG_N_SIGNALQUEUE]; - Int sigqueue_head; - Int sigqueue_tail; + /* tmp_sig_mask is usually the same as sig_mask, and is kept in + sync whenever sig_mask is changed. The only time they have + different values is during the execution of a sigsuspend, where + tmp_sig_mask is the temporary mask which sigsuspend installs. + It is only consulted to compute the signal mask applied to a + signal handler. */ + vki_sigset_t tmp_sig_mask; + + /* A little signal queue for signals we can't get the kernel to + queue for us. This is only allocated as needed, since it should + be rare. */ + struct SigQueue *sig_queue; + + /* Syscall the Thread is currently running; -1 if none. Should only + be set while Thread is in VgTs_WaitSys. */ + Int syscallno; + + /* A value the Tool wants to pass from its pre-syscall to its + post-syscall function. */ + void *tool_pre_syscall_value; /* Stacks. When a thread slot is freed, we don't deallocate its stack; we just leave it lying around for the next use of the @@ -848,10 +662,6 @@ typedef struct ProxyLWP ProxyLWP; */ Addr stack_base; - /* The allocated size of this thread's stack's guard area (permanently - zero if this is ThreadId == 0, since we didn't allocate its stack) */ - UInt stack_guard_size; - /* Address of the highest legitimate word in this stack. This is used for error messages only -- not critical for execution correctness. Is is set for all stacks, specifically including @@ -861,61 +671,95 @@ typedef struct ProxyLWP ProxyLWP; /* Alternate signal stack */ vki_stack_t altstack; - /* Architecture-specific thread state */ - ThreadArchState arch; + /* OS-specific thread state */ + os_thread_t os_state; /* Used in the syscall handlers. Set to True to indicate that the PRE routine for a syscall has set the syscall result already and so the syscall does not need to be handed to the kernel. */ Bool syscall_result_set; + + /* Per-thread jmp_buf to resume scheduler after a signal */ + Bool sched_jmpbuf_valid; + jmp_buf sched_jmpbuf; + + /* Info about the signal we just got */ + vki_siginfo_t siginfo; }; //ThreadState; - /* The thread table. */ extern ThreadState VG_(threads)[VG_N_THREADS]; +/* Allocate a new ThreadState */ +extern ThreadId VG_(alloc_ThreadState)(void); + +/* A thread exits. tid must currently be running. */ +extern void VG_(exit_thread)(ThreadId tid); + +/* Kill a thread. This interrupts whatever a thread is doing, and + makes it exit ASAP. This does not set the exitreason or + exitcode. */ +extern void VG_(kill_thread)(ThreadId tid); + /* Check that tid is in range and denotes a non-Empty thread. */ extern Bool VG_(is_valid_tid) ( ThreadId tid ); /* Get the ThreadState for a particular thread */ extern ThreadState *VG_(get_ThreadState)(ThreadId tid); +/* Given an LWP id (ie, real kernel thread id), find the corresponding + ThreadId */ +extern ThreadId VG_(get_lwp_tid)(Int lwpid); + +/* Returns true if a thread is currently running (ie, has the CPU lock) */ +extern Bool VG_(is_running_thread)(ThreadId tid); + +/* Returns true if the thread is in the process of exiting */ +extern Bool VG_(is_exiting)(ThreadId tid); + +/* Return the number of non-dead Threads */ +extern Int VG_(count_living_threads)(void); + /* Nuke all threads except tid. */ -extern void VG_(nuke_all_threads_except) ( ThreadId me ); +extern void VG_(nuke_all_threads_except) ( ThreadId me, VgSchedReturnCode reason ); -/* Give a hint to the scheduler that it may be a good time to find a - new runnable thread. If prefer_sched != VG_INVALID_THREADID, then - try to schedule that thread. -*/ -extern void VG_(need_resched) ( ThreadId prefer_sched ); +/* Make a thread the running thread. The thread must previously been + sleeping, and not holding the CPU semaphore. This will set the + thread state to VgTs_Runnable, and the thread will attempt to take + the CPU semaphore. By the time it returns, tid will be the running + thread. */ +extern void VG_(set_running) ( ThreadId tid ); -/* Return codes from the scheduler. */ -typedef - enum { - VgSrc_Deadlock, /* no runnable threads and no prospect of any - even if we wait for a long time */ - VgSrc_ExitSyscall, /* client called exit(). This is the normal - route out. */ - VgSrc_FatalSig /* Killed by the default action of a fatal - signal */ - } - VgSchedReturnCode; +/* Set a thread into a sleeping state. Before the call, the thread + must be runnable, and holding the CPU semaphore. When this call + returns, the thread will be set to the specified sleeping state, + and will not be holding the CPU semaphore. Note that another + thread could be running by the time this call returns, so the + caller must be careful not to touch any shared state. It is also + the caller's responsibility to actually block until the thread is + ready to run again. */ +extern void VG_(set_sleeping) ( ThreadId tid, ThreadStatus state ); + +/* Yield the CPU for a while */ +extern void VG_(vg_yield)(void); +// The scheduler. +extern VgSchedReturnCode VG_(scheduler) ( ThreadId tid ); -// The scheduler. 'fatal_sigNo' is only set if VgSrc_FatalSig is returned. -extern VgSchedReturnCode VG_(scheduler) - ( Int* exit_code, ThreadId* last_run_thread, Int* fatal_sigNo ); +// Do everything which needs doing before the process finally ends, +// like printing reports, etc +extern void VG_(shutdown_actions)(ThreadId tid); extern void VG_(scheduler_init) ( void ); extern void VG_(pp_sched_status) ( void ); // Longjmp back to the scheduler and thus enter the sighandler immediately. -extern void VG_(resume_scheduler) ( Int sigNo, vki_siginfo_t *info ); +extern void VG_(resume_scheduler) ( ThreadId tid ); -// Longjmp, ending the scheduler, when a fatal signal occurs in the client. -extern void VG_(scheduler_handle_fatal_signal)( Int sigNo ); +/* If true, a fault is Valgrind-internal (ie, a bug) */ +extern Bool VG_(my_fault); /* The red-zone size which we put at the bottom (highest address) of thread stacks, for paranoia reasons. This can be arbitrary, and @@ -946,32 +790,34 @@ extern void VG_(scheduler_handle_fatal_signal)( Int sigNo ); SET_THREAD_REG(zztid, zzval, PTHREQ_RET, post_reg_write, \ Vg_CorePThread, zztid, O_PTHREQ_RET, sizeof(UWord)) - /* --------------------------------------------------------------------- Exports of vg_signals.c ------------------------------------------------------------------ */ -extern Bool VG_(do_signal_routing); /* whether scheduler LWP has to route signals */ +/* Set the standard set of blocked signals, used wheneever we're not + running a client syscall. */ +extern void VG_(block_signals)(ThreadId tid); -/* RT signal allocation */ -extern Int VG_(sig_rtmin); -extern Int VG_(sig_rtmax); -extern Int VG_(sig_alloc_rtsig) ( Int high ); +/* Highest signal the kernel will let us use */ +extern Int VG_(max_signal); extern void VG_(sigstartup_actions) ( void ); -extern void VG_(deliver_signal) ( ThreadId tid, const vki_siginfo_t *, Bool async ); -extern void VG_(unblock_host_signal) ( Int sigNo ); +/* Modify a thread's state so that when it next runs it will be + running in the signal handler (or doing the default action if there + is none). */ +extern void VG_(deliver_signal) ( ThreadId tid, const vki_siginfo_t * ); extern Bool VG_(is_sig_ign) ( Int sigNo ); -/* Route pending signals from the scheduler LWP to the appropriate - thread LWP. */ -extern void VG_(route_signals) ( void ); +/* Poll a thread's set of pending signals, and update the Thread's context to deliver one */ +extern void VG_(poll_signals) ( ThreadId ); /* Fake system calls for signal handling. */ extern void VG_(do_sys_sigaltstack) ( ThreadId tid ); -extern void VG_(do_sys_sigaction) ( ThreadId tid ); +extern Int VG_(do_sys_sigaction) ( Int signo, + const struct vki_sigaction *new_act, + struct vki_sigaction *old_act ); extern void VG_(do_sys_sigprocmask) ( ThreadId tid, Int how, vki_sigset_t* set, vki_sigset_t* oldset ); @@ -979,10 +825,6 @@ extern void VG_(do_pthread_sigmask_SCSS_upd) ( ThreadId tid, Int how, vki_sigset_t* set, vki_sigset_t* oldset ); -/* Modify the current thread's state once we have detected it is - returning from a signal handler. */ -extern Bool VG_(signal_returns) ( ThreadId tid ); - /* Handy utilities to block/restore all host signals. */ extern void VG_(block_all_host_signals) ( /* OUT */ vki_sigset_t* saved_mask ); @@ -1001,6 +843,21 @@ extern void VG_(synth_sigill) (ThreadId tid, Addr addr); extern void VG_(get_sigstack_bounds)( Addr* low, Addr* high ); +/* Extend the stack to cover addr, if possible */ +extern Bool VG_(extend_stack)(Addr addr, UInt maxsize); + +/* Returns True if the signal is OK for the client to use */ +extern Bool VG_(client_signal_OK)(Int sigNo); + +/* Forces the client's signal handler to SIG_DFL - generally just + before using that signal to kill the process. */ +extern void VG_(set_default_handler)(Int sig); + +/* Adjust a client's signal mask to match our internal requirements */ +extern void VG_(sanitize_client_sigmask)(ThreadId tid, vki_sigset_t *mask); + +/* Wait until a thread-related predicate is true */ +extern void VG_(wait_for_threadstate)(Bool (*pred)(void *), void *arg); /* --------------------------------------------------------------------- Exports of vg_mylibc.c @@ -1053,7 +910,7 @@ extern Char **VG_(env_setenv) ( Char ***envp, const Char* varname, extern void VG_(env_unsetenv) ( Char **env, const Char *varname ); extern void VG_(env_remove_valgrind_env_stuff) ( Char** env ); - +extern void VG_(nanosleep)(struct vki_timespec *); /* --------------------------------------------------------------------- Exports of vg_message.c ------------------------------------------------------------------ */ @@ -1063,10 +920,9 @@ extern void VG_(env_remove_valgrind_env_stuff) ( Char** env ); extern void VG_(send_bytes_to_logging_sink) ( Char* msg, Int nbytes ); // Functions for printing from code within Valgrind, but which runs on the -// sim'd CPU. Defined here because needed for vg_libpthread.c, -// vg_replace_malloc.c, plus the rest of the core. The weak attribute -// ensures the multiple definitions are not a problem. They must be functions -// rather than macros so that va_list can be used. +// sim'd CPU. Defined here because needed for vg_replace_malloc.c. The +// weak attribute ensures the multiple definitions are not a problem. They +// must be functions rather than macros so that va_list can be used. __attribute__((weak)) int @@ -1101,6 +957,7 @@ VALGRIND_INTERNAL_PRINTF_BACKTRACE(char *format, ...) extern void VG_(demangle) ( Char* orig, Char* result, Int result_size ); +extern void VG_(reloc_abs_jump) ( UChar *jmp ); /* --------------------------------------------------------------------- Exports of vg_translate.c @@ -1142,9 +999,14 @@ extern ExeContext* VG_(get_ExeContext2) ( Addr ip, Addr fp, Exports of vg_errcontext.c. ------------------------------------------------------------------ */ -extern void VG_(load_suppressions) ( void ); +typedef + enum { + ThreadErr = -1, // Thread error + MutexErr = -2, // Mutex error + } + CoreErrorKind; -extern void VG_(record_pthread_error) ( ThreadId tid, Char* msg ); +extern void VG_(load_suppressions) ( void ); extern void VG_(show_all_errors) ( void ); @@ -1157,16 +1019,10 @@ extern UInt VG_(get_n_errs_found) ( void ); Exports of vg_procselfmaps.c ------------------------------------------------------------------ */ -/* Reads /proc/self/maps into a static buffer which can be parsed by - VG_(parse_procselfmaps)(). */ -extern void VG_(read_procselfmaps) ( void ); - -/* Parses /proc/self/maps, calling `record_mapping' for each entry. If - `read_from_file' is True, /proc/self/maps is read directly, otherwise - it's read from the buffer filled by VG_(read_procselfmaps_contents)(). */ +/* Parses /proc/self/maps, calling `record_mapping' for each entry. */ extern void VG_(parse_procselfmaps) ( - void (*record_mapping)( Addr addr, SizeT len, Char rr, Char ww, Char xx, + void (*record_mapping)( Addr addr, SizeT len, UInt prot, UInt dev, UInt ino, ULong foff, const UChar *filename ) ); @@ -1176,6 +1032,7 @@ void VG_(parse_procselfmaps) ( ------------------------------------------------------------------ */ typedef struct _Segment Segment; +typedef struct _CodeRedirect CodeRedirect; extern Bool VG_(is_object_file) ( const void *hdr ); extern void VG_(mini_stack_dump) ( Addr ips[], UInt n_ips ); @@ -1185,12 +1042,46 @@ extern void VG_(symtab_decref) ( SegInfo *, Addr a ); extern Bool VG_(get_fnname_nodemangle)( Addr a, Char* fnname, Int n_fnname ); +extern Addr VG_(reverse_search_one_symtab) ( const SegInfo* si, const Char* name ); + /* Set up some default redirects */ extern void VG_(setup_code_redirect_table) ( void ); +extern Bool VG_(resolve_redir_allsegs)(CodeRedirect *redir); + +/* --------------------------------------------------------------------- + Exports of vg_redir.c + ------------------------------------------------------------------ */ /* Redirection machinery */ extern Addr VG_(code_redirect) ( Addr orig ); +extern void VG_(add_redirect_addr)(const Char *from_lib, const Char *from_sym, + Addr to_addr); +extern void VG_(resolve_seg_redirs)(SegInfo *si); +extern Bool VG_(resolve_redir)(CodeRedirect *redir, const SegInfo *si); + +/* Wrapping machinery */ +enum return_type { + RT_RETURN, + RT_LONGJMP, + RT_EXIT, +}; + +typedef struct _FuncWrapper FuncWrapper; +struct _FuncWrapper { + void *(*before)(va_list args); + void (*after) (void *nonce, enum return_type, Word retval); +}; + +extern void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper); +extern const FuncWrapper *VG_(is_wrapped)(Addr eip); +extern Bool VG_(is_wrapper_return)(Addr eip); + +/* Primary interface for adding wrappers for client-side functions. */ +extern CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym, + const FuncWrapper *wrapper); + +extern Bool VG_(is_resolved)(const CodeRedirect *redir); /* --------------------------------------------------------------------- Exports of vg_main.c @@ -1228,6 +1119,12 @@ extern Int VG_(clexecfd); Char* VG_(build_child_VALGRINDCLO) ( Char* exename ); Char* VG_(build_child_exename) ( void ); +/* The master thread the one which will be responsible for mopping + everything up at exit. Normally it is tid 1, since that's the + first thread created, but it may be something else after a + fork(). */ +extern ThreadId VG_(master_tid); + /* Called when some unhandleable client behaviour is detected. Prints a msg and aborts. */ extern void VG_(unimplemented) ( Char* msg ) @@ -1274,6 +1171,7 @@ extern VexSubArch VG_(vex_subarch); #define SF_CORE (1 << 12) // allocated by core on behalf of the client #define SF_VALGRIND (1 << 13) // a valgrind-internal mapping - not in client #define SF_CODE (1 << 14) // segment contains cached code +#define SF_DEVICE (1 << 15) // device mapping; avoid careless touching struct _Segment { UInt prot; // VKI_PROT_* @@ -1321,42 +1219,22 @@ extern Segment *VG_(find_segment_above_mapped)(Addr a); extern Bool VG_(seg_contains)(const Segment *s, Addr ptr, SizeT size); extern Bool VG_(seg_overlaps)(const Segment *s, Addr ptr, SizeT size); -extern void VG_(pad_address_space) (void); -extern void VG_(unpad_address_space)(void); +extern Segment *VG_(split_segment)(Addr a); + +extern void VG_(pad_address_space) (Addr start); +extern void VG_(unpad_address_space)(Addr start); extern REGPARM(2) void VG_(unknown_SP_update) ( Addr old_SP, Addr new_SP ); -/* --------------------------------------------------------------------- - Exports of vg_proxylwp.c - ------------------------------------------------------------------ */ +///* Search /proc/self/maps for changes which aren't reflected in the +// segment list */ +//extern void VG_(sync_segments)(UInt flags); -/* Issue a syscall for thread tid */ -extern Int VG_(sys_issue)(ThreadId tid); - -extern void VG_(proxy_init) ( void ); -extern void VG_(proxy_create) ( ThreadId tid ); -extern void VG_(proxy_delete) ( ThreadId tid, Bool force ); -extern void VG_(proxy_results) ( void ); -extern void VG_(proxy_sendsig) ( ThreadId fromTid, ThreadId toTid, Int signo ); -extern void VG_(proxy_setsigmask)(ThreadId tid); -extern void VG_(proxy_sigack) ( ThreadId tid, const vki_sigset_t *); -extern void VG_(proxy_abort_syscall) ( ThreadId tid ); -extern void VG_(proxy_waitsig) ( void ); -extern void VG_(proxy_wait_sys) (ThreadId tid, Bool restart); - -extern void VG_(proxy_shutdown) ( void ); // shut down the syscall workers -extern Int VG_(proxy_resfd) ( void ); // FD something can select on to know - // a syscall finished - -/* Sanity-check the whole proxy-LWP machinery */ -void VG_(sanity_check_proxy)(void); - -/* Send a signal from a thread's proxy to the thread. This longjmps - back into the proxy's main loop, so it doesn't return. */ -__attribute__ ((__noreturn__)) -extern void VG_(proxy_handlesig)( const vki_siginfo_t *siginfo, - Addr ip, Int sysnum ); +/* Return string for prot */ +extern const HChar *VG_(prot_str)(UInt prot); + +//extern void VG_(print_shadow_stats)(); /* --------------------------------------------------------------------- Exports of vg_syscalls.c @@ -1365,8 +1243,15 @@ extern void VG_(proxy_handlesig)( const vki_siginfo_t *siginfo, extern HChar* VG_(resolve_filename_nodup)(Int fd); extern HChar* VG_(resolve_filename)(Int fd); -extern Bool VG_(pre_syscall) ( ThreadId tid ); -extern void VG_(post_syscall)( ThreadId tid, Bool restart ); +/* Simple Valgrind-internal atfork mechanism */ +extern void VG_(do_atfork_pre) (ThreadId tid); +extern void VG_(do_atfork_parent)(ThreadId tid); +extern void VG_(do_atfork_child) (ThreadId tid); + + +extern void VG_(client_syscall) ( ThreadId tid ); + +extern void VG_(post_syscall) ( ThreadId tid ); extern Bool VG_(is_kerror) ( Word res ); @@ -1389,10 +1274,11 @@ Bool VG_(fd_allowed)(Int fd, const Char *syscallname, ThreadId tid, Bool soft); void VG_(record_fd_open)(ThreadId tid, Int fd, char *pathname); // Flags describing syscall wrappers -#define Special (1 << 0) -#define MayBlock (1 << 1) -#define NBRunInLWP (1 << 2) // non-blocking, but must run in LWP context -#define PostOnFail (1 << 3) +#define Special (1 << 0) /* handled specially */ +#define MayBlock (1 << 1) /* may block */ +#define PostOnFail (1 << 2) /* call POST() function on failure */ +#define PadAddr (1 << 3) /* pad+unpad address space around syscall */ +#define Done (1 << 4) /* used if a PRE() did the syscall */ // Templates for generating the PRE and POST macros. For ones that must be // publically visible, use an empty 'qual', 'prefix' should start with @@ -1509,6 +1395,7 @@ GEN_SYSCALL_WRAPPER(sys_mlockall); GEN_SYSCALL_WRAPPER(sys_munlockall); GEN_SYSCALL_WRAPPER(sys_sched_setparam); GEN_SYSCALL_WRAPPER(sys_sched_getparam); +GEN_SYSCALL_WRAPPER(sys_sched_rr_get_interval); GEN_SYSCALL_WRAPPER(sys_sched_setscheduler); GEN_SYSCALL_WRAPPER(sys_sched_getscheduler); GEN_SYSCALL_WRAPPER(sys_sched_yield); @@ -1533,6 +1420,7 @@ GEN_SYSCALL_WRAPPER(sys_timer_delete); GEN_SYSCALL_WRAPPER(sys_clock_settime); GEN_SYSCALL_WRAPPER(sys_clock_gettime); GEN_SYSCALL_WRAPPER(sys_clock_getres); +GEN_SYSCALL_WRAPPER(sys_clock_nanosleep); GEN_SYSCALL_WRAPPER(sys_getcwd); GEN_SYSCALL_WRAPPER(sys_symlink); GEN_SYSCALL_WRAPPER(sys_getgroups); @@ -1557,6 +1445,7 @@ GEN_SYSCALL_WRAPPER(sys_select); // 4.4BSD GEN_SYSCALL_WRAPPER(sys_flock); // 4.4BSD GEN_SYSCALL_WRAPPER(sys_poll); // XPG4-UNIX GEN_SYSCALL_WRAPPER(sys_getrusage); // SVr4, 4.3BSD +GEN_SYSCALL_WRAPPER(sys_stime); // SVr4, SVID, X/OPEN GEN_SYSCALL_WRAPPER(sys_settimeofday); // SVr4, 4.3BSD (non-POSIX) GEN_SYSCALL_WRAPPER(sys_getpriority); // SVr4, 4.4BSD GEN_SYSCALL_WRAPPER(sys_setpriority); // SVr4, 4.4BSD @@ -1652,7 +1541,6 @@ GEN_SYSCALL_WRAPPER(sys_lremovexattr); // * L? GEN_SYSCALL_WRAPPER(sys_fremovexattr); // * L? GEN_SYSCALL_WRAPPER(sys_sched_setaffinity); // * L? GEN_SYSCALL_WRAPPER(sys_sched_getaffinity); // * L? -GEN_SYSCALL_WRAPPER(sys_exit_group); // * ? GEN_SYSCALL_WRAPPER(sys_lookup_dcookie); // (*/32/64) L GEN_SYSCALL_WRAPPER(sys_set_tid_address); // * ? GEN_SYSCALL_WRAPPER(sys_statfs64); // * (?) @@ -1663,6 +1551,9 @@ GEN_SYSCALL_WRAPPER(sys_mq_timedsend); // * P? GEN_SYSCALL_WRAPPER(sys_mq_timedreceive); // * P? GEN_SYSCALL_WRAPPER(sys_mq_notify); // * P? GEN_SYSCALL_WRAPPER(sys_mq_getsetattr); // * P? +GEN_SYSCALL_WRAPPER(sys_tkill); // * L +GEN_SYSCALL_WRAPPER(sys_tgkill); // * L +GEN_SYSCALL_WRAPPER(sys_gettid); // * L? #undef GEN_SYSCALL_WRAPPER @@ -1769,6 +1660,7 @@ extern void VG_(generic_POST_sys_recvmsg) ( TId, UW, UW, UW ); extern ULong* VG_(tt_fast) [VG_TT_FAST_SIZE]; extern UInt* VG_(tt_fastN)[VG_TT_FAST_SIZE]; + extern void VG_(init_tt_tc) ( void ); extern @@ -1813,7 +1705,7 @@ extern Word VG_(do_syscall) ( UInt, UWord, UWord, UWord, UWord, UWord, UWord ); #define vgPlain_do_syscall6(s,a,b,c,d,e,f) VG_(do_syscall)((s),(a),(b),(c),(d),(e),(f)) extern Int VG_(clone) ( Int (*fn)(void *), void *stack, Int flags, void *arg, - Int *child_tid, Int *parent_tid); + Int *child_tid, Int *parent_tid, vki_modify_ldt_t * ); extern void VG_(sigreturn)(void); /* --------------------------------------------------------------------- @@ -1843,6 +1735,7 @@ extern UInt VG_(run_innerloop) ( void* guest_state ); extern const Char VG_(trampoline_code_start); extern const Int VG_(trampoline_code_length); extern const Int VG_(tramp_sigreturn_offset); +extern const Int VG_(tramp_rt_sigreturn_offset); extern const Int VG_(tramp_syscall_offset); /* --------------------------------------------------------------------- @@ -1865,24 +1758,18 @@ extern void VG_(missing_tool_func) ( const Char* fn ); // Returns the architecture and subarchitecture, or indicates // that this subarchitecture is unable to run Valgrind // Returns False to indicate we cannot proceed further. - extern Bool VGA_(getArchAndSubArch)( /*OUT*/VexArch*, /*OUT*/VexSubArch* ); - // Accessors for the ThreadArchState #define INSTR_PTR(regs) ((regs).vex.ARCH_INSTR_PTR) #define STACK_PTR(regs) ((regs).vex.ARCH_STACK_PTR) #define FRAME_PTR(regs) ((regs).vex.ARCH_FRAME_PTR) - #define CLREQ_ARGS(regs) ((regs).vex.ARCH_CLREQ_ARGS) #define PTHREQ_RET(regs) ((regs).vex.ARCH_PTHREQ_RET) #define CLREQ_RET(regs) ((regs).vex.ARCH_CLREQ_RET) - - // Offsets for the Vex state #define O_STACK_PTR (offsetof(VexGuestArchState, ARCH_STACK_PTR)) #define O_FRAME_PTR (offsetof(VexGuestArchState, ARCH_FRAME_PTR)) - #define O_CLREQ_RET (offsetof(VexGuestArchState, ARCH_CLREQ_RET)) #define O_PTHREQ_RET (offsetof(VexGuestArchState, ARCH_PTHREQ_RET)) @@ -1900,6 +1787,32 @@ extern void VGA_(setup_child) ( ThreadArchState*, ThreadArchState* ); extern void VGA_(set_arg_and_bogus_ret) ( ThreadId tid, UWord arg, Addr ret ); extern void VGA_(thread_initial_stack) ( ThreadId tid, UWord arg, Addr ret ); +// OS/Platform-specific thread clear (after thread exit) +extern void VGA_(os_state_clear)(ThreadState *); + +// OS/Platform-specific thread init (at scheduler init time) +extern void VGA_(os_state_init)(ThreadState *); + +// Run a thread from beginning to end. Does not return if tid == VG_(master_tid). +void VGA_(thread_wrapper)(ThreadId tid); + +// Like VGA_(thread_wrapper), but it allocates a stack before calling +// to VGA_(thread_wrapper) on that stack, as if it had been set up by +// clone() +void VGA_(main_thread_wrapper)(ThreadId tid) __attribute__ ((__noreturn__)); + +// Return how many bytes of a thread's Valgrind stack are unused +Int VGA_(stack_unused)(ThreadId tid); + +// Terminate the process. Does not return. +void VGA_(terminate)(ThreadId tid, VgSchedReturnCode src) __attribute__((__noreturn__)); + +// wait until all other threads are dead +extern void VGA_(reap_threads)(ThreadId self); + +// handle an arch-specific client request +extern Bool VGA_(client_request)(ThreadId tid, UWord *args); + // Symtab stuff extern UInt* VGA_(reg_addr_from_tst) ( Int regno, ThreadArchState* ); @@ -1909,22 +1822,17 @@ extern Bool VGA_(setup_pointercheck) ( void ); // For attaching the debugger extern Int VGA_(ptrace_setregs_from_tst) ( Int pid, ThreadArchState* arch ); +// Used by leakcheck +extern void VGA_(mark_from_registers)(ThreadId tid, void (*marker)(Addr)); + // Signal stuff extern void VGA_(push_signal_frame) ( ThreadId tid, Addr sp_top_of_frame, const vki_siginfo_t *siginfo, void *handler, UInt flags, - const vki_sigset_t *mask); -extern Int VGA_(pop_signal_frame) ( ThreadId tid ); - -// libpthread stuff -typedef struct _ThreadArchAux ThreadArchAux; - -void VGA_(thread_create) ( ThreadArchAux *aux ); -void VGA_(thread_wrapper)( ThreadArchAux *aux ); -void VGA_(thread_exit) ( void ); - -Bool VGA_(has_tls) ( void ); + const vki_sigset_t *mask, + void *restorer ); +////typedef struct _ThreadArchAux ThreadArchAux; #define MY__STRING(__str) #__str // Assertion to use in code running on the simulated CPU. @@ -1964,7 +1872,7 @@ extern void VG_(user_assert_fail) ( const Char* expr, const Char* file, struct SyscallTableEntry { UInt *flags_ptr; - void (*before)(ThreadId tid, ThreadState *tst); + void (*before)(ThreadId tid, ThreadState *tst /*, UInt *flags*/); void (*after) (ThreadId tid, ThreadState *tst); }; @@ -1984,54 +1892,67 @@ extern const UInt VGA_(syscall_table_size); extern void VGA_(restart_syscall)(ThreadArchState* arch); -/* We need our own copy of VG_(do_syscall)() to handle a special - race-condition. If we've got signals unblocked, and we take a - signal in the gap either just before or after the syscall, we may - end up not running the syscall at all, or running it more than - once. - - The solution is to make the signal handler derive the proxy's - precise state by looking to see which eip it is executing at - exception time. - - Ranges: - - VGA_(sys_before) ... VGA_(sys_restarted): - Setting up register arguments and running state. If - interrupted, then the syscall should be considered to return - ERESTARTSYS. - - VGA_(sys_restarted): - If interrupted and eip==VGA_(sys_restarted), then either the syscall - was about to start running, or it has run, was interrupted and - the kernel wants to restart it. eax still contains the - syscall number. If interrupted, then the syscall return value - should be ERESTARTSYS. - - VGA_(sys_after): - If interrupted and eip==VGA_(sys_after), the syscall either just - finished, or it was interrupted and the kernel doesn't want to - restart it. Either way, eax equals the correct return value - (either the actual return value, or EINTR). - - VGA_(sys_after) ... VGA_(sys_done): - System call is complete, but the state hasn't been updated, - nor has the result been written back. eax contains the return - value. - - Freakin' horrible... +/* + Perform a syscall on behalf of a client thread, using a specific + signal mask. On completion, the signal mask is set to restore_mask + (which presumably blocks almost everything). If a signal happens + during the syscall, the handler should call + VGA_(interrupted_syscall)() to adjust the thread's context to do the + right thing. */ -extern const Addr VGA_(sys_before), VGA_(sys_restarted), - VGA_(sys_after), VGA_(sys_done); - -extern void VGA_(do_thread_syscall) - ( UWord sys, - UWord arg1, UWord arg2, UWord arg3, - UWord arg4, UWord arg5, UWord arg6, - /*OUT*/HWord *resultP, - /*enum PXState*/Int *stateP, - /*enum PXState*/Int poststate - ); +extern void VGA_(client_syscall)(Int syscallno, ThreadState *tst, + const vki_sigset_t *syscall_mask); + +/* + Fix up the thread's state because a syscall may have been + interrupted with a signal. Returns True if the syscall completed + (either interrupted or finished normally), or False if it was + restarted (or the signal didn't actually interrupt a syscall). + */ +extern void VGA_(interrupted_syscall)(ThreadId tid, + struct vki_ucontext *uc, + Bool restart); + + +///* --------------------------------------------------------------------- +// Thread modelling +// ------------------------------------------------------------------ */ +//extern void VG_(tm_thread_create) (ThreadId creator, ThreadId tid, Bool detached); +//extern void VG_(tm_thread_exit) (ThreadId tid); +//extern Bool VG_(tm_thread_exists) (ThreadId tid); +//extern void VG_(tm_thread_detach) (ThreadId tid); +//extern void VG_(tm_thread_join) (ThreadId joiner, ThreadId joinee); +//extern void VG_(tm_thread_switchto)(ThreadId tid); +// +//extern void VG_(tm_mutex_init) (ThreadId tid, Addr mutexp); +//extern void VG_(tm_mutex_destroy)(ThreadId tid, Addr mutexp); +//extern void VG_(tm_mutex_trylock)(ThreadId tid, Addr mutexp); +//extern void VG_(tm_mutex_giveup) (ThreadId tid, Addr mutexp); +//extern void VG_(tm_mutex_acquire)(ThreadId tid, Addr mutexp); +//extern void VG_(tm_mutex_tryunlock)(ThreadId tid, Addr mutexp); +//extern void VG_(tm_mutex_unlock) (ThreadId tid, Addr mutexp); +//extern Bool VG_(tm_mutex_exists) (Addr mutexp); +// +//extern UInt VG_(tm_error_update_extra) (Error *err); +//extern Bool VG_(tm_error_equal) (VgRes res, Error *e1, Error *e2); +//extern void VG_(tm_error_print) (Error *err); +// +//extern void VG_(tm_init) (); +// +//extern void VG_(tm_cond_init) (ThreadId tid, Addr condp); +//extern void VG_(tm_cond_destroy) (ThreadId tid, Addr condp); +//extern void VG_(tm_cond_wait) (ThreadId tid, Addr condp, Addr mutexp); +//extern void VG_(tm_cond_wakeup) (ThreadId tid, Addr condp, Addr mutexp); +//extern void VG_(tm_cond_signal) (ThreadId tid, Addr condp); +// +///* ----- pthreads ----- */ +//extern void VG_(pthread_init) (); +//extern void VG_(pthread_startfunc_wrapper)(Addr wrapper); +// +//struct vg_pthread_newthread_data { +// void *(*startfunc)(void *arg); +// void *arg; +//}; /* --------------------------------------------------------------------- Finally - autoconf-generated settings diff --git a/coregrind/core_asm.h b/coregrind/core_asm.h index 386b8e3f63..cce1d7c6c7 100644 --- a/coregrind/core_asm.h +++ b/coregrind/core_asm.h @@ -41,7 +41,7 @@ /* Magic values that the guest state might be set to when returning to the dispatcher. The only other legitimate value is to point to the start of the thread's VEX guest state. These also are return values from - VG_(run_innerloop) to the scheduler. + from VG_(run_innerloop) to the scheduler. */ /* Defines values for JMP_EMWARN, JMP_SYSCALL, JMP_CLIENTREQ and JMP_YIELD */ @@ -51,18 +51,17 @@ those from libvex_trc_values.h. */ #define VG_TRC_INNER_FASTMISS 37 /* TRC only; means fast-cache miss. */ #define VG_TRC_INNER_COUNTERZERO 41 /* TRC only; means bb ctr == 0 */ -#define VG_TRC_UNRESUMABLE_SIGNAL 43 /* TRC only; got sigsegv/sigbus */ +#define VG_TRC_FAULT_SIGNAL 43 /* TRC only; got sigsegv/sigbus */ #define VG_TRC_INVARIANT_FAILED 47 /* TRC only; invariant violation */ +#define VG_MAX_TRC 128 /* Highest possible TRC value */ + /* Constants for the fast translation lookup cache. */ #define VG_TT_FAST_BITS 16 #define VG_TT_FAST_SIZE (1 << VG_TT_FAST_BITS) #define VG_TT_FAST_MASK ((VG_TT_FAST_SIZE) - 1) -/* Assembly code stubs make this request */ -#define VG_USERREQ__SIGNAL_RETURNS 0x4001 - // XXX: all this will go into x86/ eventually... /* 0 - standard feature flags diff --git a/coregrind/gen_toolint.pl b/coregrind/gen_toolint.pl index ccce99baf3..7514c74970 100644 --- a/coregrind/gen_toolint.pl +++ b/coregrind/gen_toolint.pl @@ -84,6 +84,7 @@ if ($output eq "callwrap") { my $args = join ', ', @args; print "$ret $pfxmap{$pfx}($func)($args);\n"; + print "$ret VG_(missing_$func)($args);\n"; print "Bool VG_(defined_$func)(void);\n"; } } elsif ($output eq "toolproto") { @@ -99,11 +100,11 @@ if ($output eq "callwrap") { my ($pfx, $ret, $func, @args) = @_; my $args = join ", ", @args; - print "static $ret missing_${pfx}_$func($args) {\n"; + print "__attribute__ ((weak))\n$ret VG_(missing_$func)($args) {\n"; print " VG_(missing_tool_func)(\"${pfx}_$func\");\n"; print "}\n"; print "Bool VG_(defined_$func)(void) {\n"; - print " return $struct.${pfx}_$func != missing_${pfx}_$func;\n"; + print " return $struct.${pfx}_$func != VG_(missing_$func);\n"; print "}\n\n"; }; $indent = " "; @@ -135,7 +136,7 @@ if ($output eq "callwrap") { $generate = sub ($$$@) { my ($pfx, $ret, $func, @args) = @_; - print "$indent.${pfx}_$func = missing_${pfx}_$func,\n" + print "$indent.${pfx}_$func = VG_(missing_$func),\n" }; $indent = " "; } elsif ($output eq "initfunc") { @@ -149,7 +150,7 @@ if ($output eq "callwrap") { void VG_(init_$func)($ret (*func)($args)) { if (func == NULL) - func = missing_${pfx}_$func; + func = VG_(missing_$func); if (VG_(defined_$func)()) VG_(printf)("Warning tool is redefining $func\\n"); if (func == TL_($func)) diff --git a/coregrind/linux/Makefile.am b/coregrind/linux/Makefile.am index 35ea6697d5..6698c931a7 100644 --- a/coregrind/linux/Makefile.am +++ b/coregrind/linux/Makefile.am @@ -1,7 +1,7 @@ include $(top_srcdir)/Makefile.all.am include $(top_srcdir)/Makefile.core-AM_CPPFLAGS.am -AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -fomit-frame-pointer -g +AM_CFLAGS = $(WERROR) -Wmissing-prototypes -Winline -Wall -Wshadow -O -g noinst_HEADERS = \ core_os.h @@ -9,4 +9,6 @@ noinst_HEADERS = \ noinst_LIBRARIES = libos.a libos_a_SOURCES = \ + core_os.c \ + sema.c \ syscalls.c diff --git a/coregrind/linux/core_os.h b/coregrind/linux/core_os.h index 31e670f324..3b9963cfa1 100644 --- a/coregrind/linux/core_os.h +++ b/coregrind/linux/core_os.h @@ -43,6 +43,8 @@ extern void VGA_(linux_##x##_before)(ThreadId tid, ThreadState *tst); \ extern void VGA_(linux_##x##_after) (ThreadId tid, ThreadState *tst) +LINUX_SYSCALL_WRAPPER(sys_exit_group); + LINUX_SYSCALL_WRAPPER(sys_mount); LINUX_SYSCALL_WRAPPER(sys_oldumount); LINUX_SYSCALL_WRAPPER(sys_umount); @@ -86,6 +88,94 @@ LINUX_SYSCALL_WRAPPER(sys_io_getevents); LINUX_SYSCALL_WRAPPER(sys_io_submit); LINUX_SYSCALL_WRAPPER(sys_io_cancel); +#define FUTEX_SEMA 0 + +#if FUTEX_SEMA +/* --------------------------------------------------------------------- + Definition for a semaphore. Defined in terms of futex. + + Futex semaphore operations taken from futex-2.2/usersem.h + ------------------------------------------------------------------ */ +typedef struct { + int count; +} vg_sema_t; + +extern Int __futex_down_slow(vg_sema_t *, int, struct vki_timespec *); +extern Int __futex_up_slow(vg_sema_t *); + +void VG_(sema_init)(vg_sema_t *); +static inline void VG_(sema_deinit)(vg_sema_t *) +{ +} + +static inline void VG_(sema_down)(vg_sema_t *futx) +{ + Int val, woken = 0; + + /* Returns new value */ + while ((val = __futex_down(&futx->count)) != 0) { + Int ret = __futex_down_slow(futx, val, NULL); + if (ret < 0) + return; /* error */ + else if (ret == 1) + return; /* passed */ + else if (ret == 0) + woken = 1; /* slept */ + else + /* loop */; + } + /* If we were woken, someone else might be sleeping too: set to -1 */ + if (woken) { + futx->count = -1; + } + return; +} + +/* If __futex_up increments count from 0 -> 1, noone was waiting. + Otherwise, set to 1 and tell kernel to wake them up. */ +static inline void VG_(sema_up)(vg_sema_t *futx) +{ + if (!__futex_up(&futx->count)) + __futex_up_slow(futx); +} +#else /* !FUTEX_SEMA */ +/* + Not really a semaphore, but use a pipe for a token-passing scheme + */ +typedef struct { + Int pipe[2]; + Int owner_thread; /* who currently has it */ +} vg_sema_t; + +void VG_(sema_init)(vg_sema_t *); +void VG_(sema_deinit)(vg_sema_t *); +void VG_(sema_down)(vg_sema_t *sema); +void VG_(sema_up)(vg_sema_t *sema); + +#endif /* FUTEX_SEMA */ + +/* OS-specific thread state */ +typedef struct { + /* who we are */ + Int lwpid; /* PID of kernel task */ + Int threadgroup; /* thread group id */ + + /* how we were started */ + UInt clone_flags; /* flags passed to clone() to create this thread */ + Int *parent_tidptr; + Int *child_tidptr; + + ThreadId parent; /* parent tid (if any) */ + + /* runtime details */ + UInt *stack; /* stack base */ + UInt stacksize; /* stack size in UInts */ + + /* exit details */ + Int exitcode; /* in the case of exitgroup, set by someone else */ + Int fatalsig; /* fatal signal */ +} os_thread_t; + #endif // __LINUX_CORE_OS_H /*--------------------------------------------------------------------*/ diff --git a/coregrind/linux/syscalls.c b/coregrind/linux/syscalls.c index d86ff85bdf..a76ad3fb18 100644 --- a/coregrind/linux/syscalls.c +++ b/coregrind/linux/syscalls.c @@ -40,12 +40,41 @@ #define PRE(name, f) PRE_TEMPLATE( , vgArch_linux, name, f) #define POST(name) POST_TEMPLATE( , vgArch_linux, name) +PRE(sys_exit_group, Special) +{ + ThreadId t; + + PRINT("exit_group( %d )", ARG1); + PRE_REG_READ1(void, "exit_group", int, exit_code); + + /* A little complex; find all the threads with the same threadgroup + as this one (including this one), and mark them to exit */ + for (t = 1; t < VG_N_THREADS; t++) { + if (VG_(threads)[t].status == VgTs_Empty || /* not alive */ + VG_(threads)[t].os_state.threadgroup != tst->os_state.threadgroup) /* not our group */ + continue; + + VG_(threads)[t].exitreason = VgSrc_ExitSyscall; + VG_(threads)[t].os_state.exitcode = ARG1; + + if (t != tid) + VG_(kill_thread)(t); /* unblock it, if blocked */ + } + + /* exit_group doesn't return anything (perhaps it doesn't return?) + Nevertheless, if we don't do this, the result-not-assigned- + yet-you-said-you-were-Special assertion in the main syscall + handling logic will fire. Hence .. + */ + SET_RESULT(0); +} + PRE(sys_mount, MayBlock) { // Nb: depending on 'flags', the 'type' and 'data' args may be ignored. // We are conservative and check everything, except the memory pointed to // by 'data'. - PRINT( "sys_mount( %p, %p, %p, %p, %p )" ,ARG1,ARG2,ARG3); + PRINT( "sys_mount( %p, %p, %p, %p, %p )" ,ARG1,ARG2,ARG3,ARG4,ARG5); PRE_REG_READ5(long, "mount", char *, source, char *, target, char *, type, unsigned long, flags, void *, data); @@ -301,13 +330,32 @@ PRE(sys_personality, 0) PRE(sys_sysctl, 0) { PRINT("sys_sysctl ( %p )", ARG1 ); + struct __vki_sysctl_args *args; + args = (struct __vki_sysctl_args *)ARG1; PRE_REG_READ1(long, "sysctl", struct __sysctl_args *, args); PRE_MEM_WRITE( "sysctl(args)", ARG1, sizeof(struct __vki_sysctl_args) ); + if (!VG_(is_addressable)(ARG1, sizeof(struct __vki_sysctl_args), VKI_PROT_READ)) { + SET_RESULT( -VKI_EFAULT ); + return; + } + + PRE_MEM_READ("sysctl(name)", (Addr)args->name, args->nlen * sizeof(*args->name)); + if (args->newval != NULL) + PRE_MEM_READ("sysctl(newval)", (Addr)args->newval, args->newlen); + if (args->oldlenp != NULL) { + PRE_MEM_READ("sysctl(oldlenp)", (Addr)args->oldlenp, sizeof(*args->oldlenp)); + PRE_MEM_WRITE("sysctl(oldval)", (Addr)args->oldval, *args->oldlenp); + } } POST(sys_sysctl) { - POST_MEM_WRITE( ARG1, sizeof(struct __vki_sysctl_args) ); + struct __vki_sysctl_args *args; + args = (struct __vki_sysctl_args *)ARG1; + if (args->oldlenp != NULL) { + POST_MEM_WRITE((Addr)args->oldlenp, sizeof(*args->oldlenp)); + POST_MEM_WRITE((Addr)args->oldval, *args->oldlenp); + } } PRE(sys_prctl, MayBlock) @@ -319,7 +367,7 @@ PRE(sys_prctl, MayBlock) int, option, unsigned long, arg2, unsigned long, arg3, unsigned long, arg4, unsigned long, arg5); // XXX: totally wrong... we need to look at the 'option' arg, and do - // PRE_MEM_READs/PRE_MEM_WRITEs as necessary... + // SYS_PRE_MEM_READs/SYS_PRE_MEM_WRITEs as necessary... } PRE(sys_sendfile, MayBlock) @@ -443,11 +491,16 @@ PRE(sys_io_setup, Special) size = PGROUNDUP(sizeof(struct vki_aio_ring) + ARG1*sizeof(struct vki_io_event)); addr = VG_(find_map_space)(0, size, True); - VG_(map_segment)(addr, size, VKI_PROT_READ|VKI_PROT_EXEC, SF_FIXED); - VG_(pad_address_space)(); - SET_RESULT( VG_(do_syscall2)(SYSNO, ARG1, ARG2) ); - VG_(unpad_address_space)(); + if (addr == 0) { + SET_RESULT( -VKI_ENOMEM ); + return; + } + + VG_(map_segment)(addr, size, VKI_PROT_READ|VKI_PROT_WRITE, SF_FIXED); + + VG_(pad_address_space)(0); + VG_(unpad_address_space)(0); if (RES == 0) { struct vki_aio_ring *r = *(struct vki_aio_ring **)ARG2; @@ -468,6 +521,9 @@ PRE(sys_io_setup, Special) // before the syscall, while the aio_ring structure still exists. (And we // know that we must look at the aio_ring structure because Tom inspected the // kernel and glibc sources to see what they do, yuk.) +// +// XXX This segment can be implicitly unmapped when aio +// file-descriptors are closed... PRE(sys_io_destroy, Special) { Segment *s = VG_(find_segment)(ARG1); @@ -485,7 +541,7 @@ PRE(sys_io_destroy, Special) SET_RESULT( VG_(do_syscall1)(SYSNO, ARG1) ); - if (RES == 0 && s != NULL && VG_(seg_contains)(s, ARG1, size)) { + if (RES == 0 && s != NULL) { VG_TRACK( die_mem_munmap, ARG1, size ); VG_(unmap_range)(ARG1, size); } @@ -504,7 +560,7 @@ PRE(sys_io_getevents, MayBlock) ARG4, sizeof(struct vki_io_event)*ARG3 ); if (ARG5 != 0) PRE_MEM_READ( "io_getevents(timeout)", - ARG5, sizeof(struct vki_timespec)); + ARG5, sizeof(struct vki_timespec)); } POST(sys_io_getevents) diff --git a/coregrind/stage1.c b/coregrind/stage1.c index 0a0cb77ecb..247912c7d8 100644 --- a/coregrind/stage1.c +++ b/coregrind/stage1.c @@ -43,6 +43,7 @@ #include "core.h" #include "ume.h" +#include "memcheck/memcheck.h" static int stack[SIGSTKSZ*4]; @@ -115,8 +116,8 @@ static void *fix_auxv(void *v_init_esp, const struct exeinfo *info, seen = 0; for(; auxv->a_type != AT_NULL; auxv++) { if (0) - printf("doing auxv %p %4lld: %lld %p\n", - auxv, (ULong)auxv->a_type, (ULong)auxv->u.a_val, auxv->u.a_ptr); + printf("doing auxv %p %5lld: %lld %p\n", + auxv, (Long)auxv->a_type, (Long)auxv->u.a_val, auxv->u.a_ptr); switch(auxv->a_type) { case AT_PHDR: @@ -297,21 +298,27 @@ static void main2(void) foreach_map(prmap, /*dummy*/NULL); } - jmp_with_stack(info.init_eip, (Addr)esp); + jmp_with_stack((void (*)(void))info.init_eip, (Addr)esp); } int main(int argc, char** argv) { struct rlimit rlim; - const char *cp = getenv(VALGRINDLIB); - - if (cp != NULL) - valgrind_lib = cp; + const char *cp; // Initial stack pointer is to argc, which is immediately before argv[0] // on the stack. Nb: Assumes argc is word-aligned. init_sp = argv - 1; + /* The Linux libc startup sequence leaves this in an apparently + undefined state, but it really is defined, so mark it so. */ + VALGRIND_MAKE_READABLE(init_sp, sizeof(int)); + + cp = getenv(VALGRINDLIB); + + if (cp != NULL) + valgrind_lib = cp; + /* Set the address space limit as high as it will go, since we make a lot of very large mappings. */ getrlimit(RLIMIT_AS, &rlim); @@ -319,7 +326,7 @@ int main(int argc, char** argv) setrlimit(RLIMIT_AS, &rlim); /* move onto another stack so we can play with the main one */ - jmp_with_stack((Addr)main2, (Addr)stack + sizeof(stack)); + jmp_with_stack(main2, (Addr)stack + sizeof(stack)); } /*--------------------------------------------------------------------*/ diff --git a/coregrind/ume.c b/coregrind/ume.c index 38de1b0a52..f69ecdcffb 100644 --- a/coregrind/ume.c +++ b/coregrind/ume.c @@ -307,6 +307,7 @@ static int load_ELF(char *hdr, int len, int fd, const char *name, info->phnum = e->e.e_phnum; info->entry = e->e.e_entry + ebase; + info->phdr = 0; for(i = 0; i < e->e.e_phnum; i++) { ESZ(Phdr) *ph = &e->p[i]; @@ -375,6 +376,9 @@ static int load_ELF(char *hdr, int len, int fd, const char *name, } } + if (info->phdr == 0) + info->phdr = minaddr + e->e.e_phoff; + if (info->exe_base != info->exe_end) { if (minaddr >= maxaddr || (minaddr + ebase < info->exe_base || @@ -417,6 +421,7 @@ static int load_ELF(char *hdr, int len, int fd, const char *name, entry = baseoff + interp->e.e_entry; info->interp_base = (ESZ(Addr))base; + free(interp->p); free(interp); } else entry = (void *)e->e.e_entry; @@ -426,6 +431,7 @@ static int load_ELF(char *hdr, int len, int fd, const char *name, info->init_eip = (Addr)entry; + free(e->p); free(e); return 0; diff --git a/coregrind/ume.h b/coregrind/ume.h index 48bbf95de9..eb720eb49a 100644 --- a/coregrind/ume.h +++ b/coregrind/ume.h @@ -41,6 +41,7 @@ /*--- General stuff ---*/ /*------------------------------------------------------------*/ +extern void foreach_map(int (*fn)(char *start, char *end, const char *perm, off_t offset, int maj, int min, int ino, void* extra), @@ -49,7 +50,9 @@ void foreach_map(int (*fn)(char *start, char *end, // Jump to a new 'ip' with the stack 'sp'. This is intended // to simulate the initial CPU state when the kernel starts an program // after exec; and so should clear all the other registers. -void jmp_with_stack(Addr ip, Addr sp) __attribute__((noreturn)); +extern +__attribute__((noreturn)) +void jmp_with_stack(void (*eip)(void), Addr sp); /*------------------------------------------------------------*/ /*--- Loading ELF files ---*/ @@ -81,7 +84,7 @@ struct exeinfo // checks execute permissions, sets up interpreter if program is a script, // reads headers, maps file into memory, and returns important info about // the program. -int do_exec(const char *exe, struct exeinfo *info); +extern int do_exec(const char *exe, struct exeinfo *info); /*------------------------------------------------------------*/ /*--- Finding and dealing with auxv ---*/ @@ -96,7 +99,7 @@ struct ume_auxv } u; }; -struct ume_auxv *find_auxv(UWord* orig_esp); +extern struct ume_auxv *find_auxv(UWord* orig_esp); /* Our private auxv entries */ #define AT_UME_PADFD 0xff01 /* padding file fd */ diff --git a/coregrind/vg_default.c b/coregrind/vg_default.c index f88fe75313..9e3ffff12d 100644 --- a/coregrind/vg_default.c +++ b/coregrind/vg_default.c @@ -88,7 +88,7 @@ void* TL_(malloc)( ThreadId tid, SizeT size ) } __attribute__ ((weak)) -void TL_(free)( ThreadId tid, void* p ) +void TL_(free)( ThreadId tid, void* p ) { /* see comment for TL_(malloc)() above */ if (VG_(tl_malloc_called_by_scheduler)) diff --git a/coregrind/vg_demangle.c b/coregrind/vg_demangle.c index 7c52cb53a5..2d3278a362 100644 --- a/coregrind/vg_demangle.c +++ b/coregrind/vg_demangle.c @@ -64,7 +64,9 @@ void VG_(demangle) ( Char* orig, Char* result, Int result_size ) /* Check that the demangler isn't leaking. */ /* 15 Feb 02: if this assertion fails, this is not a disaster. Comment it out, and let me know. (jseward@acm.org). */ - vg_assert(VG_(is_empty_arena)(VG_AR_DEMANGLE)); + // 9 Feb 05: it fails very occasionally, as reported in bug #87480. + // It's very rare, and not a disaster, so let it slide. + //vg_assert(VG_(is_empty_arena)(VG_AR_DEMANGLE)); /* VG_(show_all_arena_stats)(); */ diff --git a/coregrind/vg_errcontext.c b/coregrind/vg_errcontext.c index 612f666ec6..5ca241b4e8 100644 --- a/coregrind/vg_errcontext.c +++ b/coregrind/vg_errcontext.c @@ -51,6 +51,7 @@ static UInt n_errs_suppressed = 0; /* forwards ... */ static Supp* is_suppressible_error ( Error* err ); +static ThreadId last_tid_printed = 1; /*------------------------------------------------------------*/ /*--- Error type ---*/ @@ -58,11 +59,6 @@ static Supp* is_suppressible_error ( Error* err ); /* Note: it is imperative this doesn't overlap with (0..) at all, as tools * effectively extend it by defining their own enums in the (0..) range. */ -typedef - enum { - PThreadErr = -1, // Pthreading error - } - CoreErrorKind; /* Errors. Extensible (via the 'extra' field). Tools can use a normal enum (with element values in the normal range (0..)) for `ekind'. @@ -130,15 +126,26 @@ typedef } CoreSuppKind; +/* Max number of callers for context in a suppression. */ +#define VG_MAX_SUPP_CALLERS 24 + /* For each caller specified for a suppression, record the nature of the caller name. Not of interest to tools. */ typedef enum { + NoName, /* Error case */ ObjName, /* Name is of an shared object file. */ FunName /* Name is of a function. */ } SuppLocTy; +typedef + struct { + SuppLocTy ty; + Char* name; + } + SuppLoc; + /* Suppressions. Tools can get/set tool-relevant parts with functions declared in include/tool.h. Extensible via the 'extra' field. Tools can use a normal enum (with element values in the normal range @@ -147,10 +154,12 @@ struct _Supp { struct _Supp* next; Int count; // The number of times this error has been suppressed. Char* sname; // The name by which the suppression is referred to. - /* First two (name of fn where err occurs, and immediate caller) - * are mandatory; extra two are optional. */ - SuppLocTy caller_ty[VG_N_SUPP_CALLERS]; - Char* caller [VG_N_SUPP_CALLERS]; + + // Length of 'callers' + Int n_callers; + // Array of callers, for matching stack traces. First one (name of fn + // where err occurs) is mandatory; rest are optional. + SuppLoc* callers; /* The tool-specific part */ SuppKind skind; // What kind of suppression. Must use the range (0..). @@ -205,13 +214,10 @@ static Bool eq_Error ( VgRes res, Error* e1, Error* e2 ) return False; switch (e1->ekind) { - case PThreadErr: - vg_assert(VG_(needs).core_errors); - if (e1->string == e2->string) - return True; - if (0 == VG_(strcmp)(e1->string, e2->string)) - return True; - return False; + // case ThreadErr: + // case MutexErr: + // vg_assert(VG_(needs).core_errors); + // return VG_(tm_error_equal)(res, e1, e2); default: if (VG_(needs).tool_errors) return TL_(eq_Error)(res, e1, e2); @@ -228,15 +234,17 @@ static void pp_Error ( Error* err, Bool printCount ) { if (printCount) VG_(message)(Vg_UserMsg, "Observed %d times:", err->count ); - if (err->tid > 1) + if (err->tid > 0 && err->tid != last_tid_printed) { VG_(message)(Vg_UserMsg, "Thread %d:", err->tid ); + last_tid_printed = err->tid; + } switch (err->ekind) { - case PThreadErr: - vg_assert(VG_(needs).core_errors); - VG_(message)(Vg_UserMsg, "%s", err->string ); - VG_(pp_ExeContext)(err->where); - break; + // case ThreadErr: + // case MutexErr: + // vg_assert(VG_(needs).core_errors); + // VG_(tm_error_print)(err); + // break; default: if (VG_(needs).tool_errors) TL_(pp_Error)( err ); @@ -292,8 +300,7 @@ Bool VG_(is_action_requested) ( Char* action, Bool* clo ) } -// Initialisation picks out values from the appropriate ThreadState as -// necessary. +/* Construct an error */ static __inline__ void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a, Char* s, void* extra, ExeContext* where ) @@ -328,14 +335,14 @@ static void gen_suppression(Error* err) ExeContext* ec = VG_(get_error_where)(err); Int stop_at = VG_(clo_backtrace_size); - /* At most VG_N_SUPP_CALLERS names */ - if (stop_at > VG_N_SUPP_CALLERS) stop_at = VG_N_SUPP_CALLERS; + /* At most VG_MAX_SUPP_CALLERS names */ + if (stop_at > VG_MAX_SUPP_CALLERS) stop_at = VG_MAX_SUPP_CALLERS; vg_assert(stop_at > 0); VG_(printf)("{\n"); VG_(printf)(" \n"); - if (PThreadErr == err->ekind) { + if (ThreadErr == err->ekind || MutexErr == err->ekind) { VG_(printf)(" core:PThread\n"); } else { @@ -528,16 +535,24 @@ void VG_(maybe_record_error) ( ThreadId tid, p = VG_(arena_malloc)(VG_AR_ERRORS, sizeof(Error)); *p = err; - /* update `extra', for non-core errors (core ones don't use 'extra') */ - if (VG_(needs).tool_errors && PThreadErr != ekind) { - extra_size = TL_(update_extra)(p); + /* update `extra' */ + switch (ekind) { + // case ThreadErr: + // case MutexErr: + // vg_assert(VG_(needs).core_errors); + // extra_size = VG_(tm_error_update_extra)(p); + // break; + default: + vg_assert(VG_(needs).tool_errors); + extra_size = TL_(update_extra)(p); + break; + } - /* copy block pointed to by `extra', if there is one */ - if (NULL != p->extra && 0 != extra_size) { - void* new_extra = VG_(malloc)(extra_size); - VG_(memcpy)(new_extra, p->extra, extra_size); - p->extra = new_extra; - } + /* copy block pointed to by `extra', if there is one */ + if (NULL != p->extra && 0 != extra_size) { + void* new_extra = VG_(malloc)(extra_size); + VG_(memcpy)(new_extra, p->extra, extra_size); + p->extra = new_extra; } p->next = vg_errors; @@ -608,12 +623,6 @@ Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, Char* s, /* These are called not from generated code but from the scheduler */ -void VG_(record_pthread_error) ( ThreadId tid, Char* msg ) -{ - if (! VG_(needs).core_errors) return; - VG_(maybe_record_error)( tid, PThreadErr, /*addr*/0, msg, /*extra*/NULL ); -} - void VG_(show_all_errors) ( void ) { Int i, n_min; @@ -746,16 +755,16 @@ Bool VG_(get_line) ( Int fd, Char* buf, Int nBuf ) (fun: or obj:) part. Returns False if failed. */ -static Bool setLocationTy ( Char** p_caller, SuppLocTy* p_ty ) +static Bool setLocationTy ( SuppLoc* p ) { - if (VG_(strncmp)(*p_caller, "fun:", 4) == 0) { - (*p_caller) += 4; - *p_ty = FunName; + if (VG_(strncmp)(p->name, "fun:", 4) == 0) { + p->name += 4; + p->ty = FunName; return True; } - if (VG_(strncmp)(*p_caller, "obj:", 4) == 0) { - (*p_caller) += 4; - *p_ty = ObjName; + if (VG_(strncmp)(p->name, "obj:", 4) == 0) { + p->name += 4; + p->ty = ObjName; return True; } VG_(printf)("location should start with fun: or obj:\n"); @@ -787,10 +796,12 @@ static void load_one_suppressions_file ( Char* filename ) { # define N_BUF 200 Int fd, i; - Bool eof, too_many_contexts = False; + Bool eof; Char buf[N_BUF+1]; Char* tool_names; Char* supp_name; + Char* err_str = NULL; + SuppLoc tmp_callers[VG_MAX_SUPP_CALLERS]; fd = VG_(open)( filename, VKI_O_RDONLY, 0 ); if (fd < 0) { @@ -799,32 +810,42 @@ static void load_one_suppressions_file ( Char* filename ) VG_(exit)(1); } +#define BOMB(S) { err_str = S; goto syntax_error; } + while (True) { /* Assign and initialise the two suppression halves (core and tool) */ Supp* supp; supp = VG_(arena_malloc)(VG_AR_CORE, sizeof(Supp)); supp->count = 0; - for (i = 0; i < VG_N_SUPP_CALLERS; i++) supp->caller[i] = NULL; + + // Initialise temporary reading-in buffer. + for (i = 0; i < VG_MAX_SUPP_CALLERS; i++) { + tmp_callers[i].ty = NoName; + tmp_callers[i].name = NULL; + } + supp->string = supp->extra = NULL; eof = VG_(get_line) ( fd, buf, N_BUF ); if (eof) break; - if (!VG_STREQ(buf, "{")) goto syntax_error; + if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file"); eof = VG_(get_line) ( fd, buf, N_BUF ); - if (eof || VG_STREQ(buf, "}")) goto syntax_error; + + if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'"); + supp->sname = VG_(arena_strdup)(VG_AR_CORE, buf); eof = VG_(get_line) ( fd, buf, N_BUF ); - if (eof) goto syntax_error; + if (eof) BOMB("unexpected end-of-file"); /* Check it has the "tool1,tool2,...:supp" form (look for ':') */ i = 0; while (True) { if (buf[i] == ':') break; - if (buf[i] == '\0') goto syntax_error; + if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line"); i++; } buf[i] = '\0'; /* Replace ':', splitting into two strings */ @@ -832,31 +853,29 @@ static void load_one_suppressions_file ( Char* filename ) tool_names = & buf[0]; supp_name = & buf[i+1]; - /* Is it a core suppression? */ if (VG_(needs).core_errors && tool_name_present("core", tool_names)) { + // A core suppression if (VG_STREQ(supp_name, "PThread")) supp->skind = PThreadSupp; else - goto syntax_error; + BOMB("unknown core suppression type"); } - - /* Is it a tool suppression? */ else if (VG_(needs).tool_errors && tool_name_present(VG_(details).name, tool_names)) { - if (TL_(recognised_suppression)(supp_name, supp)) - { + // A tool suppression + if (TL_(recognised_suppression)(supp_name, supp)) { /* Do nothing, function fills in supp->skind */ - } else - goto syntax_error; + } else { + BOMB("unknown tool suppression type"); + } } - else { - /* Ignore rest of suppression */ + // Ignore rest of suppression while (True) { eof = VG_(get_line) ( fd, buf, N_BUF ); - if (eof) goto syntax_error; + if (eof) BOMB("unexpected end-of-file"); if (VG_STREQ(buf, "}")) break; } @@ -864,32 +883,46 @@ static void load_one_suppressions_file ( Char* filename ) } if (VG_(needs).tool_errors && - !TL_(read_extra_suppression_info)(fd, buf, N_BUF, supp)) - goto syntax_error; + !TL_(read_extra_suppression_info)(fd, buf, N_BUF, supp)) + { + BOMB("bad or missing extra suppression info"); + } - /* "i > 0" ensures at least one caller read. */ - for (i = 0; i <= VG_N_SUPP_CALLERS; i++) { + i = 0; + while (True) { eof = VG_(get_line) ( fd, buf, N_BUF ); - if (eof) goto syntax_error; - if (i > 0 && VG_STREQ(buf, "}")) - break; - if (i == VG_N_SUPP_CALLERS) + if (eof) + BOMB("unexpected end-of-file"); + if (VG_STREQ(buf, "}")) { + if (i > 0) { + break; + } else { + BOMB("missing stack trace"); + } + } + if (i == VG_MAX_SUPP_CALLERS) + BOMB("too many callers in stack trace"); + if (i > 0 && i >= VG_(clo_backtrace_size)) break; - supp->caller[i] = VG_(arena_strdup)(VG_AR_CORE, buf); - if (!setLocationTy(&(supp->caller[i]), &(supp->caller_ty[i]))) - goto syntax_error; + tmp_callers[i].name = VG_(arena_strdup)(VG_AR_CORE, buf); + if (!setLocationTy(&(tmp_callers[i]))) + BOMB("location should start with 'fun:' or 'obj:'"); + i++; } - /* make sure to grab the '}' if the num callers is >= - VG_N_SUPP_CALLERS */ + // If the num callers is >= VG_(clo_backtrace_size), ignore any extra + // lines and grab the '}'. if (!VG_STREQ(buf, "}")) { - // Don't just ignore extra lines -- abort. (Someone complained - // about silent ignoring of lines in bug #77922.) - //do { - // eof = VG_(get_line) ( fd, buf, N_BUF ); - //} while (!eof && !VG_STREQ(buf, "}")); - too_many_contexts = True; - goto syntax_error; + do { + eof = VG_(get_line) ( fd, buf, N_BUF ); + } while (!eof && !VG_STREQ(buf, "}")); + } + + // Copy tmp_callers[] into supp->callers[] + supp->n_callers = i; + supp->callers = VG_(arena_malloc)(VG_AR_CORE, i*sizeof(SuppLoc)); + for (i = 0; i < supp->n_callers; i++) { + supp->callers[i] = tmp_callers[i]; } supp->next = vg_suppressions; @@ -899,26 +932,14 @@ static void load_one_suppressions_file ( Char* filename ) return; syntax_error: - if (eof) { - VG_(message)(Vg_UserMsg, - "FATAL: in suppressions file `%s': unexpected EOF", - filename ); - } else if (too_many_contexts) { - VG_(message)(Vg_UserMsg, - "FATAL: in suppressions file: `%s': at %s:", - filename, buf ); - VG_(message)(Vg_UserMsg, - "too many lines (limit of %d contexts in suppressions)", - VG_N_SUPP_CALLERS); - } else { - VG_(message)(Vg_UserMsg, - "FATAL: in suppressions file: `%s': syntax error on: %s", - filename, buf ); - } + VG_(message)(Vg_UserMsg, + "FATAL: in suppressions file `%s': %s", filename, err_str ); + VG_(close)(fd); VG_(message)(Vg_UserMsg, "exiting now."); VG_(exit)(1); +# undef BOMB # undef N_BUF } @@ -936,24 +957,12 @@ void VG_(load_suppressions) ( void ) } } -/* Return the name of an erring fn in a way which is useful - for comparing against the contents of a suppressions file. - Doesn't demangle the fn name, because we want to refer to - mangled names in the suppressions file. -*/ -static void get_objname_fnname ( Addr a, Char* obj_buf, Int n_obj_buf, - Char* fun_buf, Int n_fun_buf ) -{ - (void)VG_(get_objname) ( a, obj_buf, n_obj_buf ); - (void)VG_(get_fnname_nodemangle)( a, fun_buf, n_fun_buf ); -} - -static __inline__ +static Bool supp_matches_error(Supp* su, Error* err) { switch (su->skind) { case PThreadSupp: - return (err->ekind == PThreadErr); + return (err->ekind == ThreadErr || err->ekind == MutexErr); default: if (VG_(needs).tool_errors) { return TL_(error_matches_suppression)(err, su); @@ -967,22 +976,28 @@ Bool supp_matches_error(Supp* su, Error* err) } } -static __inline__ -Bool supp_matches_callers(Supp* su, Char caller_obj[][M_VG_ERRTXT], - Char caller_fun[][M_VG_ERRTXT]) +static +Bool supp_matches_callers(Error* err, Supp* su) { Int i; - - for (i = 0; i < VG_N_SUPP_CALLERS && su->caller[i] != NULL; i++) { - switch (su->caller_ty[i]) { - case ObjName: if (VG_(string_match)(su->caller[i], - caller_obj[i])) break; - return False; - case FunName: if (VG_(string_match)(su->caller[i], - caller_fun[i])) break; - return False; + Char caller_name[M_VG_ERRTXT]; + + for (i = 0; i < su->n_callers; i++) { + Addr a = err->where->ips[i]; + vg_assert(su->callers[i].name != NULL); + switch (su->callers[i].ty) { + case ObjName: + (void)VG_(get_objname)(a, caller_name, M_VG_ERRTXT); + break; + + case FunName: + // Nb: mangled names used in suppressions + (void)VG_(get_fnname_nodemangle)(a, caller_name, M_VG_ERRTXT); + break; default: VG_(tool_panic)("supp_matches_callers"); } + if (!VG_(string_match)(su->callers[i].name, caller_name)) + return False; } /* If we reach here, it's a match */ @@ -995,32 +1010,13 @@ Bool supp_matches_callers(Supp* su, Char caller_obj[][M_VG_ERRTXT], */ static Supp* is_suppressible_error ( Error* err ) { - Int i; - - static Char caller_obj[VG_N_SUPP_CALLERS][M_VG_ERRTXT]; - static Char caller_fun[VG_N_SUPP_CALLERS][M_VG_ERRTXT]; - Supp* su; - /* get_objname_fnname() writes the function name and object name if - it finds them in the debug info. So the strings in the suppression - file should match these. - */ - - /* Initialise these strs so they are always safe to compare, even - if get_objname_fnname doesn't write anything to them. */ - for (i = 0; i < VG_N_SUPP_CALLERS; i++) - caller_obj[i][0] = caller_fun[i][0] = 0; - - for (i = 0; i < VG_N_SUPP_CALLERS && i < VG_(clo_backtrace_size); i++) { - get_objname_fnname ( err->where->ips[i], caller_obj[i], M_VG_ERRTXT, - caller_fun[i], M_VG_ERRTXT ); - } - /* See if the error context matches any suppression. */ for (su = vg_suppressions; su != NULL; su = su->next) { if (supp_matches_error(su, err) && - supp_matches_callers(su, caller_obj, caller_fun)) { + supp_matches_callers(err, su)) + { return su; } } @@ -1028,5 +1024,5 @@ static Supp* is_suppressible_error ( Error* err ) } /*--------------------------------------------------------------------*/ -/*--- end vg_errcontext.c ---*/ +/*--- end ---*/ /*--------------------------------------------------------------------*/ diff --git a/coregrind/vg_execontext.c b/coregrind/vg_execontext.c index 72734838e8..295ada2030 100644 --- a/coregrind/vg_execontext.c +++ b/coregrind/vg_execontext.c @@ -159,6 +159,7 @@ Bool VG_(eq_ExeContext) ( VgRes res, ExeContext* e1, ExeContext* e2 ) static UInt stack_snapshot2 ( Addr* ips, UInt n_ips, Addr ip, Addr fp, Addr fp_min, Addr fp_max_orig ) { + static const Bool debug = False; Int i; Addr fp_max; UInt n_found = 0; @@ -181,6 +182,10 @@ static UInt stack_snapshot2 ( Addr* ips, UInt n_ips, Addr ip, Addr fp, fp_max = (fp_max_orig + VKI_PAGE_SIZE - 1) & ~(VKI_PAGE_SIZE - 1); fp_max -= sizeof(Addr); + if (debug) + VG_(printf)("n_ips=%d fp_min=%p fp_max_orig=%p, fp_max=%p ip=%p fp=%p\n", + n_ips, fp_min, fp_max_orig, fp_max, ip, fp); + /* Assertion broken before main() is reached in pthreaded programs; the * offending stack traces only have one item. --njn, 2002-aug-16 */ /* vg_assert(fp_min <= fp_max);*/ @@ -197,7 +202,8 @@ static UInt stack_snapshot2 ( Addr* ips, UInt n_ips, Addr ip, Addr fp, fp = FIRST_STACK_FRAME(fp); for (i = 1; i < n_ips; i++) { if (!(fp_min <= fp && fp <= fp_max)) { - //VG_(printf)("... out of range %p\n", fp); + if (debug) + VG_(printf)("... out of range %p\n", fp); break; /* fp gone baaaad */ } // NJN 2002-sep-17: monotonicity doesn't work -- gives wrong traces... @@ -207,7 +213,8 @@ static UInt stack_snapshot2 ( Addr* ips, UInt n_ips, Addr ip, Addr fp, // } ips[i] = STACK_FRAME_RET(fp); /* ret addr */ fp = STACK_FRAME_NEXT(fp); /* old fp */ - //VG_(printf)(" %p\n", ips[i]); + if (debug) + VG_(printf)(" ips[%d]=%08p\n", i, ips[i]); } } n_found = i; @@ -305,6 +312,7 @@ ExeContext* VG_(get_ExeContext2) ( Addr ip, Addr fp, void get_needed_regs(ThreadId tid, Addr* ip, Addr* fp, Addr* sp, Addr* stack_highest_word) { + /* thread in thread table */ ThreadState* tst = & VG_(threads)[ tid ]; *ip = INSTR_PTR(tst->arch); *fp = FRAME_PTR(tst->arch); @@ -322,11 +330,14 @@ void get_needed_regs(ThreadId tid, Addr* ip, Addr* fp, Addr* sp, useful. */ if (*ip >= VG_(client_trampoline_code)+VG_(tramp_syscall_offset) && *ip < VG_(client_trampoline_code)+VG_(trampoline_code_length) && - VG_(is_addressable)(*sp, sizeof(Addr))) { + VG_(is_addressable)(*sp, sizeof(Addr), VKI_PROT_READ)) { *ip = *(Addr *)*sp; *sp += sizeof(Addr); } #endif + if (0) + VG_(printf)("tid %d: stack_highest=%p ip=%p sp=%p fp=%p\n", + tid, *stack_highest_word, *ip, *sp, *fp); } ExeContext* VG_(get_ExeContext) ( ThreadId tid ) @@ -360,6 +371,15 @@ Addr VG_(get_EIP) ( ThreadId tid ) return INSTR_PTR(VG_(threads)[ tid ].arch); } +Addr VG_(get_thread_stack_pointer) ( ThreadId tid ) +{ + Addr ret; + + ret = STACK_PTR(VG_(threads)[ tid ].arch); + + return ret; +} + /*--------------------------------------------------------------------*/ /*--- end ---*/ /*--------------------------------------------------------------------*/ diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c index 46d3683b68..3048e8d318 100644 --- a/coregrind/vg_main.c +++ b/coregrind/vg_main.c @@ -45,6 +45,8 @@ #include #include +#include "memcheck/memcheck.h" + #ifndef AT_DCACHEBSIZE #define AT_DCACHEBSIZE 19 #endif /* AT_DCACHEBSIZE */ @@ -122,11 +124,11 @@ const Char *VG_(libdir) = VG_LIBDIR; static Int vg_argc; static Char **vg_argv; -/* PID of the main thread */ -Int VG_(main_pid); - -/* PGRP of process */ -Int VG_(main_pgrp); +/* The master thread the one which will be responsible for mopping + everything up at exit. Normally it is tid 1, since that's the + first thread created, but it may be something else after a + fork(). */ +ThreadId VG_(master_tid) = VG_INVALID_THREADID; /* Application-visible file descriptor limits */ Int VG_(fd_soft_limit) = -1; @@ -191,6 +193,8 @@ static void print_all_stats ( void ) VG_(sanity_check_malloc_all)(); VG_(print_all_arena_stats)(); VG_(message)(Vg_DebugMsg, ""); + //VG_(print_shadow_stats)(); + VG_(message)(Vg_DebugMsg, ""); VG_(message)(Vg_DebugMsg, "------ Valgrind's ExeContext management stats follow ------" ); VG_(print_ExeContext_stats)(); @@ -326,21 +330,12 @@ 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 */ -int scan_auxv(void* init_sp) +static int scan_auxv(void* init_sp) { const struct ume_auxv *auxv = find_auxv((UWord*)init_sp); int padfile = -1, found = 0; @@ -641,23 +636,29 @@ static void get_command_line( int argc, char** argv, cl_argv = argv; } else { + Bool noaugment = False; + /* Count the arguments on the command line. */ vg_argv0 = argv; for (vg_argc0 = 1; vg_argc0 < argc; vg_argc0++) { - if (argv[vg_argc0][0] != '-') /* exe name */ + Char* arg = argv[vg_argc0]; + if (arg[0] != '-') /* exe name */ break; - if (VG_STREQ(argv[vg_argc0], "--")) { /* dummy arg */ + if (VG_STREQ(arg, "--")) { /* dummy arg */ vg_argc0++; break; } + VG_BOOL_CLO("--command-line-only", noaugment) } cl_argv = &argv[vg_argc0]; /* Get extra args from VALGRIND_OPTS and .valgrindrc files. Note we don't do this if getting args from VALGRINDCLO, as - those extra args will already be present in VALGRINDCLO. */ - augment_command_line(&vg_argc0, &vg_argv0); + those extra args will already be present in VALGRINDCLO. + (We also don't do it when --command-line-only=yes.) */ + if (!noaugment) + augment_command_line(&vg_argc0, &vg_argv0); } if (0) { @@ -715,19 +716,11 @@ static Bool scan_colsep(char *colsep, Bool (*func)(const char *)) return False; } -static Bool contains(const char *p) { - if (VG_STREQ(p, VG_(libdir))) { - return True; - } - return False; -} - /* 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 + LD_PRELOAD=$VALGRINDLIB/vg_inject.so:($VALGRINDLIB/vgpreload_TOOL.so:)?$LD_PRELOAD - If any of these is missing, then it is added. + If this is missing, then it is added. Yummy. String hacking in C. @@ -737,14 +730,11 @@ static Bool contains(const char *p) { 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)); @@ -772,7 +762,7 @@ static char **fix_environment(char **origenv, const char *preload) envc++; /* Allocate a new space */ - ret = malloc(sizeof(char *) * (envc+3+1)); /* 3 new entries + NULL */ + ret = malloc(sizeof(char *) * (envc+1+1)); /* 1 new entry + NULL */ vg_assert(ret); /* copy it over */ @@ -784,25 +774,7 @@ static char **fix_environment(char **origenv, const char *preload) /* 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) { - /* 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) */ - if (!scan_colsep(*cpp + ld_library_path_len, contains)) { - int len = strlen(*cpp) + vgliblen*2 + 16; - char *cp = malloc(len); - vg_assert(cp); - - 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) { + if (memcmp(*cpp, ld_preload, ld_preload_len) == 0) { int len = strlen(*cpp) + inject_path_len; char *cp = malloc(len); vg_assert(cp); @@ -819,17 +791,6 @@ static char **fix_environment(char **origenv, const char *preload) } /* Add the missing bits */ - - if (!ld_library_path_done) { - int len = ld_library_path_len + vgliblen*2 + 16; - char *cp = malloc(len); - vg_assert(cp); - - 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); @@ -841,13 +802,13 @@ static char **fix_environment(char **origenv, const char *preload) ret[envc++] = cp; } + free(inject_path); ret[envc] = NULL; return ret; } extern char **environ; /* our environment */ -//#include /* Add a string onto the string table, and return its address */ static char *copy_str(char **tab, const char *str) @@ -1053,10 +1014,7 @@ static Addr setup_client_stack(void* init_sp, break; case AT_BASE: - if (info->interp_base == 0) - auxv->a_type = AT_IGNORE; - else - auxv->u.a_val = info->interp_base; + auxv->u.a_val = info->interp_base; break; case AT_PLATFORM: /* points to a platform description string */ @@ -1092,7 +1050,7 @@ static Addr setup_client_stack(void* init_sp, 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 + need LD_PRELOAD to work for the client, we set AT_SECURE to 0. */ auxv->u.a_val = 0; break; @@ -1219,7 +1177,7 @@ 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; + int len = strlen(VG_(libdir)) + strlen(toolname) + 16; char buf[len]; void* handle; ToolInfo* toolinfo; @@ -1324,15 +1282,6 @@ void VG_(bad_option) ( Char* opt ) VG_(exit)(1); } -static void missing_tool_option ( void ) -{ - abort_msg(); - VG_(printf)("valgrind: Missing --tool option\n"); - list_tools(); - VG_(printf)("valgrind: Use --help for more information.\n"); - VG_(exit)(1); -} - static void missing_prog ( void ) { abort_msg(); @@ -1441,7 +1390,7 @@ void as_unpad(void *start, void *end, int padfile) killpad_extra extra; int res; - vg_assert(padfile > 0); + vg_assert(padfile >= 0); res = fstat(padfile, &padstat); vg_assert(0 == res); @@ -1492,10 +1441,11 @@ Int VG_(clo_trace_notbelow) = 0; Bool VG_(clo_trace_syscalls) = False; Bool VG_(clo_trace_signals) = False; Bool VG_(clo_trace_symtab) = False; +Bool VG_(clo_trace_redir) = False; Bool VG_(clo_trace_sched) = False; -Int VG_(clo_trace_pthread_level) = 0; +Bool VG_(clo_trace_pthreads) = False; Int VG_(clo_dump_error) = 0; -Int VG_(clo_backtrace_size) = 4; +Int VG_(clo_backtrace_size) = 12; Char* VG_(clo_weird_hacks) = NULL; Bool VG_(clo_run_libc_freeres) = True; Bool VG_(clo_track_fds) = False; @@ -1503,18 +1453,10 @@ Bool VG_(clo_show_below_main) = False; Bool VG_(clo_pointercheck) = True; Bool VG_(clo_support_elan3) = False; Bool VG_(clo_branchpred) = False; +Bool VG_(clo_model_pthreads) = False; static Bool VG_(clo_wait_for_gdb) = False; -/* If we're doing signal routing, poll for signals every 50mS by - default. */ -Int VG_(clo_signal_polltime) = 50; - -/* These flags reduce thread wakeup latency on syscall completion and - signal delivery, respectively. The downside is possible unfairness. */ -Bool VG_(clo_lowlat_syscalls) = False; /* low-latency syscalls */ -Bool VG_(clo_lowlat_signals) = False; /* low-latency signals */ - void usage ( Bool debug_help ) { @@ -1522,7 +1464,7 @@ void usage ( Bool debug_help ) "usage: valgrind --tool= [options] prog-and-args\n" "\n" " common user options for all Valgrind tools, with defaults in [ ]:\n" -" --tool= use the Valgrind tool named \n" +" --tool= use the Valgrind tool named [memcheck]\n" " -h --help show this message\n" " --help-debug show this message, plus debugging options\n" " --version show version\n" @@ -1534,10 +1476,7 @@ void usage ( Bool debug_help ) "\n" " uncommon user options for all Valgrind tools:\n" " --run-libc-freeres=no|yes free up glibc memory at exit? [yes]\n" -" --weird-hacks=hack1,hack2,... recognised hacks: lax-ioctls [none]\n" -" --signal-polltime=