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
(15) |
2
(12) |
3
(11) |
4
(20) |
5
(6) |
|
6
(6) |
7
(7) |
8
(8) |
9
(17) |
10
(25) |
11
(27) |
12
(6) |
|
13
(28) |
14
(16) |
15
(20) |
16
(9) |
17
(26) |
18
(7) |
19
(25) |
|
20
(7) |
21
(18) |
22
(25) |
23
(15) |
24
(21) |
25
(32) |
26
(15) |
|
27
(23) |
28
(33) |
|
|
|
|
|
|
From: Jeremy F. <je...@go...> - 2005-02-04 23:33:07
|
CVS commit by fitzhardinge:
Clarify and explain the logic behind the PROT_NONE-shadow memory
optimisation.
M +6 -1 addrcheck/ac_main.c 1.74
M +2 -2 memcheck/mac_shared.h 1.30
M +6 -1 memcheck/mc_main.c 1.60
--- valgrind/addrcheck/ac_main.c #1.73:1.74
@@ -323,5 +323,10 @@ void set_address_range_perms ( Addr a, S
for (; len >= 8; a += 8, len -= 8) {
PROF_EVENT(32);
- if (abyte8 == VGM_BYTE_INVALID && !IS_MAPPABLE(a))
+
+ /* If we're setting the addressability to "invalid", and the
+ secondary map is the distinguished_secondary_map, don't
+ allocate a new secondary map, since the distinguished map is
+ all-invalid anyway. */
+ if (abyte8 == VGM_BYTE_INVALID && IS_DISTINGUISHED(a))
continue;
ENSURE_MAPPABLE(a, "set_address_range_perms(fast)");
--- valgrind/memcheck/mac_shared.h #1.29:1.30
@@ -196,9 +196,9 @@ extern UInt MAC_(event_ctr)[N_PROF_EVENT
((smap) == &distinguished_secondary_map)
-#define IS_MAPPABLE(addr) (!(IS_DISTINGUISHED_SM(primary_map[(addr) >> 16])))
+#define IS_DISTINGUISHED(addr) (IS_DISTINGUISHED_SM(primary_map[(addr) >> 16]))
#define ENSURE_MAPPABLE(addr,caller) \
do { \
- if (IS_DISTINGUISHED_SM(primary_map[(addr) >> 16])) { \
+ if (IS_DISTINGUISHED(addr)) { \
primary_map[(addr) >> 16] = alloc_secondary_map(caller); \
/* VG_(printf)("new 2map because of %p\n", addr); */ \
--- valgrind/memcheck/mc_main.c #1.59:1.60
@@ -353,5 +353,10 @@ static void set_address_range_perms ( Ad
for (; len >= 8; a += 8, len -= 8) {
PROF_EVENT(32);
- if (abyte8 == VGM_BYTE_INVALID && !IS_MAPPABLE(a))
+
+ /* If we're setting the addressability to "invalid", and the
+ secondary map is the distinguished_secondary_map, don't
+ allocate a new secondary map, since the distinguished map is
+ all-invalid anyway. */
+ if (abyte8 == VGM_BYTE_INVALID && IS_DISTINGUISHED(a))
continue;
ENSURE_MAPPABLE(a, "set_address_range_perms(fast)");
|
|
From: Jeremy F. <je...@go...> - 2005-02-04 22:56:49
|
On Fri, 2005-02-04 at 20:38 +0000, Chris January wrote: > Sorry, maybe I'm not looking at your patch correctly but I can't see how the > VCPU state is flushed out before the exception is generated. Could you > explain please? As I understand it the VCPU state is only flushed after the > exception has occurred, the kernel has queued the SIGTRAP signal, Valgrind > has received the signal and longjmp'ed out of the scheduler. Any external > program monitoring the program looking for traps, for example, will see the > wrong instruction pointer, even if they look in the baseBlock/VG_(threads) > structure instead of the real regs. EIP in the ThreadState (previously baseBlock) is always up to date, because its updated after every instruction. If the INT never completes (which it won't), EIP in the ThreadState will be left pointing to the client instruction which triggered the exception. The other register state may be still wrong; I think vg_from_ucode might defer flushing it until the last moment, which is after the call to the helper. That just means that you need to run with --single-step=yes, like you do with any other program which requires precise exceptions. J |
|
From: Jeremy F. <je...@go...> - 2005-02-04 22:53:34
|
CVS commit by fitzhardinge:
Defer allocating shadow memory for mappings PROT_NONE protections.
They're effectively unaddressable, so there's no need to set up shadow
memory.
Also optimises the addrcheck and memcheck mode-setting so that if
we're setting pages to be unaddressable, don't bother allocating
shadow memory for them (since absent shadow already means
unaddressable).
These help a lot with memory usage when running Valgrind under itself,
since it creates large PROT_NONE mappings, but never touches their
pages.
M +3 -4 addrcheck/ac_main.c 1.73
M +8 -6 coregrind/vg_syscalls.c 1.241
M +2 -0 memcheck/mac_shared.h 1.29
M +3 -4 memcheck/mc_main.c 1.59
--- valgrind/coregrind/vg_syscalls.c #1.240:1.241
@@ -173,5 +173,4 @@ static
void mmap_segment ( Addr a, SizeT len, UInt prot, UInt mm_flags, Int fd, ULong offset )
{
- Bool rr, ww, xx;
UInt flags;
@@ -189,4 +188,6 @@ void mmap_segment ( Addr a, SizeT len, U
VG_(map_fd_segment)(a, len, prot, flags, fd, offset, NULL);
+ if (prot != VKI_PROT_NONE) {
+ Bool rr, ww, xx;
rr = prot & VKI_PROT_READ;
ww = prot & VKI_PROT_WRITE;
@@ -194,4 +195,5 @@ void mmap_segment ( Addr a, SizeT len, U
VG_TRACK( new_mem_mmap, a, len, rr, ww, xx );
+ }
}
--- valgrind/memcheck/mc_main.c #1.58:1.59
@@ -351,7 +351,8 @@ static void set_address_range_perms ( Ad
/* Once aligned, go fast. */
- while (True) {
+ for (; len >= 8; a += 8, len -= 8) {
PROF_EVENT(32);
- if (len < 8) break;
+ if (abyte8 == VGM_BYTE_INVALID && !IS_MAPPABLE(a))
+ continue;
ENSURE_MAPPABLE(a, "set_address_range_perms(fast)");
sm = primary_map[a >> 16];
@@ -360,6 +361,4 @@ static void set_address_range_perms ( Ad
((UInt*)(sm->vbyte))[(sm_off >> 2) + 0] = vword4;
((UInt*)(sm->vbyte))[(sm_off >> 2) + 1] = vword4;
- a += 8;
- len -= 8;
}
--- valgrind/memcheck/mac_shared.h #1.28:1.29
@@ -196,4 +196,6 @@ extern UInt MAC_(event_ctr)[N_PROF_EVENT
((smap) == &distinguished_secondary_map)
+#define IS_MAPPABLE(addr) (!(IS_DISTINGUISHED_SM(primary_map[(addr) >> 16])))
+
#define ENSURE_MAPPABLE(addr,caller) \
do { \
--- valgrind/addrcheck/ac_main.c #1.72:1.73
@@ -321,13 +321,12 @@ void set_address_range_perms ( Addr a, S
/* Once aligned, go fast. */
- while (True) {
+ for (; len >= 8; a += 8, len -= 8) {
PROF_EVENT(32);
- if (len < 8) break;
+ if (abyte8 == VGM_BYTE_INVALID && !IS_MAPPABLE(a))
+ continue;
ENSURE_MAPPABLE(a, "set_address_range_perms(fast)");
sm = primary_map[a >> 16];
sm_off = a & 0xFFFF;
sm->abits[sm_off >> 3] = abyte8;
- a += 8;
- len -= 8;
}
|
|
From: Jeremy F. <je...@go...> - 2005-02-04 22:44:26
|
CVS commit by fitzhardinge:
Fix a little logic bug in the scheduler loop structure. If
VG_(poll_signals)() found a fatal signal, then exit the scheduler
immediately, rather than continuing to run a bit more.
Also, handle async-sync signals correctly.
A none/tests/async-sigs.c 1.1 [no copyright]
A none/tests/async-sigs.stderr.exp 1.1
A none/tests/async-sigs.stdout.exp 1.1
A none/tests/async-sigs.vgtest 1.1
M +5 -5 coregrind/vg_scheduler.c 1.219
M +17 -7 coregrind/vg_signals.c 1.119
M +3 -1 none/tests/Makefile.am 1.62
--- valgrind/coregrind/vg_scheduler.c #1.218:1.219
@@ -672,4 +672,7 @@ VgSchedReturnCode VG_(scheduler) ( Threa
VG_(poll_signals)(tid);
+ if (VG_(is_exiting)(tid))
+ break; /* poll_signals picked up a fatal signal */
+
/* For stats purposes only. */
n_scheduling_events_MAJOR++;
@@ -734,9 +737,6 @@ VgSchedReturnCode VG_(scheduler) ( Threa
case VG_TRC_FAULT_SIGNAL:
- /* Make sure we've unblocked the signals which the handler
- blocked. This should never block more signals that
- before (ie, there's no window that unsafe signals could
- sneak in). */
- VG_(block_signals)(tid);
+ /* Everything should be set up (either we're exiting, or
+ about to start in a signal handler). */
break;
--- valgrind/coregrind/vg_signals.c #1.118:1.119
@@ -1688,8 +1688,11 @@ void vg_sync_signalhandler ( Int sigNo,
sigNo == VKI_SIGTRAP);
- 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);
+ if (info->si_code <= VKI_SI_USER) {
+ /* If some user-process sent us one of these signals (ie,
+ they're not the result of a faulting instruction), then treat
+ it as an async signal. This recipient thread may or may not
+ be running at the time, so we need to make sure we have the
+ CPU before going on. */
+ if (!VG_(is_running_thread)(tid))
VG_(set_running)(tid);
@@ -1697,6 +1700,13 @@ void vg_sync_signalhandler ( Int sigNo,
on the kernel to route them properly, so we need to queue
them manually. */
- queue_signal(0, info);
- VG_(resume_scheduler)(tid);
+ if (info->si_code == VKI_SI_TKILL)
+ queue_signal(tid, info); /* directed to us specifically */
+ else
+ queue_signal(0, info); /* shared pending */
+
+ /* Just return; either the thread was running so we just return
+ to the instruction that happened to be interrupted, or it was
+ not running - but it is now. */
+ return;
}
--- valgrind/none/tests/Makefile.am #1.61:1.62
@@ -5,4 +5,5 @@
EXTRA_DIST = $(noinst_SCRIPTS) \
args.stderr.exp args.stdout.exp args.vgtest \
+ async-sigs.stderr.exp async-sigs.stdout.exp async-sigs.vgtest \
bitfield1.stderr.exp bitfield1.vgtest \
blockfault.vgtest \
@@ -64,5 +65,5 @@
check_PROGRAMS = \
- args bitfield1 blockfault closeall coolo_strlen \
+ args async-sigs bitfield1 blockfault closeall coolo_strlen \
discard exec-sigmask execve faultstatus fcntl_setown floored fork \
fucomip getseg \
@@ -83,4 +84,5 @@
# generic C ones
args_SOURCES = args.c
+async_sigs_SOURCES = async-sigs.c
bitfield1_SOURCES = bitfield1.c
blockfault_SOURCES = blockfault.c
|
|
From: Jeremy F. <je...@go...> - 2005-02-04 22:44:18
|
CVS commit by fitzhardinge:
Extend faultstatus to test for all the interrupt-raising instructions.
Valgrind doesn't implement all of these (into and bound), so we get
some expected failures (SIGILL rather than SIGSEGV).
Removes a lot of mostly-duplicate code.
Also, fix a minor conformance bug in SIGILL - the si_addr field is
supposed to point to the illegal instruction.
M +5 -0 coregrind/x86/signal.c 1.13
M +74 -110 none/tests/faultstatus.c 1.3
M +13 -7 none/tests/faultstatus.stderr.exp 1.5
--- valgrind/none/tests/faultstatus.c #1.2:1.3
@@ -10,4 +10,13 @@
#include <unistd.h>
+struct test {
+ void (*test)(void);
+ int sig;
+ int code;
+ volatile void *addr;
+};
+
+static const struct test *cur_test;
+
static int zero();
@@ -49,39 +58,28 @@ static int testaddr(void *addr, volatile
}
-static void test1(void)
-{
- *BADADDR = 'x';
-}
-
-static void handler1(int sig, siginfo_t *si, void *uc)
+static void handler(int sig, siginfo_t *si, void *uc)
{
int ok = 1;
- ok = ok && testsig(sig, SIGSEGV);
- ok = ok && testcode(si->si_code, SEGV_MAPERR);
- ok = ok && testaddr(si->si_addr, BADADDR);
+ ok = ok && testsig(sig, cur_test->sig);
+ ok = ok && testcode(si->si_code, cur_test->code);
+ if (cur_test->addr)
+ ok = ok && testaddr(si->si_addr, cur_test->addr);
if (ok)
- fprintf(stderr, " PASS 1\n");
+ fprintf(stderr, " PASS\n");
- siglongjmp(escape, 1);
+ siglongjmp(escape, ok + 1);
}
-static void test2()
+
+static void test1(void)
{
- mapping[0] = 'x';
+ *BADADDR = 'x';
}
-static void handler2(int sig, siginfo_t *si, void *uc)
+static void test2()
{
- int ok = 1;
-
- ok = ok && testsig(sig, SIGSEGV);
- ok = ok && testcode(si->si_code, SEGV_ACCERR);
- ok = ok && testaddr(si->si_addr, mapping);
- if (ok)
- fprintf(stderr, " PASS 2\n");
-
- siglongjmp(escape, 1);
+ mapping[0] = 'x';
}
@@ -91,49 +89,16 @@ static void test3()
}
-static void handler3(int sig, siginfo_t *si, void *uc)
-{
- int ok = 1;
-
- ok = ok && testsig(sig, SIGBUS);
- ok = ok && testcode(si->si_code, BUS_ADRERR);
- ok = ok && testaddr(si->si_addr, &mapping[FILESIZE+10]);
- if (ok)
- fprintf(stderr, " PASS 3\n");
-
- siglongjmp(escape, 1);
-}
-
static void test4()
{
- asm volatile("ud2");
-}
-
-static void handler4(int sig, siginfo_t *si, void *uc)
-{
- int ok = 1;
-
- ok = ok && testsig(sig, SIGILL);
- ok = ok && testcode(si->si_code, ILL_ILLOPN);
- if (ok)
- fprintf(stderr, " PASS 4\n");
+ volatile int v = 44/zero();
- siglongjmp(escape, 1);
+ (void)v;
}
+#ifdef __i386__
+extern char test5_ill;
static void test5()
{
- volatile int v = 44/zero();
-}
-
-static void handler5(int sig, siginfo_t *si, void *uc)
-{
- int ok = 1;
-
- ok = ok && testsig(sig, SIGFPE);
- ok = ok && testcode(si->si_code, FPE_INTDIV);
- if (ok)
- fprintf(stderr, " PASS 5\n");
-
- siglongjmp(escape, 1);
+ asm volatile("test5_ill: ud2");
}
@@ -143,53 +108,37 @@ static void test6()
}
-static void handler6(int sig, siginfo_t *si, void *uc)
+static void test7()
{
- int ok = 1;
-
- ok = ok && testsig(sig, SIGTRAP);
- ok = ok && testcode(si->si_code, 128); /* should be TRAP_BRKPT */
- if (ok)
- fprintf(stderr, " PASS 6\n");
-
- siglongjmp(escape, 1);
+ asm volatile ("int $0x10");
}
-static void test7()
+static void test8()
{
- asm volatile ("int $0x40");
+ volatile int a;
+ asm volatile ("add $1, %0;"/* set OF */
+ "into"
+ : "=a" (a) : "0" (0x7fffffff) : "cc");
}
-static void handler7(int sig, siginfo_t *si, void *uc)
+static void test9()
{
- int ok = 1;
-
- ok = ok && testsig(sig, SIGSEGV);
- ok = ok && testcode(si->si_code, 128); /* GPF */
- if (ok)
- fprintf(stderr, " PASS 7\n");
+ static int limit[2] = { 0, 10 };
- siglongjmp(escape, 1);
+ asm volatile ("bound %0, %1" : : "r" (11), "m" (limit));
}
-
+#endif /* __i386__ */
int main()
{
- int fd;
- static const struct test {
- void (*test)(void);
- void (*handler)(int, siginfo_t *, void *);
- } tests[] = {
-#define T(n) { test##n, handler##n }
- T(1),
- T(2),
- T(3),
- T(4),
- T(5),
- T(6),
- T(7),
-#undef T
- };
+ int fd, i;
static const int sigs[] = { SIGSEGV, SIGILL, SIGBUS, SIGFPE, SIGTRAP };
- int i;
+ struct sigaction sa;
+
+ sa.sa_sigaction = handler;
+ sa.sa_flags = SA_SIGINFO;
+ sigfillset(&sa.sa_mask);
+
+ for(i = 0; i < sizeof(sigs)/sizeof(*sigs); i++)
+ sigaction(sigs[i], &sa, NULL);
fd = open("faultstatus.tmp", O_CREAT|O_TRUNC|O_EXCL, 0600);
@@ -204,13 +153,27 @@ int main()
close(fd);
- for(i = 0; i < sizeof(tests)/sizeof(*tests); i++) {
- int j;
- struct sigaction sa;
- sa.sa_sigaction = tests[i].handler;
- sa.sa_flags = SA_SIGINFO;
- sigfillset(&sa.sa_mask);
+ {
+ const struct test tests[] = {
+#define T(n, sig, code, addr) { test##n, sig, code, addr }
+ T(1, SIGSEGV, SEGV_MAPERR, BADADDR),
+ T(2, SIGSEGV, SEGV_ACCERR, mapping),
+ T(3, SIGBUS, BUS_ADRERR, &mapping[FILESIZE+10]),
+ T(4, SIGFPE, FPE_INTDIV, 0),
+#ifdef __i386__
+ T(5, SIGILL, ILL_ILLOPN, &test5_ill),
+ T(6, SIGTRAP, 128, 0), /* TRAP_BRKPT? */
+ T(7, SIGSEGV, 128, 0),
- for(j = 0; j < sizeof(sigs)/sizeof(*sigs); j++)
- sigaction(sigs[j], &sa, NULL);
+ /* These 2 are an expected failure - Valgrind
+ doesn't implement their instructions, and
+ so issues a SIGILL instead. */
+ T(8, SIGSEGV, 128, 0),
+ T(9, SIGSEGV, 128, 0),
+#endif /* __i386__ */
+#undef T
+ };
+
+ for(i = 0; i < sizeof(tests)/sizeof(*tests); i++) {
+ cur_test = &tests[i];
if (sigsetjmp(escape, 1) == 0) {
@@ -220,4 +183,5 @@ int main()
}
}
+ }
return 0;
--- valgrind/none/tests/faultstatus.stderr.exp #1.4:1.5
@@ -1,9 +1,15 @@
-Test 1: PASS 1
-Test 2: PASS 2
-Test 3: PASS 3
-Test 4: PASS 4
-Test 5: PASS 5
-Test 6: PASS 6
-Test 7: PASS 7
+Test 1: PASS
+Test 2: PASS
+Test 3: PASS
+Test 4: PASS
+Test 5: PASS
+Test 6: PASS
+Test 7: PASS
+Test 8: disInstr: unhandled instruction bytes: 0x........ 0x........ 0x........ 0x........
+ at 0x........: test8 (faultstatus.c:118)
+ FAIL: expected signal 11, not 4
+Test 9: disInstr: unhandled instruction bytes: 0x........ 0x........ 0x........ 0x........
+ at 0x........: test9 (faultstatus.c:127)
+ FAIL: expected signal 11, not 4
--- valgrind/coregrind/x86/signal.c #1.12:1.13
@@ -499,4 +499,9 @@ static Addr build_rt_sigframe(ThreadStat
frame->puContext = (Addr)&frame->uContext;
VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_siginfo_t));
+
+ /* SIGILL defines addr to be the faulting address */
+ if (sigNo == VKI_SIGILL && siginfo->si_code > 0)
+ frame->sigInfo._sifields._sigfault._addr = tst->arch.m_eip;
+
synth_ucontext(tst->tid, siginfo, mask, &frame->uContext, &frame->fpstate);
|
|
From: Chris J. <ch...@at...> - 2005-02-04 20:38:53
|
> On Fri, 2005-02-04 at 09:16 +0000, Chris January wrote: > > > Actually, that's what my patch does, only much more simply. > > > It calls a helper which invokes a real int3 instruction; the=20 > > > generated SIGTRAP is then delivered to the thread using the=20 > > > normal signal machinery. > >=20 > > Doesn't that mean %eip isn't in the baseBlock/VG_(threads) at=20 > > exception time? >=20 > The INT/ud2 instructions are considered to be the end of the=20 > basic block, so all the VCPU state is flushed out. EIP will=20 > point to the client's INT instruction (so it doesn't matter=20 > what kind of INT we use to raise the signal, so long as it=20 > raises the right kind of signal). Sorry, maybe I'm not looking at your patch correctly but I can't see how = the VCPU state is flushed out before the exception is generated. Could you explain please? As I understand it the VCPU state is only flushed after = the exception has occurred, the kernel has queued the SIGTRAP signal, = Valgrind has received the signal and longjmp'ed out of the scheduler. Any = external program monitoring the program looking for traps, for example, will see = the wrong instruction pointer, even if they look in the = baseBlock/VG_(threads) structure instead of the real regs. Chris |
|
From: Jeremy F. <je...@go...> - 2005-02-04 17:59:07
|
On Fri, 2005-02-04 at 09:16 +0000, Chris January wrote: > > Actually, that's what my patch does, only much more simply. > > It calls a helper which invokes a real int3 instruction; the > > generated SIGTRAP is then delivered to the thread using the > > normal signal machinery. > > Doesn't that mean %eip isn't in the baseBlock/VG_(threads) at exception > time? The INT/ud2 instructions are considered to be the end of the basic block, so all the VCPU state is flushed out. EIP will point to the client's INT instruction (so it doesn't matter what kind of INT we use to raise the signal, so long as it raises the right kind of signal). J |
|
From: Chris J. <ch...@at...> - 2005-02-04 09:20:31
|
> On Thu, 2005-02-03 at 21:17 +0000, Chris January wrote: > > I think the breakpoints patch I've posted to this list could be > > informative here since it handles INT $3. The same > principles could be > > extended to handle other interrupts. Basically what the > patch does is > > translate the trap instruction into code to return from the > innerloop > > with a particular TRC value. This value is then caught in > > VG_(scheduler) which raises a real signal (SIGTRAP in this case). > > Raising a real signal has the benefit it can be seen by a debugger. > > Actually, that's what my patch does, only much more simply. > It calls a helper which invokes a real int3 instruction; the > generated SIGTRAP is then delivered to the thread using the > normal signal machinery. Doesn't that mean %eip isn't in the baseBlock/VG_(threads) at exception time? Chris |
|
From: <js...@ac...> - 2005-02-04 03:56:51
|
Nightly build on phoenix ( SuSE 9.1 ) started at 2005-02-04 03:50:00 GMT Checking out source tree ... done Configuring ... done Building ... done Running regression tests ... done Last 20 lines of log.verbose follow -- Finished tests in none/tests ---------------------------------------- == 194 tests, 15 stderr failures, 0 stdout failures ================= corecheck/tests/as_mmap (stderr) corecheck/tests/fdleak_fcntl (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) make: *** [regtest] Error 1 |
|
From: Tom H. <to...@co...> - 2005-02-04 03:24:12
|
Nightly build on dunsmere ( Fedora Core 3 ) started at 2005-02-04 03:20:03 GMT Checking out source tree ... done Configuring ... done Building ... done Running regression tests ... done Last 20 lines of log.verbose follow seg_override: valgrind --num-callers=4 ./seg_override -- Finished tests in none/tests/x86 ------------------------------------ yield: valgrind --num-callers=4 ./yield -- Finished tests in none/tests ---------------------------------------- == 201 tests, 12 stderr failures, 0 stdout failures ================= 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/scalar (stderr) memcheck/tests/scalar_supp (stderr) memcheck/tests/vgtest_ume (stderr) make: *** [regtest] Error 1 |
|
From: Tom H. <th...@cy...> - 2005-02-04 03:20:52
|
Nightly build on audi ( Red Hat 9 ) started at 2005-02-04 03:15:05 GMT Checking out source tree ... done Configuring ... done Building ... done Running regression tests ... done Last 20 lines of log.verbose follow corecheck/tests/fdleak_socketpair (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/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) make: *** [regtest] Error 1 |
|
From: Tom H. <th...@cy...> - 2005-02-04 03:14:41
|
Nightly build on ginetta ( Red Hat 8.0 ) started at 2005-02-04 03:10:02 GMT Checking out source tree ... done Configuring ... done Building ... done Running regression tests ... done Last 20 lines of log.verbose follow seg_override: valgrind --num-callers=4 ./seg_override -- Finished tests in none/tests/x86 ------------------------------------ yield: valgrind --num-callers=4 ./yield -- Finished tests in none/tests ---------------------------------------- == 199 tests, 12 stderr failures, 0 stdout failures ================= 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) make: *** [regtest] Error 1 |
|
From: Tom H. <th...@cy...> - 2005-02-04 03:09:25
|
Nightly build on alvis ( Red Hat 7.3 ) started at 2005-02-04 03:05:02 GMT Checking out source tree ... done Configuring ... done Building ... done Running regression tests ... done Last 20 lines of log.verbose follow yield: valgrind --num-callers=4 ./yield -- Finished tests in none/tests ---------------------------------------- == 199 tests, 14 stderr failures, 0 stdout failures ================= 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/post-syscall (stderr) memcheck/tests/pth_once (stderr) memcheck/tests/scalar (stderr) memcheck/tests/threadederrno (stderr) memcheck/tests/vgtest_ume (stderr) make: *** [regtest] Error 1 |
|
From: Tom H. <th...@cy...> - 2005-02-04 03:05:08
|
Nightly build on standard ( Red Hat 7.2 ) started at 2005-02-04 03:00:04 GMT Checking out source tree ... done Configuring ... done Building ... done Running regression tests ... done Last 20 lines of log.verbose follow -- Finished tests in none/tests/x86 ------------------------------------ yield: valgrind --num-callers=4 ./yield -- Finished tests in none/tests ---------------------------------------- == 199 tests, 13 stderr failures, 0 stdout failures ================= 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/vgtest_ume (stderr) make: *** [regtest] Error 1 |
|
From: Jeremy F. <je...@go...> - 2005-02-04 02:03:26
|
CVS commit by fitzhardinge:
Support all INT instructions. The only really interesting ones are
int $0x80 (syscall, already supported) and int3 (breakpoint), but some
software uses signals raised by other INTs. This change implements
all the non-syscall INTs by simply jumping to a handler containing an
appropriate INT and letting the normal kernel machinery generate the
signal.
This also changes vg_to_ucode to explicitly recognize ud2 and not
generate a message about it, since it isn't an unknown instruction -
it's defined to be undefined.
M +9 -6 coregrind/vg_signals.c 1.118
M +28 -5 coregrind/vg_to_ucode.c 1.154
M +2 -0 coregrind/x86/core_arch.h 1.22
M +15 -1 coregrind/x86/helpers.S 1.5
M +38 -2 none/tests/faultstatus.c 1.2
M +7 -7 none/tests/faultstatus.stderr.exp 1.4
M +2 -4 none/tests/x86/int.stderr.exp 1.4
--- valgrind/coregrind/vg_to_ucode.c #1.153:1.154
@@ -5524,14 +5524,31 @@ static Addr disInstr ( UCodeBlock* cb, A
/* ------------------------ INT ------------------------ */
+ case 0xCC: /* INT3 - breakpoint */
case 0xCD: /* INT imm8 */
- d32 = getUChar(eip); eip++;
- if (d32 != 0x80) goto decode_failure;
+ if (opc == 0xCD)
+ d32 = getUChar(eip++);
+ else
+ d32 = 3;
+
/* It's important that all ArchRegs carry their up-to-date value
at this point. So we declare an end-of-block here, which
forces any TempRegs caching ArchRegs to be flushed. */
+ *isEnd = True;
+ if (d32 != 0x80) {
+ uInstr0(cb, CALLM_S, 0);
+ uInstr1(cb, CALLM, 0, Literal, 0);
+ uLiteral(cb, (Addr)((d32 == 3) ? VG_(helper_breakpoint) : VG_(helper_INT)));
+ uInstr0(cb, CALLM_E, 0);
+ }
+
jmp_lit(cb, eip);
+ if (d32 == 0x80)
LAST_UINSTR(cb).jmpkind = JmpSyscall;
- *isEnd = True;
- DIP("int $0x80\n");
+
+ if (opc == 0xCD) {
+ DIP("int $0x%02x\n", d32);
+ } else {
+ DIP("int3\n");
+ }
break;
@@ -6570,4 +6587,8 @@ static Addr disInstr ( UCodeBlock* cb, A
switch (opc) {
+ case 0x0B: /* UD2 */
+ DIP("ud2\n");
+ goto undefined_instruction;
+
/* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
@@ -7363,4 +7384,6 @@ static Addr disInstr ( UCodeBlock* cb, A
VG_(message)(Vg_DebugMsg, " at %s", loc_buf);
+ undefined_instruction:
+
uInstr0(cb, CALLM_S, 0);
uInstr1(cb, CALLM, 0, Literal, 0);
--- valgrind/coregrind/vg_signals.c #1.117:1.118
@@ -34,9 +34,9 @@
There are 4 distinct classes of signal:
- 1. Synchronous, instruction-generated (SIGILL, FPE, BUS and SEGV):
- these are signals as a result of an instruction fault. If we get
- one while running client code, then we just do the appropriate
- thing. If it happens while running Valgrind code, then it
- indicates a Valgrind bug. Note that we "manually" implement
+ 1. Synchronous, instruction-generated (SIGILL, FPE, BUS, SEGV and
+ TRAP): these are signals as a result of an instruction fault. If
+ we get one while running client code, then we just do the
+ appropriate thing. If it happens while running Valgrind code, then
+ it indicates a Valgrind bug. Note that we "manually" implement
automatic stack growth, such that if a fault happens near the
client process stack, it is extended in the same way the kernel
@@ -245,4 +245,5 @@ void calculate_SKSS_from_SCSS ( SKSS* ds
case VKI_SIGFPE:
case VKI_SIGILL:
+ case VKI_SIGTRAP:
/* For these, we always want to catch them and report, even
if the client code doesn't. */
@@ -1684,5 +1685,6 @@ void vg_sync_signalhandler ( Int sigNo,
sigNo == VKI_SIGBUS ||
sigNo == VKI_SIGFPE ||
- sigNo == VKI_SIGILL);
+ sigNo == VKI_SIGILL ||
+ sigNo == VKI_SIGTRAP);
if (!VG_(is_running_thread)(tid)) {
@@ -1940,4 +1942,5 @@ void VG_(block_signals)(ThreadId tid)
VG_(sigdelset)(&mask, VKI_SIGFPE);
VG_(sigdelset)(&mask, VKI_SIGILL);
+ VG_(sigdelset)(&mask, VKI_SIGTRAP);
/* Can't block these anyway */
--- valgrind/coregrind/x86/helpers.S #1.4:1.5
@@ -709,5 +709,19 @@
1: ud2
jmp 1b
-
+
+/* misc INT instruction - they all fail the same way */
+.globl VG_(helper_INT)
+VG_(helper_INT):
+ int $0x40
+1: ud2 /* int should not return */
+ jmp 1b
+
+/* breakpoint trap */
+.globl VG_(helper_breakpoint)
+VG_(helper_breakpoint):
+ int3
+1: ud2 /* int should not return */
+ jmp 1b
+
/* Let the linker know we don't need an executable stack */
.section .note.GNU-stack,"",@progbits
--- valgrind/coregrind/x86/core_arch.h #1.21:1.22
@@ -103,4 +103,6 @@ extern const Char VG_(helper_wrapper_ret
extern const Char VG_(helper_undefined_instruction)[];
+extern const Char VG_(helper_INT)[];
+extern const Char VG_(helper_breakpoint)[];
/* Mul, div, etc, -- we don't codegen these directly. */
--- valgrind/none/tests/faultstatus.c #1.1:1.2
@@ -138,4 +138,38 @@ static void handler5(int sig, siginfo_t
}
+static void test6()
+{
+ asm volatile ("int3");
+}
+
+static void handler6(int sig, siginfo_t *si, void *uc)
+{
+ int ok = 1;
+
+ ok = ok && testsig(sig, SIGTRAP);
+ ok = ok && testcode(si->si_code, 128); /* should be TRAP_BRKPT */
+ if (ok)
+ fprintf(stderr, " PASS 6\n");
+
+ siglongjmp(escape, 1);
+}
+
+static void test7()
+{
+ asm volatile ("int $0x40");
+}
+
+static void handler7(int sig, siginfo_t *si, void *uc)
+{
+ int ok = 1;
+
+ ok = ok && testsig(sig, SIGSEGV);
+ ok = ok && testcode(si->si_code, 128); /* GPF */
+ if (ok)
+ fprintf(stderr, " PASS 7\n");
+
+ siglongjmp(escape, 1);
+}
+
int main()
@@ -152,7 +186,9 @@ int main()
T(4),
T(5),
+ T(6),
+ T(7),
#undef T
};
- static const int sigs[] = { SIGSEGV, SIGILL, SIGBUS, SIGFPE };
+ static const int sigs[] = { SIGSEGV, SIGILL, SIGBUS, SIGFPE, SIGTRAP };
int i;
@@ -179,5 +215,5 @@ int main()
if (sigsetjmp(escape, 1) == 0) {
- fprintf(stderr, "Test %d: ", i);
+ fprintf(stderr, "Test %d: ", i+1);
tests[i].test();
fprintf(stderr, " FAIL: no fault, or handler returned\n");
--- valgrind/none/tests/faultstatus.stderr.exp #1.3:1.4
@@ -1,9 +1,9 @@
-Test 0: PASS 1
-Test 1: PASS 2
-Test 2: PASS 3
-Test 3: disInstr: unhandled instruction bytes: 0x........ 0x........ 0x........ 0x........
- at 0x........: test4 (faultstatus.c:108)
- PASS 4
-Test 4: PASS 5
+Test 1: PASS 1
+Test 2: PASS 2
+Test 3: PASS 3
+Test 4: PASS 4
+Test 5: PASS 5
+Test 6: PASS 6
+Test 7: PASS 7
--- valgrind/none/tests/x86/int.stderr.exp #1.3:1.4
@@ -1,8 +1,6 @@
-disInstr: unhandled instruction bytes: 0x........ 0x........ 0x........ 0x........
- at 0x........: main (int.c:5)
-Process terminating with default action of signal 4 (SIGILL)
- Illegal operand at address 0x........
+Process terminating with default action of signal 11 (SIGSEGV)
+ GPF (Pointer out of bounds?)
at 0x........: main (int.c:5)
|
|
From: Jeremy F. <je...@go...> - 2005-02-04 01:08:47
|
CVS commit by fitzhardinge:
Hook into the existing redirection machinery to allow wrapped
functions to be requested symbolically.
M +18 -19 vg_main.c 1.244
M +152 -51 vg_redir.c 1.3
M +9 -1 vg_transtab.c 1.40
--- valgrind/coregrind/vg_redir.c #1.2:1.3
@@ -40,15 +40,37 @@
static const Bool verbose_redir = False;
+/*
+ wraps and redirections, indexed by from_addr
-/* resolved redirections, indexed by from_addr */
+ Redirection and wrapping are two distinct mechanisms which Valgrind
+ can use to change the client's control flow.
+
+ Redirection intercepts a call to a client function, and re-points it
+ to a new piece of code (presumably functionally equivalent). The
+ original code is never run.
+
+ Wrapping does call the client's original code, but calls "before"
+ and "after" functions which can inspect (and perhaps modify) the
+ function's arguments and return value.
+ */
struct _CodeRedirect {
+ enum redir_type {
+ R_REDIRECT, /* plain redirection */
+ R_WRAPPER, /* wrap with valgrind-internal code */
+ R_CLIENT_WRAPPER, /* wrap with client-side code */
+ } type;
+
const Char *from_lib; /* library qualifier pattern */
const Char *from_sym; /* symbol */
Addr from_addr; /* old addr */
+ /* used for redirection */
const Char *to_lib; /* library qualifier pattern */
const Char *to_sym; /* symbol */
Addr to_addr; /* new addr */
+ /* used for wrapping */
+ const FuncWrapper *wrapper;
+
CodeRedirect *next; /* next pointer on unresolved list */
};
@@ -110,4 +132,17 @@ static Bool match_lib(const Char *patter
}
+static inline Bool from_resolved(const CodeRedirect *redir)
+{
+ return redir->from_addr != 0;
+}
+
+static inline Bool to_resolved(const CodeRedirect *redir)
+{
+ if (redir->type == R_REDIRECT)
+ return redir->to_addr != 0;
+ vg_assert(redir->wrapper != NULL);
+ return True;
+}
+
/* Resolve a redir using si if possible, and add it to the resolved
list */
@@ -123,5 +158,5 @@ Bool VG_(resolve_redir)(CodeRedirect *re
return False;
- resolved = (redir->from_addr != 0) && (redir->to_addr != 0);
+ resolved = from_resolved(redir) && to_resolved(redir);
if (0 && verbose_redir)
@@ -133,5 +168,5 @@ Bool VG_(resolve_redir)(CodeRedirect *re
vg_assert(!resolved);
- if (redir->from_addr == 0) {
+ if (!from_resolved(redir)) {
vg_assert(redir->from_sym != NULL);
@@ -144,5 +179,6 @@ Bool VG_(resolve_redir)(CodeRedirect *re
}
- if (redir->to_addr == 0) {
+ if (!to_resolved(redir)) {
+ vg_assert(redir->type == R_REDIRECT);
vg_assert(redir->to_sym != NULL);
@@ -156,5 +192,5 @@ Bool VG_(resolve_redir)(CodeRedirect *re
}
- resolved = (redir->from_addr != 0) && (redir->to_addr != 0);
+ resolved = from_resolved(redir) && to_resolved(redir);
if (0 && verbose_redir)
@@ -164,4 +200,6 @@ Bool VG_(resolve_redir)(CodeRedirect *re
if (resolved) {
+ switch(redir->type) {
+ case R_REDIRECT:
if (VG_(clo_verbosity) > 2 || verbose_redir) {
VG_(message)(Vg_DebugMsg, " redir resolved (%s:%s=%p -> ",
@@ -204,5 +242,7 @@ Bool VG_(resolve_redir)(CodeRedirect *re
if (r == NULL)
VG_(SkipList_Insert)(&sk_resolved_redir, redir);
- else if (verbose_redir)
+ else {
+ /* XXX leak redir */
+ 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,
@@ -210,4 +250,21 @@ Bool VG_(resolve_redir)(CodeRedirect *re
}
}
+ break;
+
+ case R_WRAPPER:
+ if (VG_(clo_verbosity) > 2 || verbose_redir) {
+ VG_(message)(Vg_DebugMsg, " redir resolved (%s:%s=%p -> wrapper)",
+ redir->from_lib, redir->from_sym, redir->from_addr);
+ }
+
+ /* XXX redir leaked */
+ VG_(wrap_function)(redir->from_addr, redir->wrapper);
+ break;
+
+ case R_CLIENT_WRAPPER:
+ VG_(core_panic)("not implemented");
+ break;
+ }
+ }
return resolved;
@@ -246,4 +303,6 @@ static void add_redirect_sym(const Char
CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
+ redir->type = R_REDIRECT;
+
redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
@@ -259,6 +318,8 @@ static void add_redirect_sym(const Char
from_lib, from_sym, to_lib, to_sym);
+ /* Check against all existing segments to see if this redirection
+ can be resolved immediately */
if (!VG_(resolve_redir_allsegs)(redir)) {
- /* can't resolve immediately; add to list */
+ /* nope, add to list */
redir->next = unresolved_redir;
unresolved_redir = redir;
@@ -266,5 +327,5 @@ static void add_redirect_sym(const Char
}
-/* Redirect a lib/symbol reference to a function at lib/symbol */
+/* Redirect a lib/symbol reference to a function at addr */
void VG_(add_redirect_addr)(const Char *from_lib, const Char *from_sym,
Addr to_addr)
@@ -272,4 +333,6 @@ void VG_(add_redirect_addr)(const Char *
CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
+ redir->type = R_REDIRECT;
+
redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
@@ -280,6 +343,8 @@ void VG_(add_redirect_addr)(const Char *
redir->to_addr = to_addr;
+ /* Check against all existing segments to see if this redirection
+ can be resolved immediately */
if (!VG_(resolve_redir_allsegs)(redir)) {
- /* can't resolve immediately; add to list */
+ /* nope, add to list */
redir->next = unresolved_redir;
unresolved_redir = redir;
@@ -287,4 +352,36 @@ void VG_(add_redirect_addr)(const Char *
}
+void VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
+ const FuncWrapper *wrapper)
+{
+ CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
+
+ if (0)
+ VG_(printf)("adding wrapper for %s:%s -> (%p,%p)\n",
+ from_lib, from_sym, wrapper->before, wrapper->after);
+
+ redir->type = R_WRAPPER;
+
+ redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
+ redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
+ redir->from_addr = 0;
+
+ redir->to_lib = NULL;
+ redir->to_sym = NULL;
+ redir->to_addr = 0;
+
+ redir->wrapper = wrapper;
+
+ /* Check against all existing segments to see if this redirection
+ can be resolved immediately */
+ if (!VG_(resolve_redir_allsegs)(redir)) {
+ /* nope, add to list */
+ redir->next = unresolved_redir;
+ unresolved_redir = redir;
+ }
+}
+
+ /* If address 'a' is being redirected, return the redirected-to
+ address. */
Addr VG_(code_redirect)(Addr a)
{
@@ -444,4 +541,5 @@ void VG_(wrap_after)(ThreadState *tst)
struct call_instance *call = find_call(EIP, ESP, tst->tid);
+ VG_(printf)("wrap_after(%p,%p,%d) -> %p\n", EIP, ESP, tst->tid, call);
if (call != NULL) {
if (call->wrapper->after)
@@ -476,4 +574,7 @@ void VG_(wrap_function)(Addr eip, const
struct wrapped_function *func;
+ if (0)
+ VG_(printf)("wrapping %p with (%p,%p)\n", eip, wrapper->before, wrapper->after);
+
func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
--- valgrind/coregrind/vg_main.c #1.243:1.244
@@ -2548,4 +2548,22 @@ int main(int argc, char **argv, char **e
//--------------------------------------------------------------
+ // Allow GDB attach
+ // p: process_cmd_line_options() [for VG_(clo_wait_for_gdb)]
+ //--------------------------------------------------------------
+ /* Hook to delay things long enough so we can get the pid and
+ attach GDB in another shell. */
+ if (VG_(clo_wait_for_gdb)) {
+ VG_(printf)("pid=%d\n", VG_(getpid)());
+ /* do "jump *$eip" to skip this in gdb */
+ VG_(do_syscall)(__NR_pause);
+ }
+
+ //--------------------------------------------------------------
+ // Read debug info to find glibc entry points to intercept
+ // p: parse_procselfmaps? [XXX for debug info?]
+ //--------------------------------------------------------------
+ VG_(setup_code_redirect_table)();
+
+ //--------------------------------------------------------------
// Build segment map (all segments)
// p: shadow/redzone segments
@@ -2577,16 +2595,4 @@ int main(int argc, char **argv, char **e
//--------------------------------------------------------------
- // Allow GDB attach
- // p: process_cmd_line_options() [for VG_(clo_wait_for_gdb)]
- //--------------------------------------------------------------
- /* Hook to delay things long enough so we can get the pid and
- attach GDB in another shell. */
- if (VG_(clo_wait_for_gdb)) {
- VG_(printf)("pid=%d\n", VG_(getpid)());
- /* do "jump *$eip" to skip this in gdb */
- VG_(do_syscall)(__NR_pause);
- }
-
- //--------------------------------------------------------------
// Search for file descriptors that are inherited from our parent
// p: process_cmd_line_options [for VG_(clo_track_fds)]
@@ -2641,11 +2647,4 @@ int main(int argc, char **argv, char **e
//--------------------------------------------------------------
- // Read debug info to find glibc entry points to intercept
- // p: parse_procselfmaps? [XXX for debug info?]
- // p: init_tt_tc? [XXX ???]
- //--------------------------------------------------------------
- VG_(setup_code_redirect_table)();
-
- //--------------------------------------------------------------
// Verbosity message
// p: end_rdtsc_calibration [so startup message is printed first]
--- valgrind/coregrind/vg_transtab.c #1.39:1.40
@@ -618,4 +618,8 @@ Addr VG_(search_transtab) ( Addr origina
{
TTEntry* tte;
+
+ if (vg_tt == NULL)
+ return 0;
+
VGP_PUSHCC(VgpSlowFindT);
tte = search_tt ( original_addr );
@@ -647,4 +651,8 @@ void VG_(invalidate_translations) ( Addr
Int i, j;
TCEntry* tce;
+
+ if (vg_tt == NULL)
+ return;
+
# ifdef DEBUG_TRANSTAB
VG_(sanity_check_tt_tc)();
@@ -670,5 +678,5 @@ void VG_(invalidate_translations) ( Addr
tce->orig_addr = VG_TTE_DELETED;
- if (unchain_blocks) {
+ if (VG_(clo_chain_bb) && unchain_blocks) {
/* make sure no other blocks chain to the one we just discarded */
for(j = 0; j < VG_TC_N_SECTORS; j++) {
|
|
From: Jeremy F. <je...@go...> - 2005-02-04 01:08:33
|
CVS commit by fitzhardinge:
Basic machinery to wrap functions. Not actually useful in this
checkin, since there's no way to activate it.
M +22 -0 core.h 1.79
M +39 -22 vg_from_ucode.c 1.91
M +199 -2 vg_redir.c 1.2
M +17 -0 x86/core_arch.h 1.21
M +41 -0 x86/dispatch.S 1.6
--- valgrind/coregrind/core.h #1.78:1.79
@@ -1103,4 +1103,26 @@ extern void VG_(resolve_seg_redirs)(SegI
extern Bool VG_(resolve_redir)(CodeRedirect *redir, const SegInfo *si);
+/* Wrapping machinery */
+enum return_type {
+ RT_RETURN,
+ RT_LONGJMP,
+ RT_EXIT,
+};
+
+typedef struct _FuncWrapper FuncWrapper;
+struct _FuncWrapper {
+ void *(*before)(ThreadState *tst);
+ void (*after) (void *nonce, enum return_type, Word retval);
+};
+
+extern void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper);
+extern const FuncWrapper *VG_(is_wrapped)(Addr eip);
+extern Bool VG_(is_wrapper_return)(Addr eip);
+
+/* Primary interface for adding wrappers for client-side functions. */
+extern void VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
+ const FuncWrapper *wrapper);
+
+
/* ---------------------------------------------------------------------
Exports of vg_main.c
--- valgrind/coregrind/vg_redir.c #1.1:1.2
@@ -54,5 +54,5 @@ struct _CodeRedirect {
};
-static Int addrcmp(const void *ap, const void *bp)
+static Int cmp_addrp(const void *ap, const void *bp)
{
Addr a = *(Addr *)ap;
@@ -78,5 +78,5 @@ static Char *straddr(void *p)
static SkipList sk_resolved_redir = SKIPLIST_INIT(CodeRedirect, from_addr,
- addrcmp, straddr, VG_AR_SYMTAB);
+ cmp_addrp, straddr, VG_AR_SYMTAB);
static CodeRedirect *unresolved_redir = NULL;
@@ -322,2 +322,199 @@ void VG_(setup_code_redirect_table) ( vo
}
+/*------------------------------------------------------------*/
+/*--- General function wrapping. ---*/
+/*------------------------------------------------------------*/
+
+/*
+ TODO:
+ - hook into the symtab machinery
+ - client-side wrappers?
+ - better interfaces for before() functions to get to arguments
+ - handle munmap of code (dlclose())
+ - handle thread exit
+ - handle longjmp
+ */
+struct callkey {
+ ThreadId tid; /* calling thread */
+ Addr esp; /* address of args on stack */
+ Addr eip; /* return address */
+};
+
+struct call_instance {
+ struct callkey key;
+
+ const FuncWrapper *wrapper;
+ void *nonce;
+};
+
+static inline Addr addrcmp(Addr a, Addr b)
+{
+ if (a < b)
+ return -1;
+ else if (a > b)
+ return 1;
+ else
+ return 0;
+}
+
+static inline Int cmp(UInt a, UInt b)
+{
+ if (a < b)
+ return -1;
+ else if (a > b)
+ return 1;
+ else
+ return 0;
+}
+
+static Int keycmp(const void *pa, const void *pb)
+{
+ const struct callkey *a = (const struct callkey *)pa;
+ const struct callkey *b = (const struct callkey *)pb;
+ Int ret;
+
+ if ((ret = cmp(a->tid, b->tid)))
+ return ret;
+
+ if ((ret = addrcmp(a->esp, b->esp)))
+ return ret;
+
+ return addrcmp(a->eip, b->eip);
+}
+
+/* List of wrapped call invocations which are currently active */
+static SkipList wrapped_frames = SKIPLIST_INIT(struct call_instance, key, keycmp,
+ NULL, VG_AR_SYMTAB);
+
+static struct call_instance *find_call(Addr retaddr, Addr argsp, ThreadId tid)
+{
+ struct callkey key = { tid, argsp, retaddr };
+
+ return VG_(SkipList_Find_Exact)(&wrapped_frames, &key);
+}
+
+static void wrapper_return(Addr retaddr);
+
+/* Called from generated code via helper */
+void VG_(wrap_before)(ThreadState *tst, const FuncWrapper *wrapper)
+{
+ Addr retaddr = ARCH_RETADDR(tst->arch);
+ Addr argp = (Addr)&ARCH_FUNC_ARG(tst->arch, 0);
+ void *nonce = NULL;
+
+ if (wrapper->before)
+ nonce = (*wrapper->before)(tst);
+
+ if (wrapper->after) {
+ /* If there's an after function, make sure it gets called */
+ struct call_instance *call;
+
+ call = find_call(retaddr, argp, tst->tid);
+
+ if (call != NULL) {
+ /* Found a stale outstanding call; clean it up and recycle
+ the structure */
+ if (call->wrapper->after)
+ (*call->wrapper->after)(call->nonce, RT_LONGJMP, 0);
+ } else {
+ call = VG_(SkipNode_Alloc)(&wrapped_frames);
+
+ call->key.tid = tst->tid;
+ call->key.esp = argp;
+ call->key.eip = retaddr;
+
+ VG_(SkipList_Insert)(&wrapped_frames, call);
+
+ wrapper_return(retaddr);
+ }
+
+ call->wrapper = wrapper;
+ call->nonce = nonce;
+ } else
+ vg_assert(nonce == NULL);
+}
+
+/* Called from generated code via helper */
+void VG_(wrap_after)(ThreadState *tst)
+{
+ Addr EIP = ARCH_INSTR_PTR(tst->arch); /* instruction after call */
+ Addr ESP = ARCH_STACK_PTR(tst->arch); /* pointer to args */
+ Word ret = ARCH_RETVAL(tst->arch); /* return value */
+
+ struct call_instance *call = find_call(EIP, ESP, tst->tid);
+
+ if (call != NULL) {
+ if (call->wrapper->after)
+ (*call->wrapper->after)(call->nonce, RT_RETURN, ret);
+
+ VG_(SkipList_Remove)(&wrapped_frames, &call->key);
+ VG_(SkipNode_Free)(&wrapped_frames, call);
+ }
+}
+
+
+struct wrapped_function {
+ Addr eip; /* eip of function entrypoint */
+ const FuncWrapper *wrapper;
+};
+
+struct wrapper_return {
+ Addr eip; /* return address */
+};
+
+/* A mapping from eip of wrapped function entrypoints to actual wrappers */
+static SkipList wrapped_functions = SKIPLIST_INIT(struct wrapped_function, eip, cmp_addrp,
+ NULL, VG_AR_SYMTAB);
+
+/* A set of EIPs which are return addresses for wrapped functions */
+static SkipList wrapper_returns = SKIPLIST_INIT(struct wrapper_return, eip, cmp_addrp,
+ NULL, VG_AR_SYMTAB);
+
+/* Wrap function starting at eip */
+void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper)
+{
+ struct wrapped_function *func;
+
+ func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
+
+ if (func == NULL) {
+ func = VG_(SkipNode_Alloc)(&wrapped_functions);
+ VG_(invalidate_translations)(eip, 1, True);
+
+ func->eip = eip;
+ VG_(SkipList_Insert)(&wrapped_functions, func);
+ }
+
+ func->wrapper = wrapper;
+}
+
+const FuncWrapper *VG_(is_wrapped)(Addr eip)
+{
+ struct wrapped_function *func = VG_(SkipList_Find_Exact)(&wrapped_functions, &eip);
+
+ if (func)
+ return func->wrapper;
+ return NULL;
+}
+
+Bool VG_(is_wrapper_return)(Addr eip)
+{
+ struct wrapper_return *ret = VG_(SkipList_Find_Exact)(&wrapper_returns, &eip);
+
+ return ret != NULL;
+}
+
+void wrapper_return(Addr eip)
+{
+ struct wrapper_return *ret;
+
+ if (VG_(is_wrapper_return)(eip))
+ return;
+
+ VG_(invalidate_translations)(eip, 1, True);
+
+ ret = VG_(SkipNode_Alloc)(&wrapper_returns);
+ ret->eip = eip;
+
+ VG_(SkipList_Insert)(&wrapper_returns, ret);
+}
--- valgrind/coregrind/vg_from_ucode.c #1.90:1.91
@@ -2274,9 +2274,10 @@ static void emit_call_patchme( void )
maybe_emit_put_eflags(); /* save flags before end of BB */
- VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
if (jumpidx >= VG_MAX_JUMPS) {
/* If there too many jumps in this basic block, fall back to
dispatch loop. */
+ VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
+
VG_(emitB) ( 0xC3 ); /* ret */
@@ -4420,9 +4421,23 @@ UChar* VG_(emit_code) ( UCodeBlock* cb,
Addr orig_eip, curr_eip;
Int tgt;
+ const FuncWrapper *wrapper;
reset_state();
+ /* Set up running state. */
+ sselive = False;
+ orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
+ curr_eip = cb->orig_eip;
+ vg_assert(curr_eip != 0); /* otherwise the incremental updating
+ algorithm gets messed up. */
+
if (dis) VG_(printf)("Generated x86 code:\n");
+ if (VG_(is_wrapper_return)(orig_eip)) {
+ /* If this the return address for a wrapped function, call
+ wrap_return_helper. This also deals with managing the
+ dispatch_ctr, so there's no need to do that too. */
+ emit_call_abs(False, (Addr)VG_(helper_wrapper_return), FlagsEmpty, FlagsEmpty);
+ } else {
/* Generate subl $1, dispatch_ctr(%ebp) and drop into dispatch if
we hit zero. We have to do this regardless of whether we're
@@ -4443,11 +4458,13 @@ UChar* VG_(emit_code) ( UCodeBlock* cb,
emit_ret();
VG_(target_forward)(&tgt);
+ }
+
+ wrapper = VG_(is_wrapped)(orig_eip);
+ if (wrapper != NULL) {
+ /* This is the start of a wrapped function */
+ VG_(emit_pushl_lit32)((UInt)wrapper);
+ emit_call_abs(False, (Addr)VG_(helper_wrapper_before), FlagsEmpty, FlagsEmpty);
+ }
- /* Set up running state. */
- sselive = False;
- orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
- curr_eip = cb->orig_eip;
- vg_assert(curr_eip != 0); /* otherwise the incremental updating
- algorithm gets messed up. */
/* for each uinstr ... */
for (i = 0; i < cb->used; i++) {
--- valgrind/coregrind/x86/dispatch.S #1.5:1.6
@@ -190,4 +190,45 @@
1: addl $4, %esp /* remove our call address */
ret /* return into main dispatch loop above */
+
+/* This is called from generated code when we're about to
+ start running a wrapped function. When called, the only live
+ registers are %eax and %ebp, so they're the only ones we preserve.
+
+ We are called with FuncWrapper * on the stack
+
+ This calls VG_(wrap_before)(ThreadState *tst, FuncWrapper *wrapper)
+*/
+.globl VG_(helper_wrapper_before)
+VG_(helper_wrapper_before):
+ pushl %eax /* save %eax */
+ pushl %ebp /* save %ebp */
+
+ pushl 12(%esp) /* pass FuncWrapper * */
+ pushl %ebp /* pass %ebp */
+ call VG_(wrap_before)
+ add $8, %esp /* remove args */
+
+ popl %ebp /* restore %ebp */
+ popl %eax /* restore %eax */
+ ret $4 /* remove argument */
+
+/* This is called from generated code when we're returning from a wrapped function.
+ Again, the only live registers are %eax and %ebp.
+ This is inserted instead of the normal dispatch_ctr management code, so we need
+ to duplicate that functionality too.
+*/
+.globl VG_(helper_wrapper_return)
+VG_(helper_wrapper_return):
+ subl $1, VGOFF_DISPATCH_CTR(%ebp)
+ jz 1f
+ pushl %eax
+ pushl %ebp
+ call VG_(wrap_after)
+ popl %ebp
+ popl %eax
+ ret
+1: /* counter zero */
+ add $4, %esp /* remove return addr */
+ ret /* return back into dispatch loop */
.data
--- valgrind/coregrind/x86/core_arch.h #1.20:1.21
@@ -44,4 +44,18 @@
#define ARCH_FRAME_PTR(regs) ((regs).m_ebp)
+/* Gets the return address of a function call. Assumes the VCPU is in
+ a state where a return would work (ie just before a return
+ instruction, or at the start of a called function before any local
+ frame has been set up). */
+#define ARCH_RETADDR(regs) (*(Addr *)((regs).m_esp))
+
+/* Gets argument N for a function. Makes the same assumption as ARCH_RETADDR.
+
+ XXX Assumes all args are simple words on the stack; it should
+ really be a stdargs-like stateful interface. */
+#define ARCH_FUNC_ARG(regs, N) ((((Word *)((regs).m_esp))[(N)+1]))
+
+#define ARCH_RETVAL(regs) ((regs).m_eax)
+
#define ARCH_CLREQ_ARGS(regs) ((regs).m_eax)
#define ARCH_PTHREQ_RET(regs) ((regs).m_edx)
@@ -85,4 +99,7 @@
------------------------------------------------------------------ */
+extern const Char VG_(helper_wrapper_before)[]; /* in dispatch.S */
+extern const Char VG_(helper_wrapper_return)[]; /* in dispatch.S */
+
extern const Char VG_(helper_undefined_instruction)[];
|
|
From: Jeremy F. <je...@go...> - 2005-02-04 00:26:59
|
CVS commit by fitzhardinge:
Split the redirection machinery out of vg_symtab2 into its own file,
in preparation for the wrapping machinery.
A vg_redir.c 1.1 [GPL (v2+)]
M +1 -0 Makefile.am 1.107
M +13 -0 core.h 1.78
M +18 -314 vg_symtab2.c 1.101
--- valgrind/coregrind/core.h #1.77:1.78
@@ -1075,4 +1075,5 @@ void VG_(parse_procselfmaps) (
typedef struct _Segment Segment;
+typedef struct _CodeRedirect CodeRedirect;
extern Bool VG_(is_object_file) ( const void *hdr );
@@ -1084,10 +1085,22 @@ extern void VG_(symtab_decref) ( SegIn
extern Bool VG_(get_fnname_nodemangle)( Addr a, Char* fnname, Int n_fnname );
+extern Addr VG_(reverse_search_one_symtab) ( const SegInfo* si, const Char* name );
+
/* Set up some default redirects */
extern void VG_(setup_code_redirect_table) ( void );
+extern Bool VG_(resolve_redir_allsegs)(CodeRedirect *redir);
+
+/* ---------------------------------------------------------------------
+ Exports of vg_redir.c
+ ------------------------------------------------------------------ */
/* Redirection machinery */
extern Addr VG_(code_redirect) ( Addr orig );
+extern void VG_(add_redirect_addr)(const Char *from_lib, const Char *from_sym,
+ Addr to_addr);
+extern void VG_(resolve_seg_redirs)(SegInfo *si);
+extern Bool VG_(resolve_redir)(CodeRedirect *redir, const SegInfo *si);
+
/* ---------------------------------------------------------------------
Exports of vg_main.c
--- valgrind/coregrind/vg_symtab2.c #1.100:1.101
@@ -35,4 +35,6 @@
#include <elf.h> /* ELF defns */
+static SegInfo* segInfo = NULL;
+
static Bool
intercept_demangle(const Char*, Char*, Int);
@@ -834,13 +836,9 @@ intercept_demangle(const Char* symbol, C
}
-// Forward declaration
-static void add_redirect_addr(const Char *from_lib, const Char *from_sym,
- Addr to_addr);
-
static
void handle_intercept( SegInfo* si, Char* symbol, Elf32_Sym* sym)
{
int len = VG_(strlen)(symbol) + 1 - VG_INTERCEPT_PREFIX_LEN;
- char *lib = VG_(malloc)(len);
+ char *lib = VG_(arena_malloc)(VG_AR_SYMTAB, len);
Char *func;
@@ -851,6 +849,17 @@ void handle_intercept( SegInfo* si, Char
*func = '\0';
- add_redirect_addr(lib, func+1, si->offset + sym->st_value);
- VG_(free)(lib);
+ VG_(add_redirect_addr)(lib, func+1, si->offset + sym->st_value);
+ VG_(arena_free)(VG_AR_SYMTAB, lib);
+}
+
+Bool VG_(resolve_redir_allsegs)(CodeRedirect *redir)
+{
+ SegInfo *si;
+
+ for(si = segInfo; si != NULL; si = si->next)
+ if (VG_(resolve_redir)(redir, si))
+ return True;
+
+ return False;
}
@@ -1537,8 +1546,4 @@ Bool vg_read_lib_symbols ( SegInfo* si )
disjoint address ranges.
*/
-static SegInfo* segInfo = NULL;
-
-static void resolve_seg_redirs(SegInfo *si);
-
SegInfo *VG_(read_seg_symbols) ( Segment *seg )
{
@@ -1596,5 +1601,5 @@ SegInfo *VG_(read_seg_symbols) ( Segment
/* do redirects */
- resolve_seg_redirs( si );
+ VG_(resolve_seg_redirs)( si );
}
VGP_POPCC(VgpReadSyms);
@@ -1695,6 +1700,5 @@ static Int search_one_symtab ( SegInfo*
scan of the table. Returns NULL if not found. */
-static Addr reverse_search_one_symtab ( const SegInfo* si,
- const Char* name )
+Addr VG_(reverse_search_one_symtab) ( const SegInfo* si, const Char* name )
{
UInt i;
@@ -2224,304 +2228,4 @@ void VG_(mini_stack_dump) ( Addr eips[],
/*------------------------------------------------------------*/
-/*--- General purpose redirection. ---*/
-/*------------------------------------------------------------*/
-
-/* Set to True for debug printing. */
-static const Bool verbose_redir = False;
-
-
-/* resolved redirections, indexed by from_addr */
-typedef struct _CodeRedirect {
- const Char *from_lib; /* library qualifier pattern */
- const Char *from_sym; /* symbol */
- Addr from_addr; /* old addr */
-
- const Char *to_lib; /* library qualifier pattern */
- const Char *to_sym; /* symbol */
- Addr to_addr; /* new addr */
-
- struct _CodeRedirect *next; /* next pointer on unresolved list */
-} CodeRedirect;
-
-static Int addrcmp(const void *ap, const void *bp)
-{
- Addr a = *(Addr *)ap;
- Addr b = *(Addr *)bp;
- Int ret;
-
- if (a == b)
- ret = 0;
- else
- ret = (a < b) ? -1 : 1;
-
- return ret;
-}
-
-static Char *straddr(void *p)
-{
- static Char buf[16];
-
- VG_(sprintf)(buf, "%p", *(Addr *)p);
-
- return buf;
-}
-
-static SkipList sk_resolved_redir = SKIPLIST_INIT(CodeRedirect, from_addr,
- addrcmp, straddr, VG_AR_SYMTAB);
-static CodeRedirect *unresolved_redir = NULL;
-
-static Bool match_lib(const Char *pattern, const SegInfo *si)
-{
- /* pattern == NULL matches everything, otherwise use globbing
-
- If the pattern starts with:
- file:, then match filename
- soname:, then match soname
- something else, match filename
- */
- const Char *name = si->filename;
-
- if (pattern == NULL)
- return True;
-
- if (VG_(strncmp)(pattern, "file:", 5) == 0) {
- pattern += 5;
- name = si->filename;
- }
- if (VG_(strncmp)(pattern, "soname:", 7) == 0) {
- pattern += 7;
- name = si->soname;
- }
-
- if (name == NULL)
- return False;
-
- return VG_(string_match)(pattern, name);
-}
-
-/* Resolve a redir using si if possible, and add it to the resolved
- list */
-static Bool resolve_redir(CodeRedirect *redir, const SegInfo *si)
-{
- Bool resolved;
-
- vg_assert(si != NULL);
- vg_assert(si->seg != NULL);
-
- /* no redirection from Valgrind segments */
- if (si->seg->flags & SF_VALGRIND)
- return False;
-
- resolved = (redir->from_addr != 0) && (redir->to_addr != 0);
-
- if (0 && verbose_redir)
- VG_(printf)(" consider FROM binding %s:%s -> %s:%s in %s(%s)\n",
- redir->from_lib, redir->from_sym,
- redir->to_lib, redir->to_sym,
- si->filename, si->soname);
-
- vg_assert(!resolved);
-
- if (redir->from_addr == 0) {
- vg_assert(redir->from_sym != NULL);
-
- if (match_lib(redir->from_lib, si)) {
- redir->from_addr = reverse_search_one_symtab(si, redir->from_sym);
- if (verbose_redir && redir->from_addr != 0)
- VG_(printf)(" bind FROM: %p = %s:%s\n",
- redir->from_addr,redir->from_lib, redir->from_sym );
- }
- }
-
- if (redir->to_addr == 0) {
- vg_assert(redir->to_sym != NULL);
-
- if (match_lib(redir->to_lib, si)) {
- redir->to_addr = reverse_search_one_symtab(si, redir->to_sym);
- if (verbose_redir && redir->to_addr != 0)
- VG_(printf)(" bind TO: %p = %s:%s\n",
- redir->to_addr,redir->to_lib, redir->to_sym );
-
- }
- }
-
- resolved = (redir->from_addr != 0) && (redir->to_addr != 0);
-
- if (0 && verbose_redir)
- VG_(printf)("resolve_redir: %s:%s from=%p %s:%s to=%p\n",
- redir->from_lib, redir->from_sym, redir->from_addr,
- redir->to_lib, redir->to_sym, redir->to_addr);
-
- if (resolved) {
- if (VG_(clo_verbosity) > 2 || verbose_redir) {
- VG_(message)(Vg_DebugMsg, " redir resolved (%s:%s=%p -> ",
- redir->from_lib, redir->from_sym, redir->from_addr);
- VG_(message)(Vg_DebugMsg, " %s:%s=%p)",
- redir->to_lib, redir->to_sym, redir->to_addr);
- }
-
- if (VG_(search_transtab)(redir->from_addr) != 0) {
- /* For some given (from, to) redir, the "from" function got
- called before the .so containing "to" became available. We
- know this because there is already a translation for the
- entry point of the original "from". So the redirect will
- never actually take effect unless that translation is
- discarded.
-
- Note, we only really need to discard the first bb of the
- old entry point, and so we avoid the problem of having to
- figure out how big that bb was -- since it is at least 1
- byte of original code, we can just pass 1 as the original
- size to invalidate_translations() and it will indeed get
- rid of the translation.
-
- Note, this is potentially expensive -- discarding
- translations causes complete unchaining.
- */
- if (VG_(clo_verbosity) > 2) {
- VG_(message)(Vg_UserMsg,
- "Discarding translation due to redirect of already called function" );
- VG_(message)(Vg_UserMsg,
- " %s (%p -> %p)",
- redir->from_sym, redir->from_addr, redir->to_addr );
- }
- VG_(invalidate_translations)(redir->from_addr, 1, True);
- }
-
- {
- CodeRedirect *r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &redir->from_addr);
-
- if (r == NULL)
- 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);
- }
- }
-
- return resolved;
-}
-
-/* Go through the complete redir list, resolving as much as possible with this SegInfo.
-
- This should be called when a new SegInfo symtab is loaded.
- */
-static void resolve_seg_redirs(SegInfo *si)
-{
- CodeRedirect **prevp = &unresolved_redir;
- CodeRedirect *redir, *next;
-
- if (verbose_redir)
- VG_(printf)("Considering redirs to/from %s(soname=%s)\n",
- si->filename, si->soname);
-
- /* visit each unresolved redir - if it becomes resolved, then
- remove it from the unresolved list */
- for(redir = unresolved_redir; redir != NULL; redir = next) {
- next = redir->next;
-
- if (resolve_redir(redir, si)) {
- *prevp = next;
- redir->next = NULL;
- } else
- prevp = &redir->next;
- }
-}
-
-static Bool resolve_redir_allsegs(CodeRedirect *redir)
-{
- SegInfo *si;
-
- for(si = segInfo; si != NULL; si = si->next)
- if (resolve_redir(redir, si))
- return True;
-
- return False;
-}
-
-/* Redirect a lib/symbol reference to a function at lib/symbol */
-static void add_redirect_sym(const Char *from_lib, const Char *from_sym,
- const Char *to_lib, const Char *to_sym)
-{
- CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
-
- redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
- redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
- redir->from_addr = 0;
-
- redir->to_lib = VG_(arena_strdup)(VG_AR_SYMTAB, to_lib);
- redir->to_sym = VG_(arena_strdup)(VG_AR_SYMTAB, to_sym);
- redir->to_addr = 0;
-
- if (VG_(clo_verbosity) >= 2)
- VG_(message)(Vg_UserMsg,
- "REDIRECT %s(%s) to %s(%s)",
- from_lib, from_sym, to_lib, to_sym);
-
- if (!resolve_redir_allsegs(redir)) {
- /* can't resolve immediately; add to list */
- redir->next = unresolved_redir;
- unresolved_redir = redir;
- }
-}
-
-/* Redirect a lib/symbol reference to a function at lib/symbol */
-static void add_redirect_addr(const Char *from_lib, const Char *from_sym,
- Addr to_addr)
-{
- CodeRedirect *redir = VG_(SkipNode_Alloc)(&sk_resolved_redir);
-
- redir->from_lib = VG_(arena_strdup)(VG_AR_SYMTAB, from_lib);
- redir->from_sym = VG_(arena_strdup)(VG_AR_SYMTAB, from_sym);
- redir->from_addr = 0;
-
- redir->to_lib = NULL;
- redir->to_sym = NULL;
- redir->to_addr = to_addr;
-
- if (!resolve_redir_allsegs(redir)) {
- /* can't resolve immediately; add to list */
- redir->next = unresolved_redir;
- unresolved_redir = redir;
- }
-}
-
-Addr VG_(code_redirect)(Addr a)
-{
- CodeRedirect *r = VG_(SkipList_Find_Exact)(&sk_resolved_redir, &a);
-
- if (r == NULL)
- return a;
-
- vg_assert(r->to_addr != 0);
-
- return r->to_addr;
-}
-
-void VG_(setup_code_redirect_table) ( void )
-{
- /* Redirect _dl_sysinfo_int80, which is glibc's default system call
- routine, to the routine in our trampoline page so that the
- special sysinfo unwind hack in vg_execontext.c will kick in.
- */
- add_redirect_addr("soname:ld-linux.so.2", "_dl_sysinfo_int80",
- VG_(client_trampoline_code)+VG_(tramp_syscall_offset));
-
- /* Overenthusiastic use of PLT bypassing by the glibc people also
- means we need to patch the following functions to our own
- implementations of said, in mac_replace_strmem.c.
- */
- add_redirect_sym("soname:libc.so.6", "stpcpy",
- "*vgpreload_memcheck.so*", "stpcpy");
- add_redirect_sym("soname:libc.so.6", "strnlen",
- "*vgpreload_memcheck.so*", "strnlen");
- add_redirect_sym("soname:ld-linux.so.2", "stpcpy",
- "*vgpreload_memcheck.so*", "stpcpy");
- add_redirect_sym("soname:ld-linux.so.2", "strchr",
- "*vgpreload_memcheck.so*", "strchr");
-}
-
-/*------------------------------------------------------------*/
/*--- SegInfo accessor functions ---*/
/*------------------------------------------------------------*/
--- valgrind/coregrind/Makefile.am #1.106:1.107
@@ -66,4 +66,5 @@
vg_signals.c \
vg_symtab2.c \
+ vg_redir.c \
vg_dwarf.c \
vg_stabs.c \
|
|
From: Jeremy F. <je...@go...> - 2005-02-04 00:26:54
|
On Thu, 2005-02-03 at 21:17 +0000, Chris January wrote: > I think the breakpoints patch I've posted to this list could be informative > here since it handles INT $3. The same principles could be extended to > handle other interrupts. Basically what the patch does is translate the trap > instruction into code to return from the innerloop with a particular TRC > value. This value is then caught in VG_(scheduler) which raises a real > signal (SIGTRAP in this case). Raising a real signal has the benefit it can > be seen by a debugger. Actually, that's what my patch does, only much more simply. It calls a helper which invokes a real int3 instruction; the generated SIGTRAP is then delivered to the thread using the normal signal machinery. J |
|
From: Jeremy F. <je...@go...> - 2005-02-04 00:26:02
|
CVS commit by fitzhardinge:
Fix relocation of absolute jumps (which the code doesn't do presently,
so there was no real bug).
M +6 -9 vg_from_ucode.c 1.90
--- valgrind/coregrind/vg_from_ucode.c #1.89:1.90
@@ -2220,6 +2220,8 @@ Addr VG_(get_jmp_dest)(Addr a)
UChar *cp = (UChar *)a;
- if (*cp++ != 0xE9) /* 0xE9 == jmp */
+ if (*cp != 0xE9 && /* 0xE9 == jmp */
+ *cp != 0xE8) /* 0xE8 == call */
return 0;
+ cp++;
delta = (*cp++) << 0;
@@ -2257,5 +2259,5 @@ void VG_(reloc_abs_jump)(UChar *instr)
vg_assert(*instr == 0xE8 || /* call */
- *instr == 0xEB); /* jmp */
+ *instr == 0xE9); /* jmp */
*absaddr = delta;
@@ -2276,14 +2278,9 @@ static void emit_call_patchme( void )
if (jumpidx >= VG_MAX_JUMPS) {
/* If there too many jumps in this basic block, fall back to
- dispatch loop. We still need to keep it the same size as the
- call sequence. */
+ dispatch loop. */
VG_(emitB) ( 0xC3 ); /* ret */
- VG_(emitB) ( 0x8d ); /* 4 byte nop (lea 0x0(%esi,1),%esi) */
- VG_(emitB) ( 0x74 );
- VG_(emitB) ( 0x26 );
- VG_(emitB) ( 0x00 );
if (dis)
- VG_(printf)("\n\t\tret; nop4\n");
+ VG_(printf)("\n\t\tret\n");
if (0 && VG_(clo_verbosity))
|