|
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)
|