gdb support for user mode (Paul Brook)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1367 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
6e4255f6a6
commit
1fddef4b1b
@ -298,6 +298,9 @@ endif
|
|||||||
ifeq ($(ARCH),ia64)
|
ifeq ($(ARCH),ia64)
|
||||||
OBJS += ia64-syscall.o
|
OBJS += ia64-syscall.o
|
||||||
endif
|
endif
|
||||||
|
ifdef CONFIG_GDBSTUB
|
||||||
|
OBJS+=gdbstub.o
|
||||||
|
endif
|
||||||
|
|
||||||
all: $(PROGS)
|
all: $(PROGS)
|
||||||
|
|
||||||
|
12
exec.c
12
exec.c
@ -1076,7 +1076,7 @@ static void tb_reset_jump_recursive(TranslationBlock *tb)
|
|||||||
tb_reset_jump_recursive2(tb, 1);
|
tb_reset_jump_recursive2(tb, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
|
#if defined(TARGET_HAS_ICE)
|
||||||
static void breakpoint_invalidate(CPUState *env, target_ulong pc)
|
static void breakpoint_invalidate(CPUState *env, target_ulong pc)
|
||||||
{
|
{
|
||||||
target_ulong phys_addr;
|
target_ulong phys_addr;
|
||||||
@ -1090,7 +1090,7 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc)
|
|||||||
breakpoint is reached */
|
breakpoint is reached */
|
||||||
int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
|
int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
|
||||||
{
|
{
|
||||||
#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
|
#if defined(TARGET_HAS_ICE)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < env->nb_breakpoints; i++) {
|
for(i = 0; i < env->nb_breakpoints; i++) {
|
||||||
@ -1112,7 +1112,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
|
|||||||
/* remove a breakpoint */
|
/* remove a breakpoint */
|
||||||
int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
|
int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
|
||||||
{
|
{
|
||||||
#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
|
#if defined(TARGET_HAS_ICE)
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < env->nb_breakpoints; i++) {
|
for(i = 0; i < env->nb_breakpoints; i++) {
|
||||||
if (env->breakpoints[i] == pc)
|
if (env->breakpoints[i] == pc)
|
||||||
@ -1120,9 +1120,9 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
|
|||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
found:
|
found:
|
||||||
memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
|
|
||||||
(env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
|
|
||||||
env->nb_breakpoints--;
|
env->nb_breakpoints--;
|
||||||
|
if (i < env->nb_breakpoints)
|
||||||
|
env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
|
||||||
|
|
||||||
breakpoint_invalidate(env, pc);
|
breakpoint_invalidate(env, pc);
|
||||||
return 0;
|
return 0;
|
||||||
@ -1135,7 +1135,7 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
|
|||||||
CPU loop after each instruction */
|
CPU loop after each instruction */
|
||||||
void cpu_single_step(CPUState *env, int enabled)
|
void cpu_single_step(CPUState *env, int enabled)
|
||||||
{
|
{
|
||||||
#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
|
#if defined(TARGET_HAS_ICE)
|
||||||
if (env->singlestep_enabled != enabled) {
|
if (env->singlestep_enabled != enabled) {
|
||||||
env->singlestep_enabled = enabled;
|
env->singlestep_enabled = enabled;
|
||||||
/* must flush all the translated code to avoid inconsistancies */
|
/* must flush all the translated code to avoid inconsistancies */
|
||||||
|
152
gdbstub.c
152
gdbstub.c
@ -17,7 +17,18 @@
|
|||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "qemu.h"
|
||||||
|
#else
|
||||||
#include "vl.h"
|
#include "vl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
@ -31,9 +42,10 @@ enum RSState {
|
|||||||
RS_GETLINE,
|
RS_GETLINE,
|
||||||
RS_CHKSUM1,
|
RS_CHKSUM1,
|
||||||
RS_CHKSUM2,
|
RS_CHKSUM2,
|
||||||
|
RS_CONTINUE
|
||||||
};
|
};
|
||||||
|
/* XXX: This is not thread safe. Do we care? */
|
||||||
static int gdbserver_fd;
|
static int gdbserver_fd = -1;
|
||||||
|
|
||||||
typedef struct GDBState {
|
typedef struct GDBState {
|
||||||
enum RSState state;
|
enum RSState state;
|
||||||
@ -43,6 +55,11 @@ typedef struct GDBState {
|
|||||||
int line_csum;
|
int line_csum;
|
||||||
} GDBState;
|
} GDBState;
|
||||||
|
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
/* XXX: remove this hack. */
|
||||||
|
static GDBState gdbserver_state;
|
||||||
|
#endif
|
||||||
|
|
||||||
static int get_char(GDBState *s)
|
static int get_char(GDBState *s)
|
||||||
{
|
{
|
||||||
uint8_t ch;
|
uint8_t ch;
|
||||||
@ -330,8 +347,47 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
|||||||
env->npc = tswapl(registers[69]);
|
env->npc = tswapl(registers[69]);
|
||||||
env->fsr = tswapl(registers[70]);
|
env->fsr = tswapl(registers[70]);
|
||||||
}
|
}
|
||||||
#else
|
#elif defined (TARGET_ARM)
|
||||||
|
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t *ptr;
|
||||||
|
|
||||||
|
ptr = mem_buf;
|
||||||
|
/* 16 core integer registers (4 bytes each). */
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
*(uint32_t *)ptr = tswapl(env->regs[i]);
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
|
/* 8 FPA registers (12 bytes each), FPS (4 bytes).
|
||||||
|
Not yet implemented. */
|
||||||
|
memset (ptr, 0, 8 * 12 + 4);
|
||||||
|
ptr += 8 * 12 + 4;
|
||||||
|
/* CPSR (4 bytes). */
|
||||||
|
*(uint32_t *)ptr = tswapl (env->cpsr);
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
|
return ptr - mem_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t *ptr;
|
||||||
|
|
||||||
|
ptr = mem_buf;
|
||||||
|
/* Core integer registers. */
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
env->regs[i] = tswapl(*(uint32_t *)ptr);
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
|
/* Ignore FPA regs and scr. */
|
||||||
|
ptr += 8 * 12 + 4;
|
||||||
|
env->cpsr = tswapl(*(uint32_t *)ptr);
|
||||||
|
}
|
||||||
|
#else
|
||||||
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@ -343,10 +399,8 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* port = 0 means default port */
|
static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
|
||||||
static int gdb_handle_packet(GDBState *s, const char *line_buf)
|
|
||||||
{
|
{
|
||||||
CPUState *env = cpu_single_env;
|
|
||||||
const char *p;
|
const char *p;
|
||||||
int ch, reg_size, type;
|
int ch, reg_size, type;
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
@ -361,6 +415,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
|
|||||||
ch = *p++;
|
ch = *p++;
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
case '?':
|
case '?':
|
||||||
|
/* TODO: Make this return the correct value for user-mode. */
|
||||||
snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
|
snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
|
||||||
put_packet(s, buf);
|
put_packet(s, buf);
|
||||||
break;
|
break;
|
||||||
@ -376,8 +431,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
|
|||||||
env->npc = addr + 4;
|
env->npc = addr + 4;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
vm_start();
|
return RS_CONTINUE;
|
||||||
break;
|
|
||||||
case 's':
|
case 's':
|
||||||
if (*p != '\0') {
|
if (*p != '\0') {
|
||||||
addr = strtoul(p, (char **)&p, 16);
|
addr = strtoul(p, (char **)&p, 16);
|
||||||
@ -391,8 +445,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
cpu_single_step(env, 1);
|
cpu_single_step(env, 1);
|
||||||
vm_start();
|
return RS_CONTINUE;
|
||||||
break;
|
|
||||||
case 'g':
|
case 'g':
|
||||||
reg_size = cpu_gdb_read_registers(env, mem_buf);
|
reg_size = cpu_gdb_read_registers(env, mem_buf);
|
||||||
memtohex(buf, mem_buf, reg_size);
|
memtohex(buf, mem_buf, reg_size);
|
||||||
@ -472,6 +525,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
|
|||||||
|
|
||||||
extern void tb_flush(CPUState *env);
|
extern void tb_flush(CPUState *env);
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
static void gdb_vm_stopped(void *opaque, int reason)
|
static void gdb_vm_stopped(void *opaque, int reason)
|
||||||
{
|
{
|
||||||
GDBState *s = opaque;
|
GDBState *s = opaque;
|
||||||
@ -490,17 +544,20 @@ static void gdb_vm_stopped(void *opaque, int reason)
|
|||||||
snprintf(buf, sizeof(buf), "S%02x", ret);
|
snprintf(buf, sizeof(buf), "S%02x", ret);
|
||||||
put_packet(s, buf);
|
put_packet(s, buf);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void gdb_read_byte(GDBState *s, int ch)
|
static void gdb_read_byte(GDBState *s, CPUState *env, int ch)
|
||||||
{
|
{
|
||||||
int i, csum;
|
int i, csum;
|
||||||
char reply[1];
|
char reply[1];
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
if (vm_running) {
|
if (vm_running) {
|
||||||
/* when the CPU is running, we cannot do anything except stop
|
/* when the CPU is running, we cannot do anything except stop
|
||||||
it when receiving a char */
|
it when receiving a char */
|
||||||
vm_stop(EXCP_INTERRUPT);
|
vm_stop(EXCP_INTERRUPT);
|
||||||
} else {
|
} else {
|
||||||
|
#endif
|
||||||
switch(s->state) {
|
switch(s->state) {
|
||||||
case RS_IDLE:
|
case RS_IDLE:
|
||||||
if (ch == '$') {
|
if (ch == '$') {
|
||||||
@ -535,13 +592,67 @@ static void gdb_read_byte(GDBState *s, int ch)
|
|||||||
} else {
|
} else {
|
||||||
reply[0] = '+';
|
reply[0] = '+';
|
||||||
put_buffer(s, reply, 1);
|
put_buffer(s, reply, 1);
|
||||||
s->state = gdb_handle_packet(s, s->line_buf);
|
s->state = gdb_handle_packet(s, env, s->line_buf);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case RS_CONTINUE:
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
vm_start();
|
||||||
|
s->state = RS_IDLE;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
int
|
||||||
|
gdb_handlesig (CPUState *env, int sig)
|
||||||
|
{
|
||||||
|
GDBState *s;
|
||||||
|
char buf[256];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (gdbserver_fd < 0)
|
||||||
|
return sig;
|
||||||
|
|
||||||
|
s = &gdbserver_state;
|
||||||
|
|
||||||
|
/* disable single step if it was enabled */
|
||||||
|
cpu_single_step(env, 0);
|
||||||
|
tb_flush(env);
|
||||||
|
|
||||||
|
if (sig != 0)
|
||||||
|
{
|
||||||
|
snprintf(buf, sizeof(buf), "S%02x", sig);
|
||||||
|
put_packet(s, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: How do we terminate this loop? */
|
||||||
|
sig = 0;
|
||||||
|
s->state = RS_IDLE;
|
||||||
|
while (s->state != RS_CONTINUE)
|
||||||
|
{
|
||||||
|
n = read (s->fd, buf, 256);
|
||||||
|
if (n > 0)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
gdb_read_byte (s, env, buf[i]);
|
||||||
|
}
|
||||||
|
else if (n == 0 || errno != EAGAIN)
|
||||||
|
{
|
||||||
|
/* XXX: Connection closed. Should probably wait for annother
|
||||||
|
connection before continuing. */
|
||||||
|
return sig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sig;
|
||||||
|
}
|
||||||
|
#else
|
||||||
static int gdb_can_read(void *opaque)
|
static int gdb_can_read(void *opaque)
|
||||||
{
|
{
|
||||||
return 256;
|
return 256;
|
||||||
@ -559,10 +670,12 @@ static void gdb_read(void *opaque, const uint8_t *buf, int size)
|
|||||||
vm_start();
|
vm_start();
|
||||||
} else {
|
} else {
|
||||||
for(i = 0; i < size; i++)
|
for(i = 0; i < size; i++)
|
||||||
gdb_read_byte(s, buf[i]);
|
gdb_read_byte(s, cpu_single_env, buf[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static void gdb_accept(void *opaque, const uint8_t *buf, int size)
|
static void gdb_accept(void *opaque, const uint8_t *buf, int size)
|
||||||
{
|
{
|
||||||
GDBState *s;
|
GDBState *s;
|
||||||
@ -585,15 +698,21 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size)
|
|||||||
val = 1;
|
val = 1;
|
||||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
|
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
|
||||||
|
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
s = &gdbserver_state;
|
||||||
|
memset (s, 0, sizeof (GDBState));
|
||||||
|
#else
|
||||||
s = qemu_mallocz(sizeof(GDBState));
|
s = qemu_mallocz(sizeof(GDBState));
|
||||||
if (!s) {
|
if (!s) {
|
||||||
close(fd);
|
close(fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
s->fd = fd;
|
s->fd = fd;
|
||||||
|
|
||||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
/* stop the VM */
|
/* stop the VM */
|
||||||
vm_stop(EXCP_INTERRUPT);
|
vm_stop(EXCP_INTERRUPT);
|
||||||
|
|
||||||
@ -601,6 +720,7 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size)
|
|||||||
qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s);
|
qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s);
|
||||||
/* when the VM is stopped, the following callback is called */
|
/* when the VM is stopped, the following callback is called */
|
||||||
qemu_add_vm_stop_handler(gdb_vm_stopped, s);
|
qemu_add_vm_stop_handler(gdb_vm_stopped, s);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gdbserver_open(int port)
|
static int gdbserver_open(int port)
|
||||||
@ -631,7 +751,9 @@ static int gdbserver_open(int port)
|
|||||||
perror("listen");
|
perror("listen");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||||
|
#endif
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -641,6 +763,10 @@ int gdbserver_start(int port)
|
|||||||
if (gdbserver_fd < 0)
|
if (gdbserver_fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
/* accept connections */
|
/* accept connections */
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
gdb_accept (NULL, NULL, 0);
|
||||||
|
#else
|
||||||
qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL);
|
qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL);
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
11
gdbstub.h
Normal file
11
gdbstub.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef GDBSTUB_H
|
||||||
|
#define GDBSTUB_H
|
||||||
|
|
||||||
|
#define DEFAULT_GDBSTUB_PORT 1234
|
||||||
|
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
int gdb_handlesig (CPUState *, int);
|
||||||
|
#endif
|
||||||
|
int gdbserver_start(int);
|
||||||
|
|
||||||
|
#endif
|
@ -278,6 +278,20 @@ void cpu_loop(CPUX86State *env)
|
|||||||
case EXCP_INTERRUPT:
|
case EXCP_INTERRUPT:
|
||||||
/* just indicate that signals should be handled asap */
|
/* just indicate that signals should be handled asap */
|
||||||
break;
|
break;
|
||||||
|
case EXCP_DEBUG:
|
||||||
|
{
|
||||||
|
int sig;
|
||||||
|
|
||||||
|
sig = gdb_handlesig (env, TARGET_SIGTRAP);
|
||||||
|
if (sig)
|
||||||
|
{
|
||||||
|
info.si_signo = sig;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_TRAP_BRKPT;
|
||||||
|
queue_signal(info.si_signo, &info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
pc = env->segs[R_CS].base + env->eip;
|
pc = env->segs[R_CS].base + env->eip;
|
||||||
fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
|
fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
|
||||||
@ -379,6 +393,20 @@ void cpu_loop(CPUARMState *env)
|
|||||||
queue_signal(info.si_signo, &info);
|
queue_signal(info.si_signo, &info);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case EXCP_DEBUG:
|
||||||
|
{
|
||||||
|
int sig;
|
||||||
|
|
||||||
|
sig = gdb_handlesig (env, TARGET_SIGTRAP);
|
||||||
|
if (sig)
|
||||||
|
{
|
||||||
|
info.si_signo = sig;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_TRAP_BRKPT;
|
||||||
|
queue_signal(info.si_signo, &info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error:
|
error:
|
||||||
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||||
@ -529,6 +557,20 @@ void cpu_loop (CPUSPARCState *env)
|
|||||||
break;
|
break;
|
||||||
case 0x100: // XXX, why do we get these?
|
case 0x100: // XXX, why do we get these?
|
||||||
break;
|
break;
|
||||||
|
case EXCP_DEBUG:
|
||||||
|
{
|
||||||
|
int sig;
|
||||||
|
|
||||||
|
sig = gdb_handlesig (env, TARGET_SIGTRAP);
|
||||||
|
if (sig)
|
||||||
|
{
|
||||||
|
info.si_signo = sig;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_TRAP_BRKPT;
|
||||||
|
queue_signal(info.si_signo, &info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf ("Unhandled trap: 0x%x\n", trapnr);
|
printf ("Unhandled trap: 0x%x\n", trapnr);
|
||||||
cpu_dump_state(env, stderr, fprintf, 0);
|
cpu_dump_state(env, stderr, fprintf, 0);
|
||||||
@ -911,8 +953,20 @@ void cpu_loop(CPUPPCState *env)
|
|||||||
case EXCP_INTERRUPT:
|
case EXCP_INTERRUPT:
|
||||||
/* Don't know why this should ever happen... */
|
/* Don't know why this should ever happen... */
|
||||||
break;
|
break;
|
||||||
case EXCP_DEBUG:
|
case EXCP_DEBUG:
|
||||||
break;
|
{
|
||||||
|
int sig;
|
||||||
|
|
||||||
|
sig = gdb_handlesig (env, TARGET_SIGTRAP);
|
||||||
|
if (sig)
|
||||||
|
{
|
||||||
|
info.si_signo = sig;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_TRAP_BRKPT;
|
||||||
|
queue_signal(info.si_signo, &info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||||
trapnr);
|
trapnr);
|
||||||
@ -930,10 +984,11 @@ void cpu_loop(CPUPPCState *env)
|
|||||||
void usage(void)
|
void usage(void)
|
||||||
{
|
{
|
||||||
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n"
|
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n"
|
||||||
"usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n"
|
"usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] program [arguments...]\n"
|
||||||
"Linux CPU emulator (compiled for %s emulation)\n"
|
"Linux CPU emulator (compiled for %s emulation)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"-h print this help\n"
|
"-h print this help\n"
|
||||||
|
"-g wait gdb connection to port %d\n"
|
||||||
"-L path set the elf interpreter prefix (default=%s)\n"
|
"-L path set the elf interpreter prefix (default=%s)\n"
|
||||||
"-s size set the stack size in bytes (default=%ld)\n"
|
"-s size set the stack size in bytes (default=%ld)\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -944,6 +999,7 @@ void usage(void)
|
|||||||
"-d options activate log (logfile=%s)\n"
|
"-d options activate log (logfile=%s)\n"
|
||||||
"-p pagesize set the host page size to 'pagesize'\n",
|
"-p pagesize set the host page size to 'pagesize'\n",
|
||||||
TARGET_ARCH,
|
TARGET_ARCH,
|
||||||
|
DEFAULT_GDBSTUB_PORT,
|
||||||
interp_prefix,
|
interp_prefix,
|
||||||
x86_stack_size,
|
x86_stack_size,
|
||||||
DEBUG_LOGFILE);
|
DEBUG_LOGFILE);
|
||||||
@ -967,6 +1023,7 @@ int main(int argc, char **argv)
|
|||||||
CPUState *env;
|
CPUState *env;
|
||||||
int optind;
|
int optind;
|
||||||
const char *r;
|
const char *r;
|
||||||
|
int use_gdbstub = 0;
|
||||||
|
|
||||||
if (argc <= 1)
|
if (argc <= 1)
|
||||||
usage();
|
usage();
|
||||||
@ -1020,6 +1077,8 @@ int main(int argc, char **argv)
|
|||||||
fprintf(stderr, "page size must be a power of two\n");
|
fprintf(stderr, "page size must be a power of two\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
} else if (!strcmp(r, "g")) {
|
||||||
|
use_gdbstub = 1;
|
||||||
} else
|
} else
|
||||||
#ifdef USE_CODE_COPY
|
#ifdef USE_CODE_COPY
|
||||||
if (!strcmp(r, "no-code-copy")) {
|
if (!strcmp(r, "no-code-copy")) {
|
||||||
@ -1176,6 +1235,10 @@ int main(int argc, char **argv)
|
|||||||
#error unsupported target CPU
|
#error unsupported target CPU
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (use_gdbstub) {
|
||||||
|
gdbserver_start (DEFAULT_GDBSTUB_PORT);
|
||||||
|
gdb_handlesig(env, 0);
|
||||||
|
}
|
||||||
cpu_loop(env);
|
cpu_loop(env);
|
||||||
/* never exits */
|
/* never exits */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
|
#include "gdbstub.h"
|
||||||
|
|
||||||
/* This struct is used to hold certain information about the image.
|
/* This struct is used to hold certain information about the image.
|
||||||
* Basically, it replicates in user space what would be certain
|
* Basically, it replicates in user space what would be certain
|
||||||
|
@ -1675,6 +1675,12 @@ void process_pending_signals(void *cpu_env)
|
|||||||
k->first = q->next;
|
k->first = q->next;
|
||||||
if (!k->first)
|
if (!k->first)
|
||||||
k->pending = 0;
|
k->pending = 0;
|
||||||
|
|
||||||
|
sig = gdb_handlesig (cpu_env, sig);
|
||||||
|
if (!sig) {
|
||||||
|
fprintf (stderr, "Lost signal\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
handler = k->sa._sa_handler;
|
handler = k->sa._sa_handler;
|
||||||
if (handler == TARGET_SIG_DFL) {
|
if (handler == TARGET_SIG_DFL) {
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
#include "softfloat.h"
|
#include "softfloat.h"
|
||||||
|
|
||||||
|
#define TARGET_HAS_ICE 1
|
||||||
|
|
||||||
#define EXCP_UDEF 1 /* undefined instruction */
|
#define EXCP_UDEF 1 /* undefined instruction */
|
||||||
#define EXCP_SWI 2 /* software interrupt */
|
#define EXCP_SWI 2 /* software interrupt */
|
||||||
#define EXCP_PREFETCH_ABORT 3
|
#define EXCP_PREFETCH_ABORT 3
|
||||||
@ -62,6 +64,11 @@ typedef struct CPUARMState {
|
|||||||
int user_mode_only;
|
int user_mode_only;
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
|
|
||||||
|
/* ICE debug support. */
|
||||||
|
target_ulong breakpoints[MAX_BREAKPOINTS];
|
||||||
|
int nb_breakpoints;
|
||||||
|
int singlestep_enabled;
|
||||||
|
|
||||||
/* in order to avoid passing too many arguments to the memory
|
/* in order to avoid passing too many arguments to the memory
|
||||||
write helpers, we store some rarely used information in the CPU
|
write helpers, we store some rarely used information in the CPU
|
||||||
context) */
|
context) */
|
||||||
|
@ -858,6 +858,12 @@ void OPPROTO op_undef_insn(void)
|
|||||||
cpu_loop_exit();
|
cpu_loop_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OPPROTO op_debug(void)
|
||||||
|
{
|
||||||
|
env->exception_index = EXCP_DEBUG;
|
||||||
|
cpu_loop_exit();
|
||||||
|
}
|
||||||
|
|
||||||
/* VFP support. We follow the convention used for VFP instrunctions:
|
/* VFP support. We follow the convention used for VFP instrunctions:
|
||||||
Single precition routines have a "s" suffix, double precision a
|
Single precition routines have a "s" suffix, double precision a
|
||||||
"d" suffix. */
|
"d" suffix. */
|
||||||
|
@ -2026,6 +2026,17 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
|||||||
dc->pc = pc_start;
|
dc->pc = pc_start;
|
||||||
lj = -1;
|
lj = -1;
|
||||||
do {
|
do {
|
||||||
|
if (env->nb_breakpoints > 0) {
|
||||||
|
for(j = 0; j < env->nb_breakpoints; j++) {
|
||||||
|
if (env->breakpoints[j] == dc->pc) {
|
||||||
|
gen_op_movl_T0_im((long)dc->pc);
|
||||||
|
gen_op_movl_reg_TN[0][15]();
|
||||||
|
gen_op_debug();
|
||||||
|
dc->is_jmp = DISAS_JUMP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (search_pc) {
|
if (search_pc) {
|
||||||
j = gen_opc_ptr - gen_opc_buf;
|
j = gen_opc_ptr - gen_opc_buf;
|
||||||
if (lj < j) {
|
if (lj < j) {
|
||||||
@ -2040,7 +2051,8 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
|||||||
disas_thumb_insn(dc);
|
disas_thumb_insn(dc);
|
||||||
else
|
else
|
||||||
disas_arm_insn(env, dc);
|
disas_arm_insn(env, dc);
|
||||||
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
|
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
|
||||||
|
!env->singlestep_enabled &&
|
||||||
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
|
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
|
||||||
switch(dc->is_jmp) {
|
switch(dc->is_jmp) {
|
||||||
case DISAS_JUMP_NEXT:
|
case DISAS_JUMP_NEXT:
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
close to the modifying instruction */
|
close to the modifying instruction */
|
||||||
#define TARGET_HAS_PRECISE_SMC
|
#define TARGET_HAS_PRECISE_SMC
|
||||||
|
|
||||||
|
#define TARGET_HAS_ICE 1
|
||||||
|
|
||||||
#include "cpu-defs.h"
|
#include "cpu-defs.h"
|
||||||
|
|
||||||
#include "softfloat.h"
|
#include "softfloat.h"
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
#include "softfloat.h"
|
#include "softfloat.h"
|
||||||
|
|
||||||
|
#define TARGET_HAS_ICE 1
|
||||||
|
|
||||||
/* Instruction types */
|
/* Instruction types */
|
||||||
enum {
|
enum {
|
||||||
PPC_NONE = 0x0000,
|
PPC_NONE = 0x0000,
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
#include "softfloat.h"
|
#include "softfloat.h"
|
||||||
|
|
||||||
|
#define TARGET_HAS_ICE 1
|
||||||
|
|
||||||
/*#define EXCP_INTERRUPT 0x100*/
|
/*#define EXCP_INTERRUPT 0x100*/
|
||||||
|
|
||||||
/* trap definitions */
|
/* trap definitions */
|
||||||
|
7
vl.h
7
vl.h
@ -71,6 +71,7 @@ static inline char *realpath(const char *path, char *resolved_path)
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
#include "gdbstub.h"
|
||||||
|
|
||||||
#endif /* !defined(QEMU_TOOL) */
|
#endif /* !defined(QEMU_TOOL) */
|
||||||
|
|
||||||
@ -829,10 +830,4 @@ const char *readline_get_history(unsigned int index);
|
|||||||
void readline_start(const char *prompt, int is_password,
|
void readline_start(const char *prompt, int is_password,
|
||||||
ReadLineFunc *readline_func, void *opaque);
|
ReadLineFunc *readline_func, void *opaque);
|
||||||
|
|
||||||
/* gdbstub.c */
|
|
||||||
|
|
||||||
#define DEFAULT_GDBSTUB_PORT 1234
|
|
||||||
|
|
||||||
int gdbserver_start(int port);
|
|
||||||
|
|
||||||
#endif /* VL_H */
|
#endif /* VL_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user