From 401ccafc8c941c19870fac8bd2eed12b1887c7fe Mon Sep 17 00:00:00 2001 From: Denis Drakhnya Date: Fri, 12 Mar 2021 00:21:06 +0200 Subject: [PATCH] e2k: Fix C++ exceptions for v5+. v5+ has different procedure stack layout. Reading the stack through the acees_hw_stacks syscall requires to shuffle registers for a backward compatibility with previous versions. Signed-off-by: Denis Drakhnya --- linux-user/syscall.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 043f72bbbd..d776b79e37 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7132,13 +7132,12 @@ exit: return ret; } -static abi_long copy_procedure_stack(abi_ulong dst, abi_ulong dst_tag, abi_ulong src, - abi_ulong size) +static abi_long copy_procedure_stack(CPUE2KState *env, abi_ulong dst, + abi_ulong dst_tag, abi_ulong src, abi_ulong size) { abi_ullong *from, *to; uint8_t *to_tag = NULL; abi_long ret = 0; - int i; from = lock_user(VERIFY_READ, src, size, 1); to = lock_user(VERIFY_WRITE, dst, size, 0); @@ -7158,8 +7157,26 @@ static abi_long copy_procedure_stack(abi_ulong dst, abi_ulong dst_tag, abi_ulong memset(to_tag, 0, size / 8); } - for (i = 0; i < size; i += sizeof(abi_ullong), to++, from++) { - *to = *from; + /* v5+ has different stack layout and we need to shuffle registers + * for backward compatibility. */ + if (env->version >= 5) { + int i, j; + bool to_ps = dst >= env->psp.base + && dst < (env->psp.base + env->psp.size); + + i = ((to_ps ? dst : src) - env->psp.base) / sizeof(abi_ullong); + + if (to_ps) { + for (j = 0; j < size / sizeof(abi_ullong); j++, i++) { + to[j + ((i & 3) == 1 ? 1 : ((i & 3) == 2 ? -1 : 0))] = from[j]; + } + } else { + for (j = 0; j < size / sizeof(abi_ullong); j++, i++) { + to[j] = from[j + ((i & 3) == 1 ? 1 : ((i & 3) == 2 ? -1 : 0))]; + } + } + } else { + memcpy(to, from, size); } exit: @@ -7286,7 +7303,7 @@ static abi_long do_e2k_access_hw_stacks(CPUState *cpu, abi_ulong arg2, dst_tag = env->psp.base_tag; src = buf_addr; } - ret = copy_procedure_stack(dst, dst_tag, src, used_size); + ret = copy_procedure_stack(env, dst, dst_tag, src, used_size); break; } case READ_PROCEDURE_STACK_EX: @@ -7311,7 +7328,7 @@ static abi_long do_e2k_access_hw_stacks(CPUState *cpu, abi_ulong arg2, dst_tag = env->psp.base_tag + offset / 8; src = buf_addr; } - ret = copy_procedure_stack(dst, dst_tag, src, buf_size); + ret = copy_procedure_stack(env, dst, dst_tag, src, buf_size); break; } default: