You can subscribe to this list here.
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(122) |
Nov
(152) |
Dec
(69) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2003 |
Jan
(6) |
Feb
(25) |
Mar
(73) |
Apr
(82) |
May
(24) |
Jun
(25) |
Jul
(10) |
Aug
(11) |
Sep
(10) |
Oct
(54) |
Nov
(203) |
Dec
(182) |
| 2004 |
Jan
(307) |
Feb
(305) |
Mar
(430) |
Apr
(312) |
May
(187) |
Jun
(342) |
Jul
(487) |
Aug
(637) |
Sep
(336) |
Oct
(373) |
Nov
(441) |
Dec
(210) |
| 2005 |
Jan
(385) |
Feb
(480) |
Mar
(636) |
Apr
(544) |
May
(679) |
Jun
(625) |
Jul
(810) |
Aug
(838) |
Sep
(634) |
Oct
(521) |
Nov
(965) |
Dec
(543) |
| 2006 |
Jan
(494) |
Feb
(431) |
Mar
(546) |
Apr
(411) |
May
(406) |
Jun
(322) |
Jul
(256) |
Aug
(401) |
Sep
(345) |
Oct
(542) |
Nov
(308) |
Dec
(481) |
| 2007 |
Jan
(427) |
Feb
(326) |
Mar
(367) |
Apr
(255) |
May
(244) |
Jun
(204) |
Jul
(223) |
Aug
(231) |
Sep
(354) |
Oct
(374) |
Nov
(497) |
Dec
(362) |
| 2008 |
Jan
(322) |
Feb
(482) |
Mar
(658) |
Apr
(422) |
May
(476) |
Jun
(396) |
Jul
(455) |
Aug
(267) |
Sep
(280) |
Oct
(253) |
Nov
(232) |
Dec
(304) |
| 2009 |
Jan
(486) |
Feb
(470) |
Mar
(458) |
Apr
(423) |
May
(696) |
Jun
(461) |
Jul
(551) |
Aug
(575) |
Sep
(134) |
Oct
(110) |
Nov
(157) |
Dec
(102) |
| 2010 |
Jan
(226) |
Feb
(86) |
Mar
(147) |
Apr
(117) |
May
(107) |
Jun
(203) |
Jul
(193) |
Aug
(238) |
Sep
(300) |
Oct
(246) |
Nov
(23) |
Dec
(75) |
| 2011 |
Jan
(133) |
Feb
(195) |
Mar
(315) |
Apr
(200) |
May
(267) |
Jun
(293) |
Jul
(353) |
Aug
(237) |
Sep
(278) |
Oct
(611) |
Nov
(274) |
Dec
(260) |
| 2012 |
Jan
(303) |
Feb
(391) |
Mar
(417) |
Apr
(441) |
May
(488) |
Jun
(655) |
Jul
(590) |
Aug
(610) |
Sep
(526) |
Oct
(478) |
Nov
(359) |
Dec
(372) |
| 2013 |
Jan
(467) |
Feb
(226) |
Mar
(391) |
Apr
(281) |
May
(299) |
Jun
(252) |
Jul
(311) |
Aug
(352) |
Sep
(481) |
Oct
(571) |
Nov
(222) |
Dec
(231) |
| 2014 |
Jan
(185) |
Feb
(329) |
Mar
(245) |
Apr
(238) |
May
(281) |
Jun
(399) |
Jul
(382) |
Aug
(500) |
Sep
(579) |
Oct
(435) |
Nov
(487) |
Dec
(256) |
| 2015 |
Jan
(338) |
Feb
(357) |
Mar
(330) |
Apr
(294) |
May
(191) |
Jun
(108) |
Jul
(142) |
Aug
(261) |
Sep
(190) |
Oct
(54) |
Nov
(83) |
Dec
(22) |
| 2016 |
Jan
(49) |
Feb
(89) |
Mar
(33) |
Apr
(50) |
May
(27) |
Jun
(34) |
Jul
(53) |
Aug
(53) |
Sep
(98) |
Oct
(206) |
Nov
(93) |
Dec
(53) |
| 2017 |
Jan
(65) |
Feb
(82) |
Mar
(102) |
Apr
(86) |
May
(187) |
Jun
(67) |
Jul
(23) |
Aug
(93) |
Sep
(65) |
Oct
(45) |
Nov
(35) |
Dec
(17) |
| 2018 |
Jan
(26) |
Feb
(35) |
Mar
(38) |
Apr
(32) |
May
(8) |
Jun
(43) |
Jul
(27) |
Aug
(30) |
Sep
(43) |
Oct
(42) |
Nov
(38) |
Dec
(67) |
| 2019 |
Jan
(32) |
Feb
(37) |
Mar
(53) |
Apr
(64) |
May
(49) |
Jun
(18) |
Jul
(14) |
Aug
(53) |
Sep
(25) |
Oct
(30) |
Nov
(49) |
Dec
(31) |
| 2020 |
Jan
(87) |
Feb
(45) |
Mar
(37) |
Apr
(51) |
May
(99) |
Jun
(36) |
Jul
(11) |
Aug
(14) |
Sep
(20) |
Oct
(24) |
Nov
(40) |
Dec
(23) |
| 2021 |
Jan
(14) |
Feb
(53) |
Mar
(85) |
Apr
(15) |
May
(19) |
Jun
(3) |
Jul
(14) |
Aug
(1) |
Sep
(57) |
Oct
(73) |
Nov
(56) |
Dec
(22) |
| 2022 |
Jan
(3) |
Feb
(22) |
Mar
(6) |
Apr
(55) |
May
(46) |
Jun
(39) |
Jul
(15) |
Aug
(9) |
Sep
(11) |
Oct
(34) |
Nov
(20) |
Dec
(36) |
| 2023 |
Jan
(79) |
Feb
(41) |
Mar
(99) |
Apr
(169) |
May
(48) |
Jun
(16) |
Jul
(16) |
Aug
(57) |
Sep
(19) |
Oct
|
Nov
|
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
|
|
|
|
|
|
1
(4) |
|
2
(5) |
3
(3) |
4
(3) |
5
(7) |
6
(7) |
7
(9) |
8
(10) |
|
9
(12) |
10
(26) |
11
(9) |
12
(6) |
13
(7) |
14
(15) |
15
(25) |
|
16
(20) |
17
(32) |
18
(11) |
19
(19) |
20
(22) |
21
(6) |
22
(8) |
|
23
(16) |
24
(25) |
25
(11) |
26
(16) |
27
(12) |
28
(15) |
29
(11) |
|
30
(5) |
31
(8) |
|
|
|
|
|
|
From: Eyal L. <ey...@ey...> - 2005-01-15 11:56:20
|
Jeremy Fitzhardinge wrote: [trim] > So the real question is why there's an assertion failure? > > Are you positive that your processes are not crashing like this outside > of Valgrind? Yes, it works just fine. The crash happens when the server is starting, and the plain run has no problems running about 300 regression tests (some rather elaborate). To make it simple, I am attaching a small program that demonstrates the problem. I posted it to the list a while ago, but it never hurts to do it again. This should make it easier to diagnose and (hopefully) fix. -- Eyal Lebedinsky (ey...@ey...) <http://samba.org/eyal/> If attaching .zip rename to .dat |
|
From: Jeremy F. <je...@go...> - 2005-01-15 11:17:25
|
On Sat, 2005-01-15 at 20:59 +1100, Eyal Lebedinsky wrote: > SYSCALL[29282,2](120) special:sys_clone ( 1200011, 0x0, 0x0, 0x0, 0x1D190BF8 )sys_fork ( ) fork: process 29282 created child 29303 > --> 0 (0x0) > --> 29303 (0x7277) > SYSCALL[29282,2]( 7) mayBlock:sys_waitpid ( 29303, 0x1D1909B4, 0 ) --> ... > SYSCALL[29303,2]( 4) mayBlock:sys_write ( 2, 0x1BFC3378, 635 ) --> ... > SYSCALL[29303,2]( 4) --> 635 (0x27B) > SYSCALL[29303,2](175) special:sys_rt_sigprocmask ( 1, 0x1D1906A4, 0x0, 8 ) --> 0 (0x0) > SYSCALL[29303,2](270):sys_tgkill ( 29282, 29300, 6 )==2005-01-15 20:56:02.227 29282== This looks like an assertion failure in the child process very shortly after a fork. It kills threadgroup 29282. > ==2005-01-15 20:56:02.227 29282== Process terminating with default action of signal 6 (SIGABRT) > ==2005-01-15 20:56:02.228 29282== at 0x1BE59511: (within /lib/tls/libpthread-0.60.so) > ==2005-01-15 20:56:02.228 29282== > ==2005-01-15 20:56:02.228 29282== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 25 from 1) > ==2005-01-15 20:56:02.228 29282== malloc/free: in use at exit: 10008 bytes in 26 blocks. > ==2005-01-15 20:56:02.228 29282== malloc/free: 34 allocs, 8 frees, 14241 bytes allocated. > ==2005-01-15 20:56:02.228 29282== For counts of detected errors, rerun with: -v > ==2005-01-15 20:56:02.228 29282== searching for pointers to 26 not-freed blocks. > ==2005-01-15 20:56:02.489 29282== checked 24775060 bytes. > ==2005-01-15 20:56:02.490 29282== > ==2005-01-15 20:56:02.490 29282== 68 bytes in 1 blocks are possibly lost in loss record 4 of 16 > ==2005-01-15 20:56:02.490 29282== at 0x1B906FE5: calloc (vg_replace_malloc.c:175) > ==2005-01-15 20:56:02.490 29282== by 0x1B8F25A8: (within /lib/ld-2.3.2.so) > ==2005-01-15 20:56:02.490 29282== by 0x1B8F287B: _dl_allocate_tls (in /lib/ld-2.3.2.so) > ==2005-01-15 20:56:02.490 29282== by 0x1BE5424A: allocate_stack (in /lib/tls/libpthread-0.60.so) > ==2005-01-15 20:56:02.490 29282== by 0x1BE53C54: pthread_create@@GLIBC_2.1 (in /lib/tls/libpthread-0.60.so) > ==2005-01-15 20:56:02.490 29282== by 0x1BD1CC1F: ??? (thread.c:793) > ==2005-01-15 20:56:02.490 29282== by 0x1BD1DD18: skthcr (thread.c:1401) > ==2005-01-15 20:56:02.490 29282== by 0x1BCFA06B: skmain (main.c:1237) > ==2005-01-15 20:56:02.490 29282== by 0x804A4B9: main (ssan3sv.c:319) > ==2005-01-15 20:56:02.490 29282== > ==2005-01-15 20:56:02.490 29282== > ==2005-01-15 20:56:02.490 29282== 268 bytes in 1 blocks are definitely lost in loss record 7 of 16 > ==2005-01-15 20:56:02.490 29282== at 0x1B9065C1: malloc (vg_replace_malloc.c:130) > ==2005-01-15 20:56:02.490 29282== by 0x1BD37D95: suwmal (malloc.c:46) > ==2005-01-15 20:56:02.490 29282== by 0x1BCF7579: ??? (log.c:298) > ==2005-01-15 20:56:02.490 29282== by 0x1BCF78D0: sksetp (log.c:520) > ==2005-01-15 20:56:02.490 29282== by 0x1BD033A2: skredi (redir.c:217) > ==2005-01-15 20:56:02.490 29282== by 0x1BCF9E20: skmain (main.c:1124) > ==2005-01-15 20:56:02.490 29282== by 0x804A4B9: main (ssan3sv.c:319) > ==2005-01-15 20:56:02.490 29282== > ==2005-01-15 20:56:02.490 29282== LEAK SUMMARY: > ==2005-01-15 20:56:02.490 29282== definitely lost: 268 bytes in 1 blocks. > ==2005-01-15 20:56:02.490 29282== possibly lost: 68 bytes in 1 blocks. > ==2005-01-15 20:56:02.490 29282== still reachable: 9672 bytes in 24 blocks. > ==2005-01-15 20:56:02.490 29282== suppressed: 0 bytes in 0 blocks. > ==2005-01-15 20:56:02.490 29282== Reachable blocks (those to which a pointer was found) are not shown. > ==2005-01-15 20:56:02.490 29282== To see them, rerun with: --show-reachable=yes > --> 0 (0x0) > SYSCALL[29303,2](174) special:sys_rt_sigaction ( 6, 0x1D1905DC, 0x0, 8 ) --> 0 (0x0) > SYSCALL[29303,2]( 91):sys_munmap ( 0x1BE3B000, 4096 ) --> 0 (0x0) > SYSCALL[29303,2](270):sys_tgkill ( 29282, 29300, 6 ) --> 0 (0x0) And this looks like a bug, but I'm not sure whose. 29303, the process created by the fork(), it trying to send itself SIGABRT with tgkill, after (presumably) using sigaction to set SIGABRT to SIG_DFL. But it's using the threadgroup id of its parent along with its own pid, which should cause it to fail with ESRCH. It fails to do the kill, because there's no pending SIGABRT, but the syscall doesn't return an error code. So, it could be a libc bug (for using a bad tgkill after fork()), a Valgrind bug (for confusing the client into using a bad tgkill), and/or a kernel bug (for not making tgkill return an error code when it should). Because the SIGABRT doesn't get delivered to 29303, it carries on to the following instruction, which is hlt, and so this crash. So the real question is why there's an assertion failure? Are you positive that your processes are not crashing like this outside of Valgrind? > --2005-01-15 20:56:02.496 29303-- disInstr: unhandled instruction bytes: 0xF4 0xEB 0xDE 0xC7 > --2005-01-15 20:56:02.496 29303-- at 0x1BEB1E23: abort (in /lib/tls/libc-2.3.2.so) > ==2005-01-15 20:56:02.496 29303== > ==2005-01-15 20:56:02.496 29303== Process terminating with default action of signal 4 (SIGILL) > ==2005-01-15 20:56:02.496 29303== Illegal operand at address 0xB00896F0 > ==2005-01-15 20:56:02.496 29303== at 0x1BEB1E23: abort (in /lib/tls/libc-2.3.2.so) > ==2005-01-15 20:56:02.496 29303== > ==2005-01-15 20:56:02.496 29303== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 25 from 1) > ==2005-01-15 20:56:02.496 29303== malloc/free: in use at exit: 10008 bytes in 26 blocks. > ==2005-01-15 20:56:02.496 29303== malloc/free: 38 allocs, 12 frees, 15977 bytes allocated. > ==2005-01-15 20:56:02.496 29303== For counts of detected errors, rerun with: -v > ==2005-01-15 20:56:02.496 29303== searching for pointers to 26 not-freed blocks. > [29267] end: Sat Jan 15 20:56:02 EST 2005 > ==2005-01-15 20:56:02.665 29303== checked 24771384 bytes. > ==2005-01-15 20:56:02.665 29303== > ==2005-01-15 20:56:02.665 29303== 68 bytes in 1 blocks are possibly lost in loss record 4 of 16 > ==2005-01-15 20:56:02.665 29303== at 0x1B906FE5: calloc (vg_replace_malloc.c:175) > ==2005-01-15 20:56:02.665 29303== by 0x1B8F25A8: (within /lib/ld-2.3.2.so) > ==2005-01-15 20:56:02.665 29303== by 0x1B8F287B: _dl_allocate_tls (in /lib/ld-2.3.2.so) > ==2005-01-15 20:56:02.665 29303== by 0x1BE5424A: allocate_stack (in /lib/tls/libpthread-0.60.so) > ==2005-01-15 20:56:02.665 29303== by 0x1BE53C54: pthread_create@@GLIBC_2.1 (in /lib/tls/libpthread-0.60.so) > ==2005-01-15 20:56:02.665 29303== by 0x1BD1CC1F: ??? (thread.c:793) > ==2005-01-15 20:56:02.665 29303== by 0x1BD1DD18: skthcr (thread.c:1401) > ==2005-01-15 20:56:02.665 29303== by 0x1BCFA06B: skmain (main.c:1237) > ==2005-01-15 20:56:02.665 29303== by 0x804A4B9: main (ssan3sv.c:319) > ==2005-01-15 20:56:02.665 29303== > ==2005-01-15 20:56:02.665 29303== > ==2005-01-15 20:56:02.665 29303== 268 bytes in 1 blocks are definitely lost in loss record 7 of 16 > ==2005-01-15 20:56:02.665 29303== at 0x1B9065C1: malloc (vg_replace_malloc.c:130) > ==2005-01-15 20:56:02.665 29303== by 0x1BD37D95: suwmal (malloc.c:46) > ==2005-01-15 20:56:02.665 29303== by 0x1BCF7579: ??? (log.c:298) > ==2005-01-15 20:56:02.665 29303== by 0x1BCF78D0: sksetp (log.c:520) > ==2005-01-15 20:56:02.665 29303== by 0x1BD033A2: skredi (redir.c:217) > ==2005-01-15 20:56:02.665 29303== by 0x1BCF9E20: skmain (main.c:1124) > ==2005-01-15 20:56:02.665 29303== by 0x804A4B9: main (ssan3sv.c:319) > ==2005-01-15 20:56:02.665 29303== > ==2005-01-15 20:56:02.665 29303== LEAK SUMMARY: > ==2005-01-15 20:56:02.665 29303== definitely lost: 268 bytes in 1 blocks. > ==2005-01-15 20:56:02.665 29303== possibly lost: 68 bytes in 1 blocks. > ==2005-01-15 20:56:02.665 29303== still reachable: 9672 bytes in 24 blocks. > ==2005-01-15 20:56:02.665 29303== suppressed: 0 bytes in 0 blocks. > ==2005-01-15 20:56:02.665 29303== Reachable blocks (those to which a pointer was found) are not shown. > ==2005-01-15 20:56:02.665 29303== To see them, rerun with: --show-reachable=yes J |
|
From: Tom H. <th...@cy...> - 2005-01-15 10:35:53
|
In message <200...@we...>
Naveen Kumar <g_n...@ya...> wrote:
> --- Jeremy Fitzhardinge <je...@go...> wrote:
>
> > What version are you using? Are you tracking CVS? There doesn't seem to
> > be enough in that link line; I would expect to see solaris/libos.a and
> > x86-solaris/libplatform.a there.
>
> I am working off valgrind ver 2.2.0.
That's probably a bad idea if you're working on a port - there is
a lot of infrastructure work in CVS to assist in porting.
Tom
--
Tom Hughes (th...@cy...)
Software Engineer, Cyberscience Corporation
http://www.cyberscience.com/
|
|
From: Eyal L. <ey...@ey...> - 2005-01-15 09:59:30
|
Jeremy Fitzhardinge wrote:
> On Sat, 2005-01-15 at 19:17 +1100, Eyal Lebedinsky wrote:
>
>>--2005-01-15 18:51:19.459 15031-- disInstr: unhandled instruction bytes: 0xF4 0xEB 0xDE 0xC7
>>--2005-01-15 18:51:19.459 15031-- at 0x1BEB1E23: abort (in /lib/tls/libc-2.3.2.so)
>>
>>vg built off latest cvs, on Debian testing.
>>
>>$ gcc --version
>>gcc (GCC) 3.3.5 (Debian 1:3.3.5-5)
>>Copyright (C) 2003 Free Software Foundation, Inc.
>>This is free software; see the source for copying conditions. There is NO
>>warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>
>
> This looks like
> hlt
> jmp -34
>
> Hm, and since it's in abort(), perhaps its deliberately doing it to kill
> itself.
>
> Hm, but it does suggest it failed to kill itself with SIGABRT first.
>
> What does running with --trace-syscalls=yes or --trace-signals=yes say?
Running as follows, log attached.
valgrind --tool=memcheck \
--leak-check=yes \
--show-reachable=no \
--num-callers=32 \
--error-limit=no \
--run-libc-freeres=no \
--trace-syscalls=yes \
The executable is a server. When launched if immediately forks itself
and the parent only takes care of restarting the child if it dies. It
seems as if the child died just after launch and the parents exited
clean.
Naturally, there are a number of threads running even when the server
is idle. For example, my main() is actually a thread, the real main
that crt calls is practically empty, doing just a thread_create and
_join.
I should say that I avoided using cvs for a few months now since I
had problems spawning processes (I follow branch 2.2.0). I decided
to give head a try after reading of the progress done in the
threading area.
--
Eyal Lebedinsky (ey...@ey...) <http://samba.org/eyal/>
If attaching .zip rename to .dat
|
|
From: Jeremy F. <je...@go...> - 2005-01-15 09:16:35
|
On Sat, 2005-01-15 at 19:17 +1100, Eyal Lebedinsky wrote: > --2005-01-15 18:51:19.459 15031-- disInstr: unhandled instruction bytes: 0xF4 0xEB 0xDE 0xC7 > --2005-01-15 18:51:19.459 15031-- at 0x1BEB1E23: abort (in /lib/tls/libc-2.3.2.so) > > vg built off latest cvs, on Debian testing. > > $ gcc --version > gcc (GCC) 3.3.5 (Debian 1:3.3.5-5) > Copyright (C) 2003 Free Software Foundation, Inc. > This is free software; see the source for copying conditions. There is NO > warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. This looks like hlt jmp -34 Hm, and since it's in abort(), perhaps its deliberately doing it to kill itself. Hm, but it does suggest it failed to kill itself with SIGABRT first. What does running with --trace-syscalls=yes or --trace-signals=yes say? J |
|
From: Eyal L. <ey...@ey...> - 2005-01-15 08:17:11
|
--2005-01-15 18:51:19.459 15031-- disInstr: unhandled instruction bytes: 0xF4 0xEB 0xDE 0xC7 --2005-01-15 18:51:19.459 15031-- at 0x1BEB1E23: abort (in /lib/tls/libc-2.3.2.so) vg built off latest cvs, on Debian testing. $ gcc --version gcc (GCC) 3.3.5 (Debian 1:3.3.5-5) Copyright (C) 2003 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Any idea? -- Eyal Lebedinsky (ey...@ey...) <http://samba.org/eyal/> If attaching .zip rename to .dat |
|
From: <js...@ac...> - 2005-01-15 03:57:31
|
Nightly build on phoenix ( SuSE 9.1 ) started at 2005-01-15 03:50:00 GMT Checking out source tree ... done Configuring ... done Building ... done Running regression tests ... done Last 20 lines of log.verbose follow corecheck/tests/sigkill (stderr) helgrind/tests/allok (stderr) helgrind/tests/deadlock (stderr) helgrind/tests/inherit (stderr) helgrind/tests/race (stderr) helgrind/tests/race2 (stderr) helgrind/tests/readshared (stderr) massif/tests/toobig-allocs (stderr) massif/tests/true_html (stderr) massif/tests/true_text (stderr) memcheck/tests/pth_once (stderr) memcheck/tests/scalar (stderr) memcheck/tests/threadederrno (stderr) memcheck/tests/writev (stderr) none/tests/blockfault (stderr) none/tests/exec-sigmask (stdout) none/tests/susphello (stdout) none/tests/susphello (stderr) make: *** [regtest] Error 1 |
|
From: Jeremy F. <je...@go...> - 2005-01-15 03:26:39
|
CVS commit by fitzhardinge:
Allow the VCPU state to be examined and manipulated from within a signal
handler. Integer state is pretty easy, but FP state requires a lot of
fiddley conversion between the CPU's state and the structure passed to
the signal handler.
A none/tests/sigcontext.c 1.1 [no copyright]
A none/tests/sigcontext.stderr.exp 1.1
A none/tests/sigcontext.stdout.exp 1.1
A none/tests/sigcontext.vgtest 1.1
M +6 -12 coregrind/vg_scheduler.c 1.204
M +114 -97 coregrind/vg_signals.c 1.106
M +35 -1 coregrind/x86/core_arch.h 1.17
M +238 -67 coregrind/x86/signal.c 1.7
M +2 -2 coregrind/x86/state.c 1.14
M +5 -2 none/tests/Makefile.am 1.55
--- valgrind/coregrind/vg_signals.c #1.105:1.106
@@ -728,8 +728,7 @@ void vg_push_signal_frame ( ThreadId tid
/* Clear the signal frame created by vg_push_signal_frame, restore the
- simulated machine state, and return the signal number that the
- frame was for. */
+ simulated machine state. */
static
-Int vg_pop_signal_frame ( ThreadId tid )
+void vg_pop_signal_frame ( ThreadId tid )
{
Int sigNo = VGA_(pop_signal_frame)(tid);
@@ -737,6 +736,4 @@ Int vg_pop_signal_frame ( ThreadId tid )
/* Notify tools */
VG_TRACK( post_deliver_signal, tid, sigNo );
-
- return sigNo;
}
@@ -749,11 +746,7 @@ Int vg_pop_signal_frame ( ThreadId tid )
void VG_(signal_returns) ( ThreadId tid )
{
- Int sigNo;
-
/* Pop the signal frame and restore tid's status to what it was
before the signal was delivered. */
- sigNo = vg_pop_signal_frame(tid);
-
- vg_assert(sigNo >= 1 && sigNo <= _VKI_NSIG);
+ vg_pop_signal_frame(tid);
}
@@ -1151,7 +1144,12 @@ static void make_coredump(ThreadId tid,
continue;
- vg_assert(VG_(lseek)(core_fd, 0, VKI_SEEK_CUR) == phdrs[i].p_offset);
- if (phdrs[i].p_filesz > 0)
- VG_(write)(core_fd, (void *)seg->addr, seg->len);
+ if (phdrs[i].p_filesz > 0) {
+ Int ret;
+
+ vg_assert(VG_(lseek)(core_fd, phdrs[i].p_offset, VKI_SEEK_SET) == phdrs[i].p_offset);
+
+ vg_assert(seg->len >= phdrs[i].p_filesz);
+ ret = VG_(write)(core_fd, (void *)seg->addr, phdrs[i].p_filesz);
+ }
}
@@ -1170,6 +1168,8 @@ static void vg_default_action(const vki_
{
Int sigNo = info->si_signo;
- Bool terminate = False;
- Bool core = False;
+ Bool terminate = False; /* kills process */
+ Bool core = False; /* kills process w/ core */
+ struct vki_rlimit corelim;
+ Bool could_core;
vg_assert(VG_(is_running_thread)(tid));
@@ -1210,10 +1210,11 @@ static void vg_default_action(const vki_
if (VG_(clo_trace_signals))
- VG_(message)(Vg_DebugMsg, "delivering %d to default handler %s%s",
- sigNo, terminate ? "terminate" : "", core ? "+core" : "");
+ VG_(message)(Vg_DebugMsg, "delivering %d (code %d) to default handler %s%s",
+ sigNo, info->si_code, terminate ? "terminate" : "", core ? "+core" : "");
- if (terminate) {
- struct vki_rlimit corelim;
- Bool could_core = core;
+ if (!terminate)
+ return; /* nothing to do */
+
+ could_core = core;
if (core) {
@@ -1235,4 +1236,5 @@ static void vg_default_action(const vki_
if (info->si_code > VKI_SI_USER) {
const Char *event = NULL;
+ Bool haveaddr = True;
switch(sigNo) {
@@ -1241,4 +1243,16 @@ static void vg_default_action(const vki_
case 1: event = "Access not within mapped region"; break;
case 2: event = "Bad permissions for mapped region"; break;
+ case 128:
+ /* General Protection Fault: The CPU/kernel
+ isn't telling us anything useful, but this
+ is commonly the result of exceeding a
+ segment limit, such as the one imposed by
+ --pointercheck=yes. */
+ if (VG_(clo_pointercheck))
+ event = "GPF (Pointer out of bounds?)";
+ else
+ event = "General Protection Fault";
+ haveaddr = False;
+ break;
}
break;
@@ -1279,7 +1293,11 @@ static void vg_default_action(const vki_
}
- if (event != NULL)
+ if (event != NULL) {
+ if (haveaddr)
VG_(message)(Vg_UserMsg, " %s at address %p",
event, info->_sifields._sigfault._addr);
+ else
+ VG_(message)(Vg_UserMsg, " %s", event);
+ }
}
@@ -1311,5 +1329,4 @@ static void vg_default_action(const vki_
VG_(threads)[tid].exitreason = VgSrc_FatalSig;
VG_(threads)[tid].os_state.fatalsig = sigNo;
- }
}
@@ -1534,5 +1551,5 @@ void vg_sync_signalhandler ( Int sigNo,
if (VG_(clo_trace_signals))
VG_(message)(Vg_DebugMsg,
- " -> extended stack base to %p\n", base);
+ " -> extended stack base to %p", base);
return; // extension succeeded, restart instruction
} else
--- valgrind/coregrind/vg_scheduler.c #1.203:1.204
@@ -659,4 +659,6 @@ static void handle_syscall(ThreadId tid)
SCHEDSETJMP(tid, sigcode, VG_(client_syscall)(tid));
+ vg_assert(VG_(is_running_thread)(tid));
+
switch(sigcode) {
case VgSig_None:
@@ -665,22 +667,15 @@ static void handle_syscall(ThreadId tid)
case VgSig_Exiting:
vg_assert(VG_(is_exiting)(tid));
- if (tst->status != VgTs_Runnable) {
- vg_assert(tst->status == VgTs_WaitSys);
- VG_(set_running)(tid);
- }
break;
case VgSig_AsyncSig:
case VgSig_FatalSig:
- if (tst->status != VgTs_Runnable) {
- vg_assert(tst->status == VgTs_WaitSys);
- VG_(set_running)(tid);
- }
-
if (sigcode == VgSig_FatalSig) {
/* was fatal, we're exiting */
- tst->exitreason = VgSrc_FatalSig;
+ vg_assert(VG_(is_exiting)(tid));
}
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &VG_(blocked_mask), NULL);
+
tst->siginfo.si_signo = 0; /* don't care about signal state */
break;
@@ -693,5 +688,4 @@ static void handle_syscall(ThreadId tid)
vg_assert(tst->siginfo.si_signo == 0);
- vg_assert(VG_(is_running_thread)(tid));
}
--- valgrind/coregrind/x86/core_arch.h #1.16:1.17
@@ -242,4 +242,34 @@ typedef struct _LDT_ENTRY {
#define VG_SIZE_OF_SSESTATE_W ((VG_SIZE_OF_SSESTATE+3)/4)
+#define X86_FXSR_MAGIC 0x0000
+
+struct i387_fsave_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
+ long status; /* software status information */
+};
+
+struct i387_fxsave_struct {
+ unsigned short cwd;
+ unsigned short swd;
+ unsigned short twd;
+ unsigned short fop;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long mxcsr;
+ long mxcsr_mask;
+ long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
+ long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
+ long padding[56];
+} __attribute__ ((aligned (16)));
+
// Architecture-specific part of a ThreadState
@@ -292,5 +322,9 @@ typedef struct {
fxsave/fxrestore. So we have to do it "by hand".
*/
- UInt m_sse[VG_SIZE_OF_SSESTATE_W];
+ union {
+ UInt state[VG_SIZE_OF_SSESTATE_W];
+ struct i387_fsave_struct fsave;
+ struct i387_fxsave_struct fxsave;
+ } m_sse;
UInt sh_eax;
--- valgrind/coregrind/x86/signal.c #1.6:1.7
@@ -49,5 +49,5 @@ typedef
they're the return address and the signal number. */
- /* Sig handler's (bogus) return address */
+ /* Sig handler's return address */
Addr retaddr;
/* The arg to the sig handler. We need to inspect this after
@@ -73,25 +73,18 @@ typedef
/* Sanity check word. */
UInt magicPI;
+
+ UInt handlerflags; /* flags for signal handler */
+
/* pointed to by psigInfo */
vki_siginfo_t sigInfo;
/* pointed to by puContext */
struct vki_ucontext uContext;
+ struct _vki_fpstate fpstate;
/* Safely-saved version of sigNo, as described above. */
Int sigNo_private;
- /* Saved processor state. */
- UInt m_sse[VG_SIZE_OF_SSESTATE_W];
-
- UInt m_eax;
- UInt m_ecx;
- UInt m_edx;
- UInt m_ebx;
- UInt m_ebp;
- UInt m_esp;
- UInt m_esi;
- UInt m_edi;
- UInt m_eflags;
- Addr m_eip;
+ /* XXX This is wrong. Surely we should store the shadow values
+ into the shadow memory behind the actual values? */
UInt sh_eax;
UInt sh_ebx;
@@ -107,8 +100,4 @@ typedef
vki_sigset_t mask;
- /* Scheduler-private stuff: what was the thread's status prior to
- delivering this signal? */
- ThreadStatus status;
-
/* Sanity check word. Is the highest-addressed word; do not
move!*/
@@ -121,7 +110,192 @@ typedef
/*------------------------------------------------------------*/
+/*
+ Great gobs of FP state conversion taken wholesale from
+ linux/arch/i386/kernel/i387.c
+ */
+
+/*
+ * FXSR floating point environment conversions.
+ */
+#define X86_FXSR_MAGIC 0x0000
+
+/*
+ * FPU tag word conversions.
+ */
+
+static inline unsigned short twd_i387_to_fxsr( unsigned short twd )
+{
+ unsigned int tmp; /* to avoid 16 bit prefixes in the code */
+
+ /* Transform each pair of bits into 01 (valid) or 00 (empty) */
+ tmp = ~twd;
+ tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
+ /* and move the valid bits to the lower byte. */
+ tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
+ tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
+ tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
+ return tmp;
+}
+
+static unsigned long twd_fxsr_to_i387( const struct i387_fxsave_struct *fxsave )
+{
+ struct _vki_fpxreg *st = NULL;
+ unsigned long twd = (unsigned long) fxsave->twd;
+ unsigned long tag;
+ unsigned long ret = 0xffff0000u;
+ int i;
+
+#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16);
+
+ for ( i = 0 ; i < 8 ; i++ ) {
+ if ( twd & 0x1 ) {
+ st = (struct _vki_fpxreg *) FPREG_ADDR( fxsave, i );
+
+ switch ( st->exponent & 0x7fff ) {
+ case 0x7fff:
+ tag = 2; /* Special */
+ break;
+ case 0x0000:
+ if ( !st->significand[0] &&
+ !st->significand[1] &&
+ !st->significand[2] &&
+ !st->significand[3] ) {
+ tag = 1; /* Zero */
+ } else {
+ tag = 2; /* Special */
+ }
+ break;
+ default:
+ if ( st->significand[3] & 0x8000 ) {
+ tag = 0; /* Valid */
+ } else {
+ tag = 2; /* Special */
+ }
+ break;
+ }
+ } else {
+ tag = 3; /* Empty */
+ }
+ ret |= (tag << (2 * i));
+ twd = twd >> 1;
+ }
+ return ret;
+}
+
+static void convert_fxsr_to_user( struct _vki_fpstate *buf,
+ const struct i387_fxsave_struct *fxsave )
+{
+ unsigned long env[7];
+ struct _vki_fpreg *to;
+ struct _vki_fpxreg *from;
+ int i;
+
+ env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul;
+ env[1] = (unsigned long)fxsave->swd | 0xffff0000ul;
+ env[2] = twd_fxsr_to_i387(fxsave);
+ env[3] = fxsave->fip;
+ env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
+ env[5] = fxsave->foo;
+ env[6] = fxsave->fos;
+
+ VG_(memcpy)(buf, env, 7 * sizeof(unsigned long));
+
+ to = &buf->_st[0];
+ from = (struct _vki_fpxreg *) &fxsave->st_space[0];
+ for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
+ unsigned long __user *t = (unsigned long __user *)to;
+ unsigned long *f = (unsigned long *)from;
+
+ t[0] = f[0];
+ t[1] = f[1];
+ to->exponent = from->exponent;
+ }
+}
+
+static void convert_fxsr_from_user( struct i387_fxsave_struct *fxsave,
+ const struct _vki_fpstate *buf )
+{
+ unsigned long env[7];
+ struct _vki_fpxreg *to;
+ const struct _vki_fpreg *from;
+ int i;
+
+ VG_(memcpy)(env, buf, 7 * sizeof(long));
+
+ fxsave->cwd = (unsigned short)(env[0] & 0xffff);
+ fxsave->swd = (unsigned short)(env[1] & 0xffff);
+ fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
+ fxsave->fip = env[3];
+ fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16);
+ fxsave->fcs = (env[4] & 0xffff);
+ fxsave->foo = env[5];
+ fxsave->fos = env[6];
+
+ to = (struct _vki_fpxreg *) &fxsave->st_space[0];
+ from = &buf->_st[0];
+ for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
+ unsigned long *t = (unsigned long *)to;
+ unsigned long __user *f = (unsigned long __user *)from;
+
+ t[0] = f[0];
+ t[1] = f[1];
+ to->exponent = from->exponent;
+ }
+}
+
+static inline void save_i387_fsave( arch_thread_t *regs, struct _vki_fpstate *buf )
+{
+ struct i387_fsave_struct *fs = ®s->m_sse.fsave;
+
+ fs->status = fs->swd;
+ VG_(memcpy)(buf, fs, sizeof(*fs));
+}
+
+static void save_i387_fxsave( arch_thread_t *regs, struct _vki_fpstate *buf )
+{
+ const struct i387_fxsave_struct *fx = ®s->m_sse.fxsave;
+ convert_fxsr_to_user( buf, fx );
+
+ buf->status = fx->swd;
+ buf->magic = X86_FXSR_MAGIC;
+ VG_(memcpy)(buf->_fxsr_env, fx, sizeof(struct i387_fxsave_struct));
+}
+
+static void save_i387( arch_thread_t *regs, struct _vki_fpstate *buf )
+{
+ if ( VG_(have_ssestate) )
+ save_i387_fxsave( regs, buf );
+ else
+ save_i387_fsave( regs, buf );
+}
+
+static inline void restore_i387_fsave( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
+{
+ VG_(memcpy)( ®s->m_sse.fsave, buf, sizeof(struct i387_fsave_struct) );
+}
+
+static void restore_i387_fxsave( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
+{
+ VG_(memcpy)(®s->m_sse.fxsave, &buf->_fxsr_env[0],
+ sizeof(struct i387_fxsave_struct) );
+ /* mxcsr reserved bits must be masked to zero for security reasons */
+ regs->m_sse.fxsave.mxcsr &= 0xffbf;
+ convert_fxsr_from_user( ®s->m_sse.fxsave, buf );
+}
+
+static void restore_i387( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
+{
+ if ( VG_(have_ssestate) ) {
+ restore_i387_fxsave( regs, buf );
+ } else {
+ restore_i387_fsave( regs, buf );
+ }
+}
+
+
/* Make up a plausible-looking thread state from the thread's current state */
static void synth_ucontext(ThreadId tid, const vki_siginfo_t *si,
- const vki_sigset_t *set, struct vki_ucontext *uc)
+ const vki_sigset_t *set,
+ struct vki_ucontext *uc, struct _vki_fpstate *fpstate)
{
ThreadState *tst = VG_(get_ThreadState)(tid);
@@ -134,4 +308,7 @@ static void synth_ucontext(ThreadId tid,
uc->uc_sigmask = *set;
uc->uc_stack = tst->altstack;
+ sc->fpstate = fpstate;
+
+ save_i387(&tst->arch, fpstate);
#define SC(reg) sc->reg = tst->arch.m_##reg
@@ -173,5 +350,4 @@ void VGA_(push_signal_frame)(ThreadId ti
Addr esp;
ThreadState* tst;
- Int i;
VgSigFrame* frame;
Int sigNo = siginfo->si_signo;
@@ -202,4 +379,6 @@ void VGA_(push_signal_frame)(ThreadId ti
if (flags & VKI_SA_SIGINFO) {
/* if the client asked for a siginfo delivery, then build the stack that way */
+
+ /* pointers to siginfo and ucontext */
VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (siginfo)",
(Addr)&frame->handlerArgs, sizeof(frame->handlerArgs.sigInfo) );
@@ -208,4 +387,5 @@ void VGA_(push_signal_frame)(ThreadId ti
VG_TRACK( post_mem_write, (Addr)&frame->handlerArgs, sizeof(frame->handlerArgs.sigInfo) );
+ /* siginfo */
VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (siginfo)",
(Addr)&frame->sigInfo, sizeof(frame->sigInfo) );
@@ -213,14 +393,15 @@ void VGA_(push_signal_frame)(ThreadId ti
VG_TRACK( post_mem_write, (Addr)&frame->sigInfo, sizeof(frame->sigInfo) );
- VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (siginfo)",
+ /* ucontext */
+ VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (ucontext)",
(Addr)&frame->uContext, sizeof(frame->uContext) );
- synth_ucontext(tid, siginfo, mask, &frame->uContext);
+ synth_ucontext(tid, siginfo, mask, &frame->uContext, &frame->fpstate);
VG_TRACK( post_mem_write, (Addr)&frame->uContext, sizeof(frame->uContext) );
} else {
struct vki_ucontext uc;
- /* otherwise just put the sigcontext there */
+ /* non-siginfo: just put the sigcontext there */
- synth_ucontext(tid, siginfo, mask, &uc);
+ synth_ucontext(tid, siginfo, mask, &uc, &frame->fpstate);
VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (sigcontext)",
@@ -236,18 +417,4 @@ void VGA_(push_signal_frame)(ThreadId ti
frame->magicPI = 0x31415927;
- for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++)
- frame->m_sse[i] = tst->arch.m_sse[i];
-
- frame->m_eax = tst->arch.m_eax;
- frame->m_ecx = tst->arch.m_ecx;
- frame->m_edx = tst->arch.m_edx;
- frame->m_ebx = tst->arch.m_ebx;
- frame->m_ebp = tst->arch.m_ebp;
- frame->m_esp = tst->arch.m_esp;
- frame->m_esi = tst->arch.m_esi;
- frame->m_edi = tst->arch.m_edi;
- frame->m_eflags = tst->arch.m_eflags;
- frame->m_eip = tst->arch.m_eip;
-
if (VG_(needs).shadow_regs) {
frame->sh_eax = tst->arch.sh_eax;
@@ -264,10 +431,5 @@ void VGA_(push_signal_frame)(ThreadId ti
frame->mask = tst->sig_mask;
- /* If the thread is currently blocked in a syscall, we want it to
- resume as runnable. */
- if (tst->status == VgTs_WaitSys)
- frame->status = VgTs_Runnable;
- else
- frame->status = tst->status;
+ frame->handlerflags = flags;
frame->magicE = 0x27182818;
@@ -285,5 +447,5 @@ void VGA_(push_signal_frame)(ThreadId ti
if (0)
- VG_(printf)("pushed signal frame; %%ESP now = %p, next %%EBP = %p, status=%d\n",
+ VG_(printf)("pushed signal frame; %%ESP now = %p, next %%EIP = %p, status=%d\n",
esp, tst->arch.m_eip, tst->status);
}
@@ -292,7 +454,7 @@ Int VGA_(pop_signal_frame)(ThreadId tid)
{
Addr esp;
- Int i;
VgSigFrame* frame;
ThreadState* tst;
+ struct vki_sigcontext *sc;
vg_assert(VG_(is_valid_tid)(tid));
@@ -307,7 +469,4 @@ Int VGA_(pop_signal_frame)(ThreadId tid)
vg_assert(frame->magicPI == 0x31415927);
vg_assert(frame->magicE == 0x27182818);
- if (VG_(clo_trace_signals))
- VG_(message)(Vg_DebugMsg,
- "vg_pop_signal_frame (thread %d): valid magic; EIP=%p", tid, frame->m_eip);
/* Mark the frame structure as nonaccessible. */
@@ -315,17 +474,28 @@ Int VGA_(pop_signal_frame)(ThreadId tid)
/* restore machine state */
- for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++)
- tst->arch.m_sse[i] = frame->m_sse[i];
+ if (frame->handlerflags & VKI_SA_SIGINFO)
+ sc = &frame->uContext.uc_mcontext;
+ else
+ sc = &frame->handlerArgs.sigContext;
- tst->arch.m_eax = frame->m_eax;
- tst->arch.m_ecx = frame->m_ecx;
- tst->arch.m_edx = frame->m_edx;
- tst->arch.m_ebx = frame->m_ebx;
- tst->arch.m_ebp = frame->m_ebp;
- tst->arch.m_esp = frame->m_esp;
- tst->arch.m_esi = frame->m_esi;
- tst->arch.m_edi = frame->m_edi;
- tst->arch.m_eflags = frame->m_eflags;
- tst->arch.m_eip = frame->m_eip;
+ tst->arch.m_eax = sc->eax;
+ tst->arch.m_ecx = sc->ecx;
+ tst->arch.m_edx = sc->edx;
+ tst->arch.m_ebx = sc->ebx;
+ tst->arch.m_ebp = sc->ebp;
+ tst->arch.m_esp = sc->esp;
+ tst->arch.m_esi = sc->esi;
+ tst->arch.m_edi = sc->edi;
+ tst->arch.m_eflags = sc->eflags;
+ tst->arch.m_eip = sc->eip;
+
+ tst->arch.m_cs = sc->cs;
+ tst->arch.m_ss = sc->ss;
+ tst->arch.m_ds = sc->ds;
+ tst->arch.m_es = sc->es;
+ tst->arch.m_fs = sc->fs;
+ tst->arch.m_gs = sc->gs;
+
+ restore_i387(&tst->arch, &frame->fpstate);
if (VG_(needs).shadow_regs) {
@@ -341,7 +511,8 @@ Int VGA_(pop_signal_frame)(ThreadId tid)
}
- /* And restore the thread's status to what it was before the signal
- was delivered. */
- tst->status = frame->status;
+ if (VG_(clo_trace_signals))
+ VG_(message)(Vg_DebugMsg,
+ "vg_pop_signal_frame (thread %d): valid magic; EIP=%p",
+ tid, sc->eip);
tst->sig_mask = frame->mask;
@@ -439,5 +610,5 @@ void VGA_(fill_elffpxregs_from_tst) ( vk
const arch_thread_t* arch )
{
- VG_(memcpy)(xfpu, arch->m_sse, sizeof(*xfpu));
+ VG_(memcpy)(xfpu, arch->m_sse.state, sizeof(*xfpu));
}
--- valgrind/coregrind/x86/state.c #1.13:1.14
@@ -317,5 +317,5 @@ void VGA_(load_state) ( arch_thread_t* a
for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++)
- VG_(baseBlock)[VGOFF_(m_ssestate) + i] = arch->m_sse[i];
+ VG_(baseBlock)[VGOFF_(m_ssestate) + i] = arch->m_sse.state[i];
if (VG_(needs).shadow_regs) {
@@ -396,5 +396,5 @@ n",
for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++)
- arch->m_sse[i]
+ arch->m_sse.state[i]
= VG_(baseBlock)[VGOFF_(m_ssestate) + i];
--- valgrind/none/tests/Makefile.am #1.54:1.55
@@ -49,9 +49,10 @@
shortpush.stderr.exp shortpush.vgtest \
shorts.stderr.exp shorts.vgtest \
- tls.stderr.exp tls.stdout.exp \
+ sigcontext.stdout.exp sigcontext.stderr.exp sigcontext.vgtest \
smc1.stderr.exp smc1.stdout.exp smc1.vgtest \
syscall-restart1.vgtest syscall-restart1.stdout.exp syscall-restart1.stderr.exp \
syscall-restart2.vgtest syscall-restart2.stdout.exp syscall-restart2.stderr.exp \
system.stderr.exp system.vgtest \
+ tls.stderr.exp tls.stdout.exp \
yield.stderr.exp yield.stdout.exp yield.vgtest
@@ -62,5 +63,6 @@
munmap_exe map_unaligned map_unmap mq mremap rcrl readline1 \
resolv rlimit_nofile sem semlimit sha1_test \
- shortpush shorts smc1 susphello pending pth_blockedsig pth_stackalign \
+ shortpush shorts sigcontext \
+ smc1 susphello pending pth_blockedsig pth_stackalign \
syscall-restart1 syscall-restart2 system \
coolo_sigaction gxx304 yield
@@ -102,4 +104,5 @@
shortpush_SOURCES = shortpush.c
shorts_SOURCES = shorts.c
+sigcontext_SOURCES = sigcontext.c
susphello_SOURCES = susphello.c
susphello_LDADD = -lpthread
|
|
From: Jeremy F. <je...@go...> - 2005-01-15 03:26:31
|
CVS commit by fitzhardinge:
Warn if a program appears to be using the now-obsolete Valgrind
libpthread.
M +11 -44 core.h 1.56
M +47 -0 vg_scheduler.c 1.203
--- valgrind/coregrind/vg_scheduler.c #1.202:1.203
@@ -1056,4 +1056,51 @@ void do_client_request ( ThreadId tid )
break;
+ /* Obsolete requests: print a warning in case there's an old
+ libpthread.so still hanging around. */
+ case VG_USERREQ__APPLY_IN_NEW_THREAD:
+ case VG_USERREQ__QUIT:
+ case VG_USERREQ__WAIT_JOINER:
+ case VG_USERREQ__PTHREAD_JOIN:
+ case VG_USERREQ__SET_CANCELSTATE:
+ case VG_USERREQ__SET_CANCELTYPE:
+ case VG_USERREQ__TESTCANCEL:
+ case VG_USERREQ__SET_CANCELPEND:
+ case VG_USERREQ__SET_OR_GET_DETACH:
+ case VG_USERREQ__PTHREAD_GET_THREADID:
+ case VG_USERREQ__PTHREAD_MUTEX_LOCK:
+ case VG_USERREQ__PTHREAD_MUTEX_TIMEDLOCK:
+ case VG_USERREQ__PTHREAD_MUTEX_TRYLOCK:
+ case VG_USERREQ__PTHREAD_MUTEX_UNLOCK:
+ case VG_USERREQ__PTHREAD_COND_WAIT:
+ case VG_USERREQ__PTHREAD_COND_TIMEDWAIT:
+ case VG_USERREQ__PTHREAD_COND_SIGNAL:
+ case VG_USERREQ__PTHREAD_COND_BROADCAST:
+ case VG_USERREQ__PTHREAD_KEY_CREATE:
+ case VG_USERREQ__PTHREAD_KEY_DELETE:
+ case VG_USERREQ__PTHREAD_SETSPECIFIC_PTR:
+ case VG_USERREQ__PTHREAD_GETSPECIFIC_PTR:
+ case VG_USERREQ__PTHREAD_SIGMASK:
+ case VG_USERREQ__SIGWAIT:
+ case VG_USERREQ__PTHREAD_KILL:
+ case VG_USERREQ__PTHREAD_YIELD:
+ case VG_USERREQ__PTHREAD_KEY_VALIDATE:
+ case VG_USERREQ__CLEANUP_PUSH:
+ case VG_USERREQ__CLEANUP_POP:
+ case VG_USERREQ__GET_KEY_D_AND_S:
+ case VG_USERREQ__NUKE_OTHER_THREADS:
+ case VG_USERREQ__GET_N_SIGS_RETURNED:
+ case VG_USERREQ__SET_FHSTACK_USED:
+ case VG_USERREQ__GET_FHSTACK_USED:
+ case VG_USERREQ__SET_FHSTACK_ENTRY:
+ case VG_USERREQ__GET_FHSTACK_ENTRY:
+ case VG_USERREQ__GET_SIGRT_MIN:
+ case VG_USERREQ__GET_SIGRT_MAX:
+ case VG_USERREQ__ALLOC_RTSIG:
+ VG_(message)(Vg_UserMsg, "It looks like you've got an old libpthread.so* ");
+ VG_(message)(Vg_UserMsg, "installed in \"%s\".", VG_(libdir));
+ VG_(message)(Vg_UserMsg, "Please delete it and try again.");
+ VG_(exit)(99);
+ break;
+
default:
if (VGA_(client_request)(tid, arg)) {
--- valgrind/coregrind/core.h #1.55:1.56
@@ -458,35 +458,14 @@ extern Bool VG_(is_empty_arena) ( Arena
#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
@@ -502,7 +481,6 @@ extern Bool VG_(is_empty_arena) ( Arena
#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
@@ -512,35 +489,21 @@ extern Bool VG_(is_empty_arena) ( Arena
#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
@@ -548,4 +511,8 @@ extern Bool VG_(is_empty_arena) ( Arena
#define VG_USERREQ__INTERNAL_PRINTF_BACKTRACE 0x3104
+/* Denote the finish of __libc_freeres_wrapper().
+ A synonym for exit. */
+#define VG_USERREQ__LIBC_FREERES_DONE 0x3029
+
/*
In core_asm.h:
|
|
From: Tom H. <to...@co...> - 2005-01-15 03:24:08
|
Nightly build on dunsmere ( Fedora Core 3 ) started at 2005-01-15 03:20:03 GMT Checking out source tree ... done Configuring ... done Building ... done Running regression tests ... done Last 20 lines of log.verbose follow none/tests/x86/badseg (stderr) none/tests/x86/bt_everything (stderr) none/tests/x86/bt_literal (stderr) none/tests/x86/cpuid (stderr) none/tests/x86/dastest (stderr) none/tests/x86/fpu_lazy_eflags (stderr) none/tests/x86/insn_basic (stderr) none/tests/x86/insn_cmov (stderr) none/tests/x86/insn_fpu (stderr) none/tests/x86/insn_mmx (stderr) none/tests/x86/insn_mmxext (stderr) none/tests/x86/insn_sse (stderr) none/tests/x86/int (stderr) none/tests/x86/pushpopseg (stderr) none/tests/x86/rcl_assert (stderr) none/tests/x86/seg_override (stderr) none/tests/yield (stdout) none/tests/yield (stderr) make: *** [regtest] Error 1 |
|
From: Tom H. <th...@cy...> - 2005-01-15 03:21:37
|
Nightly build on audi ( Red Hat 9 ) started at 2005-01-15 03:15:05 GMT Checking out source tree ... done Configuring ... done Building ... done Running regression tests ... done Last 20 lines of log.verbose follow helgrind/tests/inherit (stderr) helgrind/tests/race (stderr) helgrind/tests/race2 (stderr) helgrind/tests/readshared (stderr) massif/tests/toobig-allocs (stderr) massif/tests/true_html (stderr) massif/tests/true_text (stderr) memcheck/tests/badpoll (stderr) memcheck/tests/buflen_check (stderr) memcheck/tests/execve (stderr) memcheck/tests/execve2 (stderr) memcheck/tests/scalar (stderr) memcheck/tests/scalar_exit_group (stderr) memcheck/tests/scalar_supp (stderr) memcheck/tests/writev (stderr) none/tests/blockfault (stderr) none/tests/exec-sigmask (stdout) none/tests/yield (stdout) make: *** [regtest] Error 1 |
|
From: Tom H. <th...@cy...> - 2005-01-15 03:11:12
|
Nightly build on ginetta ( Red Hat 8.0 ) started at 2005-01-15 03:10:02 GMT Checking out source tree ... done Configuring ... done Building ... done Running regression tests ... done Last 20 lines of log.verbose follow U valgrind/tests/unused/signal3.c U valgrind/tests/unused/sigwait_all.c U valgrind/tests/unused/twoparams.c U valgrind/tests/unused/twoparams.s running: aclocal running: autoheader autoheader: `config.h.in' is created running: automake -a configure.in: installing `./install-sh' configure.in: installing `./mkinstalldirs' configure.in: installing `./missing' configure.in:67: installing `./config.guess' configure.in:67: installing `./config.sub' addrcheck/Makefile.am: installing `./depcomp' coregrind/Makefile.am: installing `./compile' running: autoconf configure.in:258: error: possibly undefined macro: AS_HELP_STRING error: while running 'autoconf' make: *** No targets specified and no makefile found. Stop. make: *** No rule to make target `regtest'. Stop. |
|
From: Tom H. <th...@cy...> - 2005-01-15 03:05:45
|
Nightly build on alvis ( Red Hat 7.3 ) started at 2005-01-15 03:05:02 GMT Checking out source tree ... done Configuring ... done Building ... done Running regression tests ... done Last 20 lines of log.verbose follow U valgrind/tests/unused/signal3.c U valgrind/tests/unused/sigwait_all.c U valgrind/tests/unused/twoparams.c U valgrind/tests/unused/twoparams.s running: aclocal running: autoheader autoheader: `config.h.in' is created running: automake -a configure.in: installing `./install-sh' configure.in: installing `./mkinstalldirs' configure.in: installing `./missing' configure.in:67: installing `./config.guess' configure.in:67: installing `./config.sub' addrcheck/Makefile.am: installing `./depcomp' coregrind/Makefile.am: installing `./compile' running: autoconf configure.in:258: error: possibly undefined macro: AS_HELP_STRING error: while running 'autoconf' make: *** No targets specified and no makefile found. Stop. make: *** No rule to make target `regtest'. Stop. |
|
From: Tom H. <th...@cy...> - 2005-01-15 03:01:39
|
Nightly build on standard ( Red Hat 7.2 ) started at 2005-01-15 03:00:04 GMT Checking out source tree ... done Configuring ... done Building ... done Running regression tests ... done Last 20 lines of log.verbose follow U valgrind/tests/unused/signal3.c U valgrind/tests/unused/sigwait_all.c U valgrind/tests/unused/twoparams.c U valgrind/tests/unused/twoparams.s running: aclocal running: autoheader autoheader: `config.h.in' is created running: automake -a configure.in: installing `./install-sh' configure.in: installing `./mkinstalldirs' configure.in: installing `./missing' configure.in:67: installing `./config.guess' configure.in:67: installing `./config.sub' addrcheck/Makefile.am: installing `./depcomp' coregrind/Makefile.am: installing `./compile' running: autoconf configure.in:258: error: possibly undefined macro: AS_HELP_STRING error: while running 'autoconf' make: *** No targets specified and no makefile found. Stop. make: *** No rule to make target `regtest'. Stop. |
|
From: Jeremy F. <je...@go...> - 2005-01-15 02:19:37
|
CVS commit by fitzhardinge: Fix pth_blockedsig.stdout.exp and tweak .cvsignore M +5 -0 .cvsignore 1.23 M +1 -1 pth_blockedsig.stdout.exp 1.3 --- valgrind/none/tests/.cvsignore #1.22:1.23 @@ -3,4 +3,5 @@ args bitfield1 +blockfault closeall coolo_sigaction @@ -13,4 +14,5 @@ fork fucomip +getseg gxx304 insn_basic @@ -39,4 +41,6 @@ resolv rlimit_nofile +map_unaligned +pending sem semlimit @@ -44,4 +48,5 @@ shortpush shorts +sigcontext smc1 susphello --- valgrind/none/tests/pth_blockedsig.stdout.exp #1.2:1.3 @@ -1 +1 @@ -thread 2 sending SIGUSR1 to thread 1 +thread CHILD sending SIGUSR1 to thread MAIN |
|
From: Jeremy F. <je...@go...> - 2005-01-15 02:08:56
|
CVS commit by fitzhardinge:
Add an expensive sanity check to make sure that the Segment list is
consistent with the contents of /proc/self/maps at all times.es
M +4 -2 core.h 1.62
M +43 -4 vg_main.c 1.234
M +269 -9 vg_memory.c 1.83
M +2 -1 vg_procselfmaps.c 1.17
--- valgrind/coregrind/vg_memory.c #1.82:1.83
@@ -114,4 +114,13 @@ static void freeseg(Segment *s)
}
+static inline Segment *allocseg()
+{
+ Segment *s;
+
+ s = VG_(SkipNode_Alloc)(&sk_segments);
+
+ return s;
+}
+
/* Split a segment at address a, returning the new segment */
Segment *VG_(split_segment)(Addr a)
@@ -133,5 +142,5 @@ Segment *VG_(split_segment)(Addr a)
vg_assert(a > s->addr && a < (s->addr+s->len));
- ns = VG_(SkipNode_Alloc)(&sk_segments);
+ ns = allocseg();
*ns = *s;
@@ -143,4 +152,8 @@ Segment *VG_(split_segment)(Addr a)
s->len = delta;
+ vg_assert(ns->len > 0);
+ vg_assert(s->len > 0);
+ vg_assert(ns->addr == (s->addr+s->len));
+
if (s->filename != NULL)
ns->filename = VG_(arena_strdup)(VG_AR_CORE, s->filename);
@@ -205,4 +218,6 @@ void VG_(unmap_range)(Addr addr, SizeT l
s->len = addr - s->addr;
+ vg_assert(s->len > 0);
+
if (debug)
VG_(printf)(" case 1: s->len=%d\n", s->len);
@@ -220,5 +235,5 @@ void VG_(unmap_range)(Addr addr, SizeT l
s->len -= delta;
- vg_assert(s->len != 0);
+ vg_assert(s->len > 0);
} else if (addr <= s->addr && end >= seg_end) {
/* this segment is completely contained within [addr, addr+len)
@@ -241,4 +256,5 @@ void VG_(unmap_range)(Addr addr, SizeT l
vg_assert(middle->addr == addr);
+ vg_assert(middle->len == len);
rs = VG_(SkipList_Remove)(&sk_segments, &addr);
vg_assert(rs == middle);
@@ -251,4 +267,6 @@ void VG_(unmap_range)(Addr addr, SizeT l
}
}
+
+ //VG_(sanity_check_memory)();
}
@@ -327,4 +345,7 @@ void VG_(map_file_segment)(Addr addr, Si
addr, (ULong)len, prot, flags, dev, ino, off, filename);
+ if (len == 0)
+ return;
+
/* Everything must be page-aligned */
vg_assert((addr & (VKI_PAGE_SIZE-1)) == 0);
@@ -353,5 +374,5 @@ void VG_(map_file_segment)(Addr addr, Si
VG_(unmap_range)(addr, len);
- s = VG_(SkipNode_Alloc)(&sk_segments);
+ s = allocseg();
s->addr = addr;
@@ -463,23 +484,40 @@ void VG_(mprotect_range)(Addr a, SizeT l
Segment *s, *next;
static const Bool debug = False || mem_debug;
+ Segment *s1, *s2;
if (debug)
VG_(printf)("mprotect_range(%p, %d, %x)\n", a, len, prot);
+ if (len == 0)
+ return;
+
/* Everything must be page-aligned */
vg_assert((a & (VKI_PAGE_SIZE-1)) == 0);
len = PGROUNDUP(len);
- VG_(split_segment)(a);
- VG_(split_segment)(a+len);
+ s1 = VG_(split_segment)(a);
+ s2 = VG_(split_segment)(a+len);
- for(s = VG_(SkipList_Find)(&sk_segments, &a);
+ if (debug) {
+ s = VG_(find_segment)(a);
+ VG_(printf)(" split: s1=%p-%p s2=%p-%p s(%p)=%p-%p\n",
+ s1 ? s1->addr : 0, s1 ? (s1->addr+s1->len) : 0,
+ s2 ? s2->addr : 0, s2 ? (s2->addr+s2->len) : 0,
+ a,
+ s ? s->addr : 0, s ? (s->addr+s->len) : 0);
+ }
+
+ for(s = VG_(find_segment)(a);
s != NULL && s->addr < a+len;
s = next)
{
- next = VG_(SkipNode_Next)(&sk_segments, s);
+ next = VG_(next_segment)(s);
if (s->addr < a)
continue;
+ if (debug)
+ VG_(printf)(" setting s->%p - %p to prot %x\n",
+ s->addr, s->addr+s->len, prot);
+
s->prot = prot;
}
@@ -846,10 +884,17 @@ void *VG_(shadow_alloc)(UInt size)
size = PGROUNDUP(size);
- if (shadow_alloc == 0)
+ if (shadow_alloc == 0) {
shadow_alloc = VG_(shadow_base);
+ vg_assert(VG_(is_addressable)(VG_(shadow_base), VG_(shadow_end)-VG_(shadow_base),
+ VKI_PROT_NONE));
+ }
if (shadow_alloc >= VG_(shadow_end))
return 0;
+ if (0)
+ VG_(printf)("shadow_base=%p shadow_alloc=%p alloc %d\n",
+ VG_(shadow_base), shadow_alloc, size);
+
ret = (void *)shadow_alloc;
VG_(mprotect)(ret, size, VKI_PROT_READ|VKI_PROT_WRITE);
@@ -861,4 +906,219 @@ void *VG_(shadow_alloc)(UInt size)
/*--------------------------------------------------------------------*/
+/*--- Sanity checking ---*/
+/*--------------------------------------------------------------------*/
+
+static Segment *next_segment;
+static Bool segment_maps_ok;
+static Addr prevmapstart, prevmapend;
+
+static void check_segment_maps(Addr addr, SizeT len, Char rr, Char ww, Char xx,
+ UInt dev, UInt ino, ULong foff, const UChar *filename)
+{
+ Addr segend;
+ Addr end = addr+len;
+ Segment *seg, *next, *prev;
+ UInt prot;
+
+ if (addr >= VG_(valgrind_last))
+ return; /* don't care */
+
+ if (addr < prevmapend) {
+ VG_(printf)("KERNEL BUG: mapping %p-%p <= prevmap %p-%p !?\n",
+ addr, end, prevmapstart, prevmapend);
+ return;
+ }
+ prevmapstart = addr;
+ prevmapend = end;
+
+ prot = 0;
+ prot |= rr == 'r' ? VKI_PROT_READ : 0;
+ prot |= ww == 'w' ? VKI_PROT_WRITE: 0;
+ prot |= xx == 'x' ? VKI_PROT_EXEC : 0;
+
+ if (next_segment == NULL)
+ seg = VG_(first_segment)();
+ else
+ seg = next_segment;
+
+ if (seg == NULL)
+ return; /* no segments yet */
+
+ segend = seg->addr + seg->len;
+
+ /*
+ The invariants here are:
+ 1. all mappings from /proc/self/maps must be completely covered by Segments
+ - there may be multiple Segments per map
+ 2. a Segment may never overlap the ends of a map
+ 3. all Segments must be backed by mappings
+ 4. Segment permissions must not be a superset of mapping permissions (subset OK)
+ */
+
+ /*
+ Check invariant 3: this segment must have the same start address
+ as the mapping. If we find a floating Segment (ie, has no
+ mapping backing it), then skip forward through list until we
+ find a Segment which could overlap this mapping.
+
+ And inv 2: if it doesn't start at the beginnging of the mapping,
+ it should be some completely floating segment; it must not
+ overlap the mapping.
+ */
+ prev = NULL;
+ while (seg && seg->addr < addr) {
+ VG_(printf)("INV 3 FAILED: seg %p-%p %4x doesn't start at beginning of mapping %p-%p\n",
+ seg->addr, segend, seg->flags, addr, end);
+ if (VG_(seg_overlaps)(seg, addr, len))
+ VG_(printf)(" 2 FAILED: seg %p-%p overlaps of mapping %p-%p\n",
+ seg->addr, segend, addr, end);
+ segment_maps_ok = False;
+ prev = seg;
+ seg = VG_(next_segment)(seg);
+ }
+
+ if (seg == NULL)
+ return; /* no more segments */
+
+ /* Iterate over all Segments covering the mapping */
+ next = VG_(next_segment)(seg);
+
+ while(seg && (seg->addr < end)) {
+ prev = seg;
+ segend = seg->addr + seg->len;
+
+ if (0)
+ VG_(printf)("seg: %p-%p (%c%c%c) %4x mapping %p-%p %x (%c%c%c) %s%s %s\n",
+ seg->addr, segend,
+ seg->prot & VKI_PROT_READ ? 'r' : '-',
+ seg->prot & VKI_PROT_WRITE? 'w' : '-',
+ seg->prot & VKI_PROT_EXEC ? 'x' : '-',
+ seg->flags,
+ addr, end, prot, rr, ww, xx,
+ (addr == seg->addr && segend == end) ? "" : " !!!",
+ (seg->prot & prot) != seg->prot ? " ???" : "",
+ seg->filename ? seg->filename : (const Char *)"");
+
+ vg_assert(VG_(seg_overlaps)(seg, addr, len));
+
+ if ((seg->addr < addr) || (segend > end)) {
+ VG_(printf)("INV 2 FAILED: seg %p-%p crosses boundaries of mapping %p-%p\n",
+ seg->addr, segend,
+ addr, end);
+ segment_maps_ok = False;
+ }
+
+ if ((seg->prot & prot) != seg->prot) {
+ VG_(printf)("INV 4 FAILED: seg %p-%p permissions %c%c%c not subset of mapping %p-%p permissions %c%c%c\n",
+ seg->addr, segend,
+ seg->prot & VKI_PROT_READ ? 'r' : '-',
+ seg->prot & VKI_PROT_WRITE? 'w' : '-',
+ seg->prot & VKI_PROT_EXEC ? 'x' : '-',
+ addr, end,
+ rr, ww, xx);
+ segment_maps_ok = False;
+ }
+
+ if (filename != NULL) {
+ Int delta;
+
+ if (!(seg->flags & SF_FILE)) {
+ VG_(printf)("seg %p-%p flags %x does't have SF_FILE\n",
+ seg->addr, segend, seg->flags);
+ segment_maps_ok = False;
+ }
+
+ delta = seg->addr - addr;
+ if ((seg->offset - delta) != foff) {
+ VG_(printf)("seg %p-%p file %s delta %d offset %lld != (%p-%p) %lld %s\n",
+ seg->addr, segend, seg->filename, delta, seg->offset,
+ addr, end, foff, filename);
+ segment_maps_ok = False;
+ }
+ }
+
+ next = VG_(next_segment)(seg);
+
+ /* segments covering a map must be contigious */
+ if (next == NULL || next->addr != segend)
+ break;
+
+ prev = seg;
+ seg = next;
+ }
+
+ segend = seg->addr + seg->len;
+
+ if (0)
+ VG_(printf)("loop done seg=%p-%p next=%p-%p map=%p-%p\n",
+ seg ? seg->addr : 0, seg ? (seg->addr+seg->len) : 0,
+ next ? next->addr : 0, next ? (next->addr+next->len) : 0,
+ addr, end);
+
+ /* otherwise the loop exited too early */
+ //vg_assert(seg == NULL || segend <= end);
+ vg_assert(next == NULL || next->addr >= end);
+
+ if ((prev->addr+prev->len) != end) {
+ VG_(printf)("INV 1 FAILED: seg -%p does not end at mapping %p-%p end\n",
+ prev->addr, prev->addr+prev->len, addr, end);
+ segment_maps_ok = False;
+ }
+
+ next_segment = next;
+}
+
+Bool VG_(sanity_check_memory)(void)
+{
+ Segment *seg;
+ Addr prev;
+ Bool ok = True;
+
+ /* First, walk the segment list and make sure it looks internally OK */
+ prev = 0;
+ for(seg = VG_(first_segment)();
+ seg != NULL;
+ seg = VG_(next_segment)(seg)) {
+ Addr end = seg->addr + seg->len;
+
+ if (end <= seg->addr) {
+ ok = False;
+ VG_(printf)("Segment %p: %p-%p has bad size %d\n",
+ seg, seg->addr, end, seg->len);
+ }
+
+ if (seg->addr < prev) {
+ ok = False;
+ VG_(printf)("Segment %p: %p-%p is before previous seg (ending at %p)\n",
+ seg, seg->addr, end, prev);
+ }
+
+ if (!!(seg->flags & SF_VALGRIND) != (seg->addr >= VG_(client_end))) {
+ ok = False;
+ VG_(printf)("Segment %p: %p-%p has flags (%x) inconsistent with client_end=%p\n",
+ seg, seg->addr, seg->addr+seg->len, seg->flags, VG_(client_end));
+ }
+
+ if (prev < end)
+ prev = end;
+ }
+
+ /* Now compare with /proc/self/maps */
+ VG_(read_procselfmaps)();
+
+ next_segment = NULL;
+ segment_maps_ok = True;
+ prevmapstart = prevmapend = 0;
+ VG_(parse_procselfmaps)(check_segment_maps);
+
+ ok = ok && segment_maps_ok;
+
+ if (0 && ok)
+ VG_(printf)("(memory segments OK)\n");
+
+ return ok && segment_maps_ok;
+}
+
+/*--------------------------------------------------------------------*/
/*--- end vg_memory.c ---*/
/*--------------------------------------------------------------------*/
--- valgrind/coregrind/core.h #1.61:1.62
@@ -114,6 +114,6 @@ typedef struct _ThreadState ThreadState;
#define M_VG_MSGBUF 10000
-/* Size of a smallish table used to read /proc/self/map entries. */
-#define M_PROCMAP_BUF 50000
+/* Size of a big enough table used to read /proc/self/map entries. */
+#define M_PROCMAP_BUF 200000
/* Max length of pathname to a .so/executable file. */
@@ -1184,4 +1184,6 @@ extern void VG_(align_BaB)( UInt );
extern Int VG_(alloc_BaB_1_set)( Addr ); // Allocate & init baseBlock slot
+extern Bool VG_(sanity_check_memory)(void);
+
/* ---------------------------------------------------------------------
Exports of vg_memory.c
--- valgrind/coregrind/vg_main.c #1.233:1.234
@@ -2321,6 +2321,9 @@ static void build_valgrind_map_callback
start allocating more memory (note: heap is OK, it's just mmap
which is the problem here). */
- if (start >= VG_(valgrind_base) && (start+size-1) <= VG_(valgrind_last)) {
+ if (start >= VG_(client_end) && (start+size-1) <= VG_(valgrind_last)) {
flags |= SF_VALGRIND;
+ if (rr == 'r') prot |= VKI_PROT_READ;
+ if (ww == 'w') prot |= VKI_PROT_WRITE;
+ if (xx == 'x') prot |= VKI_PROT_EXEC;
VG_(map_file_segment)(start, size, prot, flags, dev, ino, foffset, filename);
}
@@ -2330,4 +2333,14 @@ static void build_valgrind_map_callback
Addr sp_at_startup___global_arg = 0;
+/*
+ This second pass adds in client mappings, and loads symbol tables
+ for all interesting mappings. The trouble is that things can
+ change as we go, because we're calling the Tool to track memory as
+ we find it.
+
+ So for Valgrind mappings, we don't replace any mappings which
+ aren't still identical (which will include the .so mappings, so we
+ will load their symtabs)>
+ */
static void build_segment_map_callback
( Addr start, SizeT size, Char rr, Char ww, Char xx,
@@ -2342,4 +2355,8 @@ static void build_segment_map_callback
= (start == VG_(clstk_base) && (start+size) == VG_(clstk_end));
+ if (0)
+ VG_(printf)("init: %p-%p prot %c%c%c stack=%d\n",
+ start, start+size, rr, ww, xx, is_stack_segment);
+
if (rr == 'r') prot |= VKI_PROT_READ;
if (ww == 'w') prot |= VKI_PROT_WRITE;
@@ -2354,7 +2371,24 @@ static void build_segment_map_callback
flags |= SF_FILE;
- if (start >= VG_(valgrind_base) && (start+size-1) <= VG_(valgrind_last))
- flags |= SF_VALGRIND;
+ if (start >= VG_(client_end) && (start+size-1) <= VG_(valgrind_last)) {
+ Segment *s = VG_(find_segment)(start);
+ /* We have to be a bit careful about inserting new mappings into
+ the Valgrind part of the address space. We're actively
+ changing things as we parse these mappings, particularly in
+ shadow memory, and so we don't want to overwrite those
+ changes. Therefore, we only insert/update a mapping if it is
+ mapped from a file or it exactly matches an existing mapping.
+
+ NOTE: we're only talking about the Segment list mapping
+ metadata; this doesn't actually mmap anything more. */
+ if (filename || (s && s->addr == start && s->len == size)) {
+ flags |= SF_VALGRIND;
+ VG_(map_file_segment)(start, size, prot, flags, dev, ino, foffset, filename);
+ } else {
+ /* assert range is already mapped */
+ vg_assert(VG_(is_addressable)(start, size, VKI_PROT_NONE));
+ }
+ } else
VG_(map_file_segment)(start, size, prot, flags, dev, ino, foffset, filename);
@@ -2423,4 +2457,7 @@ void VG_(sanity_check_general) ( Bool fo
VGP_POPCC(VgpSkinExpensiveSanity);
}
+
+ vg_assert(VG_(sanity_check_memory)());
+
/*
if ((sanity_fast_count % 500) == 0) VG_(mallocSanityCheckAll)();
@@ -2686,8 +2723,10 @@ int main(int argc, char **argv, char **e
//--------------------------------------------------------------
// Build segment map (all segments)
+ // p: shadow/redzone segments
// p: setup_client_stack() [for 'sp_at_startup']
// p: init tool [for 'new_mem_startup']
//--------------------------------------------------------------
sp_at_startup___global_arg = sp_at_startup;
+ VG_(read_procselfmaps)();
VG_(parse_procselfmaps) ( build_segment_map_callback ); /* everything */
sp_at_startup___global_arg = 0;
--- valgrind/coregrind/vg_procselfmaps.c #1.16:1.17
@@ -101,6 +101,7 @@ void VG_(read_procselfmaps)(void)
buf_n_tot = 0;
do {
+ Int want = M_PROCMAP_BUF - buf_n_tot;
n_chunk = VG_(read) ( fd, &procmap_buf[buf_n_tot],
- M_PROCMAP_BUF - buf_n_tot );
+ want > 4000 ? 4000 : want );
buf_n_tot += n_chunk;
} while ( n_chunk > 0 && buf_n_tot < M_PROCMAP_BUF );
|
|
From: Jeremy F. <je...@go...> - 2005-01-15 02:08:55
|
CVS commit by fitzhardinge:
Add a missing thread-creation track.
M +9 -7 core_os.c 1.5
--- valgrind/coregrind/linux/core_os.c #1.4:1.5
@@ -40,4 +40,6 @@ void VGA_(thread_wrapper)(ThreadId tid)
}
+ VG_TRACK ( post_thread_create, tst->os_state.parent, tid );
+
tst->os_state.lwpid = VG_(gettid)();
tst->os_state.threadgroup = VG_(getpid)();
|
|
From: Jeremy F. <je...@go...> - 2005-01-15 02:08:25
|
CVS commit by fitzhardinge:
A couple of cleanups to vg_procselfmaps and its users:
- VG_(parse_procselfmaps) now reads the file for itself, rather than relying on
the caller to call VG_(read_procselfmaps) first. VG_(read_procselfmaps) is no
longer publically visible.
- read_procselfmaps uses a dynamic buffer, to cope with any sized /proc/self/maps.
Modern programs with many mappings can make this file very large.
M +8 -13 core.h 1.63
M +16 -30 vg_main.c 1.235
M +27 -20 vg_memory.c 1.84
M +59 -45 vg_procselfmaps.c 1.18
--- valgrind/coregrind/core.h #1.62:1.63
@@ -114,7 +114,4 @@ typedef struct _ThreadState ThreadState;
#define M_VG_MSGBUF 10000
-/* Size of a big enough table used to read /proc/self/map entries. */
-#define M_PROCMAP_BUF 200000
-
/* Max length of pathname to a .so/executable file. */
#define M_VG_LIBNAMESTR 100
@@ -1074,14 +1071,8 @@ extern UInt VG_(get_n_errs_found) (
------------------------------------------------------------------ */
-/* 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 ) );
@@ -1184,6 +1175,4 @@ extern void VG_(align_BaB)( UInt );
extern Int VG_(alloc_BaB_1_set)( Addr ); // Allocate & init baseBlock slot
-extern Bool VG_(sanity_check_memory)(void);
-
/* ---------------------------------------------------------------------
Exports of vg_memory.c
@@ -1255,4 +1244,10 @@ extern REGPARM(1)
void VG_(unknown_SP_update) ( Addr new_SP );
+/* Check vg_memory structures for sanity */
+extern Bool VG_(sanity_check_memory)(void);
+
+/* Return string for prot */
+extern const Char *VG_(prot_str)(UInt prot);
+
/* ---------------------------------------------------------------------
Exports of vg_syscalls.c
--- valgrind/coregrind/vg_main.c #1.234:1.235
@@ -2310,11 +2310,8 @@ Int VG_(helper_offset)(Addr a)
/*====================================================================*/
-static void build_valgrind_map_callback
- ( Addr start, SizeT size, Char rr, Char ww, Char xx,
- UInt dev, UInt ino, ULong foffset, const UChar* filename )
+static void build_valgrind_map_callback ( Addr start, SizeT size, UInt prot,
+ UInt dev, UInt ino, ULong foffset,
+ const UChar* filename )
{
- UInt prot = 0;
- UInt flags = SF_MMAP|SF_NOSYMS;
-
/* Only record valgrind mappings for now, without loading any
symbols. This is so we know where the free space is before we
@@ -2322,9 +2319,10 @@ static void build_valgrind_map_callback
which is the problem here). */
if (start >= VG_(client_end) && (start+size-1) <= VG_(valgrind_last)) {
- flags |= SF_VALGRIND;
- if (rr == 'r') prot |= VKI_PROT_READ;
- if (ww == 'w') prot |= VKI_PROT_WRITE;
- if (xx == 'x') prot |= VKI_PROT_EXEC;
- VG_(map_file_segment)(start, size, prot, flags, dev, ino, foffset, filename);
+ if (0)
+ VG_(printf)("init1: %p-%p prot %s\n",
+ start, start+size, VG_(prot_str)(prot));
+ VG_(map_file_segment)(start, size, prot,
+ SF_MMAP|SF_NOSYMS|SF_VALGRIND,
+ dev, ino, foffset, filename);
}
}
@@ -2343,9 +2341,8 @@ Addr sp_at_startup___global_arg = 0;
will load their symtabs)>
*/
-static void build_segment_map_callback
- ( Addr start, SizeT size, Char rr, Char ww, Char xx,
- UInt dev, UInt ino, ULong foffset, const UChar* filename )
+static void build_segment_map_callback ( Addr start, SizeT size, UInt prot,
+ UInt dev, UInt ino, ULong foffset,
+ const UChar* filename )
{
- UInt prot = 0;
UInt flags;
Bool is_stack_segment;
@@ -2356,10 +2353,6 @@ static void build_segment_map_callback
if (0)
- VG_(printf)("init: %p-%p prot %c%c%c stack=%d\n",
- start, start+size, rr, ww, xx, is_stack_segment);
-
- if (rr == 'r') prot |= VKI_PROT_READ;
- if (ww == 'w') prot |= VKI_PROT_WRITE;
- if (xx == 'x') prot |= VKI_PROT_EXEC;
+ VG_(printf)("init2: %p-%p prot %s stack=%d\n",
+ start, start+size, VG_(prot_str)(prot), is_stack_segment);
if (is_stack_segment)
@@ -2394,5 +2387,6 @@ static void build_segment_map_callback
if (VG_(is_client_addr)(start) && VG_(is_client_addr)(start+size-1))
- VG_TRACK( new_mem_startup, start, size, rr=='r', ww=='w', xx=='x' );
+ VG_TRACK( new_mem_startup, start, size,
+ !!(prot & VKI_PROT_READ), !!(prot & VKI_PROT_WRITE), !!(prot & VKI_PROT_EXEC));
/* If this is the stack segment mark all below %esp as noaccess. */
@@ -2684,12 +2678,5 @@ int main(int argc, char **argv, char **e
//--------------------------------------------------------------
- // Read /proc/self/maps into a buffer
- // p: all memory layout, environment setup [so memory maps are right]
- //--------------------------------------------------------------
- VG_(read_procselfmaps)();
-
- //--------------------------------------------------------------
// Build segment map (Valgrind segments only)
- // p: read proc/self/maps
// p: sk_pre_clo_init() [to setup new_mem_startup tracker]
//--------------------------------------------------------------
@@ -2728,5 +2715,4 @@ int main(int argc, char **argv, char **e
//--------------------------------------------------------------
sp_at_startup___global_arg = sp_at_startup;
- VG_(read_procselfmaps)();
VG_(parse_procselfmaps) ( build_segment_map_callback ); /* everything */
sp_at_startup___global_arg = 0;
--- valgrind/coregrind/vg_memory.c #1.83:1.84
@@ -909,9 +909,29 @@ void *VG_(shadow_alloc)(UInt size)
/*--------------------------------------------------------------------*/
+const Char *VG_(prot_str)(UInt prot)
+{
+ static const Char *str[] = {
+ "---",
+ "r--",
+ "-w-",
+ "rw-",
+ "--x",
+ "r-x",
+ "-wx",
+ "rwx",
+ };
+
+ vg_assert(VKI_PROT_READ == 1);
+ vg_assert(VKI_PROT_WRITE == 2);
+ vg_assert(VKI_PROT_EXEC == 4);
+
+ return str[prot & 7];
+}
+
static Segment *next_segment;
static Bool segment_maps_ok;
static Addr prevmapstart, prevmapend;
-static void check_segment_maps(Addr addr, SizeT len, Char rr, Char ww, Char xx,
+static void check_segment_maps(Addr addr, SizeT len, UInt prot,
UInt dev, UInt ino, ULong foff, const UChar *filename)
{
@@ -919,5 +939,4 @@ static void check_segment_maps(Addr addr
Addr end = addr+len;
Segment *seg, *next, *prev;
- UInt prot;
if (addr >= VG_(valgrind_last))
@@ -932,9 +951,4 @@ static void check_segment_maps(Addr addr
prevmapend = end;
- prot = 0;
- prot |= rr == 'r' ? VKI_PROT_READ : 0;
- prot |= ww == 'w' ? VKI_PROT_WRITE: 0;
- prot |= xx == 'x' ? VKI_PROT_EXEC : 0;
-
if (next_segment == NULL)
seg = VG_(first_segment)();
@@ -989,11 +1003,9 @@ static void check_segment_maps(Addr addr
if (0)
- VG_(printf)("seg: %p-%p (%c%c%c) %4x mapping %p-%p %x (%c%c%c) %s%s %s\n",
+ VG_(printf)("seg: %p-%p (%s) %4x mapping %p-%p %s %s%s %s\n",
seg->addr, segend,
- seg->prot & VKI_PROT_READ ? 'r' : '-',
- seg->prot & VKI_PROT_WRITE? 'w' : '-',
- seg->prot & VKI_PROT_EXEC ? 'x' : '-',
+ VG_(prot_str)(seg->prot),
seg->flags,
- addr, end, prot, rr, ww, xx,
+ addr, end, VG_(prot_str)(prot),
(addr == seg->addr && segend == end) ? "" : " !!!",
(seg->prot & prot) != seg->prot ? " ???" : "",
@@ -1010,11 +1022,9 @@ static void check_segment_maps(Addr addr
if ((seg->prot & prot) != seg->prot) {
- VG_(printf)("INV 4 FAILED: seg %p-%p permissions %c%c%c not subset of mapping %p-%p permissions %c%c%c\n",
+ VG_(printf)("INV 4 FAILED: seg %p-%p permissions %s not subset of mapping %p-%p permissions %s\n",
seg->addr, segend,
- seg->prot & VKI_PROT_READ ? 'r' : '-',
- seg->prot & VKI_PROT_WRITE? 'w' : '-',
- seg->prot & VKI_PROT_EXEC ? 'x' : '-',
+ VG_(prot_str)(seg->prot),
addr, end,
- rr, ww, xx);
+ VG_(prot_str)(prot));
segment_maps_ok = False;
}
@@ -1104,7 +1114,4 @@ Bool VG_(sanity_check_memory)(void)
}
- /* Now compare with /proc/self/maps */
- VG_(read_procselfmaps)();
-
next_segment = NULL;
segment_maps_ok = True;
--- valgrind/coregrind/vg_procselfmaps.c #1.17:1.18
@@ -33,12 +33,4 @@
#include "core.h"
-
-/* static ... to keep it out of the stack frame. */
-static Char procmap_buf[M_PROCMAP_BUF];
-
-/* Records length of /proc/self/maps read into procmap_buf. */
-static Int buf_n_tot;
-
-
/* Helper fns. */
@@ -57,5 +49,5 @@ static Int decdigit ( Char c )
}
-static Int readchar ( Char* buf, Char* ch )
+static Int readchar ( const Char* buf, Char* ch )
{
if (*buf == 0) return 0;
@@ -64,5 +56,5 @@ static Int readchar ( Char* buf, Char* c
}
-static Int readhex ( Char* buf, UWord* val )
+static Int readhex ( const Char* buf, UWord* val )
{
Int n = 0;
@@ -75,5 +67,5 @@ static Int readhex ( Char* buf, UWord* v
}
-static Int readdec ( Char* buf, UInt* val )
+static Int readdec ( const Char* buf, UInt* val )
{
Int n = 0;
@@ -87,8 +79,13 @@ static Int readdec ( Char* buf, UInt* va
-/* Read /proc/self/maps, store the contents in a static buffer. If there's
- a syntax error or other failure, just abort. */
-void VG_(read_procselfmaps)(void)
+/* Read /proc/self/maps, store the contents in a buffer. If there's a
+ syntax error or other failure, just abort. The buffer size is
+ increased dynamically to fit whatever sized contents we need to
+ read. It can get pretty big in some programs. */
+static const Char *read_procselfmaps(Int *maps_size)
{
+ static Char *buffer;
+ static Int bufsize = 1024;
+ Int bufused = 0;
Int n_chunk, fd;
@@ -99,22 +96,34 @@ void VG_(read_procselfmaps)(void)
VG_(exit)(1);
}
- buf_n_tot = 0;
+
+ bufused = 0;
+ if (buffer == NULL)
+ buffer = VG_(arena_malloc)(VG_AR_CORE, bufsize);
+
do {
- Int want = M_PROCMAP_BUF - buf_n_tot;
- n_chunk = VG_(read) ( fd, &procmap_buf[buf_n_tot],
- want > 4000 ? 4000 : want );
- buf_n_tot += n_chunk;
- } while ( n_chunk > 0 && buf_n_tot < M_PROCMAP_BUF );
- VG_(close)(fd);
- if (buf_n_tot >= M_PROCMAP_BUF-5) {
- VG_(message)(Vg_UserMsg, "FATAL: M_PROCMAP_BUF is too small; "
- "increase it and recompile");
- VG_(exit)(1);
+ Int want = bufsize - bufused;
+ n_chunk = VG_(read) ( fd, &buffer[bufused], want );
+
+ if (n_chunk < 0) {
+ VG_(message)(Vg_UserMsg, "FATAL: read error on /proc/self/maps");
+ VG_(exit)(99);
}
- if (buf_n_tot == 0) {
+
+ bufused += n_chunk;
+
+ if (bufused == bufsize) {
+ bufsize *= 2;
+ buffer = VG_(arena_realloc)(VG_AR_CORE, buffer, VG_MIN_MALLOC_SZB, bufsize);
+ }
+ } while ( n_chunk > 0 );
+ VG_(close)(fd);
+ if (bufused == 0) {
VG_(message)(Vg_UserMsg, "FATAL: I/O error on /proc/self/maps" );
VG_(exit)(1);
}
- procmap_buf[buf_n_tot] = 0;
+ buffer[bufused] = '\0';
+
+ *maps_size = bufused;
+ return buffer;
}
@@ -124,7 +133,6 @@ void VG_(read_procselfmaps)(void)
start address in memory
length
- r permissions char; either - or r
- w permissions char; either - or w
- x permissions char; either - or x
+ page protections (using the VKI_PROT_* flags)
+ mapped file device and inode
offset in file, or zero if no file
filename, zero terminated, or NULL if no file
@@ -132,16 +140,13 @@ void VG_(read_procselfmaps)(void)
So the sig of the called fn might be
- void (*record_mapping)( Addr start, SizeT size,
- Char r, Char w, Char x,
+ void (*record_mapping)( Addr start, SizeT size, UInt prot,
+ UInt dev, UInt info,
ULong foffset, UChar* filename )
Note that the supplied filename is transiently stored; record_mapping
should make a copy if it wants to keep it.
-
- Nb: it is important that this function does not alter the contents of
- procmap_buf!
*/
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 )
)
@@ -153,4 +158,9 @@ void VG_(parse_procselfmaps) (
UInt ino;
UWord foffset, maj, min;
+ const Char *procmap_buf;
+ Int buf_n_tot;
+ UInt prot;
+
+ procmap_buf = read_procselfmaps(&buf_n_tot);
sk_assert( '\0' != procmap_buf[0] && 0 != buf_n_tot);
@@ -223,5 +233,5 @@ void VG_(parse_procselfmaps) (
/* Try and find the name of the file mapped to this segment, if
it exists. */
- while (procmap_buf[i] != '\n' && i < M_PROCMAP_BUF-1) i++;
+ while (procmap_buf[i] != '\n' && i < buf_n_tot-1) i++;
i_eol = i;
i--;
@@ -231,21 +241,25 @@ void VG_(parse_procselfmaps) (
/* Minor hack: put a '\0' at the filename end for the call to
`record_mapping', then restore the old char with `tmp'. */
- filename = &procmap_buf[i];
- tmp = filename[i_eol - i];
+ filename = VG_(arena_malloc)(VG_AR_CORE, i_eol-i);
+ VG_(memcpy)(filename, &procmap_buf[i], i_eol-i);
filename[i_eol - i] = '\0';
} else {
- tmp = '\0';
+ tmp = 0;
filename = NULL;
foffset = 0;
}
+ prot = 0;
+ if (rr == 'r') prot |= VKI_PROT_READ;
+ if (ww == 'w') prot |= VKI_PROT_WRITE;
+ if (xx == 'x') prot |= VKI_PROT_EXEC;
+
if (start < VG_(valgrind_last))
(*record_mapping) ( start, endPlusOne-start,
- rr, ww, xx, maj * 256 + min, ino,
+ prot, maj * 256 + min, ino,
foffset, filename );
- if ('\0' != tmp) {
- filename[i_eol - i] = tmp;
- }
+ if (filename != NULL)
+ VG_(arena_free)(VG_AR_CORE, filename);
i = i_eol + 1;
|
|
From: Jeremy F. <je...@go...> - 2005-01-15 02:08:02
|
CVS commit by fitzhardinge:
Use sigreturn/rt_sigreturn to finish a signal handler rather than
using a client request. This allows clients to use SA_RESTORER, and
it helps gdb understand the signal stack frames Valgrind generates.
M +3 -5 core.h 1.61
M +3 -6 vg_scheduler.c 1.209
M +2 -24 vg_signals.c 1.110
M +5 -0 x86/core_arch.h 1.18
M +16 -17 x86/helpers.S 1.3
M +272 -184 x86/signal.c 1.10
M +32 -2 x86-linux/syscalls.c 1.12
--- valgrind/coregrind/x86/helpers.S #1.2:1.3
@@ -29,4 +29,5 @@
#include "core_asm.h"
+#include "vki_unistd.h"
/* ------------------ SIMULATED CPU HELPERS ------------------ */
@@ -45,24 +46,20 @@
.global VG_(trampoline_code_length)
.global VG_(tramp_sigreturn_offset)
+.global VG_(tramp_rt_sigreturn_offset)
.global VG_(tramp_syscall_offset)
VG_(trampoline_code_start):
-sigreturn_start:
- subl $20, %esp # allocate arg block
- movl %esp, %edx # %edx == &_zzq_args[0]
- movl $VG_USERREQ__SIGNAL_RETURNS, 0(%edx) # request
- movl $0, 4(%edx) # arg1
- movl $0, 8(%edx) # arg2
- movl $0, 12(%edx) # arg3
- movl $0, 16(%edx) # arg4
- movl %edx, %eax
- # and now the magic sequence itself:
- roll $29, %eax
- roll $3, %eax
- rorl $27, %eax
- rorl $5, %eax
- roll $13, %eax
- roll $19, %eax
- # should never get here
+sigreturn_start:
+ /* This is a very specific sequence which GDB uses to
+ recognize signal handler frames. */
+ popl %eax
+ movl $__NR_sigreturn, %eax
+ int $0x80
+ ud2
+
+rt_sigreturn_start:
+ /* Likewise for rt signal frames */
+ movl $__NR_rt_sigreturn, %eax
+ int $0x80
ud2
@@ -79,4 +76,6 @@
VG_(tramp_sigreturn_offset):
.long sigreturn_start - VG_(trampoline_code_start)
+VG_(tramp_rt_sigreturn_offset):
+ .long rt_sigreturn_start - VG_(trampoline_code_start)
VG_(tramp_syscall_offset):
.long syscall_start - VG_(trampoline_code_start)
--- valgrind/coregrind/x86/signal.c #1.9:1.10
@@ -38,37 +38,17 @@
// during the execution of signal handlers.
-typedef
- struct {
- /* There are two different stack frame formats, depending on
- whether the client set the SA_SIGINFO flag for the handler.
- This structure is put onto the client's stack as part of
- signal delivery, and therefore appears as the signal
- handler's arguments.
-
- The first two words are common for both frame formats -
- they're the return address and the signal number. */
-
- /* Sig handler's return address */
- Addr retaddr;
- /* The arg to the sig handler. We need to inspect this after
- the handler returns, but it's unreasonable to assume that the
- handler won't change it. So we keep a second copy of it in
- sigNo_private. */
- Int sigNo;
-
- /* This is where the two frames start differing. */
- union {
- struct { /* set SA_SIGINFO */
- /* ptr to siginfo_t. */
- Addr psigInfo;
-
- /* ptr to ucontext */
- Addr puContext;
- } sigInfo;
- struct vki_sigcontext sigContext; /* did not set SA_SIGINFO */
- } handlerArgs;
-
- /* The rest are private fields which the handler is unaware of. */
+// Linux has 2 signal frame structures: one for normal signal
+// deliveries, and one for SA_SIGINFO deliveries (also known as RT
+// signals).
+//
+// In theory, so long as we get the arguments to the handler function
+// right, it doesn't matter what the exact layout of the rest of the
+// frame is. Unfortunately, things like gcc's exception unwinding
+// make assumptions about the locations of various parts of the frame,
+// so we need to duplicate it exactly.
+/* Valgrind-specific parts of the signal frame */
+struct vg_sigframe
+{
/* Sanity check word. */
UInt magicPI;
@@ -76,9 +56,4 @@ typedef
UInt handlerflags; /* flags for signal handler */
- /* pointed to by psigInfo */
- vki_siginfo_t sigInfo;
- /* pointed to by puContext */
- struct vki_ucontext uContext;
- struct _vki_fpstate fpstate;
/* Safely-saved version of sigNo, as described above. */
@@ -103,6 +78,38 @@ typedef
move!*/
UInt magicE;
- }
- VgSigFrame;
+};
+
+struct sigframe
+{
+ /* Sig handler's return address */
+ Addr retaddr;
+ Int sigNo;
+
+ struct vki_sigcontext sigContext;
+ struct _vki_fpstate fpstate;
+
+ struct vg_sigframe vg;
+};
+
+struct rt_sigframe
+{
+ /* Sig handler's return address */
+ Addr retaddr;
+ Int sigNo;
+
+ /* ptr to siginfo_t. */
+ Addr psigInfo;
+
+ /* ptr to ucontext */
+ Addr puContext;
+ /* pointed to by psigInfo */
+ vki_siginfo_t sigInfo;
+
+ /* pointed to by puContext */
+ struct vki_ucontext uContext;
+ struct _vki_fpstate fpstate;
+
+ struct vg_sigframe vg;
+};
/*------------------------------------------------------------*/
@@ -343,31 +350,21 @@ static void synth_ucontext(ThreadId tid,
post_reg_write_deliver_signal)
-void VGA_(push_signal_frame)(ThreadId tid, Addr esp_top_of_frame,
- const vki_siginfo_t *siginfo,
- void *handler, UInt flags,
- const vki_sigset_t *mask)
+static Bool extend(ThreadState *tst, Addr addr, SizeT size)
{
- Addr esp;
- ThreadState* tst = VG_(get_ThreadState)(tid);
- VgSigFrame* frame;
- Int sigNo = siginfo->si_signo;
+ ThreadId tid = tst->tid;
Segment *stackseg = NULL;
- esp = esp_top_of_frame;
- esp -= sizeof(VgSigFrame);
- frame = (VgSigFrame*)esp;
-
- if (VG_(extend_stack)((Addr)frame, tst->stack_size)) {
- stackseg = VG_(find_segment)((Addr)frame);
+ if (VG_(extend_stack)(addr, tst->stack_size)) {
+ stackseg = VG_(find_segment)(addr);
if (0 && stackseg)
VG_(printf)("frame=%p seg=%p-%p\n",
- frame, stackseg->addr, stackseg->addr+stackseg->len);
+ addr, stackseg->addr, stackseg->addr+stackseg->len);
}
if (stackseg == NULL ||
- !VG_(is_addressable)((Addr)frame, sizeof(*frame), VKI_PROT_READ|VKI_PROT_WRITE)) {
+ !VG_(is_addressable)(addr, size, VKI_PROT_READ|VKI_PROT_WRITE)) {
VG_(message)(Vg_UserMsg,
"Can't extend stack to %p during signal delivery for thread %d:",
- frame, tid);
+ addr, tid);
if (stackseg == NULL)
VG_(message)(Vg_UserMsg, " no stack segment");
@@ -377,67 +374,26 @@ void VGA_(push_signal_frame)(ThreadId ti
/* set SIGSEGV to default handler */
VG_(set_default_handler)(VKI_SIGSEGV);
- VG_(synth_fault_mapping)(tid, (Addr)frame);
+ VG_(synth_fault_mapping)(tid, addr);
/* The whole process should be about to die, since the default
action of SIGSEGV to kill the whole process. */
- return;
+ return False;
}
/* For tracking memory events, indicate the entire frame has been
- * allocated, but pretend that only the first four words are written */
- VG_TRACK( new_mem_stack_signal, (Addr)frame, sizeof(VgSigFrame) );
+ allocated. */
+ VG_TRACK( new_mem_stack_signal, addr, size );
- /* Assert that the frame is placed correctly. */
- vg_assert( (sizeof(VgSigFrame) & 0x3) == 0 );
- vg_assert( ((Char*)(&frame->magicE)) + sizeof(UInt)
- == ((Char*)(esp_top_of_frame)) );
+ return True;
+}
- /* retaddr, sigNo, psigInfo, puContext fields are to be written */
- VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
- (Addr)frame, offsetof(VgSigFrame, handlerArgs) );
- frame->retaddr = (UInt)VG_(client_trampoline_code)+VG_(tramp_sigreturn_offset);
- frame->sigNo = sigNo;
+static void build_vg_sigframe(struct vg_sigframe *frame,
+ ThreadState *tst,
+ const vki_sigset_t *mask,
+ UInt flags,
+ Int sigNo)
+{
frame->sigNo_private = sigNo;
- VG_TRACK( post_mem_write, (Addr)frame, offsetof(VgSigFrame, handlerArgs) );
-
- if (flags & VKI_SA_SIGINFO) {
- /* if the client asked for a siginfo delivery, then build the stack that way */
-
- /* pointers to siginfo and ucontext */
- VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (siginfo)",
- (Addr)&frame->handlerArgs, sizeof(frame->handlerArgs.sigInfo) );
- frame->handlerArgs.sigInfo.psigInfo = (Addr)&frame->sigInfo;
- frame->handlerArgs.sigInfo.puContext = (Addr)&frame->uContext;
- VG_TRACK( post_mem_write, (Addr)&frame->handlerArgs, sizeof(frame->handlerArgs.sigInfo) );
-
- /* siginfo */
- VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (siginfo)",
- (Addr)&frame->sigInfo, sizeof(frame->sigInfo) );
- VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_siginfo_t));
- VG_TRACK( post_mem_write, (Addr)&frame->sigInfo, sizeof(frame->sigInfo) );
-
- /* ucontext */
- VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (ucontext)",
- (Addr)&frame->uContext, sizeof(frame->uContext) );
- synth_ucontext(tid, siginfo, mask, &frame->uContext, &frame->fpstate);
- VG_TRACK( post_mem_write, (Addr)&frame->uContext, sizeof(frame->uContext) );
- } else {
- struct vki_ucontext uc;
-
- /* non-siginfo: just put the sigcontext there */
-
- synth_ucontext(tid, siginfo, mask, &uc, &frame->fpstate);
-
- VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame (sigcontext)",
- (Addr)&frame->handlerArgs, sizeof(frame->handlerArgs.sigContext) );
- VG_(memcpy)(&frame->handlerArgs.sigContext, &uc.uc_mcontext,
- sizeof(struct vki_sigcontext));
- VG_TRACK( post_mem_write, (Addr)&frame->handlerArgs,
- sizeof(frame->handlerArgs.sigContext) );
-
- frame->handlerArgs.sigContext.oldmask = tst->sig_mask.sig[0];
- }
-
frame->magicPI = 0x31415927;
@@ -459,7 +415,112 @@ void VGA_(push_signal_frame)(ThreadId ti
frame->magicE = 0x27182818;
+}
+
+static Addr build_sigframe(ThreadState *tst,
+ Addr esp_top_of_frame,
+ const vki_siginfo_t *siginfo,
+ void *handler, UInt flags,
+ const vki_sigset_t *mask,
+ void *restorer)
+{
+ struct sigframe *frame;
+ Addr esp = esp_top_of_frame;
+ Int sigNo = siginfo->si_signo;
+ struct vki_ucontext uc;
+
+ esp -= sizeof(*frame);
+ esp = ROUNDDN(esp, 16);
+ frame = (struct sigframe *)esp;
+
+ if (!extend(tst, esp, sizeof(*frame)))
+ return esp_top_of_frame;
+
+ /* retaddr, sigNo, siguContext fields are to be written */
+ VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "signal handler frame",
+ esp, offsetof(struct sigframe, vg) );
+
+ frame->sigNo = sigNo;
+
+ if (flags & VKI_SA_RESTORER)
+ frame->retaddr = (Addr)restorer;
+ else {
+ if (flags & VKI_SA_SIGINFO)
+ frame->retaddr = (UInt)VG_(client_trampoline_code)+VG_(tramp_rt_sigreturn_offset);
+ else
+ frame->retaddr = (UInt)VG_(client_trampoline_code)+VG_(tramp_sigreturn_offset);
+ }
+
+ synth_ucontext(tst->tid, siginfo, mask, &uc, &frame->fpstate);
+
+ VG_(memcpy)(&frame->sigContext, &uc.uc_mcontext,
+ sizeof(struct vki_sigcontext));
+ frame->sigContext.oldmask = tst->sig_mask.sig[0];
+
+ VG_TRACK( post_mem_write, esp, offsetof(struct sigframe, vg) );
+
+ build_vg_sigframe(&frame->vg, tst, mask, flags, sigNo);
+
+ return esp;
+}
+
+static Addr build_rt_sigframe(ThreadState *tst,
+ Addr esp_top_of_frame,
+ const vki_siginfo_t *siginfo,
+ void *handler, UInt flags,
+ const vki_sigset_t *mask,
+ void *restorer)
+{
+ struct rt_sigframe *frame;
+ Addr esp = esp_top_of_frame;
+ Int sigNo = siginfo->si_signo;
+
+ esp -= sizeof(*frame);
+ esp = ROUNDDN(esp, 16);
+ frame = (struct rt_sigframe *)esp;
+
+ if (!extend(tst, esp, sizeof(*frame)))
+ return esp_top_of_frame;
+
+ /* retaddr, sigNo, pSiginfo, puContext fields are to be written */
+ VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "rt signal handler frame",
+ esp, offsetof(struct rt_sigframe, vg) );
+
+ frame->sigNo = sigNo;
+
+ if (flags & VKI_SA_RESTORER)
+ frame->retaddr = (Addr)restorer;
+ else {
+ if (flags & VKI_SA_SIGINFO)
+ frame->retaddr = (UInt)VG_(client_trampoline_code)+VG_(tramp_rt_sigreturn_offset);
+ else
+ frame->retaddr = (UInt)VG_(client_trampoline_code)+VG_(tramp_sigreturn_offset);
+ }
+
+ frame->psigInfo = (Addr)&frame->sigInfo;
+ frame->puContext = (Addr)&frame->uContext;
+ VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_siginfo_t));
+ synth_ucontext(tst->tid, siginfo, mask, &frame->uContext, &frame->fpstate);
+
+ VG_TRACK( post_mem_write, esp, offsetof(struct rt_sigframe, vg) );
+
+ build_vg_sigframe(&frame->vg, tst, mask, flags, sigNo);
+
+ return esp;
+}
+
+void VGA_(push_signal_frame)(ThreadId tid, Addr esp_top_of_frame,
+ const vki_siginfo_t *siginfo,
+ void *handler, UInt flags,
+ const vki_sigset_t *mask,
+ void *restorer)
+{
+ Addr esp;
+ ThreadState* tst = VG_(get_ThreadState)(tid);
+
+ if (flags & VKI_SA_SIGINFO)
+ esp = build_rt_sigframe(tst, esp_top_of_frame, siginfo, handler, flags, mask, restorer);
+ else
+ esp = build_sigframe(tst, esp_top_of_frame, siginfo, handler, flags, mask, restorer);
- /* Ensure 'tid' and 'tst' correspond */
- vg_assert(& VG_(threads)[tid] == tst);
/* Set the thread so it will next run the handler. */
/* tst->m_esp = esp; */
@@ -476,32 +537,38 @@ void VGA_(push_signal_frame)(ThreadId ti
}
-Int VGA_(pop_signal_frame)(ThreadId tid)
+static Bool restore_vg_sigframe(ThreadState *tst, struct vg_sigframe *frame, Int *sigNo)
{
- Addr esp;
- VgSigFrame* frame;
- ThreadState* tst;
- struct vki_sigcontext *sc;
-
- vg_assert(VG_(is_valid_tid)(tid));
- tst = & VG_(threads)[tid];
+ if (frame->magicPI != 0x31415927 ||
+ frame->magicE != 0x27182818) {
+ VG_(message)(Vg_UserMsg, "Thread %d return signal frame corrupted. Killing process.",
+ tst->tid);
+ VG_(set_default_handler)(VKI_SIGSEGV);
+ VG_(synth_fault)(tst->tid);
+ *sigNo = VKI_SIGSEGV;
+ return False;
+ }
- /* Correctly reestablish the frame base address. */
- esp = tst->arch.m_esp;
- frame = (VgSigFrame*)
- (esp -4 /* because the handler's RET pops the RA */
- +20 /* because signalreturn_bogusRA pushes 5 words */);
+ tst->sig_mask = frame->mask;
- vg_assert(frame->magicPI == 0x31415927);
- vg_assert(frame->magicE == 0x27182818);
+ if (VG_(needs).shadow_regs) {
+ tst->arch.sh_eax = frame->sh_eax;
+ tst->arch.sh_ecx = frame->sh_ecx;
+ tst->arch.sh_edx = frame->sh_edx;
+ tst->arch.sh_ebx = frame->sh_ebx;
+ tst->arch.sh_ebp = frame->sh_ebp;
+ tst->arch.sh_esp = frame->sh_esp;
+ tst->arch.sh_esi = frame->sh_esi;
+ tst->arch.sh_edi = frame->sh_edi;
+ tst->arch.sh_eflags = frame->sh_eflags;
+ }
- /* Mark the frame structure as nonaccessible. */
- VG_TRACK( die_mem_stack_signal, (Addr)frame, sizeof(VgSigFrame) );
+ *sigNo = frame->sigNo_private;
- /* restore machine state */
- if (frame->handlerflags & VKI_SA_SIGINFO)
- sc = &frame->uContext.uc_mcontext;
- else
- sc = &frame->handlerArgs.sigContext;
+ return True;
+}
+static void restore_sigcontext(ThreadState *tst, struct vki_sigcontext *sc,
+ struct _vki_fpstate *fpstate)
+{
tst->arch.m_eax = sc->eax;
tst->arch.m_ecx = sc->ecx;
@@ -522,28 +589,49 @@ Int VGA_(pop_signal_frame)(ThreadId tid)
tst->arch.m_gs = sc->gs;
- restore_i387(&tst->arch, &frame->fpstate);
+ restore_i387(&tst->arch, fpstate);
+}
- if (VG_(needs).shadow_regs) {
- tst->arch.sh_eax = frame->sh_eax;
- tst->arch.sh_ecx = frame->sh_ecx;
- tst->arch.sh_edx = frame->sh_edx;
- tst->arch.sh_ebx = frame->sh_ebx;
- tst->arch.sh_ebp = frame->sh_ebp;
- tst->arch.sh_esp = frame->sh_esp;
- tst->arch.sh_esi = frame->sh_esi;
- tst->arch.sh_edi = frame->sh_edi;
- tst->arch.sh_eflags = frame->sh_eflags;
- }
+static SizeT restore_sigframe(ThreadState *tst, struct sigframe *frame, Int *sigNo)
+{
+ if (restore_vg_sigframe(tst, &frame->vg, sigNo))
+ restore_sigcontext(tst, &frame->sigContext, &frame->fpstate);
+
+ return sizeof(*frame);
+}
+
+static SizeT restore_rt_sigframe(ThreadState *tst, struct rt_sigframe *frame, Int *sigNo)
+{
+ if (restore_vg_sigframe(tst, &frame->vg, sigNo))
+ restore_sigcontext(tst, &frame->uContext.uc_mcontext, &frame->fpstate);
+
+ return sizeof(*frame);
+}
+
+void VGA_(signal_return)(ThreadId tid, Bool isRT)
+{
+ Addr esp;
+ ThreadState* tst;
+ SizeT size;
+ Int sigNo;
+
+ tst = VG_(get_ThreadState)(tid);
+
+ /* Correctly reestablish the frame base address. */
+ esp = tst->arch.m_esp;
+
+ if (!isRT)
+ size = restore_sigframe(tst, (struct sigframe *)esp, &sigNo);
+ else
+ size = restore_rt_sigframe(tst, (struct rt_sigframe *)esp, &sigNo);
+
+ VG_TRACK( die_mem_stack_signal, esp, size );
if (VG_(clo_trace_signals))
VG_(message)(Vg_DebugMsg,
- "vg_pop_signal_frame (thread %d): valid magic; EIP=%p",
- tid, sc->eip);
-
- tst->sig_mask = frame->mask;
+ "vg_pop_signal_frame (thread %d): isRT=%d valid magic; EIP=%p",
+ tid, isRT, tst->arch.m_eip);
- /* don't use the copy exposed to the handler; it might have changed
- it. */
- return frame->sigNo_private;
+ /* tell the tools */
+ VG_TRACK( post_deliver_signal, tid, sigNo );
}
--- valgrind/coregrind/x86/core_arch.h #1.17:1.18
@@ -351,4 +351,9 @@ struct arch_thread_aux {
/* ---------------------------------------------------------------------
+ Signal stuff (should be plat)
+ ------------------------------------------------------------------ */
+void VGA_(signal_return)(ThreadId tid, Bool isRT);
+
+/* ---------------------------------------------------------------------
Miscellaneous constants
------------------------------------------------------------------ */
--- valgrind/coregrind/core.h #1.60:1.61
@@ -869,7 +869,4 @@ extern void VG_(do_pthread_sigmask_SCSS_
vki_sigset_t* oldset );
-/* Restore thread's state on return from a signal handler */
-extern void VG_(signal_returns) ( ThreadId tid );
-
/* Handy utilities to block/restore all host signals. */
extern void VG_(block_all_host_signals)
@@ -1667,4 +1664,5 @@ extern const Char VG_(trampoline_code_st
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);
@@ -1764,6 +1762,6 @@ extern void VGA_(push_signal_frame) ( Th
const vki_siginfo_t *siginfo,
void *handler, UInt flags,
- const vki_sigset_t *mask);
-extern Int VGA_(pop_signal_frame) ( ThreadId tid );
+ const vki_sigset_t *mask,
+ void *restorer );
#define MY__STRING(__str) #__str
--- valgrind/coregrind/vg_scheduler.c #1.208:1.209
@@ -536,5 +536,5 @@ UInt run_thread_for_a_while ( ThreadId t
if (VG_(is_VCPU_thread)(tid))
VG_(save_thread_state) ( tid );
- else
+
vg_assert(VG_(get_VCPU_tid)() == VG_INVALID_THREADID);
@@ -983,8 +983,4 @@ void do_client_request ( ThreadId tid )
break;
- case VG_USERREQ__SIGNAL_RETURNS:
- VG_(signal_returns)(tid);
- break;
-
case VG_USERREQ__PRINTF: {
int count =
@@ -1097,4 +1093,5 @@ void do_client_request ( ThreadId tid )
case VG_USERREQ__GET_SIGRT_MAX:
case VG_USERREQ__ALLOC_RTSIG:
+ case VG_USERREQ__SIGNAL_RETURNS: /* not pthreads, but obsolete */
VG_(message)(Vg_UserMsg, "It looks like you've got an old libpthread.so* ");
VG_(message)(Vg_UserMsg, "installed in \"%s\".", VG_(libdir));
--- valgrind/coregrind/vg_signals.c #1.109:1.110
@@ -749,31 +749,9 @@ void vg_push_signal_frame ( ThreadId tid
vg_scss.scss_per_sig[sigNo].scss_handler,
vg_scss.scss_per_sig[sigNo].scss_flags,
- &vg_scss.scss_per_sig[sigNo].scss_mask);
-}
-
-/* Clear the signal frame created by vg_push_signal_frame, restore the
- simulated machine state. */
-static
-void vg_pop_signal_frame ( ThreadId tid )
-{
- Int sigNo = VGA_(pop_signal_frame)(tid);
-
- /* Notify tools */
- VG_TRACK( post_deliver_signal, tid, sigNo );
+ &vg_scss.scss_per_sig[sigNo].scss_mask,
+ vg_scss.scss_per_sig[sigNo].scss_restorer);
}
-/* A handler is returning. Restore the machine state from the stacked
- VgSigContext and continue with whatever was going on before the
- handler ran. Returns the SA_RESTART syscall-restartability-status
- of the delivered signal. */
-
-void VG_(signal_returns) ( ThreadId tid )
-{
- /* Pop the signal frame and restore tid's status to what it was
- before the signal was delivered. */
- vg_pop_signal_frame(tid);
-}
-
static const Char *signame(Int sigNo)
{
--- valgrind/coregrind/x86-linux/syscalls.c #1.11:1.12
@@ -463,4 +463,34 @@ PRE(sys_clone, Special)
}
+PRE(sys_sigreturn, Special)
+{
+ PRINT("sigreturn ( )");
+
+ /* Adjust esp to point to start of frame; skip back up over
+ sigreturn sequence's "popl %eax" and handler ret addr */
+ tst->arch.m_esp -= sizeof(Addr)+sizeof(Word);
+
+ /* This is only so that the EIP is (might be) useful to report if
+ something goes wrong in the sigreturn */
+ restart_syscall(&tst->arch);
+
+ VGA_(signal_return)(tid, False);
+}
+
+PRE(sys_rt_sigreturn, Special)
+{
+ PRINT("rt_sigreturn ( )");
+
+ /* Adjust esp to point to start of frame; skip back up over handler
+ ret addr */
+ tst->arch.m_esp -= sizeof(Addr);
+
+ /* This is only so that the EIP is (might be) useful to report if
+ something goes wrong in the sigreturn */
+ restart_syscall(&tst->arch);
+
+ VGA_(signal_return)(tid, True);
+}
+
PRE(sys_modify_ldt, Special)
{
@@ -698,5 +728,5 @@ const struct SyscallTableEntry VGA_(sysc
GENXY(__NR_ipc, sys_ipc), // 117
GENX_(__NR_fsync, sys_fsync), // 118
- // (__NR_sigreturn, sys_sigreturn), // 119 ?/Linux
+ PLAX_(__NR_sigreturn, sys_sigreturn), // 119 ?/Linux
PLAX_(__NR_clone, sys_clone), // 120
@@ -765,5 +795,5 @@ const struct SyscallTableEntry VGA_(sysc
LINXY(__NR_getresgid, sys_getresgid16), // 171
LINX_(__NR_prctl, sys_prctl), // 172
- // (__NR_rt_sigreturn, sys_rt_sigreturn), // 173 x86/Linux only?
+ PLAX_(__NR_rt_sigreturn, sys_rt_sigreturn), // 173 x86/Linux only?
GENXY(__NR_rt_sigaction, sys_rt_sigaction), // 174
|
|
From: Jeremy F. <je...@go...> - 2005-01-15 02:07:49
|
CVS commit by fitzhardinge:
Fix up a nasty little race on thread exit. After the thread sets the
status to Empty and releases run_sema, it could get recycled. Since
there's a little bit of code which needs to run after unlocking,
there's a chance that it could get its stack stolen from under it.
The solution it to use a temporary Zombie state, which prevents the
thread structure from being reallocated. The thread exit code then
sets the state to Empty and exits without touching the stack in the
meantime.
M +2 -1 core.h 1.60
M +2 -0 vg_main.c 1.233
M +15 -4 vg_scheduler.c 1.208
M +0 -6 linux/core_os.c 1.4
M +15 -9 x86-linux/syscalls.c 1.11
--- valgrind/coregrind/core.h #1.59:1.60
@@ -604,5 +604,5 @@ typedef struct
Empty -> Init -> Runnable <=> WaitSys/Yielding
^ |
- \-----------------/
+ \---- Zombie -----/
*/
typedef
@@ -613,4 +613,5 @@ typedef
VgTs_WaitSys, /* waiting for a syscall to complete */
VgTs_Yielding, /* temporarily yielding the CPU */
+ VgTs_Zombie, /* transient state just before exiting */
}
ThreadStatus;
--- valgrind/coregrind/vg_scheduler.c #1.207:1.208
@@ -212,4 +212,5 @@ const Char* name_of_thread_state ( Threa
case VgTs_WaitSys: return "VgTs_WaitSys";
case VgTs_Yielding: return "VgTs_Yielding";
+ case VgTs_Zombie: return "VgTs_Zombie";
default: return "VgTs_???";
}
@@ -321,5 +322,6 @@ Int VG_(count_living_threads)(void)
for(tid = 1; tid < VG_N_THREADS; tid++)
- if (VG_(threads)[tid].status != VgTs_Empty)
+ if (VG_(threads)[tid].status != VgTs_Empty &&
+ VG_(threads)[tid].status != VgTs_Zombie)
count++;
@@ -367,5 +369,7 @@ inline Bool VG_(is_exiting)(ThreadId tid
}
-/* Mark the the ThreadState as unused and release the semaphore */
+/* Clear out the ThreadState and release the semaphore. Leaves the
+ ThreadState in VgTs_Zombie state, so that it doesn't get
+ reallocated until the caller is really ready. */
void VG_(exit_thread)(ThreadId tid)
{
@@ -404,5 +408,7 @@ void VG_(kill_thread)(ThreadId tid)
if (VG_(threads)[tid].status == VgTs_WaitSys) {
- //VG_(printf)("kill_thread zaps tid %d lwp %d\n", tid, VG_(threads)[tid].os_state.lwpid);
+ if (VG_(clo_trace_signals))
+ VG_(message)(Vg_DebugMsg, "kill_thread zaps tid %d lwp %d",
+ tid, VG_(threads)[tid].os_state.lwpid);
VG_(tkill)(VG_(threads)[tid].os_state.lwpid, VKI_SIGVGKILL);
}
@@ -546,5 +552,9 @@ void mostly_clear_thread_record ( Thread
VGA_(clear_thread)(&VG_(threads)[tid].arch);
VG_(threads)[tid].tid = tid;
- VG_(threads)[tid].status = VgTs_Empty;
+
+ /* Leave the thread in Zombie, so that it doesn't get reallocated
+ until the caller is finally done with the thread stack. */
+ VG_(threads)[tid].status = VgTs_Zombie;
+
VG_(sigemptyset)(&VG_(threads)[tid].sig_mask);
@@ -608,4 +618,5 @@ void VG_(scheduler_init) ( void )
mostly_clear_thread_record(i);
+ VG_(threads)[i].status = VgTs_Empty;
VG_(threads)[i].stack_size = 0;
VG_(threads)[i].stack_base = (Addr)NULL;
--- valgrind/coregrind/vg_main.c #1.232:1.233
@@ -2840,4 +2840,6 @@ void VG_(shutdown_actions)(ThreadId tid)
vg_assert(VG_(count_living_threads)() == 0);
+ VG_(threads)[tid].status = VgTs_Empty;
+
//--------------------------------------------------------------
// Finalisation: cleanup, messages, etc. Order no so important, only
--- valgrind/coregrind/x86-linux/syscalls.c #1.10:1.11
@@ -180,17 +180,23 @@ static Int start_thread(void *arg)
VG_(exit_thread)(tid);
- /* XXX There's a nasty little race here. Once we release the lock,
- in principle this thread structure could be reused for a new
- thread, recycling the stack we're actually using. The only way
- to fix this would be to release the lock, poke the reaper and
- exit without using any stack...
- Fortunately this is quite a small race.
- */
+ vg_assert(tst->status == VgTs_Zombie);
/* Poke the reaper */
VG_(tkill)(VG_(threads)[VG_(master_tid)].os_state.lwpid, VKI_SIGVGCHLD);
- /* bye-bye */
- return tst->os_state.exitcode;
+ /* We have to use this sequence to terminate the thread to prevent
+ a subtle race. If VG_(exit_thread)() had left the ThreadState
+ as Empty, then it could have been reallocated, reusing the stack
+ while we're doing these last cleanups. Instead,
+ VG_(exit_thread) leaves it as Zombie to prevent reallocation.
+ We need to make sure we don't touch the stack between marking it
+ Empty and exiting. Hence the assembler. */
+ asm volatile (
+ "movl %1, %0\n" /* set tst->status = VgTs_Empty */
+ "int $0x80\n" /* exit(tst->os_state.exitcode) */
+ : "=m" (tst->status)
+ : "n" (VgTs_Empty), "a" (__NR_exit), "b" (tst->os_state.exitcode));
+
+ VG_(core_panic)("Thread exit failed?\n");
}
--- valgrind/coregrind/linux/core_os.c #1.3:1.4
@@ -56,10 +56,4 @@ void VGA_(thread_wrapper)(ThreadId tid)
VG_(shutdown_actions)(tid);
VGA_(terminate)(tid, ret);
- } else {
- /* OK, disappear, but tell the reaper */
- vg_assert(tst->status == VgTs_Runnable);
- VG_(exit_thread)(tid);
- VG_(tkill)(VG_(threads)[VG_(master_tid)].os_state.lwpid, VKI_SIGVGCHLD);
- VG_(exit_single)(tst->os_state.exitcode);
}
}
|
|
From: Jeremy F. <je...@go...> - 2005-01-15 02:07:38
|
CVS commit by fitzhardinge: Little updates to quiet down 'make regtest'. Oh, and a revamp of the syscall args checking so that Valgrind should be much more immune to segfaulting itself. A memcheck/tests/zeropage.stdout.exp 1.1 M +71 -0 glibc-2.3.supp 1.17 M +0 -2 corecheck/tests/as_mmap.stderr.exp 1.3 M +4 -0 corecheck/tests/fdleak_cmsg.c 1.2 M +7 -7 corecheck/tests/fdleak_cmsg.stderr.exp 1.5 M +33 -0 coregrind/core.h 1.59 M +1 -1 coregrind/vg_execontext.c 1.23 M +26 -33 coregrind/vg_memory.c 1.82 M +2 -6 coregrind/vg_scheduler.c 1.207 M +29 -11 coregrind/vg_signals.c 1.109 M +9 -2 coregrind/vg_symtab2.c 1.98 M +474 -430 coregrind/vg_syscalls.c 1.231 M +1 -1 coregrind/vg_translate.c 1.94 M +61 -44 coregrind/linux/syscalls.c 1.5 M +2 -44 coregrind/x86/signal.c 1.9 M +31 -17 coregrind/x86-linux/syscalls.c 1.10 M +1 -1 include/tool.h.base 1.19 M +1 -0 massif/ms_main.c 1.22 M +1 -1 memcheck/tests/scalar.c 1.52 M +12 -1 memcheck/tests/scalar.stderr.exp 1.44 M +0 -3 memcheck/tests/zeropage.stderr.exp 1.3 M +0 -1 none/tests/cmdline1.stdout.exp 1.8 M +0 -2 none/tests/cmdline2.stdout.exp 1.8 M +57 -11 none/tests/exec-sigmask.c 1.2 M +1 -0 none/tests/exec-sigmask.stderr.exp 1.2 M +1 -0 none/tests/exec-sigmask.stdout.exp 1.2 M +1 -2 none/tests/pth_blockedsig.c 1.3 M +23 -13 none/tests/yield.c 1.4 M +1 -1 tests/toobig-allocs.c 1.2 |
|
From: Jeremy F. <je...@go...> - 2005-01-15 02:07:06
|
CVS commit by fitzhardinge:
What started as a simple signal queueing patch turned into an omnibus
signal rework. Lots of details changed, but the big picture is the
same.
A none/tests/blockfault.c 1.1 [no copyright]
A none/tests/blockfault.stderr.exp 1.1
A none/tests/blockfault.stdout.exp 1.1
A none/tests/blockfault.vgtest 1.1
M +32 -16 coregrind/core.h 1.58
M +11 -2 coregrind/vg_main.c 1.232
M +3 -3 coregrind/vg_mylibc.c 1.109
M +58 -65 coregrind/vg_scheduler.c 1.206
M +249 -52 coregrind/vg_signals.c 1.108
M +9 -5 coregrind/vg_syscalls.c 1.230
M +4 -10 coregrind/linux/core_os.c 1.3
M +69 -2 coregrind/x86/signal.c 1.8
M +7 -2 coregrind/x86-linux/ldt.c 1.7
M +6 -1 coregrind/x86-linux/syscalls.c 1.9
M +3 -3 include/tool.h.base 1.18
M +3 -1 none/tests/Makefile.am 1.56
M +1 -1 none/tests/x86/badseg.c 1.2
--- valgrind/coregrind/core.h #1.57:1.58
@@ -653,4 +653,9 @@ struct _ThreadState {
vki_sigset_t 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;
+
/* 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
@@ -700,17 +705,4 @@ struct _ThreadState {
//ThreadState;
-
-/* When something interesting happens in a signal handler, we need to
- longjmp back into the scheduling loop. This enum is the code which
- is returned via longjmp/setjmp to describe what happened. */
-typedef enum {
- VgSig_None = 0, /* nothing special happened*/
- VgSig_AsyncSig = 1, /* we were signalled externally */
- VgSig_FaultSig, /* an instruction faulted */
- VgSig_FatalSig, /* a fatal signal */
- VgSig_Exiting, /* we're exiting */
-} VgSigCode;
-
-
/* The thread table. */
extern ThreadState VG_(threads)[VG_N_THREADS];
@@ -795,6 +787,17 @@ extern void VG_(pp_sched_status) ( void
// Longjmp back to the scheduler and thus enter the sighandler immediately.
-extern void VG_(resume_scheduler) ( ThreadId tid, VgSigCode code,
- Int sigNo, const vki_siginfo_t *info );
+extern void VG_(resume_scheduler) ( ThreadId tid );
+
+/* Copy the state of a thread from VG_(baseBlock), presumably after it
+ has been descheduled. For sanity-check purposes, fill the vacated
+ VG_(baseBlock) with garbage so as to make the system more likely to
+ fail quickly if we erroneously continue to poke around inside
+ VG_(baseBlock) without first doing a load_thread_state().
+*/
+void VG_(save_thread_state) ( ThreadId tid );
+
+/* Copy the saved state of a thread into VG_(baseBlock), ready for it
+ to be run. */
+void VG_(load_thread_state) ( ThreadId tid );
/* The red-zone size which we put at the bottom (highest address) of
@@ -843,4 +846,7 @@ extern Int VG_(max_signal);
extern void VG_(sigstartup_actions) ( void );
+/* 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 * );
@@ -852,5 +858,5 @@ extern void VG_(poll_signals) ( ThreadId
/* Fake system calls for signal handling. */
extern void VG_(do_sys_sigaltstack) ( ThreadId tid );
-extern Int VG_(do_sys_sigaction) ( ThreadId tid, Int signo,
+extern Int VG_(do_sys_sigaction) ( Int signo,
const struct vki_sigaction *new_act,
struct vki_sigaction *old_act );
@@ -882,4 +888,14 @@ extern void VG_(synth_fault_perms) (Thr
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);
+
/* ---------------------------------------------------------------------
Exports of vg_mylibc.c
--- valgrind/coregrind/vg_scheduler.c #1.205:1.206
@@ -278,16 +278,4 @@ ThreadId VG_(get_lwp_tid)(Int lwp)
}
-/* Copy the saved state of a thread into VG_(baseBlock), ready for it
- to be run. */
-static void load_thread_state ( ThreadId tid )
-{
- vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
-
- VGA_(load_state)(&VG_(threads)[tid].arch, tid);
-
- vg_tid_currently_in_baseBlock = tid;
- vg_tid_last_in_baseBlock = tid;
-}
-
/*
Mark a thread as Runnable. This will block until the run_sema is
@@ -457,5 +445,5 @@ void VG_(vg_yield)(void)
VG_(baseBlock) without first doing a load_thread_state().
*/
-static void save_thread_state ( ThreadId tid )
+void VG_(save_thread_state) ( ThreadId tid )
{
vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
@@ -466,7 +454,18 @@ static void save_thread_state ( ThreadId
}
+/* Copy the saved state of a thread into VG_(baseBlock), ready for it
+ to be run. */
+void VG_(load_thread_state) ( ThreadId tid )
+{
+ vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
-void VG_(resume_scheduler)(ThreadId tid, VgSigCode why,
- Int sigNo, const vki_siginfo_t *info)
+ VGA_(load_state)(&VG_(threads)[tid].arch, tid);
+
+ vg_tid_currently_in_baseBlock = tid;
+ vg_tid_last_in_baseBlock = tid;
+}
+
+
+void VG_(resume_scheduler)(ThreadId tid)
{
ThreadState *tst = VG_(get_ThreadState)(tid);
@@ -477,23 +476,20 @@ void VG_(resume_scheduler)(ThreadId tid,
/* Can't continue; must longjmp back to the scheduler and thus
enter the sighandler immediately. */
- tst->siginfo.si_signo = sigNo;
- if (info != NULL)
- VG_(memcpy)(&tst->siginfo, info, sizeof(vki_siginfo_t));
- LONGJMP(tst->sched_jmpbuf, why);
+ LONGJMP(tst->sched_jmpbuf, True);
}
}
-#define SCHEDSETJMP(tid, sigcode, stmt) \
+#define SCHEDSETJMP(tid, jumped, stmt) \
do { \
ThreadState * volatile _qq_tst = VG_(get_ThreadState)(tid); \
\
- sigcode = SETJMP(_qq_tst->sched_jmpbuf); \
- if ((sigcode) == 0) { \
+ (jumped) = SETJMP(_qq_tst->sched_jmpbuf); \
+ if ((jumped) == 0) { \
vg_assert(!_qq_tst->sched_jmpbuf_valid); \
_qq_tst->sched_jmpbuf_valid = True; \
stmt; \
} else if (VG_(clo_trace_sched)) \
- VG_(printf)("SCHEDSETJMP(line %d) tid %d, sigcode=%d\n", __LINE__, tid, sigcode); \
+ VG_(printf)("SCHEDSETJMP(line %d) tid %d, jumped=%d\n", __LINE__, tid, jumped); \
vg_assert(_qq_tst->sched_jmpbuf_valid); \
_qq_tst->sched_jmpbuf_valid = False; \
@@ -506,28 +502,35 @@ UInt run_thread_for_a_while ( ThreadId t
{
volatile UInt trc = 0;
- VgSigCode sigcode;
+ Bool jumped;
vg_assert(VG_(is_valid_tid)(tid));
vg_assert(VG_(is_running_thread)(tid));
+ vg_assert(!VG_(is_exiting)(tid));
VGP_PUSHCC(VgpRun);
- load_thread_state ( tid );
+ VG_(load_thread_state) ( tid );
/* there should be no undealt-with signals */
- vg_assert(VG_(threads)[tid].siginfo.si_signo == 0);
+ //vg_assert(VG_(threads)[tid].siginfo.si_signo == 0);
- //VG_(printf)("running EIP = %p\n", VG_(threads)[tid].arch.m_eip);
+ //VG_(printf)("running EIP = %p ESP=%p\n", VG_(threads)[tid].arch.m_eip, VG_(threads)[tid].arch.m_esp);
- SCHEDSETJMP(tid, sigcode, trc = VG_(run_innerloop)());
+ SCHEDSETJMP(tid, jumped, trc = VG_(run_innerloop)());
- if (sigcode != VgSig_None) {
+ if (jumped) {
/* We get here if the client took a fault, which caused our
signal handler to longjmp. */
- vg_assert(sigcode == VgSig_FaultSig); /* or fatal... */
vg_assert(trc == 0);
trc = VG_TRC_FAULT_SIGNAL;
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &VG_(blocked_mask), NULL);
}
- save_thread_state ( tid );
+ /* If we were delivered a signal, then the ThreadState registers
+ may already be up to date. */
+ if (VG_(is_VCPU_thread)(tid))
+ VG_(save_thread_state) ( tid );
+ else
+ vg_assert(VG_(get_VCPU_tid)() == VG_INVALID_THREADID);
+
VGP_POPCC(VgpRun);
return trc;
@@ -538,4 +541,6 @@ static
void mostly_clear_thread_record ( ThreadId tid )
{
+ vki_sigset_t savedmask;
+
vg_assert(tid >= 0 && tid < VG_N_THREADS);
VGA_(clear_thread)(&VG_(threads)[tid].arch);
@@ -551,4 +556,12 @@ void mostly_clear_thread_record ( Thread
VG_(threads)[tid].altstack.ss_flags = VKI_SS_DISABLE;
+ /* clear out queued signals */
+ VG_(block_all_host_signals)(&savedmask);
+ if (VG_(threads)[tid].sig_queue != NULL) {
+ VG_(arena_free)(VG_AR_CORE, VG_(threads)[tid].sig_queue);
+ VG_(threads)[tid].sig_queue = NULL;
+ }
+ VG_(restore_all_host_signals)(&savedmask);
+
VG_(threads)[tid].sched_jmpbuf_valid = False;
}
@@ -590,4 +603,6 @@ void VG_(scheduler_init) ( void )
for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
+ VG_(threads)[i].sig_queue = NULL;
+
VGA_(os_state_init)(&VG_(threads)[i]);
mostly_clear_thread_record(i);
@@ -608,5 +624,5 @@ void VG_(scheduler_init) ( void )
VGA_(init_thread)(&VG_(threads)[tid_main].arch);
- save_thread_state ( tid_main );
+ VG_(save_thread_state) ( tid_main );
/* Initial thread's stack is the original process stack */
@@ -653,5 +669,5 @@ static void handle_syscall(ThreadId tid)
{
ThreadState *tst = VG_(get_ThreadState)(tid);
- VgSigCode sigcode;
+ Bool jumped;
/* Syscall may or may not block; either way, it will be
@@ -659,5 +675,5 @@ static void handle_syscall(ThreadId tid)
runnable again. We could take a signal while the
syscall runs. */
- SCHEDSETJMP(tid, sigcode, VG_(client_syscall)(tid));
+ SCHEDSETJMP(tid, jumped, VG_(client_syscall)(tid));
if (!VG_(is_running_thread)(tid))
@@ -667,31 +682,8 @@ static void handle_syscall(ThreadId tid)
vg_assert(VG_(is_running_thread)(tid));
- switch(sigcode) {
- case VgSig_None:
- break; /* nothing */
-
- case VgSig_Exiting:
- vg_assert(VG_(is_exiting)(tid));
- break;
-
- case VgSig_AsyncSig:
- case VgSig_FatalSig:
- if (sigcode == VgSig_FatalSig) {
- /* was fatal, we're exiting */
- vg_assert(VG_(is_exiting)(tid));
- }
-
+ if (jumped) {
VG_(sigprocmask)(VKI_SIG_SETMASK, &VG_(blocked_mask), NULL);
-
- tst->siginfo.si_signo = 0; /* don't care about signal state */
- break;
-
- case VgSig_FaultSig:
- /* We should never get an instruction fault from doing a
- syscall. */
- vg_assert(0);
+ VG_(poll_signals)(tid);
}
-
- vg_assert(tst->siginfo.si_signo == 0);
}
@@ -782,5 +774,9 @@ VgSchedReturnCode VG_(scheduler) ( Threa
/* Explicit yield, because they're expecting to be
spinning. */
- VG_(vg_yield)();
+ //VG_(vg_yield)();
+ VG_(dispatch_ctr) = 0;
+ //VG_(set_sleeping)(tid, VgTs_Yielding);
+ //VG_(do_syscall)(__NR_sched_yield);
+ //VG_(set_running)(tid);
break;
@@ -796,7 +792,4 @@ VgSchedReturnCode VG_(scheduler) ( Threa
sneak in). */
VG_(sigprocmask)(VKI_SIG_SETMASK, &VG_(blocked_mask), NULL);
-
- VG_(deliver_signal)(tid, &tst->siginfo);
- tst->siginfo.si_signo = 0; /* done */
break;
--- valgrind/coregrind/vg_signals.c #1.107:1.108
@@ -103,4 +103,11 @@ vki_sigset_t VG_(blocked_mask);
Int VG_(max_signal) = _VKI_NSIG;
+#define N_QUEUED_SIGNALS 4
+
+typedef struct SigQueue {
+ Int next;
+ vki_siginfo_t sigs[N_QUEUED_SIGNALS];
+} SigQueue;
+
/* ---------------------------------------------------------------------
HIGH LEVEL STUFF TO DO WITH SIGNALS: POLICY (MOSTLY)
@@ -452,15 +459,13 @@ void VG_(do_sys_sigaltstack) ( ThreadId
-Int VG_(do_sys_sigaction) ( ThreadId tid, Int signo,
+Int VG_(do_sys_sigaction) ( Int signo,
const struct vki_sigaction *new_act,
struct vki_sigaction *old_act )
{
- vg_assert(VG_(is_valid_tid)(tid));
-
if (VG_(clo_trace_signals))
VG_(message)(Vg_DebugExtraMsg,
- "sys_sigaction: tid %d, sigNo %d, "
+ "sys_sigaction: sigNo %d, "
"new %p, old %p, new flags 0x%llx",
- tid, signo, (UWord)new_act, (UWord)old_act,
+ signo, (UWord)new_act, (UWord)old_act,
(ULong)(new_act ? new_act->sa_flags : 0) );
@@ -674,4 +679,13 @@ void VG_(restore_all_host_signals) ( /*
}
+Bool VG_(client_signal_OK)(Int sigNo)
+{
+ Bool ret = sigNo >= 1 && sigNo <= VKI_SIGVGRTUSERMAX;
+
+ //VG_(printf)("client_signal_OK(%d) -> %d\n", sigNo, ret);
+
+ return ret;
+}
+
/* ---------------------------------------------------------------------
The signal simulation proper. A simplified version of what the
@@ -722,4 +736,7 @@ void vg_push_signal_frame ( ThreadId tid
vg_assert(vg_scss.scss_per_sig[sigNo].scss_handler != VKI_SIG_DFL);
+ /* This may fail if the client stack is busted; if that happens,
+ the whole process will exit rather than simply calling the
+ signal handler. */
VGA_(push_signal_frame)(tid, esp_top_of_frame, siginfo,
vg_scss.scss_per_sig[sigNo].scss_handler,
@@ -1342,4 +1359,8 @@ static void synth_fault_common(ThreadId
info._sifields._sigfault._addr = (void*)addr;
+ /* If they're trying to block the signal, force it to be delivered */
+ if (VG_(sigismember)(&VG_(threads)[tid].sig_mask, VKI_SIGSEGV))
+ VG_(set_default_handler)(VKI_SIGSEGV);
+
VG_(deliver_signal)(tid, &info);
}
@@ -1402,6 +1423,5 @@ void VG_(deliver_signal) ( ThreadId tid,
the signal to get through no matter what; if they're ignoring
it, then we do this override (this is so we can send it SIGSEGV,
- etc).
- */
+ etc). */
handler_fn = handler->scss_handler;
if (handler_fn == VKI_SIG_IGN)
@@ -1416,6 +1436,17 @@ void VG_(deliver_signal) ( ThreadId tid,
%EIP so that when execution continues, we will enter the
signal handler with the frame on top of the client's stack,
- as it expects. */
+ as it expects.
+
+ Signal delivery can fail if the client stack is too small or
+ missing, and we can't push the frame. If that happens,
+ push_signal_frame will cause the whole process to exit when
+ we next hit the scheduler.
+ */
vg_assert(VG_(is_valid_tid)(tid));
+
+ /* Before we muck with the thread's state, we need to work out where it is. */
+ if (VG_(is_VCPU_thread)(tid)) {
+ VG_(save_thread_state)(tid);
+ }
vg_push_signal_frame ( tid, info );
@@ -1441,4 +1472,83 @@ void VG_(deliver_signal) ( ThreadId tid,
}
+/* Make a signal pending for a thread, for later delivery.
+ VG_(poll_signals) will arrange for it to be delivered at the right
+ time.
+
+ tid==0 means add it to the process-wide queue, and not sent it to a
+ specific thread.
+*/
+void queue_signal(ThreadId tid, const vki_siginfo_t *si)
+{
+ ThreadState *tst;
+ SigQueue *sq;
+ vki_sigset_t savedmask;
+
+ tst = VG_(get_ThreadState)(tid);
+
+ /* Protect the signal queue against async deliveries */
+ VG_(block_all_host_signals)(&savedmask);
+
+ if (tst->sig_queue == NULL) {
+ tst->sig_queue = VG_(arena_malloc)(VG_AR_CORE, sizeof(*tst->sig_queue));
+ VG_(memset)(tst->sig_queue, 0, sizeof(*tst->sig_queue));
+ }
+ sq = tst->sig_queue;
+
+ if (VG_(clo_trace_signals))
+ VG_(message)(Vg_DebugMsg, "Queueing signal %d (idx %d) to thread %d",
+ si->si_signo, sq->next, tid);
+
+ /* Add signal to the queue. If the queue gets overrun, then old
+ queued signals may get lost. */
+ if (sq->sigs[sq->next].si_signo != 0)
+ VG_(message)(Vg_UserMsg, "Signal %d being dropped from thread %d's queue\n",
+ sq->sigs[sq->next].si_signo, tid);
+
+ sq->sigs[sq->next] = *si;
+ sq->next = (sq->next+1) % N_QUEUED_SIGNALS;
+
+ VG_(restore_all_host_signals)(&savedmask);
+}
+
+/*
+ Returns the next queued signal for thread tid which is in "set".
+ tid==0 means process-wide signal. Set si_signo to 0 when the
+ signal has been delivered.
+
+ Must be called with all signals blocked, to protect against async
+ deliveries.
+*/
+static vki_siginfo_t *next_queued(ThreadId tid, const vki_sigset_t *set)
+{
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+ SigQueue *sq;
+ Int idx;
+ vki_siginfo_t *ret = NULL;
+
+ sq = tst->sig_queue;
+ if (sq == NULL)
+ goto out;
+
+ idx = sq->next;
+ do {
+ if (0)
+ VG_(printf)("idx=%d si_signo=%d inset=%d\n", idx,
+ sq->sigs[idx].si_signo, VG_(sigismember)(set, sq->sigs[idx].si_signo));
+
+ if (sq->sigs[idx].si_signo != 0 && VG_(sigismember)(set, sq->sigs[idx].si_signo)) {
+ if (VG_(clo_trace_signals))
+ VG_(message)(Vg_DebugMsg, "Returning queued signal %d (idx %d) for thread %d",
+ sq->sigs[idx].si_signo, idx, tid);
+ ret = &sq->sigs[idx];
+ goto out;
+ }
+
+ idx = (idx + 1) % N_QUEUED_SIGNALS;
+ } while(idx != sq->next);
+ out:
+ return ret;
+}
+
/*
Receive an async signal from the kernel.
@@ -1458,4 +1568,8 @@ void vg_async_signalhandler ( Int sigNo,
VG_(set_running)(tid);
+ if (VG_(clo_trace_signals))
+ VG_(message)(Vg_DebugMsg, "Async handler got signal %d for tid %d info %d",
+ sigNo, tid, info->si_code);
+
/* Update thread state properly if this signal happened in or around a syscall */
VGA_(interrupted_syscall)(&tst->arch, uc,
@@ -1468,9 +1582,64 @@ void vg_async_signalhandler ( Int sigNo,
handler.
*/
- VG_(resume_scheduler)(tid, VgSig_AsyncSig, sigNo, info);
+ VG_(resume_scheduler)(tid);
VG_(core_panic)("vg_async_signalhandler: got unexpected signal while outside of scheduler");
}
+/* Extend the stack to cover addr. maxsize is the limit the stack can grow to.
+
+ Returns True on success, False on failure.
+
+ Succeeds without doing anything if addr is already within a segment.
+
+ Failure could be caused by:
+ - addr not below a growable segment
+ - new stack size would exceed maxsize
+ - mmap failed for some other reason
+ */
+Bool VG_(extend_stack)(Addr addr, UInt maxsize)
+{
+ Segment *seg;
+ Addr base;
+ UInt newsize;
+
+ /* Find the next Segment above addr */
+ seg = VG_(find_segment)(addr);
+ if (seg == NULL)
+ seg = VG_(first_segment)();
+ else if (VG_(seg_contains)(seg, addr, sizeof(void *)))
+ return True;
+ else
+ seg = VG_(next_segment)(seg);
+
+ /* If there isn't one, or it isn't growable, fail */
+ if (seg == NULL ||
+ !(seg->flags & SF_GROWDOWN) ||
+ VG_(seg_contains)(seg, addr, sizeof(void *)))
+ return False;
+
+ vg_assert(seg->addr > addr);
+
+ /* Create the mapping */
+ base = PGROUNDDN(addr);
+ newsize = seg->addr - base;
+
+ if (seg->len + newsize >= maxsize)
+ return False;
+
+ if (VG_(mmap)((Char *)base, newsize,
+ seg->prot,
+ VKI_MAP_PRIVATE | VKI_MAP_FIXED | VKI_MAP_ANONYMOUS | VKI_MAP_CLIENT,
+ seg->flags,
+ -1, 0) == (void *)-1)
+ return False;
+
+ if (0)
+ VG_(printf)("extended stack: %p %d\n",
+ base, newsize);
+
+ return True;
+}
+
/*
Recieve a sync signal from the host.
@@ -1481,11 +1650,4 @@ void vg_sync_signalhandler ( Int sigNo,
ThreadId tid = VG_(get_lwp_tid)(VG_(gettid)());
- if (!VG_(is_running_thread)(tid)) {
- /* This may possibly happen if someone sent us one of the sync
- signals with a kill syscall. Get the CPU before going on. */
- vg_assert(info->si_code <= VKI_SI_USER);
- VG_(set_running)(tid);
- }
-
vg_assert(info != NULL);
vg_assert(info->si_signo == sigNo);
@@ -1495,7 +1657,22 @@ void vg_sync_signalhandler ( Int sigNo,
sigNo == VKI_SIGILL);
+ if (!VG_(is_running_thread)(tid)) {
+ /* This may possibly happen if someone sent us one of the sync
+ signals with a kill syscall. Get the CPU before going on. */
+ vg_assert(info->si_code <= VKI_SI_USER);
+ VG_(set_running)(tid);
+
+ /* Since every thread has these signals unblocked, we can't rely
+ on the kernel to route them properly, so we need to queue
+ them manually. */
+ queue_signal(0, info);
+ VG_(resume_scheduler)(tid);
+ }
+
if (VG_(clo_trace_signals)) {
- VG_(message)(Vg_DebugMsg, "signal %d arrived ... si_code=%d, EIP=%p",
- sigNo, info->si_code, ARCH_INSTR_PTR(VG_(threads)[tid].arch) );
+ VG_(message)(Vg_DebugMsg, "signal %d arrived ... si_code=%d, EIP=%p, eip=%p",
+ sigNo, info->si_code,
+ ARCH_INSTR_PTR(VG_(threads)[tid].arch),
+ UCONTEXT_INSTR_PTR(uc) );
}
vg_assert(sigNo >= 1 && sigNo <= VG_(max_signal));
@@ -1534,8 +1711,5 @@ void vg_sync_signalhandler ( Int sigNo,
if (info->si_code == 1 && /* SEGV_MAPERR */
- seg != NULL &&
- fault >= esp &&
- fault < seg->addr &&
- (seg->flags & SF_GROWDOWN)) {
+ fault >= esp) {
/* If the fault address is above esp but below the current known
stack segment base, and it was a fault because there was
@@ -1543,17 +1717,12 @@ void vg_sync_signalhandler ( Int sigNo,
then extend the stack segment.
*/
- Addr base = PGROUNDDN(esp);
- if (seg->len + (seg->addr - base) <= VG_(threads)[tid].stack_size &&
- (void*)-1 != VG_(mmap)((Char *)base, seg->addr - base,
- VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
- VKI_MAP_PRIVATE|VKI_MAP_FIXED|VKI_MAP_ANONYMOUS|VKI_MAP_CLIENT,
- SF_STACK|SF_GROWDOWN,
- -1, 0)) {
+ if (VG_(extend_stack)(fault, VG_(threads)[tid].stack_size)) {
if (VG_(clo_trace_signals))
VG_(message)(Vg_DebugMsg,
- " -> extended stack base to %p", base);
+ " -> extended stack base to %p", PGROUNDDN(fault));
return; // extension succeeded, restart instruction
} else
- VG_(message)(Vg_UserMsg, "Stack overflow in thread %d", tid);
+ VG_(message)(Vg_UserMsg, "Stack overflow in thread %d: can't grow stack to %p",
+ tid, fault);
/* Fall into normal signal handling for all other cases */
@@ -1580,22 +1749,23 @@ void vg_sync_signalhandler ( Int sigNo,
}
- if (info->si_code <= VKI_SI_USER) {
- /*
- OK, one of sync signals was sent async by user-mode, so try
- to deliver it to someone who cares.
-
- XXX For now, just drop it.
- */
- VG_(message)(Vg_UserMsg,
- "dropping signal %s sent by pid %d",
- signame(sigNo), info->_sifields._kill._pid);
- } else {
+ /* OK, this is a signal we really have to deal with. If it came
+ from the client's code, then we can jump back into the scheduler
+ and have it delivered. Otherwise it's a Valgrind bug. */
+ {
Addr context_ip;
Char buf[1024];
- ThreadState *tst;
+ ThreadState *tst = VG_(get_ThreadState)(VG_(get_lwp_tid)(VG_(gettid)()));
+
+ if (VG_(sigismember)(&tst->sig_mask, sigNo)) {
+ /* signal is blocked, but they're not allowed to block faults */
+ VG_(set_default_handler)(sigNo);
+ }
/* Can't continue; must longjmp back to the scheduler and thus
enter the sighandler immediately. */
- VG_(resume_scheduler)(tid, VgSig_FaultSig, sigNo, info);
+ VG_(deliver_signal)(tid, info);
+ VG_(resume_scheduler)(tid);
+
+
/* If resume_scheduler returns, it means we don't have longjmp
@@ -1656,10 +1826,5 @@ static void sigvgkill_handler(int signo,
VG_(set_running)(tid);
- /* Check that the signal comes from within, and ignore it if not. */
- if (si->si_code != VKI_SI_TKILL ||
- VG_(get_lwp_tid)(si->_sifields._kill._pid) == VG_INVALID_THREADID)
- return;
-
- VG_(resume_scheduler)(tid, VgSig_Exiting, 0, 0);
+ VG_(resume_scheduler)(tid);
VG_(core_panic)("sigvgkill_handler couldn't return to the scheduler\n");
@@ -1686,4 +1851,19 @@ void pp_vg_ksigaction ( struct vki_sigac
/*
+ Force signal handler to default
+ */
+void VG_(set_default_handler)(Int signo)
+{
+ struct vki_sigaction sa;
+
+ sa.ksa_handler = VKI_SIG_DFL;
+ sa.sa_flags = 0;
+ sa.sa_restorer = 0;
+ VG_(sigemptyset)(&sa.sa_mask);
+
+ VG_(do_sys_sigaction)(signo, &sa, NULL);
+}
+
+/*
Poll for pending signals, and set the next one up for delivery.
*/
@@ -1691,8 +1871,9 @@ void VG_(poll_signals)(ThreadId tid)
{
static const struct vki_timespec zero = { 0, 0 };
- vki_siginfo_t si;
+ vki_siginfo_t si, *sip;
vki_sigset_t pollset;
ThreadState *tst = VG_(get_ThreadState)(tid);
Int i;
+ vki_sigset_t saved_mask;
/* look for all the signals this thread isn't blocking */
@@ -1702,4 +1883,20 @@ void VG_(poll_signals)(ThreadId tid)
VG_(sigdelset)(&pollset, VKI_SIGVGCHLD); /* never look for this */
+ //VG_(printf)("tid %d pollset=%08x%08x\n", tid, pollset.sig[1], pollset.sig[0]);
+
+ VG_(block_all_host_signals)(&saved_mask);
+
+ /* First look for any queued pending signals */
+ sip = next_queued(0, &pollset); /* process-wide */
+ if (sip == NULL)
+ sip = next_queued(tid, &pollset); /* this thread */
+ if (sip != NULL) {
+ VG_(deliver_signal)(tid, sip);
+ sip->si_signo = 0;
+ VG_(restore_all_host_signals)(&saved_mask);
+ return;
+ }
+ VG_(restore_all_host_signals)(&saved_mask);
+
/* Grab a single pending signal for this thread, and deliver it to
the thread */
--- valgrind/coregrind/vg_mylibc.c #1.108:1.109
@@ -60,5 +60,5 @@ Int VG_(sigemptyset)( vki_sigset_t* set
}
-Bool VG_(isemptysigset)( vki_sigset_t* set )
+Bool VG_(isemptysigset)( const vki_sigset_t* set )
{
Int i;
@@ -69,5 +69,5 @@ Bool VG_(isemptysigset)( vki_sigset_t* s
}
-Bool VG_(isfullsigset)( vki_sigset_t* set )
+Bool VG_(isfullsigset)( const vki_sigset_t* set )
{
Int i;
@@ -101,5 +101,5 @@ Int VG_(sigdelset)( vki_sigset_t* set, I
}
-Int VG_(sigismember) ( vki_sigset_t* set, Int signum )
+Int VG_(sigismember) ( const vki_sigset_t* set, Int signum )
{
if (set == NULL)
--- valgrind/coregrind/vg_main.c #1.231:1.232
@@ -2697,7 +2697,16 @@ int main(int argc, char **argv, char **e
// p: segment stuff [otherwise get seg faults...]
//--------------------------------------------------------------
+ {
+ Segment *seg;
VG_(mprotect)( (void *)VG_(client_trampoline_code),
VG_(trampoline_code_length), VKI_PROT_READ|VKI_PROT_EXEC );
+ /* Make sure this segment isn't treated as stack */
+ seg = VG_(find_segment)(VG_(client_trampoline_code));
+ if (seg && VG_(seg_contains)(seg, VG_(client_trampoline_code),
+ VG_(trampoline_code_length)))
+ seg->flags &= ~(SF_STACK | SF_GROWDOWN);
+ }
+
//==============================================================
// Can use VG_(map)() after segments set up
--- valgrind/coregrind/vg_syscalls.c #1.229:1.230
@@ -1935,4 +1935,8 @@ PRE(sys_fcntl, 0)
case VKI_F_SETSIG:
case VKI_F_SETLEASE:
+ if (arg2 == VKI_F_SETSIG && !VG_(client_signal_OK)(arg3)) {
+ set_result(-VKI_EINVAL);
+ return;
+ }
PRE_REG_READ3(long, "fcntl",
unsigned int, fd, unsigned int, cmd, unsigned long, arg);
@@ -4074,5 +4078,5 @@ PRE(sys_tkill, 0)
PRINT("sys_tkill ( %d, %d )", arg1,arg2);
PRE_REG_READ2(long, "tkill", int, tid, int, sig);
- if (arg2 == VKI_SIGVGKILL || arg2 == VKI_SIGVGCHLD)
+ if (!VG_(client_signal_OK)(arg2))
set_result( -VKI_EINVAL );
}
@@ -4092,5 +4096,5 @@ PRE(sys_tgkill, 0)
PRINT("sys_tgkill ( %d, %d, %d )", arg1,arg2,arg3);
PRE_REG_READ3(long, "tgkill", int, tgid, int, tid, int, sig);
- if (arg2 == VKI_SIGVGKILL || arg2 == VKI_SIGVGCHLD)
+ if (!VG_(client_signal_OK)(arg3))
set_result( -VKI_EINVAL );
}
@@ -4110,5 +4114,5 @@ PRE(sys_kill, 0)
PRINT("sys_kill ( %d, %d )", arg1,arg2);
PRE_REG_READ2(long, "kill", int, pid, int, sig);
- if (arg2 == VKI_SIGVGKILL || arg2 == VKI_SIGVGCHLD)
+ if (!VG_(client_signal_OK)(arg2))
set_result( -VKI_EINVAL );
}
@@ -5422,5 +5426,5 @@ PRE(sys_sigaction, Special)
}
- set_result(VG_(do_sys_sigaction)(tid, arg1, newp, oldp));
+ set_result(VG_(do_sys_sigaction)(arg1, newp, oldp));
if (arg3 != 0 && SYSRES == 0) {
@@ -5453,5 +5457,5 @@ PRE(sys_rt_sigaction, Special)
PRE_MEM_WRITE( "rt_sigaction(oldact)", arg3, sizeof(struct vki_sigaction));
- set_result(VG_(do_sys_sigaction)(tid, arg1, (const struct vki_sigaction *)arg2,
+ set_result(VG_(do_sys_sigaction)(arg1, (const struct vki_sigaction *)arg2,
(struct vki_sigaction *)arg3));
}
--- valgrind/coregrind/x86/signal.c #1.7:1.8
@@ -343,4 +343,47 @@ static void synth_ucontext(ThreadId tid,
post_reg_write_deliver_signal)
+static Bool seg_ok(Segment *seg, VgSigFrame *frame)
+{
+ if (!VG_(seg_overlaps)(seg, (Addr)frame, sizeof(*frame)))
+ return False;
+
+ if ((seg->prot & (VKI_PROT_READ|VKI_PROT_WRITE)) != (VKI_PROT_READ|VKI_PROT_WRITE))
+ return False;
+
+ return True;
+}
+
+/* Make sure that there are segments covering all of frame, and
+ they're read/write. */
+static Bool compat_segments(Segment *seg, VgSigFrame *frame)
+{
+ Segment *next;
+ Addr a = (Addr)frame;
+ UInt remains = sizeof(*frame);
+
+ while(remains && seg) {
+ Addr end = seg->addr + seg->len;
+
+ next = VG_(next_segment)(seg);
+
+ if (!seg_ok(seg, frame))
+ return False;
+
+ if ((end - a) > remains)
+ remains = 0;
+ else {
+ remains -= end - a;
+ a = end;
+ }
+
+ if (next->addr != end)
+ next = NULL;
+
+ seg = next;
+ }
+
+ return remains == 0;
+}
+
void VGA_(push_signal_frame)(ThreadId tid, Addr esp_top_of_frame,
const vki_siginfo_t *siginfo,
@@ -349,7 +392,8 @@ void VGA_(push_signal_frame)(ThreadId ti
{
Addr esp;
- ThreadState* tst;
+ ThreadState* tst = VG_(get_ThreadState)(tid);
VgSigFrame* frame;
Int sigNo = siginfo->si_signo;
+ Segment *stackseg = NULL;
esp = esp_top_of_frame;
@@ -357,5 +401,28 @@ void VGA_(push_signal_frame)(ThreadId ti
frame = (VgSigFrame*)esp;
- tst = & VG_(threads)[tid];
+ if (VG_(extend_stack)((Addr)frame, tst->stack_size)) {
+ stackseg = VG_(find_segment)((Addr)frame);
+ if (0 && stackseg)
+ VG_(printf)("frame=%p seg=%p-%p\n",
+ frame, stackseg->addr, stackseg->addr+stackseg->len);
+ }
+
+ if (stackseg == NULL || !compat_segments(stackseg, frame)) {
+ VG_(message)(Vg_UserMsg,
+ "Can't extend stack to %p during signal delivery for thread %d:",
+ frame, tid);
+ if (stackseg == NULL)
+ VG_(message)(Vg_UserMsg, " no stack segment");
+ else
+ VG_(message)(Vg_UserMsg, " too small or bad protection modes");
+
+ /* set SIGSEGV to default handler */
+ VG_(set_default_handler)(VKI_SIGSEGV);
+ VG_(synth_fault_mapping)(tid, (Addr)frame);
+
+ /* The whole process should be about to die, since the default
+ action of SIGSEGV to kill the whole process. */
+ return;
+ }
/* For tracking memory events, indicate the entire frame has been
--- valgrind/include/tool.h.base #1.17:1.18
@@ -533,10 +533,10 @@
extern Int VG_(sigemptyset) ( vki_sigset_t* set );
-extern Bool VG_(isfullsigset) ( vki_sigset_t* set );
-extern Bool VG_(isemptysigset) ( vki_sigset_t* set );
+extern Bool VG_(isfullsigset) ( const vki_sigset_t* set );
+extern Bool VG_(isemptysigset) ( const vki_sigset_t* set );
extern Int VG_(sigaddset) ( vki_sigset_t* set, Int signum );
extern Int VG_(sigdelset) ( vki_sigset_t* set, Int signum );
-extern Int VG_(sigismember) ( vki_sigset_t* set, Int signum );
+extern Int VG_(sigismember) ( const vki_sigset_t* set, Int signum );
extern void VG_(sigaddset_from_set) ( vki_sigset_t* dst, vki_sigset_t* src );
--- valgrind/none/tests/Makefile.am #1.55:1.56
@@ -6,4 +6,5 @@
args.stderr.exp args.stdout.exp args.vgtest \
bitfield1.stderr.exp bitfield1.vgtest \
+ blockfault.vgtest \
closeall.stderr.exp closeall.vgtest \
cmdline1.stderr.exp cmdline1.stdout.exp cmdline1.vgtest \
@@ -58,5 +59,5 @@
check_PROGRAMS = \
- args bitfield1 closeall coolo_strlen \
+ args bitfield1 blockfault closeall coolo_strlen \
discard exec-sigmask execve fcntl_setown floored fork \
fucomip getseg \
@@ -75,4 +76,5 @@
args_SOURCES = args.c
bitfield1_SOURCES = bitfield1.c
+blockfault_SOURCES = blockfault.c
closeall_SOURCES = closeall.c
coolo_strlen_SOURCES = coolo_strlen.c
--- valgrind/coregrind/x86-linux/syscalls.c #1.8:1.9
@@ -399,4 +399,9 @@ PRE(sys_clone, Special)
cloneflags = arg1 & (VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES | VKI_CLONE_VFORK);
+ if ((arg1 & VKI_CSIGNAL) && !VG_(client_signal_OK)(arg1 & VKI_CSIGNAL)) {
+ set_result( -VKI_EINVAL );
+ return;
+ }
+
switch(cloneflags) {
case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
--- valgrind/coregrind/x86-linux/ldt.c #1.6:1.7
@@ -191,6 +191,11 @@ Addr VG_(do_useseg) ( UInt seg_selector,
privilege). This forms the bottom 2 bits of the selector. */
if ((seg_selector & 3) != 3) {
- VG_(synth_fault)(VG_(get_VCPU_tid)());
- return 0;
+ ThreadId tid = VG_(get_VCPU_tid)();
+ vg_assert(tid != VG_INVALID_THREADID);
+
+ //VG_(printf)("synth fault EIP=%p\n", VG_(baseBlock)[VGOFF_(m_eip)]);
+ VG_(synth_fault)(tid);
+ VG_(resume_scheduler)(tid);
+ VG_(core_panic)("do_useseg called outside of scheduler loop?");
}
--- valgrind/coregrind/linux/core_os.c #1.2:1.3
@@ -138,6 +138,4 @@ void VGA_(intercept_libc_freeres_wrapper
void VGA_(final_tidyup)(ThreadId tid)
{
- struct vki_sigaction sa;
-
vg_assert(VG_(is_running_thread)(tid));
@@ -161,12 +159,8 @@ void VGA_(final_tidyup)(ThreadId tid)
/* and restore handlers to default */
- sa.ksa_handler = VKI_SIG_DFL;
- VG_(sigemptyset)(&sa.sa_mask);
- sa.sa_flags = 0;
-
- VG_(do_sys_sigaction)(tid, VKI_SIGSEGV, &sa, NULL);
- VG_(do_sys_sigaction)(tid, VKI_SIGBUS, &sa, NULL);
- VG_(do_sys_sigaction)(tid, VKI_SIGILL, &sa, NULL);
- VG_(do_sys_sigaction)(tid, VKI_SIGFPE, &sa, NULL);
+ VG_(set_default_handler)(VKI_SIGSEGV);
+ VG_(set_default_handler)(VKI_SIGBUS);
+ VG_(set_default_handler)(VKI_SIGILL);
+ VG_(set_default_handler)(VKI_SIGFPE);
// We were exiting, so assert that...
--- valgrind/none/tests/x86/badseg.c #1.1:1.2
@@ -16,5 +16,5 @@ int main()
sa.sa_sigaction = handler;
- sigemptyset(&sa.sa_mask);
+ sigfillset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
|
|
From: Jeremy F. <je...@go...> - 2005-01-15 02:05:20
|
CVS commit by fitzhardinge:
Misc changes needed so that Valgrind can run itself.
M +4 -0 coregrind/core.h 1.57
M +2 -2 coregrind/stage1.c 1.31
M +3 -11 coregrind/vg_main.c 1.231
M +4 -2 coregrind/vg_messages.c 1.17
M +4 -3 coregrind/vg_procselfmaps.c 1.16
M +8 -2 coregrind/vg_scheduler.c 1.205
M +54 -24 coregrind/vg_signals.c 1.107
M +12 -2 coregrind/vg_symtab2.c 1.97
M +17 -9 coregrind/vg_syscalls.c 1.229
M +23 -20 coregrind/vg_transtab.c 1.37
M +14 -2 coregrind/linux/core_os.c 1.2
M +4 -4 include/x86-linux/vki_arch.h 1.10
--- valgrind/coregrind/vg_syscalls.c #1.228:1.229
@@ -118,5 +118,5 @@ Bool VG_(valid_client_addr)(Addr start,
return True;
- if (cl_base < 0x10000)
+ if (0 && cl_base < 0x10000)
cl_base = 0x10000;
@@ -893,5 +893,7 @@ static Addr do_brk(Addr newbrk)
VG_(brk_base), VG_(brk_limit), newbrk);
- if (newbrk < VG_(brk_base) || newbrk >= VG_(client_end))
+ if (newbrk < VG_(brk_base) || /* too low */
+ newbrk >= VG_(client_end) || /* too high */
+ (newbrk - VG_(brk_base)) > VG_(client_rlimit_data).rlim_cur) /* out of limits */
return VG_(brk_limit);
@@ -916,5 +918,4 @@ static Addr do_brk(Addr newbrk)
/* new brk in a new page - fix the mappings */
if (newbrk > VG_(brk_limit)) {
-
if (debug)
VG_(printf)(" extending brk: current=%p newaddr=%p delta=%d\n",
@@ -4334,4 +4335,12 @@ PRE(sys_open, MayBlock)
}
PRE_MEM_RASCIIZ( "open(filename)", arg1 );
+
+ if (VG_(strcmp)((Char *)arg1, "/proc/self/exe") == 0) {
+ Char name[20];
+ VG_(sprintf)(name, "/proc/self/fd/%d", VG_(clexecfd));
+
+ set_result(VG_(open)(name, arg2, arg3));
+ *flags |= Done;
+ }
}
@@ -4473,5 +4482,5 @@ PRE(sys_readlink, Special)
set_result( VG_(do_syscall)(saved, arg1, arg2, arg3));
if ((Int)SYSRES == -2) {
- char name[25];
+ Char name[25];
VG_(sprintf)(name, "/proc/%d/exe", VG_(getpid)());
@@ -5337,5 +5346,5 @@ PRE(sys_rt_sigtimedwait, MayBlock)
PRE_MEM_WRITE( "rt_sigtimedwait(info)", arg2, sizeof(vki_siginfo_t) );
PRE_MEM_READ( "rt_sigtimedwait(timeout)",
- arg4, sizeof(struct vki_timespec) );
+ arg3, sizeof(struct vki_timespec) );
}
@@ -5861,7 +5870,6 @@ void VG_(client_syscall) ( ThreadId tid
(sys->before)(tst->tid, tst, &flags);
- if ((Word)SYSRES <= 0) {
- /* "before" decided the syscall wasn't viable, so don't do
- anything - just pretend the syscall happened. */
+ if ((Word)SYSRES <= 0 || (flags & Done)) {
+ /* "before" did the syscall, so don't do anything else. */
PRINT(" ==> %lld (0x%llx)\n", (Long)(Word)SYSRES, (ULong)SYSRES);
} else if (mayBlock) {
--- valgrind/coregrind/core.h #1.56:1.57
@@ -838,4 +838,7 @@ extern void VG_(resume_scheduler) ( Thre
extern vki_sigset_t VG_(blocked_mask);
+/* Highest signal the kernel will let us use */
+extern Int VG_(max_signal);
+
extern void VG_(sigstartup_actions) ( void );
@@ -1265,4 +1268,5 @@ void VG_(record_fd_open)(Int tid, Int fd
#define MayBlock (1 << 1)
#define PostOnFail (1 << 2)
+#define Done (1 << 3) /* used if a PRE() did the syscall */
// For each generic ("gen") wrapper, we declare the pre-wrapper, the
--- valgrind/coregrind/stage1.c #1.30:1.31
@@ -116,6 +116,6 @@ static void *fix_auxv(void *v_init_esp,
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 %5d: %d %p\n",
+ auxv, auxv->a_type, auxv->u.a_val, auxv->u.a_ptr);
switch(auxv->a_type) {
--- valgrind/coregrind/vg_main.c #1.230:1.231
@@ -859,5 +859,4 @@ static char **fix_environment(char **ori
extern char **environ; /* our environment */
-//#include <error.h>
/* Add a string onto the string table, and return its address */
@@ -1063,7 +1062,4 @@ static Addr setup_client_stack(void* ini
case AT_BASE:
- if (info->interp_base == 0)
- auxv->a_type = AT_IGNORE;
- else
auxv->u.a_val = info->interp_base;
break;
@@ -2320,8 +2316,4 @@ static void build_valgrind_map_callback
UInt prot = 0;
UInt flags = SF_MMAP|SF_NOSYMS;
- Bool is_stack_segment;
-
- is_stack_segment =
- (start == VG_(clstk_base) && (start+size) == VG_(clstk_end));
/* Only record valgrind mappings for now, without loading any
@@ -2507,5 +2499,5 @@ static int prmap(char *start, char *end,
}
-int main(int argc, char **argv)
+int main(int argc, char **argv, char **envp)
{
char **cl_argv;
@@ -2625,5 +2617,5 @@ int main(int argc, char **argv)
// p: load_tool() [for 'preload']
//--------------------------------------------------------------
- env = fix_environment(environ, preload);
+ env = fix_environment(envp, preload);
//--------------------------------------------------------------
--- valgrind/coregrind/vg_procselfmaps.c #1.15:1.16
@@ -239,4 +239,5 @@ void VG_(parse_procselfmaps) (
}
+ if (start < VG_(valgrind_last))
(*record_mapping) ( start, endPlusOne-start,
rr, ww, xx, maj * 256 + min, ino,
--- valgrind/coregrind/vg_messages.c #1.16:1.17
@@ -103,4 +103,5 @@ int VG_(start_msg) ( VgMsgKind kind )
Char ts[32];
Char c;
+ static const Char pfx[] = ">>>>>>>>>>>>>>>>";
vg_n_mbuf = 0;
vg_mbuf[vg_n_mbuf] = 0;
@@ -116,5 +117,6 @@ int VG_(start_msg) ( VgMsgKind kind )
default: c = '?'; break;
}
- return VG_(add_to_msg)( "%c%c%s%d%c%c ",
+ return VG_(add_to_msg)( "%s%c%c%s%d%c%c ",
+ &pfx[sizeof(pfx)-1-RUNNING_ON_VALGRIND],
c,c, ts, VG_(getpid)(), c,c );
}
--- valgrind/coregrind/vg_signals.c #1.106:1.107
@@ -100,4 +100,7 @@ static const Char *signame(Int sigNo);
vki_sigset_t VG_(blocked_mask);
+/* Maximum usable signal. */
+Int VG_(max_signal) = _VKI_NSIG;
+
/* ---------------------------------------------------------------------
HIGH LEVEL STUFF TO DO WITH SIGNALS: POLICY (MOSTLY)
@@ -244,17 +247,15 @@ void calculate_SKSS_from_SCSS ( SKSS* ds
break;
- case VKI_SIGVGKILL:
+ default:
+ if (sig == VKI_SIGVGKILL)
skss_handler = sigvgkill_handler;
- break;
-
- case VKI_SIGVGCHLD:
+ else if (sig == VKI_SIGVGCHLD)
skss_handler = sigvgchld_handler;
- break;
-
- default:
+ else {
if (scss_handler == VKI_SIG_IGN)
skss_handler = VKI_SIG_IGN;
else
skss_handler = vg_async_signalhandler;
+ }
break;
}
@@ -320,5 +321,5 @@ static void handle_SCSS_change ( Bool fo
/* Compare the new SKSS entries vs the old ones, and update kernel
where they differ. */
- for (sig = 1; sig <= _VKI_NSIG; sig++) {
+ for (sig = 1; sig <= VG_(max_signal); sig++) {
/* Trying to do anything with SIGKILL is pointless; just ignore
@@ -469,5 +470,5 @@ Int VG_(do_sys_sigaction) ( ThreadId tid
/* Reject out-of-range signal numbers. */
- if (signo < 1 || signo > _VKI_NSIG) goto bad_signo;
+ if (signo < 1 || signo > VG_(max_signal)) goto bad_signo;
/* don't let them use our signals */
@@ -686,5 +687,5 @@ void vg_push_signal_frame ( ThreadId tid
Int sigNo = siginfo->si_signo;
- vg_assert(sigNo >= 1 && sigNo <= _VKI_NSIG);
+ vg_assert(sigNo >= 1 && sigNo <= VG_(max_signal));
vg_assert(VG_(is_valid_tid)(tid));
tst = & VG_(threads)[tid];
@@ -791,5 +792,5 @@ static const Char *signame(Int sigNo)
case VKI_SIGRTMIN ... VKI_SIGRTMAX:
- VG_(sprintf)(buf, "SIGRT%d", sigNo);
+ VG_(sprintf)(buf, "SIGRT%d", sigNo-VKI_SIGRTMIN);
return buf;
@@ -1495,8 +1496,8 @@ void vg_sync_signalhandler ( Int sigNo,
if (VG_(clo_trace_signals)) {
- VG_(message)(Vg_DebugMsg, "signal %d arrived ... si_code=%d",
- sigNo, info->si_code );
+ VG_(message)(Vg_DebugMsg, "signal %d arrived ... si_code=%d, EIP=%p",
+ sigNo, info->si_code, ARCH_INSTR_PTR(VG_(threads)[tid].arch) );
}
- vg_assert(sigNo >= 1 && sigNo <= _VKI_NSIG);
+ vg_assert(sigNo >= 1 && sigNo <= VG_(max_signal));
/* Special fault-handling case. We can now get signals which can
@@ -1646,8 +1647,12 @@ static void sigvgkill_handler(int signo,
ThreadId tid = VG_(get_lwp_tid)(VG_(gettid)());
- //VG_(printf)("sigvgkill for lwp %d tid %d\n", VG_(gettid)(), tid);
+ if (VG_(clo_trace_signals))
+ VG_(message)(Vg_DebugMsg, "sigvgkill for lwp %d tid %d", VG_(gettid)(), tid);
vg_assert(signo == VKI_SIGVGKILL);
vg_assert(si->si_signo == signo);
+ vg_assert(VG_(threads)[tid].status == VgTs_WaitSys);
+
+ VG_(set_running)(tid);
/* Check that the signal comes from within, and ignore it if not. */
@@ -1674,5 +1679,5 @@ void pp_vg_ksigaction ( struct vki_sigac
sa->ksa_handler, (UInt)sa->sa_flags, sa->sa_restorer);
VG_(printf)("vg_ksigaction: { ");
- for (i = 1; i <= _VKI_NSIG; i++)
+ for (i = 1; i <= VG_(max_signal); i++)
if (VG_(sigismember(&(sa->sa_mask),i)))
VG_(printf)("%d ", i);
@@ -1701,5 +1706,5 @@ void VG_(poll_signals)(ThreadId tid)
if (VG_(sigtimedwait)(&pollset, &si, &zero) > 0) {
if (VG_(clo_trace_signals))
- VG_(message)(Vg_DebugMsg, "poll_signals: got signal %d for thread %d\n", si.si_signo, tid);
+ VG_(message)(Vg_DebugMsg, "poll_signals: got signal %d for thread %d", si.si_signo, tid);
VG_(deliver_signal)(tid, &si);
}
@@ -1735,5 +1739,28 @@ void VG_(sigstartup_actions) ( void )
/* Get the old host action */
ret = VG_(sigaction)(i, NULL, &sa);
+
+ if (ret != 0)
+ break;
+
+ /* Try setting it back to see if this signal is really
+ available */
+ if (i >= VKI_SIGRTMIN) {
+ struct vki_sigaction tsa;
+
+ tsa.ksa_handler = (void *)vg_sync_signalhandler;
+ tsa.sa_flags = VKI_SA_SIGINFO;
+ VG_(sigfillset)(&tsa.sa_mask);
+
+ /* try setting it to some arbitrary handler */
+ if (VG_(sigaction)(i, &tsa, NULL) != 0) {
+ /* failed - not really usable */
+ break;
+ }
+
+ ret = VG_(sigaction)(i, &sa, NULL);
vg_assert(ret == 0);
+ }
+
+ VG_(max_signal) = i;
if (VG_(clo_trace_signals))
@@ -1747,4 +1774,7 @@ void VG_(sigstartup_actions) ( void )
}
+ if (VG_(clo_trace_signals))
+ VG_(message)(Vg_DebugMsg, "Max kernel-supported signal is %d", VG_(max_signal));
+
/* Our private internal signals are treated as ignored */
vg_scss.scss_per_sig[VKI_SIGVGCHLD].scss_handler = VKI_SIG_IGN;
--- valgrind/coregrind/vg_symtab2.c #1.96:1.97
@@ -493,9 +493,10 @@ void canonicaliseSymtab ( SegInfo* si )
VG_INTERCEPT_PREFIX_LEN) == 0) {
int len = VG_(strlen)(si->symtab[i].name);
- char *buf = VG_(malloc)(len), *colon;
+ char *buf = VG_(arena_malloc)(VG_AR_SYMTAB, len), *colon;
intercept_demangle(si->symtab[i].name, buf, len);
colon = buf + VG_(strlen)(buf) - 1;
while(*colon != ':') colon--;
VG_(strncpy_safely)(si->symtab[i].name, colon+1, len);
+ VG_(arena_free)(VG_AR_SYMTAB, buf);
}
}
@@ -2384,5 +2385,14 @@ static Bool resolve_redir(CodeRedirect *
}
+ {
+ CodeRedirect *r = VG_(SkipList_Find)(&sk_resolved_redir, &redir->from_addr);
+
+ if (r == NULL || r->from_addr != redir->from_addr)
VG_(SkipList_Insert)(&sk_resolved_redir, redir);
+ else if (verbose_redir)
+ VG_(message)(Vg_DebugMsg, " redir %s:%s:%p->%s:%s:%p duplicated\n",
+ redir->from_lib, redir->from_sym, redir->from_addr,
+ redir->to_lib, redir->to_sym, redir->to_addr);
+ }
}
--- valgrind/coregrind/vg_transtab.c #1.36:1.37
@@ -31,4 +31,5 @@
#include "core.h"
+#include "memcheck/memcheck.h"
/* #define DEBUG_TRANSTAB */
@@ -361,4 +362,5 @@ void discard_oldest_sector ( void )
s, vg_tc_used[s]);
+ VALGRIND_DISCARD_TRANSLATIONS(vg_tc[s], vg_tc_used[s]);
for(i = 0; i < VG_TC_N_SECTORS; i++) {
if (i != s && vg_tc[i] != NULL)
@@ -401,8 +402,8 @@ Int maybe_commission_sector ( void )
for (s = 0; s < VG_TC_N_SECTORS; s++) {
if (vg_tc[s] == NULL) {
-#if 1
+ if (1)
vg_tc[s] = VG_(get_memory_from_mmap)
( vg_tc_sector_szB, "trans-cache(sector)" );
-#else
+ else {
// Alternative: put translations in an mmap'd file. The main
// reason is to help OProfile -- OProfile can assign time spent in
@@ -421,5 +422,7 @@ Int maybe_commission_sector ( void )
vg_tc[s] = VG_(mmap)(0, PGROUNDUP(vg_tc_sector_szB), VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC, VKI_MAP_SHARED, 0, fd, 0);
VG_(close)(fd);
-#endif
+ }
+
+ VALGRIND_MAKE_WRITABLE(vg_tc[s], vg_tc_sector_szB);
vg_tc_used[s] = 0;
VG_(sprintf)(msg, "after allocation of sector %d (size %d)",
--- valgrind/coregrind/vg_scheduler.c #1.204:1.205
@@ -447,4 +447,6 @@ void VG_(vg_yield)(void)
VG_(nanosleep)(&ts);
VG_(set_running)(tid);
+
+ VG_(poll_signals)(tid); /* something might have happened */
}
@@ -659,4 +661,8 @@ static void handle_syscall(ThreadId tid)
SCHEDSETJMP(tid, sigcode, VG_(client_syscall)(tid));
+ if (!VG_(is_running_thread)(tid))
+ VG_(printf)("tid %d not running; running_tid=%d, tid %d status %d\n",
+ tid, running_tid, tid, tst->status);
+
vg_assert(VG_(is_running_thread)(tid));
@@ -970,5 +976,5 @@ void do_client_request ( ThreadId tid )
case VG_USERREQ__RUNNING_ON_VALGRIND:
- SET_CLREQ_RETVAL(tid, 1);
+ SET_CLREQ_RETVAL(tid, RUNNING_ON_VALGRIND+1);
break;
@@ -1112,5 +1118,5 @@ void do_client_request ( ThreadId tid )
static Bool whined = False;
- if (!whined) {
+ if (!whined && VG_(clo_verbosity) > 2) {
// Allow for requests in core, but defined by tools, which
// have 0 and 0 in their two high bytes.
--- valgrind/include/x86-linux/vki_arch.h #1.9:1.10
@@ -136,8 +136,7 @@ typedef struct {
/* Use high signals because native pthreads wants to use low */
-#define VKI_SIGVGKILL (VKI_SIGRTMAX-0) // [[internal: kill]]
-#define VKI_SIGVGCHLD (VKI_SIGRTMAX-1) // [[internal: thread death]]
-#define VKI_SIGVGRTUSERMAX (VKI_SIGRTMAX-2) // [[internal: last
- // user-usable RT signal]]
+#define VKI_SIGVGKILL (VG_(max_signal)-0) // [[internal: kill]]
+#define VKI_SIGVGCHLD (VG_(max_signal)-1) // [[internal: thread death]]
+#define VKI_SIGVGRTUSERMAX (VG_(max_signal)-2) // [[internal: last user-usable RT signal]]
#define VKI_SA_NOCLDSTOP 0x00000001u
@@ -270,4 +269,5 @@ struct vki_sigcontext {
#define VKI_O_RDONLY 00
#define VKI_O_WRONLY 01
+#define VKI_O_RDWR 02
#define VKI_O_CREAT 0100 /* not fcntl */
#define VKI_O_EXCL 0200 /* not fcntl */
--- valgrind/coregrind/linux/core_os.c #1.1:1.2
@@ -30,4 +30,14 @@ void VGA_(thread_wrapper)(ThreadId tid)
tid, &tid);
+ if (tid == 1) {
+ /* Thread 1 has its stack on the main process stack, and so
+ is expandable. Do this so that backtraces are printed
+ properly.
+ XXX Perhaps it should have a private stack too?
+ */
+ tst->os_state.stack = (UInt *)VG_(valgrind_last) - VG_STACK_SIZE_W;
+ tst->os_state.stacksize = VG_STACK_SIZE_W;
+ }
+
tst->os_state.lwpid = VG_(gettid)();
tst->os_state.threadgroup = VG_(getpid)();
@@ -112,4 +122,5 @@ void VGA_(reap_threads)(ThreadId self)
vg_assert(si.si_signo == VKI_SIGVGCHLD);
}
+ vg_assert(VG_(count_living_threads)() == 1);
}
@@ -123,5 +134,6 @@ void VGA_(intercept_libc_freeres_wrapper
}
-/* Clean up the client by calling __libc_freeres() (if requested) */
+/* Final clean-up before terminating the process.
+ Clean up the client by calling __libc_freeres() (if requested) */
void VGA_(final_tidyup)(ThreadId tid)
{
|
|
From: Jeremy F. <je...@go...> - 2005-01-15 02:00:19
|
CVS commit by fitzhardinge: Redo threading model so that we no longer emulate pthreads. Threads are done at the kernel level with clone etc. Vastly simplifies things. A coregrind/linux/core_os.c 1.1 [no copyright] A coregrind/linux/sema.c 1.1 [no copyright] A coregrind/x86-linux/platform-private.h 1.1 [no copyright] A none/tests/pending.c 1.1 [no copyright] A none/tests/pending.stderr.exp 1.1 A none/tests/pending.stdout.exp 1.1 M +3 -18 coregrind/Makefile.am 1.106 M +182 -273 coregrind/core.h 1.55 M +1 -1 coregrind/core_asm.h 1.5 M +2 -3 coregrind/vg_execontext.c 1.22 M +0 -36 coregrind/vg_intercept.c.base 1.3 M +31 -103 coregrind/vg_main.c 1.230 M +30 -15 coregrind/vg_mylibc.c 1.108 M +504 -2732 coregrind/vg_scheduler.c 1.202 M +288 -604 coregrind/vg_signals.c 1.105 M +2 -19 coregrind/vg_symtab2.c 1.96 M +292 -357 coregrind/vg_syscalls.c 1.228 M +2 -2 coregrind/vg_to_ucode.c 1.152 M +2 -0 coregrind/linux/Makefile.am 1.3 M +87 -1 coregrind/linux/core_os.h 1.3 M +23 -1 coregrind/linux/syscalls.c 1.4 M +25 -22 coregrind/x86/core_arch.h 1.16 M +0 -4 coregrind/x86/dispatch.S 1.3 M +1 -8 coregrind/x86/signal.c 1.6 M +6 -9 coregrind/x86/state.c 1.13 M +76 -0 coregrind/x86-linux/core_platform.h 1.13 M +1 -1 coregrind/x86-linux/ldt.c 1.6 M +124 -6 coregrind/x86-linux/syscall.S 1.3 M +327 -144 coregrind/x86-linux/syscalls.c 1.8 M +11 -11 helgrind/hg_main.c 1.92 M +14 -7 include/tool.h.base 1.17 M +10 -1 include/linux/vki.h 1.11 M +5 -4 include/x86-linux/vki_arch.h 1.9 M +2 -1 memcheck/mac_leakcheck.c 1.16 M +13 -13 memcheck/mc_main.c 1.56 M +1 -1 memcheck/tests/scalar_exit_group.stderr.exp 1.2 M +3 -1 none/tests/Makefile.am 1.54 M +1 -1 none/tests/syscall-restart1.c 1.2 M +2 -0 tests/vg_regtest.in 1.27 R coregrind/vg_libpthread.c 1.180 R coregrind/vg_libpthread.vs 1.10 R coregrind/vg_libpthread_unimp.c 1.50 R coregrind/vg_proxylwp.c 1.31 |
|
From: Jeremy F. <je...@go...> - 2005-01-15 01:59:44
|
On Wed, 2005-01-12 at 15:09 -0800, Jeremy Fitzhardinge wrote: > OK, I went through and cleaned things up, and I think its ready for > checkin. Well, I'll take the absence of any protest that everyone thinks this is OK. I'll start checking them in time for today's regression tests (assuming they get picked up in time). J |