]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
This change does two things: one is the implementation of
authorJeremy Fitzhardinge <jeremy@valgrind.org>
Tue, 16 Mar 2004 09:49:08 +0000 (09:49 +0000)
committerJeremy Fitzhardinge <jeremy@valgrind.org>
Tue, 16 Mar 2004 09:49:08 +0000 (09:49 +0000)
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

coregrind/vg_include.h
coregrind/vg_ldt.c
coregrind/vg_signals.c
coregrind/vg_translate.c
none/tests/badseg.c [new file with mode: 0644]
none/tests/badseg.stderr.exp [new file with mode: 0644]
none/tests/badseg.stdout.exp [new file with mode: 0644]
none/tests/badseg.vgtest [new file with mode: 0644]

index b77de0853aaf9939898d83a608204a95e6d59e4a..3e807b8b012951e88547ef0711260265885010bd 100644 (file)
@@ -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
    ------------------------------------------------------------------ */
index a767395f47574f52c2238e21ed8420dc603d1d80..24702efb83a8a25ccc850d978a6b9812e49b6ce9 100644 (file)
@@ -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;
index c1645779a670c6c8cfd32f4c55ec77956bba4bc9..08a355febaf9e341b49122aaf9cf0f03693c7fd6 100644 (file)
@@ -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) {
       /* 
index 738c5f70d540fb324d39b1722735a521c9d2f386..6ed8bd2266899f91d2d0c685a045ae9f79e10553 100644 (file)
@@ -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 (file)
index 0000000..51b5ab8
--- /dev/null
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <signal.h>
+
+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 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/badseg.stdout.exp b/none/tests/badseg.stdout.exp
new file mode 100644 (file)
index 0000000..40a2937
--- /dev/null
@@ -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 (file)
index 0000000..e5622a3
--- /dev/null
@@ -0,0 +1 @@
+prog: badseg