[PATCH] linux-user/loongarch64: Decode BRK break codes for FPE signals

WANG Rui posted 1 patch 3 weeks, 5 days ago
linux-user/loongarch64/cpu_loop.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
[PATCH] linux-user/loongarch64: Decode BRK break codes for FPE signals
Posted by WANG Rui 3 weeks, 5 days ago
Handle specific LoongArch BRK break codes in user-mode emulation
to deliver accurate floating-point exception signals. Specifically,
BRK_OVERFLOW (6) triggers TARGET_FPE_INTOVF, and BRK_DIVZERO (7)
triggers TARGET_FPE_INTDIV. Other BRK codes fall back to a generic
SIGTRAP.

This improves correctness for programs that rely on BRK to signal
overflow or divide-by-zero conditions.

Signed-off-by: WANG Rui <wangrui@loongson.cn>
---
 linux-user/loongarch64/cpu_loop.c | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c
index 0614d3de22..ec8a06c88c 100644
--- a/linux-user/loongarch64/cpu_loop.c
+++ b/linux-user/loongarch64/cpu_loop.c
@@ -11,6 +11,12 @@
 #include "user/cpu_loop.h"
 #include "signal-common.h"
 
+/* Break codes */
+enum {
+    BRK_OVERFLOW = 6,
+    BRK_DIVZERO = 7
+};
+
 void cpu_loop(CPULoongArchState *env)
 {
     CPUState *cs = env_cpu(env);
@@ -66,9 +72,26 @@ void cpu_loop(CPULoongArchState *env)
             force_sig_fault(TARGET_SIGFPE, si_code, env->pc);
             break;
         case EXCP_DEBUG:
-        case EXCCODE_BRK:
             force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
             break;
+        case EXCCODE_BRK:
+            {
+                unsigned int opcode;
+
+                get_user_u32(opcode, env->pc);
+
+                switch (opcode & 0x7fff) {
+                case BRK_OVERFLOW:
+                    force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->pc);
+                    break;
+                case BRK_DIVZERO:
+                    force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc);
+                    break;
+                default:
+                    force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
+                }
+            }
+            break;
         case EXCCODE_BCE:
             force_sig_fault(TARGET_SIGSYS, TARGET_SI_KERNEL, env->pc);
             break;
-- 
2.49.0
Re: [PATCH] linux-user/loongarch64: Decode BRK break codes for FPE signals
Posted by gaosong 2 weeks, 3 days ago
在 2025/4/14 下午3:49, WANG Rui 写道:
> Handle specific LoongArch BRK break codes in user-mode emulation
> to deliver accurate floating-point exception signals. Specifically,
> BRK_OVERFLOW (6) triggers TARGET_FPE_INTOVF, and BRK_DIVZERO (7)
> triggers TARGET_FPE_INTDIV. Other BRK codes fall back to a generic
> SIGTRAP.
>
> This improves correctness for programs that rely on BRK to signal
> overflow or divide-by-zero conditions.
>
> Signed-off-by: WANG Rui <wangrui@loongson.cn>
> ---
>   linux-user/loongarch64/cpu_loop.c | 25 ++++++++++++++++++++++++-
>   1 file changed, 24 insertions(+), 1 deletion(-)
Acked-by: Song Gao <gaosong@loongson.cn>

thanks.
Song Gao
> diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c
> index 0614d3de22..ec8a06c88c 100644
> --- a/linux-user/loongarch64/cpu_loop.c
> +++ b/linux-user/loongarch64/cpu_loop.c
> @@ -11,6 +11,12 @@
>   #include "user/cpu_loop.h"
>   #include "signal-common.h"
>   
> +/* Break codes */
> +enum {
> +    BRK_OVERFLOW = 6,
> +    BRK_DIVZERO = 7
> +};
> +
>   void cpu_loop(CPULoongArchState *env)
>   {
>       CPUState *cs = env_cpu(env);
> @@ -66,9 +72,26 @@ void cpu_loop(CPULoongArchState *env)
>               force_sig_fault(TARGET_SIGFPE, si_code, env->pc);
>               break;
>           case EXCP_DEBUG:
> -        case EXCCODE_BRK:
>               force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
>               break;
> +        case EXCCODE_BRK:
> +            {
> +                unsigned int opcode;
> +
> +                get_user_u32(opcode, env->pc);
> +
> +                switch (opcode & 0x7fff) {
> +                case BRK_OVERFLOW:
> +                    force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->pc);
> +                    break;
> +                case BRK_DIVZERO:
> +                    force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc);
> +                    break;
> +                default:
> +                    force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
> +                }
> +            }
> +            break;
>           case EXCCODE_BCE:
>               force_sig_fault(TARGET_SIGSYS, TARGET_SI_KERNEL, env->pc);
>               break;