QOM CPUState refactorings

* Fix cpu_memory_rw_debug() breakage in s390x KVM
 * Replace final CPUArchState in sysemu/kvm.h
 * Introduce model subclasses for XtensaCPU
 * Introduce CPUClass::gdb_num[_core]_regs
 * Introduce CPUClass::gdb_core_xml_file
 * Introduce CPUClass::gdb_{read,write}_register()
 * Propagate CPUState further in gdbstub
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.19 (GNU/Linux)
 
 iQIcBAABAgAGBQJR8vJsAAoJEPou0S0+fgE/ll4QALiUVXNcH8ymDs46JdXfMjyN
 4IqZS8VpgddD0WODLSjY/tE39JYY5K4Zl69Cs8kX/jZBeJk0w7XUZS3y6kvW4a0C
 lVEoxAYn2XE2I0pgJg+F95Z7rzDR/Y0laalkIbqYKjqmvS//KXBUif7Zw+oiqNAE
 sWtq+GqzG0vPiGN/rUGXuny//A/xWbHzZxqtpF4RgVg5eeRQh1acbpgoCwhZ/pJY
 31AGbIfSaXLKfLzXDrKhNbsruSaNxZ0Yc6BG9h/DQDOG9VY0zMIc1xC+IGlWvlAE
 v/AdaOhZP4GGWw4TN8tUR+Or+dD9KQbwkPtNs7bECutJUgRl3u4iE9lEEV8Rosho
 952r/qWPXyiphQ4VjKkG+tphtqj1npiDasKdoxhoQCIk05AXUFdr3XMMMm8+6cXb
 Ex1cKFoqQ+orc8pGn8jZmY7T1douZA0k38siHduEvb+dzMBdDcfbGw646g/deXZQ
 TDtB/pKTrZa7s/JqMXuuppHMmjLFQpRrL7Wmag3VhaVj/fL1oDX/DGIQ/xw8Zkdn
 2W9skac++LHSkcq+rkM1EgMT9AWzAGRrBK31Mz0f726NuKkzO52ZujCvQWQRfHPF
 gJEb1auxa3E6dYwK6ITsOw8j/bq+7gQKihhdQeXdu/EAfE1PZmPnaoqYgIOVuZo6
 j6bF5EgH+9I60+eLPmYT
 =Crvv
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'afaerber/tags/qom-cpu-for-anthony' into staging

QOM CPUState refactorings

* Fix cpu_memory_rw_debug() breakage in s390x KVM
* Replace final CPUArchState in sysemu/kvm.h
* Introduce model subclasses for XtensaCPU
* Introduce CPUClass::gdb_num[_core]_regs
* Introduce CPUClass::gdb_core_xml_file
* Introduce CPUClass::gdb_{read,write}_register()
* Propagate CPUState further in gdbstub

# gpg: Signature made Fri 26 Jul 2013 05:04:28 PM CDT using RSA key ID 3E7E013F
# gpg: Can't check signature: public key not found

# By Andreas Färber (23) and others
# Via Andreas Färber
* afaerber/tags/qom-cpu-for-anthony: (25 commits)
  cpu: Introduce CPUClass::gdb_core_xml_file for GDB_CORE_XML
  target-cris: Factor out CPUClass::gdb_read_register() hook for v10
  cpu: Introduce CPUClass::gdb_{read,write}_register()
  gdbstub: Replace GET_REG*() macros with gdb_get_reg*() functions
  target-xtensa: Move cpu_gdb_{read,write}_register()
  target-lm32: Move cpu_gdb_{read,write}_register()
  target-s390x: Move cpu_gdb_{read,write}_register()
  target-alpha: Move cpu_gdb_{read,write}_register()
  target-cris: Move cpu_gdb_{read,write}_register()
  target-microblaze: Move cpu_gdb_{read,write}_register()
  target-sh4: Move cpu_gdb_{read,write}_register()
  target-openrisc: Move cpu_gdb_{read,write}_register()
  target-mips: Move cpu_gdb_{read,write}_register()
  target-m68k: Move cpu_gdb_{read,write}_register()
  target-arm: Move cpu_gdb_{read,write}_register()
  target-sparc: Move cpu_gdb_{read,write}_register()
  target-ppc: Move cpu_gdb_{read,write}_register()
  target-i386: Move cpu_gdb_{read,write}_register()
  cpu: Introduce CPUState::gdb_num_regs and CPUClass::gdb_num_core_regs
  gdbstub: Drop dead code in cpu_gdb_{read,write}_register()
  ...
This commit is contained in:
Anthony Liguori 2013-07-26 17:53:19 -05:00
commit 200a06397f
70 changed files with 1993 additions and 1392 deletions

5
exec.c
View File

@ -590,15 +590,14 @@ void cpu_breakpoint_remove_all(CPUArchState *env, int mask)
void cpu_single_step(CPUState *cpu, int enabled) void cpu_single_step(CPUState *cpu, int enabled)
{ {
#if defined(TARGET_HAS_ICE) #if defined(TARGET_HAS_ICE)
CPUArchState *env = cpu->env_ptr;
if (cpu->singlestep_enabled != enabled) { if (cpu->singlestep_enabled != enabled) {
cpu->singlestep_enabled = enabled; cpu->singlestep_enabled = enabled;
if (kvm_enabled()) { if (kvm_enabled()) {
kvm_update_guest_debug(env, 0); kvm_update_guest_debug(cpu, 0);
} else { } else {
/* must flush all the translated code to avoid inconsistencies */ /* must flush all the translated code to avoid inconsistencies */
/* XXX: only flush what is necessary */ /* XXX: only flush what is necessary */
CPUArchState *env = cpu->env_ptr;
tb_flush(env); tb_flush(env);
} }
} }

1382
gdbstub.c

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,43 @@ static inline int cpu_index(CPUState *cpu)
#endif #endif
} }
/* The GDB remote protocol transfers values in target byte order. This means
* we can use the raw memory access routines to access the value buffer.
* Conveniently, these also handle the case where the buffer is mis-aligned.
*/
static inline int gdb_get_reg8(uint8_t *mem_buf, uint8_t val)
{
stb_p(mem_buf, val);
return 1;
}
static inline int gdb_get_reg16(uint8_t *mem_buf, uint16_t val)
{
stw_p(mem_buf, val);
return 2;
}
static inline int gdb_get_reg32(uint8_t *mem_buf, uint32_t val)
{
stl_p(mem_buf, val);
return 4;
}
static inline int gdb_get_reg64(uint8_t *mem_buf, uint64_t val)
{
stq_p(mem_buf, val);
return 8;
}
#if TARGET_LONG_BITS == 64
#define gdb_get_regl(buf, val) gdb_get_reg64(buf, val)
#define ldtul_p(addr) ldq_p(addr)
#else
#define gdb_get_regl(buf, val) gdb_get_reg32(buf, val)
#define ldtul_p(addr) ldl_p(addr)
#endif
#endif #endif
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
@ -47,6 +84,14 @@ int gdbserver_start(int);
int gdbserver_start(const char *port); int gdbserver_start(const char *port);
#endif #endif
/**
* gdb_has_xml:
* This is an ugly hack to cope with both new and old gdb.
* If gdb sends qXfer:features:read then assume we're talking to a newish
* gdb that understands target descriptions.
*/
extern bool gdb_has_xml;
/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */ /* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
extern const char *const xml_builtin[][2]; extern const char *const xml_builtin[][2];

View File

@ -80,7 +80,11 @@ struct TranslationBlock;
* @synchronize_from_tb: Callback for synchronizing state from a TCG * @synchronize_from_tb: Callback for synchronizing state from a TCG
* #TranslationBlock. * #TranslationBlock.
* @get_phys_page_debug: Callback for obtaining a physical address. * @get_phys_page_debug: Callback for obtaining a physical address.
* @gdb_read_register: Callback for letting GDB read a register.
* @gdb_write_register: Callback for letting GDB write a register.
* @vmsd: State description for migration. * @vmsd: State description for migration.
* @gdb_num_core_regs: Number of core registers accessible to GDB.
* @gdb_core_xml_file: File name for core registers GDB XML description.
* *
* Represents a CPU family or model. * Represents a CPU family or model.
*/ */
@ -108,8 +112,9 @@ typedef struct CPUClass {
void (*set_pc)(CPUState *cpu, vaddr value); void (*set_pc)(CPUState *cpu, vaddr value);
void (*synchronize_from_tb)(CPUState *cpu, struct TranslationBlock *tb); void (*synchronize_from_tb)(CPUState *cpu, struct TranslationBlock *tb);
hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr); hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr);
int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg);
int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
const struct VMStateDescription *vmsd;
int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu, int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu,
int cpuid, void *opaque); int cpuid, void *opaque);
int (*write_elf64_qemunote)(WriteCoreDumpFunction f, CPUState *cpu, int (*write_elf64_qemunote)(WriteCoreDumpFunction f, CPUState *cpu,
@ -118,6 +123,10 @@ typedef struct CPUClass {
int cpuid, void *opaque); int cpuid, void *opaque);
int (*write_elf32_qemunote)(WriteCoreDumpFunction f, CPUState *cpu, int (*write_elf32_qemunote)(WriteCoreDumpFunction f, CPUState *cpu,
void *opaque); void *opaque);
const struct VMStateDescription *vmsd;
int gdb_num_core_regs;
const char *gdb_core_xml_file;
} CPUClass; } CPUClass;
struct KVMState; struct KVMState;
@ -142,6 +151,7 @@ struct kvm_run;
* @env_ptr: Pointer to subclass-specific CPUArchState field. * @env_ptr: Pointer to subclass-specific CPUArchState field.
* @current_tb: Currently executing TB. * @current_tb: Currently executing TB.
* @gdb_regs: Additional GDB registers. * @gdb_regs: Additional GDB registers.
* @gdb_num_regs: Number of total registers accessible to GDB.
* @next_cpu: Next CPU sharing TB cache. * @next_cpu: Next CPU sharing TB cache.
* @kvm_fd: vCPU file descriptor for KVM. * @kvm_fd: vCPU file descriptor for KVM.
* *
@ -177,6 +187,7 @@ struct CPUState {
void *env_ptr; /* CPUArchState */ void *env_ptr; /* CPUArchState */
struct TranslationBlock *current_tb; struct TranslationBlock *current_tb;
struct GDBRegisterState *gdb_regs; struct GDBRegisterState *gdb_regs;
int gdb_num_regs;
CPUState *next_cpu; CPUState *next_cpu;
int kvm_fd; int kvm_fd;

View File

@ -174,7 +174,7 @@ int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr, int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr,
target_ulong len, int type); target_ulong len, int type);
void kvm_remove_all_breakpoints(CPUState *cpu); void kvm_remove_all_breakpoints(CPUState *cpu);
int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap); int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap);
#ifndef _WIN32 #ifndef _WIN32
int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset); int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset);
#endif #endif

View File

@ -1883,9 +1883,8 @@ static void kvm_invoke_set_guest_debug(void *data)
&dbg_data->dbg); &dbg_data->dbg);
} }
int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
{ {
CPUState *cpu = ENV_GET_CPU(env);
struct kvm_set_guest_debug_data data; struct kvm_set_guest_debug_data data;
data.dbg.control = reinject_trap; data.dbg.control = reinject_trap;
@ -1935,9 +1934,7 @@ int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
} }
for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
CPUArchState *env = cpu->env_ptr; err = kvm_update_guest_debug(cpu, 0);
err = kvm_update_guest_debug(env, 0);
if (err) { if (err) {
return err; return err;
} }
@ -1977,9 +1974,7 @@ int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr,
} }
for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
CPUArchState *env = cpu->env_ptr; err = kvm_update_guest_debug(cpu, 0);
err = kvm_update_guest_debug(env, 0);
if (err) { if (err) {
return err; return err;
} }
@ -2007,15 +2002,13 @@ void kvm_remove_all_breakpoints(CPUState *cpu)
kvm_arch_remove_all_hw_breakpoints(); kvm_arch_remove_all_hw_breakpoints();
for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
CPUArchState *env = cpu->env_ptr; kvm_update_guest_debug(cpu, 0);
kvm_update_guest_debug(env, 0);
} }
} }
#else /* !KVM_CAP_SET_GUEST_DEBUG */ #else /* !KVM_CAP_SET_GUEST_DEBUG */
int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
{ {
return -EINVAL; return -EINVAL;
} }

View File

@ -78,7 +78,7 @@ void kvm_setup_guest_memory(void *start, size_t size)
{ {
} }
int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
{ {
return -ENOSYS; return -ENOSYS;
} }

View File

@ -3637,7 +3637,7 @@ int main(int argc, char **argv, char **envp)
exit(1); exit(1);
} }
cpu = ENV_GET_CPU(env); cpu = ENV_GET_CPU(env);
cpu_reset(ENV_GET_CPU(env)); cpu_reset(cpu);
thread_cpu = cpu; thread_cpu = cpu;

View File

@ -157,6 +157,17 @@ static int cpu_common_write_elf64_note(WriteCoreDumpFunction f,
} }
static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg)
{
return 0;
}
static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg)
{
return 0;
}
void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags) int flags)
{ {
@ -226,6 +237,14 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp)
} }
} }
static void cpu_common_initfn(Object *obj)
{
CPUState *cpu = CPU(obj);
CPUClass *cc = CPU_GET_CLASS(obj);
cpu->gdb_num_regs = cc->gdb_num_core_regs;
}
static int64_t cpu_common_get_arch_id(CPUState *cpu) static int64_t cpu_common_get_arch_id(CPUState *cpu)
{ {
return cpu->cpu_index; return cpu->cpu_index;
@ -245,6 +264,8 @@ static void cpu_class_init(ObjectClass *klass, void *data)
k->write_elf32_note = cpu_common_write_elf32_note; k->write_elf32_note = cpu_common_write_elf32_note;
k->write_elf64_qemunote = cpu_common_write_elf64_qemunote; k->write_elf64_qemunote = cpu_common_write_elf64_qemunote;
k->write_elf64_note = cpu_common_write_elf64_note; k->write_elf64_note = cpu_common_write_elf64_note;
k->gdb_read_register = cpu_common_gdb_read_register;
k->gdb_write_register = cpu_common_gdb_write_register;
dc->realize = cpu_common_realizefn; dc->realize = cpu_common_realizefn;
dc->no_user = 1; dc->no_user = 1;
} }
@ -253,6 +274,7 @@ static const TypeInfo cpu_type_info = {
.name = TYPE_CPU, .name = TYPE_CPU,
.parent = TYPE_DEVICE, .parent = TYPE_DEVICE,
.instance_size = sizeof(CPUState), .instance_size = sizeof(CPUState),
.instance_init = cpu_common_initfn,
.abstract = true, .abstract = true,
.class_size = sizeof(CPUClass), .class_size = sizeof(CPUClass),
.class_init = cpu_class_init, .class_init = cpu_class_init,

View File

@ -7,6 +7,7 @@ stub-obj-y += fdset-add-fd.o
stub-obj-y += fdset-find-fd.o stub-obj-y += fdset-find-fd.o
stub-obj-y += fdset-get-fd.o stub-obj-y += fdset-get-fd.o
stub-obj-y += fdset-remove-fd.o stub-obj-y += fdset-remove-fd.o
stub-obj-y += gdbstub.o
stub-obj-y += get-fd.o stub-obj-y += get-fd.o
stub-obj-y += get-vm-name.o stub-obj-y += get-vm-name.o
stub-obj-y += iothread-lock.o stub-obj-y += iothread-lock.o

5
stubs/gdbstub.c Normal file
View File

@ -0,0 +1,5 @@
#include "qemu-common.h"
const char *const xml_builtin[][2] = {
{ NULL, NULL }
};

View File

@ -1,3 +1,4 @@
obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_SOFTMMU) += machine.o
obj-y += translate.o helper.o cpu.o obj-y += translate.o helper.o cpu.o
obj-y += int_helper.o fpu_helper.o sys_helper.o mem_helper.o obj-y += int_helper.o fpu_helper.o sys_helper.o mem_helper.o
obj-y += gdbstub.o

View File

@ -82,5 +82,7 @@ void alpha_cpu_do_interrupt(CPUState *cpu);
void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
int flags); int flags);
hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int alpha_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif #endif

View File

@ -271,11 +271,14 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = alpha_cpu_do_interrupt; cc->do_interrupt = alpha_cpu_do_interrupt;
cc->dump_state = alpha_cpu_dump_state; cc->dump_state = alpha_cpu_dump_state;
cc->set_pc = alpha_cpu_set_pc; cc->set_pc = alpha_cpu_set_pc;
cc->gdb_read_register = alpha_cpu_gdb_read_register;
cc->gdb_write_register = alpha_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->do_unassigned_access = alpha_cpu_unassigned_access; cc->do_unassigned_access = alpha_cpu_unassigned_access;
cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug; cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug;
dc->vmsd = &vmstate_alpha_cpu; dc->vmsd = &vmstate_alpha_cpu;
#endif #endif
cc->gdb_num_core_regs = 67;
} }
static const TypeInfo alpha_cpu_type_info = { static const TypeInfo alpha_cpu_type_info = {

93
target-alpha/gdbstub.c Normal file
View File

@ -0,0 +1,93 @@
/*
* Alpha 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 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 "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.h"
int alpha_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
AlphaCPU *cpu = ALPHA_CPU(cs);
CPUAlphaState *env = &cpu->env;
uint64_t val;
CPU_DoubleU d;
switch (n) {
case 0 ... 30:
val = env->ir[n];
break;
case 32 ... 62:
d.d = env->fir[n - 32];
val = d.ll;
break;
case 63:
val = cpu_alpha_load_fpcr(env);
break;
case 64:
val = env->pc;
break;
case 66:
val = env->unique;
break;
case 31:
case 65:
/* 31 really is the zero register; 65 is unassigned in the
gdb protocol, but is still required to occupy 8 bytes. */
val = 0;
break;
default:
return 0;
}
return gdb_get_regl(mem_buf, val);
}
int alpha_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
AlphaCPU *cpu = ALPHA_CPU(cs);
CPUAlphaState *env = &cpu->env;
target_ulong tmp = ldtul_p(mem_buf);
CPU_DoubleU d;
switch (n) {
case 0 ... 30:
env->ir[n] = tmp;
break;
case 32 ... 62:
d.ll = tmp;
env->fir[n - 32] = d.d;
break;
case 63:
cpu_alpha_store_fpcr(env, tmp);
break;
case 64:
env->pc = tmp;
break;
case 66:
env->unique = tmp;
break;
case 31:
case 65:
/* 31 really is the zero register; 65 is unassigned in the
gdb protocol, but is still required to occupy 8 bytes. */
break;
default:
return 0;
}
return 8;
}

View File

@ -4,3 +4,4 @@ obj-$(CONFIG_KVM) += kvm.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o obj-$(CONFIG_NO_KVM) += kvm-stub.o
obj-y += translate.o op_helper.o helper.o cpu.o obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += neon_helper.o iwmmxt_helper.o obj-y += neon_helper.o iwmmxt_helper.o
obj-y += gdbstub.o

View File

@ -149,4 +149,7 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
hwaddr arm_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr arm_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif #endif

View File

@ -824,10 +824,14 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = arm_cpu_do_interrupt; cc->do_interrupt = arm_cpu_do_interrupt;
cc->dump_state = arm_cpu_dump_state; cc->dump_state = arm_cpu_dump_state;
cc->set_pc = arm_cpu_set_pc; cc->set_pc = arm_cpu_set_pc;
cc->gdb_read_register = arm_cpu_gdb_read_register;
cc->gdb_write_register = arm_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = arm_cpu_get_phys_page_debug; cc->get_phys_page_debug = arm_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_arm_cpu; cc->vmsd = &vmstate_arm_cpu;
#endif #endif
cc->gdb_num_core_regs = 26;
cc->gdb_core_xml_file = "arm-core.xml";
} }
static void cpu_register(const ARMCPUInfo *info) static void cpu_register(const ARMCPUInfo *info)

102
target-arm/gdbstub.c Normal file
View File

@ -0,0 +1,102 @@
/*
* ARM 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 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 "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.h"
/* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect
whatever the target description contains. Due to a historical mishap
the FPA registers appear in between core integer regs and the CPSR.
We hack round this by giving the FPA regs zero size when talking to a
newer gdb. */
int arm_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
if (n < 16) {
/* Core integer register. */
return gdb_get_reg32(mem_buf, env->regs[n]);
}
if (n < 24) {
/* FPA registers. */
if (gdb_has_xml) {
return 0;
}
memset(mem_buf, 0, 12);
return 12;
}
switch (n) {
case 24:
/* FPA status register. */
if (gdb_has_xml) {
return 0;
}
return gdb_get_reg32(mem_buf, 0);
case 25:
/* CPSR */
return gdb_get_reg32(mem_buf, cpsr_read(env));
}
/* Unknown register. */
return 0;
}
int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
uint32_t tmp;
tmp = ldl_p(mem_buf);
/* Mask out low bit of PC to workaround gdb bugs. This will probably
cause problems if we ever implement the Jazelle DBX extensions. */
if (n == 15) {
tmp &= ~1;
}
if (n < 16) {
/* Core integer register. */
env->regs[n] = tmp;
return 4;
}
if (n < 24) { /* 16-23 */
/* FPA registers (ignored). */
if (gdb_has_xml) {
return 0;
}
return 12;
}
switch (n) {
case 24:
/* FPA status register (ignored). */
if (gdb_has_xml) {
return 0;
}
return 4;
case 25:
/* CPSR */
cpsr_write(env, tmp, 0xffffffff);
return 4;
}
/* Unknown register. */
return 0;
}

View File

@ -1,2 +1,3 @@
obj-y += translate.o op_helper.o helper.o cpu.o obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += mmu.o machine.o obj-$(CONFIG_SOFTMMU) += mmu.o machine.o

View File

@ -81,4 +81,8 @@ void cris_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
hwaddr cris_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr cris_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int crisv10_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int cris_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int cris_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif #endif

View File

@ -175,6 +175,7 @@ static void crisv8_cpu_class_init(ObjectClass *oc, void *data)
ccc->vr = 8; ccc->vr = 8;
cc->do_interrupt = crisv10_cpu_do_interrupt; cc->do_interrupt = crisv10_cpu_do_interrupt;
cc->gdb_read_register = crisv10_cpu_gdb_read_register;
} }
static void crisv9_cpu_class_init(ObjectClass *oc, void *data) static void crisv9_cpu_class_init(ObjectClass *oc, void *data)
@ -184,6 +185,7 @@ static void crisv9_cpu_class_init(ObjectClass *oc, void *data)
ccc->vr = 9; ccc->vr = 9;
cc->do_interrupt = crisv10_cpu_do_interrupt; cc->do_interrupt = crisv10_cpu_do_interrupt;
cc->gdb_read_register = crisv10_cpu_gdb_read_register;
} }
static void crisv10_cpu_class_init(ObjectClass *oc, void *data) static void crisv10_cpu_class_init(ObjectClass *oc, void *data)
@ -193,6 +195,7 @@ static void crisv10_cpu_class_init(ObjectClass *oc, void *data)
ccc->vr = 10; ccc->vr = 10;
cc->do_interrupt = crisv10_cpu_do_interrupt; cc->do_interrupt = crisv10_cpu_do_interrupt;
cc->gdb_read_register = crisv10_cpu_gdb_read_register;
} }
static void crisv11_cpu_class_init(ObjectClass *oc, void *data) static void crisv11_cpu_class_init(ObjectClass *oc, void *data)
@ -202,6 +205,7 @@ static void crisv11_cpu_class_init(ObjectClass *oc, void *data)
ccc->vr = 11; ccc->vr = 11;
cc->do_interrupt = crisv10_cpu_do_interrupt; cc->do_interrupt = crisv10_cpu_do_interrupt;
cc->gdb_read_register = crisv10_cpu_gdb_read_register;
} }
static void crisv32_cpu_class_init(ObjectClass *oc, void *data) static void crisv32_cpu_class_init(ObjectClass *oc, void *data)
@ -255,9 +259,13 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = cris_cpu_do_interrupt; cc->do_interrupt = cris_cpu_do_interrupt;
cc->dump_state = cris_cpu_dump_state; cc->dump_state = cris_cpu_dump_state;
cc->set_pc = cris_cpu_set_pc; cc->set_pc = cris_cpu_set_pc;
cc->gdb_read_register = cris_cpu_gdb_read_register;
cc->gdb_write_register = cris_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = cris_cpu_get_phys_page_debug; cc->get_phys_page_debug = cris_cpu_get_phys_page_debug;
#endif #endif
cc->gdb_num_core_regs = 49;
} }
static const TypeInfo cris_cpu_type_info = { static const TypeInfo cris_cpu_type_info = {

130
target-cris/gdbstub.c Normal file
View File

@ -0,0 +1,130 @@
/*
* CRIS 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 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 "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.h"
int crisv10_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
CRISCPU *cpu = CRIS_CPU(cs);
CPUCRISState *env = &cpu->env;
if (n < 15) {
return gdb_get_reg32(mem_buf, env->regs[n]);
}
if (n == 15) {
return gdb_get_reg32(mem_buf, env->pc);
}
if (n < 32) {
switch (n) {
case 16:
return gdb_get_reg8(mem_buf, env->pregs[n - 16]);
case 17:
return gdb_get_reg8(mem_buf, env->pregs[n - 16]);
case 20:
case 21:
return gdb_get_reg16(mem_buf, env->pregs[n - 16]);
default:
if (n >= 23) {
return gdb_get_reg32(mem_buf, env->pregs[n - 16]);
}
break;
}
}
return 0;
}
int cris_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
CRISCPU *cpu = CRIS_CPU(cs);
CPUCRISState *env = &cpu->env;
uint8_t srs;
srs = env->pregs[PR_SRS];
if (n < 16) {
return gdb_get_reg32(mem_buf, env->regs[n]);
}
if (n >= 21 && n < 32) {
return gdb_get_reg32(mem_buf, env->pregs[n - 16]);
}
if (n >= 33 && n < 49) {
return gdb_get_reg32(mem_buf, env->sregs[srs][n - 33]);
}
switch (n) {
case 16:
return gdb_get_reg8(mem_buf, env->pregs[0]);
case 17:
return gdb_get_reg8(mem_buf, env->pregs[1]);
case 18:
return gdb_get_reg32(mem_buf, env->pregs[2]);
case 19:
return gdb_get_reg8(mem_buf, srs);
case 20:
return gdb_get_reg16(mem_buf, env->pregs[4]);
case 32:
return gdb_get_reg32(mem_buf, env->pc);
}
return 0;
}
int cris_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
CRISCPU *cpu = CRIS_CPU(cs);
CPUCRISState *env = &cpu->env;
uint32_t tmp;
if (n > 49) {
return 0;
}
tmp = ldl_p(mem_buf);
if (n < 16) {
env->regs[n] = tmp;
}
if (n >= 21 && n < 32) {
env->pregs[n - 16] = tmp;
}
/* FIXME: Should support function regs be writable? */
switch (n) {
case 16:
return 1;
case 17:
return 1;
case 18:
env->pregs[PR_PID] = tmp;
break;
case 19:
return 1;
case 20:
return 2;
case 32:
env->pc = tmp;
break;
}
return 4;
}

View File

@ -1,6 +1,7 @@
obj-y += translate.o helper.o cpu.o obj-y += translate.o helper.o cpu.o
obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o
obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o
obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o
obj-$(CONFIG_KVM) += kvm.o hyperv.o obj-$(CONFIG_KVM) += kvm.o hyperv.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o obj-$(CONFIG_NO_KVM) += kvm-stub.o

View File

@ -106,4 +106,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
hwaddr x86_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr x86_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int x86_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif #endif

View File

@ -2538,6 +2538,8 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
cc->dump_state = x86_cpu_dump_state; cc->dump_state = x86_cpu_dump_state;
cc->set_pc = x86_cpu_set_pc; cc->set_pc = x86_cpu_set_pc;
cc->synchronize_from_tb = x86_cpu_synchronize_from_tb; cc->synchronize_from_tb = x86_cpu_synchronize_from_tb;
cc->gdb_read_register = x86_cpu_gdb_read_register;
cc->gdb_write_register = x86_cpu_gdb_write_register;
cc->get_arch_id = x86_cpu_get_arch_id; cc->get_arch_id = x86_cpu_get_arch_id;
cc->get_paging_enabled = x86_cpu_get_paging_enabled; cc->get_paging_enabled = x86_cpu_get_paging_enabled;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
@ -2549,6 +2551,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
cc->write_elf32_qemunote = x86_cpu_write_elf32_qemunote; cc->write_elf32_qemunote = x86_cpu_write_elf32_qemunote;
cc->vmsd = &vmstate_x86_cpu; cc->vmsd = &vmstate_x86_cpu;
#endif #endif
cc->gdb_num_core_regs = CPU_NB_REGS * 2 + 25;
} }
static const TypeInfo x86_cpu_type_info = { static const TypeInfo x86_cpu_type_info = {

231
target-i386/gdbstub.c Normal file
View File

@ -0,0 +1,231 @@
/*
* x86 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 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 "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.h"
#ifdef TARGET_X86_64
static const int gpr_map[16] = {
R_EAX, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP, R_ESP,
8, 9, 10, 11, 12, 13, 14, 15
};
#else
#define gpr_map gpr_map32
#endif
static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
#define IDX_IP_REG CPU_NB_REGS
#define IDX_FLAGS_REG (IDX_IP_REG + 1)
#define IDX_SEG_REGS (IDX_FLAGS_REG + 1)
#define IDX_FP_REGS (IDX_SEG_REGS + 6)
#define IDX_XMM_REGS (IDX_FP_REGS + 16)
#define IDX_MXCSR_REG (IDX_XMM_REGS + CPU_NB_REGS)
int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
if (n < CPU_NB_REGS) {
if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
return gdb_get_reg64(mem_buf, env->regs[gpr_map[n]]);
} else if (n < CPU_NB_REGS32) {
return gdb_get_reg32(mem_buf, env->regs[gpr_map32[n]]);
}
} else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
#ifdef USE_X86LDOUBLE
/* FIXME: byteswap float values - after fixing fpregs layout. */
memcpy(mem_buf, &env->fpregs[n - IDX_FP_REGS], 10);
#else
memset(mem_buf, 0, 10);
#endif
return 10;
} else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
n -= IDX_XMM_REGS;
if (n < CPU_NB_REGS32 ||
(TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) {
stq_p(mem_buf, env->xmm_regs[n].XMM_Q(0));
stq_p(mem_buf + 8, env->xmm_regs[n].XMM_Q(1));
return 16;
}
} else {
switch (n) {
case IDX_IP_REG:
if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
return gdb_get_reg64(mem_buf, env->eip);
} else {
return gdb_get_reg32(mem_buf, env->eip);
}
case IDX_FLAGS_REG:
return gdb_get_reg32(mem_buf, env->eflags);
case IDX_SEG_REGS:
return gdb_get_reg32(mem_buf, env->segs[R_CS].selector);
case IDX_SEG_REGS + 1:
return gdb_get_reg32(mem_buf, env->segs[R_SS].selector);
case IDX_SEG_REGS + 2:
return gdb_get_reg32(mem_buf, env->segs[R_DS].selector);
case IDX_SEG_REGS + 3:
return gdb_get_reg32(mem_buf, env->segs[R_ES].selector);
case IDX_SEG_REGS + 4:
return gdb_get_reg32(mem_buf, env->segs[R_FS].selector);
case IDX_SEG_REGS + 5:
return gdb_get_reg32(mem_buf, env->segs[R_GS].selector);
case IDX_FP_REGS + 8:
return gdb_get_reg32(mem_buf, env->fpuc);
case IDX_FP_REGS + 9:
return gdb_get_reg32(mem_buf, (env->fpus & ~0x3800) |
(env->fpstt & 0x7) << 11);
case IDX_FP_REGS + 10:
return gdb_get_reg32(mem_buf, 0); /* ftag */
case IDX_FP_REGS + 11:
return gdb_get_reg32(mem_buf, 0); /* fiseg */
case IDX_FP_REGS + 12:
return gdb_get_reg32(mem_buf, 0); /* fioff */
case IDX_FP_REGS + 13:
return gdb_get_reg32(mem_buf, 0); /* foseg */
case IDX_FP_REGS + 14:
return gdb_get_reg32(mem_buf, 0); /* fooff */
case IDX_FP_REGS + 15:
return gdb_get_reg32(mem_buf, 0); /* fop */
case IDX_MXCSR_REG:
return gdb_get_reg32(mem_buf, env->mxcsr);
}
}
return 0;
}
static int x86_cpu_gdb_load_seg(X86CPU *cpu, int sreg, uint8_t *mem_buf)
{
CPUX86State *env = &cpu->env;
uint16_t selector = ldl_p(mem_buf);
if (selector != env->segs[sreg].selector) {
#if defined(CONFIG_USER_ONLY)
cpu_x86_load_seg(env, sreg, selector);
#else
unsigned int limit, flags;
target_ulong base;
if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
base = selector << 4;
limit = 0xffff;
flags = 0;
} else {
if (!cpu_x86_get_descr_debug(env, selector, &base, &limit,
&flags)) {
return 4;
}
}
cpu_x86_load_seg_cache(env, sreg, selector, base, limit, flags);
#endif
}
return 4;
}
int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
uint32_t tmp;
if (n < CPU_NB_REGS) {
if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
env->regs[gpr_map[n]] = ldtul_p(mem_buf);
return sizeof(target_ulong);
} else if (n < CPU_NB_REGS32) {
n = gpr_map32[n];
env->regs[n] &= ~0xffffffffUL;
env->regs[n] |= (uint32_t)ldl_p(mem_buf);
return 4;
}
} else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
#ifdef USE_X86LDOUBLE
/* FIXME: byteswap float values - after fixing fpregs layout. */
memcpy(&env->fpregs[n - IDX_FP_REGS], mem_buf, 10);
#endif
return 10;
} else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
n -= IDX_XMM_REGS;
if (n < CPU_NB_REGS32 ||
(TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) {
env->xmm_regs[n].XMM_Q(0) = ldq_p(mem_buf);
env->xmm_regs[n].XMM_Q(1) = ldq_p(mem_buf + 8);
return 16;
}
} else {
switch (n) {
case IDX_IP_REG:
if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
env->eip = ldq_p(mem_buf);
return 8;
} else {
env->eip &= ~0xffffffffUL;
env->eip |= (uint32_t)ldl_p(mem_buf);
return 4;
}
case IDX_FLAGS_REG:
env->eflags = ldl_p(mem_buf);
return 4;
case IDX_SEG_REGS:
return x86_cpu_gdb_load_seg(cpu, R_CS, mem_buf);
case IDX_SEG_REGS + 1:
return x86_cpu_gdb_load_seg(cpu, R_SS, mem_buf);
case IDX_SEG_REGS + 2:
return x86_cpu_gdb_load_seg(cpu, R_DS, mem_buf);
case IDX_SEG_REGS + 3:
return x86_cpu_gdb_load_seg(cpu, R_ES, mem_buf);
case IDX_SEG_REGS + 4:
return x86_cpu_gdb_load_seg(cpu, R_FS, mem_buf);
case IDX_SEG_REGS + 5:
return x86_cpu_gdb_load_seg(cpu, R_GS, mem_buf);
case IDX_FP_REGS + 8:
env->fpuc = ldl_p(mem_buf);
return 4;
case IDX_FP_REGS + 9:
tmp = ldl_p(mem_buf);
env->fpstt = (tmp >> 11) & 7;
env->fpus = tmp & ~0x3800;
return 4;
case IDX_FP_REGS + 10: /* ftag */
return 4;
case IDX_FP_REGS + 11: /* fiseg */
return 4;
case IDX_FP_REGS + 12: /* fioff */
return 4;
case IDX_FP_REGS + 13: /* foseg */
return 4;
case IDX_FP_REGS + 14: /* fooff */
return 4;
case IDX_FP_REGS + 15: /* fop */
return 4;
case IDX_MXCSR_REG:
env->mxcsr = ldl_p(mem_buf);
return 4;
}
}
/* Unrecognised register. */
return 0;
}

View File

@ -1618,7 +1618,7 @@ static int kvm_guest_debug_workarounds(X86CPU *cpu)
*/ */
if (reinject_trap || if (reinject_trap ||
(!kvm_has_robust_singlestep() && cs->singlestep_enabled)) { (!kvm_has_robust_singlestep() && cs->singlestep_enabled)) {
ret = kvm_update_guest_debug(env, reinject_trap); ret = kvm_update_guest_debug(cs, reinject_trap);
} }
return ret; return ret;
} }

View File

@ -1,2 +1,3 @@
obj-y += translate.o op_helper.o helper.o cpu.o obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_SOFTMMU) += machine.o

View File

@ -79,5 +79,7 @@ void lm32_cpu_do_interrupt(CPUState *cpu);
void lm32_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, void lm32_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags); int flags);
hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int lm32_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int lm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif #endif

View File

@ -87,10 +87,13 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = lm32_cpu_do_interrupt; cc->do_interrupt = lm32_cpu_do_interrupt;
cc->dump_state = lm32_cpu_dump_state; cc->dump_state = lm32_cpu_dump_state;
cc->set_pc = lm32_cpu_set_pc; cc->set_pc = lm32_cpu_set_pc;
cc->gdb_read_register = lm32_cpu_gdb_read_register;
cc->gdb_write_register = lm32_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = lm32_cpu_get_phys_page_debug; cc->get_phys_page_debug = lm32_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_lm32_cpu; cc->vmsd = &vmstate_lm32_cpu;
#endif #endif
cc->gdb_num_core_regs = 32 + 7;
} }
static const TypeInfo lm32_cpu_type_info = { static const TypeInfo lm32_cpu_type_info = {

92
target-lm32/gdbstub.c Normal file
View File

@ -0,0 +1,92 @@
/*
* LM32 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 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 "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.h"
#include "hw/lm32/lm32_pic.h"
int lm32_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
LM32CPU *cpu = LM32_CPU(cs);
CPULM32State *env = &cpu->env;
if (n < 32) {
return gdb_get_reg32(mem_buf, env->regs[n]);
} else {
switch (n) {
case 32:
return gdb_get_reg32(mem_buf, env->pc);
/* FIXME: put in right exception ID */
case 33:
return gdb_get_reg32(mem_buf, 0);
case 34:
return gdb_get_reg32(mem_buf, env->eba);
case 35:
return gdb_get_reg32(mem_buf, env->deba);
case 36:
return gdb_get_reg32(mem_buf, env->ie);
case 37:
return gdb_get_reg32(mem_buf, lm32_pic_get_im(env->pic_state));
case 38:
return gdb_get_reg32(mem_buf, lm32_pic_get_ip(env->pic_state));
}
}
return 0;
}
int lm32_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
LM32CPU *cpu = LM32_CPU(cs);
CPUClass *cc = CPU_GET_CLASS(cs);
CPULM32State *env = &cpu->env;
uint32_t tmp;
if (n > cc->gdb_num_core_regs) {
return 0;
}
tmp = ldl_p(mem_buf);
if (n < 32) {
env->regs[n] = tmp;
} else {
switch (n) {
case 32:
env->pc = tmp;
break;
case 34:
env->eba = tmp;
break;
case 35:
env->deba = tmp;
break;
case 36:
env->ie = tmp;
break;
case 37:
lm32_pic_set_im(env->pic_state, tmp);
break;
case 38:
lm32_pic_set_ip(env->pic_state, tmp);
break;
}
}
return 4;
}

View File

@ -1,2 +1,3 @@
obj-y += m68k-semi.o obj-y += m68k-semi.o
obj-y += translate.o op_helper.o helper.o cpu.o obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += gdbstub.o

View File

@ -74,5 +74,7 @@ void m68k_cpu_do_interrupt(CPUState *cpu);
void m68k_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, void m68k_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags); int flags);
hwaddr m68k_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr m68k_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int m68k_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int m68k_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif #endif

View File

@ -190,10 +190,14 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data)
cc->do_interrupt = m68k_cpu_do_interrupt; cc->do_interrupt = m68k_cpu_do_interrupt;
cc->dump_state = m68k_cpu_dump_state; cc->dump_state = m68k_cpu_dump_state;
cc->set_pc = m68k_cpu_set_pc; cc->set_pc = m68k_cpu_set_pc;
cc->gdb_read_register = m68k_cpu_gdb_read_register;
cc->gdb_write_register = m68k_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug; cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug;
#endif #endif
dc->vmsd = &vmstate_m68k_cpu; dc->vmsd = &vmstate_m68k_cpu;
cc->gdb_num_core_regs = 18;
cc->gdb_core_xml_file = "cf-core.xml";
} }
static void register_cpu_type(const M68kCPUInfo *info) static void register_cpu_type(const M68kCPUInfo *info)

75
target-m68k/gdbstub.c Normal file
View File

@ -0,0 +1,75 @@
/*
* m68k 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 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 "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.h"
int m68k_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
M68kCPU *cpu = M68K_CPU(cs);
CPUM68KState *env = &cpu->env;
if (n < 8) {
/* D0-D7 */
return gdb_get_reg32(mem_buf, env->dregs[n]);
} else if (n < 16) {
/* A0-A7 */
return gdb_get_reg32(mem_buf, env->aregs[n - 8]);
} else {
switch (n) {
case 16:
return gdb_get_reg32(mem_buf, env->sr);
case 17:
return gdb_get_reg32(mem_buf, env->pc);
}
}
/* FP registers not included here because they vary between
ColdFire and m68k. Use XML bits for these. */
return 0;
}
int m68k_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
M68kCPU *cpu = M68K_CPU(cs);
CPUM68KState *env = &cpu->env;
uint32_t tmp;
tmp = ldl_p(mem_buf);
if (n < 8) {
/* D0-D7 */
env->dregs[n] = tmp;
} else if (n < 16) {
/* A0-A7 */
env->aregs[n - 8] = tmp;
} else {
switch (n) {
case 16:
env->sr = tmp;
break;
case 17:
env->pc = tmp;
break;
default:
return 0;
}
}
return 4;
}

View File

@ -1,2 +1,3 @@
obj-y += translate.o op_helper.o helper.o cpu.o obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += mmu.o obj-$(CONFIG_SOFTMMU) += mmu.o

View File

@ -75,5 +75,7 @@ void mb_cpu_do_interrupt(CPUState *cs);
void mb_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, void mb_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags); int flags);
hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int mb_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif #endif

View File

@ -141,12 +141,15 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = mb_cpu_do_interrupt; cc->do_interrupt = mb_cpu_do_interrupt;
cc->dump_state = mb_cpu_dump_state; cc->dump_state = mb_cpu_dump_state;
cc->set_pc = mb_cpu_set_pc; cc->set_pc = mb_cpu_set_pc;
cc->gdb_read_register = mb_cpu_gdb_read_register;
cc->gdb_write_register = mb_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->do_unassigned_access = mb_cpu_unassigned_access; cc->do_unassigned_access = mb_cpu_unassigned_access;
cc->get_phys_page_debug = mb_cpu_get_phys_page_debug; cc->get_phys_page_debug = mb_cpu_get_phys_page_debug;
#endif #endif
dc->vmsd = &vmstate_mb_cpu; dc->vmsd = &vmstate_mb_cpu;
dc->props = mb_properties; dc->props = mb_properties;
cc->gdb_num_core_regs = 32 + 5;
} }
static const TypeInfo mb_cpu_type_info = { static const TypeInfo mb_cpu_type_info = {

View File

@ -0,0 +1,56 @@
/*
* MicroBlaze 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 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 "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.h"
int mb_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
CPUMBState *env = &cpu->env;
if (n < 32) {
return gdb_get_reg32(mem_buf, env->regs[n]);
} else {
return gdb_get_reg32(mem_buf, env->sregs[n - 32]);
}
return 0;
}
int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
CPUClass *cc = CPU_GET_CLASS(cs);
CPUMBState *env = &cpu->env;
uint32_t tmp;
if (n > cc->gdb_num_core_regs) {
return 0;
}
tmp = ldl_p(mem_buf);
if (n < 32) {
env->regs[n] = tmp;
} else {
env->sregs[n - 32] = tmp;
}
return 4;
}

View File

@ -1,2 +1,3 @@
obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o
obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_SOFTMMU) += machine.o

View File

@ -78,5 +78,7 @@ void mips_cpu_do_interrupt(CPUState *cpu);
void mips_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, void mips_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags); int flags);
hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int mips_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif #endif

View File

@ -100,10 +100,14 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
cc->dump_state = mips_cpu_dump_state; cc->dump_state = mips_cpu_dump_state;
cc->set_pc = mips_cpu_set_pc; cc->set_pc = mips_cpu_set_pc;
cc->synchronize_from_tb = mips_cpu_synchronize_from_tb; cc->synchronize_from_tb = mips_cpu_synchronize_from_tb;
cc->gdb_read_register = mips_cpu_gdb_read_register;
cc->gdb_write_register = mips_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->do_unassigned_access = mips_cpu_unassigned_access; cc->do_unassigned_access = mips_cpu_unassigned_access;
cc->get_phys_page_debug = mips_cpu_get_phys_page_debug; cc->get_phys_page_debug = mips_cpu_get_phys_page_debug;
#endif #endif
cc->gdb_num_core_regs = 73;
} }
static const TypeInfo mips_cpu_type_info = { static const TypeInfo mips_cpu_type_info = {

155
target-mips/gdbstub.c Normal file
View File

@ -0,0 +1,155 @@
/*
* MIPS 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 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 "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.h"
int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
if (n < 32) {
return gdb_get_regl(mem_buf, env->active_tc.gpr[n]);
}
if (env->CP0_Config1 & (1 << CP0C1_FP)) {
if (n >= 38 && n < 70) {
if (env->CP0_Status & (1 << CP0St_FR)) {
return gdb_get_regl(mem_buf,
env->active_fpu.fpr[n - 38].d);
} else {
return gdb_get_regl(mem_buf,
env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX]);
}
}
switch (n) {
case 70:
return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr31);
case 71:
return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr0);
}
}
switch (n) {
case 32:
return gdb_get_regl(mem_buf, (int32_t)env->CP0_Status);
case 33:
return gdb_get_regl(mem_buf, env->active_tc.LO[0]);
case 34:
return gdb_get_regl(mem_buf, env->active_tc.HI[0]);
case 35:
return gdb_get_regl(mem_buf, env->CP0_BadVAddr);
case 36:
return gdb_get_regl(mem_buf, (int32_t)env->CP0_Cause);
case 37:
return gdb_get_regl(mem_buf, env->active_tc.PC |
!!(env->hflags & MIPS_HFLAG_M16));
case 72:
return gdb_get_regl(mem_buf, 0); /* fp */
case 89:
return gdb_get_regl(mem_buf, (int32_t)env->CP0_PRid);
}
if (n >= 73 && n <= 88) {
/* 16 embedded regs. */
return gdb_get_regl(mem_buf, 0);
}
return 0;
}
/* convert MIPS rounding mode in FCR31 to IEEE library */
static unsigned int ieee_rm[] = {
float_round_nearest_even,
float_round_to_zero,
float_round_up,
float_round_down
};
#define RESTORE_ROUNDING_MODE \
set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], \
&env->active_fpu.fp_status)
int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
target_ulong tmp;
tmp = ldtul_p(mem_buf);
if (n < 32) {
env->active_tc.gpr[n] = tmp;
return sizeof(target_ulong);
}
if (env->CP0_Config1 & (1 << CP0C1_FP)
&& n >= 38 && n < 73) {
if (n < 70) {
if (env->CP0_Status & (1 << CP0St_FR)) {
env->active_fpu.fpr[n - 38].d = tmp;
} else {
env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp;
}
}
switch (n) {
case 70:
env->active_fpu.fcr31 = tmp & 0xFF83FFFF;
/* set rounding mode */
RESTORE_ROUNDING_MODE;
break;
case 71:
env->active_fpu.fcr0 = tmp;
break;
}
return sizeof(target_ulong);
}
switch (n) {
case 32:
env->CP0_Status = tmp;
break;
case 33:
env->active_tc.LO[0] = tmp;
break;
case 34:
env->active_tc.HI[0] = tmp;
break;
case 35:
env->CP0_BadVAddr = tmp;
break;
case 36:
env->CP0_Cause = tmp;
break;
case 37:
env->active_tc.PC = tmp & ~(target_ulong)1;
if (tmp & 1) {
env->hflags |= MIPS_HFLAG_M16;
} else {
env->hflags &= ~(MIPS_HFLAG_M16);
}
break;
case 72: /* fp, ignored */
break;
default:
if (n > 89) {
return 0;
}
/* Other registers are readonly. Ignore writes. */
break;
}
return sizeof(target_ulong);
}

View File

@ -2,3 +2,4 @@ obj-$(CONFIG_SOFTMMU) += machine.o
obj-y += cpu.o exception.o interrupt.o mmu.o translate.o obj-y += cpu.o exception.o interrupt.o mmu.o translate.o
obj-y += exception_helper.o fpu_helper.o int_helper.o \ obj-y += exception_helper.o fpu_helper.o int_helper.o \
interrupt_helper.o mmu_helper.o sys_helper.o interrupt_helper.o mmu_helper.o sys_helper.o
obj-y += gdbstub.o

View File

@ -155,10 +155,13 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = openrisc_cpu_do_interrupt; cc->do_interrupt = openrisc_cpu_do_interrupt;
cc->dump_state = openrisc_cpu_dump_state; cc->dump_state = openrisc_cpu_dump_state;
cc->set_pc = openrisc_cpu_set_pc; cc->set_pc = openrisc_cpu_set_pc;
cc->gdb_read_register = openrisc_cpu_gdb_read_register;
cc->gdb_write_register = openrisc_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = openrisc_cpu_get_phys_page_debug; cc->get_phys_page_debug = openrisc_cpu_get_phys_page_debug;
dc->vmsd = &vmstate_openrisc_cpu; dc->vmsd = &vmstate_openrisc_cpu;
#endif #endif
cc->gdb_num_core_regs = 32 + 3;
} }
static void cpu_register(const OpenRISCCPUInfo *info) static void cpu_register(const OpenRISCCPUInfo *info)

View File

@ -350,6 +350,8 @@ void openrisc_cpu_do_interrupt(CPUState *cpu);
void openrisc_cpu_dump_state(CPUState *cpu, FILE *f, void openrisc_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags); fprintf_function cpu_fprintf, int flags);
hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int openrisc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int openrisc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void openrisc_translate_init(void); void openrisc_translate_init(void);
int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env, int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
target_ulong address, target_ulong address,

83
target-openrisc/gdbstub.c Normal file
View File

@ -0,0 +1,83 @@
/*
* OpenRISC 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 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 "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.h"
int openrisc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
CPUOpenRISCState *env = &cpu->env;
if (n < 32) {
return gdb_get_reg32(mem_buf, env->gpr[n]);
} else {
switch (n) {
case 32: /* PPC */
return gdb_get_reg32(mem_buf, env->ppc);
case 33: /* NPC */
return gdb_get_reg32(mem_buf, env->npc);
case 34: /* SR */
return gdb_get_reg32(mem_buf, env->sr);
default:
break;
}
}
return 0;
}
int openrisc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
CPUClass *cc = CPU_GET_CLASS(cs);
CPUOpenRISCState *env = &cpu->env;
uint32_t tmp;
if (n > cc->gdb_num_core_regs) {
return 0;
}
tmp = ldl_p(mem_buf);
if (n < 32) {
env->gpr[n] = tmp;
} else {
switch (n) {
case 32: /* PPC */
env->ppc = tmp;
break;
case 33: /* NPC */
env->npc = tmp;
break;
case 34: /* SR */
env->sr = tmp;
break;
default:
break;
}
}
return 4;
}

View File

@ -13,3 +13,4 @@ obj-y += timebase_helper.o
obj-y += misc_helper.o obj-y += misc_helper.o
obj-y += mem_helper.o obj-y += mem_helper.o
obj-$(CONFIG_USER_ONLY) += user_only_helper.o obj-$(CONFIG_USER_ONLY) += user_only_helper.o
obj-y += gdbstub.o

View File

@ -106,5 +106,7 @@ void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
void ppc_cpu_dump_statistics(CPUState *cpu, FILE *f, void ppc_cpu_dump_statistics(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags); fprintf_function cpu_fprintf, int flags);
hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif #endif

131
target-ppc/gdbstub.c Normal file
View File

@ -0,0 +1,131 @@
/*
* PowerPC 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 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 "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.h"
/* Old gdb always expects FP registers. Newer (xml-aware) gdb only
* expects whatever the target description contains. Due to a
* historical mishap the FP registers appear in between core integer
* regs and PC, MSR, CR, and so forth. We hack round this by giving the
* FP regs zero size when talking to a newer gdb.
*/
int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
if (n < 32) {
/* gprs */
return gdb_get_regl(mem_buf, env->gpr[n]);
} else if (n < 64) {
/* fprs */
if (gdb_has_xml) {
return 0;
}
stfq_p(mem_buf, env->fpr[n-32]);
return 8;
} else {
switch (n) {
case 64:
return gdb_get_regl(mem_buf, env->nip);
case 65:
return gdb_get_regl(mem_buf, env->msr);
case 66:
{
uint32_t cr = 0;
int i;
for (i = 0; i < 8; i++) {
cr |= env->crf[i] << (32 - ((i + 1) * 4));
}
return gdb_get_reg32(mem_buf, cr);
}
case 67:
return gdb_get_regl(mem_buf, env->lr);
case 68:
return gdb_get_regl(mem_buf, env->ctr);
case 69:
return gdb_get_regl(mem_buf, env->xer);
case 70:
{
if (gdb_has_xml) {
return 0;
}
return gdb_get_reg32(mem_buf, env->fpscr);
}
}
}
return 0;
}
int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
if (n < 32) {
/* gprs */
env->gpr[n] = ldtul_p(mem_buf);
return sizeof(target_ulong);
} else if (n < 64) {
/* fprs */
if (gdb_has_xml) {
return 0;
}
env->fpr[n-32] = ldfq_p(mem_buf);
return 8;
} else {
switch (n) {
case 64:
env->nip = ldtul_p(mem_buf);
return sizeof(target_ulong);
case 65:
ppc_store_msr(env, ldtul_p(mem_buf));
return sizeof(target_ulong);
case 66:
{
uint32_t cr = ldl_p(mem_buf);
int i;
for (i = 0; i < 8; i++) {
env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF;
}
return 4;
}
case 67:
env->lr = ldtul_p(mem_buf);
return sizeof(target_ulong);
case 68:
env->ctr = ldtul_p(mem_buf);
return sizeof(target_ulong);
case 69:
env->xer = ldtul_p(mem_buf);
return sizeof(target_ulong);
case 70:
/* fpscr */
if (gdb_has_xml) {
return 0;
}
store_fpscr(env, ldtul_p(mem_buf), 0xffffffff);
return sizeof(target_ulong);
}
}
return 0;
}

View File

@ -8458,9 +8458,18 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
cc->dump_state = ppc_cpu_dump_state; cc->dump_state = ppc_cpu_dump_state;
cc->dump_statistics = ppc_cpu_dump_statistics; cc->dump_statistics = ppc_cpu_dump_statistics;
cc->set_pc = ppc_cpu_set_pc; cc->set_pc = ppc_cpu_set_pc;
cc->gdb_read_register = ppc_cpu_gdb_read_register;
cc->gdb_write_register = ppc_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = ppc_cpu_get_phys_page_debug; cc->get_phys_page_debug = ppc_cpu_get_phys_page_debug;
#endif #endif
cc->gdb_num_core_regs = 71;
#if defined(TARGET_PPC64)
cc->gdb_core_xml_file = "power64-core.xml";
#else
cc->gdb_core_xml_file = "power-core.xml";
#endif
} }
static const TypeInfo ppc_cpu_type_info = { static const TypeInfo ppc_cpu_type_info = {

View File

@ -1,4 +1,5 @@
obj-y += translate.o helper.o cpu.o interrupt.o obj-y += translate.o helper.o cpu.o interrupt.o
obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o
obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += ioinst.o obj-$(CONFIG_SOFTMMU) += ioinst.o
obj-$(CONFIG_KVM) += kvm.o obj-$(CONFIG_KVM) += kvm.o

View File

@ -75,5 +75,7 @@ void s390_cpu_do_interrupt(CPUState *cpu);
void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags); int flags);
hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif #endif

View File

@ -173,10 +173,13 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = s390_cpu_do_interrupt; cc->do_interrupt = s390_cpu_do_interrupt;
cc->dump_state = s390_cpu_dump_state; cc->dump_state = s390_cpu_dump_state;
cc->set_pc = s390_cpu_set_pc; cc->set_pc = s390_cpu_set_pc;
cc->gdb_read_register = s390_cpu_gdb_read_register;
cc->gdb_write_register = s390_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = s390_cpu_get_phys_page_debug; cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
#endif #endif
dc->vmsd = &vmstate_s390_cpu; dc->vmsd = &vmstate_s390_cpu;
cc->gdb_num_core_regs = S390_NUM_REGS;
} }
static const TypeInfo s390_cpu_type_info = { static const TypeInfo s390_cpu_type_info = {

88
target-s390x/gdbstub.c Normal file
View File

@ -0,0 +1,88 @@
/*
* s390x 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 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 "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.h"
#include "qemu/bitops.h"
int s390_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
uint64_t val;
int cc_op;
switch (n) {
case S390_PSWM_REGNUM:
cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr);
val = deposit64(env->psw.mask, 44, 2, cc_op);
return gdb_get_regl(mem_buf, val);
case S390_PSWA_REGNUM:
return gdb_get_regl(mem_buf, env->psw.addr);
case S390_R0_REGNUM ... S390_R15_REGNUM:
return gdb_get_regl(mem_buf, env->regs[n-S390_R0_REGNUM]);
case S390_A0_REGNUM ... S390_A15_REGNUM:
return gdb_get_reg32(mem_buf, env->aregs[n-S390_A0_REGNUM]);
case S390_FPC_REGNUM:
return gdb_get_reg32(mem_buf, env->fpc);
case S390_F0_REGNUM ... S390_F15_REGNUM:
return gdb_get_reg64(mem_buf, env->fregs[n-S390_F0_REGNUM].ll);
}
return 0;
}
int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
target_ulong tmpl;
uint32_t tmp32;
int r = 8;
tmpl = ldtul_p(mem_buf);
tmp32 = ldl_p(mem_buf);
switch (n) {
case S390_PSWM_REGNUM:
env->psw.mask = tmpl;
env->cc_op = extract64(tmpl, 44, 2);
break;
case S390_PSWA_REGNUM:
env->psw.addr = tmpl;
break;
case S390_R0_REGNUM ... S390_R15_REGNUM:
env->regs[n-S390_R0_REGNUM] = tmpl;
break;
case S390_A0_REGNUM ... S390_A15_REGNUM:
env->aregs[n-S390_A0_REGNUM] = tmp32;
r = 4;
break;
case S390_FPC_REGNUM:
env->fpc = tmp32;
r = 4;
break;
case S390_F0_REGNUM ... S390_F15_REGNUM:
env->fregs[n-S390_F0_REGNUM].ll = tmpl;
break;
default:
return 0;
}
return r;
}

View File

@ -345,12 +345,10 @@ void *kvm_arch_ram_alloc(ram_addr_t size)
int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
{ {
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01}; static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
cpu_memory_rw_debug(env, bp->pc, (uint8_t *)diag_501, 4, 1)) { cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)diag_501, 4, 1)) {
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
@ -358,16 +356,14 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
{ {
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
uint8_t t[4]; uint8_t t[4];
static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01}; static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
if (cpu_memory_rw_debug(env, bp->pc, t, 4, 0)) { if (cpu_memory_rw_debug(cs, bp->pc, t, 4, 0)) {
return -EINVAL; return -EINVAL;
} else if (memcmp(t, diag_501, 4)) { } else if (memcmp(t, diag_501, 4)) {
return -EINVAL; return -EINVAL;
} else if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) { } else if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
return -EINVAL; return -EINVAL;
} }

View File

@ -1 +1,2 @@
obj-y += translate.o op_helper.o helper.o cpu.o obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += gdbstub.o

View File

@ -87,5 +87,7 @@ void superh_cpu_do_interrupt(CPUState *cpu);
void superh_cpu_dump_state(CPUState *cpu, FILE *f, void superh_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags); fprintf_function cpu_fprintf, int flags);
hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int superh_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int superh_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif #endif

View File

@ -286,10 +286,13 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data)
cc->dump_state = superh_cpu_dump_state; cc->dump_state = superh_cpu_dump_state;
cc->set_pc = superh_cpu_set_pc; cc->set_pc = superh_cpu_set_pc;
cc->synchronize_from_tb = superh_cpu_synchronize_from_tb; cc->synchronize_from_tb = superh_cpu_synchronize_from_tb;
cc->gdb_read_register = superh_cpu_gdb_read_register;
cc->gdb_write_register = superh_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = superh_cpu_get_phys_page_debug; cc->get_phys_page_debug = superh_cpu_get_phys_page_debug;
#endif #endif
dc->vmsd = &vmstate_sh_cpu; dc->vmsd = &vmstate_sh_cpu;
cc->gdb_num_core_regs = 59;
} }
static const TypeInfo superh_cpu_type_info = { static const TypeInfo superh_cpu_type_info = {

146
target-sh4/gdbstub.c Normal file
View File

@ -0,0 +1,146 @@
/*
* SuperH 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 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 "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.h"
/* Hint: Use "set architecture sh4" in GDB to see fpu registers */
/* FIXME: We should use XML for this. */
int superh_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
SuperHCPU *cpu = SUPERH_CPU(cs);
CPUSH4State *env = &cpu->env;
switch (n) {
case 0 ... 7:
if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
return gdb_get_regl(mem_buf, env->gregs[n + 16]);
} else {
return gdb_get_regl(mem_buf, env->gregs[n]);
}
case 8 ... 15:
return gdb_get_regl(mem_buf, env->gregs[n]);
case 16:
return gdb_get_regl(mem_buf, env->pc);
case 17:
return gdb_get_regl(mem_buf, env->pr);
case 18:
return gdb_get_regl(mem_buf, env->gbr);
case 19:
return gdb_get_regl(mem_buf, env->vbr);
case 20:
return gdb_get_regl(mem_buf, env->mach);
case 21:
return gdb_get_regl(mem_buf, env->macl);
case 22:
return gdb_get_regl(mem_buf, env->sr);
case 23:
return gdb_get_regl(mem_buf, env->fpul);
case 24:
return gdb_get_regl(mem_buf, env->fpscr);
case 25 ... 40:
if (env->fpscr & FPSCR_FR) {
stfl_p(mem_buf, env->fregs[n - 9]);
} else {
stfl_p(mem_buf, env->fregs[n - 25]);
}
return 4;
case 41:
return gdb_get_regl(mem_buf, env->ssr);
case 42:
return gdb_get_regl(mem_buf, env->spc);
case 43 ... 50:
return gdb_get_regl(mem_buf, env->gregs[n - 43]);
case 51 ... 58:
return gdb_get_regl(mem_buf, env->gregs[n - (51 - 16)]);
}
return 0;
}
int superh_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
SuperHCPU *cpu = SUPERH_CPU(cs);
CPUSH4State *env = &cpu->env;
switch (n) {
case 0 ... 7:
if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
env->gregs[n + 16] = ldl_p(mem_buf);
} else {
env->gregs[n] = ldl_p(mem_buf);
}
break;
case 8 ... 15:
env->gregs[n] = ldl_p(mem_buf);
break;
case 16:
env->pc = ldl_p(mem_buf);
break;
case 17:
env->pr = ldl_p(mem_buf);
break;
case 18:
env->gbr = ldl_p(mem_buf);
break;
case 19:
env->vbr = ldl_p(mem_buf);
break;
case 20:
env->mach = ldl_p(mem_buf);
break;
case 21:
env->macl = ldl_p(mem_buf);
break;
case 22:
env->sr = ldl_p(mem_buf);
break;
case 23:
env->fpul = ldl_p(mem_buf);
break;
case 24:
env->fpscr = ldl_p(mem_buf);
break;
case 25 ... 40:
if (env->fpscr & FPSCR_FR) {
env->fregs[n - 9] = ldfl_p(mem_buf);
} else {
env->fregs[n - 25] = ldfl_p(mem_buf);
}
break;
case 41:
env->ssr = ldl_p(mem_buf);
break;
case 42:
env->spc = ldl_p(mem_buf);
break;
case 43 ... 50:
env->gregs[n - 43] = ldl_p(mem_buf);
break;
case 51 ... 58:
env->gregs[n - (51 - 16)] = ldl_p(mem_buf);
break;
default:
return 0;
}
return 4;
}

View File

@ -4,3 +4,4 @@ obj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
obj-$(TARGET_SPARC) += int32_helper.o obj-$(TARGET_SPARC) += int32_helper.o
obj-$(TARGET_SPARC64) += int64_helper.o obj-$(TARGET_SPARC64) += int64_helper.o
obj-$(TARGET_SPARC64) += vis_helper.o obj-$(TARGET_SPARC64) += vis_helper.o
obj-y += gdbstub.o

View File

@ -79,5 +79,7 @@ void sparc_cpu_do_interrupt(CPUState *cpu);
void sparc_cpu_dump_state(CPUState *cpu, FILE *f, void sparc_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags); fprintf_function cpu_fprintf, int flags);
hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int sparc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif #endif

View File

@ -787,10 +787,18 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data)
#endif #endif
cc->set_pc = sparc_cpu_set_pc; cc->set_pc = sparc_cpu_set_pc;
cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb; cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb;
cc->gdb_read_register = sparc_cpu_gdb_read_register;
cc->gdb_write_register = sparc_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->do_unassigned_access = sparc_cpu_unassigned_access; cc->do_unassigned_access = sparc_cpu_unassigned_access;
cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug; cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug;
#endif #endif
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
cc->gdb_num_core_regs = 86;
#else
cc->gdb_num_core_regs = 72;
#endif
} }
static const TypeInfo sparc_cpu_type_info = { static const TypeInfo sparc_cpu_type_info = {

208
target-sparc/gdbstub.c Normal file
View File

@ -0,0 +1,208 @@
/*
* 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 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 "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.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, uint8_t *mem_buf, int n)
{
SPARCCPU *cpu = SPARC_CPU(cs);
CPUSPARCState *env = &cpu->env;
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, env->fsr);
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 (double width, even numbers only) */
return gdb_get_reg64(mem_buf, env->fpr[(n - 32) / 2].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, env->fsr);
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)
abi_ulong 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:
env->fsr = 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 (double width, even numbers only) */
env->fpr[(n - 32) / 2].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:
env->fsr = tmp;
break;
case 84:
env->fprs = tmp;
break;
case 85:
env->y = tmp;
break;
default:
return 0;
}
}
return 8;
#endif
}

View File

@ -3,3 +3,4 @@ obj-y += core-dc232b.o
obj-y += core-dc233c.o obj-y += core-dc233c.o
obj-y += core-fsf.o obj-y += core-fsf.o
obj-y += translate.o op_helper.o helper.o cpu.o obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += gdbstub.o

View File

@ -45,6 +45,7 @@
* XtensaCPUClass: * XtensaCPUClass:
* @parent_realize: The parent class' realize handler. * @parent_realize: The parent class' realize handler.
* @parent_reset: The parent class' reset handler. * @parent_reset: The parent class' reset handler.
* @config: The CPU core configuration.
* *
* An Xtensa CPU model. * An Xtensa CPU model.
*/ */
@ -55,6 +56,8 @@ typedef struct XtensaCPUClass {
DeviceRealize parent_realize; DeviceRealize parent_realize;
void (*parent_reset)(CPUState *cpu); void (*parent_reset)(CPUState *cpu);
const XtensaConfig *config;
} XtensaCPUClass; } XtensaCPUClass;
/** /**
@ -84,5 +87,7 @@ void xtensa_cpu_do_interrupt(CPUState *cpu);
void xtensa_cpu_dump_state(CPUState *cpu, FILE *f, void xtensa_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags); fprintf_function cpu_fprintf, int flags);
hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int xtensa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int xtensa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif #endif

View File

@ -64,10 +64,32 @@ static void xtensa_cpu_reset(CPUState *s)
reset_mmu(env); reset_mmu(env);
} }
static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model)
{
ObjectClass *oc;
char *typename;
if (cpu_model == NULL) {
return NULL;
}
typename = g_strdup_printf("%s-" TYPE_XTENSA_CPU, cpu_model);
oc = object_class_by_name(typename);
g_free(typename);
if (oc == NULL || !object_class_dynamic_cast(oc, TYPE_XTENSA_CPU) ||
object_class_is_abstract(oc)) {
return NULL;
}
return oc;
}
static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp)
{ {
CPUState *cs = CPU(dev);
XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(dev); XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(dev);
cs->gdb_num_regs = xcc->config->gdb_regmap.num_regs;
xcc->parent_realize(dev, errp); xcc->parent_realize(dev, errp);
} }
@ -75,10 +97,12 @@ static void xtensa_cpu_initfn(Object *obj)
{ {
CPUState *cs = CPU(obj); CPUState *cs = CPU(obj);
XtensaCPU *cpu = XTENSA_CPU(obj); XtensaCPU *cpu = XTENSA_CPU(obj);
XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(obj);
CPUXtensaState *env = &cpu->env; CPUXtensaState *env = &cpu->env;
static bool tcg_inited; static bool tcg_inited;
cs->env_ptr = env; cs->env_ptr = env;
env->config = xcc->config;
cpu_exec_init(env); cpu_exec_init(env);
if (tcg_enabled() && !tcg_inited) { if (tcg_enabled() && !tcg_inited) {
@ -105,9 +129,12 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
xcc->parent_reset = cc->reset; xcc->parent_reset = cc->reset;
cc->reset = xtensa_cpu_reset; cc->reset = xtensa_cpu_reset;
cc->class_by_name = xtensa_cpu_class_by_name;
cc->do_interrupt = xtensa_cpu_do_interrupt; cc->do_interrupt = xtensa_cpu_do_interrupt;
cc->dump_state = xtensa_cpu_dump_state; cc->dump_state = xtensa_cpu_dump_state;
cc->set_pc = xtensa_cpu_set_pc; cc->set_pc = xtensa_cpu_set_pc;
cc->gdb_read_register = xtensa_cpu_gdb_read_register;
cc->gdb_write_register = xtensa_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug; cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug;
#endif #endif
@ -119,7 +146,7 @@ static const TypeInfo xtensa_cpu_type_info = {
.parent = TYPE_CPU, .parent = TYPE_CPU,
.instance_size = sizeof(XtensaCPU), .instance_size = sizeof(XtensaCPU),
.instance_init = xtensa_cpu_initfn, .instance_init = xtensa_cpu_initfn,
.abstract = false, .abstract = true,
.class_size = sizeof(XtensaCPUClass), .class_size = sizeof(XtensaCPUClass),
.class_init = xtensa_cpu_class_init, .class_init = xtensa_cpu_class_init,
}; };

109
target-xtensa/gdbstub.c Normal file
View File

@ -0,0 +1,109 @@
/*
* Xtensa 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 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 "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.h"
int xtensa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
XtensaCPU *cpu = XTENSA_CPU(cs);
CPUXtensaState *env = &cpu->env;
const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
return 0;
}
switch (reg->type) {
case 9: /*pc*/
return gdb_get_reg32(mem_buf, env->pc);
case 1: /*ar*/
xtensa_sync_phys_from_window(env);
return gdb_get_reg32(mem_buf, env->phys_regs[(reg->targno & 0xff)
% env->config->nareg]);
case 2: /*SR*/
return gdb_get_reg32(mem_buf, env->sregs[reg->targno & 0xff]);
case 3: /*UR*/
return gdb_get_reg32(mem_buf, env->uregs[reg->targno & 0xff]);
case 4: /*f*/
return gdb_get_reg32(mem_buf, float32_val(env->fregs[reg->targno
& 0x0f]));
case 8: /*a*/
return gdb_get_reg32(mem_buf, env->regs[reg->targno & 0x0f]);
default:
qemu_log("%s from reg %d of unsupported type %d\n",
__func__, n, reg->type);
return 0;
}
}
int xtensa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
XtensaCPU *cpu = XTENSA_CPU(cs);
CPUXtensaState *env = &cpu->env;
uint32_t tmp;
const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
return 0;
}
tmp = ldl_p(mem_buf);
switch (reg->type) {
case 9: /*pc*/
env->pc = tmp;
break;
case 1: /*ar*/
env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp;
xtensa_sync_window_from_phys(env);
break;
case 2: /*SR*/
env->sregs[reg->targno & 0xff] = tmp;
break;
case 3: /*UR*/
env->uregs[reg->targno & 0xff] = tmp;
break;
case 4: /*f*/
env->fregs[reg->targno & 0x0f] = make_float32(tmp);
break;
case 8: /*a*/
env->regs[reg->targno & 0x0f] = tmp;
break;
default:
qemu_log("%s to reg %d of unsupported type %d\n",
__func__, n, reg->type);
return 0;
}
return 4;
}

View File

@ -35,10 +35,35 @@
static struct XtensaConfigList *xtensa_cores; static struct XtensaConfigList *xtensa_cores;
static void xtensa_core_class_init(ObjectClass *oc, void *data)
{
CPUClass *cc = CPU_CLASS(oc);
XtensaCPUClass *xcc = XTENSA_CPU_CLASS(oc);
const XtensaConfig *config = data;
xcc->config = config;
/* Use num_core_regs to see only non-privileged registers in an unmodified
* gdb. Use num_regs to see all registers. gdb modification is required
* for that: reset bit 0 in the 'flags' field of the registers definitions
* in the gdb/xtensa-config.c inside gdb source tree or inside gdb overlay.
*/
cc->gdb_num_core_regs = config->gdb_regmap.num_regs;
}
void xtensa_register_core(XtensaConfigList *node) void xtensa_register_core(XtensaConfigList *node)
{ {
TypeInfo type = {
.parent = TYPE_XTENSA_CPU,
.class_init = xtensa_core_class_init,
.class_data = (void *)node->config,
};
node->next = xtensa_cores; node->next = xtensa_cores;
xtensa_cores = node; xtensa_cores = node;
type.name = g_strdup_printf("%s-" TYPE_XTENSA_CPU, node->config->name);
type_register(&type);
g_free((gpointer)type.name);
} }
static uint32_t check_hw_breakpoints(CPUXtensaState *env) static uint32_t check_hw_breakpoints(CPUXtensaState *env)
@ -72,24 +97,17 @@ void xtensa_breakpoint_handler(CPUXtensaState *env)
XtensaCPU *cpu_xtensa_init(const char *cpu_model) XtensaCPU *cpu_xtensa_init(const char *cpu_model)
{ {
ObjectClass *oc;
XtensaCPU *cpu; XtensaCPU *cpu;
CPUXtensaState *env; CPUXtensaState *env;
const XtensaConfig *config = NULL;
XtensaConfigList *core = xtensa_cores;
for (; core; core = core->next) oc = cpu_class_by_name(TYPE_XTENSA_CPU, cpu_model);
if (strcmp(core->config->name, cpu_model) == 0) { if (oc == NULL) {
config = core->config;
break;
}
if (config == NULL) {
return NULL; return NULL;
} }
cpu = XTENSA_CPU(object_new(TYPE_XTENSA_CPU)); cpu = XTENSA_CPU(object_new(object_class_get_name(oc)));
env = &cpu->env; env = &cpu->env;
env->config = config;
xtensa_irq_init(env); xtensa_irq_init(env);