2003-11-28 18:07:29 +03:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2006-01-15 20:55:25 +03:00
|
|
|
// $Id: dbg_main.cc,v 1.33 2006-01-15 17:55:25 sshwarts Exp $
|
2003-11-28 18:07:29 +03:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Copyright (C) 2001 MandrakeSoft S.A.
|
|
|
|
//
|
|
|
|
// MandrakeSoft S.A.
|
|
|
|
// 43, rue d'Aboukir
|
|
|
|
// 75002 Paris - France
|
|
|
|
// http://www.linux-mandrake.com/
|
|
|
|
// http://www.mandrakesoft.com/
|
|
|
|
//
|
|
|
|
// 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, write to the Free Software
|
|
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
2006-01-15 20:55:25 +03:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include <signal.h>
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "bochs.h"
|
2004-06-19 19:20:15 +04:00
|
|
|
#include "iodev/iodev.h"
|
2003-11-28 18:07:29 +03:00
|
|
|
#if BX_DEBUGGER
|
|
|
|
|
|
|
|
#define LOG_THIS genlog->
|
|
|
|
|
|
|
|
#if HAVE_LIBREADLINE
|
|
|
|
extern "C" {
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <readline/readline.h>
|
|
|
|
#if HAVE_READLINE_HISTORY_H
|
|
|
|
#include <readline/history.h>
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-01-04 16:13:45 +03:00
|
|
|
|
2003-11-28 18:07:29 +03:00
|
|
|
static unsigned doit = 0;
|
|
|
|
|
|
|
|
#define SIM_NAME0 "bochs"
|
|
|
|
#ifndef SIM_NAME1_STR
|
|
|
|
#define SIM_NAME1_STR "sim1"
|
|
|
|
#endif
|
|
|
|
#define SIM_NAME(x) ((x == 0) ? SIM_NAME0 : SIM_NAME1_STR)
|
|
|
|
|
|
|
|
// default CPU in the debugger. For commands like "dump_cpu" it will
|
|
|
|
// use the default instead of always dumping all cpus.
|
2005-12-24 19:07:47 +03:00
|
|
|
|
2003-11-28 18:07:29 +03:00
|
|
|
Bit32u dbg_cpu = 0;
|
|
|
|
|
|
|
|
bx_param_bool_c *sim_running;
|
|
|
|
|
|
|
|
static void bx_dbg_usage(void);
|
|
|
|
static char bx_debug_rc_fname[BX_MAX_PATH];
|
|
|
|
static char tmp_buf[512];
|
|
|
|
static char tmp_buf_prev[512];
|
|
|
|
static char *tmp_buf_ptr;
|
|
|
|
static char *argv0 = NULL;
|
|
|
|
|
|
|
|
#if BX_NUM_SIMULATORS >= 2
|
|
|
|
#define BX_DBG_IO_JOURNAL_SIZE 1024
|
|
|
|
#define BX_DBG_UCMEM_JOURNAL_SIZE 1024
|
|
|
|
#define BX_DBG_ASYNC_JOURNAL_SIZE 1024
|
|
|
|
#define BX_DBG_MASTER_MODE 10
|
|
|
|
#define BX_DBG_SLAVE_MODE 11
|
|
|
|
// #define BX_DBG_DEFAULT_ICOUNT_QUANTUM 50
|
|
|
|
#define BX_DBG_DEFAULT_ICOUNT_QUANTUM 3 /* mch */
|
|
|
|
|
|
|
|
static unsigned bx_dbg_cosimulateN(bx_dbg_icount_t count);
|
|
|
|
static int bx_dbg_compare_sim_iaddr(void);
|
|
|
|
static bx_bool bx_dbg_compare_sim_cpu(void);
|
|
|
|
static bx_bool bx_dbg_compare_sim_memory(void);
|
|
|
|
static void bx_dbg_journal_a20_event(unsigned val);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static FILE *debugger_log = NULL;
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
#if BX_NUM_SIMULATORS >= 2
|
|
|
|
// some fields used only for cosimulation
|
|
|
|
unsigned icount_quantum;
|
|
|
|
unsigned master_slave_mode;
|
|
|
|
unsigned master, slave;
|
|
|
|
struct {
|
|
|
|
struct {
|
|
|
|
Bit8u op;
|
|
|
|
Bit8u len;
|
|
|
|
Bit16u addr;
|
|
|
|
Bit32u value;
|
2005-04-10 22:03:16 +04:00
|
|
|
} element[BX_DBG_IO_JOURNAL_SIZE];
|
2003-11-28 18:07:29 +03:00
|
|
|
unsigned size;
|
|
|
|
unsigned head, tail;
|
2005-04-10 22:03:16 +04:00
|
|
|
} IO_journal;
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
struct {
|
|
|
|
struct {
|
|
|
|
Bit8u op;
|
|
|
|
Bit8u len;
|
|
|
|
Bit32u addr;
|
|
|
|
Bit32u value;
|
2005-04-10 22:03:16 +04:00
|
|
|
} element[BX_DBG_UCMEM_JOURNAL_SIZE];
|
2003-11-28 18:07:29 +03:00
|
|
|
unsigned size;
|
|
|
|
unsigned head, tail;
|
2005-04-10 22:03:16 +04:00
|
|
|
} UCmem_journal;
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// need to handle DMA stuff in here...
|
|
|
|
|
|
|
|
#define BX_DBG_ASYNC_JOURNAL_NONE 0
|
|
|
|
#define BX_DBG_ASYNC_JOURNAL_A20 1
|
|
|
|
#define BX_DBG_ASYNC_JOURNAL_IAC 2
|
|
|
|
#define BX_DBG_ASYNC_JOURNAL_NMI 3
|
|
|
|
#define BX_DBG_ASYNC_JOURNAL_RESET 4
|
|
|
|
|
|
|
|
// Asynchronous events at the boundaries they are *taken* by the master simulator.
|
|
|
|
// These are replayed back to the slave at the same boundaries.
|
|
|
|
struct {
|
|
|
|
struct {
|
|
|
|
unsigned what; // A20, INTR, NMI, RESET, IAC, ...
|
|
|
|
bx_dbg_icount_t icount;
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
unsigned val;
|
2005-04-10 22:03:16 +04:00
|
|
|
} a20, nmi, reset, iac;
|
2003-11-28 18:07:29 +03:00
|
|
|
// perhaps other more complex types here
|
2005-04-10 22:03:16 +04:00
|
|
|
} u;
|
|
|
|
} element[BX_DBG_ASYNC_JOURNAL_SIZE];
|
2003-11-28 18:07:29 +03:00
|
|
|
unsigned size;
|
|
|
|
unsigned head, tail;
|
2005-04-10 22:03:16 +04:00
|
|
|
} async_journal;
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
struct {
|
|
|
|
bx_bool iaddr;
|
|
|
|
bx_bool cpu;
|
|
|
|
bx_bool memory;
|
2005-04-10 22:03:16 +04:00
|
|
|
} compare_at_sync;
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
bx_bool fast_forward_mode;
|
|
|
|
|
|
|
|
#endif // #if BX_NUM_SIMULATORS >= 2
|
|
|
|
|
|
|
|
// some fields used for single CPU debugger
|
|
|
|
bx_bool auto_disassemble;
|
|
|
|
unsigned disassemble_size;
|
|
|
|
char default_display_format;
|
|
|
|
char default_unit_size;
|
|
|
|
Bit32u default_addr;
|
|
|
|
unsigned next_bpoint_id;
|
|
|
|
|
|
|
|
// last icount known to be in sync
|
|
|
|
#if BX_DBG_ICOUNT_SIZE == 32
|
|
|
|
Bit32u last_sync_icount;
|
|
|
|
#else // BX_DBG_ICOUNT_SIZE == 64
|
|
|
|
Bit64u last_sync_icount;
|
|
|
|
#endif
|
2005-04-10 22:03:16 +04:00
|
|
|
} bx_debugger;
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// cosim commands for handling of comparison of simulator
|
|
|
|
// environments when both simulators have reached a common
|
|
|
|
// point (synchronized).
|
|
|
|
|
|
|
|
// cosim compare_at_sync iaddr (default is on)
|
|
|
|
// cosim compare_at_sync cpu (default is off)
|
|
|
|
// cosim compare_at_sync memory (default is off)
|
|
|
|
// cosim compare iaddr
|
|
|
|
// cosim compare cpu
|
|
|
|
// cosim compare memory
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
FILE *fp;
|
|
|
|
char fname[BX_MAX_PATH];
|
|
|
|
unsigned lineno;
|
2005-04-10 22:03:16 +04:00
|
|
|
} bx_infile_stack_entry_t;
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
bx_infile_stack_entry_t bx_infile_stack[BX_INFILE_DEPTH];
|
|
|
|
int bx_infile_stack_index = 0;
|
|
|
|
|
|
|
|
static int bx_nest_infile(char *path);
|
|
|
|
|
|
|
|
void bx_debug_ctrlc_handler(int signum);
|
|
|
|
|
|
|
|
static void bx_unnest_infile(void);
|
|
|
|
static void bx_get_command(void);
|
|
|
|
static void bx_dbg_print_guard_results();
|
|
|
|
static void bx_dbg_breakpoint_changed(void);
|
|
|
|
|
|
|
|
bx_dbg_callback_t bx_dbg_callback[BX_NUM_SIMULATORS];
|
|
|
|
bx_guard_t bx_guard;
|
|
|
|
|
|
|
|
|
|
|
|
// DMA stuff
|
|
|
|
void bx_dbg_post_dma_reports(void);
|
|
|
|
#define BX_BATCH_DMA_BUFSIZE 512
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
unsigned this_many; // batch this many max before posting events
|
|
|
|
unsigned Qsize; // this many have been batched
|
|
|
|
struct {
|
|
|
|
Bit32u addr; // address of DMA op
|
|
|
|
unsigned len; // number of bytes in op
|
|
|
|
unsigned what; // BX_READ or BX_WRITE
|
|
|
|
Bit32u val; // value of DMA op
|
|
|
|
bx_dbg_icount_t icount; // icount at this dma op
|
2005-04-08 22:30:34 +04:00
|
|
|
} Q[BX_BATCH_DMA_BUFSIZE];
|
|
|
|
} bx_dbg_batch_dma;
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
|
|
|
|
// some buffers for disassembly
|
|
|
|
#if BX_DISASM
|
|
|
|
static Bit8u bx_disasm_ibuf[32];
|
|
|
|
static char bx_disasm_tbuf[512];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void dbg_printf (const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
char *buf = new char[1024];
|
|
|
|
vsprintf (buf, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
if (debugger_log != NULL) {
|
|
|
|
fprintf(debugger_log,"%s", buf);
|
|
|
|
fflush(debugger_log);
|
2005-03-26 22:41:59 +03:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
SIM->debug_puts (buf); // send to debugger, which will free buf when done.
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
int bx_dbg_main(int argc, char *argv[])
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
int i, bochs_argc=0, sim1_argc=0, sim2_argc=0;
|
|
|
|
char **bochs_argv = NULL;
|
|
|
|
char **sim1_argv = NULL;
|
|
|
|
char **sim2_argv = NULL;
|
|
|
|
argc = 1;
|
|
|
|
|
|
|
|
setbuf (stdout, NULL);
|
|
|
|
setbuf (stderr, NULL);
|
|
|
|
|
|
|
|
bx_dbg_batch_dma.this_many = 1;
|
|
|
|
bx_dbg_batch_dma.Qsize = 0;
|
|
|
|
|
|
|
|
// initialize callback functions, and guard environment
|
|
|
|
memset(bx_dbg_callback, 0, sizeof(bx_dbg_callback));
|
|
|
|
memset(&bx_guard, 0, sizeof(bx_guard));
|
|
|
|
bx_guard.async.irq = 1;
|
|
|
|
bx_guard.async.dma = 1;
|
|
|
|
|
|
|
|
memset(&bx_debugger, 0, sizeof(bx_debugger));
|
|
|
|
#if BX_NUM_SIMULATORS >= 2
|
|
|
|
bx_debugger.icount_quantum = BX_DBG_DEFAULT_ICOUNT_QUANTUM;
|
|
|
|
bx_debugger.IO_journal.size = 0;
|
|
|
|
bx_debugger.IO_journal.head = 0;
|
|
|
|
bx_debugger.IO_journal.tail = 0;
|
|
|
|
bx_debugger.UCmem_journal.size = 0;
|
|
|
|
bx_debugger.UCmem_journal.head = 0;
|
|
|
|
bx_debugger.UCmem_journal.tail = 0;
|
|
|
|
bx_debugger.async_journal.size = 0;
|
|
|
|
bx_debugger.async_journal.head = 0;
|
|
|
|
bx_debugger.async_journal.tail = 0;
|
|
|
|
bx_debugger.master = 0;
|
|
|
|
bx_debugger.slave = 1;
|
|
|
|
bx_debugger.compare_at_sync.iaddr = 1;
|
|
|
|
bx_debugger.fast_forward_mode = 0;
|
|
|
|
#endif
|
|
|
|
bx_debugger.auto_disassemble = 1;
|
|
|
|
bx_debugger.disassemble_size = 0;
|
|
|
|
bx_debugger.default_display_format = 'x';
|
|
|
|
bx_debugger.default_unit_size = 'w';
|
|
|
|
bx_debugger.default_addr = 0;
|
|
|
|
bx_debugger.next_bpoint_id = 1;
|
|
|
|
bx_debugger.last_sync_icount = 0;
|
|
|
|
|
|
|
|
|
|
|
|
argv0 = strdup(argv[0]);
|
|
|
|
|
|
|
|
bx_debug_rc_fname[0] = '\0';
|
|
|
|
|
|
|
|
bochs_argv = (char **) &argv[0];
|
|
|
|
sim1_argv = bochs_argv; // start out with something reasonable
|
|
|
|
sim2_argv = bochs_argv; // start out with something reasonable
|
|
|
|
bochs_argc = 1;
|
|
|
|
sim1_argc = 1;
|
|
|
|
sim2_argc = 1;
|
|
|
|
|
|
|
|
// process "-rc pathname" option, if it exists
|
|
|
|
i = 1;
|
|
|
|
if ( (argc >= 2) && !strcmp(argv[1], "-rc") ) {
|
|
|
|
if ( argc == 2 ) {
|
2005-12-14 23:05:40 +03:00
|
|
|
BX_ERROR(("%s: -rc option used, but no path specified.",
|
2003-11-28 18:07:29 +03:00
|
|
|
argv[0] ));
|
|
|
|
bx_dbg_usage();
|
|
|
|
BX_EXIT(1);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
strncpy(bx_debug_rc_fname, argv[2], BX_MAX_PATH-1);
|
|
|
|
i += 2; // skip past "-rc" and filename
|
|
|
|
bochs_argv = (char **) &argv[2];
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// process options to bochs framework
|
|
|
|
for (; i<argc; i++) {
|
|
|
|
if (strcmp(argv[i], "-sim1") == 0) {
|
|
|
|
break;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if (strcmp(argv[i], "-sim2") == 0) {
|
|
|
|
break;
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
bochs_argc++;
|
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (i<argc) { // more args to process
|
|
|
|
// process options to each CPU simulator
|
|
|
|
if (strcmp(argv[i], "-sim1") == 0) {
|
|
|
|
process_sim1:
|
|
|
|
sim1_argv = (char **) &argv[i];
|
|
|
|
i++;
|
|
|
|
for (; i<argc; i++) {
|
|
|
|
if (strcmp(argv[i], "-sim2") == 0)
|
|
|
|
goto process_sim2;
|
|
|
|
sim1_argc++;
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if (strcmp(argv[i], "-sim2") == 0) {
|
|
|
|
process_sim2:
|
|
|
|
sim2_argv = (char **) &argv[i];
|
|
|
|
i++;
|
|
|
|
for (; i<argc; i++) {
|
|
|
|
if (strcmp(argv[i], "-sim1") == 0)
|
|
|
|
goto process_sim1;
|
|
|
|
sim2_argc++;
|
|
|
|
}
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
bx_infile_stack_index = 0;
|
|
|
|
bx_infile_stack[0].fp = stdin;
|
|
|
|
strncpy(bx_infile_stack[0].fname, argv[0], BX_MAX_PATH);
|
|
|
|
bx_infile_stack[0].fname[BX_MAX_PATH-1] = 0;
|
|
|
|
bx_infile_stack[0].lineno = 0;
|
|
|
|
|
|
|
|
if (bx_debug_rc_fname[0] == '\0') {
|
|
|
|
BX_INFO(("Warning: no rc file specified."));
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
|
|
|
BX_INFO (("%s: using rc file '%s'.", argv[0], bx_debug_rc_fname));
|
|
|
|
// if there's an error, the user will know about it before proceeding
|
|
|
|
(void) bx_nest_infile(bx_debug_rc_fname);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// Open debugger log file if needed
|
|
|
|
if ((strlen(bx_options.log.Odebugger_filename->getptr()) > 0)
|
|
|
|
&& (strcmp(bx_options.log.Odebugger_filename->getptr(), "-") != 0)) {
|
|
|
|
debugger_log = fopen (bx_options.log.Odebugger_filename->getptr(), "w");
|
|
|
|
if (!debugger_log) {
|
|
|
|
BX_PANIC(("Can not open debugger log file '%s'",
|
|
|
|
bx_options.log.Odebugger_filename->getptr()));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_INFO(("Using debugger log file %s",
|
|
|
|
bx_options.log.Odebugger_filename->getptr()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if BX_DISASM
|
|
|
|
memset(bx_disasm_ibuf, 0, sizeof(bx_disasm_ibuf));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
BX_SIM1_INIT(&bx_dbg_callback[0], sim1_argc, sim1_argv);
|
2005-04-10 22:03:16 +04:00
|
|
|
#if BX_NUM_SIMULATORS >= 2
|
2003-11-28 18:07:29 +03:00
|
|
|
BX_SIM2_INIT(&bx_dbg_callback[1], sim2_argc, sim2_argv);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// parse any remaining args in the usual way
|
|
|
|
bx_parse_cmdline (1, bochs_argc, bochs_argv);
|
|
|
|
|
|
|
|
// initialize hardware
|
|
|
|
bx_init_hardware();
|
|
|
|
|
|
|
|
#if BX_NUM_SIMULATORS >= 2
|
|
|
|
bx_debugger.compare_at_sync.cpu = 0;
|
|
|
|
bx_debugger.compare_at_sync.memory = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// call init routines for each CPU+mem simulator
|
|
|
|
// initialize for SMP. one memory, multiple processors.
|
|
|
|
|
|
|
|
#if BX_NUM_SIMULATORS > 1
|
|
|
|
#error cosimulation not supported until SMP stuff settles
|
|
|
|
BX_MEM(1) = new BX_MEM_C ();
|
|
|
|
BX_CPU(1) = new BX_CPU_C (BX_MEM(1));
|
|
|
|
BX_CPU(1)->reset(BX_RESET_HARDWARE);
|
|
|
|
BX_MEM(1)->init_memory(bx_options.memory.Osize->get () * 1024*1024);
|
|
|
|
BX_MEM(1)->load_ROM(bx_options.rom.path->getptr (), bx_options.rom.address->get (), 1);
|
|
|
|
BX_MEM(1)->load_ROM(bx_options.vgarom.path->getptr (), 0xc0000, 2);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// (mch) Moved from main.cc
|
|
|
|
DEV_init_devices();
|
|
|
|
DEV_reset_devices(BX_RESET_HARDWARE);
|
2004-11-01 15:53:45 +03:00
|
|
|
bx_gui->init_signal_handlers ();
|
|
|
|
bx_pc_system.start_timers();
|
|
|
|
|
2005-11-09 20:17:06 +03:00
|
|
|
// Just like in main.cc before set_init_done()
|
|
|
|
if (bx_options.load32bitOSImage.OwhichOS->get ()) {
|
|
|
|
void bx_load32bitOSimagehack(void);
|
|
|
|
bx_load32bitOSimagehack();
|
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
SIM->set_init_done (1);
|
|
|
|
|
|
|
|
// update headerbar buttons since drive status can change during init
|
|
|
|
bx_gui->update_drive_status_buttons ();
|
2004-11-01 15:53:45 +03:00
|
|
|
// iniialize statusbar and set all items inactive
|
|
|
|
bx_gui->statusbar_setitem(-1, 0);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// create a boolean parameter that will tell if the simulation is
|
|
|
|
// running (continue command) or waiting for user response. This affects
|
|
|
|
// some parts of the GUI.
|
|
|
|
sim_running = new bx_param_bool_c (BXP_DEBUG_RUNNING,
|
|
|
|
"Simulation is running", "",
|
|
|
|
0);
|
|
|
|
|
|
|
|
// setup Ctrl-C handler
|
|
|
|
if (!SIM->is_wx_selected ()) {
|
|
|
|
signal(SIGINT, bx_debug_ctrlc_handler);
|
|
|
|
BX_INFO (("set SIGINT handler to bx_debug_ctrlc_handler"));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print disassembly of the first instruction... you wouldn't think it
|
|
|
|
// would have to be so hard. First initialize guard_found, since it is used
|
|
|
|
// in the disassembly code to decide what instruction to print.
|
|
|
|
for (i=0; i<BX_SMP_PROCESSORS; i++) {
|
2006-01-15 20:55:25 +03:00
|
|
|
BX_CPU(i)->guard_found.cs = BX_CPU(i)->sregs[BX_SEG_REG_CS].selector.value;
|
|
|
|
BX_CPU(i)->guard_found.eip = BX_CPU(i)->prev_eip;
|
2003-11-28 18:07:29 +03:00
|
|
|
BX_CPU(i)->guard_found.laddr =
|
2006-01-15 20:55:25 +03:00
|
|
|
BX_CPU(i)->get_segment_base(BX_SEG_REG_CS) + BX_CPU(i)->prev_eip;
|
2003-11-28 18:07:29 +03:00
|
|
|
BX_CPU(i)->guard_found.is_32bit_code =
|
|
|
|
BX_CPU(i)->sregs[BX_SEG_REG_CS].cache.u.segment.d_b;
|
|
|
|
}
|
|
|
|
// finally, call the usual function to print the disassembly
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Next at t=" FMT_LL "d\n", bx_pc_system.time_ticks ());
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_disassemble_current (-1, 0); // all cpus, don't print time
|
|
|
|
|
|
|
|
bx_dbg_user_input_loop();
|
|
|
|
|
|
|
|
if (debugger_log != NULL)
|
|
|
|
fclose(debugger_log);
|
|
|
|
|
|
|
|
bx_dbg_exit(0);
|
|
|
|
return(0); // keep compiler happy
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_usage(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("usage: %s [-rc path] [-sim1 ... ] [-sim2 ... ]\n", argv0);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_interpret_line (char *cmd)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
bx_add_lex_input (cmd);
|
|
|
|
bxparse ();
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_user_input_loop(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
int reti;
|
|
|
|
unsigned include_cmd_len = strlen(BX_INCLUDE_CMD);
|
|
|
|
|
|
|
|
while ( 1 ) {
|
|
|
|
SIM->refresh_ci ();
|
|
|
|
SIM->set_display_mode (DISP_MODE_CONFIG);
|
|
|
|
bx_get_command();
|
|
|
|
reparse:
|
|
|
|
if ((*tmp_buf_ptr == '\n') || (*tmp_buf_ptr == 0))
|
2005-04-08 22:30:34 +04:00
|
|
|
{
|
2003-11-28 18:07:29 +03:00
|
|
|
if ((*tmp_buf_prev != '\n') && (*tmp_buf_prev != 0)) {
|
|
|
|
strncpy(tmp_buf, tmp_buf_prev, sizeof(tmp_buf_prev));
|
|
|
|
goto reparse;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( (strncmp(tmp_buf_ptr, BX_INCLUDE_CMD, include_cmd_len) == 0) &&
|
|
|
|
(tmp_buf_ptr[include_cmd_len] == ' ' ||
|
2005-04-08 22:30:34 +04:00
|
|
|
tmp_buf_ptr[include_cmd_len] == '\t') )
|
|
|
|
{
|
2003-11-28 18:07:29 +03:00
|
|
|
char *ptr;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
ptr = tmp_buf_ptr + include_cmd_len+1;
|
|
|
|
while ( *ptr==' ' || *ptr=='\t' )
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
len = strlen(ptr);
|
|
|
|
if (len == 0) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%s: no filename given to 'source' command.\n", argv0);
|
2003-11-28 18:07:29 +03:00
|
|
|
if (bx_infile_stack_index > 0) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%s: ERROR in source file causes exit.\n", argv0);
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
continue;
|
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
ptr[len-1] = 0; // get rid of newline
|
|
|
|
reti = bx_nest_infile(ptr);
|
|
|
|
if ((reti==0) && (bx_infile_stack_index > 0)) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%s: ERROR in source file causes exit.\n", argv0);
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
|
|
|
// Give a chance to the command line extensions, to
|
|
|
|
// consume the command. If they return 0, then
|
|
|
|
// we need to process the command. A return of 1
|
|
|
|
// means, the extensions have handled the command
|
|
|
|
if ( bx_dbg_extensions(tmp_buf_ptr)==0 ) {
|
|
|
|
// process command here
|
|
|
|
bx_add_lex_input(tmp_buf_ptr);
|
|
|
|
bxparse();
|
|
|
|
}
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_get_command(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
char *charptr_ret;
|
|
|
|
|
|
|
|
bx_infile_stack[bx_infile_stack_index].lineno++;
|
|
|
|
|
|
|
|
char prompt[256];
|
|
|
|
if (bx_infile_stack_index == 0) {
|
|
|
|
sprintf(prompt, "<bochs:%d> ", bx_infile_stack[bx_infile_stack_index].lineno);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
if (SIM->is_wx_selected() && bx_infile_stack_index == 0) {
|
2005-01-05 22:54:32 +03:00
|
|
|
// wait for wxWidgets to send another debugger command
|
2003-11-28 18:07:29 +03:00
|
|
|
charptr_ret = SIM->debug_get_next_command ();
|
|
|
|
if (charptr_ret) {
|
|
|
|
strncpy (tmp_buf, charptr_ret, sizeof(tmp_buf));
|
|
|
|
strcat (tmp_buf, "\n");
|
|
|
|
// The returned string was allocated in wxmain.cc by "new char[]".
|
|
|
|
// Free it with delete[].
|
|
|
|
delete [] charptr_ret;
|
|
|
|
charptr_ret = &tmp_buf[0];
|
|
|
|
} else {
|
|
|
|
// if debug_get_next_command returned NULL, probably the GUI is
|
|
|
|
// shutting down
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if HAVE_LIBREADLINE
|
|
|
|
else if (bx_infile_stack_index == 0) {
|
|
|
|
charptr_ret = readline (prompt);
|
|
|
|
// beware, returns NULL on end of file
|
|
|
|
if (charptr_ret && strlen(charptr_ret) > 0) {
|
|
|
|
add_history (charptr_ret);
|
|
|
|
strcpy (tmp_buf, charptr_ret);
|
|
|
|
strcat (tmp_buf, "\n");
|
|
|
|
free (charptr_ret);
|
|
|
|
charptr_ret = &tmp_buf[0];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
charptr_ret = fgets(tmp_buf, sizeof(tmp_buf),
|
|
|
|
bx_infile_stack[bx_infile_stack_index].fp);
|
|
|
|
}
|
|
|
|
#else /* !HAVE_LIBREADLINE */
|
|
|
|
else {
|
|
|
|
if (bx_infile_stack_index == 0)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%s", prompt);
|
2003-11-28 18:07:29 +03:00
|
|
|
strncpy(tmp_buf_prev, tmp_buf, sizeof(tmp_buf));
|
|
|
|
charptr_ret = fgets(tmp_buf, sizeof(tmp_buf),
|
|
|
|
bx_infile_stack[bx_infile_stack_index].fp);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (charptr_ret == NULL) {
|
|
|
|
// see if error was due to EOF condition
|
|
|
|
if (feof(bx_infile_stack[bx_infile_stack_index].fp)) {
|
|
|
|
if (bx_infile_stack_index > 0) {
|
|
|
|
// nested level of include files, pop back to previous one
|
|
|
|
bx_unnest_infile();
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
|
|
|
// not nested, sitting at stdin prompt, user wants out
|
|
|
|
bx_dbg_quit_command();
|
2005-04-08 22:30:34 +04:00
|
|
|
BX_PANIC (("bx_dbg_quit_command should not return, but it did"));
|
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// call recursively
|
|
|
|
bx_get_command();
|
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// error was not EOF, see if it was from a Ctrl-C
|
|
|
|
if (bx_guard.interrupt_requested) {
|
|
|
|
tmp_buf[0] = '\n';
|
|
|
|
tmp_buf[1] = 0;
|
|
|
|
tmp_buf_ptr = &tmp_buf[0];
|
|
|
|
bx_guard.interrupt_requested = 0;
|
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("fgets() returned ERROR.\n");
|
|
|
|
dbg_printf ("intr request was %u\n", bx_guard.interrupt_requested);
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
tmp_buf_ptr = &tmp_buf[0];
|
|
|
|
|
|
|
|
if (debugger_log != NULL) {
|
|
|
|
fprintf(debugger_log, "%s", tmp_buf);
|
|
|
|
fflush(debugger_log);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// look for first non-whitespace character
|
2006-01-15 20:55:25 +03:00
|
|
|
while (((*tmp_buf_ptr == ' ') || (*tmp_buf_ptr == '\t')) &&
|
2005-04-08 22:30:34 +04:00
|
|
|
(*tmp_buf_ptr != '\n') && (*tmp_buf_ptr != 0) )
|
|
|
|
{
|
2003-11-28 18:07:29 +03:00
|
|
|
tmp_buf_ptr++;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
int bx_nest_infile(char *path)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
FILE *tmp_fp;
|
|
|
|
|
|
|
|
tmp_fp = fopen(path, "r");
|
|
|
|
if (!tmp_fp) {
|
2006-01-15 20:55:25 +03:00
|
|
|
dbg_printf ("%s: can not open file '%s' for reading.\n", argv0, path);
|
2003-11-28 18:07:29 +03:00
|
|
|
return(0);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if ( (bx_infile_stack_index+1) >= BX_INFILE_DEPTH ) {
|
2005-04-08 22:30:34 +04:00
|
|
|
dbg_printf ("%s: source files nested too deeply\n", argv0);
|
2003-11-28 18:07:29 +03:00
|
|
|
return(0);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
bx_infile_stack_index++;
|
|
|
|
bx_infile_stack[bx_infile_stack_index].fp = tmp_fp;
|
|
|
|
strncpy(bx_infile_stack[bx_infile_stack_index].fname, path, BX_MAX_PATH);
|
|
|
|
bx_infile_stack[bx_infile_stack_index].fname[BX_MAX_PATH-1] = 0;
|
|
|
|
bx_infile_stack[bx_infile_stack_index].lineno = 0;
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_unnest_infile(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
if (bx_infile_stack_index <= 0) {
|
2005-04-08 22:30:34 +04:00
|
|
|
dbg_printf ("%s: ERROR: unnest_infile(): nesting level = 0.\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
argv0);
|
|
|
|
bx_dbg_exit(1);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
fclose(bx_infile_stack[bx_infile_stack_index].fp);
|
|
|
|
bx_infile_stack_index--;
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
int bxwrap(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
2005-04-08 22:30:34 +04:00
|
|
|
dbg_printf ("%s: ERROR: bxwrap() called.\n", argv0);
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
|
|
|
return(0); // keep compiler quiet
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bxerror(char *s)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
2005-04-08 22:30:34 +04:00
|
|
|
dbg_printf ("%s:%d: %s at '%s'\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_infile_stack[bx_infile_stack_index].fname,
|
|
|
|
bx_infile_stack[bx_infile_stack_index].lineno,
|
|
|
|
s, bxtext);
|
|
|
|
|
|
|
|
if (bx_infile_stack_index > 0) {
|
2005-04-08 22:30:34 +04:00
|
|
|
dbg_printf ("%s: ERROR in source file causes exit.\n", argv0);
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
2005-03-26 22:41:59 +03:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_debug_ctrlc_handler(int signum)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
UNUSED(signum);
|
|
|
|
if (SIM->is_wx_selected ()) {
|
|
|
|
// in a multithreaded environment, a signal such as SIGINT can be sent to all
|
|
|
|
// threads. This function is only intended to handle signals in the
|
|
|
|
// simulator thread. It will simply return if called from any other thread.
|
|
|
|
// Otherwise the BX_PANIC() below can be called in multiple threads at
|
|
|
|
// once, leading to multiple threads trying to display a dialog box,
|
|
|
|
// leading to GUI deadlock.
|
|
|
|
if (!SIM->is_sim_thread ()) {
|
|
|
|
BX_INFO (("bx_signal_handler: ignored sig %d because it wasn't called from the simulator thread", signum));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BX_INFO(("Ctrl-C detected in signal handler."));
|
|
|
|
|
|
|
|
signal(SIGINT, bx_debug_ctrlc_handler);
|
|
|
|
bx_debug_break ();
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_debug_break ()
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
bx_guard.interrupt_requested = 1;
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_exit(int code)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
2005-12-14 23:05:40 +03:00
|
|
|
BX_DEBUG(("dbg: before sim1_exit" ));
|
2003-11-28 18:07:29 +03:00
|
|
|
for (int cpu=0; cpu < BX_SMP_PROCESSORS; cpu++) {
|
|
|
|
if (BX_CPU(cpu)) BX_CPU(cpu)->atexit();
|
|
|
|
}
|
|
|
|
|
|
|
|
#if BX_NUM_SIMULATORS >= 2
|
2005-04-10 22:03:16 +04:00
|
|
|
dbg_printf ("before sim2_exit\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
if (BX_CPU(1)) BX_CPU(1)->atexit();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bx_atexit();
|
|
|
|
BX_EXIT(code);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
2006-01-15 20:55:25 +03:00
|
|
|
// commands invoked from parser
|
2003-11-28 18:07:29 +03:00
|
|
|
//
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_quit_command(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
BX_INFO(("dbg: Quit"));
|
|
|
|
bx_dbg_exit(0);
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_trace_on_command(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
BX_CPU(dbg_cpu)->trace = 1;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Tracing enabled for %s\n", BX_CPU(dbg_cpu)->name);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_trace_off_command(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
BX_CPU(dbg_cpu)->trace = 0;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Tracing disabled for %s\n", BX_CPU(dbg_cpu)->name);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_trace_reg_on_command(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
BX_CPU(dbg_cpu)->trace_reg = 1;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Register-Tracing enabled for %s\n", BX_CPU(dbg_cpu)->name);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_trace_reg_off_command(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
BX_CPU(dbg_cpu)->trace_reg = 0;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Register-Tracing disabled for %s\n", BX_CPU(dbg_cpu)->name);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_ptime_command(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("ptime: " FMT_LL "d\n", bx_pc_system.time_ticks());
|
2003-11-28 18:07:29 +03:00
|
|
|
#if BX_NUM_SIMULATORS >= 2
|
|
|
|
dbg_printf (
|
|
|
|
#if BX_DBG_ICOUNT_SIZE == 32
|
|
|
|
"Last synchronized icount was %lu\n",
|
|
|
|
(unsigned long) bx_debugger.last_sync_icount
|
|
|
|
#else // BX_DBG_ICOUNT_SIZE == 64
|
|
|
|
"Last synchronized icount was %Lu\n",
|
|
|
|
(unsigned long long) bx_debugger.last_sync_icount
|
|
|
|
#endif /* BX_DBG_ICOUNT_SIZE == 32 */
|
|
|
|
);
|
|
|
|
#endif /* BX_NUM_SIMULATORS >= 2 */
|
|
|
|
}
|
|
|
|
|
|
|
|
int timebp_timer = -1;
|
|
|
|
Bit64u timebp_queue[MAX_CONCURRENT_BPS];
|
|
|
|
int timebp_queue_size = 0;
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_timebp_command(bx_bool absolute, Bit64u time)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
Bit64u diff = (absolute) ? time - bx_pc_system.time_ticks() : time;
|
|
|
|
Bit64u abs_time = (absolute) ? time : time + bx_pc_system.time_ticks();
|
|
|
|
|
|
|
|
if (time < bx_pc_system.time_ticks()) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Request for time break point in the past. I can't let you do that.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (timebp_queue_size == MAX_CONCURRENT_BPS) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Too many time break points\n");
|
2005-03-26 22:41:59 +03:00
|
|
|
return;
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (timebp_timer >= 0) {
|
|
|
|
if (timebp_queue_size == 0 || abs_time < timebp_queue[0]) {
|
|
|
|
/* first in queue */
|
|
|
|
for (int i = timebp_queue_size; i >= 0; i--)
|
|
|
|
timebp_queue[i+1] = timebp_queue[i];
|
|
|
|
timebp_queue[0] = abs_time;
|
|
|
|
timebp_queue_size++;
|
|
|
|
bx_pc_system.activate_timer_ticks(timebp_timer, diff, 1);
|
|
|
|
} else {
|
|
|
|
/* not first, insert at suitable place */
|
|
|
|
for (int i = 1; i < timebp_queue_size; i++) {
|
|
|
|
if (timebp_queue[i] == abs_time) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Time breakpoint not inserted (duplicate)\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
} else if (abs_time < timebp_queue[i]) {
|
|
|
|
for (int j = timebp_queue_size; j >= i; j++)
|
|
|
|
timebp_queue[j+1] = timebp_queue[j];
|
|
|
|
timebp_queue[i] = abs_time;
|
|
|
|
goto inserted;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* last */
|
|
|
|
timebp_queue[timebp_queue_size] = abs_time;
|
|
|
|
inserted:
|
|
|
|
timebp_queue_size++;
|
|
|
|
}
|
|
|
|
} else {
|
2005-03-26 22:41:59 +03:00
|
|
|
timebp_queue_size = 1;
|
|
|
|
timebp_queue[0] = abs_time;
|
|
|
|
timebp_timer = bx_pc_system.register_timer_ticks(&bx_pc_system, bx_pc_system_c::timebp_handler, diff, 0, 1, "debug.timebp");
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Time breakpoint inserted. Delta = " FMT_LL "u\n", diff);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2006-01-15 20:55:25 +03:00
|
|
|
Bit32u conv_4xBit8u_to_Bit32u (const Bit8u* buf)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
Bit32u ret = 0;
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
ret |= (buf[i] << (8 * i));
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_record_command(char* path_quoted)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
2005-04-08 22:30:34 +04:00
|
|
|
// skip beginning double quote
|
|
|
|
if (path_quoted[0] == '"')
|
|
|
|
path_quoted++;
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2005-04-08 22:30:34 +04:00
|
|
|
// null out ending quote
|
|
|
|
int len = strlen(path_quoted);
|
|
|
|
if (path_quoted[len - 1] == '"')
|
|
|
|
path_quoted[len - 1] = '\0';
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2005-04-08 22:30:34 +04:00
|
|
|
bx_dbg.record_io = fopen(path_quoted, "w");
|
|
|
|
if (bx_dbg.record_io)
|
|
|
|
dbg_printf ("IO record file '%s' opened\n", path_quoted);
|
|
|
|
else
|
|
|
|
dbg_printf ("Error opening '%s' for writing\n", path_quoted);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static FILE* playback_file = 0;
|
|
|
|
|
|
|
|
struct playback_entry_t
|
|
|
|
{
|
|
|
|
char command[100];
|
|
|
|
Bit32u argument;
|
|
|
|
|
|
|
|
void trigger ();
|
|
|
|
};
|
|
|
|
|
|
|
|
static playback_entry_t playback_entry;
|
|
|
|
static Bit64u last_playback_time = 0;
|
|
|
|
static int playback_timer_index = -1;
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_playback_command(char* path_quoted)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
// skip beginning double quote
|
|
|
|
if (path_quoted[0] == '"')
|
|
|
|
path_quoted++;
|
|
|
|
|
|
|
|
// null out ending quote
|
|
|
|
int len = strlen(path_quoted);
|
|
|
|
if (path_quoted[len - 1] == '"')
|
|
|
|
path_quoted[len - 1] = '\0';
|
|
|
|
|
|
|
|
playback_file = fopen(path_quoted, "r");
|
|
|
|
if (playback_file) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Playback from '%s'\n", path_quoted);
|
2003-11-28 18:07:29 +03:00
|
|
|
last_playback_time = 0;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("playback times relative from " FMT_LL "d\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_pc_system.time_ticks());
|
|
|
|
enter_playback_entry();
|
2005-04-08 22:30:34 +04:00
|
|
|
} else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error opening '%s' for reading\n", path_quoted);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// BW added. toggles vm86 mode switch breakpoint
|
|
|
|
//dummy not used and may be null
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_modebp_command(char* dummy)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
BX_CPU(dbg_cpu)->debug_vm = BX_CPU(dbg_cpu)->getB_VM ();
|
|
|
|
BX_CPU(dbg_cpu)->mode_break = !BX_CPU(dbg_cpu)->mode_break;
|
|
|
|
dbg_printf (" mode switch break %s\n",
|
|
|
|
BX_CPU(dbg_cpu)->mode_break ? "enabled" : "disabled");
|
|
|
|
}
|
|
|
|
|
|
|
|
// where
|
|
|
|
// stack trace: ebp -> old ebp
|
|
|
|
// return eip at ebp + 4
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_where_command()
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
if (!BX_CPU(dbg_cpu)->protected_mode()) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("'where' only supported in protected mode\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
if (BX_CPU(dbg_cpu)->get_segment_base(BX_SEG_REG_SS) != 0) {
|
|
|
|
dbg_printf ("non-zero stack base\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
}
|
2005-11-27 21:25:57 +03:00
|
|
|
Bit32u bp = BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_EBP);
|
|
|
|
Bit32u ip = BX_CPU(dbg_cpu)->get_ip();
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%d) 0x%08x\n", 0, ip);
|
2003-11-28 18:07:29 +03:00
|
|
|
for (int i = 1; i < 50; i++) {
|
|
|
|
// Up
|
|
|
|
bx_bool paddr_valid;
|
|
|
|
Bit32u paddr;
|
|
|
|
Bit8u buf[4];
|
|
|
|
|
|
|
|
// bp = [bp];
|
|
|
|
BX_CPU(dbg_cpu)->dbg_xlate_linear2phy(bp, &paddr, &paddr_valid);
|
|
|
|
if (paddr_valid) {
|
|
|
|
if (BX_MEM(0)->dbg_fetch_mem(paddr, 4, buf)) {
|
|
|
|
bp = conv_4xBit8u_to_Bit32u(buf);
|
|
|
|
} else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%d) Physical memory read error (BP)\n", i);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%d) Could not translate linear address (BP)\n", i);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ip = [bp + 4];
|
|
|
|
BX_CPU(dbg_cpu)->dbg_xlate_linear2phy(bp + 4, &paddr, &paddr_valid);
|
|
|
|
if (paddr_valid) {
|
|
|
|
if (BX_MEM(0)->dbg_fetch_mem(paddr, 4, buf)) {
|
|
|
|
ip = conv_4xBit8u_to_Bit32u(buf);
|
|
|
|
} else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%d) Physical memory read error (IP)\n", i);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%d) Could not translate linear address (IP)\n", i);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%d) 0x%08x\n", i, ip);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_print_string_command(Bit32u start_addr)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("0x%08x: ", start_addr);
|
2003-11-28 18:07:29 +03:00
|
|
|
for (int i = 0; ; i++) {
|
|
|
|
Bit32u paddr;
|
|
|
|
bx_bool paddr_valid;
|
|
|
|
Bit8u buf[1];
|
|
|
|
BX_CPU(dbg_cpu)->dbg_xlate_linear2phy(start_addr+i, &paddr, &paddr_valid);
|
|
|
|
if (paddr_valid) {
|
|
|
|
if (BX_MEM(0)->dbg_fetch_mem(paddr, 1, buf)) {
|
|
|
|
if (buf[0] == 0)
|
|
|
|
break;
|
|
|
|
if (isgraph(buf[0]) || buf[0] == 0x20)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%c", buf[0]);
|
2003-11-28 18:07:29 +03:00
|
|
|
else
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("\\%d", buf[0]);
|
2003-11-28 18:07:29 +03:00
|
|
|
} else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("<read error>");
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("<no translation>");
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static bx_address last_cr3;
|
|
|
|
static bx_bool last_pe = 0;
|
|
|
|
static bx_bool last_vm = 0;
|
|
|
|
|
|
|
|
unsigned int dbg_show_mask = 0;
|
|
|
|
// 0x80 print mode
|
|
|
|
// 0x40 print interrupts
|
|
|
|
// 0x20 print calls
|
|
|
|
|
|
|
|
//BW added. toggles show symbolic info (calls to begin with)
|
|
|
|
// 0x1 call
|
|
|
|
// 0x2 return
|
|
|
|
// 0x4 int
|
|
|
|
// 0x8 iret
|
|
|
|
// 0x10 interrupts (includes iret)
|
|
|
|
|
|
|
|
static void dbg_dump_table(bx_bool);
|
|
|
|
|
|
|
|
void bx_dbg_show_command(char* arg)
|
|
|
|
{
|
|
|
|
if(arg) {
|
|
|
|
if (!strcmp(arg,"\"mode\"")){
|
|
|
|
dbg_show_mask = 0x80;
|
|
|
|
} else if (!strcmp(arg,"\"int\"")){
|
|
|
|
dbg_show_mask = 0xc0;
|
|
|
|
} else if(!strcmp(arg,"\"call\"")){
|
|
|
|
dbg_show_mask = 0xe0;
|
|
|
|
} else if(!strcmp(arg,"\"ret\"")){
|
|
|
|
dbg_show_mask = 0xe0;
|
|
|
|
} else if(!strcmp(arg,"\"off\"")){
|
|
|
|
dbg_show_mask = 0x0;
|
|
|
|
} else if(!strcmp(arg,"\"tab\"")){
|
|
|
|
dbg_dump_table(1);
|
|
|
|
return;
|
|
|
|
} else if(!strcmp(arg,"\"c\"")){
|
|
|
|
dbg_dump_table(0);
|
|
|
|
return;
|
|
|
|
} else if(!strcmp(arg,"\"dbg-all\"")){
|
|
|
|
bx_dbg.floppy = 1;
|
|
|
|
bx_dbg.keyboard = 1;
|
|
|
|
bx_dbg.video = 1;
|
|
|
|
bx_dbg.disk = 1;
|
|
|
|
bx_dbg.pit = 1;
|
|
|
|
bx_dbg.pic = 1;
|
|
|
|
bx_dbg.bios = 1;
|
|
|
|
bx_dbg.cmos = 1;
|
|
|
|
bx_dbg.a20 = 1;
|
|
|
|
bx_dbg.interrupts = 1;
|
|
|
|
bx_dbg.exceptions = 1;
|
|
|
|
bx_dbg.unsupported = 1;
|
|
|
|
bx_dbg.temp = 1;
|
|
|
|
bx_dbg.reset = 1;
|
|
|
|
bx_dbg.mouse = 1;
|
|
|
|
bx_dbg.io = 1;
|
|
|
|
bx_dbg.debugger = 1;
|
|
|
|
bx_dbg.xms = 1;
|
|
|
|
bx_dbg.v8086 = 1;
|
|
|
|
bx_dbg.paging = 1;
|
|
|
|
bx_dbg.creg = 1;
|
|
|
|
bx_dbg.dreg = 1;
|
|
|
|
bx_dbg.dma = 1;
|
|
|
|
bx_dbg.unsupported_io = 1;
|
|
|
|
/* bx_dbg.record_io = 1; this is a pointer .. somewhere */
|
|
|
|
printf("Turned on all bx_dbg flags\n");
|
|
|
|
return;
|
|
|
|
} else if(!strcmp(arg,"\"none\"")){
|
|
|
|
bx_dbg.floppy = 0;
|
|
|
|
bx_dbg.keyboard = 0;
|
|
|
|
bx_dbg.video = 0;
|
|
|
|
bx_dbg.disk = 0;
|
|
|
|
bx_dbg.pit = 0;
|
|
|
|
bx_dbg.pic = 0;
|
|
|
|
bx_dbg.bios = 0;
|
|
|
|
bx_dbg.cmos = 0;
|
|
|
|
bx_dbg.a20 = 0;
|
|
|
|
bx_dbg.interrupts = 0;
|
|
|
|
bx_dbg.exceptions = 0;
|
|
|
|
bx_dbg.unsupported = 0;
|
|
|
|
bx_dbg.temp = 0;
|
|
|
|
bx_dbg.reset = 0;
|
|
|
|
bx_dbg.mouse = 0;
|
|
|
|
bx_dbg.io = 0;
|
|
|
|
bx_dbg.debugger = 0;
|
|
|
|
bx_dbg.xms = 0;
|
|
|
|
bx_dbg.v8086 = 0;
|
|
|
|
bx_dbg.paging = 0;
|
|
|
|
bx_dbg.creg = 0;
|
|
|
|
bx_dbg.dreg = 0;
|
|
|
|
bx_dbg.dma = 0;
|
|
|
|
bx_dbg.unsupported_io = 0;
|
|
|
|
/* bx_dbg.record_io = 0; this is a pointer .. somewhere */
|
|
|
|
printf("Turned off all bx_dbg flags\n");
|
|
|
|
return;
|
|
|
|
} else if(!strcmp(arg,"\"vga\"")){
|
|
|
|
DEV_vga_refresh();
|
|
|
|
return;
|
|
|
|
} else {
|
2004-09-19 11:56:49 +04:00
|
|
|
printf("Unrecognized arg: %s (\"mode\" \"int\" \"call\" \"ret\" \"off\" \"tab\" \"c\" \"dbg-all\" \"none\" are valid)\n",arg);
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dbg_printf (" show mask is 0x%x\n", dbg_show_mask);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// enable trace if any print is active
|
|
|
|
if(dbg_show_mask & 0xe0)
|
|
|
|
dbg_show_mask |= 0x1f;
|
|
|
|
|
|
|
|
dbg_printf (" show mask is 0x%x, cleared show_flag\n", dbg_show_mask);
|
|
|
|
BX_CPU(dbg_cpu)->show_flag = 0;
|
|
|
|
last_cr3 = BX_CPU(dbg_cpu)->cr3;
|
|
|
|
last_pe = BX_CPU(dbg_cpu)->cr0.pe;
|
|
|
|
last_vm = BX_CPU(dbg_cpu)->getB_VM ();
|
|
|
|
|
2004-09-19 22:38:09 +04:00
|
|
|
dbg_printf (FMT_TICK ": address %04x:%08x %08x\n\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_pc_system.time_ticks(),
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.cs,
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.eip,
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.laddr);
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void playback_function(void* this_ptr)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
((playback_entry_t*)this_ptr)->trigger();
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void enter_playback_entry()
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
static const int playback_buf_size = 100;
|
|
|
|
char playback_buf[playback_buf_size];
|
|
|
|
if (!fgets(playback_buf, playback_buf_size, playback_file))
|
|
|
|
return;
|
|
|
|
|
|
|
|
Bit64u time;
|
|
|
|
if (sscanf(playback_buf, "%s " FMT_LL "d %x", playback_entry.command, &time, &playback_entry.argument) != 3) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Parse error in playback string '%s'\n", playback_buf);
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bit64u diff = time - last_playback_time;
|
|
|
|
last_playback_time = time;
|
|
|
|
|
|
|
|
if (time < last_playback_time) {
|
|
|
|
BX_PANIC(("Negative diff in playback"));
|
|
|
|
} else if (diff == 0) {
|
|
|
|
playback_entry.trigger();
|
|
|
|
} else {
|
|
|
|
if (playback_timer_index >= 0)
|
|
|
|
bx_pc_system.activate_timer_ticks(playback_timer_index, diff, 0);
|
|
|
|
else
|
|
|
|
playback_timer_index = bx_pc_system.register_timer_ticks(&playback_entry, playback_function, diff, 0, 1, "debug.playback");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void playback_entry_t::trigger ()
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
if (!strcmp("gen_scancode", command)) {
|
|
|
|
DEV_kbd_gen_scancode(argument);
|
|
|
|
} else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Unknown playback command '%s'\n", command);
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
enter_playback_entry();
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_print_stack_command(int nwords)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
// Get linear address for stack top
|
2005-06-10 00:08:17 +04:00
|
|
|
bx_bool UseESP=BX_CPU(dbg_cpu)->sregs[BX_SEG_REG_SS].cache.u.segment.d_b;
|
2005-04-08 22:30:34 +04:00
|
|
|
Bit32u linear_sp = BX_CPU(dbg_cpu)->get_segment_base(BX_SEG_REG_SS)+
|
2005-11-27 21:25:57 +03:00
|
|
|
(UseESP ? BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_ESP)
|
|
|
|
: BX_CPU(dbg_cpu)->get_reg16(BX_16BIT_REG_SP));
|
2003-11-28 18:07:29 +03:00
|
|
|
Bit8u buf[8];
|
|
|
|
|
|
|
|
for (int i = 0; i < nwords; i++) {
|
|
|
|
Bit32u paddr;
|
|
|
|
bx_bool paddr_valid;
|
|
|
|
BX_CPU(dbg_cpu)->dbg_xlate_linear2phy(linear_sp, &paddr, &paddr_valid);
|
|
|
|
if (paddr_valid) {
|
|
|
|
if (BX_MEM(0)->dbg_fetch_mem(paddr, (UseESP?4:2), buf))
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf (" %08x [%08x] %04x\n", linear_sp, paddr,
|
2003-11-28 18:07:29 +03:00
|
|
|
(Bit32u)buf[0] | ((Bit32u)buf[1] << 8) |
|
|
|
|
(UseESP?(((Bit32u)buf[2] << 16) | ((Bit32u)buf[3] << 24)):0));
|
|
|
|
else
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf (" %08x [%08x] <read error>\n", linear_sp, paddr);
|
2003-11-28 18:07:29 +03:00
|
|
|
} else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf (" %08x <could not translate>\n", linear_sp);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
linear_sp += (UseESP?4:2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int num_write_watchpoints = 0;
|
|
|
|
int num_read_watchpoints = 0;
|
|
|
|
Bit32u write_watchpoint[MAX_WRITE_WATCHPOINTS];
|
|
|
|
Bit32u read_watchpoint[MAX_READ_WATCHPOINTS];
|
|
|
|
bx_bool watchpoint_continue = 0;
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_watch(int read, Bit32u address)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
if (read == -1) {
|
|
|
|
// print watch point info
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < num_read_watchpoints; i++) {
|
|
|
|
Bit8u buf[2];
|
|
|
|
if (BX_MEM(0)->dbg_fetch_mem(read_watchpoint[i], 2, buf))
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("read %08x (%04x)\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
read_watchpoint[i], (int)buf[0] | ((int)buf[1] << 8));
|
|
|
|
else
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("read %08x (read error)\n", read_watchpoint[i]);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
for (i = 0; i < num_write_watchpoints; i++) {
|
|
|
|
Bit8u buf[2];
|
|
|
|
if (BX_MEM(0)->dbg_fetch_mem(write_watchpoint[i], 2, buf))
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("write %08x (%04x)\n", write_watchpoint[i], (int)buf[0] | ((int)buf[1] << 8));
|
2003-11-28 18:07:29 +03:00
|
|
|
else
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("write %08x (read error)\n", write_watchpoint[i]);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (read) {
|
|
|
|
if (num_read_watchpoints == MAX_READ_WATCHPOINTS) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Too many read watchpoints\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
read_watchpoint[num_read_watchpoints++] = address;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Read watchpoint at %08x inserted\n", address);
|
2003-11-28 18:07:29 +03:00
|
|
|
} else {
|
|
|
|
if (num_write_watchpoints == MAX_WRITE_WATCHPOINTS) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Too many write watchpoints\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
write_watchpoint[num_write_watchpoints++] = address;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Write watchpoint at %08x inserted\n", address);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_unwatch(int read, Bit32u address)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
if (read == -1) {
|
|
|
|
// unwatch all
|
|
|
|
num_read_watchpoints = num_write_watchpoints = 0;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("All watchpoints removed\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
} else {
|
|
|
|
if (read) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Watchpoint remove not implemented\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
} else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Watchpoint remove not implemented\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_continue_command(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
// continue executing, until a guard found
|
|
|
|
|
2005-04-10 22:03:16 +04:00
|
|
|
one_more:
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
#if BX_NUM_SIMULATORS >= 2
|
|
|
|
bx_guard.interrupt_requested = 0;
|
|
|
|
bx_guard.special_unwind_stack = 0;
|
|
|
|
while (1) {
|
|
|
|
if ( !bx_dbg_cosimulateN(bx_debugger.icount_quantum) )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
bx_guard.icount = 0;
|
|
|
|
// I must guard for ICOUNT or one CPU could run forever without giving
|
|
|
|
// the others a chance.
|
|
|
|
bx_guard.guard_for |= BX_DBG_GUARD_ICOUNT;
|
|
|
|
bx_guard.guard_for |= BX_DBG_GUARD_CTRL_C; // stop on Ctrl-C
|
|
|
|
|
|
|
|
// update gui (disable continue command, enable stop command, etc.)
|
|
|
|
sim_running->set (1);
|
|
|
|
SIM->refresh_ci ();
|
|
|
|
|
|
|
|
// use simulation mode while executing instructions. When the prompt
|
|
|
|
// is printed, we will return to config mode.
|
|
|
|
SIM->set_display_mode (DISP_MODE_SIM);
|
|
|
|
|
|
|
|
bx_guard.interrupt_requested = 0;
|
|
|
|
bx_guard.special_unwind_stack = 0;
|
|
|
|
int stop = 0;
|
|
|
|
int which = -1;
|
2005-11-10 21:14:18 +03:00
|
|
|
while (!stop && !bx_guard.interrupt_requested) {
|
2003-11-28 18:07:29 +03:00
|
|
|
// the quantum is an arbitrary number of cycles to run in each
|
|
|
|
// processor. In SMP mode, when this limit is reached, the
|
|
|
|
// cpu_loop exits so that another processor can be simulated
|
|
|
|
// for a few cycles. With a single processor, the quantum
|
|
|
|
// setting should have no effect, although a low setting does
|
|
|
|
// lead to poor performance because cpu_loop is returning and
|
|
|
|
// getting called again, over and over.
|
|
|
|
int quantum = 25;
|
|
|
|
int cpu;
|
|
|
|
for (cpu=0; cpu < BX_SMP_PROCESSORS; cpu++) {
|
|
|
|
BX_CPU(cpu)->guard_found.guard_found = 0;
|
|
|
|
BX_CPU(cpu)->guard_found.icount = 0;
|
|
|
|
bx_guard.icount = quantum;
|
|
|
|
BX_CPU(cpu)->cpu_loop (-1);
|
|
|
|
/// check out BX_CPU(cpu)->guard_found.icount
|
2005-12-14 23:05:40 +03:00
|
|
|
//dbg_printf ("dbg_cont: after cpu_loop guard_found.icount=%d\n", BX_CPU(cpu)->guard_found.icount);
|
2003-11-28 18:07:29 +03:00
|
|
|
// set stop flag if a guard found other than icount or halted
|
|
|
|
unsigned long found = BX_CPU(cpu)->guard_found.guard_found;
|
|
|
|
stop_reason_t reason = (stop_reason_t) BX_CPU(cpu)->stop_reason;
|
2004-01-17 11:36:29 +03:00
|
|
|
if (found == BX_DBG_GUARD_ICOUNT) {
|
2003-11-28 18:07:29 +03:00
|
|
|
// I expected this guard, don't stop
|
|
|
|
} else if (found!=0) {
|
|
|
|
stop = 1;
|
|
|
|
which = cpu;
|
|
|
|
} else if (reason != STOP_NO_REASON && reason != STOP_CPU_HALTED) {
|
|
|
|
stop = 1;
|
|
|
|
which = cpu;
|
|
|
|
}
|
|
|
|
// even if stop==1, finish cycling through all processors.
|
|
|
|
// "which" remembers which cpu set the stop flag. If multiple
|
|
|
|
// cpus set stop, too bad.
|
|
|
|
}
|
|
|
|
// increment time tick only after all processors have had their chance.
|
|
|
|
#if BX_SMP_PROCESSORS==1
|
|
|
|
// all ticks are handled inside the cpu loop
|
|
|
|
#else
|
|
|
|
// We must tick by the number of instructions that were
|
|
|
|
// ACTUALLY executed, not the number that we asked it to
|
|
|
|
// execute. Even this is tricky with SMP because one might
|
|
|
|
// have hit a breakpoint, while others executed the whole
|
|
|
|
// quantum.
|
|
|
|
int max_executed = 0;
|
|
|
|
for (cpu=0; cpu<BX_SMP_PROCESSORS; cpu++) {
|
|
|
|
if (BX_CPU(cpu)->guard_found.icount > max_executed)
|
|
|
|
max_executed = BX_CPU(cpu)->guard_found.icount;
|
|
|
|
}
|
|
|
|
// potential deadlock if all processors are halted. Then
|
|
|
|
// max_executed will be 0, tick will be incremented by zero, and
|
|
|
|
// there will never be a timed event to wake them up. To avoid this,
|
|
|
|
// always tick by a minimum of 1.
|
|
|
|
if (max_executed < 1) max_executed=1;
|
|
|
|
|
|
|
|
BX_TICKN(max_executed);
|
|
|
|
#endif /* BX_SMP_PROCESSORS>1 */
|
|
|
|
}
|
|
|
|
#endif /* BX_NUM_SIMULATORS */
|
|
|
|
|
|
|
|
sim_running->set (0);
|
|
|
|
SIM->refresh_ci ();
|
|
|
|
|
|
|
|
// (mch) hack
|
|
|
|
DEV_vga_refresh();
|
|
|
|
|
|
|
|
BX_INSTR_DEBUG_PROMPT();
|
|
|
|
bx_dbg_print_guard_results();
|
|
|
|
|
|
|
|
if (watchpoint_continue && (BX_CPU(which)->stop_reason == STOP_READ_WATCH_POINT ||
|
|
|
|
BX_CPU(which)->stop_reason == STOP_WRITE_WATCH_POINT))
|
|
|
|
goto one_more;
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_stepN_command(bx_dbg_icount_t count)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
if (count == 0) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: stepN: count=0\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
2005-03-26 22:41:59 +03:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// use simulation mode while executing instructions. When the prompt
|
|
|
|
// is printed, we will return to config mode.
|
|
|
|
SIM->set_display_mode (DISP_MODE_SIM);
|
|
|
|
|
|
|
|
#if BX_NUM_SIMULATORS >= 2
|
|
|
|
bx_guard.interrupt_requested = 0;
|
|
|
|
bx_guard.special_unwind_stack = 0;
|
|
|
|
bx_dbg_cosimulateN(count);
|
|
|
|
#else
|
|
|
|
// single CPU
|
|
|
|
bx_guard.guard_for |= BX_DBG_GUARD_ICOUNT; // looking for icount
|
|
|
|
bx_guard.guard_for |= BX_DBG_GUARD_CTRL_C; // or Ctrl-C
|
|
|
|
// for now, step each CPU one BX_DBG_DEFAULT_ICOUNT_QUANTUM at a time
|
|
|
|
//BX_INFO(("Stepping each CPU a total of %d cycles", count));
|
|
|
|
for (unsigned cycle=0; cycle < count; cycle++) {
|
|
|
|
for (unsigned cpu=0; cpu < BX_SMP_PROCESSORS; cpu++) {
|
|
|
|
//BX_INFO(("Stepping %s", BX_CPU(cpu)->name));
|
|
|
|
bx_guard.icount = 1;
|
|
|
|
bx_guard.interrupt_requested = 0;
|
|
|
|
BX_CPU(cpu)->guard_found.guard_found = 0;
|
|
|
|
BX_CPU(cpu)->guard_found.icount = 0;
|
|
|
|
BX_CPU(cpu)->cpu_loop(-1);
|
|
|
|
}
|
|
|
|
#if BX_SMP_PROCESSORS==1
|
|
|
|
// ticks are handled inside the cpu loop
|
|
|
|
#else
|
|
|
|
BX_TICK1 ();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
//BX_INFO(("Stepped each CPU a total of %d cycles", count));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
BX_INSTR_DEBUG_PROMPT();
|
|
|
|
bx_dbg_print_guard_results();
|
|
|
|
}
|
|
|
|
|
2004-01-04 16:13:45 +03:00
|
|
|
static disassembler bx_disassemble;
|
|
|
|
|
2003-11-28 18:07:29 +03:00
|
|
|
void bx_dbg_disassemble_current (int which_cpu, int print_time)
|
|
|
|
{
|
|
|
|
Bit32u phy;
|
|
|
|
bx_bool valid;
|
|
|
|
|
|
|
|
if (which_cpu < 0) {
|
|
|
|
// iterate over all of them.
|
|
|
|
for (int i=0; i<BX_SMP_PROCESSORS; i++)
|
|
|
|
bx_dbg_disassemble_current (i, print_time);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BX_CPU(which_cpu)->dbg_xlate_linear2phy(BX_CPU(which_cpu)->guard_found.laddr, &phy, &valid);
|
|
|
|
|
|
|
|
if (valid) {
|
|
|
|
unsigned ilen;
|
|
|
|
|
|
|
|
BX_CPU(which_cpu)->mem->dbg_fetch_mem(phy, 16, bx_disasm_ibuf);
|
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
unsigned cpu_mode = BX_CPU(which_cpu)->get_cpu_mode();
|
2005-11-22 01:26:58 +03:00
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
ilen = bx_disassemble.disasm(BX_CPU(which_cpu)->guard_found.is_32bit_code,
|
|
|
|
cpu_mode == BX_MODE_LONG_64 /* is_64 */,
|
|
|
|
BX_CPU(which_cpu)->get_segment_base(BX_SEG_REG_CS),
|
|
|
|
BX_CPU(which_cpu)->guard_found.eip, bx_disasm_ibuf, bx_disasm_tbuf);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// Note: it would be nice to display only the modified registers here, the easy
|
|
|
|
// way out I have thought of would be to keep a prev_eax, prev_ebx, etc copies
|
|
|
|
// in each cpu description (see cpu/cpu.h) and update/compare those "prev" values
|
|
|
|
// from here. (eks)
|
|
|
|
if( BX_CPU(dbg_cpu)->trace_reg )
|
|
|
|
dbg_printf (
|
|
|
|
"eax: %08X\tecx: %08X\tedx: %08X\tebx: %08X\tesp: %08X\tebp: %08X\tesi: %08X\tedi: %08X\ncf=%u af=%u zf=%u sf=%u of=%u pf=%u tf=%u if=%u df=%u iopl=%u nt=%u rf=%u vm=%u\n",
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(which_cpu)->get_reg32(BX_32BIT_REG_EAX),
|
|
|
|
BX_CPU(which_cpu)->get_reg32(BX_32BIT_REG_ECX),
|
|
|
|
BX_CPU(which_cpu)->get_reg32(BX_32BIT_REG_EDX),
|
|
|
|
BX_CPU(which_cpu)->get_reg32(BX_32BIT_REG_EBX),
|
|
|
|
BX_CPU(which_cpu)->get_reg32(BX_32BIT_REG_ESP),
|
|
|
|
BX_CPU(which_cpu)->get_reg32(BX_32BIT_REG_EBP),
|
|
|
|
BX_CPU(which_cpu)->get_reg32(BX_32BIT_REG_ESI),
|
|
|
|
BX_CPU(which_cpu)->get_reg32(BX_32BIT_REG_EDI),
|
2003-11-28 18:07:29 +03:00
|
|
|
BX_CPU(which_cpu)->getB_CF(),
|
|
|
|
BX_CPU(which_cpu)->getB_AF(),
|
|
|
|
BX_CPU(which_cpu)->getB_ZF(),
|
|
|
|
BX_CPU(which_cpu)->getB_SF(),
|
|
|
|
BX_CPU(which_cpu)->getB_OF(),
|
|
|
|
BX_CPU(which_cpu)->getB_PF(),
|
|
|
|
BX_CPU(which_cpu)->getB_TF (),
|
|
|
|
BX_CPU(which_cpu)->getB_IF (),
|
|
|
|
BX_CPU(which_cpu)->getB_DF (),
|
|
|
|
BX_CPU(which_cpu)->get_IOPL (),
|
|
|
|
BX_CPU(which_cpu)->getB_NT (),
|
|
|
|
BX_CPU(which_cpu)->getB_RF (),
|
|
|
|
BX_CPU(which_cpu)->getB_VM ());
|
|
|
|
|
|
|
|
if (print_time)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%u).[" FMT_LL "d] ", which_cpu, bx_pc_system.time_ticks());
|
2003-11-28 18:07:29 +03:00
|
|
|
else
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%u) ", which_cpu);
|
|
|
|
if (BX_CPU(which_cpu)->get_cpu_mode() == BX_MODE_IA32_PROTECTED) { // 16bit & 32bit protected mode
|
|
|
|
dbg_printf ("[0x%08x] %04x:%08x (%s): ",
|
2003-11-28 18:07:29 +03:00
|
|
|
phy,
|
|
|
|
(unsigned) BX_CPU(which_cpu)->guard_found.cs,
|
|
|
|
(unsigned) BX_CPU(which_cpu)->guard_found.eip,
|
2005-04-08 22:30:34 +04:00
|
|
|
bx_dbg_symbolic_address((BX_CPU(which_cpu)->cr3) >> 12, BX_CPU(which_cpu)->guard_found.eip, BX_CPU(which_cpu)->get_segment_base(BX_SEG_REG_CS)));
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
else { // Real & V86 mode
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("[0x%08x] %04x:%04x (%s): ",
|
2003-11-28 18:07:29 +03:00
|
|
|
phy,
|
|
|
|
(unsigned) BX_CPU(which_cpu)->guard_found.cs,
|
|
|
|
(unsigned) BX_CPU(which_cpu)->guard_found.eip,
|
|
|
|
bx_dbg_symbolic_address_16bit(BX_CPU(which_cpu)->guard_found.eip, BX_CPU(which_cpu)->sregs[BX_SEG_REG_CS].selector.value));
|
|
|
|
}
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%-25s ; ", bx_disasm_tbuf);
|
2003-11-28 18:07:29 +03:00
|
|
|
for (unsigned j=0; j<ilen; j++)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%02x", (unsigned) bx_disasm_ibuf[j]);
|
|
|
|
dbg_printf ("\n");
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%u).[" FMT_LL "d] ??? (physical address not available)\n", which_cpu, bx_pc_system.time_ticks());
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_print_guard_results(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
unsigned sim;
|
|
|
|
|
|
|
|
for (sim=0; sim<BX_SMP_PROCESSORS; sim++) {
|
|
|
|
unsigned long found = BX_CPU(sim)->guard_found.guard_found;
|
|
|
|
if (found & BX_DBG_GUARD_ICOUNT) {
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if (found & BX_DBG_GUARD_CTRL_C) {
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
#if BX_DBG_SUPPORT_VIR_BPOINT
|
|
|
|
else if (found & BX_DBG_GUARD_IADDR_VIR) {
|
|
|
|
i = BX_CPU(sim)->guard_found.iaddr_index;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%u) Breakpoint %u, 0x%x (0x%x:0x%x)\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
sim,
|
|
|
|
bx_guard.iaddr.vir[i].bpoint_id,
|
|
|
|
BX_CPU(sim)->guard_found.laddr,
|
|
|
|
BX_CPU(sim)->guard_found.cs,
|
|
|
|
BX_CPU(sim)->guard_found.eip);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if BX_DBG_SUPPORT_LIN_BPOINT
|
|
|
|
else if (found & BX_DBG_GUARD_IADDR_LIN) {
|
|
|
|
i = BX_CPU(sim)->guard_found.iaddr_index;
|
|
|
|
if (bx_guard.iaddr.lin[i].bpoint_id != 0)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%u) Breakpoint %u, 0x%x in ?? ()\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
sim,
|
|
|
|
bx_guard.iaddr.lin[i].bpoint_id,
|
|
|
|
BX_CPU(sim)->guard_found.laddr);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if BX_DBG_SUPPORT_PHY_BPOINT
|
|
|
|
else if (found & BX_DBG_GUARD_IADDR_PHY) {
|
|
|
|
i = BX_CPU(sim)->guard_found.iaddr_index;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%u) Breakpoint %u, 0x%x in ?? ()\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
sim,
|
|
|
|
bx_guard.iaddr.phy[i].bpoint_id,
|
|
|
|
BX_CPU(sim)->guard_found.laddr);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else if (BX_CPU(sim)->stop_reason == STOP_CPU_HALTED) {
|
|
|
|
/* returned early because processor is in halt state */
|
|
|
|
}
|
|
|
|
else if (BX_CPU(sim)->stop_reason == STOP_MAGIC_BREAK_POINT) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%u) Magic breakpoint\n", sim);
|
2003-11-28 18:07:29 +03:00
|
|
|
} else if (BX_CPU(sim)->stop_reason == STOP_TIME_BREAK_POINT) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%u) Caught time breakpoint\n", sim);
|
2003-11-28 18:07:29 +03:00
|
|
|
} else if (BX_CPU(sim)->stop_reason == STOP_MODE_BREAK_POINT) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%u) Caught vm mode switch breakpoint to %s mode\n",
|
2005-04-08 22:30:34 +04:00
|
|
|
sim, BX_CPU(sim)->get_VM () ? "virtual 86" : "protected");
|
2003-11-28 18:07:29 +03:00
|
|
|
} else if (BX_CPU(sim)->stop_reason == STOP_READ_WATCH_POINT) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%u) Caught read watch point at %08X\n", sim, BX_CPU(sim)->watchpoint);
|
2003-11-28 18:07:29 +03:00
|
|
|
} else if (BX_CPU(sim)->stop_reason == STOP_WRITE_WATCH_POINT) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("(%u) Caught write watch point at %08X\n", sim, BX_CPU(sim)->watchpoint);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: (%u) print_guard_results: guard_found ? (stop reason %u)\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
sim, BX_CPU(sim)->stop_reason);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
#if BX_DISASM
|
|
|
|
if (bx_debugger.auto_disassemble) {
|
|
|
|
if (sim==0) {
|
|
|
|
// print this only once
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Next at t=" FMT_LL "d\n", bx_pc_system.time_ticks ());
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
bx_dbg_disassemble_current (sim, 0); // one cpu, don't print time
|
|
|
|
}
|
|
|
|
#endif // #if BX_DISASM
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
// print the TSC value for every CPU
|
|
|
|
for (sim=0; sim<BX_SMP_PROCESSORS; sim++) {
|
|
|
|
dbg_printf ("TSC[%d] = " FMT_LL "d\n", sim, BX_CPU(sim)->tsc);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_breakpoint_changed(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
#if BX_DBG_SUPPORT_VIR_BPOINT
|
|
|
|
if (bx_guard.iaddr.num_virtual)
|
|
|
|
bx_guard.guard_for |= BX_DBG_GUARD_IADDR_VIR;
|
|
|
|
else
|
|
|
|
bx_guard.guard_for &= ~BX_DBG_GUARD_IADDR_VIR;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BX_DBG_SUPPORT_LIN_BPOINT
|
|
|
|
if (bx_guard.iaddr.num_linear)
|
|
|
|
bx_guard.guard_for |= BX_DBG_GUARD_IADDR_LIN;
|
|
|
|
else
|
|
|
|
bx_guard.guard_for &= ~BX_DBG_GUARD_IADDR_LIN;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BX_DBG_SUPPORT_PHY_BPOINT
|
|
|
|
if (bx_guard.iaddr.num_physical)
|
|
|
|
bx_guard.guard_for |= BX_DBG_GUARD_IADDR_PHY;
|
|
|
|
else
|
|
|
|
bx_guard.guard_for &= ~BX_DBG_GUARD_IADDR_PHY;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_en_dis_breakpoint_command(unsigned handle, bx_bool enable)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
#if BX_DBG_SUPPORT_VIR_BPOINT
|
|
|
|
if (bx_dbg_en_dis_vbreak (handle, enable))
|
|
|
|
goto done;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BX_DBG_SUPPORT_LIN_BPOINT
|
|
|
|
if (bx_dbg_en_dis_lbreak (handle, enable))
|
|
|
|
goto done;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BX_DBG_SUPPORT_PHY_BPOINT
|
|
|
|
if (bx_dbg_en_dis_pbreak (handle, enable))
|
|
|
|
goto done;
|
|
|
|
#endif
|
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: breakpoint %u not found.\n", handle);
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
done:
|
|
|
|
bx_dbg_breakpoint_changed();
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
bx_bool bx_dbg_en_dis_pbreak (unsigned handle, bx_bool enable)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
#if BX_DBG_SUPPORT_PHY_BPOINT
|
|
|
|
// see if breakpoint is a physical breakpoint
|
|
|
|
for (unsigned i=0; i<bx_guard.iaddr.num_physical; i++) {
|
|
|
|
if (bx_guard.iaddr.phy[i].bpoint_id == handle) {
|
|
|
|
bx_guard.iaddr.phy[i].enabled=enable;
|
|
|
|
return (bx_bool)true;
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
|
|
|
return (bx_bool)false;
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
bx_bool bx_dbg_en_dis_lbreak (unsigned handle, bx_bool enable)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
#if BX_DBG_SUPPORT_LIN_BPOINT
|
|
|
|
// see if breakpoint is a linear breakpoint
|
|
|
|
for (unsigned i=0; i<bx_guard.iaddr.num_linear; i++) {
|
|
|
|
if (bx_guard.iaddr.lin[i].bpoint_id == handle) {
|
|
|
|
bx_guard.iaddr.lin[i].enabled=enable;
|
|
|
|
return (bx_bool)true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return (bx_bool)false;
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
bx_bool bx_dbg_en_dis_vbreak (unsigned handle, bx_bool enable)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
#if BX_DBG_SUPPORT_VIR_BPOINT
|
|
|
|
// see if breakpoint is a virtual breakpoint
|
|
|
|
for (unsigned i=0; i<bx_guard.iaddr.num_virtual; i++) {
|
|
|
|
if (bx_guard.iaddr.vir[i].bpoint_id == handle) {
|
|
|
|
bx_guard.iaddr.vir[i].enabled=enable;
|
|
|
|
return (bx_bool)true;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
|
|
|
return (bx_bool)false;
|
2005-03-26 22:41:59 +03:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_del_breakpoint_command(unsigned handle)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
#if BX_DBG_SUPPORT_VIR_BPOINT
|
|
|
|
if (bx_dbg_del_vbreak (handle))
|
|
|
|
goto done;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BX_DBG_SUPPORT_LIN_BPOINT
|
|
|
|
if (bx_dbg_del_lbreak (handle))
|
|
|
|
goto done;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BX_DBG_SUPPORT_PHY_BPOINT
|
|
|
|
if (bx_dbg_del_pbreak (handle))
|
|
|
|
goto done;
|
|
|
|
#endif
|
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: breakpoint %u not found.\n", handle);
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
done:
|
|
|
|
bx_dbg_breakpoint_changed();
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
bx_bool bx_dbg_del_pbreak (unsigned handle)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
#if BX_DBG_SUPPORT_PHY_BPOINT
|
|
|
|
// see if breakpoint is a physical breakpoint
|
|
|
|
for (unsigned i=0; i<bx_guard.iaddr.num_physical; i++) {
|
|
|
|
if (bx_guard.iaddr.phy[i].bpoint_id == handle) {
|
|
|
|
// found breakpoint, delete it by shifting remaining entries left
|
|
|
|
for (unsigned j=i; j<(bx_guard.iaddr.num_physical-1); j++) {
|
|
|
|
bx_guard.iaddr.phy[j] = bx_guard.iaddr.phy[j+1];
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
bx_guard.iaddr.num_physical--;
|
|
|
|
return 1;
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
2005-04-08 22:30:34 +04:00
|
|
|
return 0;
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
bx_bool bx_dbg_del_lbreak (unsigned handle)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
#if BX_DBG_SUPPORT_LIN_BPOINT
|
|
|
|
// see if breakpoint is a linear breakpoint
|
|
|
|
for (unsigned i=0; i<bx_guard.iaddr.num_linear; i++) {
|
|
|
|
if (bx_guard.iaddr.lin[i].bpoint_id == handle) {
|
|
|
|
// found breakpoint, delete it by shifting remaining entries left
|
|
|
|
for (unsigned j=i; j<(bx_guard.iaddr.num_linear-1); j++) {
|
|
|
|
bx_guard.iaddr.lin[j] = bx_guard.iaddr.lin[j+1];
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
bx_guard.iaddr.num_linear--;
|
|
|
|
return 1;
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
2005-04-08 22:30:34 +04:00
|
|
|
return 0;
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
bx_bool bx_dbg_del_vbreak (unsigned handle)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
#if BX_DBG_SUPPORT_VIR_BPOINT
|
|
|
|
// see if breakpoint is a virtual breakpoint
|
|
|
|
for (unsigned i=0; i<bx_guard.iaddr.num_virtual; i++) {
|
|
|
|
if (bx_guard.iaddr.vir[i].bpoint_id == handle) {
|
|
|
|
// found breakpoint, delete it by shifting remaining entries left
|
|
|
|
for (unsigned j=i; j<(bx_guard.iaddr.num_virtual-1); j++) {
|
|
|
|
bx_guard.iaddr.vir[j] = bx_guard.iaddr.vir[j+1];
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
bx_guard.iaddr.num_virtual--;
|
|
|
|
return 1;
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
2005-04-08 22:30:34 +04:00
|
|
|
return 0;
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
int bx_dbg_vbreakpoint_command(BreakpointKind bk, Bit32u cs, Bit32u eip)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
#if BX_DBG_SUPPORT_VIR_BPOINT
|
|
|
|
if (bk != bkRegular) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: vbreak of this kind not implemented yet.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return -1;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (bx_guard.iaddr.num_virtual >= BX_DBG_MAX_VIR_BPOINTS) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: no more virtual breakpoint slots left.\n");
|
|
|
|
dbg_printf ("Error: see BX_DBG_MAX_VIR_BPOINTS.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return -1;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
bx_guard.iaddr.vir[bx_guard.iaddr.num_virtual].cs = cs;
|
|
|
|
bx_guard.iaddr.vir[bx_guard.iaddr.num_virtual].eip = eip;
|
|
|
|
bx_guard.iaddr.vir[bx_guard.iaddr.num_virtual].bpoint_id = bx_debugger.next_bpoint_id++;
|
|
|
|
int BpId = (int)bx_guard.iaddr.vir[bx_guard.iaddr.num_virtual].bpoint_id;
|
|
|
|
bx_guard.iaddr.vir[bx_guard.iaddr.num_virtual].enabled=1;
|
|
|
|
bx_guard.iaddr.num_virtual++;
|
|
|
|
bx_guard.guard_for |= BX_DBG_GUARD_IADDR_VIR;
|
|
|
|
return BpId;
|
|
|
|
|
|
|
|
#else
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: virtual breakpoint support not compiled in.\n");
|
|
|
|
dbg_printf ("Error: see BX_DBG_SUPPORT_VIR_BPOINT.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
int bx_dbg_lbreakpoint_command(BreakpointKind bk, Bit32u laddress)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
#if BX_DBG_SUPPORT_LIN_BPOINT
|
|
|
|
if (bk == bkAtIP) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: lbreak of this kind not implemented yet.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return -1;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (bx_guard.iaddr.num_linear >= BX_DBG_MAX_LIN_BPOINTS) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: no more linear breakpoint slots left.\n");
|
|
|
|
dbg_printf ("Error: see BX_DBG_MAX_LIN_BPOINTS.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return -1;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
bx_guard.iaddr.lin[bx_guard.iaddr.num_linear].addr = laddress;
|
|
|
|
int BpId = (bk == bkStepOver) ? 0 : bx_debugger.next_bpoint_id++;
|
|
|
|
bx_guard.iaddr.lin[bx_guard.iaddr.num_linear].bpoint_id = BpId;
|
|
|
|
bx_guard.iaddr.lin[bx_guard.iaddr.num_linear].enabled=1;
|
|
|
|
bx_guard.iaddr.num_linear++;
|
|
|
|
bx_guard.guard_for |= BX_DBG_GUARD_IADDR_LIN;
|
|
|
|
return BpId;
|
|
|
|
|
|
|
|
#else
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: linear breakpoint support not compiled in.\n");
|
|
|
|
dbg_printf ("Error: see BX_DBG_SUPPORT_LIN_BPOINT.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
int bx_dbg_pbreakpoint_command(BreakpointKind bk, Bit32u paddress)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
#if BX_DBG_SUPPORT_PHY_BPOINT
|
|
|
|
if (bk != bkRegular) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: pbreak of this kind not implemented yet.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return -1;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (bx_guard.iaddr.num_physical >= BX_DBG_MAX_PHY_BPOINTS) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: no more physical breakpoint slots left.\n");
|
|
|
|
dbg_printf ("Error: see BX_DBG_MAX_PHY_BPOINTS.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return -1;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
bx_guard.iaddr.phy[bx_guard.iaddr.num_physical].addr = paddress;
|
|
|
|
bx_guard.iaddr.phy[bx_guard.iaddr.num_physical].bpoint_id = bx_debugger.next_bpoint_id++;
|
|
|
|
int BpId = (int)bx_guard.iaddr.phy[bx_guard.iaddr.num_physical].bpoint_id;
|
|
|
|
bx_guard.iaddr.phy[bx_guard.iaddr.num_physical].enabled=1;
|
|
|
|
bx_guard.iaddr.num_physical++;
|
|
|
|
bx_guard.guard_for |= BX_DBG_GUARD_IADDR_PHY;
|
|
|
|
return BpId;
|
|
|
|
#else
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: physical breakpoint support not compiled in.\n");
|
|
|
|
dbg_printf ("Error: see BX_DBG_SUPPORT_PHY_BPOINT.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_info_bpoints_command(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
// Num Type Disp Enb Address What
|
|
|
|
// 1 breakpoint keep y 0x00010664 in main at temp.c:7
|
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Num Type Disp Enb Address\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
#if BX_DBG_SUPPORT_VIR_BPOINT
|
|
|
|
for (i=0; i<bx_guard.iaddr.num_virtual; i++) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%3u ", bx_guard.iaddr.vir[i].bpoint_id);
|
|
|
|
dbg_printf ("vbreakpoint ");
|
|
|
|
dbg_printf ("keep ");
|
2003-11-28 18:07:29 +03:00
|
|
|
dbg_printf ( bx_guard.iaddr.vir[i].enabled?"y ":"n ");
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("0x%04x:0x%08x\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_guard.iaddr.vir[i].cs,
|
|
|
|
bx_guard.iaddr.vir[i].eip);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BX_DBG_SUPPORT_LIN_BPOINT
|
|
|
|
for (i=0; i<bx_guard.iaddr.num_linear; i++) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%3u ", bx_guard.iaddr.lin[i].bpoint_id);
|
|
|
|
dbg_printf ("lbreakpoint ");
|
|
|
|
dbg_printf ("keep ");
|
2003-11-28 18:07:29 +03:00
|
|
|
dbg_printf ( bx_guard.iaddr.lin[i].enabled?"y ":"n ");
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("0x%08x\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_guard.iaddr.lin[i].addr);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BX_DBG_SUPPORT_PHY_BPOINT
|
|
|
|
for (i=0; i<bx_guard.iaddr.num_physical; i++) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%3u ", bx_guard.iaddr.phy[i].bpoint_id);
|
|
|
|
dbg_printf ("pbreakpoint ");
|
|
|
|
dbg_printf ("keep ");
|
2003-11-28 18:07:29 +03:00
|
|
|
dbg_printf ( bx_guard.iaddr.phy[i].enabled?"y ":"n ");
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("0x%08x\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_guard.iaddr.phy[i].addr);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_set_command(char *p1, char *p2, char *p3)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: %s %s %s: command 'set' not implemented yet.\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
p1, p2, p3);
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_take_command(char *what, unsigned n)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
if ( !strcmp(what, "dma") ) {
|
|
|
|
unsigned i;
|
|
|
|
if (n == 0) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: take what n=0.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
2005-03-26 22:41:59 +03:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_post_dma_reports(); // in case there's some pending reports
|
|
|
|
bx_dbg_batch_dma.this_many = n;
|
|
|
|
|
|
|
|
for (i=0; i<n; i++) {
|
|
|
|
BX_CPU(0)->dbg_take_dma();
|
2005-03-26 22:41:59 +03:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
bx_dbg_batch_dma.this_many = 1; // reset to normal
|
|
|
|
bx_dbg_post_dma_reports(); // print reports and flush
|
|
|
|
if (bx_guard.report.dma)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("done\n");
|
2005-03-26 22:41:59 +03:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(what, "irq") ) {
|
|
|
|
BX_CPU(0)->dbg_take_irq();
|
|
|
|
|
|
|
|
if (bx_guard.report.irq)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("done\n");
|
2005-03-26 22:41:59 +03:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: Take '%s' not understood.\n", what);
|
2005-03-26 22:41:59 +03:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_info_registers_command(int which_regs_mask)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
Bit32u reg;
|
|
|
|
bx_dbg_cpu_t cpu;
|
|
|
|
|
|
|
|
for (unsigned i=0; i<BX_SMP_PROCESSORS; i++) {
|
|
|
|
if (which_regs_mask & BX_INFO_CPU_REGS) {
|
|
|
|
memset(&cpu, 0, sizeof(cpu));
|
|
|
|
BX_CPU(i)->dbg_get_cpu(&cpu);
|
|
|
|
|
2005-03-28 22:19:02 +04:00
|
|
|
#if (BX_SMP_PROCESSORS >= 2)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%s:\n", BX_CPU(i)->name, i);
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
|
|
|
reg = cpu.eax;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("eax 0x%-8x\t%d\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
reg = cpu.ecx;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("ecx 0x%-8x\t%d\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
reg = cpu.edx;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("edx 0x%-8x\t%d\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
reg = cpu.ebx;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("ebx 0x%-8x\t%d\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
reg = cpu.esp;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("esp 0x%-8x\t0x%-8x\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
reg = cpu.ebp;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("ebp 0x%-8x\t0x%-8x\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
reg = cpu.esi;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("esi 0x%-8x\t%d\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
reg = cpu.edi;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("edi 0x%-8x\t%d\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
reg = cpu.eip;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("eip 0x%-8x\t0x%-8x\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
reg = cpu.eflags;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("eflags 0x%-8x\t%d\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
reg = cpu.cs.sel;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("cs 0x%-8x\t%d\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
reg = cpu.ss.sel;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("ss 0x%-8x\t%d\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
reg = cpu.ds.sel;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("ds 0x%-8x\t%d\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
reg = cpu.es.sel;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("es 0x%-8x\t%d\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
reg = cpu.fs.sel;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("fs 0x%-8x\t%d\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
reg = cpu.gs.sel;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("gs 0x%-8x\t%d\n", (unsigned) reg, (int) reg);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
2005-03-28 22:19:02 +04:00
|
|
|
#if BX_SUPPORT_FPU
|
2003-11-28 18:07:29 +03:00
|
|
|
if (which_regs_mask & BX_INFO_FPU_REGS) {
|
|
|
|
BX_CPU(i)->print_state_FPU ();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_info_program_command(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf (" Using the running image of child process -1.\n");
|
|
|
|
dbg_printf ("Program stopped at 0x0.\n");
|
|
|
|
dbg_printf ("It stopped at breakpoint 0.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_dump_cpu_command(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
bx_dbg_cpu_t cpu;
|
|
|
|
|
|
|
|
for (unsigned i=0; i<BX_SMP_PROCESSORS; i++ ) {
|
|
|
|
BX_CPU(i)->dbg_get_cpu(&cpu);
|
|
|
|
|
|
|
|
#if (BX_SMP_PROCESSORS >= 2)
|
2005-04-17 01:43:06 +04:00
|
|
|
dbg_printf ("CPU#%u\n", i);
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
2005-04-17 01:43:06 +04:00
|
|
|
dbg_printf ("eax:0x%08x, ebx:0x%08x, ecx:0x%08x, edx:0x%08x\n",
|
|
|
|
(unsigned) cpu.eax, (unsigned) cpu.ebx,
|
|
|
|
(unsigned) cpu.ecx, (unsigned) cpu.edx);
|
|
|
|
dbg_printf ("ebp:0x%08x, esp:0x%08x, esi:0x%08x, edi:0x%08x\n",
|
|
|
|
(unsigned) cpu.ebp, (unsigned) cpu.esp,
|
|
|
|
(unsigned) cpu.esi, (unsigned) cpu.edi);
|
|
|
|
dbg_printf ("eip:0x%08x, eflags:0x%08x, inhibit_mask:%u\n",
|
|
|
|
(unsigned) cpu.eip, (unsigned) cpu.eflags, cpu.inhibit_mask);
|
|
|
|
|
|
|
|
dbg_printf ("cs:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) cpu.cs.sel, (unsigned) cpu.cs.des_l,
|
|
|
|
(unsigned) cpu.cs.des_h, (unsigned) cpu.cs.valid);
|
2005-04-17 01:43:06 +04:00
|
|
|
dbg_printf ("ss:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) cpu.ss.sel, (unsigned) cpu.ss.des_l,
|
|
|
|
(unsigned) cpu.ss.des_h, (unsigned) cpu.ss.valid);
|
2005-04-17 01:43:06 +04:00
|
|
|
dbg_printf ("ds:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) cpu.ds.sel, (unsigned) cpu.ds.des_l,
|
|
|
|
(unsigned) cpu.ds.des_h, (unsigned) cpu.ds.valid);
|
2005-04-17 01:43:06 +04:00
|
|
|
dbg_printf ("es:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) cpu.es.sel, (unsigned) cpu.es.des_l,
|
|
|
|
(unsigned) cpu.es.des_h, (unsigned) cpu.es.valid);
|
2005-04-17 01:43:06 +04:00
|
|
|
dbg_printf ("fs:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) cpu.fs.sel, (unsigned) cpu.fs.des_l,
|
|
|
|
(unsigned) cpu.fs.des_h, (unsigned) cpu.fs.valid);
|
2005-04-17 01:43:06 +04:00
|
|
|
dbg_printf ("gs:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) cpu.gs.sel, (unsigned) cpu.gs.des_l,
|
|
|
|
(unsigned) cpu.gs.des_h, (unsigned) cpu.gs.valid);
|
|
|
|
|
2005-04-17 01:43:06 +04:00
|
|
|
dbg_printf ("ldtr:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) cpu.ldtr.sel, (unsigned) cpu.ldtr.des_l,
|
|
|
|
(unsigned) cpu.ldtr.des_h, (unsigned) cpu.ldtr.valid);
|
|
|
|
|
2005-04-17 01:43:06 +04:00
|
|
|
dbg_printf ("tr:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) cpu.tr.sel, (unsigned) cpu.tr.des_l,
|
|
|
|
(unsigned) cpu.tr.des_h, (unsigned) cpu.tr.valid);
|
|
|
|
|
2005-04-17 01:43:06 +04:00
|
|
|
dbg_printf ("gdtr:base=0x%08x, limit=0x%x\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) cpu.gdtr.base, (unsigned) cpu.gdtr.limit);
|
2005-04-17 01:43:06 +04:00
|
|
|
dbg_printf ("idtr:base=0x%08x, limit=0x%x\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) cpu.idtr.base, (unsigned) cpu.idtr.limit);
|
|
|
|
|
2005-04-17 01:43:06 +04:00
|
|
|
dbg_printf ("dr0:0x%08x, dr1:0x%08x, dr2:0x%08x\n",
|
|
|
|
(unsigned) cpu.dr0, (unsigned) cpu.dr1, (unsigned) cpu.dr2);
|
|
|
|
dbg_printf ("dr3:0x%08x, dr6:0x%08x, dr7:0x%08x\n",
|
|
|
|
(unsigned) cpu.dr3, (unsigned) cpu.dr6, (unsigned) cpu.dr7);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2005-04-17 01:43:06 +04:00
|
|
|
dbg_printf ("cr0:0x%08x, cr1:0x%08x, cr2:0x%08x\n",
|
|
|
|
(unsigned) cpu.cr0, (unsigned) cpu.cr1, (unsigned) cpu.cr2);
|
|
|
|
dbg_printf ("cr3:0x%08x, cr4:0x%08x\n",
|
|
|
|
(unsigned) cpu.cr3, (unsigned) cpu.cr4);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2004-08-06 19:49:55 +04:00
|
|
|
#if BX_SUPPORT_PCI
|
2003-11-28 18:07:29 +03:00
|
|
|
if (bx_options.Oi440FXSupport->get ()) {
|
|
|
|
DEV_pci_print_i440fx_state();
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
|
|
|
|
2005-04-17 01:43:06 +04:00
|
|
|
dbg_printf ("done\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
static void bx_print_char (Bit8u ch)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
if (ch < 10)
|
|
|
|
dbg_printf (" \\%d ", ch);
|
|
|
|
else if (isprint(ch))
|
|
|
|
dbg_printf (" %c ", ch);
|
|
|
|
else
|
|
|
|
dbg_printf (" \\x%02X", ch);
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void dbg_printf_binary (char *format, Bit32u data, int bits)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
int b,len = 0;
|
|
|
|
char num[33];
|
|
|
|
|
|
|
|
for (b = 1 << (bits - 1); b; b >>= 1)
|
|
|
|
num [len++] = (data & b) ? '1' : '0';
|
|
|
|
num [len] = 0;
|
|
|
|
dbg_printf (format, num);
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_examine_command(char *command, char *format, bx_bool format_passed,
|
2003-11-28 18:07:29 +03:00
|
|
|
Bit32u addr, bx_bool addr_passed, int simulator)
|
|
|
|
{
|
|
|
|
unsigned repeat_count, i;
|
|
|
|
char ch, display_format, unit_size;
|
|
|
|
bx_bool iteration, memory_dump = false;
|
|
|
|
unsigned data_size;
|
|
|
|
bx_bool paddr_valid;
|
|
|
|
Bit32u paddr;
|
|
|
|
Bit8u data8;
|
|
|
|
Bit16u data16;
|
|
|
|
Bit32u data32;
|
|
|
|
unsigned columns, per_line, offset;
|
|
|
|
bx_bool is_linear;
|
|
|
|
unsigned char databuf[8];
|
|
|
|
|
|
|
|
if (simulator == 0)
|
|
|
|
printf("[%s]:\n", SIM_NAME0);
|
|
|
|
else
|
|
|
|
printf("[%s]:\n", SIM_NAME1_STR);
|
|
|
|
|
|
|
|
// If command was the extended "xp" command, meaning eXamine Physical memory,
|
|
|
|
// then flag memory address as physical, rather than linear.
|
|
|
|
if (strcmp(command, "xp") == 0) {
|
|
|
|
is_linear = 0;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
|
|
|
is_linear = 1;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (addr_passed==0)
|
|
|
|
addr = bx_debugger.default_addr;
|
|
|
|
|
|
|
|
if (format_passed==0) {
|
|
|
|
display_format = bx_debugger.default_display_format;
|
|
|
|
unit_size = bx_debugger.default_unit_size;
|
|
|
|
repeat_count = 1;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
|
|
|
if (format==NULL) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("dbg_examine: format NULL\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (strlen(format) < 2) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("dbg_examine: invalid format passed.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (format[0] != '/') {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("dbg_examine: '/' is not first char of format.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
format++;
|
|
|
|
repeat_count = 0;
|
|
|
|
ch = *format;
|
|
|
|
iteration = 0;
|
|
|
|
|
|
|
|
while ( (ch>='0') && (ch<='9') ) {
|
|
|
|
iteration = 1;
|
|
|
|
repeat_count = 10*repeat_count + (ch-'0');
|
|
|
|
format++;
|
|
|
|
ch = *format;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (iteration==0) {
|
|
|
|
// if no count given, use default
|
|
|
|
repeat_count = 1;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if (repeat_count==0) {
|
|
|
|
// count give, but zero is an error
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("dbg_examine: repeat count given but is zero.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// set up the default display format and unit size parameters
|
|
|
|
display_format = bx_debugger.default_display_format;
|
|
|
|
unit_size = bx_debugger.default_unit_size;
|
|
|
|
|
|
|
|
for (i = 0; format [i]; i++) {
|
|
|
|
switch (ch = format [i]) {
|
|
|
|
case 'x': // hex
|
|
|
|
case 'd': // signed decimal
|
|
|
|
case 'u': // unsigned decimal
|
|
|
|
case 'o': // octal
|
|
|
|
case 't': // binary
|
|
|
|
case 'c': // chars
|
|
|
|
case 's': // null terminated string
|
|
|
|
case 'i': // machine instruction
|
|
|
|
display_format = ch;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'b': // bytes
|
|
|
|
case 'h': // halfwords (two bytes)
|
|
|
|
case 'w': // words (4 bytes)
|
|
|
|
case 'g': // giant words (8 bytes)
|
|
|
|
unit_size = ch;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'm': // memory dump
|
|
|
|
memory_dump = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("dbg_examine: invalid format passed. \'%c\'\n", ch);
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
|
|
|
break;
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// store current options as default
|
|
|
|
bx_debugger.default_display_format = display_format;
|
|
|
|
bx_debugger.default_unit_size = unit_size;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
//dbg_printf (" repeat count was %u\n", repeat_count);
|
|
|
|
//dbg_printf (" display_format = '%c'\n", display_format);
|
|
|
|
//dbg_printf (" unit_size = '%c'\n", unit_size);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if ( (display_format == 'i') || (display_format == 's') ) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("error: dbg_examine: 'i' and 's' formats not supported.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (unit_size == 'g') {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("error: dbg_examine: 'g' (8-byte) unit size not supported.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
data_size = 0;
|
|
|
|
per_line = 0;
|
|
|
|
offset = 0;
|
|
|
|
|
|
|
|
if (memory_dump) {
|
|
|
|
if (display_format == 'c') {
|
|
|
|
// Display character dump in lines of 64 characters
|
|
|
|
unit_size = 'b';
|
|
|
|
data_size = 1;
|
|
|
|
per_line = 64;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else
|
|
|
|
switch (unit_size) {
|
|
|
|
case 'b': data_size = 1; per_line = 16; break;
|
|
|
|
case 'h': data_size = 2; per_line = 8; break;
|
|
|
|
case 'w': data_size = 4; per_line = 4; break;
|
|
|
|
//case 'g': data_size = 8; per_line = 2; break;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
|
|
|
// binary format is quite large
|
|
|
|
if (display_format == 't')
|
|
|
|
per_line /= 4;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
switch (unit_size) {
|
|
|
|
case 'b': data_size = 1; per_line = 8; break;
|
|
|
|
case 'h': data_size = 2; per_line = 8; break;
|
|
|
|
case 'w': data_size = 4; per_line = 4; break;
|
2003-11-28 18:07:29 +03:00
|
|
|
//case 'g': data_size = 8; per_line = 2; break;
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
columns = per_line + 1; // set current number columns past limit
|
|
|
|
|
|
|
|
for (i=1; i<=repeat_count; i++) {
|
|
|
|
|
|
|
|
if (columns > per_line) {
|
|
|
|
// if not 1st run, need a newline from last line
|
|
|
|
if (i!=1)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
if (memory_dump)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%08X ", addr );
|
2003-11-28 18:07:29 +03:00
|
|
|
else
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("0x%08x <bogus+%8u>:", addr, offset);
|
2003-11-28 18:07:29 +03:00
|
|
|
columns = 1;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
/* Put a space in the middle of dump, for readability */
|
|
|
|
if ((columns - 1) == per_line / 2
|
2005-04-08 22:30:34 +04:00
|
|
|
&& memory_dump && display_format != 'c')
|
2003-11-28 18:07:29 +03:00
|
|
|
dbg_printf (" ");
|
|
|
|
|
|
|
|
if (is_linear) {
|
|
|
|
BX_CPU(simulator)->dbg_xlate_linear2phy(addr, &paddr, &paddr_valid);
|
|
|
|
if (!paddr_valid) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("error: examine memory: no tranlation for linear-to-phy mem available.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
|
|
|
paddr = addr; // address is already physical address
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
BX_MEM(simulator)->dbg_fetch_mem(paddr, data_size, databuf);
|
|
|
|
//FIXME HanishKVC The char display for data to be properly integrated
|
|
|
|
// so that repeat_count, columns, etc. can be set or used properly.
|
|
|
|
// Also for data_size of 2 and 4 how to display the individual
|
|
|
|
// characters i.e in which order to be decided.
|
|
|
|
switch (data_size) {
|
|
|
|
case 1:
|
|
|
|
data8 = databuf[0];
|
|
|
|
if (memory_dump)
|
|
|
|
switch (display_format) {
|
|
|
|
case 'd': dbg_printf ("%03d ", data8); break;
|
|
|
|
case 'u': dbg_printf ("%03u ", data8); break;
|
|
|
|
case 'o': dbg_printf ("%03o ", data8); break;
|
|
|
|
case 't': dbg_printf_binary ("%s ", data8, 8); break;
|
|
|
|
case 'c': dbg_printf ("%c", isprint(data8) ? data8 : '.'); break;
|
|
|
|
default : dbg_printf ("%02X ", data8); break;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else
|
|
|
|
switch (display_format) {
|
2005-12-14 23:05:40 +03:00
|
|
|
case 'x': dbg_printf ("\t0x%02x", (unsigned) data8); break;
|
|
|
|
case 'd': dbg_printf ("\t%d", (int) (Bit8s) data8); break;
|
|
|
|
case 'u': dbg_printf ("\t%u", (unsigned) data8); break;
|
|
|
|
case 'o': dbg_printf ("\t%o", (unsigned) data8); break;
|
2003-11-28 18:07:29 +03:00
|
|
|
case 't': dbg_printf_binary ("\t%s", data8, 8); break;
|
|
|
|
case 'c': bx_print_char (data8); break;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
#ifdef BX_LITTLE_ENDIAN
|
|
|
|
data16 = * (Bit16u *) databuf;
|
|
|
|
#else
|
2005-04-08 22:30:34 +04:00
|
|
|
data16 = (databuf[1]<<8) | databuf[0];
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
|
|
|
if (memory_dump)
|
|
|
|
switch (display_format) {
|
|
|
|
case 'd': dbg_printf ("%05d ", data16); break;
|
|
|
|
case 'u': dbg_printf ("%05u ", data16); break;
|
|
|
|
case 'o': dbg_printf ("%06o ", data16); break;
|
|
|
|
case 't': dbg_printf_binary ("%s ", data16, 16); break;
|
|
|
|
default : dbg_printf ("%04X ", data16); break;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else
|
|
|
|
switch (display_format) {
|
2005-12-14 23:05:40 +03:00
|
|
|
case 'x': dbg_printf ("\t0x%04x", (unsigned) data16); break;
|
|
|
|
case 'd': dbg_printf ("\t%d", (int) (Bit16s) data16); break;
|
|
|
|
case 'u': dbg_printf ("\t%u", (unsigned) data16); break;
|
|
|
|
case 'o': dbg_printf ("\t%o", (unsigned) data16); break;
|
2003-11-28 18:07:29 +03:00
|
|
|
case 't': dbg_printf_binary ("\t%s", data16, 16); break;
|
|
|
|
case 'c':
|
|
|
|
bx_print_char (data16>>8);
|
|
|
|
bx_print_char (data16 & 0xff);
|
|
|
|
break;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
#ifdef BX_LITTLE_ENDIAN
|
|
|
|
data32 = * (Bit32u *) databuf;
|
|
|
|
#else
|
|
|
|
data32 = (databuf[3]<<24) | (databuf[2]<<16) |
|
|
|
|
(databuf[1]<<8) | databuf[0];
|
|
|
|
#endif
|
|
|
|
if (memory_dump)
|
|
|
|
switch (display_format) {
|
|
|
|
case 'd': dbg_printf ("%10d ", data32); break;
|
|
|
|
case 'u': dbg_printf ("%10u ", data32); break;
|
|
|
|
case 'o': dbg_printf ("%12o ", data32); break;
|
|
|
|
case 't': dbg_printf_binary ("%s ", data32, 32); break;
|
|
|
|
default : dbg_printf ("%08X ", data32); break;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else
|
|
|
|
switch (display_format) {
|
2005-12-14 23:05:40 +03:00
|
|
|
case 'x': dbg_printf ("\t0x%08x", (unsigned) data32); break;
|
|
|
|
case 'd': dbg_printf ("\t%d", (int) (Bit32s) data32); break;
|
|
|
|
case 'u': dbg_printf ("\t%u", (unsigned) data32); break;
|
|
|
|
case 'o': dbg_printf ("\t%o", (unsigned) data32); break;
|
2005-04-08 22:30:34 +04:00
|
|
|
case 't': dbg_printf_binary ("\t%s", data32, 32); break;
|
|
|
|
case 'c':
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_print_char (0xff & (data32>>24));
|
|
|
|
bx_print_char (0xff & (data32>>16));
|
|
|
|
bx_print_char (0xff & (data32>> 8));
|
|
|
|
bx_print_char (0xff & (data32>> 0));
|
2005-04-08 22:30:34 +04:00
|
|
|
break;
|
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
addr += data_size;
|
|
|
|
bx_debugger.default_addr = addr;
|
|
|
|
columns++;
|
|
|
|
offset += data_size;
|
|
|
|
}
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_setpmem_command(Bit32u addr, unsigned len, Bit32u val)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
bx_bool is_OK;
|
|
|
|
Bit8u buf[4];
|
|
|
|
|
|
|
|
switch ( len ) {
|
|
|
|
case 1:
|
|
|
|
buf[0] = (Bit8u) val;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
buf[0] = val & 0xff;
|
|
|
|
buf[1] = (val>>8) & 0xff;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
buf[0] = val & 0xff; val >>= 8;
|
|
|
|
buf[1] = val & 0xff; val >>= 8;
|
|
|
|
buf[2] = val & 0xff; val >>= 8;
|
|
|
|
buf[3] = val & 0xff;
|
|
|
|
break;
|
|
|
|
default:
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: setpmem: bad length value = %u\n", len);
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
is_OK = BX_MEM(0)->dbg_set_mem(addr, len, buf);
|
|
|
|
if (!is_OK) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: setpmem: could not set memory, out of physical bounds?\n");
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_set_symbol_command(char *symbol, Bit32u val)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
bx_bool is_OK = false;
|
|
|
|
symbol++; // get past '$'
|
|
|
|
|
|
|
|
if ( !strcmp(symbol, "eax") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_EAX, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "ecx") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_ECX, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "edx") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_EDX, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "ebx") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_EBX, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "esp") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_ESP, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "ebp") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_EBP, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "esi") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_ESI, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "edi") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_EDI, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "eip") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_EIP, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "eflags") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_EFLAGS, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "cs") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_CS, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "ss") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_SS, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "ds") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_DS, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "es") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_ES, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "fs") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_FS, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "gs") ) {
|
|
|
|
is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_GS, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "cpu") ) {
|
|
|
|
#if ((BX_SMP_PROCESSORS>1) && (BX_SUPPORT_APIC))
|
2006-01-10 09:13:26 +03:00
|
|
|
if (val > BX_SMP_PROCESSORS) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("invalid cpu id number %d\n", val);
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
dbg_cpu = val;
|
|
|
|
#endif
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "synchronous_dma") ) {
|
|
|
|
bx_guard.async.dma = !val;
|
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "synchronous_irq") ) {
|
|
|
|
bx_guard.async.irq = !val;
|
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "event_reports") ) {
|
|
|
|
bx_guard.report.irq = val;
|
|
|
|
bx_guard.report.a20 = val;
|
|
|
|
bx_guard.report.io = val;
|
|
|
|
bx_guard.report.ucmem = val;
|
|
|
|
bx_guard.report.dma = val;
|
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "auto_disassemble") ) {
|
|
|
|
bx_debugger.auto_disassemble = (val > 0);
|
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(symbol, "disassemble_size") ) {
|
|
|
|
if ( (val!=16) && (val!=32) && (val!=0) ) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: disassemble_size must be 16 or 32.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_debugger.disassemble_size = val;
|
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: set: unrecognized symbol.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (!is_OK) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: could not set register '%s'.\n", symbol);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_query_command(char *what)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
unsigned pending;
|
|
|
|
|
|
|
|
if ( !strcmp(what, "pending") ) {
|
|
|
|
pending = BX_CPU(0)->dbg_query_pending();
|
|
|
|
|
|
|
|
if ( pending & BX_DBG_PENDING_DMA )
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("pending DMA\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if ( pending & BX_DBG_PENDING_IRQ )
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("pending IRQ\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (!pending)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("pending none\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("done\n");
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: Query '%s' not understood.\n", what);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_set_cpu_command(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
int reti;
|
|
|
|
char *rets;
|
|
|
|
bx_bool retb;
|
|
|
|
unsigned long ul1, ul2, ul3, ul4;
|
|
|
|
|
|
|
|
bx_dbg_cpu_t cpu;
|
|
|
|
|
|
|
|
fp = bx_infile_stack[bx_infile_stack_index].fp;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "eax:0x%lx", &ul1); cpu.eax = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "ebx:0x%lx", &ul1); cpu.ebx = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "ecx:0x%lx", &ul1); cpu.ecx = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "edx:0x%lx", &ul1); cpu.edx = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "ebp:0x%lx", &ul1); cpu.ebp = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "esi:0x%lx", &ul1); cpu.esi = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "edi:0x%lx", &ul1); cpu.edi = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "esp:0x%lx", &ul1); cpu.esp = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "eflags:0x%lx", &ul1); cpu.eflags = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "eip:0x%lx", &ul1); cpu.eip = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "cs:s=0x%lx, dl=0x%lx, dh=0x%lx, valid=%lu",
|
|
|
|
&ul1, &ul2, &ul3, &ul4);
|
|
|
|
cpu.cs.sel = (Bit16u) ul1;
|
|
|
|
cpu.cs.des_l = ul2;
|
|
|
|
cpu.cs.des_h = ul3;
|
|
|
|
cpu.cs.valid = ul4;
|
|
|
|
if (reti != 4) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "ss:s=0x%lx, dl=0x%lx, dh=0x%lx, valid=%lu",
|
|
|
|
&ul1, &ul2, &ul3, &ul4);
|
|
|
|
cpu.ss.sel = (Bit16u) ul1;
|
|
|
|
cpu.ss.des_l = ul2;
|
|
|
|
cpu.ss.des_h = ul3;
|
|
|
|
cpu.ss.valid = ul4;
|
|
|
|
if (reti != 4) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "ds:s=0x%lx, dl=0x%lx, dh=0x%lx, valid=%lu",
|
|
|
|
&ul1, &ul2, &ul3, &ul4);
|
|
|
|
cpu.ds.sel = (Bit16u) ul1;
|
|
|
|
cpu.ds.des_l = ul2;
|
|
|
|
cpu.ds.des_h = ul3;
|
|
|
|
cpu.ds.valid = ul4;
|
|
|
|
if (reti != 4) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "es:s=0x%lx, dl=0x%lx, dh=0x%lx, valid=%lu",
|
|
|
|
&ul1, &ul2, &ul3, &ul4);
|
|
|
|
cpu.es.sel = (Bit16u) ul1;
|
|
|
|
cpu.es.des_l = ul2;
|
|
|
|
cpu.es.des_h = ul3;
|
|
|
|
cpu.es.valid = ul4;
|
|
|
|
if (reti != 4) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "fs:s=0x%lx, dl=0x%lx, dh=0x%lx, valid=%lu",
|
|
|
|
&ul1, &ul2, &ul3, &ul4);
|
|
|
|
cpu.fs.sel = (Bit16u) ul1;
|
|
|
|
cpu.fs.des_l = ul2;
|
|
|
|
cpu.fs.des_h = ul3;
|
|
|
|
cpu.fs.valid = ul4;
|
|
|
|
if (reti != 4) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "gs:s=0x%lx, dl=0x%lx, dh=0x%lx, valid=%lu",
|
|
|
|
&ul1, &ul2, &ul3, &ul4);
|
|
|
|
cpu.gs.sel = (Bit16u) ul1;
|
|
|
|
cpu.gs.des_l = ul2;
|
|
|
|
cpu.gs.des_h = ul3;
|
|
|
|
cpu.gs.valid = ul4;
|
|
|
|
if (reti != 4) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "ldtr:s=0x%lx, dl=0x%lx, dh=0x%lx, valid=%lu",
|
|
|
|
&ul1, &ul2, &ul3, &ul4);
|
|
|
|
cpu.ldtr.sel = (Bit16u) ul1;
|
|
|
|
cpu.ldtr.des_l = ul2;
|
|
|
|
cpu.ldtr.des_h = ul3;
|
|
|
|
cpu.ldtr.valid = ul4;
|
|
|
|
if (reti != 4) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "tr:s=0x%lx, dl=0x%lx, dh=0x%lx, valid=%lu",
|
|
|
|
&ul1, &ul2, &ul3, &ul4);
|
|
|
|
cpu.tr.sel = (Bit16u) ul1;
|
|
|
|
cpu.tr.des_l = ul2;
|
|
|
|
cpu.tr.des_h = ul3;
|
|
|
|
cpu.tr.valid = ul4;
|
|
|
|
if (reti != 4) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "gdtr:base=0x%lx, limit=0x%lx",
|
|
|
|
&ul1, &ul2);
|
|
|
|
cpu.gdtr.base = ul1;
|
|
|
|
cpu.gdtr.limit = ul2;
|
|
|
|
if (reti != 2) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "idtr:base=0x%lx, limit=0x%lx",
|
|
|
|
&ul1, &ul2);
|
|
|
|
cpu.idtr.base = ul1;
|
|
|
|
cpu.idtr.limit = ul2;
|
|
|
|
if (reti != 2) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "dr0:0x%lx", &ul1); cpu.dr0 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "dr1:0x%lx", &ul1); cpu.dr1 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "dr2:0x%lx", &ul1); cpu.dr2 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "dr3:0x%lx", &ul1); cpu.dr3 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "dr6:0x%lx", &ul1); cpu.dr6 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "dr7:0x%lx", &ul1); cpu.dr7 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "tr3:0x%lx", &ul1); cpu.tr3 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "tr4:0x%lx", &ul1); cpu.tr4 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "tr5:0x%lx", &ul1); cpu.tr5 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "tr6:0x%lx", &ul1); cpu.tr6 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "tr7:0x%lx", &ul1); cpu.tr7 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "cr0:0x%lx", &ul1); cpu.cr0 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "cr1:0x%lx", &ul1); cpu.cr1 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "cr2:0x%lx", &ul1); cpu.cr2 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "cr3:0x%lx", &ul1); cpu.cr3 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "cr4:0x%lx", &ul1); cpu.cr4 = ul1;
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "inhibit_mask:%u", &cpu.inhibit_mask);
|
|
|
|
if (reti != 1) goto scanf_error;
|
|
|
|
|
|
|
|
rets = fgets(tmp_buf, 512, fp); if (!rets) goto eof_error;
|
|
|
|
reti = sscanf(tmp_buf, "done");
|
|
|
|
if (reti != 0) goto scanf_error;
|
|
|
|
|
|
|
|
retb = BX_CPU(0)->dbg_set_cpu(&cpu);
|
|
|
|
if (retb == 0)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: dbg_set_cpu encountered error\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
else
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("OK\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
eof_error:
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: EOF encountered in dbg_set_cpu input stream\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
scanf_error:
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: scanf returned error in dbg_set_cpu input stream\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_disassemble_command(const char *format, bx_num_range range)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
bx_bool paddr_valid;
|
2004-09-19 11:56:49 +04:00
|
|
|
Bit32u paddr/*, Base */;
|
2003-11-28 18:07:29 +03:00
|
|
|
unsigned ilen;
|
|
|
|
int numlines = INT_MAX;
|
|
|
|
|
|
|
|
if (range.from == EMPTY_ARG) {
|
2005-11-27 21:25:57 +03:00
|
|
|
range.from = bx_dbg_get_laddr(bx_dbg_get_selector_value(1), BX_CPU(dbg_cpu)->get_ip());
|
2003-11-28 18:07:29 +03:00
|
|
|
range.to = range.from;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (format) {
|
|
|
|
// format always begins with '/' (checked in lexer)
|
|
|
|
// so we won't bother checking it here second time.
|
|
|
|
numlines = atoi(format + 1);
|
|
|
|
if (range.to == range.from)
|
|
|
|
range.to = BX_MAX_BIT64S; // Disassemble just X lines
|
|
|
|
}
|
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
do {
|
|
|
|
numlines--;
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
BX_CPU(dbg_cpu)->dbg_xlate_linear2phy((Bit32u)range.from, &paddr, &paddr_valid);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
if (paddr_valid) {
|
|
|
|
unsigned dis_size = bx_debugger.disassemble_size;
|
|
|
|
if (dis_size == 0) {
|
|
|
|
dis_size = 16; // until otherwise proven
|
|
|
|
if (BX_CPU(dbg_cpu)->sregs[BX_SEG_REG_CS].cache.u.segment.d_b)
|
|
|
|
dis_size = 32;
|
|
|
|
}
|
|
|
|
BX_MEM(0)->dbg_fetch_mem(paddr, 16, bx_disasm_ibuf);
|
|
|
|
ilen = bx_disassemble.disasm(dis_size==32, dis_size==64,
|
|
|
|
0, (Bit32u)range.from, bx_disasm_ibuf, bx_disasm_tbuf);
|
|
|
|
|
|
|
|
char *Sym=bx_dbg_disasm_symbolic_address((Bit32u)range.from, 0);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%08x: ", (unsigned) range.from);
|
|
|
|
dbg_printf ("(%20s): ", Sym?Sym:"");
|
|
|
|
dbg_printf ("%-25s ; ", bx_disasm_tbuf);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
for (unsigned j=0; j<ilen; j++)
|
|
|
|
dbg_printf ("%02x", (unsigned) bx_disasm_ibuf[j]);
|
|
|
|
dbg_printf ("\n");
|
2005-11-14 21:09:22 +03:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("??? (physical address not available)\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
ilen = 0; // keep compiler happy
|
|
|
|
range.from = range.to; // bail out
|
2005-11-14 21:09:22 +03:00
|
|
|
}
|
|
|
|
range.from += ilen;
|
|
|
|
} while ((range.from < range.to) && numlines > 0);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-04-08 22:30:34 +04:00
|
|
|
void bx_dbg_instrument_command(const char *comm)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
#if BX_INSTRUMENTATION
|
|
|
|
if ( !strcmp(comm, "start") ) {
|
|
|
|
BX_INSTR_START ();
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(comm, "stop") ) {
|
|
|
|
BX_INSTR_STOP ();
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(comm, "reset") ) {
|
|
|
|
BX_INSTR_RESET (dbg_cpu);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else if ( !strcmp(comm, "print") ) {
|
|
|
|
BX_INSTR_PRINT ();
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
2005-03-26 22:41:59 +03:00
|
|
|
dbg_printf ("Error: command instrument %s not implemented.\n", comm);
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
#else
|
2005-04-08 22:30:34 +04:00
|
|
|
UNUSED(comm);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2005-04-08 22:30:34 +04:00
|
|
|
dbg_printf ("Error: instrumentation not enabled.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_loader_command(char *path_quoted)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
// skip beginning double quote
|
|
|
|
if (path_quoted[0] == '"')
|
|
|
|
path_quoted++;
|
|
|
|
|
|
|
|
// null out ending quote
|
|
|
|
len = strlen(path_quoted);
|
|
|
|
if (path_quoted[len - 1] == '"')
|
|
|
|
path_quoted[len - 1] = '\0';
|
|
|
|
|
|
|
|
#if BX_USE_LOADER
|
|
|
|
{
|
2005-04-08 22:30:34 +04:00
|
|
|
bx_loader_misc_t loader_misc;
|
|
|
|
bx_dbg_callback[0].loader(path_quoted, &loader_misc);
|
2003-11-28 18:07:29 +03:00
|
|
|
#if 0
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("dr0: 0x%08x\n", loader_misc.dr0);
|
|
|
|
dbg_printf ("dr1: 0x%08x\n", loader_misc.dr1);
|
|
|
|
dbg_printf ("dr2: 0x%08x\n", loader_misc.dr2);
|
|
|
|
dbg_printf ("dr3: 0x%08x\n", loader_misc.dr3);
|
|
|
|
dbg_printf ("dr6: 0x%08x\n", loader_misc.dr6);
|
|
|
|
dbg_printf ("dr7: 0x%08x\n", loader_misc.dr7);
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
2005-04-08 22:30:34 +04:00
|
|
|
bx_cpu.dr0 = loader_misc.dr0;
|
|
|
|
bx_cpu.dr1 = loader_misc.dr1;
|
|
|
|
bx_cpu.dr2 = loader_misc.dr2;
|
|
|
|
bx_cpu.dr3 = loader_misc.dr3;
|
|
|
|
bx_cpu.dr7 = loader_misc.dr7;
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
#else
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: loader not implemented.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_doit_command(unsigned n)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
// generic command to add temporary hacks to
|
|
|
|
// for debugging purposes
|
|
|
|
UNUSED(n);
|
|
|
|
|
|
|
|
bx_dbg.interrupts = n;
|
|
|
|
bx_dbg.exceptions = n;
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_crc_command(Bit32u addr1, Bit32u addr2)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
Bit32u crc1;
|
|
|
|
|
|
|
|
if (addr1 >= addr2) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: crc: invalid range.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (!BX_MEM(0)->dbg_crc32(crc32, addr1, addr2, &crc1)) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("sim0: could not CRC memory\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
#if BX_NUM_SIMULATORS == 1
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("0x%lx\n", crc1);
|
2003-11-28 18:07:29 +03:00
|
|
|
#else
|
|
|
|
if (!BX_MEM(1)->dbg_crc32(crc32, addr1, addr2, &crc2)) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("sim1: could not CRC memory\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
if (crc1 == crc2) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("CRC same: 0x%x\n", (unsigned) crc1);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("CRC different: sim0=0x%x, sim1=0x%x\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) crc1, (unsigned) crc2);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_info_dirty_command(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
unsigned char *page_tbl = BX_MEM(0)->dbg_dirty_pages;
|
|
|
|
unsigned page_tbl_size = BX_MEM(0)->dbg_count_dirty_pages ();
|
|
|
|
|
|
|
|
for (unsigned i=0; i<page_tbl_size; i++) {
|
|
|
|
if (page_tbl[i]) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("0x%x\n", i);
|
2003-11-28 18:07:29 +03:00
|
|
|
page_tbl[i] = 0; // reset to clean
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void bx_dbg_print_descriptor (unsigned char desc[8], int verbose)
|
|
|
|
{
|
|
|
|
int lo = (desc[3] << 24) | (desc[2] << 16) | (desc[1] << 8) | (desc[0]);
|
|
|
|
int hi = (desc[7] << 24) | (desc[6] << 16) | (desc[5] << 8) | (desc[4]);
|
|
|
|
//dbg_printf ("descriptor hi,lo = %08x,%08x\n", hi, lo);
|
|
|
|
int base = ((lo >> 16) & 0xffff)
|
|
|
|
| ((hi << 16) & 0xff0000)
|
|
|
|
| (hi & 0xff000000);
|
|
|
|
int limit = (hi & 0x000f0000) | (lo & 0xffff);
|
|
|
|
int segment = (lo >> 16) & 0xffff;
|
|
|
|
int offset = (lo & 0xffff) | (hi & 0xffff0000);
|
|
|
|
int type = (hi >> 8) & 0x0f;
|
|
|
|
int dpl = (hi >> 13) & 0x03;
|
|
|
|
int s = (hi >> 12) & 0x01;
|
|
|
|
int d_b = (hi >> 22) & 0x01;
|
|
|
|
int g = (hi >> 23) & 0x01;
|
|
|
|
#if 0
|
|
|
|
int present = (hi >> 15) & 0x01;
|
|
|
|
int avl = (hi >> 20) & 0x01;
|
|
|
|
int base_is_jump_addr;
|
|
|
|
if (s) {
|
|
|
|
// either a code or a data segment. bit 11 (type file MSB) then says
|
|
|
|
// 0=data segment, 1=code seg
|
|
|
|
if (type&8) {
|
|
|
|
dbg_printf ("Segment type: Code, %s%s%s\n",
|
2005-04-08 22:30:34 +04:00
|
|
|
(type&2)? "Execute/Read" : "Execute-Only",
|
|
|
|
(type&4)? ", Conforming" : "",
|
|
|
|
(type&1)? ", Accessed" : "");
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("D flag=%d (use %d-bit addresses, %d-bit or 8-bit operands)\n", d_b, d_b? 32 : 16);
|
2003-11-28 18:07:29 +03:00
|
|
|
} else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Segment type: Data, %s%s%s\n",
|
2005-04-08 22:30:34 +04:00
|
|
|
(type&2)? "Read/Write" : "Read-Only",
|
|
|
|
(type&4)? ", Expand-down" : "",
|
|
|
|
(type&1)? ", Accessed" : "");
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// types from IA32-devel-guide-3, page 3-15.
|
|
|
|
static char *type_names[16] = { "Reserved", "16-Bit TSS (available)", "LDT", "16-Bit TSS (Busy)", "16-Bit Call Gate", "Task Gate", "16-Bit Interrupt Gate", "16-Bit Trap Gate", "Reserved", "32-Bit TSS (Available)", "Reserved", "32-Bit TSS (Busy)", "32-Bit Call Gate", "Reserved", "32-Bit Interrupt Gate", "32-Bit Trap Gate" };
|
|
|
|
// some kind of gate?
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("System segment, type=0x%x=%s\n", type, type_names[type]);
|
2003-11-28 18:07:29 +03:00
|
|
|
base_is_jump_addr = 1;
|
|
|
|
// for call gates, print segment:offset and parameter count p.40-15
|
|
|
|
// for task gate, only present,dpl,TSS segment selector exist. p.5-13
|
|
|
|
// for interrupt gate, segment:offset,p,dpl
|
|
|
|
// for trap gate, segment:offset,p,dpl
|
|
|
|
}
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("DPL=descriptor privilege level=%d\n", dpl);
|
2003-11-28 18:07:29 +03:00
|
|
|
if (base_is_jump_addr) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("target address=%04x:%08x\n", segment, offset);
|
2003-11-28 18:07:29 +03:00
|
|
|
} else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("base address=%p\n", base);
|
|
|
|
dbg_printf ("G=granularity=%d\n", g);
|
|
|
|
dbg_printf ("limit=0x%05x %s (see G)\n", limit, g?"4K-byte units" : "bytes");
|
|
|
|
dbg_printf ("AVL=available to OS=%d\n", avl);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("P=present=%d\n", present);
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
|
|
|
/* brief output */
|
|
|
|
// 32-bit trap gate, target=0010:c0108ec4, DPL=0, present=1
|
|
|
|
// code segment, base=0000:00cfffff, length=0xffff
|
|
|
|
if (s) {
|
|
|
|
// either a code or a data segment. bit 11 (type file MSB) then says
|
|
|
|
// 0=data segment, 1=code seg
|
|
|
|
if (type&8) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Code segment, linearaddr=%08x, len=%05x %s, %s%s%s, %d-bit addrs\n",
|
2005-04-08 22:30:34 +04:00
|
|
|
base, limit, g ? "* 4Kbytes" : "bytes",
|
|
|
|
(type&2)? "Execute/Read" : "Execute-Only",
|
|
|
|
(type&4)? ", Conforming" : "",
|
|
|
|
(type&1)? ", Accessed" : "",
|
|
|
|
d_b ? 32 : 16);
|
2003-11-28 18:07:29 +03:00
|
|
|
} else {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Data segment, linearaddr=%08x, len=%05x %s, %s%s%s\n",
|
2005-04-08 22:30:34 +04:00
|
|
|
base, limit, g ? "* 4Kbytes" : "bytes",
|
|
|
|
(type&2)? "Read/Write" : "Read-Only",
|
|
|
|
(type&4)? ", Expand-down" : "",
|
|
|
|
(type&1)? ", Accessed" : "");
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// types from IA32-devel-guide-3, page 3-15.
|
|
|
|
static char *undef = "???";
|
|
|
|
static char *type_names[16] = { undef, "16-Bit TSS (available)", "LDT", "16-Bit TSS (Busy)", "16-Bit Call Gate", "Task Gate", "16-Bit Interrupt Gate", "16-Bit Trap Gate", undef, "32-Bit TSS (Available)", undef, "32-Bit TSS (Busy)", "32-Bit Call Gate", undef, "32-Bit Interrupt Gate", "32-Bit Trap Gate" };
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%s ", type_names[type]);
|
2003-11-28 18:07:29 +03:00
|
|
|
// only print more if type is valid
|
|
|
|
if (type_names[type] == undef) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("descriptor hi=%08x, lo=%08x", hi, lo);
|
2003-11-28 18:07:29 +03:00
|
|
|
} else {
|
|
|
|
// for call gates, print segment:offset and parameter count p.4-15
|
|
|
|
// for task gate, only present,dpl,TSS segment selector exist. p.5-13
|
|
|
|
// for interrupt gate, segment:offset,p,dpl
|
|
|
|
// for trap gate, segment:offset,p,dpl
|
|
|
|
// for TSS, base address and segment limit
|
|
|
|
switch (type) {
|
2005-04-08 22:30:34 +04:00
|
|
|
case 1: case 3: // 16-bit TSS
|
|
|
|
case 9: case 11: // 32-bit TSS
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("at %08x, length 0x%05x", base, limit);
|
2005-04-08 22:30:34 +04:00
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
// it's an LDT. not much to print.
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// task, int, trap, or call gate.
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("target=0x%04x:0x%08x, DPL=%d", segment, offset, dpl);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
}
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_info_idt_command(bx_num_range range)
|
|
|
|
{
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_cpu_t cpu;
|
|
|
|
BX_CPU(0)->dbg_get_cpu(&cpu);
|
|
|
|
int n, print_table = 0;
|
|
|
|
if (range.to == EMPTY_ARG) {
|
|
|
|
// show all entries
|
|
|
|
range.from = 0;
|
|
|
|
range.to = (cpu.idtr.limit) / 8;
|
|
|
|
print_table = 1;
|
|
|
|
}
|
|
|
|
if (print_table)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Interrupt Descriptor Table (0x%08x):\n", cpu.idtr.base);
|
2003-11-28 18:07:29 +03:00
|
|
|
for (n = (int)range.from; n<=(int)range.to; n++) {
|
|
|
|
Bit32u paddr;
|
|
|
|
bx_bool paddr_valid;
|
|
|
|
BX_CPU(dbg_cpu)->dbg_xlate_linear2phy(cpu.idtr.base + 8*n, &paddr, &paddr_valid);
|
|
|
|
if (!paddr_valid) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("error: IDTR+8*%d points to invalid linear address 0x%-08x\n",
|
2005-04-08 22:30:34 +04:00
|
|
|
n, cpu.idtr.base);
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// read 8-byte entry from IDT
|
|
|
|
unsigned char entry[8];
|
|
|
|
BX_MEM(0)->dbg_fetch_mem (paddr, 8, entry);
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("IDT[0x%02x]=", n);
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_print_descriptor (entry, 0);
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
if (print_table)
|
|
|
|
dbg_printf ("You can list individual entries with 'info idt NUM' or groups with 'info idt NUMNUM'\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_info_gdt_command(bx_num_range range)
|
|
|
|
{
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_cpu_t cpu;
|
|
|
|
BX_CPU(0)->dbg_get_cpu(&cpu);
|
|
|
|
int n, print_table = 0;
|
|
|
|
if (range.to == EMPTY_ARG) {
|
|
|
|
// show all entries
|
|
|
|
range.from = 0;
|
|
|
|
range.to = (cpu.gdtr.limit) / 8;
|
|
|
|
print_table = 1;
|
|
|
|
}
|
|
|
|
if (print_table)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Global Descriptor Table (0x%08x):\n", cpu.gdtr.base);
|
2003-11-28 18:07:29 +03:00
|
|
|
for (n = (int)range.from; n<=(int)range.to; n++) {
|
|
|
|
Bit32u paddr;
|
|
|
|
bx_bool paddr_valid;
|
|
|
|
BX_CPU(dbg_cpu)->dbg_xlate_linear2phy(cpu.gdtr.base + 8*n, &paddr, &paddr_valid);
|
|
|
|
if (!paddr_valid) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("error: GDTR+8*%d points to invalid linear address 0x%-08x\n",
|
2005-04-08 22:30:34 +04:00
|
|
|
n, cpu.gdtr.base);
|
2003-11-28 18:07:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
unsigned char entry[8];
|
|
|
|
// read 8-byte entry from GDT
|
|
|
|
BX_MEM(0)->dbg_fetch_mem (paddr, 8, entry);
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("GDT[0x%02x]=", n);
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_print_descriptor (entry, 0);
|
|
|
|
}
|
2005-12-14 23:05:40 +03:00
|
|
|
if (print_table) dbg_printf ("You can list individual entries with 'info gdt NUM'.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_info_ldt_command(bx_num_range n)
|
|
|
|
{
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_cpu_t cpu;
|
|
|
|
BX_CPU(0)->dbg_get_cpu(&cpu);
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Local Descriptor Table output not implemented\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
static void bx_dbg_print_tss (unsigned char *tss, int len)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
if (len<104) {
|
|
|
|
dbg_printf ("Invalid tss length (limit must be greater then 103)\n");
|
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
dbg_printf ("ss:esp(0): 0x%04x:0x%08x\n",
|
|
|
|
*(Bit16u*)(tss+8), *(Bit32u*)(tss+4));
|
|
|
|
dbg_printf ("ss:esp(1): 0x%04x:0x%08x\n",
|
|
|
|
*(Bit16u*)(tss+0x10), *(Bit32u*)(tss+0xc));
|
|
|
|
dbg_printf ("ss:esp(2): 0x%04x:0x%08x\n",
|
|
|
|
*(Bit16u*)(tss+0x18), *(Bit32u*)(tss+0x14));
|
|
|
|
dbg_printf ("cr3: 0x%08x\n", *(Bit32u*)(tss+0x1c));
|
|
|
|
dbg_printf ("eip: 0x%08x\n", *(Bit32u*)(tss+0x20));
|
|
|
|
dbg_printf ("eflags: 0x%08x\n", *(Bit32u*)(tss+0x24));
|
|
|
|
|
|
|
|
dbg_printf ("cs: 0x%04x ds: 0x%04x ss: 0x%04x\n",
|
|
|
|
*(Bit16u*)(tss+76), *(Bit16u*)(tss+84), *(Bit16u*)(tss+80));
|
|
|
|
dbg_printf ("es: 0x%04x fs: 0x%04x gs: 0x%04x\n",
|
|
|
|
*(Bit16u*)(tss+72), *(Bit16u*)(tss+88), *(Bit16u*)(tss+92));
|
|
|
|
|
|
|
|
dbg_printf ("eax: 0x%08x ebx: 0x%08x ecx: 0x%08x edx: 0x%08x\n",
|
|
|
|
*(Bit32u*)(tss+0x28), *(Bit32u*)(tss+0x34), *(Bit32u*)(tss+0x2c), *(Bit32u*)(tss+0x30));
|
|
|
|
dbg_printf ("esi: 0x%08x edi: 0x%08x ebp: 0x%08x esp: 0x%08x\n",
|
|
|
|
*(Bit32u*)(tss+0x40), *(Bit32u*)(tss+0x44), *(Bit32u*)(tss+0x3c), *(Bit32u*)(tss+0x38));
|
|
|
|
|
|
|
|
dbg_printf ("ldt: 0x%04x\n", *(Bit16u*)(tss+0x60));
|
|
|
|
dbg_printf ("i/o map: 0x%04x\n", *(Bit16u*)(tss+0x66));
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_info_tss_command(bx_num_range range) {
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_cpu_t cpu;
|
|
|
|
BX_CPU(0)->dbg_get_cpu(&cpu);
|
|
|
|
|
|
|
|
int print_table = 0;
|
|
|
|
if (range.to == EMPTY_ARG) {
|
|
|
|
// show all entries
|
|
|
|
Bit32u laddr = (cpu.tr.des_l>>16) |
|
|
|
|
((cpu.tr.des_h<<16)&0x00ff0000) |
|
|
|
|
(cpu.tr.des_h & 0xff000000);
|
|
|
|
Bit32u len = (cpu.tr.des_l & 0xffff) + 1;
|
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("tr:s=0x%x, base=0x%x, valid=%u\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) cpu.tr.sel, laddr, (unsigned) cpu.tr.valid);
|
|
|
|
|
|
|
|
Bit32u paddr;
|
|
|
|
bx_bool paddr_valid;
|
|
|
|
BX_CPU(dbg_cpu)->dbg_xlate_linear2phy(laddr, &paddr, &paddr_valid);
|
|
|
|
|
|
|
|
bx_dbg_print_tss(BX_MEM(0)->vector+paddr, len);
|
|
|
|
|
|
|
|
range.from = 0;
|
|
|
|
range.to = (cpu.gdtr.limit) / 8;
|
|
|
|
print_table = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
bx_num_range make_num_range (Bit64s from, Bit64s to)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
bx_num_range x;
|
|
|
|
x.from = from;
|
|
|
|
x.to = to;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_info_control_regs_command(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
bx_dbg_cpu_t cpu;
|
|
|
|
#if BX_CPU_LEVEL >= 2
|
|
|
|
BX_CPU(0)->dbg_get_cpu(&cpu);
|
|
|
|
int cr0 = cpu.cr0;
|
|
|
|
int cr2 = cpu.cr2;
|
|
|
|
int cr3 = cpu.cr3;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("CR0=0x%08x\n", cr0);
|
|
|
|
dbg_printf (" PG=paging=%d\n", (cr0>>31) & 1);
|
|
|
|
dbg_printf (" CD=cache disable=%d\n", (cr0>>30) & 1);
|
|
|
|
dbg_printf (" NW=not write through=%d\n", (cr0>>29) & 1);
|
|
|
|
dbg_printf (" AM=alignment mask=%d\n", (cr0>>18) & 1);
|
|
|
|
dbg_printf (" WP=write protect=%d\n", (cr0>>16) & 1);
|
|
|
|
dbg_printf (" NE=numeric error=%d\n", (cr0>>5) & 1);
|
|
|
|
dbg_printf (" ET=extension type=%d\n", (cr0>>4) & 1);
|
|
|
|
dbg_printf (" TS=task switched=%d\n", (cr0>>3) & 1);
|
|
|
|
dbg_printf (" EM=FPU emulation=%d\n", (cr0>>2) & 1);
|
|
|
|
dbg_printf (" MP=monitor coprocessor=%d\n", (cr0>>1) & 1);
|
|
|
|
dbg_printf (" PE=protection enable=%d\n", (cr0>>0) & 1);
|
|
|
|
dbg_printf ("CR2=page fault linear address=0x%08x\n", cr2);
|
|
|
|
dbg_printf ("CR3=0x%08x\n", cr3);
|
|
|
|
dbg_printf (" PCD=page-level cache disable=%d\n", (cr3>>4) & 1);
|
|
|
|
dbg_printf (" PWT=page-level writes transparent=%d\n", (cr3>>3) & 1);
|
2003-11-28 18:07:29 +03:00
|
|
|
#if BX_CPU_LEVEL >= 4
|
|
|
|
int cr4 = cpu.cr4;
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("CR4=0x%08x\n", cr4);
|
|
|
|
dbg_printf (" VME=virtual-8086 mode extensions=%d\n", (cr4>>0) & 1);
|
|
|
|
dbg_printf (" PVI=protected-mode virtual interrupts=%d\n", (cr4>>1) & 1);
|
|
|
|
dbg_printf (" TSD=time stamp disable=%d\n", (cr4>>2) & 1);
|
|
|
|
dbg_printf (" DE=debugging extensions=%d\n", (cr4>>3) & 1);
|
|
|
|
dbg_printf (" PSE=page size extensions=%d\n", (cr4>>4) & 1);
|
|
|
|
dbg_printf (" PAE=physical address extension=%d\n", (cr4>>5) & 1);
|
|
|
|
dbg_printf (" MCE=machine check enable=%d\n", (cr4>>6) & 1);
|
|
|
|
dbg_printf (" PGE=page global enable=%d\n", (cr4>>7) & 1);
|
|
|
|
dbg_printf (" PCE=performance-monitor counter enable=%d\n", (cr4>>8) & 1);
|
|
|
|
dbg_printf (" OXFXSR=OS support for FXSAVE/FXRSTOR=%d\n", (cr4>>9) & 1);
|
|
|
|
dbg_printf (" OSXMMEXCPT=OS support for unmasked SIMD FP exceptions=%d\n", (cr4>>10) & 1);
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif /* BX_CPU_LEVEL >= 4*/
|
|
|
|
#else
|
|
|
|
/* BX_CPU_LEVEL < 2 */
|
|
|
|
dbg_printf ("CR0-4 register do not exist in cpu level %d", BX_CPU_LEVEL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* this implements the info ne2k commands in the debugger.
|
|
|
|
* info ne2k - shows all registers
|
|
|
|
* info ne2k page N - shows all registers in a page
|
|
|
|
* info ne2k page N reg M - shows just one register
|
|
|
|
*/
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_info_ne2k(int page, int reg)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
2004-08-06 19:49:55 +04:00
|
|
|
#if BX_SUPPORT_NE2K
|
2003-11-28 18:07:29 +03:00
|
|
|
DEV_ne2k_print_info (stderr, page, reg, 0);
|
|
|
|
#else
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("NE2000 support is not compiled in.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* this implements the info pic command in the debugger.
|
|
|
|
* info pic - shows pic registers
|
|
|
|
*/
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_info_pic()
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
DEV_pic_show_pic_state();
|
|
|
|
}
|
2004-08-24 14:15:56 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* this implements the info vga command in the debugger.
|
|
|
|
* info vga - shows vga registers
|
|
|
|
*/
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_info_vga()
|
2004-08-24 14:15:56 +04:00
|
|
|
{
|
|
|
|
DEV_vga_dump_status();
|
|
|
|
}
|
|
|
|
|
2003-11-28 18:07:29 +03:00
|
|
|
//
|
|
|
|
// Reports from various events
|
|
|
|
//
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_iac_report(unsigned vector, unsigned irq)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
#if BX_NUM_SIMULATORS > 1
|
|
|
|
unsigned tail, master;
|
|
|
|
#endif
|
|
|
|
|
2005-12-14 23:05:40 +03:00
|
|
|
if (doit) dbg_printf ("iac report: vector=%u\n", vector);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (bx_guard.report.irq) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("event icount=%u IRQ irq=%u vec=%x\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) BX_CPU(dbg_cpu)->guard_found.icount, irq, vector);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
#if BX_NUM_SIMULATORS > 1
|
|
|
|
if (bx_debugger.master_slave_mode == BX_DBG_SLAVE_MODE ) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: iac_report: in slave mode.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// Master simulator mode
|
|
|
|
if (bx_debugger.async_journal.size >= BX_DBG_ASYNC_JOURNAL_SIZE) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: iac: async journal full.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (bx_debugger.async_journal.size == 0) {
|
|
|
|
// start off point head & tail at same element
|
|
|
|
bx_debugger.async_journal.head = 0;
|
|
|
|
tail = bx_debugger.async_journal.tail = 0;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
|
|
|
tail = bx_debugger.async_journal.tail + 1;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
if (tail >= BX_DBG_ASYNC_JOURNAL_SIZE) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: iac_report: journal wrapped.\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(0);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
master = bx_debugger.master;
|
|
|
|
bx_debugger.async_journal.element[tail].what = BX_DBG_ASYNC_JOURNAL_IAC;
|
|
|
|
bx_debugger.async_journal.element[tail].icount = bx_guard_found[master].icount;
|
|
|
|
bx_debugger.async_journal.element[tail].u.iac.val = vector;
|
|
|
|
|
|
|
|
if (bx_debugger.async_journal.size)
|
|
|
|
bx_debugger.async_journal.tail++;
|
|
|
|
bx_debugger.async_journal.size++;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_a20_report(unsigned val)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
if (bx_guard.report.a20) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("event icount=%u A20 val=%u\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) BX_CPU(dbg_cpu)->guard_found.icount, val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_io_report(Bit32u addr, unsigned size, unsigned op, Bit32u val)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
if (bx_guard.report.io) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("event icount=%u IO addr=0x%x size=%u op=%s val=0x%x\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) BX_CPU(dbg_cpu)->guard_found.icount,
|
|
|
|
(unsigned) addr,
|
|
|
|
size,
|
|
|
|
(op==BX_READ) ? "read" : "write",
|
|
|
|
(unsigned) val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// nothing else to do. bx_dbg_inp() and bx_dbg_outp() do the journaling.
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_ucmem_report(Bit32u addr, unsigned size, unsigned op, Bit32u val)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
if (bx_guard.report.ucmem) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("event icount=%u UCmem addr=0x%x size=%u op=%s val=0x%x\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) BX_CPU(dbg_cpu)->guard_found.icount,
|
|
|
|
(unsigned) addr,
|
|
|
|
size,
|
|
|
|
(op==BX_READ) ? "read" : "write",
|
|
|
|
(unsigned) val);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
// nothing else to do. bx_dbg_ucmem_read() and bx_dbg_ucmem_write()
|
|
|
|
// do the journaling.
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_dma_report(Bit32u addr, unsigned len, unsigned what, Bit32u val)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
if (bx_dbg_batch_dma.this_many == 0) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%s: DMA batch this_many=0.\n", argv0);
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// if Q is full, post events (and flush)
|
|
|
|
if (bx_dbg_batch_dma.Qsize >= bx_dbg_batch_dma.this_many) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%s: DMA batch Q was not flushed.\n", argv0);
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// if Q already has MAX elements in it
|
|
|
|
if (bx_dbg_batch_dma.Qsize >= BX_BATCH_DMA_BUFSIZE) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("%s: DMA batch buffer overrun.\n", argv0);
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_dbg_exit(1);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
bx_dbg_batch_dma.Qsize++;
|
|
|
|
bx_dbg_batch_dma.Q[bx_dbg_batch_dma.Qsize-1].addr = addr;
|
|
|
|
bx_dbg_batch_dma.Q[bx_dbg_batch_dma.Qsize-1].len = len;
|
|
|
|
bx_dbg_batch_dma.Q[bx_dbg_batch_dma.Qsize-1].what = what;
|
|
|
|
bx_dbg_batch_dma.Q[bx_dbg_batch_dma.Qsize-1].val = val;
|
|
|
|
bx_dbg_batch_dma.Q[bx_dbg_batch_dma.Qsize-1].icount = BX_CPU(dbg_cpu)->guard_found.icount;
|
|
|
|
|
|
|
|
// if Q is full, post events (and flush)
|
|
|
|
if (bx_dbg_batch_dma.Qsize >= bx_dbg_batch_dma.this_many)
|
|
|
|
bx_dbg_post_dma_reports();
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_post_dma_reports(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
unsigned addr, len, what, val;
|
|
|
|
unsigned last_addr, last_len, last_what;
|
|
|
|
unsigned print_header;
|
|
|
|
unsigned first_iteration;
|
|
|
|
|
|
|
|
if (bx_guard.report.dma) {
|
|
|
|
if (bx_dbg_batch_dma.Qsize == 0) return; // nothing batched to print
|
|
|
|
|
|
|
|
// compress output so all contiguous DMA ops of the same type and size
|
|
|
|
// are printed on the same line
|
|
|
|
last_addr = bx_dbg_batch_dma.Q[0].addr;
|
|
|
|
last_len = bx_dbg_batch_dma.Q[0].len;
|
|
|
|
last_what = bx_dbg_batch_dma.Q[0].what;
|
|
|
|
first_iteration = 1;
|
|
|
|
|
|
|
|
for (i=0; i<bx_dbg_batch_dma.Qsize; i++) {
|
|
|
|
addr = bx_dbg_batch_dma.Q[i].addr;
|
|
|
|
len = bx_dbg_batch_dma.Q[i].len;
|
|
|
|
what = bx_dbg_batch_dma.Q[i].what;
|
|
|
|
val = bx_dbg_batch_dma.Q[i].val;
|
|
|
|
|
|
|
|
if (len != last_len)
|
|
|
|
print_header = 1;
|
|
|
|
else if (what != last_what)
|
|
|
|
print_header = 1;
|
|
|
|
else if (addr != (last_addr + last_len))
|
|
|
|
print_header = 1;
|
|
|
|
else
|
|
|
|
print_header = 0;
|
|
|
|
|
|
|
|
// now store current values for next iteration
|
|
|
|
last_addr = addr;
|
|
|
|
last_len = len;
|
|
|
|
last_what = what;
|
|
|
|
|
|
|
|
if (print_header) {
|
|
|
|
if (!first_iteration) // need return from previous line
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
else
|
|
|
|
first_iteration = 0;
|
|
|
|
// need to output the event header
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("event icount=%u DMA addr=0x%x size=%u op=%s val=0x%x",
|
2003-11-28 18:07:29 +03:00
|
|
|
(unsigned) bx_dbg_batch_dma.Q[i].icount,
|
|
|
|
addr, len, (what==BX_READ) ? "read" : "write",
|
|
|
|
val );
|
|
|
|
print_header = 0;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
|
|
|
// *no* need to output the event header
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf (" 0x%x", val);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
if (bx_dbg_batch_dma.Qsize)
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("\n");
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// empty Q, regardless of whether reports are printed
|
|
|
|
bx_dbg_batch_dma.Qsize = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// BW added. return non zero to cause a stop
|
2004-09-19 22:38:09 +04:00
|
|
|
static int symbol_level = 0;
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
int bx_dbg_symbolic_output(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
2004-09-19 22:38:09 +04:00
|
|
|
/* modes & address spaces */
|
|
|
|
if(BX_CPU(dbg_cpu)->cr0.pe != last_pe) {
|
|
|
|
dbg_printf (FMT_TICK ": Switched %s protected mode\n",
|
|
|
|
bx_pc_system.time_ticks(),
|
|
|
|
last_pe ? "from" : "to");
|
|
|
|
last_pe = !last_pe;
|
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2004-09-19 22:38:09 +04:00
|
|
|
if(last_vm != BX_CPU(dbg_cpu)->getB_VM ()) {
|
|
|
|
dbg_printf (FMT_TICK ": %s V86 mode\n",
|
|
|
|
bx_pc_system.time_ticks(),
|
|
|
|
last_vm ? "Exited" : "Entered");
|
|
|
|
last_vm = !last_vm;
|
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2004-09-19 22:38:09 +04:00
|
|
|
if(last_cr3 != BX_CPU(dbg_cpu)->cr3)
|
|
|
|
dbg_printf ("\n" FMT_TICK ": Address space switched since last trigger. CR3: 0x%08x\n",
|
|
|
|
bx_pc_system.time_ticks(), BX_CPU(dbg_cpu)->cr3);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2004-09-19 22:38:09 +04:00
|
|
|
/* interrupts */
|
|
|
|
if (dbg_show_mask & 0x40) {
|
|
|
|
if(BX_CPU(dbg_cpu)->show_flag & 0x4) {
|
|
|
|
dbg_printf (FMT_TICK ": softint %04x:%08x %08x\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_pc_system.time_ticks(),
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.cs,
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.eip,
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.laddr);
|
2004-09-19 22:38:09 +04:00
|
|
|
}
|
|
|
|
if((BX_CPU(dbg_cpu)->show_flag & 0x10) && !(BX_CPU(dbg_cpu)->show_flag & 0x4)) {
|
|
|
|
dbg_printf ("\n" FMT_TICK ": exception (not softint) %04x:%08x %08x\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_pc_system.time_ticks(),
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.cs,
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.eip,
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.laddr);
|
2004-09-19 22:38:09 +04:00
|
|
|
}
|
|
|
|
if(BX_CPU(dbg_cpu)->show_flag & 0x8) {
|
|
|
|
dbg_printf (FMT_TICK ": iret %04x:%08x %08x (from %08x)\n\n",
|
2003-11-28 18:07:29 +03:00
|
|
|
bx_pc_system.time_ticks(),
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.cs,
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.eip,
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.laddr,
|
|
|
|
BX_CPU(dbg_cpu)->show_eip);
|
2004-09-19 22:38:09 +04:00
|
|
|
}
|
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2004-09-19 22:38:09 +04:00
|
|
|
/* calls */
|
|
|
|
if(BX_CPU(dbg_cpu)->show_flag & 0x1) {
|
|
|
|
Bit32u phy = 0;
|
|
|
|
bx_bool valid;
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2004-09-19 22:38:09 +04:00
|
|
|
if (dbg_show_mask & 0x20) {
|
2003-11-28 18:07:29 +03:00
|
|
|
BX_CPU(dbg_cpu)->dbg_xlate_linear2phy(BX_CPU(dbg_cpu)->guard_found.laddr,
|
|
|
|
&phy, &valid);
|
|
|
|
|
2004-09-19 22:38:09 +04:00
|
|
|
// mingw doesn't like %ll and %*s in one statement
|
|
|
|
dbg_printf (FMT_TICK ":", bx_pc_system.time_ticks());
|
|
|
|
dbg_printf ("%*s call %04x:%08x 0x%08x (%08x) %s",
|
2003-11-28 18:07:29 +03:00
|
|
|
symbol_level+1," ",
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.cs,
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.eip,
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.laddr,
|
|
|
|
phy,
|
|
|
|
bx_dbg_symbolic_address(BX_CPU(dbg_cpu)->cr3,
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.eip,
|
|
|
|
BX_CPU(dbg_cpu)->guard_found.laddr - BX_CPU(dbg_cpu)->guard_found.eip) );
|
|
|
|
if(!valid)
|
2004-09-19 22:38:09 +04:00
|
|
|
dbg_printf (" phys not valid");
|
2003-11-28 18:07:29 +03:00
|
|
|
dbg_printf ("\n");
|
2004-09-19 22:38:09 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2004-09-19 22:38:09 +04:00
|
|
|
symbol_level++;
|
|
|
|
if(symbol_level > 40)
|
2003-11-28 18:07:29 +03:00
|
|
|
symbol_level = 10;
|
2004-09-19 22:38:09 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2004-09-19 22:38:09 +04:00
|
|
|
if (BX_CPU(dbg_cpu)->show_flag & 0x2) {
|
|
|
|
symbol_level--;
|
|
|
|
if(symbol_level < 0)
|
2003-11-28 18:07:29 +03:00
|
|
|
symbol_level = 0;
|
2004-09-19 22:38:09 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
2004-09-19 22:38:09 +04:00
|
|
|
BX_CPU(dbg_cpu)->show_flag = 0;
|
|
|
|
last_cr3 = BX_CPU(dbg_cpu)->cr3;
|
|
|
|
return 0;
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// BW added to dump page table
|
2005-03-26 22:41:59 +03:00
|
|
|
static void dbg_lin2phys(BX_CPU_C *cpu, Bit32u laddress, Bit32u *phy, bx_bool *valid, Bit32u *tlb_phy, bx_bool *tlb_valid)
|
|
|
|
{
|
2003-11-28 18:07:29 +03:00
|
|
|
Bit32u lpf, ppf, poffset, TLB_index, paddress;
|
|
|
|
Bit32u pde, pde_addr;
|
|
|
|
Bit32u pte, pte_addr;
|
|
|
|
|
|
|
|
*tlb_valid = 0;
|
|
|
|
|
|
|
|
if (cpu->cr0.pg == 0) {
|
|
|
|
*phy = laddress;
|
|
|
|
*valid = 1;
|
|
|
|
return;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
lpf = laddress & 0xfffff000; // linear page frame
|
|
|
|
poffset = laddress & 0x00000fff; // physical offset
|
|
|
|
TLB_index = BX_TLB_INDEX_OF(lpf);
|
|
|
|
|
|
|
|
// see if page is in the TLB first
|
|
|
|
#if BX_USE_QUICK_TLB_INVALIDATE
|
|
|
|
if (cpu->TLB.entry[TLB_index].lpf == (lpf | cpu->TLB.tlb_invalidate)) {
|
|
|
|
#else
|
|
|
|
if (cpu->TLB.entry[TLB_index].lpf == (lpf)) {
|
|
|
|
#endif
|
2005-04-08 22:30:34 +04:00
|
|
|
*tlb_phy = cpu->TLB.entry[TLB_index].ppf | poffset;
|
|
|
|
*tlb_valid = 1;
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get page dir entry
|
|
|
|
pde_addr = (cpu->cr3 & 0xfffff000) |
|
|
|
|
((laddress & 0xffc00000) >> 20);
|
|
|
|
BX_MEM(0)->readPhysicalPage(cpu, pde_addr, 4, &pde);
|
|
|
|
if ( !(pde & 0x01) ) {
|
|
|
|
// Page Directory Entry NOT present
|
|
|
|
goto page_fault;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
// Get page table entry
|
2005-03-26 22:41:59 +03:00
|
|
|
pte_addr = (pde & 0xfffff000) | ((laddress & 0x003ff000) >> 10);
|
2003-11-28 18:07:29 +03:00
|
|
|
BX_MEM(0)->readPhysicalPage(cpu, pte_addr, 4, &pte);
|
|
|
|
if ( !(pte & 0x01) ) {
|
|
|
|
// Page Table Entry NOT present
|
|
|
|
goto page_fault;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
ppf = pte & 0xfffff000;
|
|
|
|
paddress = ppf | poffset;
|
|
|
|
|
|
|
|
*phy = paddress;
|
|
|
|
*valid = 1;
|
|
|
|
return;
|
|
|
|
|
|
|
|
page_fault:
|
|
|
|
*phy = 0;
|
|
|
|
*valid = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dbg_dump_table(bx_bool all)
|
|
|
|
{
|
|
|
|
Bit32u lina;
|
|
|
|
Bit32u phy, tlb_phy;
|
|
|
|
bx_bool valid, tlb_valid;
|
|
|
|
|
|
|
|
Bit32u start_lina, start_phy; // start of a valid translation interval
|
|
|
|
|
|
|
|
if (BX_CPU(dbg_cpu)->cr0.pg == 0) {
|
|
|
|
printf("paging off\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("cr3: %08x \n", BX_CPU(dbg_cpu)->cr3);
|
|
|
|
|
|
|
|
lina = 0;
|
|
|
|
start_lina = 1;
|
|
|
|
start_phy = 2;
|
|
|
|
while(1) {
|
|
|
|
dbg_lin2phys(BX_CPU(dbg_cpu), lina, &phy, &valid, &tlb_phy, &tlb_valid);
|
|
|
|
if(valid) {
|
2005-03-26 22:41:59 +03:00
|
|
|
if( (lina - start_lina != phy - start_phy) || tlb_valid) {
|
|
|
|
if(all && (start_lina != 1))
|
2003-11-28 18:07:29 +03:00
|
|
|
printf("%08x - %08x: %8x - %8x\n",
|
|
|
|
start_lina, lina - 0x1000, start_phy, start_phy + (lina-0x1000-start_lina));
|
|
|
|
start_lina = lina;
|
|
|
|
start_phy = phy;
|
2005-03-26 22:41:59 +03:00
|
|
|
}
|
|
|
|
if(tlb_valid) {
|
2003-11-28 18:07:29 +03:00
|
|
|
if(all && tlb_phy == phy)
|
2005-03-26 22:41:59 +03:00
|
|
|
printf("%08x : %8x (%8x) in TLB\n", lina, phy, tlb_phy);
|
2003-11-28 18:07:29 +03:00
|
|
|
if(tlb_phy != phy)
|
2005-03-26 22:41:59 +03:00
|
|
|
printf("%08x : %8x (%8x) in TLB Phys differs!!!\n", lina, phy, tlb_phy);
|
2003-11-28 18:07:29 +03:00
|
|
|
start_lina = 1;
|
|
|
|
start_phy = 2;
|
2005-03-26 22:41:59 +03:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
} else {
|
2005-03-26 22:41:59 +03:00
|
|
|
if(all && start_lina != 1)
|
2003-11-28 18:07:29 +03:00
|
|
|
printf("%08x - %08x: %8x - %8x\n",
|
2005-03-26 22:41:59 +03:00
|
|
|
start_lina, lina - 0x1000, start_phy, start_phy + (lina-0x1000-start_lina));
|
|
|
|
if(tlb_valid) {
|
2003-11-28 18:07:29 +03:00
|
|
|
printf("%08x : (%8x) in TLB Table not valid!!!\n",
|
2005-03-26 22:41:59 +03:00
|
|
|
lina, tlb_phy);
|
|
|
|
}
|
|
|
|
start_lina = 1;
|
|
|
|
start_phy = 2;
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if(lina == 0xfffff000)
|
|
|
|
break;
|
|
|
|
lina += 0x1000;
|
|
|
|
}
|
|
|
|
if(all && start_lina != 1)
|
|
|
|
printf("%08x - %08x: %8x - %8x\n",
|
|
|
|
start_lina, 0xfffff000, start_phy, start_phy + (0xfffff000-start_lina));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*form RB list*/
|
|
|
|
static char* bx_dbg_ivt_desc(int intnum)
|
|
|
|
{ char* ret = "";
|
|
|
|
switch (intnum)
|
|
|
|
{ case 0x00 : ret = "DIVIDE ERROR" ; break;
|
|
|
|
case 0x01 : ret = "SINGLE STEP" ; break;
|
|
|
|
case 0x02 : ret = "NON-MASKABLE INTERRUPT" ; break;
|
|
|
|
case 0x03 : ret = "BREAKPOINT" ; break;
|
|
|
|
case 0x04 : ret = "INT0 DETECTED OVERFLOW" ; break;
|
|
|
|
case 0x05 : ret = "BOUND RANGE EXCEED" ; break;
|
|
|
|
case 0x06 : ret = "INVALID OPCODE" ; break;
|
|
|
|
case 0x07 : ret = "PROCESSOR EXTENSION NOT AVAILABLE" ; break;
|
|
|
|
case 0x08 : ret = "IRQ0 - SYSTEM TIMER" ; break;
|
|
|
|
case 0x09 : ret = "IRQ1 - KEYBOARD DATA READY" ; break;
|
|
|
|
case 0x0a : ret = "IRQ2 - LPT2" ; break;
|
|
|
|
case 0x0b : ret = "IRQ3 - COM2" ; break;
|
|
|
|
case 0x0c : ret = "IRQ4 - COM1" ; break;
|
|
|
|
case 0x0d : ret = "IRQ5 - FIXED DISK" ; break;
|
|
|
|
case 0x0e : ret = "IRQ6 - DISKETTE CONTROLLER" ; break;
|
|
|
|
case 0x0f : ret = "IRQ7 - PARALLEL PRINTER" ; break;
|
|
|
|
case 0x10 : ret = "VIDEO" ; break;
|
|
|
|
case 0x11 : ret = "GET EQUIPMENT LIST" ; break;
|
|
|
|
case 0x12 : ret = "GET MEMORY SIZE" ; break;
|
|
|
|
case 0x13 : ret = "DISK" ; break;
|
|
|
|
case 0x14 : ret = "SERIAL" ; break;
|
|
|
|
case 0x15 : ret = "SYSTEM" ; break;
|
|
|
|
case 0x16 : ret = "KEYBOARD" ; break;
|
|
|
|
case 0x17 : ret = "PRINTER" ; break;
|
|
|
|
case 0x18 : ret = "CASETTE BASIC" ; break;
|
|
|
|
case 0x19 : ret = "BOOTSTRAP LOADER" ; break;
|
|
|
|
case 0x1a : ret = "TIME" ; break;
|
|
|
|
case 0x1b : ret = "KEYBOARD - CONTROL-BREAK HANDLER" ; break;
|
|
|
|
case 0x1c : ret = "TIME - SYSTEM TIMER TICK" ; break;
|
|
|
|
case 0x1d : ret = "SYSTEM DATA - VIDEO PARAMETER TABLES"; break;
|
|
|
|
case 0x1e : ret = "SYSTEM DATA - DISKETTE PARAMETERS" ; break;
|
|
|
|
case 0x1f : ret = "SYSTEM DATA - 8x8 GRAPHICS FONT" ; break;
|
|
|
|
case 0x70 : ret = "IRQ8 - CMOS REAL-TIME CLOCK" ; break;
|
|
|
|
case 0x71 : ret = "IRQ9 - REDIRECTED TO INT 0A BY BIOS" ; break;
|
|
|
|
case 0x72 : ret = "IRQ10 - RESERVED" ; break;
|
|
|
|
case 0x73 : ret = "IRQ11 - RESERVED" ; break;
|
|
|
|
case 0x74 : ret = "IRQ12 - POINTING DEVICE" ; break;
|
|
|
|
case 0x75 : ret = "IRQ13 - MATH COPROCESSOR EXCEPTION" ; break;
|
|
|
|
case 0x76 : ret = "IRQ14 - HARD DISK CONTROLLER OPERATION COMPLETE"; break;
|
|
|
|
case 0x77 : ret = "IRQ15 - SECONDARY IDE CONTROLLER OPERATION COMPLETE"; break;
|
|
|
|
default : ret = "" ; break;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_info_ivt_command(bx_num_range r)
|
2003-11-28 18:07:29 +03:00
|
|
|
{ bx_dbg_cpu_t cpu;
|
|
|
|
int i;
|
|
|
|
unsigned char buff[4];
|
|
|
|
Bit16u seg;
|
|
|
|
Bit16u off;
|
|
|
|
int tail = 0;
|
|
|
|
|
|
|
|
BX_CPU(dbg_cpu)->dbg_get_cpu(&cpu);
|
|
|
|
|
|
|
|
if ((cpu.cr0 & 1) == 0)
|
2005-04-08 22:30:34 +04:00
|
|
|
{
|
|
|
|
if ((r.from == -1L) && (r.to == -1L))
|
2003-11-28 18:07:29 +03:00
|
|
|
{ r.from = 0;
|
|
|
|
r.to = 256;
|
|
|
|
tail = 1;
|
|
|
|
}
|
|
|
|
else if (r.to == r.from)
|
|
|
|
{ r.to = r.from + 1L;
|
|
|
|
}
|
|
|
|
if ((r.from > r.to) || (r.from > 256) || (r.to > 256))
|
|
|
|
{ dbg_printf("wrong range\n");
|
|
|
|
return;
|
|
|
|
}
|
2005-06-10 00:08:17 +04:00
|
|
|
for (i = (int)r.from; i < r.to; i++)
|
2005-04-08 22:30:34 +04:00
|
|
|
{
|
|
|
|
BX_MEM(0)->dbg_fetch_mem(cpu.idtr.base + i * 4, sizeof(buff), buff);
|
2003-11-28 18:07:29 +03:00
|
|
|
#ifdef BX_LITTLE_ENDIAN
|
|
|
|
seg = *(Bit16u*)(&buff[2]);
|
|
|
|
off = *(Bit16u*)(&buff[0]);
|
|
|
|
#else
|
|
|
|
seg = (buff[3] << 8) | buff[2];
|
|
|
|
off = (buff[1] << 8) | buff[0];
|
|
|
|
#endif
|
|
|
|
BX_MEM(0)->dbg_fetch_mem(cpu.idtr.base + ((seg << 4) + off), sizeof(buff), buff);
|
|
|
|
dbg_printf("INT# %02x > %04X:%04X (%08X) %s%s\n", i, seg, off, cpu.idtr.base + ((seg << 4) + off), bx_dbg_ivt_desc(i), (buff[0] == 0xcf) ? " ; dummy iret" : "");
|
|
|
|
}
|
2005-12-14 23:05:40 +03:00
|
|
|
if (tail == 1) dbg_printf ("You can list individual entries with 'info ivt NUM' or groups with 'info ivt NUM NUM'\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
dbg_printf("cpu in protected mode, use info idt\n");
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_help_command(char* command)
|
2005-04-08 22:30:34 +04:00
|
|
|
{
|
|
|
|
char* p;
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (command == NULL)
|
|
|
|
{
|
|
|
|
dbg_printf("help - show list of debugger commands\n");
|
|
|
|
dbg_printf("help \'command\'- show short command description\n");
|
|
|
|
dbg_printf("-*- Debugger control -*-\n");
|
|
|
|
dbg_printf(" help, q|quit|exit, set, instrument, show, trace-on, trace-off,\n");
|
|
|
|
dbg_printf(" record, playback, load-symbols, slist\n");
|
|
|
|
dbg_printf("-*- Execution control -*-\n");
|
|
|
|
dbg_printf(" c|cont, s|step|stepi, p|n|next, modebp\n");
|
|
|
|
dbg_printf("-*- Breakpoint management -*-\n");
|
2004-11-15 13:43:39 +03:00
|
|
|
dbg_printf(" vb|vbreak, lb|lbreak, pb|pbreak|b|break, sb, sba, blist,\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
dbg_printf(" bpe, bpd, d|del|delete\n");
|
|
|
|
dbg_printf("-*- CPU and memory contents -*-\n");
|
|
|
|
dbg_printf(" x, xp, u|disas|disassemble, r|reg|registers, setpmem, crc, info, dump_cpu,\n");
|
|
|
|
dbg_printf(" set_cpu, ptime, print-stack, watch, unwatch, ?|calc\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
p = command;
|
|
|
|
for (; *p != 0 && *p != '\"' && *p != '\''; p++); p++;
|
|
|
|
for (; *p != 0 && *p != '\"' && *p != '\''; p++); *p = 0;
|
|
|
|
p = command;
|
|
|
|
for (; *p != 0 && *p != '\"' && *p != '\''; p++); p++;
|
|
|
|
|
|
|
|
dbg_printf("help %s\n", p);
|
|
|
|
|
|
|
|
if (strcmp(p, "help") == 0)
|
|
|
|
{
|
|
|
|
bx_dbg_help_command(NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "quit") == 0) ||
|
|
|
|
(strcmp(p, "q") == 0))
|
|
|
|
{
|
|
|
|
dbg_printf("%s - quit debugger and execution\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "c") == 0) ||
|
|
|
|
(strcmp(p, "cont") == 0))
|
|
|
|
{
|
|
|
|
dbg_printf("%s - continue executing\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "stepi") == 0) ||
|
|
|
|
(strcmp(p, "step") == 0) ||
|
2005-04-08 22:30:34 +04:00
|
|
|
(strcmp(p, "s") == 0))
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
dbg_printf("%s [count] - execute count instructions, default is 1\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "next") == 0) ||
|
|
|
|
(strcmp(p, "n") == 0) ||
|
|
|
|
(strcmp(p, "p") == 0))
|
|
|
|
{
|
|
|
|
dbg_printf("%s - execute instructions, stepping over subroutines\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "vbreak") == 0) ||
|
|
|
|
(strcmp(p, "vb") == 0))
|
|
|
|
{
|
|
|
|
dbg_printf("%s seg:off - set a virtual address instruction breakpoint\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "lbreak") == 0) ||
|
|
|
|
(strcmp(p, "lb") == 0))
|
|
|
|
{
|
|
|
|
dbg_printf("%s addr - set a linear address instruction breakpoint\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "pbreak") == 0) ||
|
|
|
|
(strcmp(p, "break") == 0) ||
|
2005-04-08 22:30:34 +04:00
|
|
|
(strcmp(p, "pb") == 0) ||
|
|
|
|
(strcmp(p, "b") == 0))
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
dbg_printf("%s [*] addr - set a physical address instruction preakpoint\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "delete") == 0) ||
|
|
|
|
(strcmp(p, "del") == 0) ||
|
2005-04-08 22:30:34 +04:00
|
|
|
(strcmp(p, "d") == 0))
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
dbg_printf("%s n - delete a breakpoint\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "bpe") == 0))
|
|
|
|
{
|
|
|
|
dbg_printf("%s n - enable a breakpoint\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "bpd") == 0))
|
|
|
|
{
|
|
|
|
dbg_printf("%s n - disable a breakpoint\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "blist") == 0))
|
|
|
|
{
|
|
|
|
dbg_printf("%s - list all breakpoints (same as 'info break')\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "xp") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s /nuf addr - examine memory at physical address\n", p);
|
|
|
|
goto nuf_help;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "x") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s /nuf addr - examine memory at linear address\n", p);
|
|
|
|
nuf_help:
|
|
|
|
dbg_printf(" nuf is a sequence of numbers (how much values\n");
|
|
|
|
dbg_printf(" to display) and one or more of the [mxduotcsibhwg]\n");
|
|
|
|
dbg_printf(" format specificators:\n");
|
|
|
|
dbg_printf(" x,d,u,o,t,c,s,i select the format of the output (they stand for\n");
|
|
|
|
dbg_printf(" hex, decimal, unsigned, octal, binary, char, asciiz, instr)\n");
|
|
|
|
dbg_printf(" b,h,w,g select the size of a data element (for byte, half-word,\n");
|
|
|
|
dbg_printf(" word and giant word)\n");
|
|
|
|
dbg_printf(" m selects an alternative output format (memory dump)\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "r") == 0)||
|
|
|
|
(strcmp(p, "reg") == 0)||
|
|
|
|
(strcmp(p, "registers") == 0))
|
|
|
|
{
|
|
|
|
dbg_printf("%s = expression - set register value to expression\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "setpmem") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s addr datasize val - set physical memory location of size datasize to value val\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "crc") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s addr1 addr2 - show CRC for physical memory range addr1..addr2\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "info") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s break - show information about current breakpoint status\n", p);
|
|
|
|
dbg_printf("%s dirty - show physical pages dirtied (written to) since last display\n", p);
|
|
|
|
dbg_printf("%s program - execution status of the program\n", p);
|
|
|
|
dbg_printf("%s r|reg|registers - list of CPU integer registers and their contents\n", p);
|
|
|
|
dbg_printf("%s cpu - list of CPU registers and their contents\n", p);
|
|
|
|
dbg_printf("%s fpu - list of FPU registers and their contents\n", p);
|
|
|
|
dbg_printf("%s idt - show interrupt descriptor table\n", p);
|
|
|
|
dbg_printf("%s ivt - show interrupt vector table\n", p);
|
|
|
|
dbg_printf("%s gdt - show global descriptor table\n", p);
|
|
|
|
dbg_printf("%s tss - show current task state segment\n", p);
|
|
|
|
dbg_printf("%s cr - show CR0-4 registers\n", p);
|
|
|
|
dbg_printf("%s flags - show decoded EFLAGS register\n", p);
|
|
|
|
dbg_printf("%s symbols [string] - list symbols whose prefix is string\n", p);
|
|
|
|
dbg_printf("%s pic - show PICs registers\n", p);
|
|
|
|
dbg_printf("%s ne2000 - show NE2000 registers\n", p);
|
2004-08-24 14:15:56 +04:00
|
|
|
dbg_printf("%s vga - show vga registers\n", p);
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "set") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s $reg = val - change CPU register to value val\n", p);
|
|
|
|
dbg_printf("%s $disassemble_size = n - tell debugger what segment size [16|32] to use\n", p);
|
|
|
|
dbg_printf("when \"disassemble\" command is used. Default is 32\n");
|
|
|
|
dbg_printf("%s $auto_disassemble = n - cause debugger to disassemble current instruction\n", p);
|
|
|
|
dbg_printf("every time execution stops if n = 1. Default is 0\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "dump_cpu") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s - dump complete cpu state\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "set_cpu") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s - set complete cpu state\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "disassemble") == 0) ||
|
|
|
|
(strcmp(p, "disas") == 0) ||
|
|
|
|
(strcmp(p, "u") == 0))
|
|
|
|
{
|
|
|
|
dbg_printf("%s [/count] start end - disassemble instructions for given linear adress\n", p);
|
|
|
|
dbg_printf(" Optional 'count' is the number of disassembled instructions\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "instrument") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s start - calls bx_instr_start()\n", p);
|
|
|
|
dbg_printf("%s stop - calls bx_instr_stop()\n", p);
|
|
|
|
dbg_printf("%s reset - calls bx_instr_reset()\n", p);
|
|
|
|
dbg_printf("%s print - calls bx_instr_print()\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "trace-on") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s - disassemble every executed instruction\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "trace-off") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s - disable tracing\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "ptime") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s - print current time (number of ticks since start of simulation)\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "sb") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s delta - insert a time breakpoint delta instruction into the future\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "sba") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s time - insert a time breakpoint at time\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "record") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s filename - record console input to file filename\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "playback") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s filename - playbackconsole input from file filename\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "print-stack") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s [num_words] - print the num_words top 16 bit words on the stack\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "watch") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s - print current watch point status\n", p);
|
|
|
|
dbg_printf("%s stop - stop simulation whena watchpoint is encountred\n", p);
|
|
|
|
dbg_printf("%s continue - do not stop the simulation when watch point is encountred\n", p);
|
|
|
|
dbg_printf("%s read addr - insert a read watch point at physical address addr\n", p);
|
|
|
|
dbg_printf("%s write addr - insert a write watch point at physical address addr\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "unwatch") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s - remove all watch points\n", p);
|
|
|
|
dbg_printf("%s read addr - remove a read watch point at physical address addr\n", p);
|
|
|
|
dbg_printf("%s write addr - remove a write watch point at physical address addr\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "load-symbols") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s [global] filename [offset] - load symbols from file filename\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "slist") == 0))
|
|
|
|
{
|
|
|
|
dbg_printf("%s [string] - list symbols whose preffix is string (same as 'info symbols')\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "modebp") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s - toggles vm86 mode switch breakpoint\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (strcmp(p, "show") == 0)
|
|
|
|
{
|
|
|
|
dbg_printf("%s [string] - toggles show symbolic info (calls to begin with)\n", p);
|
|
|
|
dbg_printf("%s - shows current show mode\n", p);
|
|
|
|
dbg_printf("%s \"mode\" - show, when processor switch mode\n", p);
|
|
|
|
dbg_printf("%s \"int\" - show, when interrupt is happens\n", p);
|
|
|
|
dbg_printf("%s \"call\" - show, when call is happens\n", p);
|
|
|
|
dbg_printf("%s \"ret\" - show, when iret is happens\n", p);
|
|
|
|
dbg_printf("%s \"off\" - toggles off symbolic info\n", p);
|
|
|
|
dbg_printf("%s \"dbg-all\" - turn on all show flags\n", p);
|
|
|
|
dbg_printf("%s \"none\" - turn off all show flags\n", p);
|
|
|
|
dbg_printf("%s \"tab\" - show page tables\n", p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((strcmp(p, "calc") == 0) ||
|
|
|
|
(strcmp(p, "?") == 0))
|
|
|
|
{
|
|
|
|
dbg_printf("%s expr - calculate a expression and display the result.\n", p);
|
|
|
|
dbg_printf(" 'expr' can reference any general-purpose and segment\n");
|
|
|
|
dbg_printf(" registers, use any arithmetic and logic operations, and\n");
|
|
|
|
dbg_printf(" also the special ':' operator which computes the linear\n");
|
|
|
|
dbg_printf(" address for a segment:offset (in real and v86 mode) or\n");
|
|
|
|
dbg_printf(" of a selector:offset (in protected mode) pair.\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dbg_printf("%s - unknow command, try help\n", p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_calc_command(Bit64u value)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
dbg_printf ("0x" FMT_LL "x " FMT_LL "d\n", value, value);
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
Bit32u bx_dbg_get_reg_value(Regs reg)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
switch(reg)
|
|
|
|
{
|
|
|
|
case rAL:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg8l(BX_8BIT_REG_AL);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rBL:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg8l(BX_8BIT_REG_BL);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rCL:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg8l(BX_8BIT_REG_CL);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rDL:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg8l(BX_8BIT_REG_DL);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rAH:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg8h(BX_8BIT_REG_AH);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rBH:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg8h(BX_8BIT_REG_BH);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rCH:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg8h(BX_8BIT_REG_CH);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rDH:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg8h(BX_8BIT_REG_DH);
|
|
|
|
|
2003-11-28 18:07:29 +03:00
|
|
|
case rAX:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg16(BX_16BIT_REG_AX);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rBX:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg16(BX_16BIT_REG_BX);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rCX:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg16(BX_16BIT_REG_CX);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rDX:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg16(BX_16BIT_REG_DX);
|
|
|
|
case rSI:
|
|
|
|
return BX_CPU(dbg_cpu)->get_reg16(BX_16BIT_REG_SI);
|
|
|
|
case rDI:
|
|
|
|
return BX_CPU(dbg_cpu)->get_reg16(BX_16BIT_REG_DI);
|
|
|
|
case rBP:
|
|
|
|
return BX_CPU(dbg_cpu)->get_reg16(BX_16BIT_REG_BP);
|
|
|
|
case rSP:
|
|
|
|
return BX_CPU(dbg_cpu)->get_reg16(BX_16BIT_REG_SP);
|
|
|
|
|
2003-11-28 18:07:29 +03:00
|
|
|
case rEAX:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_EAX);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rEBX:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_EBX);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rECX:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_ECX);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rEDX:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_EDX);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rESI:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_ESI);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rEDI:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_EDI);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rEBP:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_EBP);
|
2003-11-28 18:07:29 +03:00
|
|
|
case rESP:
|
2005-11-27 21:25:57 +03:00
|
|
|
return BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_ESP);
|
|
|
|
|
2003-11-28 18:07:29 +03:00
|
|
|
case rIP:
|
2005-11-27 21:25:57 +03:00
|
|
|
return (Bit16u) BX_CPU(dbg_cpu)->get_ip();
|
2003-11-28 18:07:29 +03:00
|
|
|
case rEIP:
|
2005-11-27 21:25:57 +03:00
|
|
|
return (Bit32u) BX_CPU(dbg_cpu)->get_ip();
|
|
|
|
|
2003-11-28 18:07:29 +03:00
|
|
|
default:
|
|
|
|
fprintf(stderr, "unknown register ??? (BUG!!!)\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_set_reg_value (Regs reg, Bit32u value)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
switch(reg)
|
|
|
|
{
|
|
|
|
case rAL:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg8l(BX_8BIT_REG_AL, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rBL:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg8l(BX_8BIT_REG_BL, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rCL:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg8l(BX_8BIT_REG_CL, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rDL:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg8l(BX_8BIT_REG_DL, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rAH:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg8h(BX_8BIT_REG_AH, value>>8);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rBH:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg8h(BX_8BIT_REG_BH, value>>8);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rCH:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg8h(BX_8BIT_REG_CH, value>>8);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rDH:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg8h(BX_8BIT_REG_DH, value>>8);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
2005-11-27 21:25:57 +03:00
|
|
|
|
2003-11-28 18:07:29 +03:00
|
|
|
case rAX:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg16(BX_16BIT_REG_AX, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rBX:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg16(BX_16BIT_REG_BX, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rCX:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg16(BX_16BIT_REG_CX, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rDX:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg16(BX_16BIT_REG_DX, value);
|
|
|
|
break;
|
|
|
|
case rSI:
|
|
|
|
BX_CPU(dbg_cpu)->set_reg16(BX_16BIT_REG_SI, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
2005-11-27 21:25:57 +03:00
|
|
|
case rDI:
|
|
|
|
BX_CPU(dbg_cpu)->set_reg16(BX_16BIT_REG_DI, value);
|
|
|
|
break;
|
|
|
|
case rBP:
|
|
|
|
BX_CPU(dbg_cpu)->set_reg16(BX_16BIT_REG_BP, value);
|
|
|
|
break;
|
|
|
|
case rSP:
|
|
|
|
BX_CPU(dbg_cpu)->set_reg16(BX_16BIT_REG_SP, value);
|
|
|
|
break;
|
|
|
|
|
2003-11-28 18:07:29 +03:00
|
|
|
case rEAX:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg32(BX_32BIT_REG_EAX, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rEBX:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg32(BX_32BIT_REG_EBX, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rECX:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg32(BX_32BIT_REG_ECX, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rEDX:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg32(BX_32BIT_REG_EDX, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rESI:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg32(BX_32BIT_REG_ESI, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rEDI:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg32(BX_32BIT_REG_EDI, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rEBP:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg32(BX_32BIT_REG_EBP, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
case rESP:
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU(dbg_cpu)->set_reg32(BX_32BIT_REG_ESP, value);
|
2003-11-28 18:07:29 +03:00
|
|
|
break;
|
|
|
|
/*
|
|
|
|
case rIP:
|
|
|
|
BX_CPU(dbg_cpu)->set_IP(value);
|
|
|
|
break;
|
|
|
|
case rEIP:
|
|
|
|
BX_CPU(dbg_cpu)->set_EIP(value);
|
|
|
|
break;
|
|
|
|
*/
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "unknown register ??? (BUG!!!)\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
Bit16u bx_dbg_get_selector_value(unsigned int seg_no)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
bx_dbg_sreg_t sreg;
|
|
|
|
|
|
|
|
if (seg_no > 5) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: seg_no out of bounds\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
BX_CPU(dbg_cpu)->dbg_get_sreg(&sreg, seg_no);
|
|
|
|
if (!sreg.valid) {
|
2005-12-14 23:05:40 +03:00
|
|
|
dbg_printf ("Error: segment valid bit cleared\n");
|
2003-11-28 18:07:29 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return sreg.sel;
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
Bit32u bx_dbg_get_laddr(Bit16u sel, Bit32u ofs)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
bool protmode = (BX_CPU(dbg_cpu)->cr0.pe)
|
|
|
|
&& !(BX_CPU(dbg_cpu)->get_VM());
|
|
|
|
|
|
|
|
if (protmode) {
|
|
|
|
bx_descriptor_t descriptor;
|
|
|
|
bx_selector_t selector;
|
|
|
|
Bit32u dword1, dword2;
|
|
|
|
|
|
|
|
/* if selector is NULL, error */
|
|
|
|
if ((sel & 0xfffc) == 0) {
|
|
|
|
dbg_printf ("ERROR: Dereferencing a NULL selector!\n");
|
|
|
|
return 0;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
/* parse fields in selector */
|
|
|
|
BX_CPU(dbg_cpu)->parse_selector(sel, &selector);
|
|
|
|
|
|
|
|
Bit32u desc_base;
|
|
|
|
if (selector.ti) {
|
|
|
|
// LDT
|
|
|
|
if ((selector.index*8 + 7) > BX_CPU(dbg_cpu)->ldtr.cache.u.ldt.limit) {
|
|
|
|
dbg_printf ("ERROR: selector (%04x) > GDT size limit\n", selector.index*8);
|
|
|
|
return 0;
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
desc_base = BX_CPU(dbg_cpu)->ldtr.cache.u.ldt.base;
|
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
|
|
|
// GDT
|
|
|
|
if ((selector.index*8 + 7) > BX_CPU(dbg_cpu)->gdtr.limit) {
|
|
|
|
dbg_printf ("ERROR: selector (%04x) > GDT size limit\n", selector.index*8);
|
|
|
|
return 0;
|
|
|
|
}
|
2005-04-08 22:30:34 +04:00
|
|
|
desc_base = BX_CPU(dbg_cpu)->gdtr.base;
|
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
BX_CPU(dbg_cpu)->access_linear(desc_base + selector.index * 8, 4, 0, BX_READ, &dword1);
|
|
|
|
BX_CPU(dbg_cpu)->access_linear(desc_base + selector.index * 8 + 4, 4, 0, BX_READ, &dword2);
|
|
|
|
|
|
|
|
memset (&descriptor, 0, sizeof (descriptor));
|
|
|
|
BX_CPU(dbg_cpu)->parse_descriptor(dword1, dword2, &descriptor);
|
|
|
|
|
|
|
|
if (!descriptor.segment) {
|
|
|
|
dbg_printf ("ERROR: selector %04x points to a system descriptor and is not supported!\n", sel);
|
|
|
|
return 0;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
/* #NP(selector) if descriptor is not present */
|
|
|
|
if (descriptor.p==0) {
|
|
|
|
dbg_printf ("ERROR: descriptor %04x not present!\n", sel);
|
|
|
|
return 0;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
Bit32u lowaddr, highaddr;
|
|
|
|
if (descriptor.u.segment.c_ed && !descriptor.u.segment.executable) // expand-down
|
|
|
|
lowaddr = descriptor.u.segment.limit_scaled,
|
|
|
|
highaddr = descriptor.u.segment.g ? 0xffffffff : 0xffff;
|
|
|
|
else
|
|
|
|
lowaddr = 0, highaddr = descriptor.u.segment.limit_scaled;
|
|
|
|
|
|
|
|
if ((ofs < lowaddr) || (ofs > highaddr)) {
|
|
|
|
dbg_printf ("WARNING: Offset %08X is out of selector %04x limit (%08x...%08x)!\n",
|
|
|
|
ofs, sel, lowaddr, highaddr);
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
return descriptor.u.segment.base + ofs;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
else {
|
|
|
|
return sel * 16 + ofs;
|
2005-04-08 22:30:34 +04:00
|
|
|
}
|
2003-11-28 18:07:29 +03:00
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_step_over_command ()
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
Bit8u *fetchPtr;
|
|
|
|
bxInstruction_c iStorage BX_CPP_AlignN (32);
|
|
|
|
bxInstruction_c *i = &iStorage;
|
2005-04-08 22:30:34 +04:00
|
|
|
Bit32u Laddr = BX_CPU (dbg_cpu)->get_segment_base(BX_SEG_REG_CS) +
|
2005-11-27 21:25:57 +03:00
|
|
|
BX_CPU (dbg_cpu)->get_ip ();
|
2003-11-28 18:07:29 +03:00
|
|
|
Bit32u Paddr;
|
|
|
|
bx_bool paddr_valid;
|
2005-02-24 15:58:48 +03:00
|
|
|
bx_address remainingInPage;
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
BX_CPU (dbg_cpu)->dbg_xlate_linear2phy (Laddr, &Paddr, &paddr_valid);
|
|
|
|
|
|
|
|
if(!paddr_valid) {
|
|
|
|
dbg_printf ("bx_dbg_step_over_command:: Invalid physical address\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fetchPtr = BX_CPU (dbg_cpu)->mem->getHostMemAddr (BX_CPU(dbg_cpu), Paddr, BX_READ);
|
|
|
|
unsigned ret = BX_CPU (dbg_cpu)->fetchDecode (fetchPtr, i, 15);
|
2005-02-24 15:58:48 +03:00
|
|
|
remainingInPage = BX_CPU(dbg_cpu)->eipPageWindowSize -
|
|
|
|
(BX_CPU(dbg_cpu)->dword.eip + BX_CPU(dbg_cpu)->eipPageBias);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
if (ret == 0)
|
2005-02-24 15:58:48 +03:00
|
|
|
BX_CPU (dbg_cpu)->boundaryFetch (fetchPtr, remainingInPage, i);
|
2003-11-28 18:07:29 +03:00
|
|
|
|
|
|
|
unsigned b1 = i->b1 ();
|
|
|
|
|
|
|
|
switch(b1) {
|
|
|
|
// Jcc short
|
|
|
|
case 0x70:
|
|
|
|
case 0x71:
|
|
|
|
case 0x72:
|
|
|
|
case 0x73:
|
|
|
|
case 0x74:
|
|
|
|
case 0x75:
|
|
|
|
case 0x76:
|
|
|
|
case 0x77:
|
|
|
|
case 0x78:
|
|
|
|
case 0x79:
|
|
|
|
case 0x7A:
|
|
|
|
case 0x7B:
|
|
|
|
case 0x7C:
|
|
|
|
case 0x7D:
|
|
|
|
case 0x7E:
|
|
|
|
case 0x7F:
|
|
|
|
|
|
|
|
// Jcc near
|
|
|
|
case 0x180:
|
|
|
|
case 0x181:
|
|
|
|
case 0x182:
|
|
|
|
case 0x183:
|
|
|
|
case 0x184:
|
|
|
|
case 0x185:
|
|
|
|
case 0x186:
|
|
|
|
case 0x187:
|
|
|
|
case 0x188:
|
|
|
|
case 0x189:
|
|
|
|
case 0x18A:
|
|
|
|
case 0x18B:
|
|
|
|
case 0x18C:
|
|
|
|
case 0x18D:
|
|
|
|
case 0x18E:
|
|
|
|
case 0x18F:
|
|
|
|
|
|
|
|
// jcxz
|
|
|
|
case 0xE3:
|
|
|
|
|
|
|
|
// retn n
|
|
|
|
case 0xC2:
|
|
|
|
// retn
|
|
|
|
case 0xC3:
|
|
|
|
// retf n
|
|
|
|
case 0xCA:
|
|
|
|
// retf
|
|
|
|
case 0xCB:
|
|
|
|
// iret
|
|
|
|
case 0xCF:
|
|
|
|
|
|
|
|
// jmp near
|
|
|
|
case 0xE9:
|
|
|
|
// jmp far
|
|
|
|
case 0xEA:
|
|
|
|
// jmp short
|
|
|
|
case 0xEB:
|
|
|
|
bx_dbg_stepN_command (1);
|
|
|
|
return;
|
|
|
|
// jmp absolute indirect
|
|
|
|
case 0xFF:
|
|
|
|
switch (i->nnn ()) {
|
|
|
|
// near
|
|
|
|
case 4:
|
|
|
|
// far
|
|
|
|
case 5:
|
|
|
|
bx_dbg_stepN_command (1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// calls, ints, loops and so on
|
|
|
|
int BpId = bx_dbg_lbreakpoint_command (bkStepOver, Laddr + i->ilen ());
|
|
|
|
if (BpId == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
bx_dbg_continue_command ();
|
|
|
|
|
|
|
|
if (bx_dbg_del_lbreak (BpId))
|
|
|
|
bx_dbg_breakpoint_changed ();
|
|
|
|
}
|
|
|
|
|
2005-03-26 22:41:59 +03:00
|
|
|
void bx_dbg_info_flags(void)
|
2003-11-28 18:07:29 +03:00
|
|
|
{
|
|
|
|
if(BX_CPU(dbg_cpu)->getB_ID())
|
|
|
|
dbg_printf ("ID ");
|
2005-02-04 01:08:34 +03:00
|
|
|
if(BX_CPU(dbg_cpu)->getB_VIP())
|
2003-11-28 18:07:29 +03:00
|
|
|
dbg_printf ("VIP ");
|
2005-02-04 01:08:34 +03:00
|
|
|
if(BX_CPU(dbg_cpu)->getB_VIF())
|
2003-11-28 18:07:29 +03:00
|
|
|
dbg_printf ("VIF ");
|
|
|
|
if(BX_CPU(dbg_cpu)->getB_AC())
|
|
|
|
dbg_printf ("AC ");
|
|
|
|
if(BX_CPU(dbg_cpu)->getB_VM())
|
|
|
|
dbg_printf ("VM ");
|
|
|
|
if(BX_CPU(dbg_cpu)->getB_RF())
|
|
|
|
dbg_printf ("RF ");
|
|
|
|
if(BX_CPU(dbg_cpu)->getB_NT())
|
|
|
|
dbg_printf ("NT ");
|
|
|
|
dbg_printf ("IOPL=%d ", BX_CPU(dbg_cpu)->get_IOPL());
|
2004-08-15 00:44:48 +04:00
|
|
|
if(BX_CPU(dbg_cpu)->getB_OF())
|
2003-11-28 18:07:29 +03:00
|
|
|
dbg_printf ("OF ");
|
|
|
|
if(BX_CPU(dbg_cpu)->getB_DF())
|
|
|
|
dbg_printf ("DF ");
|
|
|
|
if(BX_CPU(dbg_cpu)->getB_IF())
|
|
|
|
dbg_printf ("IF ");
|
|
|
|
if(BX_CPU(dbg_cpu)->getB_TF())
|
|
|
|
dbg_printf ("TF ");
|
|
|
|
if(BX_CPU(dbg_cpu)->getB_SF())
|
|
|
|
dbg_printf ("SF ");
|
|
|
|
if(BX_CPU(dbg_cpu)->getB_ZF())
|
|
|
|
dbg_printf ("ZF ");
|
|
|
|
if(BX_CPU(dbg_cpu)->getB_AF())
|
|
|
|
dbg_printf ("AF ");
|
|
|
|
if(BX_CPU(dbg_cpu)->getB_PF())
|
|
|
|
dbg_printf ("PF ");
|
|
|
|
if(BX_CPU(dbg_cpu)->getB_CF())
|
|
|
|
dbg_printf ("CF");
|
|
|
|
dbg_printf ("\n");
|
|
|
|
}
|
|
|
|
|
2005-02-02 00:17:57 +03:00
|
|
|
#endif /* if BX_DEBUGGER */
|