mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-27 04:13:53 -06:00

The gdbstub implementation for the Sparc architecture would
incorrectly calculate the the floating point register offset.
This resulted in, for example, registers f32 and f34 to point to
the same value.
The issue was caused by the confusion between even register numbers
and even register indexes. For example, the register index of f32 is 64
and f34 is 65.
Cc: qemu-stable@nongnu.org
Fixes: 30038fd818
("target-sparc: Change fpr representation to doubles.")
Signed-off-by: Mikael Szreder <git@miszr.win>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-ID: <20250214070343.11501-1-git@miszr.win>
217 lines
5.8 KiB
C
217 lines
5.8 KiB
C
/*
|
|
* SPARC gdb server stub
|
|
*
|
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "qemu/osdep.h"
|
|
#include "cpu.h"
|
|
#include "gdbstub/helpers.h"
|
|
|
|
#ifdef TARGET_ABI32
|
|
#define gdb_get_rega(buf, val) gdb_get_reg32(buf, val)
|
|
#else
|
|
#define gdb_get_rega(buf, val) gdb_get_regl(buf, val)
|
|
#endif
|
|
|
|
int sparc_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
|
{
|
|
CPUSPARCState *env = cpu_env(cs);
|
|
|
|
if (n < 8) {
|
|
/* g0..g7 */
|
|
return gdb_get_rega(mem_buf, env->gregs[n]);
|
|
}
|
|
if (n < 32) {
|
|
/* register window */
|
|
return gdb_get_rega(mem_buf, env->regwptr[n - 8]);
|
|
}
|
|
#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
|
|
if (n < 64) {
|
|
/* fprs */
|
|
if (n & 1) {
|
|
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower);
|
|
} else {
|
|
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper);
|
|
}
|
|
}
|
|
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
|
switch (n) {
|
|
case 64:
|
|
return gdb_get_rega(mem_buf, env->y);
|
|
case 65:
|
|
return gdb_get_rega(mem_buf, cpu_get_psr(env));
|
|
case 66:
|
|
return gdb_get_rega(mem_buf, env->wim);
|
|
case 67:
|
|
return gdb_get_rega(mem_buf, env->tbr);
|
|
case 68:
|
|
return gdb_get_rega(mem_buf, env->pc);
|
|
case 69:
|
|
return gdb_get_rega(mem_buf, env->npc);
|
|
case 70:
|
|
return gdb_get_rega(mem_buf, cpu_get_fsr(env));
|
|
case 71:
|
|
return gdb_get_rega(mem_buf, 0); /* csr */
|
|
default:
|
|
return gdb_get_rega(mem_buf, 0);
|
|
}
|
|
#else
|
|
if (n < 64) {
|
|
/* f0-f31 */
|
|
if (n & 1) {
|
|
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower);
|
|
} else {
|
|
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper);
|
|
}
|
|
}
|
|
if (n < 80) {
|
|
/* f32-f62 (16 double width registers, even register numbers only)
|
|
* n == 64: f32 : env->fpr[16]
|
|
* n == 65: f34 : env->fpr[17]
|
|
* etc...
|
|
* n == 79: f62 : env->fpr[31]
|
|
*/
|
|
return gdb_get_reg64(mem_buf, env->fpr[(n - 64) + 16].ll);
|
|
}
|
|
switch (n) {
|
|
case 80:
|
|
return gdb_get_regl(mem_buf, env->pc);
|
|
case 81:
|
|
return gdb_get_regl(mem_buf, env->npc);
|
|
case 82:
|
|
return gdb_get_regl(mem_buf, (cpu_get_ccr(env) << 32) |
|
|
((env->asi & 0xff) << 24) |
|
|
((env->pstate & 0xfff) << 8) |
|
|
cpu_get_cwp64(env));
|
|
case 83:
|
|
return gdb_get_regl(mem_buf, cpu_get_fsr(env));
|
|
case 84:
|
|
return gdb_get_regl(mem_buf, env->fprs);
|
|
case 85:
|
|
return gdb_get_regl(mem_buf, env->y);
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
int sparc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
|
{
|
|
SPARCCPU *cpu = SPARC_CPU(cs);
|
|
CPUSPARCState *env = &cpu->env;
|
|
#if defined(TARGET_ABI32)
|
|
uint32_t tmp;
|
|
|
|
tmp = ldl_p(mem_buf);
|
|
#else
|
|
target_ulong tmp;
|
|
|
|
tmp = ldtul_p(mem_buf);
|
|
#endif
|
|
|
|
if (n < 8) {
|
|
/* g0..g7 */
|
|
env->gregs[n] = tmp;
|
|
} else if (n < 32) {
|
|
/* register window */
|
|
env->regwptr[n - 8] = tmp;
|
|
}
|
|
#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
|
|
else if (n < 64) {
|
|
/* fprs */
|
|
/* f0-f31 */
|
|
if (n & 1) {
|
|
env->fpr[(n - 32) / 2].l.lower = tmp;
|
|
} else {
|
|
env->fpr[(n - 32) / 2].l.upper = tmp;
|
|
}
|
|
} else {
|
|
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
|
switch (n) {
|
|
case 64:
|
|
env->y = tmp;
|
|
break;
|
|
case 65:
|
|
cpu_put_psr(env, tmp);
|
|
break;
|
|
case 66:
|
|
env->wim = tmp;
|
|
break;
|
|
case 67:
|
|
env->tbr = tmp;
|
|
break;
|
|
case 68:
|
|
env->pc = tmp;
|
|
break;
|
|
case 69:
|
|
env->npc = tmp;
|
|
break;
|
|
case 70:
|
|
cpu_put_fsr(env, tmp);
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
return 4;
|
|
#else
|
|
else if (n < 64) {
|
|
/* f0-f31 */
|
|
tmp = ldl_p(mem_buf);
|
|
if (n & 1) {
|
|
env->fpr[(n - 32) / 2].l.lower = tmp;
|
|
} else {
|
|
env->fpr[(n - 32) / 2].l.upper = tmp;
|
|
}
|
|
return 4;
|
|
} else if (n < 80) {
|
|
/* f32-f62 (16 double width registers, even register numbers only)
|
|
* n == 64: f32 : env->fpr[16]
|
|
* n == 65: f34 : env->fpr[17]
|
|
* etc...
|
|
* n == 79: f62 : env->fpr[31]
|
|
*/
|
|
env->fpr[(n - 64) + 16].ll = tmp;
|
|
} else {
|
|
switch (n) {
|
|
case 80:
|
|
env->pc = tmp;
|
|
break;
|
|
case 81:
|
|
env->npc = tmp;
|
|
break;
|
|
case 82:
|
|
cpu_put_ccr(env, tmp >> 32);
|
|
env->asi = (tmp >> 24) & 0xff;
|
|
env->pstate = (tmp >> 8) & 0xfff;
|
|
cpu_put_cwp64(env, tmp & 0xff);
|
|
break;
|
|
case 83:
|
|
cpu_put_fsr(env, tmp);
|
|
break;
|
|
case 84:
|
|
env->fprs = tmp;
|
|
break;
|
|
case 85:
|
|
env->y = tmp;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
return 8;
|
|
#endif
|
|
}
|