log activation from gdb - gdb single step support for x86 - stop timer when cpu is being debugged
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@402 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
0806e3f66f
commit
3486513433
@ -377,6 +377,10 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc);
|
|||||||
int cpu_breakpoint_remove(CPUState *env, uint32_t pc);
|
int cpu_breakpoint_remove(CPUState *env, uint32_t pc);
|
||||||
void cpu_single_step(CPUState *env, int enabled);
|
void cpu_single_step(CPUState *env, int enabled);
|
||||||
|
|
||||||
|
#define CPU_LOG_ALL 1
|
||||||
|
void cpu_set_log(int log_flags);
|
||||||
|
void cpu_set_log_filename(const char *filename);
|
||||||
|
|
||||||
/* memory API */
|
/* memory API */
|
||||||
|
|
||||||
typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value);
|
typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value);
|
||||||
|
23
exec.c
23
exec.c
@ -78,6 +78,11 @@ CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
|
|||||||
CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
|
CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
|
||||||
static int io_mem_nb;
|
static int io_mem_nb;
|
||||||
|
|
||||||
|
/* log support */
|
||||||
|
char *logfilename = "/tmp/qemu.log";
|
||||||
|
FILE *logfile;
|
||||||
|
int loglevel;
|
||||||
|
|
||||||
static void page_init(void)
|
static void page_init(void)
|
||||||
{
|
{
|
||||||
/* NOTE: we can always suppose that host_page_size >=
|
/* NOTE: we can always suppose that host_page_size >=
|
||||||
@ -676,6 +681,24 @@ void cpu_single_step(CPUState *env, int enabled)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* enable or disable low levels log */
|
||||||
|
void cpu_set_log(int log_flags)
|
||||||
|
{
|
||||||
|
loglevel = log_flags;
|
||||||
|
if (loglevel && !logfile) {
|
||||||
|
logfile = fopen(logfilename, "w");
|
||||||
|
if (!logfile) {
|
||||||
|
perror(logfilename);
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
setvbuf(logfile, NULL, _IOLBF, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_set_log_filename(const char *filename)
|
||||||
|
{
|
||||||
|
logfilename = strdup(filename);
|
||||||
|
}
|
||||||
|
|
||||||
/* mask must never be zero */
|
/* mask must never be zero */
|
||||||
void cpu_interrupt(CPUState *env, int mask)
|
void cpu_interrupt(CPUState *env, int mask)
|
||||||
|
17
gdbstub.c
17
gdbstub.c
@ -437,7 +437,24 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
|
|||||||
goto breakpoint_error;
|
goto breakpoint_error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'Q':
|
||||||
|
if (!strncmp(p, "Tinit", 5)) {
|
||||||
|
/* init traces */
|
||||||
|
put_packet("OK");
|
||||||
|
} else if (!strncmp(p, "TStart", 6)) {
|
||||||
|
/* start log (gdb 'tstart' command) */
|
||||||
|
cpu_set_log(CPU_LOG_ALL);
|
||||||
|
put_packet("OK");
|
||||||
|
} else if (!strncmp(p, "TStop", 5)) {
|
||||||
|
/* stop log (gdb 'tstop' command) */
|
||||||
|
cpu_set_log(0);
|
||||||
|
put_packet("OK");
|
||||||
|
} else {
|
||||||
|
goto unknown_command;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
|
unknown_command:
|
||||||
/* put empty packet */
|
/* put empty packet */
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
put_packet(buf);
|
put_packet(buf);
|
||||||
|
@ -60,6 +60,7 @@ typedef struct DisasContext {
|
|||||||
int cpl;
|
int cpl;
|
||||||
int iopl;
|
int iopl;
|
||||||
int tf; /* TF cpu flag */
|
int tf; /* TF cpu flag */
|
||||||
|
int singlestep_enabled; /* "hardware" single step enabled */
|
||||||
int jmp_opt; /* use direct block chaining for direct jumps */
|
int jmp_opt; /* use direct block chaining for direct jumps */
|
||||||
int mem_index; /* select memory access functions */
|
int mem_index; /* select memory access functions */
|
||||||
struct TranslationBlock *tb;
|
struct TranslationBlock *tb;
|
||||||
@ -1712,7 +1713,9 @@ static void gen_eob(DisasContext *s)
|
|||||||
{
|
{
|
||||||
if (s->cc_op != CC_OP_DYNAMIC)
|
if (s->cc_op != CC_OP_DYNAMIC)
|
||||||
gen_op_set_cc_op(s->cc_op);
|
gen_op_set_cc_op(s->cc_op);
|
||||||
if (s->tf) {
|
if (s->singlestep_enabled) {
|
||||||
|
gen_op_debug();
|
||||||
|
} else if (s->tf) {
|
||||||
gen_op_raise_exception(EXCP01_SSTP);
|
gen_op_raise_exception(EXCP01_SSTP);
|
||||||
} else {
|
} else {
|
||||||
gen_op_movl_T0_0();
|
gen_op_movl_T0_0();
|
||||||
@ -4368,6 +4371,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
|||||||
dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
|
dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
|
||||||
dc->iopl = (flags >> IOPL_SHIFT) & 3;
|
dc->iopl = (flags >> IOPL_SHIFT) & 3;
|
||||||
dc->tf = (flags >> TF_SHIFT) & 1;
|
dc->tf = (flags >> TF_SHIFT) & 1;
|
||||||
|
dc->singlestep_enabled = env->singlestep_enabled;
|
||||||
dc->cc_op = CC_OP_DYNAMIC;
|
dc->cc_op = CC_OP_DYNAMIC;
|
||||||
dc->cs_base = cs_base;
|
dc->cs_base = cs_base;
|
||||||
dc->tb = tb;
|
dc->tb = tb;
|
||||||
@ -4425,7 +4429,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
|||||||
break;
|
break;
|
||||||
/* if single step mode, we generate only one instruction and
|
/* if single step mode, we generate only one instruction and
|
||||||
generate an exception */
|
generate an exception */
|
||||||
if (dc->tf) {
|
if (dc->tf || dc->singlestep_enabled) {
|
||||||
gen_op_jmp_im(pc_ptr - dc->cs_base);
|
gen_op_jmp_im(pc_ptr - dc->cs_base);
|
||||||
gen_eob(dc);
|
gen_eob(dc);
|
||||||
break;
|
break;
|
||||||
|
101
vl.c
101
vl.c
@ -50,7 +50,6 @@
|
|||||||
|
|
||||||
#include "vl.h"
|
#include "vl.h"
|
||||||
|
|
||||||
#define DEBUG_LOGFILE "/tmp/vl.log"
|
|
||||||
#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
|
#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
|
||||||
#define BIOS_FILENAME "bios.bin"
|
#define BIOS_FILENAME "bios.bin"
|
||||||
#define VGABIOS_FILENAME "vgabios.bin"
|
#define VGABIOS_FILENAME "vgabios.bin"
|
||||||
@ -209,8 +208,6 @@ static const char *bios_dir = CONFIG_QEMU_SHAREDIR;
|
|||||||
char phys_ram_file[1024];
|
char phys_ram_file[1024];
|
||||||
CPUX86State *global_env;
|
CPUX86State *global_env;
|
||||||
CPUX86State *cpu_single_env;
|
CPUX86State *cpu_single_env;
|
||||||
FILE *logfile = NULL;
|
|
||||||
int loglevel;
|
|
||||||
IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
|
IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
|
||||||
IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
|
IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
|
||||||
BlockDriverState *bs_table[MAX_DISKS];
|
BlockDriverState *bs_table[MAX_DISKS];
|
||||||
@ -832,6 +829,69 @@ int speaker_data_on;
|
|||||||
int dummy_refresh_clock;
|
int dummy_refresh_clock;
|
||||||
int pit_min_timer_count = 0;
|
int pit_min_timer_count = 0;
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__powerpc__)
|
||||||
|
|
||||||
|
static inline uint32_t get_tbl(void)
|
||||||
|
{
|
||||||
|
uint32_t tbl;
|
||||||
|
asm volatile("mftb %0" : "=r" (tbl));
|
||||||
|
return tbl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t get_tbu(void)
|
||||||
|
{
|
||||||
|
uint32_t tbl;
|
||||||
|
asm volatile("mftbu %0" : "=r" (tbl));
|
||||||
|
return tbl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t cpu_get_real_ticks(void)
|
||||||
|
{
|
||||||
|
uint32_t l, h, h1;
|
||||||
|
/* NOTE: we test if wrapping has occurred */
|
||||||
|
do {
|
||||||
|
h = get_tbu();
|
||||||
|
l = get_tbl();
|
||||||
|
h1 = get_tbu();
|
||||||
|
} while (h != h1);
|
||||||
|
return ((int64_t)h << 32) | l;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__i386__)
|
||||||
|
|
||||||
|
int64_t cpu_get_real_ticks(void)
|
||||||
|
{
|
||||||
|
int64_t val;
|
||||||
|
asm("rdtsc" : "=A" (val));
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error unsupported CPU
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int64_t cpu_ticks_offset;
|
||||||
|
static int64_t cpu_ticks_last;
|
||||||
|
|
||||||
|
int64_t cpu_get_ticks(void)
|
||||||
|
{
|
||||||
|
return cpu_get_real_ticks() + cpu_ticks_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable cpu_get_ticks() */
|
||||||
|
void cpu_enable_ticks(void)
|
||||||
|
{
|
||||||
|
cpu_ticks_offset = cpu_ticks_last - cpu_get_real_ticks();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* disable cpu_get_ticks() : the clock is stopped. You must not call
|
||||||
|
cpu_get_ticks() after that. */
|
||||||
|
void cpu_disable_ticks(void)
|
||||||
|
{
|
||||||
|
cpu_ticks_last = cpu_get_ticks();
|
||||||
|
}
|
||||||
|
|
||||||
int64_t get_clock(void)
|
int64_t get_clock(void)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
@ -839,13 +899,6 @@ int64_t get_clock(void)
|
|||||||
return tv.tv_sec * 1000000LL + tv.tv_usec;
|
return tv.tv_sec * 1000000LL + tv.tv_usec;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t cpu_get_ticks(void)
|
|
||||||
{
|
|
||||||
int64_t val;
|
|
||||||
asm("rdtsc" : "=A" (val));
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_calibrate_ticks(void)
|
void cpu_calibrate_ticks(void)
|
||||||
{
|
{
|
||||||
int64_t usec, ticks;
|
int64_t usec, ticks;
|
||||||
@ -3297,12 +3350,17 @@ int main_loop(void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
serial_ok = 1;
|
serial_ok = 1;
|
||||||
|
cpu_enable_ticks();
|
||||||
for(;;) {
|
for(;;) {
|
||||||
ret = cpu_x86_exec(env);
|
ret = cpu_x86_exec(env);
|
||||||
if (reset_requested)
|
if (reset_requested) {
|
||||||
|
ret = EXCP_INTERRUPT;
|
||||||
break;
|
break;
|
||||||
if (ret == EXCP_DEBUG)
|
}
|
||||||
return EXCP_DEBUG;
|
if (ret == EXCP_DEBUG) {
|
||||||
|
ret = EXCP_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
/* if hlt instruction, we wait until the next IRQ */
|
/* if hlt instruction, we wait until the next IRQ */
|
||||||
if (ret == EXCP_HLT)
|
if (ret == EXCP_HLT)
|
||||||
timeout = 10;
|
timeout = 10;
|
||||||
@ -3359,10 +3417,12 @@ int main_loop(void *opaque)
|
|||||||
uint8_t buf[1];
|
uint8_t buf[1];
|
||||||
/* stop emulation if requested by gdb */
|
/* stop emulation if requested by gdb */
|
||||||
n = read(gdbstub_fd, buf, 1);
|
n = read(gdbstub_fd, buf, 1);
|
||||||
if (n == 1)
|
if (n == 1) {
|
||||||
|
ret = EXCP_INTERRUPT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* timer IRQ */
|
/* timer IRQ */
|
||||||
if (timer_irq_pending) {
|
if (timer_irq_pending) {
|
||||||
@ -3377,7 +3437,8 @@ int main_loop(void *opaque)
|
|||||||
gui_refresh_pending = 0;
|
gui_refresh_pending = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return EXCP_INTERRUPT;
|
cpu_disable_ticks();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void help(void)
|
void help(void)
|
||||||
@ -3535,7 +3596,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
loglevel = 1;
|
cpu_set_log(CPU_LOG_ALL);
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
pstrcpy(network_script, sizeof(network_script), optarg);
|
pstrcpy(network_script, sizeof(network_script), optarg);
|
||||||
@ -3563,14 +3624,6 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
/* init debug */
|
/* init debug */
|
||||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
if (loglevel) {
|
|
||||||
logfile = fopen(DEBUG_LOGFILE, "w");
|
|
||||||
if (!logfile) {
|
|
||||||
perror(DEBUG_LOGFILE);
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
setvbuf(logfile, NULL, _IOLBF, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* init network tun interface */
|
/* init network tun interface */
|
||||||
if (net_fd < 0)
|
if (net_fd < 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user