aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Wessel <jason.wessel@windriver.com>2010-01-26 16:29:50 -0600
committerAurelien Jarno <aurelien@aurel32.net>2010-02-28 19:20:02 +0100
commit63a54736f31f9e11da6fb52319bba26e7d24f571 (patch)
tree230a6acdea201b38b7b3373c34d4ac2acd8c3e5d
parent6049f4f831c6f409031dfa09282b38d0cbaecad8 (diff)
target-i386: fix crash on x86 32bit linux host with hw breakpoint exceptions
If you make use of hw breakpoints on a 32bit x86 linux host, qemu will segmentation fault when processing the exception. The problem is that the value of env is stored in $ebp in the op_helper raise_exception() function, and it can have the wrong value when calling it from non generated code. It is possible to work around the problem by restoring the value of env before calling raise_exception() using a new helper function that takes (CPUState *) as one of the arguments. Signed-off-by: Jason Wessel <jason.wessel@windriver.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
-rw-r--r--target-i386/exec.h1
-rw-r--r--target-i386/helper.c6
-rw-r--r--target-i386/op_helper.c5
3 files changed, 9 insertions, 3 deletions
diff --git a/target-i386/exec.h b/target-i386/exec.h
index 1fd74fd695..4ff3c573ca 100644
--- a/target-i386/exec.h
+++ b/target-i386/exec.h
@@ -73,6 +73,7 @@ void do_interrupt_user(int intno, int is_int, int error_code,
target_ulong next_eip);
void QEMU_NORETURN raise_exception_err(int exception_index, int error_code);
void QEMU_NORETURN raise_exception(int exception_index);
+void QEMU_NORETURN raise_exception_env(int exception_index, CPUState *nenv);
void do_smm_enter(void);
/* n must be a constant to be efficient */
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 080d2b8c7d..ce2b5eb346 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -1862,7 +1862,7 @@ int check_hw_breakpoints(CPUState *env, int force_dr6_update)
static CPUDebugExcpHandler *prev_debug_excp_handler;
-void raise_exception(int exception_index);
+void raise_exception_env(int exception_index, CPUState *env);
static void breakpoint_handler(CPUState *env)
{
@@ -1872,7 +1872,7 @@ static void breakpoint_handler(CPUState *env)
if (env->watchpoint_hit->flags & BP_CPU) {
env->watchpoint_hit = NULL;
if (check_hw_breakpoints(env, 0))
- raise_exception(EXCP01_DB);
+ raise_exception_env(EXCP01_DB, env);
else
cpu_resume_from_signal(env, NULL);
}
@@ -1881,7 +1881,7 @@ static void breakpoint_handler(CPUState *env)
if (bp->pc == env->eip) {
if (bp->flags & BP_CPU) {
check_hw_breakpoints(env, 1);
- raise_exception(EXCP01_DB);
+ raise_exception_env(EXCP01_DB, env);
}
break;
}
diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index 5eea3221b3..4bb434708c 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -1351,6 +1351,11 @@ void raise_exception(int exception_index)
raise_interrupt(exception_index, 0, 0, 0);
}
+void raise_exception_env(int exception_index, CPUState *nenv)
+{
+ env = nenv;
+ raise_exception(exception_index);
+}
/* SMM support */
#if defined(CONFIG_USER_ONLY)