From: Jeremy Fitzhardinge Date: Tue, 16 Mar 2004 09:49:08 +0000 (+0000) Subject: This change does two things: one is the implementation of X-Git-Tag: svn/VALGRIND_2_1_2~181 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cae906da57fada6606ce2e711f8bccbc7d708b82;p=thirdparty%2Fvalgrind.git This change does two things: one is the implementation of VG_(synth_fault_*), which synthesize faults as if an instruction had caused a CPU fault. This is used in two places: one in vg_translate.c, when trying to fetch instructions from bad memory, and the other in vg_ldt.c, when using a bad segment register. This fixes a bug where an assertion would fail rather than getting a useful message. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2324 --- diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h index b77de0853a..3e807b8b01 100644 --- a/coregrind/vg_include.h +++ b/coregrind/vg_include.h @@ -1080,6 +1080,14 @@ extern vki_ksiginfo_t VG_(unresumable_siginfo); extern void VG_(kill_self)(Int sigNo); +/* These function synthesize a fault, as if the running instruction + had had a fault. These functions do not return - they longjmp back + into the scheduler so the signal can be delivered. */ +extern void VG_(synth_fault) (ThreadId tid); +extern void VG_(synth_fault_mapping)(ThreadId tid, Addr addr); +extern void VG_(synth_fault_perms) (ThreadId tid, Addr addr); + + /* --------------------------------------------------------------------- Exports of vg_mylibc.c ------------------------------------------------------------------ */ diff --git a/coregrind/vg_ldt.c b/coregrind/vg_ldt.c index a767395f47..24702efb83 100644 --- a/coregrind/vg_ldt.c +++ b/coregrind/vg_ldt.c @@ -181,7 +181,10 @@ Addr VG_(do_useseg) ( UInt seg_selector, Addr virtual_addr ) /* Sanity check the segment selector. Ensure that RPL=11b (least privilege). This forms the bottom 2 bits of the selector. */ - vg_assert((seg_selector & 3) == 3); + if ((seg_selector & 3) != 3) { + VG_(synth_fault)(VG_(get_current_tid)()); + return 0; + } /* Extract the table number */ table = (seg_selector & 4) >> 2; diff --git a/coregrind/vg_signals.c b/coregrind/vg_signals.c index c1645779a6..08a355feba 100644 --- a/coregrind/vg_signals.c +++ b/coregrind/vg_signals.c @@ -100,6 +100,7 @@ static void vg_sync_signalhandler ( Int sigNo, vki_ksiginfo_t *info, struct vki static void vg_async_signalhandler ( Int sigNo, vki_ksiginfo_t *info, struct vki_ucontext * ); static void vg_babyeater ( Int sigNo, vki_ksiginfo_t *info, struct vki_ucontext * ); static void proxy_sigvg_handler ( Int sigNo, vki_ksiginfo_t *info, struct vki_ucontext * ); +static void resume_scheduler(Int signo, vki_ksiginfo_t *info); static Bool is_correct_sigmask(void); static const Char *signame(Int sigNo); @@ -1817,6 +1818,52 @@ static void vg_default_action(const vki_ksiginfo_t *info, ThreadId tid) vg_assert(!terminate); } +/* Synthesize a fault where the address is OK, but the page + permissions are bad */ +void VG_(synth_fault_perms)(ThreadId tid, Addr addr) +{ + vki_ksiginfo_t info; + + vg_assert(VG_(threads)[tid].status == VgTs_Runnable); + + info.si_signo = VKI_SIGSEGV; + info.si_code = 2; + info._sifields._sigfault._addr = (void*)addr; + + resume_scheduler(VKI_SIGSEGV, &info); + VG_(deliver_signal)(tid, &info, False); +} + +/* Synthesize a fault where the address there's nothing mapped at the + address */ +void VG_(synth_fault_mapping)(ThreadId tid, Addr addr) +{ + vki_ksiginfo_t info; + + vg_assert(VG_(threads)[tid].status == VgTs_Runnable); + + info.si_signo = VKI_SIGSEGV; + info.si_code = 1; + info._sifields._sigfault._addr = (void*)addr; + + resume_scheduler(VKI_SIGSEGV, &info); + VG_(deliver_signal)(tid, &info, False); +} + +/* Synthesize a misc memory fault */ +void VG_(synth_fault)(ThreadId tid) +{ + vki_ksiginfo_t info; + + vg_assert(VG_(threads)[tid].status == VgTs_Runnable); + + info.si_signo = VKI_SIGSEGV; + info.si_code = 0x80; + info._sifields._sigfault._addr = (void*)0; + + resume_scheduler(VKI_SIGSEGV, &info); + VG_(deliver_signal)(tid, &info, False); +} void VG_(deliver_signal) ( ThreadId tid, const vki_ksiginfo_t *info, Bool async ) { @@ -1973,6 +2020,18 @@ void vg_async_signalhandler ( Int sigNo, vki_ksiginfo_t *info, struct vki_uconte VG_(proxy_handlesig)(info, &uc->uc_mcontext); } +static void resume_scheduler(Int sigNo, vki_ksiginfo_t *info) +{ + if (VG_(scheduler_jmpbuf_valid)) { + /* Can't continue; must longjmp back to the scheduler and thus + enter the sighandler immediately. */ + VG_(memcpy)(&VG_(unresumable_siginfo), info, sizeof(vki_ksiginfo_t)); + + VG_(longjmpd_on_signal) = sigNo; + __builtin_longjmp(VG_(scheduler_jmpbuf),1); + } +} + /* Recieve a sync signal from the host. @@ -2111,14 +2170,9 @@ void vg_sync_signalhandler ( Int sigNo, vki_ksiginfo_t *info, struct vki_ucontex } } - if (VG_(scheduler_jmpbuf_valid)) { - /* Can't continue; must longjmp back to the scheduler and thus - enter the sighandler immediately. */ - VG_(memcpy)(&VG_(unresumable_siginfo), info, sizeof(vki_ksiginfo_t)); - - VG_(longjmpd_on_signal) = sigNo; - __builtin_longjmp(VG_(scheduler_jmpbuf),1); - } + /* Can't continue; must longjmp back to the scheduler and thus + enter the sighandler immediately. */ + resume_scheduler(sigNo, info); if (info->si_code <= VKI_SI_USER) { /* diff --git a/coregrind/vg_translate.c b/coregrind/vg_translate.c index 738c5f70d5..6ed8bd2266 100644 --- a/coregrind/vg_translate.c +++ b/coregrind/vg_translate.c @@ -2399,21 +2399,15 @@ void VG_(translate) ( /*IN*/ ThreadId tid, if (seg == NULL || !VG_(seg_contains)(seg, orig_addr, 1) || (seg->prot & (VKI_PROT_READ|VKI_PROT_EXEC)) == 0) { - vki_ksiginfo_t info; - /* Code address is bad - deliver a signal instead */ vg_assert(!VG_(is_addressable)(orig_addr, 1)); - info.si_signo = VKI_SIGSEGV; - if (seg != NULL && VG_(seg_contains)(seg, orig_addr, 1)) { vg_assert((seg->prot & VKI_PROT_EXEC) == 0); - info.si_code = 2; /* invalid permissions for mapped object */ + VG_(synth_fault_perms)(tid, orig_addr); } else - info.si_code = 1; /* address not mapped to object */ - info._sifields._sigfault._addr = (void*)orig_addr; + VG_(synth_fault_mapping)(tid, orig_addr); - VG_(deliver_signal)(tid, &info, False); return; } else seg->flags |= SF_CODE; /* contains cached code */ diff --git a/none/tests/badseg.c b/none/tests/badseg.c new file mode 100644 index 0000000000..51b5ab8246 --- /dev/null +++ b/none/tests/badseg.c @@ -0,0 +1,27 @@ +#include +#include + +static void handler(int sig, siginfo_t *info, void *v) +{ + printf("info: sig=%d code=%d addr=%p\n", + info->si_signo, info->si_code, info->si_addr); + exit(0); +} + +int main() +{ + struct sigaction sa; + int val; + + sa.sa_sigaction = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + + sigaction(SIGSEGV, &sa, NULL); + + asm volatile("mov %1, %%fs; mov %%fs:0, %0" : "=r" (val) : "r"(4)); + + printf("val=%d\n", val); + + return 0; +} diff --git a/none/tests/badseg.stderr.exp b/none/tests/badseg.stderr.exp new file mode 100644 index 0000000000..139597f9cb --- /dev/null +++ b/none/tests/badseg.stderr.exp @@ -0,0 +1,2 @@ + + diff --git a/none/tests/badseg.stdout.exp b/none/tests/badseg.stdout.exp new file mode 100644 index 0000000000..40a293750f --- /dev/null +++ b/none/tests/badseg.stdout.exp @@ -0,0 +1 @@ +info: sig=11 code=128 addr=(nil) diff --git a/none/tests/badseg.vgtest b/none/tests/badseg.vgtest new file mode 100644 index 0000000000..e5622a3a64 --- /dev/null +++ b/none/tests/badseg.vgtest @@ -0,0 +1 @@ +prog: badseg