Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dosbox-staging/dosbox-staging.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordiaxen <diaxen@vogons.org>2011-11-29 22:33:00 +0400
committerPatryk Obara <dreamer.tan@gmail.com>2020-05-25 03:24:04 +0300
commit477a8688d7c008e9066032a90a38424ee35eb7df (patch)
tree9fde4b8fd106dc24732ebcfd115965e27b0353e1
parenteb0a3dffc228fa5d7ba4fa803015eb5aa5d4195c (diff)
Connect GDB client to DOSBoxvogons/gdbserver-r3778
This change allows using the GNU debugger as an alternative to the DOSBox built-in debugger. The built-in debugger may be more convenient to show x86 specific information about execution state, whereas Gdb is useful for C and C++ source level debugging. With this change the configure script can be used with a new option: ./autogen.sh ./configure --enable-debug=gdbserver DOSBox then listen on TCP port 1234 and a Gdb client compiled for x86_64 or i686 targets can be connected: $ gdb (gdb) target remote localhost:1234 The gdb architecture must be set depending on the code your are trying to disassemble (16 or 32 bits), for instance: (gdb) set architecture i8086 (gdb) x/32i $eip Breakpoints and watchpoints are supported and some DOSBox specific features are available through the gdb "monitor" command. This patch adds the following files: - src/debug/gdb_server.cpp file - src/debug/debug_log.cpp - src/debug/debug_helpers.cpp The debug.cpp file has been split in 3 files so that the original file now contains built-in debugger stuff only and debug_log.cpp/debug_helpers.cpp files contain common code used by both built-in and Gdb debuggers. Some variables which were previously local to debug.cpp have been prefixed by DEBUG_ and debug.h has been updated accordingly. Rebased to SVN r3778 by ykhwong Imported-from: https://www.vogons.org/viewtopic.php?p=259378#p259378
-rw-r--r--configure.in7
-rw-r--r--include/debug.h80
-rw-r--r--include/logging.h13
-rw-r--r--include/paging.h20
-rw-r--r--src/cpu/core_dyn_x86.cpp20
-rw-r--r--src/cpu/core_dyn_x86/decoder.h2
-rw-r--r--src/cpu/core_dynrec.cpp20
-rw-r--r--src/cpu/core_full.cpp8
-rw-r--r--src/cpu/core_full/op.h6
-rw-r--r--src/cpu/core_normal.cpp14
-rw-r--r--src/cpu/core_normal/prefix_none.h8
-rw-r--r--src/cpu/core_prefetch.cpp12
-rw-r--r--src/cpu/core_simple.cpp14
-rw-r--r--src/cpu/cpu.cpp6
-rw-r--r--src/cpu/paging.cpp4
-rw-r--r--src/debug/Makefile.am3
-rw-r--r--src/debug/debug.cpp989
-rw-r--r--src/debug/debug.cpp.orig2493
-rw-r--r--src/debug/debug_disasm.cpp2
-rw-r--r--src/debug/debug_gui.cpp93
-rw-r--r--src/debug/debug_helpers.cpp347
-rw-r--r--src/debug/debug_log.cpp502
-rw-r--r--src/debug/gdb_server.cpp1090
-rw-r--r--src/debug/poll.cpp595
-rw-r--r--src/debug/poll.h60
-rw-r--r--src/dos/dos_execute.cpp2
-rw-r--r--src/dos/dos_execute.cpp.orig504
-rw-r--r--src/dosbox.cpp6
-rw-r--r--src/gui/sdlmain.cpp6
-rw-r--r--src/gui/sdlmain.cpp.orig2057
-rw-r--r--src/misc/support.cpp2
31 files changed, 7979 insertions, 1006 deletions
diff --git a/configure.in b/configure.in
index 54b5356c4..40c8e48e4 100644
--- a/configure.in
+++ b/configure.in
@@ -188,13 +188,16 @@ AC_C_BIGENDIAN
#Features to enable/disable
AH_TEMPLATE(C_DEBUG,[Define to 1 to enable internal debugger, requires libcurses])
AH_TEMPLATE(C_HEAVY_DEBUG,[Define to 1 to enable heavy debugging, also have to enable C_DEBUG])
-AC_ARG_ENABLE(debug,AC_HELP_STRING([--enable-debug],[Enable debug mode]),[
+AH_TEMPLATE(C_GDBSERVER,[Define to 1 to enable GNU debugger server])
+AC_ARG_ENABLE(debug,AC_HELP_STRING([--enable-debug],[Enable debugger (yes, heavy or gdbserver)]),[
AC_CHECK_HEADER(curses.h,have_curses_h=yes,)
AC_CHECK_LIB(curses, initscr, have_curses_lib=yes, , )
AC_CHECK_LIB(ncurses, initscr, have_ncurses_lib=yes, , )
AC_CHECK_LIB(pdcurses, initscr, have_pdcurses_lib=yes, , )
- if test x$enable_debug = xno; then
+ if test x$enable_debug = xgdbserver; then
+ AC_DEFINE(C_GDBSERVER,1)
+ elif test x$enable_debug = xno; then
AC_MSG_RESULT([Debugger not enabled])
elif test x$have_curses_lib = xyes -a x$have_curses_h = xyes ; then
LIBS="$LIBS -lcurses"
diff --git a/include/debug.h b/include/debug.h
index 031e68315..3917b15ef 100644
--- a/include/debug.h
+++ b/include/debug.h
@@ -16,6 +16,19 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#ifndef DOSBOX_DEBUG_H
+#define DOSBOX_DEBUG_H
+
+#if C_DEBUG || C_GDBSERVER
+
+#include <fstream>
+
+extern Bit16u DEBUG_dataSeg;
+extern Bit32u DEBUG_dataOfs;
+extern bool DEBUG_showExtend;
+extern char DEBUG_curSelectorName[3];
+extern bool DEBUG_exitLoop;
+
void DEBUG_SetupConsole(void);
void DEBUG_DrawScreen(void);
bool DEBUG_Breakpoint(void);
@@ -25,11 +38,72 @@ void DEBUG_CheckExecuteBreakpoint(Bit16u seg, Bit32u off);
bool DEBUG_ExitLoop(void);
void DEBUG_RefreshPage(char scroll);
Bitu DEBUG_EnableDebugger(void);
+Bit32u DEBUG_GetHexValue(char* str, char*& hex);
+Bit32u DEBUG_GetAddress(Bit16u seg, Bit32u offset);
+char* DEBUG_AnalyzeInstruction(char* inst, bool saveSelector);
+bool DEBUG_GetDescriptorInfo(char* selname, char* out1, char* out2);
+
+void DEBUG_LogMCBChain(Bit16u mcb_segment);
+void DEBUG_LogMCBS(void);
+void DEBUG_LogGDT(void);
+void DEBUG_LogLDT(void);
+void DEBUG_LogIDT(void);
+void DEBUG_LogPages(char* selname);
+void DEBUG_LogCPUInfo(void);
+void DEBUG_LogInstruction(Bit16u segValue, Bit32u eipValue, std::ofstream& out);
-extern Bitu cycle_count;
-extern Bitu debugCallback;
+extern bool DEBUG_showExtend;
+
+extern Bitu DEBUG_cycle_count;
+extern Bitu DEBUG_debugCallback;
+
+#if C_HEAVY_DEBUG || C_GDBSERVER
+extern std::ofstream DEBUG_cpuLogFile;
+extern bool DEBUG_cpuLog;
+extern int DEBUG_cpuLogCounter;
+extern int DEBUG_cpuLogType; // log detail
+extern bool DEBUG_zeroProtect;
+extern bool DEBUG_logHeavy;
-#ifdef C_HEAVY_DEBUG
bool DEBUG_HeavyIsBreakpoint(void);
+void DEBUG_HeavyLogInstruction(void);
void DEBUG_HeavyWriteLogInstruction(void);
#endif
+
+#ifdef C_GDBSERVER
+void DEBUG_GdbMemReadHook(Bit32u address, int width);
+void DEBUG_GdbMemWriteHook(Bit32u address, int width, Bit32u value);
+void DEBUG_IrqBreakpoint(Bit8u intNum);
+#endif
+
+/********************/
+/* DebugVar stuff */
+/********************/
+
+#include <list>
+#include "paging.h"
+
+class CDebugVar
+{
+public:
+ CDebugVar(char* _name, PhysPt _adr);
+
+ char* GetName(void) { return name; };
+ PhysPt GetAdr (void) { return adr; };
+
+private:
+ PhysPt adr;
+ char name[16];
+
+public:
+ static void InsertVariable (char* name, PhysPt adr);
+ static CDebugVar* FindVar (PhysPt adr);
+ static void DeleteAll ();
+ static bool SaveVars (char* name);
+ static bool LoadVars (char* name);
+
+ static std::list<CDebugVar*> varList;
+};
+
+#endif
+#endif
diff --git a/include/logging.h b/include/logging.h
index 7faf84cde..4ef0cbafc 100644
--- a/include/logging.h
+++ b/include/logging.h
@@ -37,7 +37,12 @@ enum LOG_SEVERITIES {
LOG_ERROR
};
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
+struct _LogGroup {
+ char const* front;
+ bool enabled;
+};
+
class LOG
{
LOG_TYPES d_type;
@@ -48,14 +53,14 @@ public:
d_type(type),
d_severity(severity)
{}
- void operator() (char const* buf, ...) GCC_ATTRIBUTE(__format__(__printf__, 2, 3)); //../src/debug/debug_gui.cpp
+ void operator() (char const* buf, ...) GCC_ATTRIBUTE(__format__(__printf__, 2, 3)); //../src/debug/debug_log.cpp
};
void DEBUG_ShowMsg(char const* format,...) GCC_ATTRIBUTE(__format__(__printf__, 1, 2));
#define LOG_MSG DEBUG_ShowMsg
-#else //C_DEBUG
+#else //C_DEBUG || C_GDBSERVER
struct LOG
{
@@ -84,7 +89,7 @@ struct LOG
void GFX_ShowMsg(char const* format,...) GCC_ATTRIBUTE(__format__(__printf__, 1, 2));
#define LOG_MSG GFX_ShowMsg
-#endif //C_DEBUG
+#endif //C_DEBUG || C_GDBSERVER
#endif //DOSBOX_LOGGING_H
diff --git a/include/paging.h b/include/paging.h
index 13fee9b9f..b13ed1571 100644
--- a/include/paging.h
+++ b/include/paging.h
@@ -27,6 +27,8 @@
#include "mem.h"
#endif
+#include "debug.h"
+
// disable this to reduce the size of the TLB
// NOTE: does not work with the dynamic core (dynrec is fine)
#define USE_FULL_TLB
@@ -261,12 +263,18 @@ static INLINE PhysPt PAGING_GetPhysicalAddress(PhysPt linAddr) {
/* Special inlined memory reading/writing */
static INLINE Bit8u mem_readb_inline(PhysPt address) {
+#ifdef C_GDBSERVER
+ DEBUG_GdbMemReadHook(address, 1);
+#endif
HostPt tlb_addr=get_tlb_read(address);
if (tlb_addr) return host_readb(tlb_addr+address);
else return (Bit8u)(get_tlb_readhandler(address))->readb(address);
}
static INLINE Bit16u mem_readw_inline(PhysPt address) {
+#ifdef C_GDBSERVER
+ DEBUG_GdbMemReadHook(address, 1);
+#endif
if ((address & 0xfff)<0xfff) {
HostPt tlb_addr=get_tlb_read(address);
if (tlb_addr) return host_readw(tlb_addr+address);
@@ -275,6 +283,9 @@ static INLINE Bit16u mem_readw_inline(PhysPt address) {
}
static INLINE Bit32u mem_readd_inline(PhysPt address) {
+#ifdef C_GDBSERVER
+ DEBUG_GdbMemReadHook(address, 1);
+#endif
if ((address & 0xfff)<0xffd) {
HostPt tlb_addr=get_tlb_read(address);
if (tlb_addr) return host_readd(tlb_addr+address);
@@ -283,12 +294,18 @@ static INLINE Bit32u mem_readd_inline(PhysPt address) {
}
static INLINE void mem_writeb_inline(PhysPt address,Bit8u val) {
+#ifdef C_GDBSERVER
+ DEBUG_GdbMemWriteHook(address, 1, val);
+#endif
HostPt tlb_addr=get_tlb_write(address);
if (tlb_addr) host_writeb(tlb_addr+address,val);
else (get_tlb_writehandler(address))->writeb(address,val);
}
static INLINE void mem_writew_inline(PhysPt address,Bit16u val) {
+#ifdef C_GDBSERVER
+ DEBUG_GdbMemWriteHook(address, 2, val);
+#endif
if ((address & 0xfff)<0xfff) {
HostPt tlb_addr=get_tlb_write(address);
if (tlb_addr) host_writew(tlb_addr+address,val);
@@ -297,6 +314,9 @@ static INLINE void mem_writew_inline(PhysPt address,Bit16u val) {
}
static INLINE void mem_writed_inline(PhysPt address,Bit32u val) {
+#ifdef C_GDBSERVER
+ DEBUG_GdbMemWriteHook(address, 4, val);
+#endif
if ((address & 0xfff)<0xffd) {
HostPt tlb_addr=get_tlb_write(address);
if (tlb_addr) host_writed(tlb_addr+address,val);
diff --git a/src/cpu/core_dyn_x86.cpp b/src/cpu/core_dyn_x86.cpp
index f63d91586..daab840a8 100644
--- a/src/cpu/core_dyn_x86.cpp
+++ b/src/cpu/core_dyn_x86.cpp
@@ -113,7 +113,7 @@ enum BlockReturn {
BR_Cycles,
BR_Link1,BR_Link2,
BR_Opcode,
-#if (C_DEBUG)
+#if C_DEBUG || C_GDBSERVER
BR_OpcodeFull,
#endif
BR_Iret,
@@ -261,8 +261,8 @@ Bits CPU_Core_Dyn_X86_Run(void) {
/* Determine the linear address of CS:EIP */
restart_core:
PhysPt ip_point=SegPhys(cs)+reg_eip;
- #if C_HEAVY_DEBUG
- if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
+ #if C_HEAVY_DEBUG || C_GDBSERVER
+ if (DEBUG_HeavyIsBreakpoint()) return DEBUG_debugCallback;
#endif
CodePageHandler * chandler=0;
if (GCC_UNLIKELY(MakeCodePage(ip_point,chandler))) {
@@ -296,10 +296,10 @@ run_block:
BlockReturn ret=gen_runcode(block->cache.start);
switch (ret) {
case BR_Iret:
-#if C_HEAVY_DEBUG
+#if C_HEAVY_DEBUG || C_GDBSERVER
if (DEBUG_HeavyIsBreakpoint()) {
if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
- return debugCallback;
+ return DEBUG_debugCallback;
}
#endif
if (!GETFLAG(TF)) {
@@ -315,13 +315,13 @@ run_block:
return CBRET_NONE;
case BR_Normal:
/* Maybe check if we staying in the same page? */
-#if C_HEAVY_DEBUG
- if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
+#if C_HEAVY_DEBUG || C_GDBSERVER
+ if (DEBUG_HeavyIsBreakpoint()) return DEBUG_debugCallback;
#endif
goto restart_core;
case BR_Cycles:
-#if C_HEAVY_DEBUG
- if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
+#if C_HEAVY_DEBUG || C_GDBSERVER
+ if (DEBUG_HeavyIsBreakpoint()) return DEBUG_debugCallback;
#endif
if (!dyn_dh_fpu.state_used) return CBRET_NONE;
DH_FPU_SAVE_REINIT
@@ -339,7 +339,7 @@ run_block:
CPU_Cycles=1;
if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
return CPU_Core_Normal_Run();
-#if (C_DEBUG)
+#if C_DEBUG || C_GDBSERVER
case BR_OpcodeFull:
CPU_CycleLeft+=CPU_Cycles;
CPU_Cycles=1;
diff --git a/src/cpu/core_dyn_x86/decoder.h b/src/cpu/core_dyn_x86/decoder.h
index a9f90d070..d02e54287 100644
--- a/src/cpu/core_dyn_x86/decoder.h
+++ b/src/cpu/core_dyn_x86/decoder.h
@@ -2697,7 +2697,7 @@ illegalopcode:
gen_return(BR_Opcode);
dyn_closeblock();
goto finish_block;
-#if (C_DEBUG)
+#if C_DEBUG || C_GDBSERVER
dyn_set_eip_last();
dyn_reduce_cycles();
dyn_save_critical_regs();
diff --git a/src/cpu/core_dynrec.cpp b/src/cpu/core_dynrec.cpp
index ed975f56b..bfbef7b8d 100644
--- a/src/cpu/core_dynrec.cpp
+++ b/src/cpu/core_dynrec.cpp
@@ -107,7 +107,7 @@ enum BlockReturn {
BR_Cycles,
BR_Link1,BR_Link2,
BR_Opcode,
-#if (C_DEBUG)
+#if C_DEBUG || C_GDBSERVER
BR_OpcodeFull,
#endif
BR_Iret,
@@ -186,8 +186,8 @@ Bits CPU_Core_Dynrec_Run(void) {
for (;;) {
// Determine the linear address of CS:EIP
PhysPt ip_point=SegPhys(cs)+reg_eip;
- #if C_HEAVY_DEBUG
- if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
+ #if C_HEAVY_DEBUG || C_GDBSERVER
+ if (DEBUG_HeavyIsBreakpoint()) return DEBUG_debugCallback;
#endif
CodePageHandlerDynRec * chandler=0;
@@ -231,8 +231,8 @@ run_block:
switch (ret) {
case BR_Iret:
-#if C_HEAVY_DEBUG
- if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
+#if C_HEAVY_DEBUG || C_GDBSERVER
+ if (DEBUG_HeavyIsBreakpoint()) return DEBUG_debugCallback;
#endif
if (!GETFLAG(TF)) {
if (GETFLAG(IF) && PIC_IRQCheck) return CBRET_NONE;
@@ -247,16 +247,16 @@ run_block:
// modifying instruction (like ret) or some nontrivial cpu state
// changing instruction (for example switch to/from pmode),
// or the maximum number of instructions to translate was reached
-#if C_HEAVY_DEBUG
- if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
+#if C_HEAVY_DEBUG || C_GDBSERVER
+ if (DEBUG_HeavyIsBreakpoint()) return DEBUG_debugCallback;
#endif
break;
case BR_Cycles:
// cycles went negative, return from the core to handle
// external events, schedule the pic...
-#if C_HEAVY_DEBUG
- if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
+#if C_HEAVY_DEBUG || C_GDBSERVER
+ if (DEBUG_HeavyIsBreakpoint()) return DEBUG_debugCallback;
#endif
return CBRET_NONE;
@@ -277,7 +277,7 @@ run_block:
CPU_Cycles=1;
return CPU_Core_Normal_Run();
-#if (C_DEBUG)
+#if C_DEBUG || C_GDBSERVER
case BR_OpcodeFull:
CPU_CycleLeft+=CPU_Cycles;
CPU_Cycles=1;
diff --git a/src/cpu/core_full.cpp b/src/cpu/core_full.cpp
index f70f8078b..6398b2b81 100644
--- a/src/cpu/core_full.cpp
+++ b/src/cpu/core_full.cpp
@@ -64,12 +64,12 @@ typedef PhysPt EAPoint;
Bits CPU_Core_Full_Run(void) {
FullData inst;
while (CPU_Cycles-->0) {
-#if C_DEBUG
- cycle_count++;
-#if C_HEAVY_DEBUG
+#if C_DEBUG || C_GDBSERVER
+ DEBUG_cycle_count++;
+#if C_HEAVY_DEBUG || C_GDBSERVER
if (DEBUG_HeavyIsBreakpoint()) {
FillFlags();
- return debugCallback;
+ return DEBUG_debugCallback;
};
#endif
#endif
diff --git a/src/cpu/core_full/op.h b/src/cpu/core_full/op.h
index ea5f517dc..37297f69c 100644
--- a/src/cpu/core_full/op.h
+++ b/src/cpu/core_full/op.h
@@ -356,12 +356,12 @@ switch (inst.code.op) {
CPU_JMP(true,inst_op2_d,inst_op1_d,GetIP());
continue;
case O_INT:
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
FillFlags();
if (((inst.entry & 0xFF)==0xcc) && DEBUG_Breakpoint())
- return debugCallback;
+ return DEBUG_debugCallback;
else if (DEBUG_IntBreakpoint(inst_op1_b))
- return debugCallback;
+ return DEBUG_debugCallback;
#endif
CPU_SW_Interrupt(inst_op1_b,GetIP());
continue;
diff --git a/src/cpu/core_normal.cpp b/src/cpu/core_normal.cpp
index 530e0c62d..04d9b257b 100644
--- a/src/cpu/core_normal.cpp
+++ b/src/cpu/core_normal.cpp
@@ -28,7 +28,7 @@
#include "fpu.h"
#include "paging.h"
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
#include "debug.h"
#endif
@@ -49,7 +49,7 @@
#define SaveMd(off,val) mem_writed_inline(off,val)
#endif
-extern Bitu cycle_count;
+extern Bitu DEBUG_cycle_count;
#if C_FPU
#define CPU_FPU 1 //Enable FPU escape instructions
@@ -145,14 +145,14 @@ Bits CPU_Core_Normal_Run(void) {
BaseDS=SegBase(ds);
BaseSS=SegBase(ss);
core.base_val_ds=ds;
-#if C_DEBUG
-#if C_HEAVY_DEBUG
+#if C_DEBUG || C_GDBSERVER
+#if C_HEAVY_DEBUG || C_GDBSERVER
if (DEBUG_HeavyIsBreakpoint()) {
FillFlags();
- return debugCallback;
+ return DEBUG_debugCallback;
};
#endif
- cycle_count++;
+ DEBUG_cycle_count++;
#endif
restart_opcode:
switch (core.opcode_index+Fetchb()) {
@@ -162,7 +162,7 @@ restart_opcode:
#include "core_normal/prefix_66_0f.h"
default:
illegal_opcode:
-#if C_DEBUG
+#if C_DEBUG
{
Bitu len=(GETIP-reg_eip);
LOADIP;
diff --git a/src/cpu/core_normal/prefix_none.h b/src/cpu/core_normal/prefix_none.h
index c732d1a62..22caed46f 100644
--- a/src/cpu/core_normal/prefix_none.h
+++ b/src/cpu/core_normal/prefix_none.h
@@ -741,10 +741,10 @@
CPU_RET(false,0,GETIP);
continue;
CASE_B(0xcc) /* INT3 */
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
FillFlags();
if (DEBUG_Breakpoint())
- return debugCallback;
+ return DEBUG_debugCallback;
#endif
CPU_SW_Interrupt_NoIOPLCheck(3,GETIP);
#if CPU_TRAP_CHECK
@@ -754,10 +754,10 @@
CASE_B(0xcd) /* INT Ib */
{
Bit8u num=Fetchb();
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
FillFlags();
if (DEBUG_IntBreakpoint(num)) {
- return debugCallback;
+ return DEBUG_debugCallback;
}
#endif
CPU_SW_Interrupt(num,GETIP);
diff --git a/src/cpu/core_prefetch.cpp b/src/cpu/core_prefetch.cpp
index e378968a6..34abdf617 100644
--- a/src/cpu/core_prefetch.cpp
+++ b/src/cpu/core_prefetch.cpp
@@ -29,7 +29,7 @@
#include "fpu.h"
#include "paging.h"
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
#include "debug.h"
#endif
@@ -50,7 +50,7 @@
#define SaveMd(off,val) mem_writed_inline(off,val)
#endif
-extern Bitu cycle_count;
+extern Bitu DEBUG_cycle_count;
#if C_FPU
#define CPU_FPU 1 //Enable FPU escape instructions
@@ -220,14 +220,14 @@ Bits CPU_Core_Prefetch_Run(void) {
BaseDS=SegBase(ds);
BaseSS=SegBase(ss);
core.base_val_ds=ds;
-#if C_DEBUG
-#if C_HEAVY_DEBUG
+#if C_DEBUG || C_GDBSERVER
+#if C_HEAVY_DEBUG || C_GDBSERVER
if (DEBUG_HeavyIsBreakpoint()) {
FillFlags();
- return debugCallback;
+ return DEBUG_debugCallback;
};
#endif
- cycle_count++;
+ DEBUG_cycle_count++;
#endif
restart_opcode:
Bit8u next_opcode=Fetchb();
diff --git a/src/cpu/core_simple.cpp b/src/cpu/core_simple.cpp
index e75122707..9cc167d5f 100644
--- a/src/cpu/core_simple.cpp
+++ b/src/cpu/core_simple.cpp
@@ -27,7 +27,7 @@
#include "pic.h"
#include "fpu.h"
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
#include "debug.h"
#endif
@@ -41,7 +41,7 @@
#define SaveMw(off,val) mem_writew(off,val)
#define SaveMd(off,val) mem_writed(off,val)
-extern Bitu cycle_count;
+extern Bitu DEBUG_cycle_count;
#if C_FPU
#define CPU_FPU 1 //Enable FPU escape instructions
@@ -141,14 +141,14 @@ Bits CPU_Core_Simple_Run(void) {
BaseDS=SegBase(ds);
BaseSS=SegBase(ss);
core.base_val_ds=ds;
-#if C_DEBUG
-#if C_HEAVY_DEBUG
+#if C_DEBUG || C_GDBSERVER
+#if C_HEAVY_DEBUG || C_GDBSERVER
if (DEBUG_HeavyIsBreakpoint()) {
FillFlags();
- return debugCallback;
+ return DEBUG_debugCallback;
};
#endif
- cycle_count++;
+ DEBUG_cycle_count++;
#endif
restart_opcode:
switch (core.opcode_index+Fetchb()) {
@@ -159,7 +159,7 @@ restart_opcode:
#include "core_normal/prefix_66_0f.h"
default:
illegal_opcode:
-#if C_DEBUG
+#if C_DEBUG
{
Bitu len=(GETIP-reg_eip);
LOADIP;
diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp
index 9c9d5668c..ecd2a94f3 100644
--- a/src/cpu/cpu.cpp
+++ b/src/cpu/cpu.cpp
@@ -90,7 +90,7 @@ void CPU_Core_Dynrec_Cache_Close(void);
* In non-debug mode dosbox doesn't do detection (and hence doesn't crash at
* that point). (game might crash later due to the unhandled exception) */
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
// #define CPU_CHECK_EXCEPT 1
// #define CPU_CHECK_IGNORE 1
/* Use CHECK_EXCEPT when something doesn't work to see if a exception is
@@ -546,6 +546,10 @@ Bit8u lastint;
void CPU_Interrupt(Bitu num,Bitu type,Bitu oldeip) {
lastint=num;
FillFlags();
+#if C_GDBSERVER
+ if (type == 0)
+ DEBUG_IrqBreakpoint(num);
+#endif
#if C_DEBUG
switch (num) {
case 0xcd:
diff --git a/src/cpu/paging.cpp b/src/cpu/paging.cpp
index 6ac9b6641..60a7a7196 100644
--- a/src/cpu/paging.cpp
+++ b/src/cpu/paging.cpp
@@ -130,7 +130,7 @@ static Bits PageFaultCore(void) {
}
return 0;
}
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
Bitu DEBUG_EnableDebugger(void);
#endif
@@ -155,7 +155,7 @@ void PAGING_PageFault(PhysPt lin_addr,Bitu page_addr,Bitu faultcode) {
cpu.mpl=3;
CPU_Exception(EXCEPTION_PF,faultcode);
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
// DEBUG_EnableDebugger();
#endif
DOSBOX_RunMachine();
diff --git a/src/debug/Makefile.am b/src/debug/Makefile.am
index dfee79248..9090707b3 100644
--- a/src/debug/Makefile.am
+++ b/src/debug/Makefile.am
@@ -1,4 +1,5 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
noinst_LIBRARIES = libdebug.a
-libdebug_a_SOURCES = debug.cpp debug_gui.cpp debug_disasm.cpp debug_inc.h disasm_tables.h debug_win32.cpp \ No newline at end of file
+libdebug_a_SOURCES = debug.cpp debug_gui.cpp debug_disasm.cpp debug_inc.h \
+ disasm_tables.h debug_win32.cpp debug_log.cpp debug_helpers.cpp gdb_server.cpp poll.cpp poll.h
diff --git a/src/debug/debug.cpp b/src/debug/debug.cpp
index 7b76d573f..fd2da533d 100644
--- a/src/debug/debug.cpp
+++ b/src/debug/debug.cpp
@@ -63,18 +63,9 @@ static void DrawCode(void);
static void DEBUG_RaiseTimerIrq(void);
static void SaveMemory(Bitu seg, Bitu ofs1, Bit32u num);
static void SaveMemoryBin(Bitu seg, Bitu ofs1, Bit32u num);
-static void LogMCBS(void);
-static void LogGDT(void);
-static void LogLDT(void);
-static void LogIDT(void);
-static void LogPages(char* selname);
-static void LogCPUInfo(void);
static void OutputVecTable(char* filename);
static void DrawVariables(void);
-char* AnalyzeInstruction(char* inst, bool saveSelector);
-Bit32u GetHexValue(char* str, char*& hex);
-
#if 0
class DebugPageHandler : public PageHandler {
public:
@@ -97,31 +88,16 @@ public:
class DEBUG;
DEBUG* pDebugcom = 0;
-bool exitLoop = false;
-
-
-// Heavy Debugging Vars for logging
-#if C_HEAVY_DEBUG
-static ofstream cpuLogFile;
-static bool cpuLog = false;
-static int cpuLogCounter = 0;
-static int cpuLogType = 1; // log detail
-static bool zeroProtect = false;
-bool logHeavy = false;
-#endif
-
-
static struct {
Bit32u eax,ebx,ecx,edx,esi,edi,ebp,esp,eip;
} oldregs;
-static char curSelectorName[3] = { 0,0,0 };
static Segment oldsegs[6];
static Bitu oldflags,oldcpucpl;
DBGBlock dbg;
-Bitu cycle_count;
+Bitu DEBUG_cycle_count;
static bool debugging;
@@ -148,10 +124,6 @@ struct SCodeViewData {
int inputPos;
} codeViewData;
-static Bit16u dataSeg;
-static Bit32u dataOfs;
-static bool showExtend = true;
-
static void ClearInputLine(void) {
codeViewData.inputStr[0] = 0;
codeViewData.inputPos = 0;
@@ -162,110 +134,8 @@ static void ClearInputLine(void) {
static list<string> histBuff;
static list<string>::iterator histBuffPos = histBuff.end();
-/***********/
-/* Helpers */
-/***********/
-
-Bit32u PhysMakeProt(Bit16u selector, Bit32u offset)
-{
- Descriptor desc;
- if (cpu.gdt.GetDescriptor(selector,desc)) return desc.GetBase()+offset;
- return 0;
-};
-
-Bit32u GetAddress(Bit16u seg, Bit32u offset)
-{
- if (seg==SegValue(cs)) return SegPhys(cs)+offset;
- if (cpu.pmode && !(reg_flags & FLAG_VM)) {
- Descriptor desc;
- if (cpu.gdt.GetDescriptor(seg,desc)) return PhysMakeProt(seg,offset);
- }
- return (seg<<4)+offset;
-}
-
-static char empty_sel[] = { ' ',' ',0 };
-
-bool GetDescriptorInfo(char* selname, char* out1, char* out2)
-{
- Bitu sel;
- Descriptor desc;
-
- if (strstr(selname,"cs") || strstr(selname,"CS")) sel = SegValue(cs);
- else if (strstr(selname,"ds") || strstr(selname,"DS")) sel = SegValue(ds);
- else if (strstr(selname,"es") || strstr(selname,"ES")) sel = SegValue(es);
- else if (strstr(selname,"fs") || strstr(selname,"FS")) sel = SegValue(fs);
- else if (strstr(selname,"gs") || strstr(selname,"GS")) sel = SegValue(gs);
- else if (strstr(selname,"ss") || strstr(selname,"SS")) sel = SegValue(ss);
- else {
- sel = GetHexValue(selname,selname);
- if (*selname==0) selname=empty_sel;
- }
- if (cpu.gdt.GetDescriptor(sel,desc)) {
- switch (desc.Type()) {
- case DESC_TASK_GATE:
- sprintf(out1,"%s: s:%08X type:%02X p",selname,desc.GetSelector(),desc.saved.gate.type);
- sprintf(out2," TaskGate dpl : %01X %1X",desc.saved.gate.dpl,desc.saved.gate.p);
- return true;
- case DESC_LDT:
- case DESC_286_TSS_A:
- case DESC_286_TSS_B:
- case DESC_386_TSS_A:
- case DESC_386_TSS_B:
- sprintf(out1,"%s: b:%08X type:%02X pag",selname,desc.GetBase(),desc.saved.seg.type);
- sprintf(out2," l:%08X dpl : %01X %1X%1X%1X",desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.g);
- return true;
- case DESC_286_CALL_GATE:
- case DESC_386_CALL_GATE:
- sprintf(out1,"%s: s:%08X type:%02X p params: %02X",selname,desc.GetSelector(),desc.saved.gate.type,desc.saved.gate.paramcount);
- sprintf(out2," o:%08X dpl : %01X %1X",desc.GetOffset(),desc.saved.gate.dpl,desc.saved.gate.p);
- return true;
- case DESC_286_INT_GATE:
- case DESC_286_TRAP_GATE:
- case DESC_386_INT_GATE:
- case DESC_386_TRAP_GATE:
- sprintf(out1,"%s: s:%08X type:%02X p",selname,desc.GetSelector(),desc.saved.gate.type);
- sprintf(out2," o:%08X dpl : %01X %1X",desc.GetOffset(),desc.saved.gate.dpl,desc.saved.gate.p);
- return true;
- }
- sprintf(out1,"%s: b:%08X type:%02X parbg",selname,desc.GetBase(),desc.saved.seg.type);
- sprintf(out2," l:%08X dpl : %01X %1X%1X%1X%1X%1X",desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.r,desc.saved.seg.big,desc.saved.seg.g);
- return true;
- } else {
- strcpy(out1," ");
- strcpy(out2," ");
- }
- return false;
-};
-
-/********************/
-/* DebugVar stuff */
-/********************/
-
-class CDebugVar
-{
-public:
- CDebugVar(char* _name, PhysPt _adr) { adr=_adr; safe_strncpy(name,_name,16); };
-
- char* GetName(void) { return name; };
- PhysPt GetAdr (void) { return adr; };
-
-private:
- PhysPt adr;
- char name[16];
-
-public:
- static void InsertVariable (char* name, PhysPt adr);
- static CDebugVar* FindVar (PhysPt adr);
- static void DeleteAll ();
- static bool SaveVars (char* name);
- static bool LoadVars (char* name);
-
- static std::list<CDebugVar*> varList;
-};
-
std::list<CDebugVar*> CDebugVar::varList;
-
/********************/
/* Breakpoint stuff */
/********************/
@@ -281,7 +151,7 @@ class CBreakpoint
public:
CBreakpoint(void);
- void SetAddress (Bit16u seg, Bit32u off) { location = GetAddress(seg,off); type = BKPNT_PHYSICAL; segment = seg; offset = off; };
+ void SetAddress (Bit16u seg, Bit32u off) { location = DEBUG_GetAddress(seg,off); type = BKPNT_PHYSICAL; segment = seg; offset = off; };
void SetAddress (PhysPt adr) { location = adr; type = BKPNT_PHYSICAL; };
void SetInt (Bit8u _intNr, Bit16u ah) { intNr = _intNr, ahValue = ah; type = BKPNT_INTERRUPT; };
void SetOnce (bool _once) { once = _once; };
@@ -414,7 +284,7 @@ void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool activate)
bool CBreakpoint::CheckBreakpoint(Bitu seg, Bitu off)
// Checks if breakpoint is valid and should stop execution
{
- if ((ignoreAddressOnce!=0) && (GetAddress(seg,off)==ignoreAddressOnce)) {
+ if ((ignoreAddressOnce!=0) && (DEBUG_GetAddress(seg,off)==ignoreAddressOnce)) {
ignoreAddressOnce = 0;
return false;
} else
@@ -459,7 +329,7 @@ bool CBreakpoint::CheckBreakpoint(Bitu seg, Bitu off)
Bitu address;
if (bp->GetType()==BKPNT_MEMORY_LINEAR) address = bp->GetOffset();
- else address = GetAddress(bp->GetSegment(),bp->GetOffset());
+ else address = DEBUG_GetAddress(bp->GetSegment(),bp->GetOffset());
Bit8u value=0;
if (mem_readb_checked(address,&value)) return false;
if (bp->GetValue() != value) {
@@ -624,7 +494,7 @@ bool DEBUG_Breakpoint(void)
/* First get the phyiscal address and check for a set Breakpoint */
if (!CBreakpoint::CheckBreakpoint(SegValue(cs),reg_eip)) return false;
// Found. Breakpoint is valid
- PhysPt where=GetAddress(SegValue(cs),reg_eip);
+ PhysPt where=DEBUG_GetAddress(SegValue(cs),reg_eip);
CBreakpoint::ActivateBreakpoints(where,false); // Deactivate all breakpoints
return true;
};
@@ -632,7 +502,7 @@ bool DEBUG_Breakpoint(void)
bool DEBUG_IntBreakpoint(Bit8u intNum)
{
/* First get the phyiscal address and check for a set Breakpoint */
- PhysPt where=GetAddress(SegValue(cs),reg_eip);
+ PhysPt where=DEBUG_GetAddress(SegValue(cs),reg_eip);
if (!CBreakpoint::CheckIntBreakpoint(where,intNum,reg_ah)) return false;
// Found. Breakpoint is valid
CBreakpoint::ActivateBreakpoints(where,false); // Deactivate all breakpoints
@@ -641,8 +511,8 @@ bool DEBUG_IntBreakpoint(Bit8u intNum)
static bool StepOver()
{
- exitLoop = false;
- PhysPt start=GetAddress(SegValue(cs),reg_eip);
+ DEBUG_exitLoop = false;
+ PhysPt start=DEBUG_GetAddress(SegValue(cs),reg_eip);
char dline[200];Bitu size;
size=DasmI386(dline, start, reg_eip, cpu.code.big);
@@ -663,8 +533,8 @@ bool DEBUG_ExitLoop(void)
DrawVariables();
#endif
- if (exitLoop) {
- exitLoop = false;
+ if (DEBUG_exitLoop) {
+ DEBUG_exitLoop = false;
return true;
}
return false;
@@ -677,15 +547,15 @@ bool DEBUG_ExitLoop(void)
static void DrawData(void) {
Bit8u ch;
- Bit32u add = dataOfs;
+ Bit32u add = DEBUG_dataOfs;
Bit32u address;
/* Data win */
for (int y=0; y<8; y++) {
// Address
- if (add<0x10000) mvwprintw (dbg.win_data,1+y,0,"%04X:%04X ",dataSeg,add);
- else mvwprintw (dbg.win_data,1+y,0,"%04X:%08X ",dataSeg,add);
+ if (add<0x10000) mvwprintw (dbg.win_data,1+y,0,"%04X:%04X ",DEBUG_dataSeg,add);
+ else mvwprintw (dbg.win_data,1+y,0,"%04X:%08X ",DEBUG_dataSeg,add);
for (int x=0; x<16; x++) {
- address = GetAddress(dataSeg,add);
+ address = DEBUG_GetAddress(DEBUG_dataSeg,add);
if (mem_readb_checked(address,&ch)) ch=0;
mvwprintw (dbg.win_data,1+y,14+3*x,"%02X",ch);
if (ch<32 || !isprint(*reinterpret_cast<unsigned char*>(&ch))) ch='.';
@@ -757,22 +627,22 @@ static void DrawRegisters(void) {
mvwprintw(dbg.win_reg,0,76,"Real");
// Selector info, if available
- if ((cpu.pmode) && curSelectorName[0]) {
+ if ((cpu.pmode) && DEBUG_curSelectorName[0]) {
char out1[200], out2[200];
- GetDescriptorInfo(curSelectorName,out1,out2);
+ DEBUG_GetDescriptorInfo(DEBUG_curSelectorName,out1,out2);
mvwprintw(dbg.win_reg,2,28,out1);
mvwprintw(dbg.win_reg,3,28,out2);
}
wattrset(dbg.win_reg,0);
- mvwprintw(dbg.win_reg,3,60,"%u ",cycle_count);
+ mvwprintw(dbg.win_reg,3,60,"%u ",DEBUG_cycle_count);
wrefresh(dbg.win_reg);
};
static void DrawCode(void) {
bool saveSel;
Bit32u disEIP = codeViewData.useEIP;
- PhysPt start = GetAddress(codeViewData.useCS,codeViewData.useEIP);
+ PhysPt start = DEBUG_GetAddress(codeViewData.useCS,codeViewData.useEIP);
char dline[200];Bitu size;Bitu c;
static char line20[21] = " ";
@@ -822,7 +692,7 @@ static void DrawCode(void) {
char empty_res[] = { 0 };
char* res = empty_res;
- if (showExtend) res = AnalyzeInstruction(dline, saveSel);
+ if (DEBUG_showExtend) res = DEBUG_AnalyzeInstruction(dline, saveSel);
// Spacepad it up to 28 characters
size_t dline_len = strlen(dline);
if(dline_len < 28) for (c = dline_len; c < 28;c++) dline[c] = ' '; dline[28] = 0;
@@ -882,86 +752,42 @@ static void SetCodeWinStart()
/* User input */
/********************/
-Bit32u GetHexValue(char* str, char*& hex)
-{
- Bit32u value = 0;
- Bit32u regval = 0;
- hex = str;
- while (*hex==' ') hex++;
- if (strstr(hex,"EAX")==hex) { hex+=3; regval = reg_eax; };
- if (strstr(hex,"EBX")==hex) { hex+=3; regval = reg_ebx; };
- if (strstr(hex,"ECX")==hex) { hex+=3; regval = reg_ecx; };
- if (strstr(hex,"EDX")==hex) { hex+=3; regval = reg_edx; };
- if (strstr(hex,"ESI")==hex) { hex+=3; regval = reg_esi; };
- if (strstr(hex,"EDI")==hex) { hex+=3; regval = reg_edi; };
- if (strstr(hex,"EBP")==hex) { hex+=3; regval = reg_ebp; };
- if (strstr(hex,"ESP")==hex) { hex+=3; regval = reg_esp; };
- if (strstr(hex,"EIP")==hex) { hex+=3; regval = reg_eip; };
- if (strstr(hex,"AX")==hex) { hex+=2; regval = reg_ax; };
- if (strstr(hex,"BX")==hex) { hex+=2; regval = reg_bx; };
- if (strstr(hex,"CX")==hex) { hex+=2; regval = reg_cx; };
- if (strstr(hex,"DX")==hex) { hex+=2; regval = reg_dx; };
- if (strstr(hex,"SI")==hex) { hex+=2; regval = reg_si; };
- if (strstr(hex,"DI")==hex) { hex+=2; regval = reg_di; };
- if (strstr(hex,"BP")==hex) { hex+=2; regval = reg_bp; };
- if (strstr(hex,"SP")==hex) { hex+=2; regval = reg_sp; };
- if (strstr(hex,"IP")==hex) { hex+=2; regval = reg_ip; };
- if (strstr(hex,"CS")==hex) { hex+=2; regval = SegValue(cs); };
- if (strstr(hex,"DS")==hex) { hex+=2; regval = SegValue(ds); };
- if (strstr(hex,"ES")==hex) { hex+=2; regval = SegValue(es); };
- if (strstr(hex,"FS")==hex) { hex+=2; regval = SegValue(fs); };
- if (strstr(hex,"GS")==hex) { hex+=2; regval = SegValue(gs); };
- if (strstr(hex,"SS")==hex) { hex+=2; regval = SegValue(ss); };
-
- while (*hex) {
- if ((*hex>='0') && (*hex<='9')) value = (value<<4)+*hex-'0';
- else if ((*hex>='A') && (*hex<='F')) value = (value<<4)+*hex-'A'+10;
- else {
- if(*hex == '+') {hex++;return regval + value + GetHexValue(hex,hex); };
- if(*hex == '-') {hex++;return regval + value - GetHexValue(hex,hex); };
- break; // No valid char
- }
- hex++;
- };
- return regval + value;
-};
-
bool ChangeRegister(char* str)
{
char* hex = str;
while (*hex==' ') hex++;
- if (strstr(hex,"EAX")==hex) { hex+=3; reg_eax = GetHexValue(hex,hex); } else
- if (strstr(hex,"EBX")==hex) { hex+=3; reg_ebx = GetHexValue(hex,hex); } else
- if (strstr(hex,"ECX")==hex) { hex+=3; reg_ecx = GetHexValue(hex,hex); } else
- if (strstr(hex,"EDX")==hex) { hex+=3; reg_edx = GetHexValue(hex,hex); } else
- if (strstr(hex,"ESI")==hex) { hex+=3; reg_esi = GetHexValue(hex,hex); } else
- if (strstr(hex,"EDI")==hex) { hex+=3; reg_edi = GetHexValue(hex,hex); } else
- if (strstr(hex,"EBP")==hex) { hex+=3; reg_ebp = GetHexValue(hex,hex); } else
- if (strstr(hex,"ESP")==hex) { hex+=3; reg_esp = GetHexValue(hex,hex); } else
- if (strstr(hex,"EIP")==hex) { hex+=3; reg_eip = GetHexValue(hex,hex); } else
- if (strstr(hex,"AX")==hex) { hex+=2; reg_ax = (Bit16u)GetHexValue(hex,hex); } else
- if (strstr(hex,"BX")==hex) { hex+=2; reg_bx = (Bit16u)GetHexValue(hex,hex); } else
- if (strstr(hex,"CX")==hex) { hex+=2; reg_cx = (Bit16u)GetHexValue(hex,hex); } else
- if (strstr(hex,"DX")==hex) { hex+=2; reg_dx = (Bit16u)GetHexValue(hex,hex); } else
- if (strstr(hex,"SI")==hex) { hex+=2; reg_si = (Bit16u)GetHexValue(hex,hex); } else
- if (strstr(hex,"DI")==hex) { hex+=2; reg_di = (Bit16u)GetHexValue(hex,hex); } else
- if (strstr(hex,"BP")==hex) { hex+=2; reg_bp = (Bit16u)GetHexValue(hex,hex); } else
- if (strstr(hex,"SP")==hex) { hex+=2; reg_sp = (Bit16u)GetHexValue(hex,hex); } else
- if (strstr(hex,"IP")==hex) { hex+=2; reg_ip = (Bit16u)GetHexValue(hex,hex); } else
- if (strstr(hex,"CS")==hex) { hex+=2; SegSet16(cs,(Bit16u)GetHexValue(hex,hex)); } else
- if (strstr(hex,"DS")==hex) { hex+=2; SegSet16(ds,(Bit16u)GetHexValue(hex,hex)); } else
- if (strstr(hex,"ES")==hex) { hex+=2; SegSet16(es,(Bit16u)GetHexValue(hex,hex)); } else
- if (strstr(hex,"FS")==hex) { hex+=2; SegSet16(fs,(Bit16u)GetHexValue(hex,hex)); } else
- if (strstr(hex,"GS")==hex) { hex+=2; SegSet16(gs,(Bit16u)GetHexValue(hex,hex)); } else
- if (strstr(hex,"SS")==hex) { hex+=2; SegSet16(ss,(Bit16u)GetHexValue(hex,hex)); } else
- if (strstr(hex,"AF")==hex) { hex+=2; SETFLAGBIT(AF,GetHexValue(hex,hex)); } else
- if (strstr(hex,"CF")==hex) { hex+=2; SETFLAGBIT(CF,GetHexValue(hex,hex)); } else
- if (strstr(hex,"DF")==hex) { hex+=2; SETFLAGBIT(DF,GetHexValue(hex,hex)); } else
- if (strstr(hex,"IF")==hex) { hex+=2; SETFLAGBIT(IF,GetHexValue(hex,hex)); } else
- if (strstr(hex,"OF")==hex) { hex+=2; SETFLAGBIT(OF,GetHexValue(hex,hex)); } else
- if (strstr(hex,"ZF")==hex) { hex+=2; SETFLAGBIT(ZF,GetHexValue(hex,hex)); } else
- if (strstr(hex,"PF")==hex) { hex+=2; SETFLAGBIT(PF,GetHexValue(hex,hex)); } else
- if (strstr(hex,"SF")==hex) { hex+=2; SETFLAGBIT(SF,GetHexValue(hex,hex)); } else
+ if (strstr(hex,"EAX")==hex) { hex+=3; reg_eax = DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"EBX")==hex) { hex+=3; reg_ebx = DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"ECX")==hex) { hex+=3; reg_ecx = DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"EDX")==hex) { hex+=3; reg_edx = DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"ESI")==hex) { hex+=3; reg_esi = DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"EDI")==hex) { hex+=3; reg_edi = DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"EBP")==hex) { hex+=3; reg_ebp = DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"ESP")==hex) { hex+=3; reg_esp = DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"EIP")==hex) { hex+=3; reg_eip = DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"AX")==hex) { hex+=2; reg_ax = (Bit16u)DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"BX")==hex) { hex+=2; reg_bx = (Bit16u)DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"CX")==hex) { hex+=2; reg_cx = (Bit16u)DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"DX")==hex) { hex+=2; reg_dx = (Bit16u)DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"SI")==hex) { hex+=2; reg_si = (Bit16u)DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"DI")==hex) { hex+=2; reg_di = (Bit16u)DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"BP")==hex) { hex+=2; reg_bp = (Bit16u)DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"SP")==hex) { hex+=2; reg_sp = (Bit16u)DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"IP")==hex) { hex+=2; reg_ip = (Bit16u)DEBUG_GetHexValue(hex,hex); } else
+ if (strstr(hex,"CS")==hex) { hex+=2; SegSet16(cs,(Bit16u)DEBUG_GetHexValue(hex,hex)); } else
+ if (strstr(hex,"DS")==hex) { hex+=2; SegSet16(ds,(Bit16u)DEBUG_GetHexValue(hex,hex)); } else
+ if (strstr(hex,"ES")==hex) { hex+=2; SegSet16(es,(Bit16u)DEBUG_GetHexValue(hex,hex)); } else
+ if (strstr(hex,"FS")==hex) { hex+=2; SegSet16(fs,(Bit16u)DEBUG_GetHexValue(hex,hex)); } else
+ if (strstr(hex,"GS")==hex) { hex+=2; SegSet16(gs,(Bit16u)DEBUG_GetHexValue(hex,hex)); } else
+ if (strstr(hex,"SS")==hex) { hex+=2; SegSet16(ss,(Bit16u)DEBUG_GetHexValue(hex,hex)); } else
+ if (strstr(hex,"AF")==hex) { hex+=2; SETFLAGBIT(AF,DEBUG_GetHexValue(hex,hex)); } else
+ if (strstr(hex,"CF")==hex) { hex+=2; SETFLAGBIT(CF,DEBUG_GetHexValue(hex,hex)); } else
+ if (strstr(hex,"DF")==hex) { hex+=2; SETFLAGBIT(DF,DEBUG_GetHexValue(hex,hex)); } else
+ if (strstr(hex,"IF")==hex) { hex+=2; SETFLAGBIT(IF,DEBUG_GetHexValue(hex,hex)); } else
+ if (strstr(hex,"OF")==hex) { hex+=2; SETFLAGBIT(OF,DEBUG_GetHexValue(hex,hex)); } else
+ if (strstr(hex,"ZF")==hex) { hex+=2; SETFLAGBIT(ZF,DEBUG_GetHexValue(hex,hex)); } else
+ if (strstr(hex,"PF")==hex) { hex+=2; SETFLAGBIT(PF,DEBUG_GetHexValue(hex,hex)); } else
+ if (strstr(hex,"SF")==hex) { hex+=2; SETFLAGBIT(SF,DEBUG_GetHexValue(hex,hex)); } else
{ return false; };
return true;
};
@@ -982,24 +808,24 @@ bool ParseCommand(char* str) {
found = const_cast<char*>(s_found.c_str());
if (command == "MEMDUMP") { // Dump memory to file
- Bit16u seg = (Bit16u)GetHexValue(found,found); found++;
- Bit32u ofs = GetHexValue(found,found); found++;
- Bit32u num = GetHexValue(found,found); found++;
+ Bit16u seg = (Bit16u)DEBUG_GetHexValue(found,found); found++;
+ Bit32u ofs = DEBUG_GetHexValue(found,found); found++;
+ Bit32u num = DEBUG_GetHexValue(found,found); found++;
SaveMemory(seg,ofs,num);
return true;
};
if (command == "MEMDUMPBIN") { // Dump memory to file bineary
- Bit16u seg = (Bit16u)GetHexValue(found,found); found++;
- Bit32u ofs = GetHexValue(found,found); found++;
- Bit32u num = GetHexValue(found,found); found++;
+ Bit16u seg = (Bit16u)DEBUG_GetHexValue(found,found); found++;
+ Bit32u ofs = DEBUG_GetHexValue(found,found); found++;
+ Bit32u num = DEBUG_GetHexValue(found,found); found++;
SaveMemoryBin(seg,ofs,num);
return true;
};
if (command == "IV") { // Insert variable
- Bit16u seg = (Bit16u)GetHexValue(found,found); found++;
- Bit32u ofs = (Bit16u)GetHexValue(found,found); found++;
+ Bit16u seg = (Bit16u)DEBUG_GetHexValue(found,found); found++;
+ Bit32u ofs = (Bit16u)DEBUG_GetHexValue(found,found); found++;
char name[16];
for (int i=0; i<16; i++) {
if (found[i] && (found[i]!=' ')) name[i] = found[i];
@@ -1009,7 +835,7 @@ bool ParseCommand(char* str) {
if(!name[0]) return false;
DEBUG_ShowMsg("DEBUG: Created debug var %s at %04X:%04X\n",name,seg,ofs);
- CDebugVar::InsertVariable(name,GetAddress(seg,ofs));
+ CDebugVar::InsertVariable(name,DEBUG_GetAddress(seg,ofs));
return true;
};
@@ -1043,15 +869,15 @@ bool ParseCommand(char* str) {
};
if (command == "SM") { // Set memory with following values
- Bit16u seg = (Bit16u)GetHexValue(found,found); found++;
- Bit32u ofs = GetHexValue(found,found); found++;
+ Bit16u seg = (Bit16u)DEBUG_GetHexValue(found,found); found++;
+ Bit32u ofs = DEBUG_GetHexValue(found,found); found++;
Bit16u count = 0;
while (*found) {
while (*found==' ') found++;
if (*found) {
- Bit8u value = (Bit8u)GetHexValue(found,found);
+ Bit8u value = (Bit8u)DEBUG_GetHexValue(found,found);
if(*found) found++;
- mem_writeb_checked(GetAddress(seg,ofs+count),value);
+ mem_writeb_checked(DEBUG_GetAddress(seg,ofs+count),value);
count++;
}
};
@@ -1060,8 +886,8 @@ bool ParseCommand(char* str) {
};
if (command == "BP") { // Add new breakpoint
- Bit16u seg = (Bit16u)GetHexValue(found,found);found++; // skip ":"
- Bit32u ofs = GetHexValue(found,found);
+ Bit16u seg = (Bit16u)DEBUG_GetHexValue(found,found);found++; // skip ":"
+ Bit32u ofs = DEBUG_GetHexValue(found,found);
CBreakpoint::AddBreakpoint(seg,ofs,false);
DEBUG_ShowMsg("DEBUG: Set breakpoint at %04X:%04X\n",seg,ofs);
return true;
@@ -1070,16 +896,16 @@ bool ParseCommand(char* str) {
#if C_HEAVY_DEBUG
if (command == "BPM") { // Add new breakpoint
- Bit16u seg = (Bit16u)GetHexValue(found,found);found++; // skip ":"
- Bit32u ofs = GetHexValue(found,found);
+ Bit16u seg = (Bit16u)DEBUG_GetHexValue(found,found);found++; // skip ":"
+ Bit32u ofs = DEBUG_GetHexValue(found,found);
CBreakpoint::AddMemBreakpoint(seg,ofs);
DEBUG_ShowMsg("DEBUG: Set memory breakpoint at %04X:%04X\n",seg,ofs);
return true;
};
if (command == "BPPM") { // Add new breakpoint
- Bit16u seg = (Bit16u)GetHexValue(found,found);found++; // skip ":"
- Bit32u ofs = GetHexValue(found,found);
+ Bit16u seg = (Bit16u)DEBUG_GetHexValue(found,found);found++; // skip ":"
+ Bit32u ofs = DEBUG_GetHexValue(found,found);
CBreakpoint* bp = CBreakpoint::AddMemBreakpoint(seg,ofs);
if (bp) {
bp->SetType(BKPNT_MEMORY_PROT);
@@ -1089,7 +915,7 @@ bool ParseCommand(char* str) {
};
if (command == "BPLM") { // Add new breakpoint
- Bit32u ofs = GetHexValue(found,found);
+ Bit32u ofs = DEBUG_GetHexValue(found,found);
CBreakpoint* bp = CBreakpoint::AddMemBreakpoint(0,ofs);
if (bp) bp->SetType(BKPNT_MEMORY_LINEAR);
DEBUG_ShowMsg("DEBUG: Set linear memory breakpoint at %08X\n",ofs);
@@ -1099,9 +925,9 @@ bool ParseCommand(char* str) {
#endif
if (command == "BPINT") { // Add Interrupt Breakpoint
- Bit8u intNr = (Bit8u)GetHexValue(found,found);
+ Bit8u intNr = (Bit8u)DEBUG_GetHexValue(found,found);
bool all = !(*found);found++;
- Bit8u valAH = (Bit8u)GetHexValue(found,found);
+ Bit8u valAH = (Bit8u)DEBUG_GetHexValue(found,found);
if ((valAH==0x00) && (*found=='*' || all)) {
CBreakpoint::AddIntBreakpoint(intNr,BPINT_ALL,false);
DEBUG_ShowMsg("DEBUG: Set interrupt breakpoint at INT %02X\n",intNr);
@@ -1120,7 +946,7 @@ bool ParseCommand(char* str) {
};
if (command == "BPDEL") { // Delete Breakpoints
- Bit8u bpNr = (Bit8u)GetHexValue(found,found);
+ Bit8u bpNr = (Bit8u)DEBUG_GetHexValue(found,found);
if ((bpNr==0x00) && (*found=='*')) { // Delete all
CBreakpoint::DeleteAll();
DEBUG_ShowMsg("DEBUG: Breakpoints deleted.\n");
@@ -1132,8 +958,8 @@ bool ParseCommand(char* str) {
};
if (command == "C") { // Set code overview
- Bit16u codeSeg = (Bit16u)GetHexValue(found,found); found++;
- Bit32u codeOfs = GetHexValue(found,found);
+ Bit16u codeSeg = (Bit16u)DEBUG_GetHexValue(found,found); found++;
+ Bit32u codeOfs = DEBUG_GetHexValue(found,found);
DEBUG_ShowMsg("DEBUG: Set code overview to %04X:%04X\n",codeSeg,codeOfs);
codeViewData.useCS = codeSeg;
codeViewData.useEIP = codeOfs;
@@ -1142,40 +968,40 @@ bool ParseCommand(char* str) {
};
if (command == "D") { // Set data overview
- dataSeg = (Bit16u)GetHexValue(found,found); found++;
- dataOfs = GetHexValue(found,found);
- DEBUG_ShowMsg("DEBUG: Set data overview to %04X:%04X\n",dataSeg,dataOfs);
+ DEBUG_dataSeg = (Bit16u)DEBUG_GetHexValue(found,found); found++;
+ DEBUG_dataOfs = DEBUG_GetHexValue(found,found);
+ DEBUG_ShowMsg("DEBUG: Set data overview to %04X:%04X\n",DEBUG_dataSeg,DEBUG_dataOfs);
return true;
};
#if C_HEAVY_DEBUG
if (command == "LOG") { // Create Cpu normal log file
- cpuLogType = 1;
+ DEBUG_cpuLogType = 1;
command = "logcode";
}
if (command == "LOGS") { // Create Cpu short log file
- cpuLogType = 0;
+ DEBUG_cpuLogType = 0;
command = "logcode";
}
if (command == "LOGL") { // Create Cpu long log file
- cpuLogType = 2;
+ DEBUG_cpuLogType = 2;
command = "logcode";
}
if (command == "logcode") { //Shared code between all logs
DEBUG_ShowMsg("DEBUG: Starting log\n");
- cpuLogFile.open("LOGCPU.TXT");
- if (!cpuLogFile.is_open()) {
+ DEBUG_cpuLogFile.open("LOGCPU.TXT");
+ if (!DEBUG_cpuLogFile.is_open()) {
DEBUG_ShowMsg("DEBUG: Logfile couldn't be created.\n");
return false;
}
//Initialize log object
- cpuLogFile << hex << noshowbase << setfill('0') << uppercase;
- cpuLog = true;
- cpuLogCounter = GetHexValue(found,found);
+ DEBUG_cpuLogFile << hex << noshowbase << setfill('0') << uppercase;
+ DEBUG_cpuLog = true;
+ DEBUG_cpuLogCounter = DEBUG_GetHexValue(found,found);
debugging = false;
CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,true);
@@ -1187,7 +1013,7 @@ bool ParseCommand(char* str) {
#endif
if (command == "INTT") { //trace int.
- Bit8u intNr = (Bit8u)GetHexValue(found,found);
+ Bit8u intNr = (Bit8u)DEBUG_GetHexValue(found,found);
DEBUG_ShowMsg("DEBUG: Tracing INT %02X\n",intNr);
CPU_HW_Interrupt(intNr);
SetCodeWinStart();
@@ -1195,7 +1021,7 @@ bool ParseCommand(char* str) {
};
if (command == "INT") { // start int.
- Bit8u intNr = (Bit8u)GetHexValue(found,found);
+ Bit8u intNr = (Bit8u)DEBUG_GetHexValue(found,found);
DEBUG_ShowMsg("DEBUG: Starting INT %02X\n",intNr);
CBreakpoint::AddBreakpoint(SegValue(cs),reg_eip, true);
CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip-1,true);
@@ -1209,26 +1035,26 @@ bool ParseCommand(char* str) {
if (command == "SELINFO") {
while (found[0] == ' ') found++;
char out1[200],out2[200];
- GetDescriptorInfo(found,out1,out2);
+ DEBUG_GetDescriptorInfo(found,out1,out2);
DEBUG_ShowMsg("SelectorInfo %s:\n%s\n%s\n",found,out1,out2);
return true;
};
if (command == "DOS") {
stream >> command;
- if (command == "MCBS") LogMCBS();
+ if (command == "MCBS") DEBUG_LogMCBS();
return true;
}
- if (command == "GDT") {LogGDT(); return true;}
+ if (command == "GDT") {DEBUG_LogGDT(); return true;}
- if (command == "LDT") {LogLDT(); return true;}
+ if (command == "LDT") {DEBUG_LogLDT(); return true;}
- if (command == "IDT") {LogIDT(); return true;}
+ if (command == "IDT") {DEBUG_LogIDT(); return true;}
- if (command == "PAGING") {LogPages(found); return true;}
+ if (command == "PAGING") {DEBUG_LogPages(found); return true;}
- if (command == "CPU") {LogCPUInfo(); return true;}
+ if (command == "CPU") {DEBUG_LogCPUInfo(); return true;}
if (command == "INTVEC") {
if (found[0] != 0) {
@@ -1239,7 +1065,7 @@ bool ParseCommand(char* str) {
if (command == "INTHAND") {
if (found[0] != 0) {
- Bit8u intNr = (Bit8u)GetHexValue(found,found);
+ Bit8u intNr = (Bit8u)DEBUG_GetHexValue(found,found);
DEBUG_ShowMsg("DEBUG: Set code overview to interrupt handler %X\n",intNr);
codeViewData.useCS = mem_readw(intNr*4+2);
codeViewData.useEIP = mem_readw(intNr*4);
@@ -1249,7 +1075,7 @@ bool ParseCommand(char* str) {
};
if(command == "EXTEND") { //Toggle additional data.
- showExtend = !showExtend;
+ DEBUG_showExtend = !DEBUG_showExtend;
return true;
};
@@ -1262,14 +1088,14 @@ bool ParseCommand(char* str) {
#if C_HEAVY_DEBUG
if (command == "HEAVYLOG") { // Create Cpu log file
- logHeavy = !logHeavy;
- DEBUG_ShowMsg("DEBUG: Heavy cpu logging %s.\n",logHeavy?"on":"off");
+ DEBUG_logHeavy = !DEBUG_logHeavy;
+ DEBUG_ShowMsg("DEBUG: Heavy cpu logging %s.\n",DEBUG_logHeavy?"on":"off");
return true;
};
if (command == "ZEROPROTECT") { //toggle zero protection
- zeroProtect = !zeroProtect;
- DEBUG_ShowMsg("DEBUG: Zero code execution protection %s.\n",zeroProtect?"on":"off");
+ DEBUG_zeroProtect = !DEBUG_zeroProtect;
+ DEBUG_ShowMsg("DEBUG: Zero code execution protection %s.\n",DEBUG_zeroProtect?"on":"off");
return true;
};
@@ -1335,181 +1161,6 @@ bool ParseCommand(char* str) {
return false;
};
-char* AnalyzeInstruction(char* inst, bool saveSelector) {
- static char result[256];
-
- char instu[256];
- char prefix[3];
- Bit16u seg;
-
- strcpy(instu,inst);
- upcase(instu);
-
- result[0] = 0;
- char* pos = strchr(instu,'[');
- if (pos) {
- // Segment prefix ?
- if (*(pos-1)==':') {
- char* segpos = pos-3;
- prefix[0] = tolower(*segpos);
- prefix[1] = tolower(*(segpos+1));
- prefix[2] = 0;
- seg = (Bit16u)GetHexValue(segpos,segpos);
- } else {
- if (strstr(pos,"SP") || strstr(pos,"BP")) {
- seg = SegValue(ss);
- strcpy(prefix,"ss");
- } else {
- seg = SegValue(ds);
- strcpy(prefix,"ds");
- };
- };
-
- pos++;
- Bit32u adr = GetHexValue(pos,pos);
- while (*pos!=']') {
- if (*pos=='+') {
- pos++;
- adr += GetHexValue(pos,pos);
- } else if (*pos=='-') {
- pos++;
- adr -= GetHexValue(pos,pos);
- } else
- pos++;
- };
- Bit32u address = GetAddress(seg,adr);
- if (!(get_tlb_readhandler(address)->flags & PFLAG_INIT)) {
- static char outmask[] = "%s:[%04X]=%02X";
-
- if (cpu.pmode) outmask[6] = '8';
- switch (DasmLastOperandSize()) {
- case 8 : { Bit8u val = mem_readb(address);
- outmask[12] = '2';
- sprintf(result,outmask,prefix,adr,val);
- } break;
- case 16: { Bit16u val = mem_readw(address);
- outmask[12] = '4';
- sprintf(result,outmask,prefix,adr,val);
- } break;
- case 32: { Bit32u val = mem_readd(address);
- outmask[12] = '8';
- sprintf(result,outmask,prefix,adr,val);
- } break;
- }
- } else {
- sprintf(result,"[illegal]");
- }
- // Variable found ?
- CDebugVar* var = CDebugVar::FindVar(address);
- if (var) {
- // Replace occurence
- char* pos1 = strchr(inst,'[');
- char* pos2 = strchr(inst,']');
- if (pos1 && pos2) {
- char temp[256];
- strcpy(temp,pos2); // save end
- pos1++; *pos1 = 0; // cut after '['
- strcat(inst,var->GetName()); // add var name
- strcat(inst,temp); // add end
- };
- };
- // show descriptor info, if available
- if ((cpu.pmode) && saveSelector) {
- strcpy(curSelectorName,prefix);
- };
- };
- // If it is a callback add additional info
- pos = strstr(inst,"callback");
- if (pos) {
- pos += 9;
- Bitu nr = GetHexValue(pos,pos);
- const char* descr = CALLBACK_GetDescription(nr);
- if (descr) {
- strcat(inst," ("); strcat(inst,descr); strcat(inst,")");
- }
- };
- // Must be a jump
- if (instu[0] == 'J')
- {
- bool jmp = false;
- switch (instu[1]) {
- case 'A' : { jmp = (get_CF()?false:true) && (get_ZF()?false:true); // JA
- } break;
- case 'B' : { if (instu[2] == 'E') {
- jmp = (get_CF()?true:false) || (get_ZF()?true:false); // JBE
- } else {
- jmp = get_CF()?true:false; // JB
- }
- } break;
- case 'C' : { if (instu[2] == 'X') {
- jmp = reg_cx == 0; // JCXZ
- } else {
- jmp = get_CF()?true:false; // JC
- }
- } break;
- case 'E' : { jmp = get_ZF()?true:false; // JE
- } break;
- case 'G' : { if (instu[2] == 'E') {
- jmp = (get_SF()?true:false)==(get_OF()?true:false); // JGE
- } else {
- jmp = (get_ZF()?false:true) && ((get_SF()?true:false)==(get_OF()?true:false)); // JG
- }
- } break;
- case 'L' : { if (instu[2] == 'E') {
- jmp = (get_ZF()?true:false) || ((get_SF()?true:false)!=(get_OF()?true:false)); // JLE
- } else {
- jmp = (get_SF()?true:false)!=(get_OF()?true:false); // JL
- }
- } break;
- case 'M' : { jmp = true; // JMP
- } break;
- case 'N' : { switch (instu[2]) {
- case 'B' :
- case 'C' : { jmp = get_CF()?false:true; // JNB / JNC
- } break;
- case 'E' : { jmp = get_ZF()?false:true; // JNE
- } break;
- case 'O' : { jmp = get_OF()?false:true; // JNO
- } break;
- case 'P' : { jmp = get_PF()?false:true; // JNP
- } break;
- case 'S' : { jmp = get_SF()?false:true; // JNS
- } break;
- case 'Z' : { jmp = get_ZF()?false:true; // JNZ
- } break;
- }
- } break;
- case 'O' : { jmp = get_OF()?true:false; // JO
- } break;
- case 'P' : { if (instu[2] == 'O') {
- jmp = get_PF()?false:true; // JPO
- } else {
- jmp = get_SF()?true:false; // JP / JPE
- }
- } break;
- case 'S' : { jmp = get_SF()?true:false; // JS
- } break;
- case 'Z' : { jmp = get_ZF()?true:false; // JZ
- } break;
- }
- if (jmp) {
- pos = strchr(instu,'$');
- if (pos) {
- pos = strchr(instu,'+');
- if (pos) {
- strcpy(result,"(down)");
- } else {
- strcpy(result,"(up)");
- }
- }
- } else {
- sprintf(result,"(no jmp)");
- }
- }
- return result;
-};
-
-
Bit32u DEBUG_CheckKeys(void) {
Bits ret=0;
int key=getch();
@@ -1548,36 +1199,36 @@ Bit32u DEBUG_CheckKeys(void) {
switch(toupper(key)) {
case 'D' : // ALT - D: DS:SI
- dataSeg = SegValue(ds);
- if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_esi;
- else dataOfs = reg_si;
+ DEBUG_dataSeg = SegValue(ds);
+ if (cpu.pmode && !(reg_flags & FLAG_VM)) DEBUG_dataOfs = reg_esi;
+ else DEBUG_dataOfs = reg_si;
break;
case 'E' : //ALT - E: es:di
- dataSeg = SegValue(es);
- if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_edi;
- else dataOfs = reg_di;
+ DEBUG_dataSeg = SegValue(es);
+ if (cpu.pmode && !(reg_flags & FLAG_VM)) DEBUG_dataOfs = reg_edi;
+ else DEBUG_dataOfs = reg_di;
break;
case 'X': //ALT - X: ds:dx
- dataSeg = SegValue(ds);
- if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_edx;
- else dataOfs = reg_dx;
+ DEBUG_dataSeg = SegValue(ds);
+ if (cpu.pmode && !(reg_flags & FLAG_VM)) DEBUG_dataOfs = reg_edx;
+ else DEBUG_dataOfs = reg_dx;
break;
case 'B' : //ALT -B: es:bx
- dataSeg = SegValue(es);
- if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_ebx;
- else dataOfs = reg_bx;
+ DEBUG_dataSeg = SegValue(es);
+ if (cpu.pmode && !(reg_flags & FLAG_VM)) DEBUG_dataOfs = reg_ebx;
+ else DEBUG_dataOfs = reg_bx;
break;
case 'S': //ALT - S: ss:sp
- dataSeg = SegValue(ss);
- if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_esp;
- else dataOfs = reg_sp;
+ DEBUG_dataSeg = SegValue(ss);
+ if (cpu.pmode && !(reg_flags & FLAG_VM)) DEBUG_dataOfs = reg_esp;
+ else DEBUG_dataOfs = reg_sp;
break;
default:
break;
}
break;
- case KEY_PPAGE : dataOfs -= 16; break;
- case KEY_NPAGE : dataOfs += 16; break;
+ case KEY_PPAGE : DEBUG_dataOfs -= 16; break;
+ case KEY_NPAGE : DEBUG_dataOfs += 16; break;
case KEY_DOWN: // down
if (codeViewData.cursorPos<9) codeViewData.cursorPos++;
@@ -1592,7 +1243,7 @@ Bit32u DEBUG_CheckKeys(void) {
Bit32u newEIP = codeViewData.useEIP - 1;
if(codeViewData.useEIP) {
for (; bytes < 10; bytes++) {
- PhysPt start = GetAddress(codeViewData.useCS,newEIP);
+ PhysPt start = DEBUG_GetAddress(codeViewData.useCS,newEIP);
size = DasmI386(dline, start, newEIP, cpu.code.big);
if(codeViewData.useEIP == newEIP+size) break;
newEIP--;
@@ -1645,7 +1296,7 @@ Bit32u DEBUG_CheckKeys(void) {
DOSBOX_SetNormalLoop();
break;
case KEY_F(9): // Set/Remove Breakpoint
- { PhysPt ptr = GetAddress(codeViewData.cursorSeg,codeViewData.cursorOfs);
+ { PhysPt ptr = DEBUG_GetAddress(codeViewData.cursorSeg,codeViewData.cursorOfs);
if (CBreakpoint::IsBreakpoint(ptr)) {
CBreakpoint::DeleteBreakpoint(ptr);
DEBUG_ShowMsg("DEBUG: Breakpoint deletion success.\n");
@@ -1659,7 +1310,7 @@ Bit32u DEBUG_CheckKeys(void) {
case KEY_F(10): // Step over inst
if (StepOver()) return 0;
else {
- exitLoop = false;
+ DEBUG_exitLoop = false;
skipFirstInstruction = true; // for heavy debugger
CPU_Cycles = 1;
ret=(*cpudecoder)();
@@ -1668,7 +1319,7 @@ Bit32u DEBUG_CheckKeys(void) {
}
break;
case KEY_F(11): // trace into
- exitLoop = false;
+ DEBUG_exitLoop = false;
skipFirstInstruction = true; // for heavy debugger
CPU_Cycles = 1;
ret = (*cpudecoder)();
@@ -1730,7 +1381,7 @@ Bit32u DEBUG_CheckKeys(void) {
else
ret = (*CallBack_Handlers[ret])();
if (ret) {
- exitLoop=true;
+ DEBUG_exitLoop=true;
CPU_Cycles=CPU_CycleLeft=0;
return ret;
}
@@ -1785,239 +1436,7 @@ static void DEBUG_RaiseTimerIrq(void) {
PIC_ActivateIRQ(0);
}
-// Display the content of the MCB chain starting with the MCB at the specified segment.
-static void LogMCBChain(Bit16u mcb_segment) {
- DOS_MCB mcb(mcb_segment);
- char filename[9]; // 8 characters plus a terminating NUL
- const char *psp_seg_note;
- PhysPt dataAddr = PhysMake(dataSeg,dataOfs);// location being viewed in the "Data Overview"
-
- // loop forever, breaking out of the loop once we've processed the last MCB
- while (true) {
- // verify that the type field is valid
- if (mcb.GetType()!=0x4d && mcb.GetType()!=0x5a) {
- LOG(LOG_MISC,LOG_ERROR)("MCB chain broken at %04X:0000!",mcb_segment);
- return;
- }
-
- mcb.GetFileName(filename);
-
- // some PSP segment values have special meanings
- switch (mcb.GetPSPSeg()) {
- case MCB_FREE:
- psp_seg_note = "(free)";
- break;
- case MCB_DOS:
- psp_seg_note = "(DOS)";
- break;
- default:
- psp_seg_note = "";
- }
-
- LOG(LOG_MISC,LOG_ERROR)(" %04X %12u %04X %-7s %s",mcb_segment,mcb.GetSize() << 4,mcb.GetPSPSeg(), psp_seg_note, filename);
-
- // print a message if dataAddr is within this MCB's memory range
- PhysPt mcbStartAddr = PhysMake(mcb_segment+1,0);
- PhysPt mcbEndAddr = PhysMake(mcb_segment+1+mcb.GetSize(),0);
- if (dataAddr >= mcbStartAddr && dataAddr < mcbEndAddr) {
- LOG(LOG_MISC,LOG_ERROR)(" (data addr %04hX:%04X is %u bytes past this MCB)",dataSeg,dataOfs,dataAddr - mcbStartAddr);
- }
-
- // if we've just processed the last MCB in the chain, break out of the loop
- if (mcb.GetType()==0x5a) {
- break;
- }
- // else, move to the next MCB in the chain
- mcb_segment+=mcb.GetSize()+1;
- mcb.SetPt(mcb_segment);
- }
-}
-
-// Display the content of all Memory Control Blocks.
-static void LogMCBS(void)
-{
- LOG(LOG_MISC,LOG_ERROR)("MCB Seg Size (bytes) PSP Seg (notes) Filename");
- LOG(LOG_MISC,LOG_ERROR)("Conventional memory:");
- LogMCBChain(dos.firstMCB);
-
- LOG(LOG_MISC,LOG_ERROR)("Upper memory:");
- LogMCBChain(dos_infoblock.GetStartOfUMBChain());
-}
-
-static void LogGDT(void)
-{
- char out1[512];
- Descriptor desc;
- Bitu length = cpu.gdt.GetLimit();
- PhysPt address = cpu.gdt.GetBase();
- PhysPt max = address + length;
- Bitu i = 0;
- LOG(LOG_MISC,LOG_ERROR)("GDT Base:%08X Limit:%08X",address,length);
- while (address<max) {
- desc.Load(address);
- sprintf(out1,"%04X: b:%08X type: %02X parbg",(i<<3),desc.GetBase(),desc.saved.seg.type);
- LOG(LOG_MISC,LOG_ERROR)(out1);
- sprintf(out1," l:%08X dpl : %01X %1X%1X%1X%1X%1X",desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.r,desc.saved.seg.big,desc.saved.seg.g);
- LOG(LOG_MISC,LOG_ERROR)(out1);
- address+=8; i++;
- };
-};
-
-static void LogLDT(void) {
- char out1[512];
- Descriptor desc;
- Bitu ldtSelector = cpu.gdt.SLDT();
- if (!cpu.gdt.GetDescriptor(ldtSelector,desc)) return;
- Bitu length = desc.GetLimit();
- PhysPt address = desc.GetBase();
- PhysPt max = address + length;
- Bitu i = 0;
- LOG(LOG_MISC,LOG_ERROR)("LDT Base:%08X Limit:%08X",address,length);
- while (address<max) {
- desc.Load(address);
- sprintf(out1,"%04X: b:%08X type: %02X parbg",(i<<3)|4,desc.GetBase(),desc.saved.seg.type);
- LOG(LOG_MISC,LOG_ERROR)(out1);
- sprintf(out1," l:%08X dpl : %01X %1X%1X%1X%1X%1X",desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.r,desc.saved.seg.big,desc.saved.seg.g);
- LOG(LOG_MISC,LOG_ERROR)(out1);
- address+=8; i++;
- };
-};
-static void LogIDT(void) {
- char out1[512];
- Descriptor desc;
- Bitu address = 0;
- while (address<256*8) {
- if (cpu.idt.GetDescriptor(address,desc)) {
- sprintf(out1,"%04X: sel:%04X off:%02X",address/8,desc.GetSelector(),desc.GetOffset());
- LOG(LOG_MISC,LOG_ERROR)(out1);
- }
- address+=8;
- };
-};
-
-void LogPages(char* selname) {
- char out1[512];
- if (paging.enabled) {
- Bitu sel = GetHexValue(selname,selname);
- if ((sel==0x00) && ((*selname==0) || (*selname=='*'))) {
- for (int i=0; i<0xfffff; i++) {
- Bitu table_addr=(paging.base.page<<12)+(i >> 10)*4;
- X86PageEntry table;
- table.load=phys_readd(table_addr);
- if (table.block.p) {
- X86PageEntry entry;
- Bitu entry_addr=(table.block.base<<12)+(i & 0x3ff)*4;
- entry.load=phys_readd(entry_addr);
- if (entry.block.p) {
- sprintf(out1,"page %05Xxxx -> %04Xxxx flags [uw] %x:%x::%x:%x [d=%x|a=%x]",
- i,entry.block.base,entry.block.us,table.block.us,
- entry.block.wr,table.block.wr,entry.block.d,entry.block.a);
- LOG(LOG_MISC,LOG_ERROR)(out1);
- }
- }
- }
- } else {
- Bitu table_addr=(paging.base.page<<12)+(sel >> 10)*4;
- X86PageEntry table;
- table.load=phys_readd(table_addr);
- if (table.block.p) {
- X86PageEntry entry;
- Bitu entry_addr=(table.block.base<<12)+(sel & 0x3ff)*4;
- entry.load=phys_readd(entry_addr);
- sprintf(out1,"page %05Xxxx -> %04Xxxx flags [puw] %x:%x::%x:%x::%x:%x",sel,entry.block.base,entry.block.p,table.block.p,entry.block.us,table.block.us,entry.block.wr,table.block.wr);
- LOG(LOG_MISC,LOG_ERROR)(out1);
- } else {
- sprintf(out1,"pagetable %03X not present, flags [puw] %x::%x::%x",(sel >> 10),table.block.p,table.block.us,table.block.wr);
- LOG(LOG_MISC,LOG_ERROR)(out1);
- }
- }
- }
-};
-
-static void LogCPUInfo(void) {
- char out1[512];
- sprintf(out1,"cr0:%08X cr2:%08X cr3:%08X cpl=%x",cpu.cr0,paging.cr2,paging.cr3,cpu.cpl);
- LOG(LOG_MISC,LOG_ERROR)(out1);
- sprintf(out1,"eflags:%08X [vm=%x iopl=%x nt=%x]",reg_flags,GETFLAG(VM)>>17,GETFLAG(IOPL)>>12,GETFLAG(NT)>>14);
- LOG(LOG_MISC,LOG_ERROR)(out1);
- sprintf(out1,"GDT base=%08X limit=%08X",cpu.gdt.GetBase(),cpu.gdt.GetLimit());
- LOG(LOG_MISC,LOG_ERROR)(out1);
- sprintf(out1,"IDT base=%08X limit=%08X",cpu.idt.GetBase(),cpu.idt.GetLimit());
- LOG(LOG_MISC,LOG_ERROR)(out1);
-
- Bitu sel=CPU_STR();
- Descriptor desc;
- if (cpu.gdt.GetDescriptor(sel,desc)) {
- sprintf(out1,"TR selector=%04X, base=%08X limit=%08X*%X",sel,desc.GetBase(),desc.GetLimit(),desc.saved.seg.g?0x4000:1);
- LOG(LOG_MISC,LOG_ERROR)(out1);
- }
- sel=CPU_SLDT();
- if (cpu.gdt.GetDescriptor(sel,desc)) {
- sprintf(out1,"LDT selector=%04X, base=%08X limit=%08X*%X",sel,desc.GetBase(),desc.GetLimit(),desc.saved.seg.g?0x4000:1);
- LOG(LOG_MISC,LOG_ERROR)(out1);
- }
-};
-
-#if C_HEAVY_DEBUG
-static void LogInstruction(Bit16u segValue, Bit32u eipValue, ofstream& out) {
- static char empty[23] = { 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,0 };
-
- PhysPt start = GetAddress(segValue,eipValue);
- char dline[200];Bitu size;
- size = DasmI386(dline, start, reg_eip, cpu.code.big);
- char* res = empty;
- if (showExtend && (cpuLogType > 0) ) {
- res = AnalyzeInstruction(dline,false);
- if (!res || !(*res)) res = empty;
- Bitu reslen = strlen(res);
- if (reslen<22) for (Bitu i=0; i<22-reslen; i++) res[reslen+i] = ' '; res[22] = 0;
- };
- Bitu len = strlen(dline);
- if (len<30) for (Bitu i=0; i<30-len; i++) dline[len + i] = ' '; dline[30] = 0;
-
- // Get register values
-
- if(cpuLogType == 0) {
- out << setw(4) << SegValue(cs) << ":" << setw(4) << reg_eip << " " << dline;
- } else if (cpuLogType == 1) {
- out << setw(4) << SegValue(cs) << ":" << setw(8) << reg_eip << " " << dline << " " << res;
- } else if (cpuLogType == 2) {
- char ibytes[200]=""; char tmpc[200];
- for (Bitu i=0; i<size; i++) {
- Bit8u value;
- if (mem_readb_checked(start+i,&value)) sprintf(tmpc,"%s","?? ");
- else sprintf(tmpc,"%02X ",value);
- strcat(ibytes,tmpc);
- }
- len = strlen(ibytes);
- if (len<21) { for (Bitu i=0; i<21-len; i++) ibytes[len + i] =' '; ibytes[21]=0;} //NOTE THE BRACKETS
- out << setw(4) << SegValue(cs) << ":" << setw(8) << reg_eip << " " << dline << " " << res << " " << ibytes;
- }
-
- out << " EAX:" << setw(8) << reg_eax << " EBX:" << setw(8) << reg_ebx
- << " ECX:" << setw(8) << reg_ecx << " EDX:" << setw(8) << reg_edx
- << " ESI:" << setw(8) << reg_esi << " EDI:" << setw(8) << reg_edi
- << " EBP:" << setw(8) << reg_ebp << " ESP:" << setw(8) << reg_esp
- << " DS:" << setw(4) << SegValue(ds)<< " ES:" << setw(4) << SegValue(es);
-
- if(cpuLogType == 0) {
- out << " SS:" << setw(4) << SegValue(ss) << " C" << (get_CF()>0) << " Z" << (get_ZF()>0)
- << " S" << (get_SF()>0) << " O" << (get_OF()>0) << " I" << GETFLAGBOOL(IF);
- } else {
- out << " FS:" << setw(4) << SegValue(fs) << " GS:" << setw(4) << SegValue(gs)
- << " SS:" << setw(4) << SegValue(ss)
- << " CF:" << (get_CF()>0) << " ZF:" << (get_ZF()>0) << " SF:" << (get_SF()>0)
- << " OF:" << (get_OF()>0) << " AF:" << (get_AF()>0) << " PF:" << (get_PF()>0)
- << " IF:" << GETFLAGBOOL(IF);
- }
- if(cpuLogType == 2) {
- out << " TF:" << GETFLAGBOOL(TF) << " VM:" << GETFLAGBOOL(VM) <<" FLG:" << setw(8) << reg_flags
- << " CR0:" << setw(8) << cpu.cr0;
- }
- out << endl;
-};
-#endif
// DEBUG.COM stuff
@@ -2088,7 +1507,7 @@ void DEBUG_CheckExecuteBreakpoint(Bit16u seg, Bit32u off)
Bitu DEBUG_EnableDebugger(void)
{
- exitLoop = true;
+ DEBUG_exitLoop = true;
DEBUG_Enable(true);
CPU_Cycles=CPU_CycleLeft=0;
return 0;
@@ -2128,7 +1547,7 @@ void DEBUG_ShutDown(Section * /*sec*/) {
#endif
}
-Bitu debugCallback;
+Bitu DEBUG_debugCallback;
void DEBUG_Init(Section* sec) {
@@ -2141,14 +1560,20 @@ void DEBUG_Init(Section* sec) {
/* setup debug.com */
PROGRAMS_MakeFile("DEBUG.COM",DEBUG_ProgramStart);
/* Setup callback */
- debugCallback=CALLBACK_Allocate();
- CALLBACK_Setup(debugCallback,DEBUG_EnableDebugger,CB_RETF,"debugger");
+ DEBUG_debugCallback=CALLBACK_Allocate();
+ CALLBACK_Setup(DEBUG_debugCallback,DEBUG_EnableDebugger,CB_RETF,"debugger");
/* shutdown function */
sec->AddDestroyFunction(&DEBUG_ShutDown);
}
// DEBUGGING VAR STUFF
+CDebugVar::CDebugVar(char* _name, PhysPt _adr)
+{
+ adr=_adr;
+ safe_strncpy(name,_name,16);
+};
+
void CDebugVar::InsertVariable(char* name, PhysPt adr)
{
varList.push_back(new CDebugVar(name,adr));
@@ -2237,7 +1662,7 @@ static void SaveMemory(Bitu seg, Bitu ofs1, Bit32u num) {
sprintf(buffer,"%04X:%04X ",seg,ofs1);
for (Bit16u x=0; x<16; x++) {
Bit8u value;
- if (mem_readb_checked(GetAddress(seg,ofs1+x),&value)) sprintf(temp,"%s","?? ");
+ if (mem_readb_checked(DEBUG_GetAddress(seg,ofs1+x),&value)) sprintf(temp,"%s","?? ");
else sprintf(temp,"%02X ",value);
strcat(buffer,temp);
}
@@ -2250,7 +1675,7 @@ static void SaveMemory(Bitu seg, Bitu ofs1, Bit32u num) {
sprintf(buffer,"%04X:%04X ",seg,ofs1);
for (Bit16u x=0; x<num; x++) {
Bit8u value;
- if (mem_readb_checked(GetAddress(seg,ofs1+x),&value)) sprintf(temp,"%s","?? ");
+ if (mem_readb_checked(DEBUG_GetAddress(seg,ofs1+x),&value)) sprintf(temp,"%s","?? ");
else sprintf(temp,"%02X ",value);
strcat(buffer,temp);
}
@@ -2269,7 +1694,7 @@ static void SaveMemoryBin(Bitu seg, Bitu ofs1, Bit32u num) {
for (Bitu x = 0; x < num;x++) {
Bit8u val;
- if (mem_readb_checked(GetAddress(seg,ofs1+x),&val)) val=0;
+ if (mem_readb_checked(DEBUG_GetAddress(seg,ofs1+x),&val)) val=0;
fwrite(&val,1,1,f);
}
@@ -2329,144 +1754,24 @@ static void DrawVariables(void) {
#if C_HEAVY_DEBUG
-const Bit32u LOGCPUMAX = 20000;
-
-static Bit32u logCount = 0;
-
-struct TLogInst {
- Bit16u s_cs;
- Bit32u eip;
- Bit32u eax;
- Bit32u ebx;
- Bit32u ecx;
- Bit32u edx;
- Bit32u esi;
- Bit32u edi;
- Bit32u ebp;
- Bit32u esp;
- Bit16u s_ds;
- Bit16u s_es;
- Bit16u s_fs;
- Bit16u s_gs;
- Bit16u s_ss;
- bool c;
- bool z;
- bool s;
- bool o;
- bool a;
- bool p;
- bool i;
- char dline[31];
- char res[23];
-};
-
-TLogInst logInst[LOGCPUMAX];
-
-void DEBUG_HeavyLogInstruction(void) {
-
- static char empty[23] = { 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,0 };
-
- PhysPt start = GetAddress(SegValue(cs),reg_eip);
- char dline[200];
- DasmI386(dline, start, reg_eip, cpu.code.big);
- char* res = empty;
- if (showExtend) {
- res = AnalyzeInstruction(dline,false);
- if (!res || !(*res)) res = empty;
- Bitu reslen = strlen(res);
- if (reslen<22) for (Bitu i=0; i<22-reslen; i++) res[reslen+i] = ' '; res[22] = 0;
- };
-
- Bitu len = strlen(dline);
- if (len < 30) for (Bitu i=0; i < 30-len; i++) dline[len+i] = ' ';
- dline[30] = 0;
-
- TLogInst & inst = logInst[logCount];
- strcpy(inst.dline,dline);
- inst.s_cs = SegValue(cs);
- inst.eip = reg_eip;
- strcpy(inst.res,res);
- inst.eax = reg_eax;
- inst.ebx = reg_ebx;
- inst.ecx = reg_ecx;
- inst.edx = reg_edx;
- inst.esi = reg_esi;
- inst.edi = reg_edi;
- inst.ebp = reg_ebp;
- inst.esp = reg_esp;
- inst.s_ds = SegValue(ds);
- inst.s_es = SegValue(es);
- inst.s_fs = SegValue(fs);
- inst.s_gs = SegValue(gs);
- inst.s_ss = SegValue(ss);
- inst.c = get_CF()>0;
- inst.z = get_ZF()>0;
- inst.s = get_SF()>0;
- inst.o = get_OF()>0;
- inst.a = get_AF()>0;
- inst.p = get_PF()>0;
- inst.i = GETFLAGBOOL(IF);
-
- if (++logCount >= LOGCPUMAX) logCount = 0;
-};
-
-void DEBUG_HeavyWriteLogInstruction(void) {
- if (!logHeavy) return;
- logHeavy = false;
-
- DEBUG_ShowMsg("DEBUG: Creating cpu log LOGCPU_INT_CD.TXT\n");
-
- ofstream out("LOGCPU_INT_CD.TXT");
- if (!out.is_open()) {
- DEBUG_ShowMsg("DEBUG: Failed.\n");
- return;
- }
- out << hex << noshowbase << setfill('0') << uppercase;
- Bit32u startLog = logCount;
- do {
- // Write Instructions
- TLogInst & inst = logInst[startLog];
- out << setw(4) << inst.s_cs << ":" << setw(8) << inst.eip << " "
- << inst.dline << " " << inst.res << " EAX:" << setw(8)<< inst.eax
- << " EBX:" << setw(8) << inst.ebx << " ECX:" << setw(8) << inst.ecx
- << " EDX:" << setw(8) << inst.edx << " ESI:" << setw(8) << inst.esi
- << " EDI:" << setw(8) << inst.edi << " EBP:" << setw(8) << inst.ebp
- << " ESP:" << setw(8) << inst.esp << " DS:" << setw(4) << inst.s_ds
- << " ES:" << setw(4) << inst.s_es<< " FS:" << setw(4) << inst.s_fs
- << " GS:" << setw(4) << inst.s_gs<< " SS:" << setw(4) << inst.s_ss
- << " CF:" << inst.c << " ZF:" << inst.z << " SF:" << inst.s
- << " OF:" << inst.o << " AF:" << inst.a << " PF:" << inst.p
- << " IF:" << inst.i << endl;
-
-/* fprintf(f,"%04X:%08X %s %s EAX:%08X EBX:%08X ECX:%08X EDX:%08X ESI:%08X EDI:%08X EBP:%08X ESP:%08X DS:%04X ES:%04X FS:%04X GS:%04X SS:%04X CF:%01X ZF:%01X SF:%01X OF:%01X AF:%01X PF:%01X IF:%01X\n",
- logInst[startLog].s_cs,logInst[startLog].eip,logInst[startLog].dline,logInst[startLog].res,logInst[startLog].eax,logInst[startLog].ebx,logInst[startLog].ecx,logInst[startLog].edx,logInst[startLog].esi,logInst[startLog].edi,logInst[startLog].ebp,logInst[startLog].esp,
- logInst[startLog].s_ds,logInst[startLog].s_es,logInst[startLog].s_fs,logInst[startLog].s_gs,logInst[startLog].s_ss,
- logInst[startLog].c,logInst[startLog].z,logInst[startLog].s,logInst[startLog].o,logInst[startLog].a,logInst[startLog].p,logInst[startLog].i);*/
- if (++startLog >= LOGCPUMAX) startLog = 0;
- } while (startLog != logCount);
-
- out.close();
- DEBUG_ShowMsg("DEBUG: Done.\n");
-};
-
bool DEBUG_HeavyIsBreakpoint(void) {
static Bitu zero_count = 0;
- if (cpuLog) {
- if (cpuLogCounter>0) {
- LogInstruction(SegValue(cs),reg_eip,cpuLogFile);
- cpuLogCounter--;
+ if (DEBUG_cpuLog) {
+ if (DEBUG_cpuLogCounter>0) {
+ DEBUG_LogInstruction(SegValue(cs),reg_eip,DEBUG_cpuLogFile);
+ DEBUG_cpuLogCounter--;
}
- if (cpuLogCounter<=0) {
- cpuLogFile.close();
+ if (DEBUG_cpuLogCounter<=0) {
+ DEBUG_cpuLogFile.close();
DEBUG_ShowMsg("DEBUG: cpu log LOGCPU.TXT created\n");
- cpuLog = false;
+ DEBUG_cpuLog = false;
DEBUG_EnableDebugger();
return true;
}
}
- // LogInstruction
- if (logHeavy) DEBUG_HeavyLogInstruction();
- if (zeroProtect) {
+ // DEBUG_LogInstruction
+ if (DEBUG_logHeavy) DEBUG_HeavyLogInstruction();
+ if (DEBUG_zeroProtect) {
Bit32u value=0;
if (!mem_readd_checked(SegPhys(cs)+reg_eip,&value)) {
if (value == 0) zero_count++;
diff --git a/src/debug/debug.cpp.orig b/src/debug/debug.cpp.orig
new file mode 100644
index 000000000..7b76d573f
--- /dev/null
+++ b/src/debug/debug.cpp.orig
@@ -0,0 +1,2493 @@
+/*
+ * Copyright (C) 2002-2011 The DOSBox Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include "dosbox.h"
+#if C_DEBUG
+
+#include <string.h>
+#include <list>
+#include <ctype.h>
+#include <fstream>
+#include <iomanip>
+#include <string>
+#include <sstream>
+using namespace std;
+
+#include "debug.h"
+#include "cross.h" //snprintf
+#include "cpu.h"
+#include "video.h"
+#include "pic.h"
+#include "mapper.h"
+#include "cpu.h"
+#include "callback.h"
+#include "inout.h"
+#include "mixer.h"
+#include "timer.h"
+#include "paging.h"
+#include "support.h"
+#include "shell.h"
+#include "programs.h"
+#include "debug_inc.h"
+#include "../cpu/lazyflags.h"
+#include "keyboard.h"
+#include "setup.h"
+
+#ifdef WIN32
+void WIN32_Console();
+#else
+#include <termios.h>
+#include <unistd.h>
+static struct termios consolesettings;
+#endif
+int old_cursor_state;
+
+// Forwards
+static void DrawCode(void);
+static void DEBUG_RaiseTimerIrq(void);
+static void SaveMemory(Bitu seg, Bitu ofs1, Bit32u num);
+static void SaveMemoryBin(Bitu seg, Bitu ofs1, Bit32u num);
+static void LogMCBS(void);
+static void LogGDT(void);
+static void LogLDT(void);
+static void LogIDT(void);
+static void LogPages(char* selname);
+static void LogCPUInfo(void);
+static void OutputVecTable(char* filename);
+static void DrawVariables(void);
+
+char* AnalyzeInstruction(char* inst, bool saveSelector);
+Bit32u GetHexValue(char* str, char*& hex);
+
+#if 0
+class DebugPageHandler : public PageHandler {
+public:
+ Bitu readb(PhysPt /*addr*/) {
+ }
+ Bitu readw(PhysPt /*addr*/) {
+ }
+ Bitu readd(PhysPt /*addr*/) {
+ }
+ void writeb(PhysPt /*addr*/,Bitu /*val*/) {
+ }
+ void writew(PhysPt /*addr*/,Bitu /*val*/) {
+ }
+ void writed(PhysPt /*addr*/,Bitu /*val*/) {
+ }
+};
+#endif
+
+
+class DEBUG;
+
+DEBUG* pDebugcom = 0;
+bool exitLoop = false;
+
+
+// Heavy Debugging Vars for logging
+#if C_HEAVY_DEBUG
+static ofstream cpuLogFile;
+static bool cpuLog = false;
+static int cpuLogCounter = 0;
+static int cpuLogType = 1; // log detail
+static bool zeroProtect = false;
+bool logHeavy = false;
+#endif
+
+
+
+static struct {
+ Bit32u eax,ebx,ecx,edx,esi,edi,ebp,esp,eip;
+} oldregs;
+
+static char curSelectorName[3] = { 0,0,0 };
+
+static Segment oldsegs[6];
+static Bitu oldflags,oldcpucpl;
+DBGBlock dbg;
+Bitu cycle_count;
+static bool debugging;
+
+
+static void SetColor(Bitu test) {
+ if (test) {
+ if (has_colors()) { wattrset(dbg.win_reg,COLOR_PAIR(PAIR_BYELLOW_BLACK));}
+ } else {
+ if (has_colors()) { wattrset(dbg.win_reg,0);}
+ }
+}
+
+#define MAXCMDLEN 254
+struct SCodeViewData {
+ int cursorPos;
+ Bit16u firstInstSize;
+ Bit16u useCS;
+ Bit32u useEIPlast, useEIPmid;
+ Bit32u useEIP;
+ Bit16u cursorSeg;
+ Bit32u cursorOfs;
+ bool ovrMode;
+ char inputStr[MAXCMDLEN+1];
+ char suspInputStr[MAXCMDLEN+1];
+ int inputPos;
+} codeViewData;
+
+static Bit16u dataSeg;
+static Bit32u dataOfs;
+static bool showExtend = true;
+
+static void ClearInputLine(void) {
+ codeViewData.inputStr[0] = 0;
+ codeViewData.inputPos = 0;
+}
+
+// History stuff
+#define MAX_HIST_BUFFER 50
+static list<string> histBuff;
+static list<string>::iterator histBuffPos = histBuff.end();
+
+/***********/
+/* Helpers */
+/***********/
+
+Bit32u PhysMakeProt(Bit16u selector, Bit32u offset)
+{
+ Descriptor desc;
+ if (cpu.gdt.GetDescriptor(selector,desc)) return desc.GetBase()+offset;
+ return 0;
+};
+
+Bit32u GetAddress(Bit16u seg, Bit32u offset)
+{
+ if (seg==SegValue(cs)) return SegPhys(cs)+offset;
+ if (cpu.pmode && !(reg_flags & FLAG_VM)) {
+ Descriptor desc;
+ if (cpu.gdt.GetDescriptor(seg,desc)) return PhysMakeProt(seg,offset);
+ }
+ return (seg<<4)+offset;
+}
+
+static char empty_sel[] = { ' ',' ',0 };
+
+bool GetDescriptorInfo(char* selname, char* out1, char* out2)
+{
+ Bitu sel;
+ Descriptor desc;
+
+ if (strstr(selname,"cs") || strstr(selname,"CS")) sel = SegValue(cs);
+ else if (strstr(selname,"ds") || strstr(selname,"DS")) sel = SegValue(ds);
+ else if (strstr(selname,"es") || strstr(selname,"ES")) sel = SegValue(es);
+ else if (strstr(selname,"fs") || strstr(selname,"FS")) sel = SegValue(fs);
+ else if (strstr(selname,"gs") || strstr(selname,"GS")) sel = SegValue(gs);
+ else if (strstr(selname,"ss") || strstr(selname,"SS")) sel = SegValue(ss);
+ else {
+ sel = GetHexValue(selname,selname);
+ if (*selname==0) selname=empty_sel;
+ }
+ if (cpu.gdt.GetDescriptor(sel,desc)) {
+ switch (desc.Type()) {
+ case DESC_TASK_GATE:
+ sprintf(out1,"%s: s:%08X type:%02X p",selname,desc.GetSelector(),desc.saved.gate.type);
+ sprintf(out2," TaskGate dpl : %01X %1X",desc.saved.gate.dpl,desc.saved.gate.p);
+ return true;
+ case DESC_LDT:
+ case DESC_286_TSS_A:
+ case DESC_286_TSS_B:
+ case DESC_386_TSS_A:
+ case DESC_386_TSS_B:
+ sprintf(out1,"%s: b:%08X type:%02X pag",selname,desc.GetBase(),desc.saved.seg.type);
+ sprintf(out2," l:%08X dpl : %01X %1X%1X%1X",desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.g);
+ return true;
+ case DESC_286_CALL_GATE:
+ case DESC_386_CALL_GATE:
+ sprintf(out1,"%s: s:%08X type:%02X p params: %02X",selname,desc.GetSelector(),desc.saved.gate.type,desc.saved.gate.paramcount);
+ sprintf(out2," o:%08X dpl : %01X %1X",desc.GetOffset(),desc.saved.gate.dpl,desc.saved.gate.p);
+ return true;
+ case DESC_286_INT_GATE:
+ case DESC_286_TRAP_GATE:
+ case DESC_386_INT_GATE:
+ case DESC_386_TRAP_GATE:
+ sprintf(out1,"%s: s:%08X type:%02X p",selname,desc.GetSelector(),desc.saved.gate.type);
+ sprintf(out2," o:%08X dpl : %01X %1X",desc.GetOffset(),desc.saved.gate.dpl,desc.saved.gate.p);
+ return true;
+ }
+ sprintf(out1,"%s: b:%08X type:%02X parbg",selname,desc.GetBase(),desc.saved.seg.type);
+ sprintf(out2," l:%08X dpl : %01X %1X%1X%1X%1X%1X",desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.r,desc.saved.seg.big,desc.saved.seg.g);
+ return true;
+ } else {
+ strcpy(out1," ");
+ strcpy(out2," ");
+ }
+ return false;
+};
+
+/********************/
+/* DebugVar stuff */
+/********************/
+
+class CDebugVar
+{
+public:
+ CDebugVar(char* _name, PhysPt _adr) { adr=_adr; safe_strncpy(name,_name,16); };
+
+ char* GetName(void) { return name; };
+ PhysPt GetAdr (void) { return adr; };
+
+private:
+ PhysPt adr;
+ char name[16];
+
+public:
+ static void InsertVariable (char* name, PhysPt adr);
+ static CDebugVar* FindVar (PhysPt adr);
+ static void DeleteAll ();
+ static bool SaveVars (char* name);
+ static bool LoadVars (char* name);
+
+ static std::list<CDebugVar*> varList;
+};
+
+std::list<CDebugVar*> CDebugVar::varList;
+
+
+/********************/
+/* Breakpoint stuff */
+/********************/
+
+bool skipFirstInstruction = false;
+
+enum EBreakpoint { BKPNT_UNKNOWN, BKPNT_PHYSICAL, BKPNT_INTERRUPT, BKPNT_MEMORY, BKPNT_MEMORY_PROT, BKPNT_MEMORY_LINEAR };
+
+#define BPINT_ALL 0x100
+
+class CBreakpoint
+{
+public:
+
+ CBreakpoint(void);
+ void SetAddress (Bit16u seg, Bit32u off) { location = GetAddress(seg,off); type = BKPNT_PHYSICAL; segment = seg; offset = off; };
+ void SetAddress (PhysPt adr) { location = adr; type = BKPNT_PHYSICAL; };
+ void SetInt (Bit8u _intNr, Bit16u ah) { intNr = _intNr, ahValue = ah; type = BKPNT_INTERRUPT; };
+ void SetOnce (bool _once) { once = _once; };
+ void SetType (EBreakpoint _type) { type = _type; };
+ void SetValue (Bit8u value) { ahValue = value; };
+
+ bool IsActive (void) { return active; };
+ void Activate (bool _active);
+
+ EBreakpoint GetType (void) { return type; };
+ bool GetOnce (void) { return once; };
+ PhysPt GetLocation (void) { if (GetType()!=BKPNT_INTERRUPT) return location; else return 0; };
+ Bit16u GetSegment (void) { return segment; };
+ Bit32u GetOffset (void) { return offset; };
+ Bit8u GetIntNr (void) { if (GetType()==BKPNT_INTERRUPT) return intNr; else return 0; };
+ Bit16u GetValue (void) { if (GetType()!=BKPNT_PHYSICAL) return ahValue; else return 0; };
+
+ // statics
+ static CBreakpoint* AddBreakpoint (Bit16u seg, Bit32u off, bool once);
+ static CBreakpoint* AddIntBreakpoint (Bit8u intNum, Bit16u ah, bool once);
+ static CBreakpoint* AddMemBreakpoint (Bit16u seg, Bit32u off);
+ static void ActivateBreakpoints (PhysPt adr, bool activate);
+ static bool CheckBreakpoint (PhysPt adr);
+ static bool CheckBreakpoint (Bitu seg, Bitu off);
+ static bool CheckIntBreakpoint (PhysPt adr, Bit8u intNr, Bit16u ahValue);
+ static bool IsBreakpoint (PhysPt where);
+ static bool IsBreakpointDrawn (PhysPt where);
+ static bool DeleteBreakpoint (PhysPt where);
+ static bool DeleteByIndex (Bit16u index);
+ static void DeleteAll (void);
+ static void ShowList (void);
+
+
+private:
+ EBreakpoint type;
+ // Physical
+ PhysPt location;
+ Bit8u oldData;
+ Bit16u segment;
+ Bit32u offset;
+ // Int
+ Bit8u intNr;
+ Bit16u ahValue;
+ // Shared
+ bool active;
+ bool once;
+
+ static std::list<CBreakpoint*> BPoints;
+public:
+ static CBreakpoint* ignoreOnce;
+};
+
+CBreakpoint::CBreakpoint(void):
+location(0),
+active(false),once(false),
+segment(0),offset(0),intNr(0),ahValue(0),
+type(BKPNT_UNKNOWN) { };
+
+void CBreakpoint::Activate(bool _active)
+{
+#if !C_HEAVY_DEBUG
+ if (GetType()==BKPNT_PHYSICAL) {
+ if (_active) {
+ // Set 0xCC and save old value
+ Bit8u data = mem_readb(location);
+ if (data!=0xCC) {
+ oldData = data;
+ mem_writeb(location,0xCC);
+ };
+ } else {
+ // Remove 0xCC and set old value
+ if (mem_readb (location)==0xCC) {
+ mem_writeb(location,oldData);
+ };
+ }
+ }
+#endif
+ active = _active;
+};
+
+// Statics
+std::list<CBreakpoint*> CBreakpoint::BPoints;
+CBreakpoint* CBreakpoint::ignoreOnce = 0;
+Bitu ignoreAddressOnce = 0;
+
+CBreakpoint* CBreakpoint::AddBreakpoint(Bit16u seg, Bit32u off, bool once)
+{
+ CBreakpoint* bp = new CBreakpoint();
+ bp->SetAddress (seg,off);
+ bp->SetOnce (once);
+ BPoints.push_front (bp);
+ return bp;
+};
+
+CBreakpoint* CBreakpoint::AddIntBreakpoint(Bit8u intNum, Bit16u ah, bool once)
+{
+ CBreakpoint* bp = new CBreakpoint();
+ bp->SetInt (intNum,ah);
+ bp->SetOnce (once);
+ BPoints.push_front (bp);
+ return bp;
+};
+
+CBreakpoint* CBreakpoint::AddMemBreakpoint(Bit16u seg, Bit32u off)
+{
+ CBreakpoint* bp = new CBreakpoint();
+ bp->SetAddress (seg,off);
+ bp->SetOnce (false);
+ bp->SetType (BKPNT_MEMORY);
+ BPoints.push_front (bp);
+ return bp;
+};
+
+void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool activate)
+{
+ // activate all breakpoints
+ std::list<CBreakpoint*>::iterator i;
+ CBreakpoint* bp;
+ for(i=BPoints.begin(); i != BPoints.end(); i++) {
+ bp = (*i);
+ // Do not activate, when bp is an actual address
+ if (activate && (bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==adr)) {
+ // Do not activate :)
+ continue;
+ }
+ bp->Activate(activate);
+ };
+};
+
+bool CBreakpoint::CheckBreakpoint(Bitu seg, Bitu off)
+// Checks if breakpoint is valid and should stop execution
+{
+ if ((ignoreAddressOnce!=0) && (GetAddress(seg,off)==ignoreAddressOnce)) {
+ ignoreAddressOnce = 0;
+ return false;
+ } else
+ ignoreAddressOnce = 0;
+
+ // Search matching breakpoint
+ std::list<CBreakpoint*>::iterator i;
+ CBreakpoint* bp;
+ for(i=BPoints.begin(); i != BPoints.end(); i++) {
+ bp = (*i);
+ if ((bp->GetType()==BKPNT_PHYSICAL) && bp->IsActive() && (bp->GetSegment()==seg) && (bp->GetOffset()==off)) {
+ // Ignore Once ?
+ if (ignoreOnce==bp) {
+ ignoreOnce=0;
+ bp->Activate(true);
+ return false;
+ };
+ // Found,
+ if (bp->GetOnce()) {
+ // delete it, if it should only be used once
+ (BPoints.erase)(i);
+ bp->Activate(false);
+ delete bp;
+ } else {
+ ignoreOnce = bp;
+ };
+ return true;
+ }
+#if C_HEAVY_DEBUG
+ // Memory breakpoint support
+ else if (bp->IsActive()) {
+ if ((bp->GetType()==BKPNT_MEMORY) || (bp->GetType()==BKPNT_MEMORY_PROT) || (bp->GetType()==BKPNT_MEMORY_LINEAR)) {
+ // Watch Protected Mode Memoryonly in pmode
+ if (bp->GetType()==BKPNT_MEMORY_PROT) {
+ // Check if pmode is active
+ if (!cpu.pmode) return false;
+ // Check if descriptor is valid
+ Descriptor desc;
+ if (!cpu.gdt.GetDescriptor(bp->GetSegment(),desc)) return false;
+ if (desc.GetLimit()==0) return false;
+ }
+
+ Bitu address;
+ if (bp->GetType()==BKPNT_MEMORY_LINEAR) address = bp->GetOffset();
+ else address = GetAddress(bp->GetSegment(),bp->GetOffset());
+ Bit8u value=0;
+ if (mem_readb_checked(address,&value)) return false;
+ if (bp->GetValue() != value) {
+ // Yup, memory value changed
+ DEBUG_ShowMsg("DEBUG: Memory breakpoint %s: %04X:%04X - %02X -> %02X\n",(bp->GetType()==BKPNT_MEMORY_PROT)?"(Prot)":"",bp->GetSegment(),bp->GetOffset(),bp->GetValue(),value);
+ bp->SetValue(value);
+ return true;
+ };
+ }
+ };
+#endif
+ };
+ return false;
+};
+
+bool CBreakpoint::CheckIntBreakpoint(PhysPt adr, Bit8u intNr, Bit16u ahValue)
+// Checks if interrupt breakpoint is valid and should stop execution
+{
+ if ((ignoreAddressOnce!=0) && (adr==ignoreAddressOnce)) {
+ ignoreAddressOnce = 0;
+ return false;
+ } else
+ ignoreAddressOnce = 0;
+
+ // Search matching breakpoint
+ std::list<CBreakpoint*>::iterator i;
+ CBreakpoint* bp;
+ for(i=BPoints.begin(); i != BPoints.end(); i++) {
+ bp = (*i);
+ if ((bp->GetType()==BKPNT_INTERRUPT) && bp->IsActive() && (bp->GetIntNr()==intNr)) {
+ if ((bp->GetValue()==BPINT_ALL) || (bp->GetValue()==ahValue)) {
+ // Ignore it once ?
+ if (ignoreOnce==bp) {
+ ignoreOnce=0;
+ bp->Activate(true);
+ return false;
+ };
+ // Found
+ if (bp->GetOnce()) {
+ // delete it, if it should only be used once
+ (BPoints.erase)(i);
+ bp->Activate(false);
+ delete bp;
+ } else {
+ ignoreOnce = bp;
+ }
+ return true;
+ }
+ };
+ };
+ return false;
+};
+
+void CBreakpoint::DeleteAll()
+{
+ std::list<CBreakpoint*>::iterator i;
+ CBreakpoint* bp;
+ for(i=BPoints.begin(); i != BPoints.end(); i++) {
+ bp = (*i);
+ bp->Activate(false);
+ delete bp;
+ };
+ (BPoints.clear)();
+};
+
+
+bool CBreakpoint::DeleteByIndex(Bit16u index)
+{
+ // Search matching breakpoint
+ int nr = 0;
+ std::list<CBreakpoint*>::iterator i;
+ CBreakpoint* bp;
+ for(i=BPoints.begin(); i != BPoints.end(); i++) {
+ if (nr==index) {
+ bp = (*i);
+ (BPoints.erase)(i);
+ bp->Activate(false);
+ delete bp;
+ return true;
+ }
+ nr++;
+ };
+ return false;
+};
+
+bool CBreakpoint::DeleteBreakpoint(PhysPt where)
+{
+ // Search matching breakpoint
+ std::list<CBreakpoint*>::iterator i;
+ CBreakpoint* bp;
+ for(i=BPoints.begin(); i != BPoints.end(); i++) {
+ bp = (*i);
+ if ((bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==where)) {
+ (BPoints.erase)(i);
+ bp->Activate(false);
+ delete bp;
+ return true;
+ }
+ };
+ return false;
+};
+
+bool CBreakpoint::IsBreakpoint(PhysPt adr)
+// is there a breakpoint at address ?
+{
+ // Search matching breakpoint
+ std::list<CBreakpoint*>::iterator i;
+ CBreakpoint* bp;
+ for(i=BPoints.begin(); i != BPoints.end(); i++) {
+ bp = (*i);
+ if ((bp->GetType()==BKPNT_PHYSICAL) && (bp->GetSegment()==adr)) {
+ return true;
+ };
+ if ((bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==adr)) {
+ return true;
+ };
+ };
+ return false;
+};
+
+bool CBreakpoint::IsBreakpointDrawn(PhysPt adr)
+// valid breakpoint, that should be drawn ?
+{
+ // Search matching breakpoint
+ std::list<CBreakpoint*>::iterator i;
+ CBreakpoint* bp;
+ for(i=BPoints.begin(); i != BPoints.end(); i++) {
+ bp = (*i);
+ if ((bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==adr)) {
+ // Only draw, if breakpoint is not only once,
+ return !bp->GetOnce();
+ };
+ };
+ return false;
+};
+
+void CBreakpoint::ShowList(void)
+{
+ // iterate list
+ int nr = 0;
+ std::list<CBreakpoint*>::iterator i;
+ for(i=BPoints.begin(); i != BPoints.end(); i++) {
+ CBreakpoint* bp = (*i);
+ if (bp->GetType()==BKPNT_PHYSICAL) {
+ DEBUG_ShowMsg("%02X. BP %04X:%04X\n",nr,bp->GetSegment(),bp->GetOffset());
+ } else if (bp->GetType()==BKPNT_INTERRUPT) {
+ if (bp->GetValue()==BPINT_ALL) DEBUG_ShowMsg("%02X. BPINT %02X\n",nr,bp->GetIntNr());
+ else DEBUG_ShowMsg("%02X. BPINT %02X AH=%02X\n",nr,bp->GetIntNr(),bp->GetValue());
+ } else if (bp->GetType()==BKPNT_MEMORY) {
+ DEBUG_ShowMsg("%02X. BPMEM %04X:%04X (%02X)\n",nr,bp->GetSegment(),bp->GetOffset(),bp->GetValue());
+ } else if (bp->GetType()==BKPNT_MEMORY_PROT) {
+ DEBUG_ShowMsg("%02X. BPPM %04X:%08X (%02X)\n",nr,bp->GetSegment(),bp->GetOffset(),bp->GetValue());
+ } else if (bp->GetType()==BKPNT_MEMORY_LINEAR ) {
+ DEBUG_ShowMsg("%02X. BPLM %08X (%02X)\n",nr,bp->GetOffset(),bp->GetValue());
+ };
+ nr++;
+ }
+};
+
+bool DEBUG_Breakpoint(void)
+{
+ /* First get the phyiscal address and check for a set Breakpoint */
+ if (!CBreakpoint::CheckBreakpoint(SegValue(cs),reg_eip)) return false;
+ // Found. Breakpoint is valid
+ PhysPt where=GetAddress(SegValue(cs),reg_eip);
+ CBreakpoint::ActivateBreakpoints(where,false); // Deactivate all breakpoints
+ return true;
+};
+
+bool DEBUG_IntBreakpoint(Bit8u intNum)
+{
+ /* First get the phyiscal address and check for a set Breakpoint */
+ PhysPt where=GetAddress(SegValue(cs),reg_eip);
+ if (!CBreakpoint::CheckIntBreakpoint(where,intNum,reg_ah)) return false;
+ // Found. Breakpoint is valid
+ CBreakpoint::ActivateBreakpoints(where,false); // Deactivate all breakpoints
+ return true;
+};
+
+static bool StepOver()
+{
+ exitLoop = false;
+ PhysPt start=GetAddress(SegValue(cs),reg_eip);
+ char dline[200];Bitu size;
+ size=DasmI386(dline, start, reg_eip, cpu.code.big);
+
+ if (strstr(dline,"call") || strstr(dline,"int") || strstr(dline,"loop") || strstr(dline,"rep")) {
+ CBreakpoint::AddBreakpoint (SegValue(cs),reg_eip+size, true);
+ CBreakpoint::ActivateBreakpoints(start, true);
+ debugging=false;
+ DrawCode();
+ DOSBOX_SetNormalLoop();
+ return true;
+ }
+ return false;
+};
+
+bool DEBUG_ExitLoop(void)
+{
+#if C_HEAVY_DEBUG
+ DrawVariables();
+#endif
+
+ if (exitLoop) {
+ exitLoop = false;
+ return true;
+ }
+ return false;
+};
+
+/********************/
+/* Draw windows */
+/********************/
+
+static void DrawData(void) {
+
+ Bit8u ch;
+ Bit32u add = dataOfs;
+ Bit32u address;
+ /* Data win */
+ for (int y=0; y<8; y++) {
+ // Address
+ if (add<0x10000) mvwprintw (dbg.win_data,1+y,0,"%04X:%04X ",dataSeg,add);
+ else mvwprintw (dbg.win_data,1+y,0,"%04X:%08X ",dataSeg,add);
+ for (int x=0; x<16; x++) {
+ address = GetAddress(dataSeg,add);
+ if (mem_readb_checked(address,&ch)) ch=0;
+ mvwprintw (dbg.win_data,1+y,14+3*x,"%02X",ch);
+ if (ch<32 || !isprint(*reinterpret_cast<unsigned char*>(&ch))) ch='.';
+ mvwprintw (dbg.win_data,1+y,63+x,"%c",ch);
+ add++;
+ };
+ }
+ wrefresh(dbg.win_data);
+};
+
+static void DrawRegisters(void) {
+ /* Main Registers */
+ SetColor(reg_eax!=oldregs.eax);oldregs.eax=reg_eax;mvwprintw (dbg.win_reg,0,4,"%08X",reg_eax);
+ SetColor(reg_ebx!=oldregs.ebx);oldregs.ebx=reg_ebx;mvwprintw (dbg.win_reg,1,4,"%08X",reg_ebx);
+ SetColor(reg_ecx!=oldregs.ecx);oldregs.ecx=reg_ecx;mvwprintw (dbg.win_reg,2,4,"%08X",reg_ecx);
+ SetColor(reg_edx!=oldregs.edx);oldregs.edx=reg_edx;mvwprintw (dbg.win_reg,3,4,"%08X",reg_edx);
+
+ SetColor(reg_esi!=oldregs.esi);oldregs.esi=reg_esi;mvwprintw (dbg.win_reg,0,18,"%08X",reg_esi);
+ SetColor(reg_edi!=oldregs.edi);oldregs.edi=reg_edi;mvwprintw (dbg.win_reg,1,18,"%08X",reg_edi);
+ SetColor(reg_ebp!=oldregs.ebp);oldregs.ebp=reg_ebp;mvwprintw (dbg.win_reg,2,18,"%08X",reg_ebp);
+ SetColor(reg_esp!=oldregs.esp);oldregs.esp=reg_esp;mvwprintw (dbg.win_reg,3,18,"%08X",reg_esp);
+ SetColor(reg_eip!=oldregs.eip);oldregs.eip=reg_eip;mvwprintw (dbg.win_reg,1,42,"%08X",reg_eip);
+
+ SetColor(SegValue(ds)!=oldsegs[ds].val);oldsegs[ds].val=SegValue(ds);mvwprintw (dbg.win_reg,0,31,"%04X",SegValue(ds));
+ SetColor(SegValue(es)!=oldsegs[es].val);oldsegs[es].val=SegValue(es);mvwprintw (dbg.win_reg,0,41,"%04X",SegValue(es));
+ SetColor(SegValue(fs)!=oldsegs[fs].val);oldsegs[fs].val=SegValue(fs);mvwprintw (dbg.win_reg,0,51,"%04X",SegValue(fs));
+ SetColor(SegValue(gs)!=oldsegs[gs].val);oldsegs[gs].val=SegValue(gs);mvwprintw (dbg.win_reg,0,61,"%04X",SegValue(gs));
+ SetColor(SegValue(ss)!=oldsegs[ss].val);oldsegs[ss].val=SegValue(ss);mvwprintw (dbg.win_reg,0,71,"%04X",SegValue(ss));
+ SetColor(SegValue(cs)!=oldsegs[cs].val);oldsegs[cs].val=SegValue(cs);mvwprintw (dbg.win_reg,1,31,"%04X",SegValue(cs));
+
+ /*Individual flags*/
+ Bitu changed_flags = reg_flags ^ oldflags;
+ oldflags = reg_flags;
+
+ SetColor(changed_flags&FLAG_CF);
+ mvwprintw (dbg.win_reg,1,53,"%01X",GETFLAG(CF) ? 1:0);
+ SetColor(changed_flags&FLAG_ZF);
+ mvwprintw (dbg.win_reg,1,56,"%01X",GETFLAG(ZF) ? 1:0);
+ SetColor(changed_flags&FLAG_SF);
+ mvwprintw (dbg.win_reg,1,59,"%01X",GETFLAG(SF) ? 1:0);
+ SetColor(changed_flags&FLAG_OF);
+ mvwprintw (dbg.win_reg,1,62,"%01X",GETFLAG(OF) ? 1:0);
+ SetColor(changed_flags&FLAG_AF);
+ mvwprintw (dbg.win_reg,1,65,"%01X",GETFLAG(AF) ? 1:0);
+ SetColor(changed_flags&FLAG_PF);
+ mvwprintw (dbg.win_reg,1,68,"%01X",GETFLAG(PF) ? 1:0);
+
+
+ SetColor(changed_flags&FLAG_DF);
+ mvwprintw (dbg.win_reg,1,71,"%01X",GETFLAG(DF) ? 1:0);
+ SetColor(changed_flags&FLAG_IF);
+ mvwprintw (dbg.win_reg,1,74,"%01X",GETFLAG(IF) ? 1:0);
+ SetColor(changed_flags&FLAG_TF);
+ mvwprintw (dbg.win_reg,1,77,"%01X",GETFLAG(TF) ? 1:0);
+
+ SetColor(changed_flags&FLAG_IOPL);
+ mvwprintw (dbg.win_reg,2,72,"%01X",GETFLAG(IOPL)>>12);
+
+
+ SetColor(cpu.cpl ^ oldcpucpl);
+ mvwprintw (dbg.win_reg,2,78,"%01X",cpu.cpl);
+ oldcpucpl=cpu.cpl;
+
+ if (cpu.pmode) {
+ if (reg_flags & FLAG_VM) mvwprintw(dbg.win_reg,0,76,"VM86");
+ else if (cpu.code.big) mvwprintw(dbg.win_reg,0,76,"Pr32");
+ else mvwprintw(dbg.win_reg,0,76,"Pr16");
+ } else
+ mvwprintw(dbg.win_reg,0,76,"Real");
+
+ // Selector info, if available
+ if ((cpu.pmode) && curSelectorName[0]) {
+ char out1[200], out2[200];
+ GetDescriptorInfo(curSelectorName,out1,out2);
+ mvwprintw(dbg.win_reg,2,28,out1);
+ mvwprintw(dbg.win_reg,3,28,out2);
+ }
+
+ wattrset(dbg.win_reg,0);
+ mvwprintw(dbg.win_reg,3,60,"%u ",cycle_count);
+ wrefresh(dbg.win_reg);
+};
+
+static void DrawCode(void) {
+ bool saveSel;
+ Bit32u disEIP = codeViewData.useEIP;
+ PhysPt start = GetAddress(codeViewData.useCS,codeViewData.useEIP);
+ char dline[200];Bitu size;Bitu c;
+ static char line20[21] = " ";
+
+ for (int i=0;i<10;i++) {
+ saveSel = false;
+ if (has_colors()) {
+ if ((codeViewData.useCS==SegValue(cs)) && (disEIP == reg_eip)) {
+ wattrset(dbg.win_code,COLOR_PAIR(PAIR_GREEN_BLACK));
+ if (codeViewData.cursorPos==-1) {
+ codeViewData.cursorPos = i; // Set Cursor
+ }
+ if (i == codeViewData.cursorPos) {
+ codeViewData.cursorSeg = SegValue(cs);
+ codeViewData.cursorOfs = disEIP;
+ }
+ saveSel = (i == codeViewData.cursorPos);
+ } else if (i == codeViewData.cursorPos) {
+ wattrset(dbg.win_code,COLOR_PAIR(PAIR_BLACK_GREY));
+ codeViewData.cursorSeg = codeViewData.useCS;
+ codeViewData.cursorOfs = disEIP;
+ saveSel = true;
+ } else if (CBreakpoint::IsBreakpointDrawn(start)) {
+ wattrset(dbg.win_code,COLOR_PAIR(PAIR_GREY_RED));
+ } else {
+ wattrset(dbg.win_code,0);
+ }
+ }
+
+
+ Bitu drawsize=size=DasmI386(dline, start, disEIP, cpu.code.big);
+ bool toolarge = false;
+ mvwprintw(dbg.win_code,i,0,"%04X:%04X ",codeViewData.useCS,disEIP);
+
+ if (drawsize>10) { toolarge = true; drawsize = 9; };
+ for (c=0;c<drawsize;c++) {
+ Bit8u value;
+ if (mem_readb_checked(start+c,&value)) value=0;
+ wprintw(dbg.win_code,"%02X",value);
+ }
+ if (toolarge) { waddstr(dbg.win_code,".."); drawsize++; };
+ // Spacepad up to 20 characters
+ if(drawsize && (drawsize < 11)) {
+ line20[20 - drawsize*2] = 0;
+ waddstr(dbg.win_code,line20);
+ line20[20 - drawsize*2] = ' ';
+ } else waddstr(dbg.win_code,line20);
+
+ char empty_res[] = { 0 };
+ char* res = empty_res;
+ if (showExtend) res = AnalyzeInstruction(dline, saveSel);
+ // Spacepad it up to 28 characters
+ size_t dline_len = strlen(dline);
+ if(dline_len < 28) for (c = dline_len; c < 28;c++) dline[c] = ' '; dline[28] = 0;
+ waddstr(dbg.win_code,dline);
+ // Spacepad it up to 20 characters
+ size_t res_len = strlen(res);
+ if(res_len && (res_len < 21)) {
+ waddstr(dbg.win_code,res);
+ line20[20-res_len] = 0;
+ waddstr(dbg.win_code,line20);
+ line20[20-res_len] = ' ';
+ } else waddstr(dbg.win_code,line20);
+
+ start+=size;
+ disEIP+=size;
+
+ if (i==0) codeViewData.firstInstSize = size;
+ if (i==4) codeViewData.useEIPmid = disEIP;
+ }
+
+ codeViewData.useEIPlast = disEIP;
+
+ wattrset(dbg.win_code,0);
+ if (!debugging) {
+ mvwprintw(dbg.win_code,10,0,"%s","(Running)");
+ wclrtoeol(dbg.win_code);
+ } else {
+ //TODO long lines
+ char* dispPtr = codeViewData.inputStr;
+ char* curPtr = &codeViewData.inputStr[codeViewData.inputPos];
+ mvwprintw(dbg.win_code,10,0,"%c-> %s%c",
+ (codeViewData.ovrMode?'O':'I'),dispPtr,(*curPtr?' ':'_'));
+ wclrtoeol(dbg.win_code); // not correct in pdcurses if full line
+ if (*curPtr) {
+ mvwchgat(dbg.win_code,10,(curPtr-dispPtr+4),1,0,(PAIR_BLACK_GREY),NULL);
+ }
+ }
+
+ wrefresh(dbg.win_code);
+}
+
+static void SetCodeWinStart()
+{
+ if ((SegValue(cs)==codeViewData.useCS) && (reg_eip>=codeViewData.useEIP) && (reg_eip<=codeViewData.useEIPlast)) {
+ // in valid window - scroll ?
+ if (reg_eip>=codeViewData.useEIPmid) codeViewData.useEIP += codeViewData.firstInstSize;
+
+ } else {
+ // totally out of range.
+ codeViewData.useCS = SegValue(cs);
+ codeViewData.useEIP = reg_eip;
+ }
+ codeViewData.cursorPos = -1; // Recalc Cursor position
+};
+
+/********************/
+/* User input */
+/********************/
+
+Bit32u GetHexValue(char* str, char*& hex)
+{
+ Bit32u value = 0;
+ Bit32u regval = 0;
+ hex = str;
+ while (*hex==' ') hex++;
+ if (strstr(hex,"EAX")==hex) { hex+=3; regval = reg_eax; };
+ if (strstr(hex,"EBX")==hex) { hex+=3; regval = reg_ebx; };
+ if (strstr(hex,"ECX")==hex) { hex+=3; regval = reg_ecx; };
+ if (strstr(hex,"EDX")==hex) { hex+=3; regval = reg_edx; };
+ if (strstr(hex,"ESI")==hex) { hex+=3; regval = reg_esi; };
+ if (strstr(hex,"EDI")==hex) { hex+=3; regval = reg_edi; };
+ if (strstr(hex,"EBP")==hex) { hex+=3; regval = reg_ebp; };
+ if (strstr(hex,"ESP")==hex) { hex+=3; regval = reg_esp; };
+ if (strstr(hex,"EIP")==hex) { hex+=3; regval = reg_eip; };
+ if (strstr(hex,"AX")==hex) { hex+=2; regval = reg_ax; };
+ if (strstr(hex,"BX")==hex) { hex+=2; regval = reg_bx; };
+ if (strstr(hex,"CX")==hex) { hex+=2; regval = reg_cx; };
+ if (strstr(hex,"DX")==hex) { hex+=2; regval = reg_dx; };
+ if (strstr(hex,"SI")==hex) { hex+=2; regval = reg_si; };
+ if (strstr(hex,"DI")==hex) { hex+=2; regval = reg_di; };
+ if (strstr(hex,"BP")==hex) { hex+=2; regval = reg_bp; };
+ if (strstr(hex,"SP")==hex) { hex+=2; regval = reg_sp; };
+ if (strstr(hex,"IP")==hex) { hex+=2; regval = reg_ip; };
+ if (strstr(hex,"CS")==hex) { hex+=2; regval = SegValue(cs); };
+ if (strstr(hex,"DS")==hex) { hex+=2; regval = SegValue(ds); };
+ if (strstr(hex,"ES")==hex) { hex+=2; regval = SegValue(es); };
+ if (strstr(hex,"FS")==hex) { hex+=2; regval = SegValue(fs); };
+ if (strstr(hex,"GS")==hex) { hex+=2; regval = SegValue(gs); };
+ if (strstr(hex,"SS")==hex) { hex+=2; regval = SegValue(ss); };
+
+ while (*hex) {
+ if ((*hex>='0') && (*hex<='9')) value = (value<<4)+*hex-'0';
+ else if ((*hex>='A') && (*hex<='F')) value = (value<<4)+*hex-'A'+10;
+ else {
+ if(*hex == '+') {hex++;return regval + value + GetHexValue(hex,hex); };
+ if(*hex == '-') {hex++;return regval + value - GetHexValue(hex,hex); };
+ break; // No valid char
+ }
+ hex++;
+ };
+ return regval + value;
+};
+
+bool ChangeRegister(char* str)
+{
+ char* hex = str;
+ while (*hex==' ') hex++;
+ if (strstr(hex,"EAX")==hex) { hex+=3; reg_eax = GetHexValue(hex,hex); } else
+ if (strstr(hex,"EBX")==hex) { hex+=3; reg_ebx = GetHexValue(hex,hex); } else
+ if (strstr(hex,"ECX")==hex) { hex+=3; reg_ecx = GetHexValue(hex,hex); } else
+ if (strstr(hex,"EDX")==hex) { hex+=3; reg_edx = GetHexValue(hex,hex); } else
+ if (strstr(hex,"ESI")==hex) { hex+=3; reg_esi = GetHexValue(hex,hex); } else
+ if (strstr(hex,"EDI")==hex) { hex+=3; reg_edi = GetHexValue(hex,hex); } else
+ if (strstr(hex,"EBP")==hex) { hex+=3; reg_ebp = GetHexValue(hex,hex); } else
+ if (strstr(hex,"ESP")==hex) { hex+=3; reg_esp = GetHexValue(hex,hex); } else
+ if (strstr(hex,"EIP")==hex) { hex+=3; reg_eip = GetHexValue(hex,hex); } else
+ if (strstr(hex,"AX")==hex) { hex+=2; reg_ax = (Bit16u)GetHexValue(hex,hex); } else
+ if (strstr(hex,"BX")==hex) { hex+=2; reg_bx = (Bit16u)GetHexValue(hex,hex); } else
+ if (strstr(hex,"CX")==hex) { hex+=2; reg_cx = (Bit16u)GetHexValue(hex,hex); } else
+ if (strstr(hex,"DX")==hex) { hex+=2; reg_dx = (Bit16u)GetHexValue(hex,hex); } else
+ if (strstr(hex,"SI")==hex) { hex+=2; reg_si = (Bit16u)GetHexValue(hex,hex); } else
+ if (strstr(hex,"DI")==hex) { hex+=2; reg_di = (Bit16u)GetHexValue(hex,hex); } else
+ if (strstr(hex,"BP")==hex) { hex+=2; reg_bp = (Bit16u)GetHexValue(hex,hex); } else
+ if (strstr(hex,"SP")==hex) { hex+=2; reg_sp = (Bit16u)GetHexValue(hex,hex); } else
+ if (strstr(hex,"IP")==hex) { hex+=2; reg_ip = (Bit16u)GetHexValue(hex,hex); } else
+ if (strstr(hex,"CS")==hex) { hex+=2; SegSet16(cs,(Bit16u)GetHexValue(hex,hex)); } else
+ if (strstr(hex,"DS")==hex) { hex+=2; SegSet16(ds,(Bit16u)GetHexValue(hex,hex)); } else
+ if (strstr(hex,"ES")==hex) { hex+=2; SegSet16(es,(Bit16u)GetHexValue(hex,hex)); } else
+ if (strstr(hex,"FS")==hex) { hex+=2; SegSet16(fs,(Bit16u)GetHexValue(hex,hex)); } else
+ if (strstr(hex,"GS")==hex) { hex+=2; SegSet16(gs,(Bit16u)GetHexValue(hex,hex)); } else
+ if (strstr(hex,"SS")==hex) { hex+=2; SegSet16(ss,(Bit16u)GetHexValue(hex,hex)); } else
+ if (strstr(hex,"AF")==hex) { hex+=2; SETFLAGBIT(AF,GetHexValue(hex,hex)); } else
+ if (strstr(hex,"CF")==hex) { hex+=2; SETFLAGBIT(CF,GetHexValue(hex,hex)); } else
+ if (strstr(hex,"DF")==hex) { hex+=2; SETFLAGBIT(DF,GetHexValue(hex,hex)); } else
+ if (strstr(hex,"IF")==hex) { hex+=2; SETFLAGBIT(IF,GetHexValue(hex,hex)); } else
+ if (strstr(hex,"OF")==hex) { hex+=2; SETFLAGBIT(OF,GetHexValue(hex,hex)); } else
+ if (strstr(hex,"ZF")==hex) { hex+=2; SETFLAGBIT(ZF,GetHexValue(hex,hex)); } else
+ if (strstr(hex,"PF")==hex) { hex+=2; SETFLAGBIT(PF,GetHexValue(hex,hex)); } else
+ if (strstr(hex,"SF")==hex) { hex+=2; SETFLAGBIT(SF,GetHexValue(hex,hex)); } else
+ { return false; };
+ return true;
+};
+
+bool ParseCommand(char* str) {
+ char* found = str;
+ for(char* idx = found;*idx != 0; idx++)
+ *idx = toupper(*idx);
+
+ found = trim(found);
+ string s_found(found);
+ istringstream stream(s_found);
+ string command;
+ stream >> command;
+ string::size_type next = s_found.find_first_not_of(' ',command.size());
+ if(next == string::npos) next = command.size();
+ (s_found.erase)(0,next);
+ found = const_cast<char*>(s_found.c_str());
+
+ if (command == "MEMDUMP") { // Dump memory to file
+ Bit16u seg = (Bit16u)GetHexValue(found,found); found++;
+ Bit32u ofs = GetHexValue(found,found); found++;
+ Bit32u num = GetHexValue(found,found); found++;
+ SaveMemory(seg,ofs,num);
+ return true;
+ };
+
+ if (command == "MEMDUMPBIN") { // Dump memory to file bineary
+ Bit16u seg = (Bit16u)GetHexValue(found,found); found++;
+ Bit32u ofs = GetHexValue(found,found); found++;
+ Bit32u num = GetHexValue(found,found); found++;
+ SaveMemoryBin(seg,ofs,num);
+ return true;
+ };
+
+ if (command == "IV") { // Insert variable
+ Bit16u seg = (Bit16u)GetHexValue(found,found); found++;
+ Bit32u ofs = (Bit16u)GetHexValue(found,found); found++;
+ char name[16];
+ for (int i=0; i<16; i++) {
+ if (found[i] && (found[i]!=' ')) name[i] = found[i];
+ else { name[i] = 0; break; };
+ };
+ name[15] = 0;
+
+ if(!name[0]) return false;
+ DEBUG_ShowMsg("DEBUG: Created debug var %s at %04X:%04X\n",name,seg,ofs);
+ CDebugVar::InsertVariable(name,GetAddress(seg,ofs));
+ return true;
+ };
+
+ if (command == "SV") { // Save variables
+ char name[13];
+ for (int i=0; i<12; i++) {
+ if (found[i] && (found[i]!=' ')) name[i] = found[i];
+ else { name[i] = 0; break; };
+ };
+ name[12] = 0;
+ if(!name[0]) return false;
+ DEBUG_ShowMsg("DEBUG: Variable list save (%s) : %s.\n",name,(CDebugVar::SaveVars(name)?"ok":"failure"));
+ return true;
+ };
+
+ if (command == "LV") { // load variables
+ char name[13];
+ for (int i=0; i<12; i++) {
+ if (found[i] && (found[i]!=' ')) name[i] = found[i];
+ else { name[i] = 0; break; };
+ };
+ name[12] = 0;
+ if(!name[0]) return false;
+ DEBUG_ShowMsg("DEBUG: Variable list load (%s) : %s.\n",name,(CDebugVar::LoadVars(name)?"ok":"failure"));
+ return true;
+ };
+
+ if (command == "SR") { // Set register value
+ DEBUG_ShowMsg("DEBUG: Set Register %s.\n",(ChangeRegister(found)?"success":"failure"));
+ return true;
+ };
+
+ if (command == "SM") { // Set memory with following values
+ Bit16u seg = (Bit16u)GetHexValue(found,found); found++;
+ Bit32u ofs = GetHexValue(found,found); found++;
+ Bit16u count = 0;
+ while (*found) {
+ while (*found==' ') found++;
+ if (*found) {
+ Bit8u value = (Bit8u)GetHexValue(found,found);
+ if(*found) found++;
+ mem_writeb_checked(GetAddress(seg,ofs+count),value);
+ count++;
+ }
+ };
+ DEBUG_ShowMsg("DEBUG: Memory changed.\n");
+ return true;
+ };
+
+ if (command == "BP") { // Add new breakpoint
+ Bit16u seg = (Bit16u)GetHexValue(found,found);found++; // skip ":"
+ Bit32u ofs = GetHexValue(found,found);
+ CBreakpoint::AddBreakpoint(seg,ofs,false);
+ DEBUG_ShowMsg("DEBUG: Set breakpoint at %04X:%04X\n",seg,ofs);
+ return true;
+ };
+
+#if C_HEAVY_DEBUG
+
+ if (command == "BPM") { // Add new breakpoint
+ Bit16u seg = (Bit16u)GetHexValue(found,found);found++; // skip ":"
+ Bit32u ofs = GetHexValue(found,found);
+ CBreakpoint::AddMemBreakpoint(seg,ofs);
+ DEBUG_ShowMsg("DEBUG: Set memory breakpoint at %04X:%04X\n",seg,ofs);
+ return true;
+ };
+
+ if (command == "BPPM") { // Add new breakpoint
+ Bit16u seg = (Bit16u)GetHexValue(found,found);found++; // skip ":"
+ Bit32u ofs = GetHexValue(found,found);
+ CBreakpoint* bp = CBreakpoint::AddMemBreakpoint(seg,ofs);
+ if (bp) {
+ bp->SetType(BKPNT_MEMORY_PROT);
+ DEBUG_ShowMsg("DEBUG: Set prot-mode memory breakpoint at %04X:%08X\n",seg,ofs);
+ }
+ return true;
+ };
+
+ if (command == "BPLM") { // Add new breakpoint
+ Bit32u ofs = GetHexValue(found,found);
+ CBreakpoint* bp = CBreakpoint::AddMemBreakpoint(0,ofs);
+ if (bp) bp->SetType(BKPNT_MEMORY_LINEAR);
+ DEBUG_ShowMsg("DEBUG: Set linear memory breakpoint at %08X\n",ofs);
+ return true;
+ };
+
+#endif
+
+ if (command == "BPINT") { // Add Interrupt Breakpoint
+ Bit8u intNr = (Bit8u)GetHexValue(found,found);
+ bool all = !(*found);found++;
+ Bit8u valAH = (Bit8u)GetHexValue(found,found);
+ if ((valAH==0x00) && (*found=='*' || all)) {
+ CBreakpoint::AddIntBreakpoint(intNr,BPINT_ALL,false);
+ DEBUG_ShowMsg("DEBUG: Set interrupt breakpoint at INT %02X\n",intNr);
+ } else {
+ CBreakpoint::AddIntBreakpoint(intNr,valAH,false);
+ DEBUG_ShowMsg("DEBUG: Set interrupt breakpoint at INT %02X AH=%02X\n",intNr,valAH);
+ }
+ return true;
+ };
+
+ if (command == "BPLIST") {
+ DEBUG_ShowMsg("Breakpoint list:\n");
+ DEBUG_ShowMsg("-------------------------------------------------------------------------\n");
+ CBreakpoint::ShowList();
+ return true;
+ };
+
+ if (command == "BPDEL") { // Delete Breakpoints
+ Bit8u bpNr = (Bit8u)GetHexValue(found,found);
+ if ((bpNr==0x00) && (*found=='*')) { // Delete all
+ CBreakpoint::DeleteAll();
+ DEBUG_ShowMsg("DEBUG: Breakpoints deleted.\n");
+ } else {
+ // delete single breakpoint
+ DEBUG_ShowMsg("DEBUG: Breakpoint deletion %s.\n",(CBreakpoint::DeleteByIndex(bpNr)?"success":"failure"));
+ }
+ return true;
+ };
+
+ if (command == "C") { // Set code overview
+ Bit16u codeSeg = (Bit16u)GetHexValue(found,found); found++;
+ Bit32u codeOfs = GetHexValue(found,found);
+ DEBUG_ShowMsg("DEBUG: Set code overview to %04X:%04X\n",codeSeg,codeOfs);
+ codeViewData.useCS = codeSeg;
+ codeViewData.useEIP = codeOfs;
+ codeViewData.cursorPos = 0;
+ return true;
+ };
+
+ if (command == "D") { // Set data overview
+ dataSeg = (Bit16u)GetHexValue(found,found); found++;
+ dataOfs = GetHexValue(found,found);
+ DEBUG_ShowMsg("DEBUG: Set data overview to %04X:%04X\n",dataSeg,dataOfs);
+ return true;
+ };
+
+#if C_HEAVY_DEBUG
+
+ if (command == "LOG") { // Create Cpu normal log file
+ cpuLogType = 1;
+ command = "logcode";
+ }
+
+ if (command == "LOGS") { // Create Cpu short log file
+ cpuLogType = 0;
+ command = "logcode";
+ }
+
+ if (command == "LOGL") { // Create Cpu long log file
+ cpuLogType = 2;
+ command = "logcode";
+ }
+
+ if (command == "logcode") { //Shared code between all logs
+ DEBUG_ShowMsg("DEBUG: Starting log\n");
+ cpuLogFile.open("LOGCPU.TXT");
+ if (!cpuLogFile.is_open()) {
+ DEBUG_ShowMsg("DEBUG: Logfile couldn't be created.\n");
+ return false;
+ }
+ //Initialize log object
+ cpuLogFile << hex << noshowbase << setfill('0') << uppercase;
+ cpuLog = true;
+ cpuLogCounter = GetHexValue(found,found);
+
+ debugging = false;
+ CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,true);
+ ignoreAddressOnce = SegPhys(cs)+reg_eip;
+ DOSBOX_SetNormalLoop();
+ return true;
+ };
+
+#endif
+
+ if (command == "INTT") { //trace int.
+ Bit8u intNr = (Bit8u)GetHexValue(found,found);
+ DEBUG_ShowMsg("DEBUG: Tracing INT %02X\n",intNr);
+ CPU_HW_Interrupt(intNr);
+ SetCodeWinStart();
+ return true;
+ };
+
+ if (command == "INT") { // start int.
+ Bit8u intNr = (Bit8u)GetHexValue(found,found);
+ DEBUG_ShowMsg("DEBUG: Starting INT %02X\n",intNr);
+ CBreakpoint::AddBreakpoint(SegValue(cs),reg_eip, true);
+ CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip-1,true);
+ debugging = false;
+ DrawCode();
+ DOSBOX_SetNormalLoop();
+ CPU_HW_Interrupt(intNr);
+ return true;
+ };
+
+ if (command == "SELINFO") {
+ while (found[0] == ' ') found++;
+ char out1[200],out2[200];
+ GetDescriptorInfo(found,out1,out2);
+ DEBUG_ShowMsg("SelectorInfo %s:\n%s\n%s\n",found,out1,out2);
+ return true;
+ };
+
+ if (command == "DOS") {
+ stream >> command;
+ if (command == "MCBS") LogMCBS();
+ return true;
+ }
+
+ if (command == "GDT") {LogGDT(); return true;}
+
+ if (command == "LDT") {LogLDT(); return true;}
+
+ if (command == "IDT") {LogIDT(); return true;}
+
+ if (command == "PAGING") {LogPages(found); return true;}
+
+ if (command == "CPU") {LogCPUInfo(); return true;}
+
+ if (command == "INTVEC") {
+ if (found[0] != 0) {
+ OutputVecTable(found);
+ return true;
+ }
+ };
+
+ if (command == "INTHAND") {
+ if (found[0] != 0) {
+ Bit8u intNr = (Bit8u)GetHexValue(found,found);
+ DEBUG_ShowMsg("DEBUG: Set code overview to interrupt handler %X\n",intNr);
+ codeViewData.useCS = mem_readw(intNr*4+2);
+ codeViewData.useEIP = mem_readw(intNr*4);
+ codeViewData.cursorPos = 0;
+ return true;
+ }
+ };
+
+ if(command == "EXTEND") { //Toggle additional data.
+ showExtend = !showExtend;
+ return true;
+ };
+
+ if(command == "TIMERIRQ") { //Start a timer irq
+ DEBUG_RaiseTimerIrq();
+ DEBUG_ShowMsg("Debug: Timer Int started.\n");
+ return true;
+ };
+
+
+#if C_HEAVY_DEBUG
+ if (command == "HEAVYLOG") { // Create Cpu log file
+ logHeavy = !logHeavy;
+ DEBUG_ShowMsg("DEBUG: Heavy cpu logging %s.\n",logHeavy?"on":"off");
+ return true;
+ };
+
+ if (command == "ZEROPROTECT") { //toggle zero protection
+ zeroProtect = !zeroProtect;
+ DEBUG_ShowMsg("DEBUG: Zero code execution protection %s.\n",zeroProtect?"on":"off");
+ return true;
+ };
+
+#endif
+ if (command == "HELP" || command == "?") {
+ DEBUG_ShowMsg("Debugger commands (enter all values in hex or as register):\n");
+ DEBUG_ShowMsg("--------------------------------------------------------------------------\n");
+ DEBUG_ShowMsg("F3/F6 - Previous command in history.\n");
+ DEBUG_ShowMsg("F4/F7 - Next command in history.\n");
+ DEBUG_ShowMsg("F5 - Run.\n");
+ DEBUG_ShowMsg("F9 - Set/Remove breakpoint.\n");
+ DEBUG_ShowMsg("F10/F11 - Step over / trace into instruction.\n");
+ DEBUG_ShowMsg("ALT + D/E/S/X/B - Set data view to DS:SI/ES:DI/SS:SP/DS:DX/ES:BX.\n");
+ DEBUG_ShowMsg("Escape - Clear input line.");
+ DEBUG_ShowMsg("Up/Down - Move code view cursor.\n");
+ DEBUG_ShowMsg("Page Up/Down - Scroll data view.\n");
+ DEBUG_ShowMsg("Home/End - Scroll log messages.\n");
+ DEBUG_ShowMsg("BP [segment]:[offset] - Set breakpoint.\n");
+ DEBUG_ShowMsg("BPINT [intNr] * - Set interrupt breakpoint.\n");
+ DEBUG_ShowMsg("BPINT [intNr] [ah] - Set interrupt breakpoint with ah.\n");
+#if C_HEAVY_DEBUG
+ DEBUG_ShowMsg("BPM [segment]:[offset] - Set memory breakpoint (memory change).\n");
+ DEBUG_ShowMsg("BPPM [selector]:[offset]- Set pmode-memory breakpoint (memory change).\n");
+ DEBUG_ShowMsg("BPLM [linear address] - Set linear memory breakpoint (memory change).\n");
+#endif
+ DEBUG_ShowMsg("BPLIST - List breakpoints.\n");
+ DEBUG_ShowMsg("BPDEL [bpNr] / * - Delete breakpoint nr / all.\n");
+ DEBUG_ShowMsg("C / D [segment]:[offset] - Set code / data view address.\n");
+ DEBUG_ShowMsg("DOS MCBS - Show Memory Control Block chain.\n");
+ DEBUG_ShowMsg("INT [nr] / INTT [nr] - Execute / Trace into interrupt.\n");
+#if C_HEAVY_DEBUG
+ DEBUG_ShowMsg("LOG [num] - Write cpu log file.\n");
+ DEBUG_ShowMsg("LOGS/LOGL [num] - Write short/long cpu log file.\n");
+ DEBUG_ShowMsg("HEAVYLOG - Enable/Disable automatic cpu log when dosbox exits.\n");
+ DEBUG_ShowMsg("ZEROPROTECT - Enable/Disable zero code execution detecion.\n");
+#endif
+ DEBUG_ShowMsg("SR [reg] [value] - Set register value.\n");
+ DEBUG_ShowMsg("SM [seg]:[off] [val] [.]..- Set memory with following values.\n");
+
+ DEBUG_ShowMsg("IV [seg]:[off] [name] - Create var name for memory address.\n");
+ DEBUG_ShowMsg("SV [filename] - Save var list in file.\n");
+ DEBUG_ShowMsg("LV [filename] - Load var list from file.\n");
+
+ DEBUG_ShowMsg("MEMDUMP [seg]:[off] [len] - Write memory to file memdump.txt.\n");
+ DEBUG_ShowMsg("MEMDUMPBIN [s]:[o] [len] - Write memory to file memdump.bin.\n");
+ DEBUG_ShowMsg("SELINFO [segName] - Show selector info.\n");
+
+ DEBUG_ShowMsg("INTVEC [filename] - Writes interrupt vector table to file.\n");
+ DEBUG_ShowMsg("INTHAND [intNum] - Set code view to interrupt handler.\n");
+
+ DEBUG_ShowMsg("CPU - Display CPU status information.\n");
+ DEBUG_ShowMsg("GDT - Lists descriptors of the GDT.\n");
+ DEBUG_ShowMsg("LDT - Lists descriptors of the LDT.\n");
+ DEBUG_ShowMsg("IDT - Lists descriptors of the IDT.\n");
+ DEBUG_ShowMsg("PAGING [page] - Display content of page table.\n");
+ DEBUG_ShowMsg("EXTEND - Toggle additional info.\n");
+ DEBUG_ShowMsg("TIMERIRQ - Run the system timer.\n");
+
+ DEBUG_ShowMsg("HELP - Help\n");
+
+ return true;
+ };
+ return false;
+};
+
+char* AnalyzeInstruction(char* inst, bool saveSelector) {
+ static char result[256];
+
+ char instu[256];
+ char prefix[3];
+ Bit16u seg;
+
+ strcpy(instu,inst);
+ upcase(instu);
+
+ result[0] = 0;
+ char* pos = strchr(instu,'[');
+ if (pos) {
+ // Segment prefix ?
+ if (*(pos-1)==':') {
+ char* segpos = pos-3;
+ prefix[0] = tolower(*segpos);
+ prefix[1] = tolower(*(segpos+1));
+ prefix[2] = 0;
+ seg = (Bit16u)GetHexValue(segpos,segpos);
+ } else {
+ if (strstr(pos,"SP") || strstr(pos,"BP")) {
+ seg = SegValue(ss);
+ strcpy(prefix,"ss");
+ } else {
+ seg = SegValue(ds);
+ strcpy(prefix,"ds");
+ };
+ };
+
+ pos++;
+ Bit32u adr = GetHexValue(pos,pos);
+ while (*pos!=']') {
+ if (*pos=='+') {
+ pos++;
+ adr += GetHexValue(pos,pos);
+ } else if (*pos=='-') {
+ pos++;
+ adr -= GetHexValue(pos,pos);
+ } else
+ pos++;
+ };
+ Bit32u address = GetAddress(seg,adr);
+ if (!(get_tlb_readhandler(address)->flags & PFLAG_INIT)) {
+ static char outmask[] = "%s:[%04X]=%02X";
+
+ if (cpu.pmode) outmask[6] = '8';
+ switch (DasmLastOperandSize()) {
+ case 8 : { Bit8u val = mem_readb(address);
+ outmask[12] = '2';
+ sprintf(result,outmask,prefix,adr,val);
+ } break;
+ case 16: { Bit16u val = mem_readw(address);
+ outmask[12] = '4';
+ sprintf(result,outmask,prefix,adr,val);
+ } break;
+ case 32: { Bit32u val = mem_readd(address);
+ outmask[12] = '8';
+ sprintf(result,outmask,prefix,adr,val);
+ } break;
+ }
+ } else {
+ sprintf(result,"[illegal]");
+ }
+ // Variable found ?
+ CDebugVar* var = CDebugVar::FindVar(address);
+ if (var) {
+ // Replace occurence
+ char* pos1 = strchr(inst,'[');
+ char* pos2 = strchr(inst,']');
+ if (pos1 && pos2) {
+ char temp[256];
+ strcpy(temp,pos2); // save end
+ pos1++; *pos1 = 0; // cut after '['
+ strcat(inst,var->GetName()); // add var name
+ strcat(inst,temp); // add end
+ };
+ };
+ // show descriptor info, if available
+ if ((cpu.pmode) && saveSelector) {
+ strcpy(curSelectorName,prefix);
+ };
+ };
+ // If it is a callback add additional info
+ pos = strstr(inst,"callback");
+ if (pos) {
+ pos += 9;
+ Bitu nr = GetHexValue(pos,pos);
+ const char* descr = CALLBACK_GetDescription(nr);
+ if (descr) {
+ strcat(inst," ("); strcat(inst,descr); strcat(inst,")");
+ }
+ };
+ // Must be a jump
+ if (instu[0] == 'J')
+ {
+ bool jmp = false;
+ switch (instu[1]) {
+ case 'A' : { jmp = (get_CF()?false:true) && (get_ZF()?false:true); // JA
+ } break;
+ case 'B' : { if (instu[2] == 'E') {
+ jmp = (get_CF()?true:false) || (get_ZF()?true:false); // JBE
+ } else {
+ jmp = get_CF()?true:false; // JB
+ }
+ } break;
+ case 'C' : { if (instu[2] == 'X') {
+ jmp = reg_cx == 0; // JCXZ
+ } else {
+ jmp = get_CF()?true:false; // JC
+ }
+ } break;
+ case 'E' : { jmp = get_ZF()?true:false; // JE
+ } break;
+ case 'G' : { if (instu[2] == 'E') {
+ jmp = (get_SF()?true:false)==(get_OF()?true:false); // JGE
+ } else {
+ jmp = (get_ZF()?false:true) && ((get_SF()?true:false)==(get_OF()?true:false)); // JG
+ }
+ } break;
+ case 'L' : { if (instu[2] == 'E') {
+ jmp = (get_ZF()?true:false) || ((get_SF()?true:false)!=(get_OF()?true:false)); // JLE
+ } else {
+ jmp = (get_SF()?true:false)!=(get_OF()?true:false); // JL
+ }
+ } break;
+ case 'M' : { jmp = true; // JMP
+ } break;
+ case 'N' : { switch (instu[2]) {
+ case 'B' :
+ case 'C' : { jmp = get_CF()?false:true; // JNB / JNC
+ } break;
+ case 'E' : { jmp = get_ZF()?false:true; // JNE
+ } break;
+ case 'O' : { jmp = get_OF()?false:true; // JNO
+ } break;
+ case 'P' : { jmp = get_PF()?false:true; // JNP
+ } break;
+ case 'S' : { jmp = get_SF()?false:true; // JNS
+ } break;
+ case 'Z' : { jmp = get_ZF()?false:true; // JNZ
+ } break;
+ }
+ } break;
+ case 'O' : { jmp = get_OF()?true:false; // JO
+ } break;
+ case 'P' : { if (instu[2] == 'O') {
+ jmp = get_PF()?false:true; // JPO
+ } else {
+ jmp = get_SF()?true:false; // JP / JPE
+ }
+ } break;
+ case 'S' : { jmp = get_SF()?true:false; // JS
+ } break;
+ case 'Z' : { jmp = get_ZF()?true:false; // JZ
+ } break;
+ }
+ if (jmp) {
+ pos = strchr(instu,'$');
+ if (pos) {
+ pos = strchr(instu,'+');
+ if (pos) {
+ strcpy(result,"(down)");
+ } else {
+ strcpy(result,"(up)");
+ }
+ }
+ } else {
+ sprintf(result,"(no jmp)");
+ }
+ }
+ return result;
+};
+
+
+Bit32u DEBUG_CheckKeys(void) {
+ Bits ret=0;
+ int key=getch();
+ if (key>0) {
+#if defined(WIN32) && defined(__PDCURSES__)
+ switch (key) {
+ case PADENTER: key=0x0A; break;
+ case PADSLASH: key='/'; break;
+ case PADSTAR: key='*'; break;
+ case PADMINUS: key='-'; break;
+ case PADPLUS: key='+'; break;
+ case ALT_D:
+ if (ungetch('D') != ERR) key=27;
+ break;
+ case ALT_E:
+ if (ungetch('E') != ERR) key=27;
+ break;
+ case ALT_X:
+ if (ungetch('X') != ERR) key=27;
+ break;
+ case ALT_B:
+ if (ungetch('B') != ERR) key=27;
+ break;
+ case ALT_S:
+ if (ungetch('S') != ERR) key=27;
+ break;
+ }
+#endif
+ switch (toupper(key)) {
+ case 27: // escape (a bit slow): Clears line. and processes alt commands.
+ key=getch();
+ if(key < 0) { //Purely escape Clear line
+ ClearInputLine();
+ break;
+ }
+
+ switch(toupper(key)) {
+ case 'D' : // ALT - D: DS:SI
+ dataSeg = SegValue(ds);
+ if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_esi;
+ else dataOfs = reg_si;
+ break;
+ case 'E' : //ALT - E: es:di
+ dataSeg = SegValue(es);
+ if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_edi;
+ else dataOfs = reg_di;
+ break;
+ case 'X': //ALT - X: ds:dx
+ dataSeg = SegValue(ds);
+ if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_edx;
+ else dataOfs = reg_dx;
+ break;
+ case 'B' : //ALT -B: es:bx
+ dataSeg = SegValue(es);
+ if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_ebx;
+ else dataOfs = reg_bx;
+ break;
+ case 'S': //ALT - S: ss:sp
+ dataSeg = SegValue(ss);
+ if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_esp;
+ else dataOfs = reg_sp;
+ break;
+ default:
+ break;
+ }
+ break;
+ case KEY_PPAGE : dataOfs -= 16; break;
+ case KEY_NPAGE : dataOfs += 16; break;
+
+ case KEY_DOWN: // down
+ if (codeViewData.cursorPos<9) codeViewData.cursorPos++;
+ else codeViewData.useEIP += codeViewData.firstInstSize;
+ break;
+ case KEY_UP: // up
+ if (codeViewData.cursorPos>0) codeViewData.cursorPos--;
+ else {
+ Bitu bytes = 0;
+ char dline[200];
+ Bitu size = 0;
+ Bit32u newEIP = codeViewData.useEIP - 1;
+ if(codeViewData.useEIP) {
+ for (; bytes < 10; bytes++) {
+ PhysPt start = GetAddress(codeViewData.useCS,newEIP);
+ size = DasmI386(dline, start, newEIP, cpu.code.big);
+ if(codeViewData.useEIP == newEIP+size) break;
+ newEIP--;
+ }
+ if (bytes>=10) newEIP = codeViewData.useEIP - 1;
+ }
+ codeViewData.useEIP = newEIP;
+ }
+ break;
+ case KEY_HOME: // Home: scroll log page up
+ DEBUG_RefreshPage(-1);
+ break;
+ case KEY_END: // End: scroll log page down
+ DEBUG_RefreshPage(1);
+ break;
+ case KEY_IC: // Insert: toggle insert/overwrite
+ codeViewData.ovrMode = !codeViewData.ovrMode;
+ break;
+ case KEY_LEFT: // move to the left in command line
+ if (codeViewData.inputPos > 0) codeViewData.inputPos--;
+ break;
+ case KEY_RIGHT: // move to the right in command line
+ if (codeViewData.inputStr[codeViewData.inputPos]) codeViewData.inputPos++;
+ break;
+ case KEY_F(6): // previous command (f1-f4 generate rubbish at my place)
+ case KEY_F(3): // previous command
+ if (histBuffPos == histBuff.begin()) break;
+ if (histBuffPos == histBuff.end()) {
+ // copy inputStr to suspInputStr so we can restore it
+ safe_strncpy(codeViewData.suspInputStr, codeViewData.inputStr, sizeof(codeViewData.suspInputStr));
+ }
+ safe_strncpy(codeViewData.inputStr,(*--histBuffPos).c_str(),sizeof(codeViewData.inputStr));
+ codeViewData.inputPos = strlen(codeViewData.inputStr);
+ break;
+ case KEY_F(7): // next command (f1-f4 generate rubbish at my place)
+ case KEY_F(4): // next command
+ if (histBuffPos == histBuff.end()) break;
+ if (++histBuffPos != histBuff.end()) {
+ safe_strncpy(codeViewData.inputStr,(*histBuffPos).c_str(),sizeof(codeViewData.inputStr));
+ } else {
+ // copy suspInputStr back into inputStr
+ safe_strncpy(codeViewData.inputStr, codeViewData.suspInputStr, sizeof(codeViewData.inputStr));
+ }
+ codeViewData.inputPos = strlen(codeViewData.inputStr);
+ break;
+ case KEY_F(5): // Run Program
+ debugging=false;
+ CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,true);
+ ignoreAddressOnce = SegPhys(cs)+reg_eip;
+ DOSBOX_SetNormalLoop();
+ break;
+ case KEY_F(9): // Set/Remove Breakpoint
+ { PhysPt ptr = GetAddress(codeViewData.cursorSeg,codeViewData.cursorOfs);
+ if (CBreakpoint::IsBreakpoint(ptr)) {
+ CBreakpoint::DeleteBreakpoint(ptr);
+ DEBUG_ShowMsg("DEBUG: Breakpoint deletion success.\n");
+ }
+ else {
+ CBreakpoint::AddBreakpoint(codeViewData.cursorSeg, codeViewData.cursorOfs, false);
+ DEBUG_ShowMsg("DEBUG: Set breakpoint at %04X:%04X\n",codeViewData.cursorSeg,codeViewData.cursorOfs);
+ }
+ }
+ break;
+ case KEY_F(10): // Step over inst
+ if (StepOver()) return 0;
+ else {
+ exitLoop = false;
+ skipFirstInstruction = true; // for heavy debugger
+ CPU_Cycles = 1;
+ ret=(*cpudecoder)();
+ SetCodeWinStart();
+ CBreakpoint::ignoreOnce = 0;
+ }
+ break;
+ case KEY_F(11): // trace into
+ exitLoop = false;
+ skipFirstInstruction = true; // for heavy debugger
+ CPU_Cycles = 1;
+ ret = (*cpudecoder)();
+ SetCodeWinStart();
+ CBreakpoint::ignoreOnce = 0;
+ break;
+ case 0x0A: //Parse typed Command
+ codeViewData.inputStr[MAXCMDLEN] = '\0';
+ if(ParseCommand(codeViewData.inputStr)) {
+ char* cmd = ltrim(codeViewData.inputStr);
+ if (histBuff.empty() || *--histBuff.end()!=cmd)
+ histBuff.push_back(cmd);
+ if (histBuff.size() > MAX_HIST_BUFFER) histBuff.pop_front();
+ histBuffPos = histBuff.end();
+ ClearInputLine();
+ } else {
+ codeViewData.inputPos = strlen(codeViewData.inputStr);
+ }
+ break;
+ case KEY_BACKSPACE: //backspace (linux)
+ case 0x7f: // backspace in some terminal emulators (linux)
+ case 0x08: // delete
+ if (codeViewData.inputPos == 0) break;
+ codeViewData.inputPos--;
+ // fallthrough
+ case KEY_DC: // delete character
+ if ((codeViewData.inputPos<0) || (codeViewData.inputPos>=MAXCMDLEN)) break;
+ if (codeViewData.inputStr[codeViewData.inputPos] != 0) {
+ codeViewData.inputStr[MAXCMDLEN] = '\0';
+ for(char* p=&codeViewData.inputStr[codeViewData.inputPos];(*p=*(p+1));p++) {}
+ }
+ break;
+ default:
+ if ((key>=32) && (key<127)) {
+ if ((codeViewData.inputPos<0) || (codeViewData.inputPos>=MAXCMDLEN)) break;
+ codeViewData.inputStr[MAXCMDLEN] = '\0';
+ if (codeViewData.inputStr[codeViewData.inputPos] == 0) {
+ codeViewData.inputStr[codeViewData.inputPos++] = char(key);
+ codeViewData.inputStr[codeViewData.inputPos] = '\0';
+ } else if (!codeViewData.ovrMode) {
+ int len = (int) strlen(codeViewData.inputStr);
+ if (len < MAXCMDLEN) {
+ for(len++;len>codeViewData.inputPos;len--)
+ codeViewData.inputStr[len]=codeViewData.inputStr[len-1];
+ codeViewData.inputStr[codeViewData.inputPos++] = char(key);
+ }
+ } else {
+ codeViewData.inputStr[codeViewData.inputPos++] = char(key);
+ }
+ } else if (key==killchar()) {
+ ClearInputLine();
+ }
+ break;
+ }
+ if (ret<0) return ret;
+ if (ret>0) {
+ if (GCC_UNLIKELY(ret >= CB_MAX))
+ ret = 0;
+ else
+ ret = (*CallBack_Handlers[ret])();
+ if (ret) {
+ exitLoop=true;
+ CPU_Cycles=CPU_CycleLeft=0;
+ return ret;
+ }
+ }
+ ret=0;
+ DEBUG_DrawScreen();
+ }
+ return ret;
+};
+
+Bitu DEBUG_Loop(void) {
+//TODO Disable sound
+ GFX_Events();
+ // Interrupt started ? - then skip it
+ Bit16u oldCS = SegValue(cs);
+ Bit32u oldEIP = reg_eip;
+ PIC_runIRQs();
+ SDL_Delay(1);
+ if ((oldCS!=SegValue(cs)) || (oldEIP!=reg_eip)) {
+ CBreakpoint::AddBreakpoint(oldCS,oldEIP,true);
+ CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,true);
+ debugging=false;
+ DOSBOX_SetNormalLoop();
+ return 0;
+ }
+ return DEBUG_CheckKeys();
+}
+
+void DEBUG_Enable(bool pressed) {
+ if (!pressed)
+ return;
+ static bool showhelp=false;
+ debugging=true;
+ SetCodeWinStart();
+ DEBUG_DrawScreen();
+ DOSBOX_SetLoop(&DEBUG_Loop);
+ if(!showhelp) {
+ showhelp=true;
+ DEBUG_ShowMsg("***| TYPE HELP (+ENTER) TO GET AN OVERVIEW OF ALL COMMANDS |***\n");
+ }
+ KEYBOARD_ClrBuffer();
+}
+
+void DEBUG_DrawScreen(void) {
+ DrawData();
+ DrawCode();
+ DrawRegisters();
+ DrawVariables();
+}
+
+static void DEBUG_RaiseTimerIrq(void) {
+ PIC_ActivateIRQ(0);
+}
+
+// Display the content of the MCB chain starting with the MCB at the specified segment.
+static void LogMCBChain(Bit16u mcb_segment) {
+ DOS_MCB mcb(mcb_segment);
+ char filename[9]; // 8 characters plus a terminating NUL
+ const char *psp_seg_note;
+ PhysPt dataAddr = PhysMake(dataSeg,dataOfs);// location being viewed in the "Data Overview"
+
+ // loop forever, breaking out of the loop once we've processed the last MCB
+ while (true) {
+ // verify that the type field is valid
+ if (mcb.GetType()!=0x4d && mcb.GetType()!=0x5a) {
+ LOG(LOG_MISC,LOG_ERROR)("MCB chain broken at %04X:0000!",mcb_segment);
+ return;
+ }
+
+ mcb.GetFileName(filename);
+
+ // some PSP segment values have special meanings
+ switch (mcb.GetPSPSeg()) {
+ case MCB_FREE:
+ psp_seg_note = "(free)";
+ break;
+ case MCB_DOS:
+ psp_seg_note = "(DOS)";
+ break;
+ default:
+ psp_seg_note = "";
+ }
+
+ LOG(LOG_MISC,LOG_ERROR)(" %04X %12u %04X %-7s %s",mcb_segment,mcb.GetSize() << 4,mcb.GetPSPSeg(), psp_seg_note, filename);
+
+ // print a message if dataAddr is within this MCB's memory range
+ PhysPt mcbStartAddr = PhysMake(mcb_segment+1,0);
+ PhysPt mcbEndAddr = PhysMake(mcb_segment+1+mcb.GetSize(),0);
+ if (dataAddr >= mcbStartAddr && dataAddr < mcbEndAddr) {
+ LOG(LOG_MISC,LOG_ERROR)(" (data addr %04hX:%04X is %u bytes past this MCB)",dataSeg,dataOfs,dataAddr - mcbStartAddr);
+ }
+
+ // if we've just processed the last MCB in the chain, break out of the loop
+ if (mcb.GetType()==0x5a) {
+ break;
+ }
+ // else, move to the next MCB in the chain
+ mcb_segment+=mcb.GetSize()+1;
+ mcb.SetPt(mcb_segment);
+ }
+}
+
+// Display the content of all Memory Control Blocks.
+static void LogMCBS(void)
+{
+ LOG(LOG_MISC,LOG_ERROR)("MCB Seg Size (bytes) PSP Seg (notes) Filename");
+ LOG(LOG_MISC,LOG_ERROR)("Conventional memory:");
+ LogMCBChain(dos.firstMCB);
+
+ LOG(LOG_MISC,LOG_ERROR)("Upper memory:");
+ LogMCBChain(dos_infoblock.GetStartOfUMBChain());
+}
+
+static void LogGDT(void)
+{
+ char out1[512];
+ Descriptor desc;
+ Bitu length = cpu.gdt.GetLimit();
+ PhysPt address = cpu.gdt.GetBase();
+ PhysPt max = address + length;
+ Bitu i = 0;
+ LOG(LOG_MISC,LOG_ERROR)("GDT Base:%08X Limit:%08X",address,length);
+ while (address<max) {
+ desc.Load(address);
+ sprintf(out1,"%04X: b:%08X type: %02X parbg",(i<<3),desc.GetBase(),desc.saved.seg.type);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ sprintf(out1," l:%08X dpl : %01X %1X%1X%1X%1X%1X",desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.r,desc.saved.seg.big,desc.saved.seg.g);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ address+=8; i++;
+ };
+};
+
+static void LogLDT(void) {
+ char out1[512];
+ Descriptor desc;
+ Bitu ldtSelector = cpu.gdt.SLDT();
+ if (!cpu.gdt.GetDescriptor(ldtSelector,desc)) return;
+ Bitu length = desc.GetLimit();
+ PhysPt address = desc.GetBase();
+ PhysPt max = address + length;
+ Bitu i = 0;
+ LOG(LOG_MISC,LOG_ERROR)("LDT Base:%08X Limit:%08X",address,length);
+ while (address<max) {
+ desc.Load(address);
+ sprintf(out1,"%04X: b:%08X type: %02X parbg",(i<<3)|4,desc.GetBase(),desc.saved.seg.type);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ sprintf(out1," l:%08X dpl : %01X %1X%1X%1X%1X%1X",desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.r,desc.saved.seg.big,desc.saved.seg.g);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ address+=8; i++;
+ };
+};
+
+static void LogIDT(void) {
+ char out1[512];
+ Descriptor desc;
+ Bitu address = 0;
+ while (address<256*8) {
+ if (cpu.idt.GetDescriptor(address,desc)) {
+ sprintf(out1,"%04X: sel:%04X off:%02X",address/8,desc.GetSelector(),desc.GetOffset());
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ }
+ address+=8;
+ };
+};
+
+void LogPages(char* selname) {
+ char out1[512];
+ if (paging.enabled) {
+ Bitu sel = GetHexValue(selname,selname);
+ if ((sel==0x00) && ((*selname==0) || (*selname=='*'))) {
+ for (int i=0; i<0xfffff; i++) {
+ Bitu table_addr=(paging.base.page<<12)+(i >> 10)*4;
+ X86PageEntry table;
+ table.load=phys_readd(table_addr);
+ if (table.block.p) {
+ X86PageEntry entry;
+ Bitu entry_addr=(table.block.base<<12)+(i & 0x3ff)*4;
+ entry.load=phys_readd(entry_addr);
+ if (entry.block.p) {
+ sprintf(out1,"page %05Xxxx -> %04Xxxx flags [uw] %x:%x::%x:%x [d=%x|a=%x]",
+ i,entry.block.base,entry.block.us,table.block.us,
+ entry.block.wr,table.block.wr,entry.block.d,entry.block.a);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ }
+ }
+ }
+ } else {
+ Bitu table_addr=(paging.base.page<<12)+(sel >> 10)*4;
+ X86PageEntry table;
+ table.load=phys_readd(table_addr);
+ if (table.block.p) {
+ X86PageEntry entry;
+ Bitu entry_addr=(table.block.base<<12)+(sel & 0x3ff)*4;
+ entry.load=phys_readd(entry_addr);
+ sprintf(out1,"page %05Xxxx -> %04Xxxx flags [puw] %x:%x::%x:%x::%x:%x",sel,entry.block.base,entry.block.p,table.block.p,entry.block.us,table.block.us,entry.block.wr,table.block.wr);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ } else {
+ sprintf(out1,"pagetable %03X not present, flags [puw] %x::%x::%x",(sel >> 10),table.block.p,table.block.us,table.block.wr);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ }
+ }
+ }
+};
+
+static void LogCPUInfo(void) {
+ char out1[512];
+ sprintf(out1,"cr0:%08X cr2:%08X cr3:%08X cpl=%x",cpu.cr0,paging.cr2,paging.cr3,cpu.cpl);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ sprintf(out1,"eflags:%08X [vm=%x iopl=%x nt=%x]",reg_flags,GETFLAG(VM)>>17,GETFLAG(IOPL)>>12,GETFLAG(NT)>>14);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ sprintf(out1,"GDT base=%08X limit=%08X",cpu.gdt.GetBase(),cpu.gdt.GetLimit());
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ sprintf(out1,"IDT base=%08X limit=%08X",cpu.idt.GetBase(),cpu.idt.GetLimit());
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+
+ Bitu sel=CPU_STR();
+ Descriptor desc;
+ if (cpu.gdt.GetDescriptor(sel,desc)) {
+ sprintf(out1,"TR selector=%04X, base=%08X limit=%08X*%X",sel,desc.GetBase(),desc.GetLimit(),desc.saved.seg.g?0x4000:1);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ }
+ sel=CPU_SLDT();
+ if (cpu.gdt.GetDescriptor(sel,desc)) {
+ sprintf(out1,"LDT selector=%04X, base=%08X limit=%08X*%X",sel,desc.GetBase(),desc.GetLimit(),desc.saved.seg.g?0x4000:1);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ }
+};
+
+#if C_HEAVY_DEBUG
+static void LogInstruction(Bit16u segValue, Bit32u eipValue, ofstream& out) {
+ static char empty[23] = { 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,0 };
+
+ PhysPt start = GetAddress(segValue,eipValue);
+ char dline[200];Bitu size;
+ size = DasmI386(dline, start, reg_eip, cpu.code.big);
+ char* res = empty;
+ if (showExtend && (cpuLogType > 0) ) {
+ res = AnalyzeInstruction(dline,false);
+ if (!res || !(*res)) res = empty;
+ Bitu reslen = strlen(res);
+ if (reslen<22) for (Bitu i=0; i<22-reslen; i++) res[reslen+i] = ' '; res[22] = 0;
+ };
+ Bitu len = strlen(dline);
+ if (len<30) for (Bitu i=0; i<30-len; i++) dline[len + i] = ' '; dline[30] = 0;
+
+ // Get register values
+
+ if(cpuLogType == 0) {
+ out << setw(4) << SegValue(cs) << ":" << setw(4) << reg_eip << " " << dline;
+ } else if (cpuLogType == 1) {
+ out << setw(4) << SegValue(cs) << ":" << setw(8) << reg_eip << " " << dline << " " << res;
+ } else if (cpuLogType == 2) {
+ char ibytes[200]=""; char tmpc[200];
+ for (Bitu i=0; i<size; i++) {
+ Bit8u value;
+ if (mem_readb_checked(start+i,&value)) sprintf(tmpc,"%s","?? ");
+ else sprintf(tmpc,"%02X ",value);
+ strcat(ibytes,tmpc);
+ }
+ len = strlen(ibytes);
+ if (len<21) { for (Bitu i=0; i<21-len; i++) ibytes[len + i] =' '; ibytes[21]=0;} //NOTE THE BRACKETS
+ out << setw(4) << SegValue(cs) << ":" << setw(8) << reg_eip << " " << dline << " " << res << " " << ibytes;
+ }
+
+ out << " EAX:" << setw(8) << reg_eax << " EBX:" << setw(8) << reg_ebx
+ << " ECX:" << setw(8) << reg_ecx << " EDX:" << setw(8) << reg_edx
+ << " ESI:" << setw(8) << reg_esi << " EDI:" << setw(8) << reg_edi
+ << " EBP:" << setw(8) << reg_ebp << " ESP:" << setw(8) << reg_esp
+ << " DS:" << setw(4) << SegValue(ds)<< " ES:" << setw(4) << SegValue(es);
+
+ if(cpuLogType == 0) {
+ out << " SS:" << setw(4) << SegValue(ss) << " C" << (get_CF()>0) << " Z" << (get_ZF()>0)
+ << " S" << (get_SF()>0) << " O" << (get_OF()>0) << " I" << GETFLAGBOOL(IF);
+ } else {
+ out << " FS:" << setw(4) << SegValue(fs) << " GS:" << setw(4) << SegValue(gs)
+ << " SS:" << setw(4) << SegValue(ss)
+ << " CF:" << (get_CF()>0) << " ZF:" << (get_ZF()>0) << " SF:" << (get_SF()>0)
+ << " OF:" << (get_OF()>0) << " AF:" << (get_AF()>0) << " PF:" << (get_PF()>0)
+ << " IF:" << GETFLAGBOOL(IF);
+ }
+ if(cpuLogType == 2) {
+ out << " TF:" << GETFLAGBOOL(TF) << " VM:" << GETFLAGBOOL(VM) <<" FLG:" << setw(8) << reg_flags
+ << " CR0:" << setw(8) << cpu.cr0;
+ }
+ out << endl;
+};
+#endif
+
+// DEBUG.COM stuff
+
+class DEBUG : public Program {
+public:
+ DEBUG() { pDebugcom = this; active = false; };
+ ~DEBUG() { pDebugcom = 0; };
+
+ bool IsActive() { return active; };
+
+ void Run(void)
+ {
+ if(cmd->FindExist("/NOMOUSE",false)) {
+ real_writed(0,0x33<<2,0);
+ return;
+ }
+
+ char filename[128];
+ char args[256];
+
+ cmd->FindCommand(1,temp_line);
+ safe_strncpy(filename,temp_line.c_str(),128);
+ // Read commandline
+ Bit16u i =2;
+ args[0] = 0;
+ for (;cmd->FindCommand(i++,temp_line)==true;) {
+ strncat(args,temp_line.c_str(),256);
+ strncat(args," ",256);
+ }
+ // Start new shell and execute prog
+ active = true;
+ // Save cpu state....
+ Bit16u oldcs = SegValue(cs);
+ Bit32u oldeip = reg_eip;
+ Bit16u oldss = SegValue(ss);
+ Bit32u oldesp = reg_esp;
+
+ // Workaround : Allocate Stack Space
+ Bit16u segment;
+ Bit16u size = 0x200 / 0x10;
+ if (DOS_AllocateMemory(&segment,&size)) {
+ SegSet16(ss,segment);
+ reg_sp = 0x200;
+ // Start shell
+ DOS_Shell shell;
+ shell.Execute(filename,args);
+ DOS_FreeMemory(segment);
+ }
+ // set old reg values
+ SegSet16(ss,oldss);
+ reg_esp = oldesp;
+ SegSet16(cs,oldcs);
+ reg_eip = oldeip;
+ };
+
+private:
+ bool active;
+};
+
+void DEBUG_CheckExecuteBreakpoint(Bit16u seg, Bit32u off)
+{
+ if (pDebugcom && pDebugcom->IsActive()) {
+ CBreakpoint::AddBreakpoint(seg,off,true);
+ CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,true);
+ pDebugcom = 0;
+ };
+};
+
+Bitu DEBUG_EnableDebugger(void)
+{
+ exitLoop = true;
+ DEBUG_Enable(true);
+ CPU_Cycles=CPU_CycleLeft=0;
+ return 0;
+};
+
+static void DEBUG_ProgramStart(Program * * make) {
+ *make=new DEBUG;
+}
+
+// INIT
+
+void DEBUG_SetupConsole(void) {
+ #ifdef WIN32
+ WIN32_Console();
+ #else
+ tcgetattr(0,&consolesettings);
+ printf("\e[8;50;80t"); //resize terminal
+ fflush(NULL);
+ #endif
+ memset((void *)&dbg,0,sizeof(dbg));
+ debugging=false;
+// dbg.active_win=3;
+ /* Start the Debug Gui */
+ DBGUI_StartUp();
+}
+
+void DEBUG_ShutDown(Section * /*sec*/) {
+ CBreakpoint::DeleteAll();
+ CDebugVar::DeleteAll();
+ curs_set(old_cursor_state);
+ endwin();
+ #ifndef WIN32
+ tcsetattr(0, TCSANOW,&consolesettings);
+// printf("\e[0m\e[2J"); //Seems to destroy scrolling
+ printf("\ec");
+ fflush(NULL);
+ #endif
+}
+
+Bitu debugCallback;
+
+void DEBUG_Init(Section* sec) {
+
+// MSG_Add("DEBUG_CONFIGFILE_HELP","Debugger related options.\n");
+ DEBUG_DrawScreen();
+ /* Add some keyhandlers */
+ MAPPER_AddHandler(DEBUG_Enable,MK_pause,MMOD2,"debugger","Debugger");
+ /* Reset code overview and input line */
+ memset((void*)&codeViewData,0,sizeof(codeViewData));
+ /* setup debug.com */
+ PROGRAMS_MakeFile("DEBUG.COM",DEBUG_ProgramStart);
+ /* Setup callback */
+ debugCallback=CALLBACK_Allocate();
+ CALLBACK_Setup(debugCallback,DEBUG_EnableDebugger,CB_RETF,"debugger");
+ /* shutdown function */
+ sec->AddDestroyFunction(&DEBUG_ShutDown);
+}
+
+// DEBUGGING VAR STUFF
+
+void CDebugVar::InsertVariable(char* name, PhysPt adr)
+{
+ varList.push_back(new CDebugVar(name,adr));
+};
+
+void CDebugVar::DeleteAll(void)
+{
+ std::list<CDebugVar*>::iterator i;
+ CDebugVar* bp;
+ for(i=varList.begin(); i != varList.end(); i++) {
+ bp = static_cast<CDebugVar*>(*i);
+ delete bp;
+ };
+ (varList.clear)();
+};
+
+CDebugVar* CDebugVar::FindVar(PhysPt pt)
+{
+ std::list<CDebugVar*>::iterator i;
+ CDebugVar* bp;
+ for(i=varList.begin(); i != varList.end(); i++) {
+ bp = static_cast<CDebugVar*>(*i);
+ if (bp->GetAdr()==pt) return bp;
+ };
+ return 0;
+};
+
+bool CDebugVar::SaveVars(char* name) {
+ if (varList.size()>65535) return false;
+
+ FILE* f = fopen(name,"wb+");
+ if (!f) return false;
+
+ // write number of vars
+ Bit16u num = (Bit16u)varList.size();
+ fwrite(&num,1,sizeof(num),f);
+
+ std::list<CDebugVar*>::iterator i;
+ CDebugVar* bp;
+ for(i=varList.begin(); i != varList.end(); i++) {
+ bp = static_cast<CDebugVar*>(*i);
+ // name
+ fwrite(bp->GetName(),1,16,f);
+ // adr
+ PhysPt adr = bp->GetAdr();
+ fwrite(&adr,1,sizeof(adr),f);
+ };
+ fclose(f);
+ return true;
+};
+
+bool CDebugVar::LoadVars(char* name)
+{
+ FILE* f = fopen(name,"rb");
+ if (!f) return false;
+
+ // read number of vars
+ Bit16u num;
+ fread(&num,1,sizeof(num),f);
+
+ for (Bit16u i=0; i<num; i++) {
+ char name[16];
+ // name
+ fread(name,1,16,f);
+ // adr
+ PhysPt adr;
+ fread(&adr,1,sizeof(adr),f);
+ // insert
+ InsertVariable(name,adr);
+ };
+ fclose(f);
+ return true;
+};
+
+static void SaveMemory(Bitu seg, Bitu ofs1, Bit32u num) {
+ FILE* f = fopen("MEMDUMP.TXT","wt");
+ if (!f) {
+ DEBUG_ShowMsg("DEBUG: Memory dump failed.\n");
+ return;
+ }
+
+ char buffer[128];
+ char temp[16];
+
+ while (num>16) {
+ sprintf(buffer,"%04X:%04X ",seg,ofs1);
+ for (Bit16u x=0; x<16; x++) {
+ Bit8u value;
+ if (mem_readb_checked(GetAddress(seg,ofs1+x),&value)) sprintf(temp,"%s","?? ");
+ else sprintf(temp,"%02X ",value);
+ strcat(buffer,temp);
+ }
+ ofs1+=16;
+ num-=16;
+
+ fprintf(f,"%s\n",buffer);
+ }
+ if (num>0) {
+ sprintf(buffer,"%04X:%04X ",seg,ofs1);
+ for (Bit16u x=0; x<num; x++) {
+ Bit8u value;
+ if (mem_readb_checked(GetAddress(seg,ofs1+x),&value)) sprintf(temp,"%s","?? ");
+ else sprintf(temp,"%02X ",value);
+ strcat(buffer,temp);
+ }
+ fprintf(f,"%s\n",buffer);
+ }
+ fclose(f);
+ DEBUG_ShowMsg("DEBUG: Memory dump success.\n");
+}
+
+static void SaveMemoryBin(Bitu seg, Bitu ofs1, Bit32u num) {
+ FILE* f = fopen("MEMDUMP.BIN","wb");
+ if (!f) {
+ DEBUG_ShowMsg("DEBUG: Memory binary dump failed.\n");
+ return;
+ }
+
+ for (Bitu x = 0; x < num;x++) {
+ Bit8u val;
+ if (mem_readb_checked(GetAddress(seg,ofs1+x),&val)) val=0;
+ fwrite(&val,1,1,f);
+ }
+
+ fclose(f);
+ DEBUG_ShowMsg("DEBUG: Memory dump binary success.\n");
+}
+
+static void OutputVecTable(char* filename) {
+ FILE* f = fopen(filename, "wt");
+ if (!f)
+ {
+ DEBUG_ShowMsg("DEBUG: Output of interrupt vector table failed.\n");
+ return;
+ }
+
+ for (int i=0; i<256; i++)
+ fprintf(f,"INT %02X: %04X:%04X\n", i, mem_readw(i*4+2), mem_readw(i*4));
+
+ fclose(f);
+ DEBUG_ShowMsg("DEBUG: Interrupt vector table written to %s.\n", filename);
+}
+
+#define DEBUG_VAR_BUF_LEN 16
+static void DrawVariables(void) {
+ if (CDebugVar::varList.empty()) return;
+
+ std::list<CDebugVar*>::iterator i;
+ CDebugVar *dv;
+ char buffer[DEBUG_VAR_BUF_LEN];
+
+ int idx = 0;
+ for(i=CDebugVar::varList.begin(); i != CDebugVar::varList.end(); i++, idx++) {
+
+ if (idx == 4*3) {
+ /* too many variables */
+ break;
+ }
+
+ dv = static_cast<CDebugVar*>(*i);
+
+ Bit16u value;
+ if (mem_readw_checked(dv->GetAdr(),&value))
+ snprintf(buffer,DEBUG_VAR_BUF_LEN, "%s", "??????");
+ else
+ snprintf(buffer,DEBUG_VAR_BUF_LEN, "0x%04x", value);
+
+ int y = idx / 3;
+ int x = (idx % 3) * 26;
+ mvwprintw(dbg.win_var, y, x, dv->GetName());
+ mvwprintw(dbg.win_var, y, (x + DEBUG_VAR_BUF_LEN + 1) , buffer);
+ }
+
+ wrefresh(dbg.win_var);
+};
+#undef DEBUG_VAR_BUF_LEN
+// HEAVY DEBUGGING STUFF
+
+#if C_HEAVY_DEBUG
+
+const Bit32u LOGCPUMAX = 20000;
+
+static Bit32u logCount = 0;
+
+struct TLogInst {
+ Bit16u s_cs;
+ Bit32u eip;
+ Bit32u eax;
+ Bit32u ebx;
+ Bit32u ecx;
+ Bit32u edx;
+ Bit32u esi;
+ Bit32u edi;
+ Bit32u ebp;
+ Bit32u esp;
+ Bit16u s_ds;
+ Bit16u s_es;
+ Bit16u s_fs;
+ Bit16u s_gs;
+ Bit16u s_ss;
+ bool c;
+ bool z;
+ bool s;
+ bool o;
+ bool a;
+ bool p;
+ bool i;
+ char dline[31];
+ char res[23];
+};
+
+TLogInst logInst[LOGCPUMAX];
+
+void DEBUG_HeavyLogInstruction(void) {
+
+ static char empty[23] = { 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,0 };
+
+ PhysPt start = GetAddress(SegValue(cs),reg_eip);
+ char dline[200];
+ DasmI386(dline, start, reg_eip, cpu.code.big);
+ char* res = empty;
+ if (showExtend) {
+ res = AnalyzeInstruction(dline,false);
+ if (!res || !(*res)) res = empty;
+ Bitu reslen = strlen(res);
+ if (reslen<22) for (Bitu i=0; i<22-reslen; i++) res[reslen+i] = ' '; res[22] = 0;
+ };
+
+ Bitu len = strlen(dline);
+ if (len < 30) for (Bitu i=0; i < 30-len; i++) dline[len+i] = ' ';
+ dline[30] = 0;
+
+ TLogInst & inst = logInst[logCount];
+ strcpy(inst.dline,dline);
+ inst.s_cs = SegValue(cs);
+ inst.eip = reg_eip;
+ strcpy(inst.res,res);
+ inst.eax = reg_eax;
+ inst.ebx = reg_ebx;
+ inst.ecx = reg_ecx;
+ inst.edx = reg_edx;
+ inst.esi = reg_esi;
+ inst.edi = reg_edi;
+ inst.ebp = reg_ebp;
+ inst.esp = reg_esp;
+ inst.s_ds = SegValue(ds);
+ inst.s_es = SegValue(es);
+ inst.s_fs = SegValue(fs);
+ inst.s_gs = SegValue(gs);
+ inst.s_ss = SegValue(ss);
+ inst.c = get_CF()>0;
+ inst.z = get_ZF()>0;
+ inst.s = get_SF()>0;
+ inst.o = get_OF()>0;
+ inst.a = get_AF()>0;
+ inst.p = get_PF()>0;
+ inst.i = GETFLAGBOOL(IF);
+
+ if (++logCount >= LOGCPUMAX) logCount = 0;
+};
+
+void DEBUG_HeavyWriteLogInstruction(void) {
+ if (!logHeavy) return;
+ logHeavy = false;
+
+ DEBUG_ShowMsg("DEBUG: Creating cpu log LOGCPU_INT_CD.TXT\n");
+
+ ofstream out("LOGCPU_INT_CD.TXT");
+ if (!out.is_open()) {
+ DEBUG_ShowMsg("DEBUG: Failed.\n");
+ return;
+ }
+ out << hex << noshowbase << setfill('0') << uppercase;
+ Bit32u startLog = logCount;
+ do {
+ // Write Instructions
+ TLogInst & inst = logInst[startLog];
+ out << setw(4) << inst.s_cs << ":" << setw(8) << inst.eip << " "
+ << inst.dline << " " << inst.res << " EAX:" << setw(8)<< inst.eax
+ << " EBX:" << setw(8) << inst.ebx << " ECX:" << setw(8) << inst.ecx
+ << " EDX:" << setw(8) << inst.edx << " ESI:" << setw(8) << inst.esi
+ << " EDI:" << setw(8) << inst.edi << " EBP:" << setw(8) << inst.ebp
+ << " ESP:" << setw(8) << inst.esp << " DS:" << setw(4) << inst.s_ds
+ << " ES:" << setw(4) << inst.s_es<< " FS:" << setw(4) << inst.s_fs
+ << " GS:" << setw(4) << inst.s_gs<< " SS:" << setw(4) << inst.s_ss
+ << " CF:" << inst.c << " ZF:" << inst.z << " SF:" << inst.s
+ << " OF:" << inst.o << " AF:" << inst.a << " PF:" << inst.p
+ << " IF:" << inst.i << endl;
+
+/* fprintf(f,"%04X:%08X %s %s EAX:%08X EBX:%08X ECX:%08X EDX:%08X ESI:%08X EDI:%08X EBP:%08X ESP:%08X DS:%04X ES:%04X FS:%04X GS:%04X SS:%04X CF:%01X ZF:%01X SF:%01X OF:%01X AF:%01X PF:%01X IF:%01X\n",
+ logInst[startLog].s_cs,logInst[startLog].eip,logInst[startLog].dline,logInst[startLog].res,logInst[startLog].eax,logInst[startLog].ebx,logInst[startLog].ecx,logInst[startLog].edx,logInst[startLog].esi,logInst[startLog].edi,logInst[startLog].ebp,logInst[startLog].esp,
+ logInst[startLog].s_ds,logInst[startLog].s_es,logInst[startLog].s_fs,logInst[startLog].s_gs,logInst[startLog].s_ss,
+ logInst[startLog].c,logInst[startLog].z,logInst[startLog].s,logInst[startLog].o,logInst[startLog].a,logInst[startLog].p,logInst[startLog].i);*/
+ if (++startLog >= LOGCPUMAX) startLog = 0;
+ } while (startLog != logCount);
+
+ out.close();
+ DEBUG_ShowMsg("DEBUG: Done.\n");
+};
+
+bool DEBUG_HeavyIsBreakpoint(void) {
+ static Bitu zero_count = 0;
+ if (cpuLog) {
+ if (cpuLogCounter>0) {
+ LogInstruction(SegValue(cs),reg_eip,cpuLogFile);
+ cpuLogCounter--;
+ }
+ if (cpuLogCounter<=0) {
+ cpuLogFile.close();
+ DEBUG_ShowMsg("DEBUG: cpu log LOGCPU.TXT created\n");
+ cpuLog = false;
+ DEBUG_EnableDebugger();
+ return true;
+ }
+ }
+ // LogInstruction
+ if (logHeavy) DEBUG_HeavyLogInstruction();
+ if (zeroProtect) {
+ Bit32u value=0;
+ if (!mem_readd_checked(SegPhys(cs)+reg_eip,&value)) {
+ if (value == 0) zero_count++;
+ else zero_count = 0;
+ }
+ if (GCC_UNLIKELY(zero_count == 10)) E_Exit("running zeroed code");
+ }
+
+ if (skipFirstInstruction) {
+ skipFirstInstruction = false;
+ return false;
+ }
+ if (CBreakpoint::CheckBreakpoint(SegValue(cs),reg_eip)) {
+ return true;
+ }
+ return false;
+}
+
+#endif // HEAVY DEBUG
+
+
+#endif // DEBUG
+
+
diff --git a/src/debug/debug_disasm.cpp b/src/debug/debug_disasm.cpp
index 6d8d5bc8e..c5fa5f121 100644
--- a/src/debug/debug_disasm.cpp
+++ b/src/debug/debug_disasm.cpp
@@ -63,7 +63,7 @@ Any comments/updates/bug reports to:
*/
#include "dosbox.h"
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
diff --git a/src/debug/debug_gui.cpp b/src/debug/debug_gui.cpp
index 60166d918..8f9069b75 100644
--- a/src/debug/debug_gui.cpp
+++ b/src/debug/debug_gui.cpp
@@ -32,10 +32,6 @@
#include "debug.h"
#include "debug_inc.h"
-struct _LogGroup {
- char const* front;
- bool enabled;
-};
#include <list>
#include <string>
using namespace std;
@@ -45,12 +41,10 @@ static list<string> logBuff;
static list<string>::iterator logBuffPos = logBuff.end();
static _LogGroup loggrp[LOG_MAX]={{"",true},{0,false}};
-static FILE* debuglog;
+extern FILE* debuglog;
extern int old_cursor_state;
-
-
void DEBUG_ShowMsg(char const* format,...) {
char buf[512];
@@ -100,18 +94,6 @@ void DEBUG_RefreshPage(char scroll) {
wrefresh(dbg.win_out);
}
-void LOG::operator() (char const* format, ...){
- char buf[512];
- va_list msg;
- va_start(msg,format);
- vsprintf(buf,format,msg);
- va_end(msg);
-
- if (d_type>=LOG_MAX) return;
- if ((d_severity!=LOG_ERROR) && (!loggrp[d_type].enabled)) return;
- DEBUG_ShowMsg("%10u: %s:%s\n",cycle_count,loggrp[d_type].front,buf);
-}
-
static void Draw_RegisterLayout(void) {
mvwaddstr(dbg.win_reg,0,0,"EAX=");
@@ -193,76 +175,6 @@ static void MakePairs(void) {
init_pair(PAIR_BLACK_GREY, COLOR_BLACK /*| FOREGROUND_INTENSITY */, COLOR_WHITE);
init_pair(PAIR_GREY_RED, COLOR_WHITE/*| FOREGROUND_INTENSITY */, COLOR_RED);
}
-static void LOG_Destroy(Section*) {
- if(debuglog) fclose(debuglog);
-}
-
-static void LOG_Init(Section * sec) {
- Section_prop * sect=static_cast<Section_prop *>(sec);
- const char * blah=sect->Get_string("logfile");
- if(blah && blah[0] &&(debuglog = fopen(blah,"wt+"))){
- }else{
- debuglog=0;
- }
- sect->AddDestroyFunction(&LOG_Destroy);
- char buf[1024];
- for (Bitu i=1;i<LOG_MAX;i++) {
- strcpy(buf,loggrp[i].front);
- buf[strlen(buf)]=0;
- lowcase(buf);
- loggrp[i].enabled=sect->Get_bool(buf);
- }
-}
-
-
-void LOG_StartUp(void) {
- /* Setup logging groups */
- loggrp[LOG_ALL].front="ALL";
- loggrp[LOG_VGA].front="VGA";
- loggrp[LOG_VGAGFX].front="VGAGFX";
- loggrp[LOG_VGAMISC].front="VGAMISC";
- loggrp[LOG_INT10].front="INT10";
- loggrp[LOG_SB].front="SBLASTER";
- loggrp[LOG_DMACONTROL].front="DMA_CONTROL";
-
- loggrp[LOG_FPU].front="FPU";
- loggrp[LOG_CPU].front="CPU";
- loggrp[LOG_PAGING].front="PAGING";
-
- loggrp[LOG_FCB].front="FCB";
- loggrp[LOG_FILES].front="FILES";
- loggrp[LOG_IOCTL].front="IOCTL";
- loggrp[LOG_EXEC].front="EXEC";
- loggrp[LOG_DOSMISC].front="DOSMISC";
-
- loggrp[LOG_PIT].front="PIT";
- loggrp[LOG_KEYBOARD].front="KEYBOARD";
- loggrp[LOG_PIC].front="PIC";
-
- loggrp[LOG_MOUSE].front="MOUSE";
- loggrp[LOG_BIOS].front="BIOS";
- loggrp[LOG_GUI].front="GUI";
- loggrp[LOG_MISC].front="MISC";
-
- loggrp[LOG_IO].front="IO";
- loggrp[LOG_PCI].front="PCI";
-
- /* Register the log section */
- Section_prop * sect=control->AddSection_prop("log",LOG_Init);
- Prop_string* Pstring = sect->Add_string("logfile",Property::Changeable::Always,"");
- Pstring->Set_help("file where the log messages will be saved to");
- char buf[1024];
- for (Bitu i=1;i<LOG_MAX;i++) {
- strcpy(buf,loggrp[i].front);
- lowcase(buf);
- Prop_bool* Pbool = sect->Add_bool(buf,Property::Changeable::Always,true);
- Pbool->Set_help("Enable/Disable logging of this type.");
- }
-// MSG_Add("LOG_CONFIGFILE_HELP","Logging related options for the debugger.\n");
-}
-
-
-
void DBGUI_StartUp(void) {
/* Start the main window */
@@ -277,10 +189,11 @@ void DBGUI_StartUp(void) {
#endif
old_cursor_state = curs_set(0);
start_color();
- cycle_count=0;
+ DEBUG_cycle_count=0;
MakePairs();
MakeSubWindows();
}
#endif
+
diff --git a/src/debug/debug_helpers.cpp b/src/debug/debug_helpers.cpp
new file mode 100644
index 000000000..7261a4063
--- /dev/null
+++ b/src/debug/debug_helpers.cpp
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2002-2011 The DOSBox Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "dosbox.h"
+#if C_DEBUG || C_GDBSERVER
+
+#include <string.h>
+#include <list>
+#include <ctype.h>
+#include <fstream>
+#include <iomanip>
+#include <string>
+#include <sstream>
+using namespace std;
+
+#include "debug.h"
+#include "cross.h" //snprintf
+#include "cpu.h"
+#include "video.h"
+#include "pic.h"
+#include "mapper.h"
+#include "cpu.h"
+#include "callback.h"
+#include "inout.h"
+#include "mixer.h"
+#include "timer.h"
+#include "paging.h"
+#include "support.h"
+#include "shell.h"
+#include "programs.h"
+#include "debug_inc.h"
+#include "../cpu/lazyflags.h"
+#include "keyboard.h"
+#include "setup.h"
+
+bool DEBUG_exitLoop = false;
+Bit16u DEBUG_dataSeg;
+Bit32u DEBUG_dataOfs;
+char DEBUG_curSelectorName[3] = { 0,0,0 };
+
+Bit32u PhysMakeProt(Bit16u selector, Bit32u offset)
+{
+ Descriptor desc;
+ if (cpu.gdt.GetDescriptor(selector,desc)) return desc.GetBase()+offset;
+ return 0;
+};
+
+Bit32u DEBUG_GetAddress(Bit16u seg, Bit32u offset)
+{
+ if (seg==SegValue(cs)) return SegPhys(cs)+offset;
+ if (cpu.pmode && !(reg_flags & FLAG_VM)) {
+ Descriptor desc;
+ if (cpu.gdt.GetDescriptor(seg,desc)) return PhysMakeProt(seg,offset);
+ }
+ return (seg<<4)+offset;
+}
+
+static char empty_sel[] = { ' ',' ',0 };
+
+Bit32u DEBUG_GetHexValue(char* str, char*& hex)
+{
+ Bit32u value = 0;
+ Bit32u regval = 0;
+ hex = str;
+ while (*hex==' ') hex++;
+ if (strstr(hex,"EAX")==hex) { hex+=3; regval = reg_eax; };
+ if (strstr(hex,"EBX")==hex) { hex+=3; regval = reg_ebx; };
+ if (strstr(hex,"ECX")==hex) { hex+=3; regval = reg_ecx; };
+ if (strstr(hex,"EDX")==hex) { hex+=3; regval = reg_edx; };
+ if (strstr(hex,"ESI")==hex) { hex+=3; regval = reg_esi; };
+ if (strstr(hex,"EDI")==hex) { hex+=3; regval = reg_edi; };
+ if (strstr(hex,"EBP")==hex) { hex+=3; regval = reg_ebp; };
+ if (strstr(hex,"ESP")==hex) { hex+=3; regval = reg_esp; };
+ if (strstr(hex,"EIP")==hex) { hex+=3; regval = reg_eip; };
+ if (strstr(hex,"AX")==hex) { hex+=2; regval = reg_ax; };
+ if (strstr(hex,"BX")==hex) { hex+=2; regval = reg_bx; };
+ if (strstr(hex,"CX")==hex) { hex+=2; regval = reg_cx; };
+ if (strstr(hex,"DX")==hex) { hex+=2; regval = reg_dx; };
+ if (strstr(hex,"SI")==hex) { hex+=2; regval = reg_si; };
+ if (strstr(hex,"DI")==hex) { hex+=2; regval = reg_di; };
+ if (strstr(hex,"BP")==hex) { hex+=2; regval = reg_bp; };
+ if (strstr(hex,"SP")==hex) { hex+=2; regval = reg_sp; };
+ if (strstr(hex,"IP")==hex) { hex+=2; regval = reg_ip; };
+ if (strstr(hex,"CS")==hex) { hex+=2; regval = SegValue(cs); };
+ if (strstr(hex,"DS")==hex) { hex+=2; regval = SegValue(ds); };
+ if (strstr(hex,"ES")==hex) { hex+=2; regval = SegValue(es); };
+ if (strstr(hex,"FS")==hex) { hex+=2; regval = SegValue(fs); };
+ if (strstr(hex,"GS")==hex) { hex+=2; regval = SegValue(gs); };
+ if (strstr(hex,"SS")==hex) { hex+=2; regval = SegValue(ss); };
+
+ while (*hex) {
+ if ((*hex>='0') && (*hex<='9')) value = (value<<4)+*hex-'0';
+ else if ((*hex>='A') && (*hex<='F')) value = (value<<4)+*hex-'A'+10;
+ else {
+ if(*hex == '+') {hex++;return regval + value + DEBUG_GetHexValue(hex,hex); };
+ if(*hex == '-') {hex++;return regval + value - DEBUG_GetHexValue(hex,hex); };
+ break; // No valid char
+ }
+ hex++;
+ };
+ return regval + value;
+}
+
+bool DEBUG_GetDescriptorInfo(char* selname, char* out1, char* out2)
+{
+ Bitu sel;
+ Descriptor desc;
+
+ if (strstr(selname,"cs") || strstr(selname,"CS")) sel = SegValue(cs);
+ else if (strstr(selname,"ds") || strstr(selname,"DS")) sel = SegValue(ds);
+ else if (strstr(selname,"es") || strstr(selname,"ES")) sel = SegValue(es);
+ else if (strstr(selname,"fs") || strstr(selname,"FS")) sel = SegValue(fs);
+ else if (strstr(selname,"gs") || strstr(selname,"GS")) sel = SegValue(gs);
+ else if (strstr(selname,"ss") || strstr(selname,"SS")) sel = SegValue(ss);
+ else {
+ sel = DEBUG_GetHexValue(selname,selname);
+ if (*selname==0) selname=empty_sel;
+ }
+ if (cpu.gdt.GetDescriptor(sel,desc)) {
+ switch (desc.Type()) {
+ case DESC_TASK_GATE:
+ sprintf(out1,"%s: s:%08X type:%02X p",selname,desc.GetSelector(),desc.saved.gate.type);
+ sprintf(out2," TaskGate dpl : %01X %1X",desc.saved.gate.dpl,desc.saved.gate.p);
+ return true;
+ case DESC_LDT:
+ case DESC_286_TSS_A:
+ case DESC_286_TSS_B:
+ case DESC_386_TSS_A:
+ case DESC_386_TSS_B:
+ sprintf(out1,"%s: b:%08X type:%02X pag",selname,desc.GetBase(),desc.saved.seg.type);
+ sprintf(out2," l:%08X dpl : %01X %1X%1X%1X",desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.g);
+ return true;
+ case DESC_286_CALL_GATE:
+ case DESC_386_CALL_GATE:
+ sprintf(out1,"%s: s:%08X type:%02X p params: %02X",selname,desc.GetSelector(),desc.saved.gate.type,desc.saved.gate.paramcount);
+ sprintf(out2," o:%08X dpl : %01X %1X",desc.GetOffset(),desc.saved.gate.dpl,desc.saved.gate.p);
+ return true;
+ case DESC_286_INT_GATE:
+ case DESC_286_TRAP_GATE:
+ case DESC_386_INT_GATE:
+ case DESC_386_TRAP_GATE:
+ sprintf(out1,"%s: s:%08X type:%02X p",selname,desc.GetSelector(),desc.saved.gate.type);
+ sprintf(out2," o:%08X dpl : %01X %1X",desc.GetOffset(),desc.saved.gate.dpl,desc.saved.gate.p);
+ return true;
+ }
+ sprintf(out1,"%s: b:%08X type:%02X parbg",selname,desc.GetBase(),desc.saved.seg.type);
+ sprintf(out2," l:%08X dpl : %01X %1X%1X%1X%1X%1X",desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.r,desc.saved.seg.big,desc.saved.seg.g);
+ return true;
+ } else {
+ strcpy(out1," ");
+ strcpy(out2," ");
+ }
+ return false;
+};
+
+char* DEBUG_AnalyzeInstruction(char* inst, bool saveSelector) {
+ static char result[256];
+
+ char instu[256];
+ char prefix[3];
+ Bit16u seg;
+
+ strcpy(instu,inst);
+ upcase(instu);
+
+ result[0] = 0;
+ char* pos = strchr(instu,'[');
+ if (pos) {
+ // Segment prefix ?
+ if (*(pos-1)==':') {
+ char* segpos = pos-3;
+ prefix[0] = tolower(*segpos);
+ prefix[1] = tolower(*(segpos+1));
+ prefix[2] = 0;
+ seg = (Bit16u)DEBUG_GetHexValue(segpos,segpos);
+ } else {
+ if (strstr(pos,"SP") || strstr(pos,"BP")) {
+ seg = SegValue(ss);
+ strcpy(prefix,"ss");
+ } else {
+ seg = SegValue(ds);
+ strcpy(prefix,"ds");
+ };
+ };
+
+ pos++;
+ Bit32u adr = DEBUG_GetHexValue(pos,pos);
+ while (*pos!=']') {
+ if (*pos=='+') {
+ pos++;
+ adr += DEBUG_GetHexValue(pos,pos);
+ } else if (*pos=='-') {
+ pos++;
+ adr -= DEBUG_GetHexValue(pos,pos);
+ } else
+ pos++;
+ };
+ Bit32u address = DEBUG_GetAddress(seg,adr);
+ if (!(get_tlb_readhandler(address)->flags & PFLAG_INIT)) {
+ static char outmask[] = "%s:[%04X]=%02X";
+
+ if (cpu.pmode) outmask[6] = '8';
+ switch (DasmLastOperandSize()) {
+ case 8 : { Bit8u val = mem_readb(address);
+ outmask[12] = '2';
+ sprintf(result,outmask,prefix,adr,val);
+ } break;
+ case 16: { Bit16u val = mem_readw(address);
+ outmask[12] = '4';
+ sprintf(result,outmask,prefix,adr,val);
+ } break;
+ case 32: { Bit32u val = mem_readd(address);
+ outmask[12] = '8';
+ sprintf(result,outmask,prefix,adr,val);
+ } break;
+ }
+ } else {
+ sprintf(result,"[illegal]");
+ }
+#ifndef C_GDBSERVER
+ // Variable found ?
+ CDebugVar* var = CDebugVar::FindVar(address);
+ if (var) {
+ // Replace occurance
+ char* pos1 = strchr(inst,'[');
+ char* pos2 = strchr(inst,']');
+ if (pos1 && pos2) {
+ char temp[256];
+ strcpy(temp,pos2); // save end
+ pos1++; *pos1 = 0; // cut after '['
+ strcat(inst,var->GetName()); // add var name
+ strcat(inst,temp); // add end
+ };
+ };
+#endif
+ // show descriptor info, if available
+ if ((cpu.pmode) && saveSelector) {
+ strcpy(DEBUG_curSelectorName,prefix);
+ };
+ };
+ // If it is a callback add additional info
+ pos = strstr(inst,"callback");
+ if (pos) {
+ pos += 9;
+ Bitu nr = DEBUG_GetHexValue(pos,pos);
+ const char* descr = CALLBACK_GetDescription(nr);
+ if (descr) {
+ strcat(inst," ("); strcat(inst,descr); strcat(inst,")");
+ }
+ };
+ // Must be a jump
+ if (instu[0] == 'J')
+ {
+ bool jmp = false;
+ switch (instu[1]) {
+ case 'A' : { jmp = (get_CF()?false:true) && (get_ZF()?false:true); // JA
+ } break;
+ case 'B' : { if (instu[2] == 'E') {
+ jmp = (get_CF()?true:false) || (get_ZF()?true:false); // JBE
+ } else {
+ jmp = get_CF()?true:false; // JB
+ }
+ } break;
+ case 'C' : { if (instu[2] == 'X') {
+ jmp = reg_cx == 0; // JCXZ
+ } else {
+ jmp = get_CF()?true:false; // JC
+ }
+ } break;
+ case 'E' : { jmp = get_ZF()?true:false; // JE
+ } break;
+ case 'G' : { if (instu[2] == 'E') {
+ jmp = (get_SF()?true:false)==(get_OF()?true:false); // JGE
+ } else {
+ jmp = (get_ZF()?false:true) && ((get_SF()?true:false)==(get_OF()?true:false)); // JG
+ }
+ } break;
+ case 'L' : { if (instu[2] == 'E') {
+ jmp = (get_ZF()?true:false) || ((get_SF()?true:false)!=(get_OF()?true:false)); // JLE
+ } else {
+ jmp = (get_SF()?true:false)!=(get_OF()?true:false); // JL
+ }
+ } break;
+ case 'M' : { jmp = true; // JMP
+ } break;
+ case 'N' : { switch (instu[2]) {
+ case 'B' :
+ case 'C' : { jmp = get_CF()?false:true; // JNB / JNC
+ } break;
+ case 'E' : { jmp = get_ZF()?false:true; // JNE
+ } break;
+ case 'O' : { jmp = get_OF()?false:true; // JNO
+ } break;
+ case 'P' : { jmp = get_PF()?false:true; // JNP
+ } break;
+ case 'S' : { jmp = get_SF()?false:true; // JNS
+ } break;
+ case 'Z' : { jmp = get_ZF()?false:true; // JNZ
+ } break;
+ }
+ } break;
+ case 'O' : { jmp = get_OF()?true:false; // JO
+ } break;
+ case 'P' : { if (instu[2] == 'O') {
+ jmp = get_PF()?false:true; // JPO
+ } else {
+ jmp = get_SF()?true:false; // JP / JPE
+ }
+ } break;
+ case 'S' : { jmp = get_SF()?true:false; // JS
+ } break;
+ case 'Z' : { jmp = get_ZF()?true:false; // JZ
+ } break;
+ }
+ if (jmp) {
+ pos = strchr(instu,'$');
+ if (pos) {
+ pos = strchr(instu,'+');
+ if (pos) {
+ strcpy(result,"(down)");
+ } else {
+ strcpy(result,"(up)");
+ }
+ }
+ } else {
+ sprintf(result,"(no jmp)");
+ }
+ }
+ return result;
+};
+
+#endif
diff --git a/src/debug/debug_log.cpp b/src/debug/debug_log.cpp
new file mode 100644
index 000000000..921ab20ee
--- /dev/null
+++ b/src/debug/debug_log.cpp
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) 2002-2011 The DOSBox Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "dosbox.h"
+#if C_DEBUG || C_GDBSERVER
+
+#include <string.h>
+#include <list>
+#include <ctype.h>
+#include <fstream>
+#include <iomanip>
+#include <string>
+#include <sstream>
+using namespace std;
+
+#include "control.h"
+#include "debug.h"
+#include "cross.h" //snprintf
+#include "cpu.h"
+#include "video.h"
+#include "pic.h"
+#include "mapper.h"
+#include "cpu.h"
+#include "callback.h"
+#include "inout.h"
+#include "mixer.h"
+#include "timer.h"
+#include "paging.h"
+#include "support.h"
+#include "shell.h"
+#include "programs.h"
+#include "debug_inc.h"
+#include "../cpu/lazyflags.h"
+#include "keyboard.h"
+#include "setup.h"
+
+// Heavy Debugging Vars for logging
+#if C_HEAVY_DEBUG || C_GDBSERVER
+ofstream DEBUG_cpuLogFile;
+bool DEBUG_cpuLog = false;
+int DEBUG_cpuLogCounter = 0;
+int DEBUG_cpuLogType = 1; // log detail
+bool DEBUG_zeroProtect = false;
+bool DEBUG_logHeavy = false;
+#endif
+
+bool DEBUG_showExtend = true;
+
+// Display the content of the MCB chain starting with the MCB at the specified segment.
+void DEBUG_LogMCBChain(Bit16u mcb_segment) {
+ DOS_MCB mcb(mcb_segment);
+ char filename[9]; // 8 characters plus a terminating NUL
+ const char *psp_seg_note;
+ PhysPt dataAddr = PhysMake(DEBUG_dataSeg,DEBUG_dataOfs);// location being viewed in the "Data Overview"
+
+ // loop forever, breaking out of the loop once we've processed the last MCB
+ while (true) {
+ // verify that the type field is valid
+ if (mcb.GetType()!=0x4d && mcb.GetType()!=0x5a) {
+ LOG(LOG_MISC,LOG_ERROR)("MCB chain broken at %04X:0000!",mcb_segment);
+ return;
+ }
+
+ mcb.GetFileName(filename);
+
+ // some PSP segment values have special meanings
+ switch (mcb.GetPSPSeg()) {
+ case MCB_FREE:
+ psp_seg_note = "(free)";
+ break;
+ case MCB_DOS:
+ psp_seg_note = "(DOS)";
+ break;
+ default:
+ psp_seg_note = "";
+ }
+
+ LOG(LOG_MISC,LOG_ERROR)(" %04X %12u %04X %-7s %s",mcb_segment,mcb.GetSize() << 4,mcb.GetPSPSeg(), psp_seg_note, filename);
+
+ // print a message if dataAddr is within this MCB's memory range
+ PhysPt mcbStartAddr = PhysMake(mcb_segment+1,0);
+ PhysPt mcbEndAddr = PhysMake(mcb_segment+1+mcb.GetSize(),0);
+ if (dataAddr >= mcbStartAddr && dataAddr < mcbEndAddr) {
+ LOG(LOG_MISC,LOG_ERROR)(" (data addr %04hX:%04X is %u bytes past this MCB)",DEBUG_dataSeg,DEBUG_dataOfs,dataAddr - mcbStartAddr);
+ }
+
+ // if we've just processed the last MCB in the chain, break out of the loop
+ if (mcb.GetType()==0x5a) {
+ break;
+ }
+ // else, move to the next MCB in the chain
+ mcb_segment+=mcb.GetSize()+1;
+ mcb.SetPt(mcb_segment);
+ }
+}
+
+// Display the content of all Memory Control Blocks.
+void DEBUG_LogMCBS(void)
+{
+ LOG(LOG_MISC,LOG_ERROR)("MCB Seg Size (bytes) PSP Seg (notes) Filename");
+ LOG(LOG_MISC,LOG_ERROR)("Conventional memory:");
+ DEBUG_LogMCBChain(dos.firstMCB);
+
+ LOG(LOG_MISC,LOG_ERROR)("Upper memory:");
+ DEBUG_LogMCBChain(dos_infoblock.GetStartOfUMBChain());
+}
+
+void DEBUG_LogGDT(void)
+{
+ char out1[512];
+ Descriptor desc;
+ Bitu length = cpu.gdt.GetLimit();
+ PhysPt address = cpu.gdt.GetBase();
+ PhysPt max = address + length;
+ Bitu i = 0;
+ LOG(LOG_MISC,LOG_ERROR)("GDT Base:%08X Limit:%08X",address,length);
+ while (address<max) {
+ desc.Load(address);
+ sprintf(out1,"%04X: b:%08X type: %02X parbg",(i<<3),desc.GetBase(),desc.saved.seg.type);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ sprintf(out1," l:%08X dpl : %01X %1X%1X%1X%1X%1X",desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.r,desc.saved.seg.big,desc.saved.seg.g);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ address+=8; i++;
+ };
+};
+
+void DEBUG_LogLDT(void) {
+ char out1[512];
+ Descriptor desc;
+ Bitu ldtSelector = cpu.gdt.SLDT();
+ if (!cpu.gdt.GetDescriptor(ldtSelector,desc)) return;
+ Bitu length = desc.GetLimit();
+ PhysPt address = desc.GetBase();
+ PhysPt max = address + length;
+ Bitu i = 0;
+ LOG(LOG_MISC,LOG_ERROR)("LDT Base:%08X Limit:%08X",address,length);
+ while (address<max) {
+ desc.Load(address);
+ sprintf(out1,"%04X: b:%08X type: %02X parbg",(i<<3)|4,desc.GetBase(),desc.saved.seg.type);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ sprintf(out1," l:%08X dpl : %01X %1X%1X%1X%1X%1X",desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.r,desc.saved.seg.big,desc.saved.seg.g);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ address+=8; i++;
+ };
+};
+
+void DEBUG_LogIDT(void) {
+ char out1[512];
+ Descriptor desc;
+ Bitu address = 0;
+ while (address<256*8) {
+ if (cpu.idt.GetDescriptor(address,desc)) {
+ sprintf(out1,"%04X: sel:%04X off:%02X",address/8,desc.GetSelector(),desc.GetOffset());
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ }
+ address+=8;
+ };
+};
+
+void DEBUG_LogPages(char* selname) {
+ char out1[512];
+ if (paging.enabled) {
+ Bitu sel = DEBUG_GetHexValue(selname,selname);
+ if ((sel==0x00) && ((*selname==0) || (*selname=='*'))) {
+ for (int i=0; i<0xfffff; i++) {
+ Bitu table_addr=(paging.base.page<<12)+(i >> 10)*4;
+ X86PageEntry table;
+ table.load=phys_readd(table_addr);
+ if (table.block.p) {
+ X86PageEntry entry;
+ Bitu entry_addr=(table.block.base<<12)+(i & 0x3ff)*4;
+ entry.load=phys_readd(entry_addr);
+ if (entry.block.p) {
+ sprintf(out1,"page %05Xxxx -> %04Xxxx flags [uw] %x:%x::%x:%x [d=%x|a=%x]",
+ i,entry.block.base,entry.block.us,table.block.us,
+ entry.block.wr,table.block.wr,entry.block.d,entry.block.a);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ }
+ }
+ }
+ } else {
+ Bitu table_addr=(paging.base.page<<12)+(sel >> 10)*4;
+ X86PageEntry table;
+ table.load=phys_readd(table_addr);
+ if (table.block.p) {
+ X86PageEntry entry;
+ Bitu entry_addr=(table.block.base<<12)+(sel & 0x3ff)*4;
+ entry.load=phys_readd(entry_addr);
+ sprintf(out1,"page %05Xxxx -> %04Xxxx flags [puw] %x:%x::%x:%x::%x:%x",sel,entry.block.base,entry.block.p,table.block.p,entry.block.us,table.block.us,entry.block.wr,table.block.wr);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ } else {
+ sprintf(out1,"pagetable %03X not present, flags [puw] %x::%x::%x",(sel >> 10),table.block.p,table.block.us,table.block.wr);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ }
+ }
+ }
+};
+
+void DEBUG_LogCPUInfo(void) {
+ char out1[512];
+ sprintf(out1,"cr0:%08X cr2:%08X cr3:%08X cpl=%x",cpu.cr0,paging.cr2,paging.cr3,cpu.cpl);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ sprintf(out1,"eflags:%08X [vm=%x iopl=%x nt=%x]",reg_flags,GETFLAG(VM)>>17,GETFLAG(IOPL)>>12,GETFLAG(NT)>>14);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ sprintf(out1,"GDT base=%08X limit=%08X",cpu.gdt.GetBase(),cpu.gdt.GetLimit());
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ sprintf(out1,"IDT base=%08X limit=%08X",cpu.idt.GetBase(),cpu.idt.GetLimit());
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+
+ Bitu sel=CPU_STR();
+ Descriptor desc;
+ if (cpu.gdt.GetDescriptor(sel,desc)) {
+ sprintf(out1,"TR selector=%04X, base=%08X limit=%08X*%X",sel,desc.GetBase(),desc.GetLimit(),desc.saved.seg.g?0x4000:1);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ }
+ sel=CPU_SLDT();
+ if (cpu.gdt.GetDescriptor(sel,desc)) {
+ sprintf(out1,"LDT selector=%04X, base=%08X limit=%08X*%X",sel,desc.GetBase(),desc.GetLimit(),desc.saved.seg.g?0x4000:1);
+ LOG(LOG_MISC,LOG_ERROR)(out1);
+ }
+};
+
+_LogGroup loggrp[LOG_MAX]={{"",true},{0,false}};
+FILE* debuglog;
+
+void LOG::operator() (char const* format, ...){
+ char buf[512];
+ va_list msg;
+ va_start(msg,format);
+ vsprintf(buf,format,msg);
+ va_end(msg);
+
+ if (d_type>=LOG_MAX) return;
+ if ((d_severity!=LOG_ERROR) && (!loggrp[d_type].enabled)) return;
+ DEBUG_ShowMsg("%10u: %s:%s\n",DEBUG_cycle_count,loggrp[d_type].front,buf);
+}
+
+static void LOG_Destroy(Section*) {
+ if(debuglog) fclose(debuglog);
+}
+
+static void LOG_Init(Section * sec) {
+ Section_prop * sect=static_cast<Section_prop *>(sec);
+ const char * blah=sect->Get_string("logfile");
+ if(blah && blah[0] &&(debuglog = fopen(blah,"wt+"))){
+ }else{
+ debuglog=0;
+ }
+ sect->AddDestroyFunction(&LOG_Destroy);
+ char buf[1024];
+ for (Bitu i=1;i<LOG_MAX;i++) {
+ strcpy(buf,loggrp[i].front);
+ buf[strlen(buf)]=0;
+ lowcase(buf);
+ loggrp[i].enabled=sect->Get_bool(buf);
+ }
+}
+
+
+void LOG_StartUp(void) {
+ /* Setup logging groups */
+ loggrp[LOG_ALL].front="ALL";
+ loggrp[LOG_VGA].front="VGA";
+ loggrp[LOG_VGAGFX].front="VGAGFX";
+ loggrp[LOG_VGAMISC].front="VGAMISC";
+ loggrp[LOG_INT10].front="INT10";
+ loggrp[LOG_SB].front="SBLASTER";
+ loggrp[LOG_DMACONTROL].front="DMA_CONTROL";
+
+ loggrp[LOG_FPU].front="FPU";
+ loggrp[LOG_CPU].front="CPU";
+ loggrp[LOG_PAGING].front="PAGING";
+
+ loggrp[LOG_FCB].front="FCB";
+ loggrp[LOG_FILES].front="FILES";
+ loggrp[LOG_IOCTL].front="IOCTL";
+ loggrp[LOG_EXEC].front="EXEC";
+ loggrp[LOG_DOSMISC].front="DOSMISC";
+
+ loggrp[LOG_PIT].front="PIT";
+ loggrp[LOG_KEYBOARD].front="KEYBOARD";
+ loggrp[LOG_PIC].front="PIC";
+
+ loggrp[LOG_MOUSE].front="MOUSE";
+ loggrp[LOG_BIOS].front="BIOS";
+ loggrp[LOG_GUI].front="GUI";
+ loggrp[LOG_MISC].front="MISC";
+
+ loggrp[LOG_IO].front="IO";
+ loggrp[LOG_PCI].front="PCI";
+
+ /* Register the log section */
+ Section_prop * sect=control->AddSection_prop("log",LOG_Init);
+ Prop_string* Pstring = sect->Add_string("logfile",Property::Changeable::Always,"");
+ Pstring->Set_help("file where the log messages will be saved to");
+ char buf[1024];
+ for (Bitu i=1;i<LOG_MAX;i++) {
+ strcpy(buf,loggrp[i].front);
+ lowcase(buf);
+ Prop_bool* Pbool = sect->Add_bool(buf,Property::Changeable::Always,true);
+ Pbool->Set_help("Enable/Disable logging of this type.");
+ }
+// MSG_Add("LOG_CONFIGFILE_HELP","Logging related options for the debugger.\n");
+}
+
+#if C_HEAVY_DEBUG || C_GDBSERVER
+void DEBUG_LogInstruction(Bit16u segValue, Bit32u eipValue, ofstream& out) {
+ static char empty[23] = { 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,0 };
+
+ PhysPt start = DEBUG_GetAddress(segValue,eipValue);
+ char dline[200];Bitu size;
+ size = DasmI386(dline, start, reg_eip, cpu.code.big);
+ char* res = empty;
+ if (DEBUG_showExtend && (DEBUG_cpuLogType > 0) ) {
+ res = DEBUG_AnalyzeInstruction(dline,false);
+ if (!res || !(*res)) res = empty;
+ Bitu reslen = strlen(res);
+ if (reslen<22) for (Bitu i=0; i<22-reslen; i++) res[reslen+i] = ' '; res[22] = 0;
+ };
+ Bitu len = strlen(dline);
+ if (len<30) for (Bitu i=0; i<30-len; i++) dline[len + i] = ' '; dline[30] = 0;
+
+ // Get register values
+
+ if(DEBUG_cpuLogType == 0) {
+ out << setw(4) << SegValue(cs) << ":" << setw(4) << reg_eip << " " << dline;
+ } else if (DEBUG_cpuLogType == 1) {
+ out << setw(4) << SegValue(cs) << ":" << setw(8) << reg_eip << " " << dline << " " << res;
+ } else if (DEBUG_cpuLogType == 2) {
+ char ibytes[200]=""; char tmpc[200];
+ for (Bitu i=0; i<size; i++) {
+ Bit8u value;
+ if (mem_readb_checked(start+i,&value)) sprintf(tmpc,"%s","?? ");
+ else sprintf(tmpc,"%02X ",value);
+ strcat(ibytes,tmpc);
+ }
+ len = strlen(ibytes);
+ if (len<21) { for (Bitu i=0; i<21-len; i++) ibytes[len + i] =' '; ibytes[21]=0;} //NOTE THE BRACKETS
+ out << setw(4) << SegValue(cs) << ":" << setw(8) << reg_eip << " " << dline << " " << res << " " << ibytes;
+ }
+
+ out << " EAX:" << setw(8) << reg_eax << " EBX:" << setw(8) << reg_ebx
+ << " ECX:" << setw(8) << reg_ecx << " EDX:" << setw(8) << reg_edx
+ << " ESI:" << setw(8) << reg_esi << " EDI:" << setw(8) << reg_edi
+ << " EBP:" << setw(8) << reg_ebp << " ESP:" << setw(8) << reg_esp
+ << " DS:" << setw(4) << SegValue(ds)<< " ES:" << setw(4) << SegValue(es);
+
+ if(DEBUG_cpuLogType == 0) {
+ out << " SS:" << setw(4) << SegValue(ss) << " C" << (get_CF()>0) << " Z" << (get_ZF()>0)
+ << " S" << (get_SF()>0) << " O" << (get_OF()>0) << " I" << GETFLAGBOOL(IF);
+ } else {
+ out << " FS:" << setw(4) << SegValue(fs) << " GS:" << setw(4) << SegValue(gs)
+ << " SS:" << setw(4) << SegValue(ss)
+ << " CF:" << (get_CF()>0) << " ZF:" << (get_ZF()>0) << " SF:" << (get_SF()>0)
+ << " OF:" << (get_OF()>0) << " AF:" << (get_AF()>0) << " PF:" << (get_PF()>0)
+ << " IF:" << GETFLAGBOOL(IF);
+ }
+ if(DEBUG_cpuLogType == 2) {
+ out << " TF:" << GETFLAGBOOL(TF) << " VM:" << GETFLAGBOOL(VM) <<" FLG:" << setw(8) << reg_flags
+ << " CR0:" << setw(8) << cpu.cr0;
+ }
+ out << endl;
+};
+
+const Bit32u LOGCPUMAX = 20000;
+
+static Bit32u logCount = 0;
+
+struct TLogInst {
+ Bit16u s_cs;
+ Bit32u eip;
+ Bit32u eax;
+ Bit32u ebx;
+ Bit32u ecx;
+ Bit32u edx;
+ Bit32u esi;
+ Bit32u edi;
+ Bit32u ebp;
+ Bit32u esp;
+ Bit16u s_ds;
+ Bit16u s_es;
+ Bit16u s_fs;
+ Bit16u s_gs;
+ Bit16u s_ss;
+ bool c;
+ bool z;
+ bool s;
+ bool o;
+ bool a;
+ bool p;
+ bool i;
+ char dline[31];
+ char res[23];
+};
+
+TLogInst logInst[LOGCPUMAX];
+
+void DEBUG_HeavyLogInstruction(void) {
+
+ static char empty[23] = { 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,0 };
+
+ PhysPt start = DEBUG_GetAddress(SegValue(cs),reg_eip);
+ char dline[200];
+ DasmI386(dline, start, reg_eip, cpu.code.big);
+ char* res = empty;
+ if (DEBUG_showExtend) {
+ res = DEBUG_AnalyzeInstruction(dline,false);
+ if (!res || !(*res)) res = empty;
+ Bitu reslen = strlen(res);
+ if (reslen<22) for (Bitu i=0; i<22-reslen; i++) res[reslen+i] = ' '; res[22] = 0;
+ };
+
+ Bitu len = strlen(dline);
+ if (len < 30) for (Bitu i=0; i < 30-len; i++) dline[len+i] = ' ';
+ dline[30] = 0;
+
+ TLogInst & inst = logInst[logCount];
+ strcpy(inst.dline,dline);
+ inst.s_cs = SegValue(cs);
+ inst.eip = reg_eip;
+ strcpy(inst.res,res);
+ inst.eax = reg_eax;
+ inst.ebx = reg_ebx;
+ inst.ecx = reg_ecx;
+ inst.edx = reg_edx;
+ inst.esi = reg_esi;
+ inst.edi = reg_edi;
+ inst.ebp = reg_ebp;
+ inst.esp = reg_esp;
+ inst.s_ds = SegValue(ds);
+ inst.s_es = SegValue(es);
+ inst.s_fs = SegValue(fs);
+ inst.s_gs = SegValue(gs);
+ inst.s_ss = SegValue(ss);
+ inst.c = get_CF()>0;
+ inst.z = get_ZF()>0;
+ inst.s = get_SF()>0;
+ inst.o = get_OF()>0;
+ inst.a = get_AF()>0;
+ inst.p = get_PF()>0;
+ inst.i = GETFLAGBOOL(IF);
+
+ if (++logCount >= LOGCPUMAX) logCount = 0;
+};
+
+void DEBUG_HeavyWriteLogInstruction(void) {
+ if (!DEBUG_logHeavy) return;
+ DEBUG_logHeavy = false;
+
+ DEBUG_ShowMsg("DEBUG: Creating cpu log LOGCPU_INT_CD.TXT\n");
+
+ ofstream out("LOGCPU_INT_CD.TXT");
+ if (!out.is_open()) {
+ DEBUG_ShowMsg("DEBUG: Failed.\n");
+ return;
+ }
+ out << hex << noshowbase << setfill('0') << uppercase;
+ Bit32u startLog = logCount;
+ do {
+ // Write Intructions
+ TLogInst & inst = logInst[startLog];
+ out << setw(4) << inst.s_cs << ":" << setw(8) << inst.eip << " "
+ << inst.dline << " " << inst.res << " EAX:" << setw(8)<< inst.eax
+ << " EBX:" << setw(8) << inst.ebx << " ECX:" << setw(8) << inst.ecx
+ << " EDX:" << setw(8) << inst.edx << " ESI:" << setw(8) << inst.esi
+ << " EDI:" << setw(8) << inst.edi << " EBP:" << setw(8) << inst.ebp
+ << " ESP:" << setw(8) << inst.esp << " DS:" << setw(4) << inst.s_ds
+ << " ES:" << setw(4) << inst.s_es<< " FS:" << setw(4) << inst.s_fs
+ << " GS:" << setw(4) << inst.s_gs<< " SS:" << setw(4) << inst.s_ss
+ << " CF:" << inst.c << " ZF:" << inst.z << " SF:" << inst.s
+ << " OF:" << inst.o << " AF:" << inst.a << " PF:" << inst.p
+ << " IF:" << inst.i << endl;
+
+/* fprintf(f,"%04X:%08X %s %s EAX:%08X EBX:%08X ECX:%08X EDX:%08X ESI:%08X EDI:%08X EBP:%08X ESP:%08X DS:%04X ES:%04X FS:%04X GS:%04X SS:%04X CF:%01X ZF:%01X SF:%01X OF:%01X AF:%01X PF:%01X IF:%01X\n",
+ logInst[startLog].s_cs,logInst[startLog].eip,logInst[startLog].dline,logInst[startLog].res,logInst[startLog].eax,logInst[startLog].ebx,logInst[startLog].ecx,logInst[startLog].edx,logInst[startLog].esi,logInst[startLog].edi,logInst[startLog].ebp,logInst[startLog].esp,
+ logInst[startLog].s_ds,logInst[startLog].s_es,logInst[startLog].s_fs,logInst[startLog].s_gs,logInst[startLog].s_ss,
+ logInst[startLog].c,logInst[startLog].z,logInst[startLog].s,logInst[startLog].o,logInst[startLog].a,logInst[startLog].p,logInst[startLog].i);*/
+ if (++startLog >= LOGCPUMAX) startLog = 0;
+ } while (startLog != logCount);
+
+ out.close();
+ DEBUG_ShowMsg("DEBUG: Done.\n");
+};
+
+#endif
+
+#endif
diff --git a/src/debug/gdb_server.cpp b/src/debug/gdb_server.cpp
new file mode 100644
index 000000000..4810ef85d
--- /dev/null
+++ b/src/debug/gdb_server.cpp
@@ -0,0 +1,1090 @@
+/*
+ * Copyright (C) 2002-2011 The DOSBox Team
+ * Copyright (C) 2011 Alexandre Becoulet
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "dosbox.h"
+#if defined(C_GDBSERVER)
+
+#include <string.h>
+#include <list>
+#include <ctype.h>
+#include <fstream>
+#include <iomanip>
+#include <string>
+#include <sstream>
+#include <map>
+#include <algorithm>
+#include <vector>
+
+using namespace std;
+
+#ifdef WIN32
+//#include <Winsock2.h>
+#include "poll.h"
+char * strtok_r (char *s, const char *delim, char **save_ptr) {
+ char *token;
+
+ if (s == NULL)
+ s = *save_ptr;
+
+ /* Scan leading delimiters. */
+ s += strspn (s, delim);
+ if (*s == '\0')
+ {
+ *save_ptr = s;
+ return NULL;
+ }
+
+ /* Find the end of the token. */
+ token = s;
+ s = strpbrk (token, delim);
+ if (s == NULL)
+ /* This token finishes the string. */
+ *save_ptr = token + strlen (token);
+ else
+ {
+ /* Terminate the token and make *SAVE_PTR point past it. */
+ *s = '\0';
+ *save_ptr = s + 1;
+ }
+ return token;
+}
+
+#else
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <poll.h>
+#endif
+#include <assert.h>
+#include <stdarg.h>
+
+#include "debug.h"
+#include "cpu.h"
+#include "video.h"
+#include "pic.h"
+#include "cpu.h"
+#include "callback.h"
+#include "paging.h"
+#include "setup.h"
+
+#define GDB_TCP_PORT 1234
+
+// remote protocol debug display, must not call DEBUG_ShowMsg in the end
+#define GDB_REMOTE_LOG(...) fprintf(stderr, __VA_ARGS__)
+
+enum GdbState {
+ GdbNotConnected,
+ GdbRunning,
+ GdbStoped,
+ GdbStep, // set during step by step
+ GdbMonitor, // set during monitor command processing
+};
+
+static GdbState gdb_state = GdbNotConnected;
+static bool gdb_remote_debug = false;
+static int gdb_socket, gdb_asocket;
+
+static Bit32u step_eip;
+static Bit16u step_cs;
+GdbState step_next_state;
+
+// breakpoints/watchpoints maps
+typedef map<Bit32u /* start addr */, size_t /* len */> bp_map_t;
+static bp_map_t break_points;
+static bp_map_t read_watch_points;
+static bp_map_t write_watch_points;
+
+// interrupts breakpoints bitmap
+vector<bool> int_bp(256);
+
+Bitu DEBUG_debugCallback;
+Bitu DEBUG_cycle_count;
+static Bitu cycle_bp;
+
+extern bool DEBUG_logHeavy;
+
+static inline Bit32u
+swapByte32(Bit32u x)
+{
+ return (((x >> 24) & 0x000000ff) |
+ ((x >> 8 ) & 0x0000ff00) |
+ ((x << 8 ) & 0x00ff0000) |
+ ((x << 24) & 0xff000000));
+}
+
+static inline Bit16u
+swapByte16(Bit16u x)
+{
+ return (x >> 8) | (x << 8);
+}
+
+/****************************/
+/* Gdb cpu registers access */
+/****************************/
+
+enum GdbEipMode {
+ GdbFlatEip,
+ GdbRealEip,
+};
+
+static GdbEipMode gdb_eip_mode = GdbFlatEip;
+
+static void gdbSetEip(Bit32u gdb_eip)
+{
+ /* make gdb client see flat eip value */
+ switch (gdb_eip_mode) {
+ case GdbFlatEip:
+ reg_eip = gdb_eip - SegPhys(cs);
+ break;
+ case GdbRealEip:
+ reg_eip = gdb_eip;
+ break;
+ }
+}
+
+static Bit32u gdbGetEip(void)
+{
+ switch (gdb_eip_mode) {
+ case GdbFlatEip:
+ return reg_eip + SegPhys(cs);
+ case GdbRealEip:
+ return reg_eip;
+ }
+}
+
+#define GDB_REGS_COUNT 16
+
+Bit32u DEBUG_GdbGetRegister(int reg)
+{
+ switch (reg) {
+ case 0:
+ return swapByte32(reg_eax);
+ case 1:
+ return swapByte32(reg_ecx);
+ case 2:
+ return swapByte32(reg_edx);
+ case 3:
+ return swapByte32(reg_ebx);
+ case 4:
+ return swapByte32(reg_esp);
+ case 5:
+ return swapByte32(reg_ebp);
+ case 6:
+ return swapByte32(reg_esi);
+ case 7:
+ return swapByte32(reg_edi);
+ case 8:
+ return swapByte32(gdbGetEip());
+ case 9:
+ return swapByte32(reg_flags);
+ case 10:
+ return swapByte32(SegValue(cs));
+ case 11:
+ return swapByte32(SegValue(ss));
+ case 12:
+ return swapByte32(SegValue(ds));
+ case 13:
+ return swapByte32(SegValue(es));
+ case 14:
+ return swapByte32(SegValue(fs));
+ case 15:
+ return swapByte32(SegValue(gs));
+ default:
+ return 0;
+ }
+}
+
+int DEBUG_GdbGetRegisterSize(int reg)
+{
+ switch (reg) {
+ case 0: /* gp regs */
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ return 32;
+
+ case 10: /* segments */
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ return 32;
+
+ default:
+ return 0;
+ }
+
+}
+
+void DEBUG_GdbSetRegister(int reg, Bit32u value)
+{
+ switch (reg) {
+ case 0:
+ reg_eax = swapByte32(value);
+ break;
+ case 1:
+ reg_ecx = swapByte32(value);
+ break;
+ case 2:
+ reg_edx = swapByte32(value);
+ break;
+ case 3:
+ reg_ebx = swapByte32(value);
+ break;
+ case 4:
+ reg_esp = swapByte32(value);
+ break;
+ case 5:
+ reg_ebp = swapByte32(value);
+ break;
+ case 6:
+ reg_esi = swapByte32(value);
+ break;
+ case 7:
+ reg_edi = swapByte32(value);
+ break;
+ case 8:
+ gdbSetEip(swapByte32(value));
+ break;
+ case 9:
+ reg_flags = swapByte32(value);
+ break;
+ case 10:
+ SegSet16(cs, swapByte32(value));
+ break;
+ case 11:
+ SegSet16(ss, swapByte32(value));
+ break;
+ case 12:
+ SegSet16(ds, swapByte32(value));
+ break;
+ case 13:
+ SegSet16(es, swapByte32(value));
+ break;
+ case 14:
+ SegSet16(fs, swapByte32(value));
+ break;
+ case 15:
+ SegSet16(gs, swapByte32(value));
+ break;
+ }
+}
+
+/***********************/
+/* Gdb remote protocol */
+/***********************/
+
+int DEBUG_GdbWritePacket(const char *data_)
+{
+ unsigned int i, len = strlen(data_);
+ char ack, end[4];
+ uint8_t chksum = 0;
+ char data[len];
+
+ memcpy(data, data_, len + 1);
+
+ unsigned char repeat = 0;
+ unsigned int cmplen = len;
+ char *cmp = data;
+ char *last = 0;
+
+#if 1 // gdb RLE data compression
+
+ for (i = 0; ; ) {
+ if (i < cmplen && last && (*last == cmp[i]) && (repeat + 29 < 126)) {
+ repeat++;
+ } else {
+ if (repeat > 3) {
+ while (repeat == '#' - 29 || repeat == '$' - 29 ||
+ repeat == '+' - 29 || repeat == '-' - 29) {
+ repeat--;
+ last++;
+ }
+ last[1] = '*';
+ last[2] = 29 + repeat;
+ memmove(last + 3, cmp + i, cmplen - i + 1);
+ cmp = last + 3;
+ cmplen -= i;
+ i = 0;
+ last = 0;
+ repeat = 0;
+ continue;
+ } else {
+ last = cmp + i;
+ repeat = 0;
+ }
+
+ if (i == cmplen)
+ break;
+ }
+ i++;
+ }
+
+ cmp[cmplen] = 0;
+ len = cmp - data + cmplen;
+
+#endif
+
+ for (i = 0; i < len; i++)
+ chksum += data[i];
+
+ sprintf(end, "#%02x", chksum);
+
+ do {
+ if (gdb_remote_debug)
+ GDB_REMOTE_LOG("GDB: sending packet data '%s'\n", data);
+
+ send(gdb_asocket, "$", 1, MSG_DONTWAIT | MSG_NOSIGNAL);
+ send(gdb_asocket, data, len, MSG_DONTWAIT | MSG_NOSIGNAL);
+ send(gdb_asocket, end, 3, MSG_DONTWAIT | MSG_NOSIGNAL);
+
+ if (read(gdb_asocket, &ack, 1) < 1) {
+ close(gdb_asocket);
+ gdb_state = GdbNotConnected;
+ return -1;
+ }
+ } while (ack != '+');
+
+ return 0;
+}
+
+char * DEBUG_GdbReadPacket(char *buffer, size_t size)
+{
+ int res = read(gdb_asocket, buffer, size);
+
+ if (res <= 0) {
+ close(gdb_asocket);
+ gdb_state = GdbNotConnected;
+ return 0;
+ }
+
+ uint8_t sum = 0, chksum = 0;
+ char *data = 0;
+ char *end = 0;
+ int i;
+
+ // find data in packet
+ for (i = 0; i < res; i++) {
+ switch (buffer[i]) {
+ case '$':
+ sum = 0;
+ data = buffer + i + 1;
+ break;
+
+ case '#':
+ chksum = sum;
+ end = buffer + i;
+ *end = 0;
+ goto end;
+
+ default:
+ sum += buffer[i];
+ }
+ }
+ end:
+
+ // malformed packet
+ if (!end || data >= end) {
+ if (gdb_remote_debug)
+ GDB_REMOTE_LOG("GDB: malformed packet %i bytes\n", res);
+
+ return 0;
+ }
+
+ if (gdb_remote_debug)
+ GDB_REMOTE_LOG("GDB: packet with checksum %02x: %s\n", chksum, data);
+
+ // verify checksum
+ end[3] = 0;
+ if (chksum != strtoul(end + 1, 0, 16)) {
+ send(gdb_asocket, "-", 1, MSG_DONTWAIT | MSG_NOSIGNAL);
+
+ if (gdb_remote_debug)
+ GDB_REMOTE_LOG("GDB: bad packet checksum\n");
+
+ return 0;
+ }
+
+ send(gdb_asocket, "+", 1, MSG_DONTWAIT | MSG_NOSIGNAL);
+
+ return data;
+}
+
+static bool DEBUG_GdbPointSet(bp_map_t &b, Bit32u addr, size_t len, bool set_)
+{
+ if (set_) {
+ pair<bp_map_t::iterator, bool> ret = b.insert(bp_map_t::value_type(addr, len));
+
+ if (!ret.second) // adjust existing point
+ ret.first->second = max(ret.first->second, len);
+ } else {
+ b.erase(addr);
+ }
+}
+
+void DEBUG_GdbProcessMonitorPacket(char *data)
+{
+ const char *delim = " \t,";
+ char *tokens[255], *save;
+ unsigned int i = 0;
+
+ for (char *t = strtok_r(data, delim, &save);
+ t != NULL; t = strtok_r(NULL, delim, &save)) {
+ tokens[i++] = t;
+ if (i == 255)
+ break;
+ }
+
+ if (i >= 2 && !strcmp(tokens[0], "remote_debug")) {
+ gdb_remote_debug = atoi(tokens[1]);
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+
+ if (i >= 1 && !strcmp(tokens[0], "write_log_instruction")) {
+ DEBUG_HeavyWriteLogInstruction();
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+
+ if (i >= 2 && !strcmp(tokens[0], "log_heavy")) {
+ DEBUG_logHeavy = atoi(tokens[1]);
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+
+ if (i >= 2 && !strcmp(tokens[0], "cycle_abs_bp")) {
+ cycle_bp = atoi(tokens[1]);
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+
+ if (i >= 2 && !strcmp(tokens[0], "cycle_bp")) {
+ cycle_bp = DEBUG_cycle_count + atoi(tokens[1]);
+ DEBUG_ShowMsg("GDB: Cycle break point set at %u.\n", cycle_bp);
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+
+ if (i >= 2 && !strcmp(tokens[0], "flat_eip")) {
+ gdb_eip_mode = atoi(tokens[1]) ? GdbFlatEip : GdbRealEip;
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+
+ if (i >= 3 && !strcmp(tokens[0], "int_bp")) {
+ unsigned int inum = strtoul(tokens[1], 0, 0);
+
+ if (inum < 256) {
+ int_bp[inum] = atoi(tokens[2]);
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+ }
+
+ if (i >= 1 && !strcmp(tokens[0], "log_gdt")) {
+ DEBUG_LogGDT();
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+
+ if (i >= 1 && !strcmp(tokens[0], "log_ldt")) {
+ DEBUG_LogLDT();
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+
+ if (i >= 1 && !strcmp(tokens[0], "log_idt")) {
+ DEBUG_LogIDT();
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+
+ if (i >= 1 && !strcmp(tokens[0], "log_cpuinfo")) {
+ DEBUG_LogCPUInfo();
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+
+ if (i >= 2 && !strcmp(tokens[0], "log_pages")) {
+ DEBUG_LogPages(tokens[1]);
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+
+ DEBUG_ShowMsg("Supported DOSBox Gdb monitor commands:");
+ DEBUG_ShowMsg(" monitor cycle_bp [value] - set relative cycle breakpoint.");
+ DEBUG_ShowMsg(" monitor cycle_abs_bp [value] - set absolute cycle breakpoint.");
+ DEBUG_ShowMsg(" monitor flat_eip [ 0 | 1 ] - enable/disable use of flat eip register value.");
+ DEBUG_ShowMsg(" monitor int_bp [int_num] [ 0 | 1 ] - set breakpoint on cpu interrupt.");
+ DEBUG_ShowMsg(" monitor log_gdt - Lists descriptors of the GDT.");
+ DEBUG_ShowMsg(" monitor log_ldt - Lists descriptors of the LDT.");
+ DEBUG_ShowMsg(" monitor log_idt - Lists descriptors of the IDT.");
+ DEBUG_ShowMsg(" monitor log_cpuinfo - Display CPU status information.");
+ DEBUG_ShowMsg(" monitor log_pages [page] - Display content of page table.");
+ DEBUG_ShowMsg(" monitor remote_debug [ 0 | 1 ] - enable/disable gdb remote protocol debug.");
+ DEBUG_ShowMsg(" monitor set_log_heavy [ 0 | 1 ] - enable/disable heavy CPU logging.");
+ DEBUG_ShowMsg(" monitor write_log_instruction - write instructions log to disk.");
+
+ DEBUG_GdbWritePacket("");
+}
+
+void DEBUG_GdbProcessPackets()
+{
+ char buffer[1024];
+ char *data = DEBUG_GdbReadPacket(buffer, 1024);
+
+ if (!data)
+ return;
+
+ switch (data[0]) {
+ case 'k': // Kill
+ DEBUG_GdbWritePacket("OK");
+ exit(0);
+ return;
+
+ case 'D': // Detach
+ DEBUG_GdbWritePacket("OK");
+ close(gdb_asocket);
+ gdb_state = GdbNotConnected;
+ return;
+
+ case 'q': // Query
+ switch (data[1]) {
+ case 'R': {
+ unsigned int i;
+ char byte[3] = { 0 };
+
+ if (strncmp(data + 2, "cmd", 3))
+ break;
+
+ assert(data[5] == ',');
+
+ data += 6;
+
+ for (i = 0; data[i * 2]; i++) {
+ memcpy(byte, data + i * 2, 2);
+ data[i] = strtoul(byte, 0, 16);
+ }
+
+ data[i] = 0;
+
+ if (gdb_remote_debug)
+ GDB_REMOTE_LOG("GDB: monitor packet: '%s'\n", data);
+
+ gdb_state = GdbMonitor;
+ DEBUG_GdbProcessMonitorPacket(data);
+ gdb_state = GdbStoped;
+ return;
+ }
+
+ }
+ DEBUG_GdbWritePacket("");
+ return;
+
+ case '?': // Indicate the reason the target halted
+ DEBUG_GdbWritePacket("S05"); // SIGTRAP
+ return;
+
+ case 'p': { // read single register
+ unsigned int reg = strtoul(data + 1, 0, 16);
+ char fmt[32];
+ size_t s = DEBUG_GdbGetRegisterSize(reg);
+
+ if (s == 0)
+ break;
+
+ sprintf(fmt, "%%0%ux", s / 4);
+ sprintf(buffer, fmt, DEBUG_GdbGetRegister(reg));
+ DEBUG_GdbWritePacket(buffer);
+ return;
+ }
+
+ case 'P': { // write single register
+ char *end;
+ unsigned int reg = strtoul(data + 1, &end, 16);
+ assert(*end == '=');
+ uint32_t value = strtoul(end + 1, 0, 16);
+ size_t s = DEBUG_GdbGetRegisterSize(reg);
+
+ if (s == 0)
+ break;
+
+ DEBUG_GdbSetRegister(reg, value);
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+
+ case 'g': { // read multiple registers
+ char *b = buffer;
+
+ for (unsigned int i = 0; i < 1 /* FIXME */; i++) {
+ char fmt[32];
+ sprintf(fmt, "%%0%ux", DEBUG_GdbGetRegisterSize(i) / 4);
+ b += sprintf(b, fmt, DEBUG_GdbGetRegister(i));
+ }
+ DEBUG_GdbWritePacket(buffer);
+ return;
+ }
+
+ case 'G': { // write multiple registers
+
+ data++;
+ for (unsigned int i = 0; i < GDB_REGS_COUNT; i++) {
+ size_t s = DEBUG_GdbGetRegisterSize(i) / 4;
+ char word[s + 1];
+ word[s] = 0;
+ memcpy(word, data, s);
+ if (strlen(word) != s)
+ break;
+ DEBUG_GdbSetRegister(i, strtoul(word, 0, 16));
+ data += s;
+ }
+
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+
+ case 'm': { // read memory
+ char *end;
+ uint32_t addr = strtoul(data + 1, &end, 16);
+ assert(*end == ',');
+ size_t len = strtoul(end + 1, 0, 16);
+
+ char packet[len * 2 + 1];
+ char *b = packet;
+ bool err = false;
+
+ if (len % 4 == 0 && addr % 4 == 0) { // use dword access
+ for (unsigned int i = 0; i < len / 4; i++) {
+ Bit32u value;
+ err |= mem_readd_checked(addr + i * 4, &value);
+ b += sprintf(b, "%08x", swapByte32(value));
+ }
+
+ } else if (len % 2 == 0 && addr % 2 == 0) { // use word access
+ for (unsigned int i = 0; i < len / 2; i++) {
+ Bit16u value;
+ err |= mem_readw_checked(addr + i * 2, &value);
+ b += sprintf(b, "%04x", swapByte16(value));
+ }
+
+ } else { // use byte access
+ for (unsigned int i = 0; i < len ; i++) {
+ Bit8u value;
+ err |= mem_readb_checked(addr + i, &value);
+ b += sprintf(b, "%02x", value);
+ }
+ }
+
+ DEBUG_GdbWritePacket(err ? "E0d" : packet);
+ return;
+ }
+
+ case 'M': { // write memory
+ char *end;
+ uint32_t addr = strtoul(data + 1, &end, 16);
+ assert(*end == ',');
+ size_t len = strtoul(end + 1, &end, 16);
+ assert(*end == ':');
+
+ char hex[9] = { 0 };
+ bool err = false;
+
+ if (len % 4 == 0 && addr % 4 == 0) { // use dword access
+ for (unsigned int i = 0; i < len / 4; i++)
+ {
+ memcpy(hex, end + 1 + i * 8, 8);
+ err |= mem_writed_checked(addr + i, swapByte32(strtoul(hex, 0, 16)));
+ }
+
+ } else if (len % 2 == 0 && addr % 2 == 0) { // use word access
+ for (unsigned int i = 0; i < len / 2; i++)
+ {
+ memcpy(hex, end + 1 + i * 4, 4);
+ err |= mem_writew_checked(addr + i, swapByte16(strtoul(hex, 0, 16)));
+ }
+
+ } else { // use byte access
+ for (unsigned int i = 0; i < len; i++)
+ {
+ memcpy(hex, end + 1 + i * 2, 2);
+ err |= mem_writeb_checked(addr + i, strtoul(hex, 0, 16));
+ }
+ }
+
+ DEBUG_GdbWritePacket(err ? "E0d" : "OK");
+ return;
+ }
+
+ case 'c': { // continue [optional resume addr in hex]
+ if (data[1]) {
+ gdbSetEip(strtoul(data + 1, 0, 16));
+ step_next_state = GdbRunning;
+ } else {
+ // go through single step to avoid break-point on resume address
+ gdb_state = GdbStep;
+ step_next_state = GdbRunning;
+ step_eip = gdbGetEip();
+ step_cs = SegValue(cs);
+ }
+ return;
+ }
+
+ case 's': { // continue single step [optional resume addr in hex]
+ uint32_t pc;
+
+ if (data[1])
+ gdbSetEip(strtoul(data + 1, 0, 16));
+
+ gdb_state = GdbStep;
+ step_next_state = GdbStoped;
+ step_eip = gdbGetEip();
+ step_cs = SegValue(cs);
+ return;
+ }
+
+ case 'z': // set and clean break points
+ case 'Z': {
+ char *end;
+ uint32_t addr = strtoul(data + 3, &end, 16);
+ assert(*end == ',');
+ size_t len = strtoul(end + 1, 0, 16);
+
+ switch (data[1]) {
+ case '0':
+ case '1': // execution break point
+ DEBUG_GdbPointSet(break_points, addr, len, data[0] == 'Z');
+ break;
+
+ case '2': // write watch point
+ DEBUG_GdbPointSet(write_watch_points, addr, len, data[0] == 'Z');
+ break;
+
+ case '4': // access watch point
+ DEBUG_GdbPointSet(write_watch_points, addr, len, data[0] == 'Z');
+ case '3': // read watch point
+ DEBUG_GdbPointSet(read_watch_points, addr, len, data[0] == 'Z');
+ break;
+
+ default:
+ DEBUG_GdbWritePacket("");
+ return;
+ }
+
+ DEBUG_GdbWritePacket("OK");
+ return;
+ }
+
+ default:
+ break;
+ }
+
+ // empty reply if not supported
+ DEBUG_GdbWritePacket("");
+}
+
+static bool DEBUG_GdbCheckEvent(void)
+{
+ struct pollfd pf;
+ char c;
+
+ switch (gdb_state) {
+ case GdbNotConnected: // check for incoming connection
+ pf.fd = gdb_socket;
+ pf.events = POLLIN | POLLPRI;
+
+ if (poll(&pf, 1, 0) > 0) {
+ struct sockaddr_in addr;
+ socklen_t addr_size = sizeof(addr);
+
+ gdb_asocket = accept(gdb_socket, (struct sockaddr*)&addr, &addr_size);
+
+ if (gdb_asocket >= 0) {
+ gdb_state = GdbStoped;
+ return true;
+ }
+ }
+ break;
+
+ case GdbStep:
+ case GdbRunning: // try to read CTRL-C from client
+ pf.fd = gdb_asocket;
+ pf.events = POLLIN | POLLPRI;
+
+ if (poll(&pf, 1, 0) == 1 && read(gdb_asocket, &c, 1) == 1 && c == 3) {
+ DEBUG_ShowMsg("GDB: %u: break requested.\n", DEBUG_cycle_count);
+
+ gdb_state = GdbStoped;
+ DEBUG_GdbWritePacket("S02"); // sigint
+ return true;
+ }
+ break;
+ }
+
+ return false;
+}
+
+/**********************/
+/* dosbox debug stuff */
+/**********************/
+
+void DEBUG_ShowMsg(char const* format,...)
+{
+ char buf[256];
+ va_list ap;
+ int i;
+
+ va_start(ap, format);
+ i = vsnprintf(buf, sizeof(buf) - 1, format, ap);
+ buf[i] = 0;
+ va_end(ap);
+
+ // trim spaces at end
+ for (; i > 0 && buf[i] <= 32; i--)
+ buf[i] = 0;
+
+ // display message on stderr
+ fprintf(stderr, "%s\n", buf);
+
+ // send message to gdb client
+ if (gdb_state == GdbRunning || gdb_state == GdbStep || gdb_state == GdbMonitor) {
+ if (buf[0]) {
+ char _p[sizeof(buf) * 2 + 3], *p = _p;
+ int i;
+
+ *p++ = 'O';
+ for (i = 0; buf[i]; i++)
+ p += sprintf(p, "%02x", buf[i]);
+ *p++ = '0';
+ *p++ = 'a';
+ *p++ = 0;
+
+ DEBUG_GdbWritePacket(_p);
+ }
+ }
+
+}
+
+/* called when irq is raised */
+void DEBUG_IrqBreakpoint(Bit8u intNum)
+{
+ if (gdb_state == GdbRunning && int_bp[intNum]) {
+ DEBUG_ShowMsg("GDB: %u: processor hardware interrupt 0x%x.\n", DEBUG_cycle_count, intNum);
+
+ gdb_state = GdbStoped;
+ DEBUG_GdbWritePacket("S05"); // trap
+ DEBUG_EnableDebugger();
+ }
+}
+
+/* called when "int n" opcode is encountered */
+bool DEBUG_IntBreakpoint(Bit8u intNum)
+{
+ if (gdb_state == GdbRunning && int_bp[intNum]) {
+ DEBUG_ShowMsg("GDB: %u: processor software interrupt 0x%x.\n", DEBUG_cycle_count, intNum);
+
+ gdb_state = GdbStoped;
+ DEBUG_GdbWritePacket("S05"); // trap
+ return true;
+ }
+
+ return false;
+}
+
+/* called when "int3" opcode is encountered */
+bool DEBUG_Breakpoint(void)
+{
+ return DEBUG_IntBreakpoint(3);
+}
+
+static inline bool DEBUG_GdbPointCheck(const bp_map_t &b, Bit32u addr)
+{
+ bp_map_t::const_iterator i = b.lower_bound(addr);
+
+ return (i != b.end() && i->first <= addr && i->first + i->second > addr);
+}
+
+/* called for each executed instruction */
+bool DEBUG_HeavyIsBreakpoint(void)
+{
+ static Bitu last_event_check = 0;
+
+ void DEBUG_HeavyLogInstruction(void);
+ if (DEBUG_logHeavy)
+ DEBUG_HeavyLogInstruction();
+
+ /* handle single step end */
+ if (gdb_state == GdbStep && (step_eip != gdbGetEip() || step_cs != SegValue(cs))) {
+ gdb_state = step_next_state;
+
+ if (gdb_state == GdbStoped) {
+ DEBUG_GdbWritePacket("S05"); // trap
+ return true;
+ }
+ }
+
+ /* check execution breakpoints */
+ if (gdb_state == GdbRunning) {
+
+ if (DEBUG_GdbPointCheck(break_points, gdbGetEip())) {
+ DEBUG_ShowMsg("GDB: %u: hit a breakpoint.\n", DEBUG_cycle_count);
+
+ gdb_state = GdbStoped;
+ DEBUG_GdbWritePacket("S05"); // trap
+ return true;
+ }
+
+ if (cycle_bp && cycle_bp <= DEBUG_cycle_count) {
+ DEBUG_ShowMsg("GDB: %u: hit a cycle breakpoint.\n", DEBUG_cycle_count);
+
+ cycle_bp = 0;
+ gdb_state = GdbStoped;
+ DEBUG_GdbWritePacket("S05"); // trap
+ return true;
+ }
+ }
+
+ /* sometimes check for incoming gdb client connections or CTRL-C from client */
+ if (last_event_check + 16384 < DEBUG_cycle_count) {
+ last_event_check = DEBUG_cycle_count;
+ if (DEBUG_GdbCheckEvent())
+ return true;
+ }
+
+ return false;
+}
+
+void DEBUG_GdbMemReadHook(Bit32u address, int width)
+{
+ if ((gdb_state == GdbRunning || gdb_state == GdbStep) && DEBUG_GdbPointCheck(read_watch_points, address)) {
+ DEBUG_ShowMsg("GDB: %u hit a memory read access watchpoint: address=0x%08x.\n", DEBUG_cycle_count, address);
+
+ gdb_state = GdbStoped;
+ DEBUG_EnableDebugger();
+ DEBUG_GdbWritePacket("S05"); // trap
+ }
+}
+
+void DEBUG_GdbMemWriteHook(Bit32u address, int width, Bit32u value)
+{
+ if ((gdb_state == GdbRunning || gdb_state == GdbStep) && DEBUG_GdbPointCheck(write_watch_points, address)) {
+ DEBUG_ShowMsg("GDB: %u: hit a memory write access watchpoint: address=0x%08x, new_value=0x%x.\n", DEBUG_cycle_count, address, value);
+
+ gdb_state = GdbStoped;
+ DEBUG_EnableDebugger();
+ DEBUG_GdbWritePacket("S05"); // trap
+ }
+}
+
+Bitu DEBUG_Loop(void)
+{
+ GFX_Events();
+ PIC_runIRQs();
+
+ if (gdb_state == GdbStoped)
+ DEBUG_GdbProcessPackets();
+
+ if (gdb_state != GdbStoped) {
+ DEBUG_exitLoop = false;
+ DOSBOX_SetNormalLoop();
+ }
+
+ return 0;
+}
+
+bool DEBUG_ExitLoop(void)
+{
+ if (DEBUG_exitLoop) {
+ DEBUG_exitLoop = false;
+ return true;
+ }
+ return false;
+}
+
+Bitu DEBUG_EnableDebugger(void)
+{
+ DEBUG_exitLoop = true;
+ DOSBOX_SetLoop(&DEBUG_Loop);
+ return 0;
+}
+
+void DEBUG_ShutDown(Section *sec)
+{
+ close(gdb_asocket);
+ close(gdb_socket);
+}
+
+void DEBUG_Init(Section* sec)
+{
+ /* Setup callback */
+ DEBUG_debugCallback=CALLBACK_Allocate();
+ CALLBACK_Setup(DEBUG_debugCallback,DEBUG_EnableDebugger,CB_RETF,"debugger");
+
+ /* shutdown function */
+ sec->AddDestroyFunction(&DEBUG_ShutDown);
+
+ gdb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ if (gdb_socket < 0) {
+ LOG_MSG("GDB: Unable to create socket");
+ return;
+ }
+
+ int tmp = 1;
+#ifdef WIN32
+ setsockopt(gdb_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)tmp, sizeof(tmp));
+#else
+ setsockopt(gdb_socket, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
+#endif
+
+ struct sockaddr_in addr;
+
+ int i;
+ for (int i = 0; ; i++) {
+ if (i == 10) {
+ LOG_MSG("GDB: Unable to bind socket");
+ return;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_port = htons(GDB_TCP_PORT + i);
+ addr.sin_family = AF_INET;
+
+ if (bind(gdb_socket, (struct sockaddr*)&addr, sizeof (struct sockaddr_in)) >= 0)
+ break;
+ }
+
+ if (listen(gdb_socket, 1) < 0) {
+ LOG_MSG("GDB: Unable to listen");
+ return;
+ }
+
+ LOG_MSG("GDB: listening on TCP port %i", GDB_TCP_PORT + i);
+}
+
+#endif
+
diff --git a/src/debug/poll.cpp b/src/debug/poll.cpp
new file mode 100644
index 000000000..8d8657acd
--- /dev/null
+++ b/src/debug/poll.cpp
@@ -0,0 +1,595 @@
+/* Emulation for poll(2)
+ Contributed by Paolo Bonzini.
+
+ Copyright 2001-2003, 2006-2010 Free Software Foundation, Inc.
+
+ This file is part of gnulib.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Tell gcc not to warn about the (nfd < 0) tests, below. */
+#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
+# pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+
+#include <malloc.h>
+
+#include <sys/types.h>
+#include "poll.h"
+#include <errno.h>
+#include <limits.h>
+#include <assert.h>
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# define WIN32_NATIVE
+# if defined (_MSC_VER)
+# define _WIN32_WINNT 0x0502
+# endif
+# include <winsock2.h>
+# include <windows.h>
+# include <io.h>
+# include <stdio.h>
+# include <conio.h>
+#else
+# include <sys/time.h>
+# include <sys/socket.h>
+# include <sys/select.h>
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+
+#include <time.h>
+
+#ifndef INFTIM
+# define INFTIM (-1)
+#endif
+
+/* BeOS does not have MSG_PEEK. */
+#ifndef MSG_PEEK
+# define MSG_PEEK 0
+#endif
+
+#ifdef WIN32_NATIVE
+
+#define IsConsoleHandle(h) (((long) (h) & 3) == 3)
+
+static BOOL
+IsSocketHandle (HANDLE h)
+{
+ WSANETWORKEVENTS ev;
+
+ if (IsConsoleHandle (h))
+ return FALSE;
+
+ /* Under Wine, it seems that getsockopt returns 0 for pipes too.
+ WSAEnumNetworkEvents instead distinguishes the two correctly. */
+ ev.lNetworkEvents = 0xDEADBEEF;
+ WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
+ return ev.lNetworkEvents != 0xDEADBEEF;
+}
+
+/* Declare data structures for ntdll functions. */
+typedef struct _FILE_PIPE_LOCAL_INFORMATION {
+ ULONG NamedPipeType;
+ ULONG NamedPipeConfiguration;
+ ULONG MaximumInstances;
+ ULONG CurrentInstances;
+ ULONG InboundQuota;
+ ULONG ReadDataAvailable;
+ ULONG OutboundQuota;
+ ULONG WriteQuotaAvailable;
+ ULONG NamedPipeState;
+ ULONG NamedPipeEnd;
+} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
+
+typedef struct _IO_STATUS_BLOCK
+{
+ union {
+ DWORD Status;
+ PVOID Pointer;
+ } u;
+ ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+typedef enum _FILE_INFORMATION_CLASS {
+ FilePipeLocalInformation = 24
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef DWORD (WINAPI *PNtQueryInformationFile)
+ (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
+
+# ifndef PIPE_BUF
+# define PIPE_BUF 512
+# endif
+
+/* Compute revents values for file handle H. If some events cannot happen
+ for the handle, eliminate them from *P_SOUGHT. */
+
+static int
+win32_compute_revents (HANDLE h, int *p_sought)
+{
+ int i, ret, happened;
+ INPUT_RECORD *irbuffer;
+ DWORD avail, nbuffer;
+ BOOL bRet;
+ IO_STATUS_BLOCK iosb;
+ FILE_PIPE_LOCAL_INFORMATION fpli;
+ static PNtQueryInformationFile NtQueryInformationFile;
+ static BOOL once_only;
+
+ switch (GetFileType (h))
+ {
+ case FILE_TYPE_PIPE:
+ if (!once_only)
+ {
+ NtQueryInformationFile = (PNtQueryInformationFile)
+ GetProcAddress (GetModuleHandle ("ntdll.dll"),
+ "NtQueryInformationFile");
+ once_only = TRUE;
+ }
+
+ happened = 0;
+ if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
+ {
+ if (avail)
+ happened |= *p_sought & (POLLIN | POLLRDNORM);
+ }
+ else if (GetLastError () == ERROR_BROKEN_PIPE)
+ happened |= POLLHUP;
+
+ else
+ {
+ /* It was the write-end of the pipe. Check if it is writable.
+ If NtQueryInformationFile fails, optimistically assume the pipe is
+ writable. This could happen on Win9x, where NtQueryInformationFile
+ is not available, or if we inherit a pipe that doesn't permit
+ FILE_READ_ATTRIBUTES access on the write end (I think this should
+ not happen since WinXP SP2; WINE seems fine too). Otherwise,
+ ensure that enough space is available for atomic writes. */
+ memset (&iosb, 0, sizeof (iosb));
+ memset (&fpli, 0, sizeof (fpli));
+
+ if (!NtQueryInformationFile
+ || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
+ FilePipeLocalInformation)
+ || fpli.WriteQuotaAvailable >= PIPE_BUF
+ || (fpli.OutboundQuota < PIPE_BUF &&
+ fpli.WriteQuotaAvailable == fpli.OutboundQuota))
+ happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
+ }
+ return happened;
+
+ case FILE_TYPE_CHAR:
+ ret = WaitForSingleObject (h, 0);
+ if (!IsConsoleHandle (h))
+ return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
+
+ nbuffer = avail = 0;
+ bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
+ if (bRet)
+ {
+ /* Input buffer. */
+ *p_sought &= POLLIN | POLLRDNORM;
+ if (nbuffer == 0)
+ return POLLHUP;
+ if (!*p_sought)
+ return 0;
+
+ irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
+ bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
+ if (!bRet || avail == 0)
+ return POLLHUP;
+
+ for (i = 0; i < avail; i++)
+ if (irbuffer[i].EventType == KEY_EVENT)
+ return *p_sought;
+ return 0;
+ }
+ else
+ {
+ /* Screen buffer. */
+ *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
+ return *p_sought;
+ }
+
+ default:
+ ret = WaitForSingleObject (h, 0);
+ if (ret == WAIT_OBJECT_0)
+ return *p_sought & ~(POLLPRI | POLLRDBAND);
+
+ return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
+ }
+}
+
+/* Convert fd_sets returned by select into revents values. */
+
+static int
+win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
+{
+ int happened = 0;
+
+ if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
+ happened |= (POLLIN | POLLRDNORM) & sought;
+
+ else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
+ {
+ int r, error;
+
+ char data[64];
+ WSASetLastError (0);
+ r = recv (h, data, sizeof (data), MSG_PEEK);
+ error = WSAGetLastError ();
+ WSASetLastError (0);
+
+ if (r > 0 || error == WSAENOTCONN)
+ happened |= (POLLIN | POLLRDNORM) & sought;
+
+ /* Distinguish hung-up sockets from other errors. */
+ else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
+ || error == WSAECONNABORTED || error == WSAENETRESET)
+ happened |= POLLHUP;
+
+ else
+ happened |= POLLERR;
+ }
+
+ if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
+ happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
+
+ if (lNetworkEvents & FD_OOB)
+ happened |= (POLLPRI | POLLRDBAND) & sought;
+
+ return happened;
+}
+
+#else /* !MinGW */
+
+/* Convert select(2) returned fd_sets into poll(2) revents values. */
+static int
+compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
+{
+ int happened = 0;
+ if (FD_ISSET (fd, rfds))
+ {
+ int r;
+ int socket_errno;
+
+# if defined __MACH__ && defined __APPLE__
+ /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
+ for some kinds of descriptors. Detect if this descriptor is a
+ connected socket, a server socket, or something else using a
+ 0-byte recv, and use ioctl(2) to detect POLLHUP. */
+ r = recv (fd, NULL, 0, MSG_PEEK);
+ socket_errno = (r < 0) ? errno : 0;
+ if (r == 0 || socket_errno == ENOTSOCK)
+ ioctl (fd, FIONREAD, &r);
+# else
+ char data[64];
+ r = recv (fd, data, sizeof (data), MSG_PEEK);
+ socket_errno = (r < 0) ? errno : 0;
+# endif
+ if (r == 0)
+ happened |= POLLHUP;
+
+ /* If the event happened on an unconnected server socket,
+ that's fine. */
+ else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
+ happened |= (POLLIN | POLLRDNORM) & sought;
+
+ /* Distinguish hung-up sockets from other errors. */
+ else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
+ || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
+ happened |= POLLHUP;
+
+ else
+ happened |= POLLERR;
+ }
+
+ if (FD_ISSET (fd, wfds))
+ happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
+
+ if (FD_ISSET (fd, efds))
+ happened |= (POLLPRI | POLLRDBAND) & sought;
+
+ return happened;
+}
+#endif /* !MinGW */
+
+int poll (struct pollfd *pfd, nfds_t nfd, int timeout)
+{
+#ifndef WIN32_NATIVE
+ fd_set rfds, wfds, efds;
+ struct timeval tv;
+ struct timeval *ptv;
+ int maxfd, rc;
+ nfds_t i;
+
+# ifdef _SC_OPEN_MAX
+ static int sc_open_max = -1;
+
+ if (nfd < 0
+ || (nfd > sc_open_max
+ && (sc_open_max != -1
+ || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+# else /* !_SC_OPEN_MAX */
+# ifdef OPEN_MAX
+ if (nfd < 0 || nfd > OPEN_MAX)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+# endif /* OPEN_MAX -- else, no check is needed */
+# endif /* !_SC_OPEN_MAX */
+
+ /* EFAULT is not necessary to implement, but let's do it in the
+ simplest case. */
+ if (!pfd)
+ {
+ errno = EFAULT;
+ return -1;
+ }
+
+ /* convert timeout number into a timeval structure */
+ if (timeout == 0)
+ {
+ ptv = &tv;
+ ptv->tv_sec = 0;
+ ptv->tv_usec = 0;
+ }
+ else if (timeout > 0)
+ {
+ ptv = &tv;
+ ptv->tv_sec = timeout / 1000;
+ ptv->tv_usec = (timeout % 1000) * 1000;
+ }
+ else if (timeout == INFTIM)
+ /* wait forever */
+ ptv = NULL;
+ else
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* create fd sets and determine max fd */
+ maxfd = -1;
+ FD_ZERO (&rfds);
+ FD_ZERO (&wfds);
+ FD_ZERO (&efds);
+ for (i = 0; i < nfd; i++)
+ {
+ if (pfd[i].fd < 0)
+ continue;
+
+ if (pfd[i].events & (POLLIN | POLLRDNORM))
+ FD_SET (pfd[i].fd, &rfds);
+
+ /* see select(2): "the only exceptional condition detectable
+ is out-of-band data received on a socket", hence we push
+ POLLWRBAND events onto wfds instead of efds. */
+ if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
+ FD_SET (pfd[i].fd, &wfds);
+ if (pfd[i].events & (POLLPRI | POLLRDBAND))
+ FD_SET (pfd[i].fd, &efds);
+ if (pfd[i].fd >= maxfd
+ && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
+ | POLLRDNORM | POLLRDBAND
+ | POLLWRNORM | POLLWRBAND)))
+ {
+ maxfd = pfd[i].fd;
+ if (maxfd > FD_SETSIZE)
+ {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ }
+ }
+
+ /* examine fd sets */
+ rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
+ if (rc < 0)
+ return rc;
+
+ /* establish results */
+ rc = 0;
+ for (i = 0; i < nfd; i++)
+ if (pfd[i].fd < 0)
+ pfd[i].revents = 0;
+ else
+ {
+ int happened = compute_revents (pfd[i].fd, pfd[i].events,
+ &rfds, &wfds, &efds);
+ if (happened)
+ {
+ pfd[i].revents = happened;
+ rc++;
+ }
+ }
+
+ return rc;
+#else
+ static struct timeval tv0;
+ static HANDLE hEvent;
+ WSANETWORKEVENTS ev;
+ HANDLE h, handle_array[FD_SETSIZE + 2];
+ DWORD ret, wait_timeout, nhandles;
+ fd_set rfds, wfds, xfds;
+ BOOL poll_again;
+ MSG msg;
+ int rc = 0;
+ nfds_t i;
+
+ if (nfd < 0 || timeout < -1)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!hEvent)
+ hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
+
+ handle_array[0] = hEvent;
+ nhandles = 1;
+ FD_ZERO (&rfds);
+ FD_ZERO (&wfds);
+ FD_ZERO (&xfds);
+
+ /* Classify socket handles and create fd sets. */
+ for (i = 0; i < nfd; i++)
+ {
+ int sought = pfd[i].events;
+ pfd[i].revents = 0;
+ if (pfd[i].fd < 0)
+ continue;
+ if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
+ | POLLPRI | POLLRDBAND)))
+ continue;
+
+ h = (HANDLE) _get_osfhandle (pfd[i].fd);
+ assert (h != NULL);
+ if (IsSocketHandle (h))
+ {
+ int requested = FD_CLOSE;
+
+ /* see above; socket handles are mapped onto select. */
+ if (sought & (POLLIN | POLLRDNORM))
+ {
+ requested |= FD_READ | FD_ACCEPT;
+ FD_SET ((SOCKET) h, &rfds);
+ }
+ if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
+ {
+ requested |= FD_WRITE | FD_CONNECT;
+ FD_SET ((SOCKET) h, &wfds);
+ }
+ if (sought & (POLLPRI | POLLRDBAND))
+ {
+ requested |= FD_OOB;
+ FD_SET ((SOCKET) h, &xfds);
+ }
+
+ if (requested)
+ WSAEventSelect ((SOCKET) h, hEvent, requested);
+ }
+ else
+ {
+ /* Poll now. If we get an event, do not poll again. Also,
+ screen buffer handles are waitable, and they'll block until
+ a character is available. win32_compute_revents eliminates
+ bits for the "wrong" direction. */
+ pfd[i].revents = win32_compute_revents (h, &sought);
+ if (sought)
+ handle_array[nhandles++] = h;
+ if (pfd[i].revents)
+ timeout = 0;
+ }
+ }
+
+ if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
+ {
+ /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
+ no need to call select again. */
+ poll_again = FALSE;
+ wait_timeout = 0;
+ }
+ else
+ {
+ poll_again = TRUE;
+ if (timeout == INFTIM)
+ wait_timeout = INFINITE;
+ else
+ wait_timeout = timeout;
+ }
+
+ for (;;)
+ {
+ ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
+ wait_timeout, QS_ALLINPUT);
+
+ if (ret == WAIT_OBJECT_0 + nhandles)
+ {
+ /* new input of some other kind */
+ BOOL bRet;
+ while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
+ {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+ }
+ else
+ break;
+ }
+
+ if (poll_again)
+ select (0, &rfds, &wfds, &xfds, &tv0);
+
+ /* Place a sentinel at the end of the array. */
+ handle_array[nhandles] = NULL;
+ nhandles = 1;
+ for (i = 0; i < nfd; i++)
+ {
+ int happened;
+
+ if (pfd[i].fd < 0)
+ continue;
+ if (!(pfd[i].events & (POLLIN | POLLRDNORM |
+ POLLOUT | POLLWRNORM | POLLWRBAND)))
+ continue;
+
+ h = (HANDLE) _get_osfhandle (pfd[i].fd);
+ if (h != handle_array[nhandles])
+ {
+ /* It's a socket. */
+ WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
+ WSAEventSelect ((SOCKET) h, 0, 0);
+
+ /* If we're lucky, WSAEnumNetworkEvents already provided a way
+ to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
+ if (FD_ISSET ((SOCKET) h, &rfds)
+ && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
+ ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
+ if (FD_ISSET ((SOCKET) h, &wfds))
+ ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
+ if (FD_ISSET ((SOCKET) h, &xfds))
+ ev.lNetworkEvents |= FD_OOB;
+
+ happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
+ ev.lNetworkEvents);
+ }
+ else
+ {
+ /* Not a socket. */
+ int sought = pfd[i].events;
+ happened = win32_compute_revents (h, &sought);
+ nhandles++;
+ }
+
+ if ((pfd[i].revents |= happened) != 0)
+ rc++;
+ }
+
+ return rc;
+#endif
+}
diff --git a/src/debug/poll.h b/src/debug/poll.h
new file mode 100644
index 000000000..72305368e
--- /dev/null
+++ b/src/debug/poll.h
@@ -0,0 +1,60 @@
+/* Header for poll(2) emulation
+ Contributed by Paolo Bonzini.
+
+ Copyright 2001, 2002, 2003, 2007, 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of gnulib.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _GL_POLL_H
+#define _GL_POLL_H
+
+#include <string.h>
+
+/* fake a poll(2) environment */
+#define POLLIN 0x0001 /* any readable data available */
+#define POLLPRI 0x0002 /* OOB/Urgent readable data */
+#define POLLOUT 0x0004 /* file descriptor is writeable */
+#define POLLERR 0x0008 /* some poll error occurred */
+#define POLLHUP 0x0010 /* file descriptor was "hung up" */
+#define POLLNVAL 0x0020 /* requested events "invalid" */
+#define POLLRDNORM 0x0040
+#define POLLRDBAND 0x0080
+#define POLLWRNORM 0x0100
+#define POLLWRBAND 0x0200
+
+#define MSG_WAITALL 0
+#define MSG_DONTWAIT 0x40
+#define MSG_NOSIGNAL 0x400
+
+struct pollfd
+{
+ int fd; /* which file descriptor to poll */
+ short events; /* events we are interested in */
+ short revents; /* events found on return */
+};
+
+typedef unsigned long nfds_t;
+typedef int socklen_t;
+
+extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout);
+
+/* Define INFTIM only if doing so conforms to POSIX. */
+#if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE)
+#define INFTIM (-1)
+#endif
+
+#endif /* _GL_POLL_H */
diff --git a/src/dos/dos_execute.cpp b/src/dos/dos_execute.cpp
index da43a4052..ed1a57bd0 100644
--- a/src/dos/dos_execute.cpp
+++ b/src/dos/dos_execute.cpp
@@ -476,7 +476,7 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) {
reg_di=RealOff(sssp);
reg_bp=0x91c; /* DOS internal stack begin relict */
SegSet16(ds,pspseg);SegSet16(es,pspseg);
-#if C_DEBUG
+#if C_DEBUG
/* Started from debug.com, then set breakpoint at start */
DEBUG_CheckExecuteBreakpoint(RealSeg(csip),RealOff(csip));
#endif
diff --git a/src/dos/dos_execute.cpp.orig b/src/dos/dos_execute.cpp.orig
new file mode 100644
index 000000000..da43a4052
--- /dev/null
+++ b/src/dos/dos_execute.cpp.orig
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2002-2011 The DOSBox Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include <string.h>
+#include <ctype.h>
+#include "dosbox.h"
+#include "mem.h"
+#include "dos_inc.h"
+#include "regs.h"
+#include "callback.h"
+#include "debug.h"
+#include "cpu.h"
+
+const char * RunningProgram="DOSBOX";
+
+#ifdef _MSC_VER
+#pragma pack(1)
+#endif
+struct EXE_Header {
+ Bit16u signature; /* EXE Signature MZ or ZM */
+ Bit16u extrabytes; /* Bytes on the last page */
+ Bit16u pages; /* Pages in file */
+ Bit16u relocations; /* Relocations in file */
+ Bit16u headersize; /* Paragraphs in header */
+ Bit16u minmemory; /* Minimum amount of memory */
+ Bit16u maxmemory; /* Maximum amount of memory */
+ Bit16u initSS;
+ Bit16u initSP;
+ Bit16u checksum;
+ Bit16u initIP;
+ Bit16u initCS;
+ Bit16u reloctable;
+ Bit16u overlay;
+} GCC_ATTRIBUTE(packed);
+#ifdef _MSC_VER
+#pragma pack()
+#endif
+
+#define MAGIC1 0x5a4d
+#define MAGIC2 0x4d5a
+#define MAXENV 32768u
+#define ENV_KEEPFREE 83 /* keep unallocated by environment variables */
+#define LOADNGO 0
+#define LOAD 1
+#define OVERLAY 3
+
+
+
+static void SaveRegisters(void) {
+ reg_sp-=18;
+ mem_writew(SegPhys(ss)+reg_sp+ 0,reg_ax);
+ mem_writew(SegPhys(ss)+reg_sp+ 2,reg_cx);
+ mem_writew(SegPhys(ss)+reg_sp+ 4,reg_dx);
+ mem_writew(SegPhys(ss)+reg_sp+ 6,reg_bx);
+ mem_writew(SegPhys(ss)+reg_sp+ 8,reg_si);
+ mem_writew(SegPhys(ss)+reg_sp+10,reg_di);
+ mem_writew(SegPhys(ss)+reg_sp+12,reg_bp);
+ mem_writew(SegPhys(ss)+reg_sp+14,SegValue(ds));
+ mem_writew(SegPhys(ss)+reg_sp+16,SegValue(es));
+}
+
+static void RestoreRegisters(void) {
+ reg_ax=mem_readw(SegPhys(ss)+reg_sp+ 0);
+ reg_cx=mem_readw(SegPhys(ss)+reg_sp+ 2);
+ reg_dx=mem_readw(SegPhys(ss)+reg_sp+ 4);
+ reg_bx=mem_readw(SegPhys(ss)+reg_sp+ 6);
+ reg_si=mem_readw(SegPhys(ss)+reg_sp+ 8);
+ reg_di=mem_readw(SegPhys(ss)+reg_sp+10);
+ reg_bp=mem_readw(SegPhys(ss)+reg_sp+12);
+ SegSet16(ds,mem_readw(SegPhys(ss)+reg_sp+14));
+ SegSet16(es,mem_readw(SegPhys(ss)+reg_sp+16));
+ reg_sp+=18;
+}
+
+extern void GFX_SetTitle(Bit32s cycles,Bits frameskip,bool paused);
+void DOS_UpdatePSPName(void) {
+ DOS_MCB mcb(dos.psp()-1);
+ static char name[9];
+ mcb.GetFileName(name);
+ name[8] = 0;
+ if (!strlen(name)) strcpy(name,"DOSBOX");
+ for(Bitu i = 0;i < 8;i++) { //Don't put garbage in the title bar. Mac OS X doesn't like it
+ if (name[i] == 0) break;
+ if ( !isprint(*reinterpret_cast<unsigned char*>(&name[i])) ) name[i] = '?';
+ }
+ RunningProgram = name;
+ GFX_SetTitle(-1,-1,false);
+}
+
+void DOS_Terminate(Bit16u pspseg,bool tsr,Bit8u exitcode) {
+
+ dos.return_code=exitcode;
+ dos.return_mode=(tsr)?(Bit8u)RETURN_TSR:(Bit8u)RETURN_EXIT;
+
+ DOS_PSP curpsp(pspseg);
+ if (pspseg==curpsp.GetParent()) return;
+ /* Free Files owned by process */
+ if (!tsr) curpsp.CloseFiles();
+
+ /* Get the termination address */
+ RealPt old22 = curpsp.GetInt22();
+ /* Restore vector 22,23,24 */
+ curpsp.RestoreVectors();
+ /* Set the parent PSP */
+ dos.psp(curpsp.GetParent());
+ DOS_PSP parentpsp(curpsp.GetParent());
+
+ /* Restore the SS:SP to the previous one */
+ SegSet16(ss,RealSeg(parentpsp.GetStack()));
+ reg_sp = RealOff(parentpsp.GetStack());
+ /* Restore the old CS:IP from int 22h */
+ RestoreRegisters();
+ /* Set the CS:IP stored in int 0x22 back on the stack */
+ mem_writew(SegPhys(ss)+reg_sp+0,RealOff(old22));
+ mem_writew(SegPhys(ss)+reg_sp+2,RealSeg(old22));
+ /* set IOPL=3 (Strike Commander), nested task set,
+ interrupts enabled, test flags cleared */
+ mem_writew(SegPhys(ss)+reg_sp+4,0x7202);
+ // Free memory owned by process
+ if (!tsr) DOS_FreeProcessMemory(pspseg);
+ DOS_UpdatePSPName();
+
+ if ((!(CPU_AutoDetermineMode>>CPU_AUTODETERMINE_SHIFT)) || (cpu.pmode)) return;
+
+ CPU_AutoDetermineMode>>=CPU_AUTODETERMINE_SHIFT;
+ if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CYCLES) {
+ CPU_CycleAutoAdjust=false;
+ CPU_CycleLeft=0;
+ CPU_Cycles=0;
+ CPU_CycleMax=CPU_OldCycleMax;
+ GFX_SetTitle(CPU_OldCycleMax,-1,false);
+ } else {
+ GFX_SetTitle(-1,-1,false);
+ }
+#if (C_DYNAMIC_X86) || (C_DYNREC)
+ if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CORE) {
+ cpudecoder=&CPU_Core_Normal_Run;
+ CPU_CycleLeft=0;
+ CPU_Cycles=0;
+ }
+#endif
+
+ return;
+}
+
+static bool MakeEnv(char * name,Bit16u * segment) {
+ /* If segment to copy environment is 0 copy the caller's environment */
+ DOS_PSP psp(dos.psp());
+ PhysPt envread,envwrite;
+ Bit16u envsize=1;
+ bool parentenv=true;
+
+ if (*segment==0) {
+ if (!psp.GetEnvironment()) parentenv=false; //environment seg=0
+ envread=PhysMake(psp.GetEnvironment(),0);
+ } else {
+ if (!*segment) parentenv=false; //environment seg=0
+ envread=PhysMake(*segment,0);
+ }
+
+ if (parentenv) {
+ for (envsize=0; ;envsize++) {
+ if (envsize>=MAXENV - ENV_KEEPFREE) {
+ DOS_SetError(DOSERR_ENVIRONMENT_INVALID);
+ return false;
+ }
+ if (mem_readw(envread+envsize)==0) break;
+ }
+ envsize += 2; /* account for trailing \0\0 */
+ }
+ Bit16u size=long2para(envsize+ENV_KEEPFREE);
+ if (!DOS_AllocateMemory(segment,&size)) return false;
+ envwrite=PhysMake(*segment,0);
+ if (parentenv) {
+ MEM_BlockCopy(envwrite,envread,envsize);
+// mem_memcpy(envwrite,envread,envsize);
+ envwrite+=envsize;
+ } else {
+ mem_writeb(envwrite++,0);
+ }
+ mem_writew(envwrite,1);
+ envwrite+=2;
+ char namebuf[DOS_PATHLENGTH];
+ if (DOS_Canonicalize(name,namebuf)) {
+ MEM_BlockWrite(envwrite,namebuf,(Bitu)(strlen(namebuf)+1));
+ return true;
+ } else return false;
+}
+
+bool DOS_NewPSP(Bit16u segment, Bit16u size) {
+ DOS_PSP psp(segment);
+ psp.MakeNew(size);
+ Bit16u parent_psp_seg=psp.GetParent();
+ DOS_PSP psp_parent(parent_psp_seg);
+ psp.CopyFileTable(&psp_parent,false);
+ // copy command line as well (Kings Quest AGI -cga switch)
+ psp.SetCommandTail(RealMake(parent_psp_seg,0x80));
+ return true;
+}
+
+bool DOS_ChildPSP(Bit16u segment, Bit16u size) {
+ DOS_PSP psp(segment);
+ psp.MakeNew(size);
+ Bit16u parent_psp_seg = psp.GetParent();
+ DOS_PSP psp_parent(parent_psp_seg);
+ psp.CopyFileTable(&psp_parent,true);
+ psp.SetCommandTail(RealMake(parent_psp_seg,0x80));
+ psp.SetFCB1(RealMake(parent_psp_seg,0x5c));
+ psp.SetFCB2(RealMake(parent_psp_seg,0x6c));
+ psp.SetEnvironment(psp_parent.GetEnvironment());
+ psp.SetSize(size);
+ return true;
+}
+
+static void SetupPSP(Bit16u pspseg,Bit16u memsize,Bit16u envseg) {
+ /* Fix the PSP for psp and environment MCB's */
+ DOS_MCB mcb((Bit16u)(pspseg-1));
+ mcb.SetPSPSeg(pspseg);
+ mcb.SetPt((Bit16u)(envseg-1));
+ mcb.SetPSPSeg(pspseg);
+
+ DOS_PSP psp(pspseg);
+ psp.MakeNew(memsize);
+ psp.SetEnvironment(envseg);
+
+ /* Copy file handles */
+ DOS_PSP oldpsp(dos.psp());
+ psp.CopyFileTable(&oldpsp,true);
+
+}
+
+static void SetupCMDLine(Bit16u pspseg,DOS_ParamBlock & block) {
+ DOS_PSP psp(pspseg);
+ // if cmdtail==0 it will inited as empty in SetCommandTail
+ psp.SetCommandTail(block.exec.cmdtail);
+}
+
+bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) {
+ EXE_Header head;Bitu i;
+ Bit16u fhandle;Bit16u len;Bit32u pos;
+ Bit16u pspseg,envseg,loadseg,memsize,readsize;
+ PhysPt loadaddress;RealPt relocpt;
+ Bitu headersize=0,imagesize=0;
+ DOS_ParamBlock block(block_pt);
+
+ block.LoadData();
+ //Remove the loadhigh flag for the moment!
+ if(flags&0x80) LOG(LOG_EXEC,LOG_ERROR)("using loadhigh flag!!!!!. dropping it");
+ flags &= 0x7f;
+ if (flags!=LOADNGO && flags!=OVERLAY && flags!=LOAD) {
+ DOS_SetError(DOSERR_FORMAT_INVALID);
+ return false;
+// E_Exit("DOS:Not supported execute mode %d for file %s",flags,name);
+ }
+ /* Check for EXE or COM File */
+ bool iscom=false;
+ if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) {
+ DOS_SetError(DOSERR_FILE_NOT_FOUND);
+ return false;
+ }
+ len=sizeof(EXE_Header);
+ if (!DOS_ReadFile(fhandle,(Bit8u *)&head,&len)) {
+ DOS_CloseFile(fhandle);
+ return false;
+ }
+ if (len<sizeof(EXE_Header)) {
+ if (len==0) {
+ /* Prevent executing zero byte files */
+ DOS_SetError(DOSERR_ACCESS_DENIED);
+ DOS_CloseFile(fhandle);
+ return false;
+ }
+ /* Otherwise must be a .com file */
+ iscom=true;
+ } else {
+ /* Convert the header to correct endian, i hope this works */
+ HostPt endian=(HostPt)&head;
+ for (i=0;i<sizeof(EXE_Header)/2;i++) {
+ *((Bit16u *)endian)=host_readw(endian);
+ endian+=2;
+ }
+ if ((head.signature!=MAGIC1) && (head.signature!=MAGIC2)) iscom=true;
+ else {
+ if(head.pages & ~0x07ff) /* 1 MB dos maximum address limit. Fixes TC3 IDE (kippesoep) */
+ LOG(LOG_EXEC,LOG_NORMAL)("Weird header: head.pages > 1 MB");
+ head.pages&=0x07ff;
+ headersize = head.headersize*16;
+ imagesize = head.pages*512-headersize;
+ if (imagesize+headersize<512) imagesize = 512-headersize;
+ }
+ }
+ Bit8u * loadbuf=(Bit8u *)new Bit8u[0x10000];
+ if (flags!=OVERLAY) {
+ /* Create an environment block */
+ envseg=block.exec.envseg;
+ if (!MakeEnv(name,&envseg)) {
+ DOS_CloseFile(fhandle);
+ return false;
+ }
+ /* Get Memory */
+ Bit16u minsize,maxsize;Bit16u maxfree=0xffff;DOS_AllocateMemory(&pspseg,&maxfree);
+ if (iscom) {
+ minsize=0x1000;maxsize=0xffff;
+ if (machine==MCH_PCJR) {
+ /* try to load file into memory below 96k */
+ pos=0;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET);
+ Bit16u dataread=0x1800;
+ DOS_ReadFile(fhandle,loadbuf,&dataread);
+ if (dataread<0x1800) maxsize=dataread;
+ if (minsize>maxsize) minsize=maxsize;
+ }
+ } else { /* Exe size calculated from header */
+ minsize=long2para(imagesize+(head.minmemory<<4)+256);
+ if (head.maxmemory!=0) maxsize=long2para(imagesize+(head.maxmemory<<4)+256);
+ else maxsize=0xffff;
+ }
+ if (maxfree<minsize) {
+ if (iscom) {
+ /* Reduce minimum of needed memory size to filesize */
+ pos=0;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET);
+ Bit16u dataread=0xf800;
+ DOS_ReadFile(fhandle,loadbuf,&dataread);
+ if (dataread<0xf800) minsize=((dataread+0x10)>>4)+0x20;
+ }
+ if (maxfree<minsize) {
+ DOS_CloseFile(fhandle);
+ DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
+ DOS_FreeMemory(envseg);
+ return false;
+ }
+ }
+ if (maxfree<maxsize) memsize=maxfree;
+ else memsize=maxsize;
+ if (!DOS_AllocateMemory(&pspseg,&memsize)) E_Exit("DOS:Exec error in memory");
+ if (iscom && (machine==MCH_PCJR) && (pspseg<0x2000)) {
+ maxsize=0xffff;
+ /* resize to full extent of memory block */
+ DOS_ResizeMemory(pspseg,&maxsize);
+ /* now try to lock out memory above segment 0x2000 */
+ if ((real_readb(0x2000,0)==0x5a) && (real_readw(0x2000,1)==0) && (real_readw(0x2000,3)==0x7ffe)) {
+ /* MCB after PCJr graphics memory region is still free */
+ if (pspseg+maxsize==0x17ff) {
+ DOS_MCB cmcb((Bit16u)(pspseg-1));
+ cmcb.SetType(0x5a); // last block
+ }
+ }
+ }
+ loadseg=pspseg+16;
+ if (!iscom) {
+ /* Check if requested to load program into upper part of allocated memory */
+ if ((head.minmemory == 0) && (head.maxmemory == 0))
+ loadseg = (Bit16u)(((pspseg+memsize)*0x10-imagesize)/0x10);
+ }
+ } else loadseg=block.overlay.loadseg;
+ /* Load the executable */
+ loadaddress=PhysMake(loadseg,0);
+
+ if (iscom) { /* COM Load 64k - 256 bytes max */
+ pos=0;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET);
+ readsize=0xffff-256;
+ DOS_ReadFile(fhandle,loadbuf,&readsize);
+ MEM_BlockWrite(loadaddress,loadbuf,readsize);
+ } else { /* EXE Load in 32kb blocks and then relocate */
+ pos=headersize;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET);
+ while (imagesize>0x7FFF) {
+ readsize=0x8000;DOS_ReadFile(fhandle,loadbuf,&readsize);
+ MEM_BlockWrite(loadaddress,loadbuf,readsize);
+// if (readsize!=0x8000) LOG(LOG_EXEC,LOG_NORMAL)("Illegal header");
+ loadaddress+=0x8000;imagesize-=0x8000;
+ }
+ if (imagesize>0) {
+ readsize=(Bit16u)imagesize;DOS_ReadFile(fhandle,loadbuf,&readsize);
+ MEM_BlockWrite(loadaddress,loadbuf,readsize);
+// if (readsize!=imagesize) LOG(LOG_EXEC,LOG_NORMAL)("Illegal header");
+ }
+ /* Relocate the exe image */
+ Bit16u relocate;
+ if (flags==OVERLAY) relocate=block.overlay.relocation;
+ else relocate=loadseg;
+ pos=head.reloctable;DOS_SeekFile(fhandle,&pos,0);
+ for (i=0;i<head.relocations;i++) {
+ readsize=4;DOS_ReadFile(fhandle,(Bit8u *)&relocpt,&readsize);
+ relocpt=host_readd((HostPt)&relocpt); //Endianize
+ PhysPt address=PhysMake(RealSeg(relocpt)+loadseg,RealOff(relocpt));
+ mem_writew(address,mem_readw(address)+relocate);
+ }
+ }
+ delete[] loadbuf;
+ DOS_CloseFile(fhandle);
+
+ /* Setup a psp */
+ if (flags!=OVERLAY) {
+ // Create psp after closing exe, to avoid dead file handle of exe in copied psp
+ SetupPSP(pspseg,memsize,envseg);
+ SetupCMDLine(pspseg,block);
+ };
+ CALLBACK_SCF(false); /* Carry flag cleared for caller if successfull */
+ if (flags==OVERLAY) return true; /* Everything done for overlays */
+ RealPt csip,sssp;
+ if (iscom) {
+ csip=RealMake(pspseg,0x100);
+ sssp=RealMake(pspseg,0xfffe);
+ mem_writew(PhysMake(pspseg,0xfffe),0);
+ } else {
+ csip=RealMake(loadseg+head.initCS,head.initIP);
+ sssp=RealMake(loadseg+head.initSS,head.initSP);
+ if (head.initSP<4) LOG(LOG_EXEC,LOG_ERROR)("stack underflow/wrap at EXEC");
+ }
+
+ if (flags==LOAD) {
+ SaveRegisters();
+ DOS_PSP callpsp(dos.psp());
+ /* Save the SS:SP on the PSP of calling program */
+ callpsp.SetStack(RealMakeSeg(ss,reg_sp));
+ reg_sp+=18;
+ /* Switch the psp's */
+ dos.psp(pspseg);
+ DOS_PSP newpsp(dos.psp());
+ dos.dta(RealMake(newpsp.GetSegment(),0x80));
+ /* First word on the stack is the value ax should contain on startup */
+ real_writew(RealSeg(sssp-2),RealOff(sssp-2),0xffff);
+ block.exec.initsssp = sssp-2;
+ block.exec.initcsip = csip;
+ block.SaveData();
+ return true;
+ }
+
+ if (flags==LOADNGO) {
+ if ((reg_sp>0xfffe) || (reg_sp<18)) LOG(LOG_EXEC,LOG_ERROR)("stack underflow/wrap at EXEC");
+ /* Get Caller's program CS:IP of the stack and set termination address to that */
+ RealSetVec(0x22,RealMake(mem_readw(SegPhys(ss)+reg_sp+2),mem_readw(SegPhys(ss)+reg_sp)));
+ SaveRegisters();
+ DOS_PSP callpsp(dos.psp());
+ /* Save the SS:SP on the PSP of calling program */
+ callpsp.SetStack(RealMakeSeg(ss,reg_sp));
+ /* Switch the psp's and set new DTA */
+ dos.psp(pspseg);
+ DOS_PSP newpsp(dos.psp());
+ dos.dta(RealMake(newpsp.GetSegment(),0x80));
+ /* save vectors */
+ newpsp.SaveVectors();
+ /* copy fcbs */
+ newpsp.SetFCB1(block.exec.fcb1);
+ newpsp.SetFCB2(block.exec.fcb2);
+ /* Set the stack for new program */
+ SegSet16(ss,RealSeg(sssp));reg_sp=RealOff(sssp);
+ /* Add some flags and CS:IP on the stack for the IRET */
+ CPU_Push16(RealSeg(csip));
+ CPU_Push16(RealOff(csip));
+ /* DOS starts programs with a RETF, so critical flags
+ * should not be modified (IOPL in v86 mode);
+ * interrupt flag is set explicitly, test flags cleared */
+ reg_flags=(reg_flags&(~FMASK_TEST))|FLAG_IF;
+ //Jump to retf so that we only need to store cs:ip on the stack
+ reg_ip++;
+ /* Setup the rest of the registers */
+ reg_ax=reg_bx=0;reg_cx=0xff;
+ reg_dx=pspseg;
+ reg_si=RealOff(csip);
+ reg_di=RealOff(sssp);
+ reg_bp=0x91c; /* DOS internal stack begin relict */
+ SegSet16(ds,pspseg);SegSet16(es,pspseg);
+#if C_DEBUG
+ /* Started from debug.com, then set breakpoint at start */
+ DEBUG_CheckExecuteBreakpoint(RealSeg(csip),RealOff(csip));
+#endif
+ /* Add the filename to PSP and environment MCB's */
+ char stripname[8]= { 0 };Bitu index=0;
+ while (char chr=*name++) {
+ switch (chr) {
+ case ':':case '\\':case '/':index=0;break;
+ default:if (index<8) stripname[index++]=(char)toupper(chr);
+ }
+ }
+ index=0;
+ while (index<8) {
+ if (stripname[index]=='.') break;
+ if (!stripname[index]) break;
+ index++;
+ }
+ memset(&stripname[index],0,8-index);
+ DOS_MCB pspmcb(dos.psp()-1);
+ pspmcb.SetFileName(stripname);
+ DOS_UpdatePSPName();
+ return true;
+ }
+ return false;
+}
diff --git a/src/dosbox.cpp b/src/dosbox.cpp
index 9e31162b5..e83dc1d40 100644
--- a/src/dosbox.cpp
+++ b/src/dosbox.cpp
@@ -140,7 +140,7 @@ static Bitu Normal_Loop(void) {
Bitu blah = (*CallBack_Handlers[ret])();
if (GCC_UNLIKELY(blah)) return blah;
}
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
if (DEBUG_ExitLoop()) return 0;
#endif
} else {
@@ -350,7 +350,7 @@ void DOSBOX_Init(void) {
Pstring = secprop->Add_path("captures",Property::Changeable::Always,"capture");
Pstring->Set_help("Directory where things like wave, midi, screenshot get captured.");
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
LOG_StartUp();
#endif
@@ -496,7 +496,7 @@ void DOSBOX_Init(void) {
" In that case, add 'delaysysex', for example: midiconfig=2 delaysysex\n"
" See the README/Manual for more details.");
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
secprop=control->AddSection_prop("debug",&DEBUG_Init);
#endif
diff --git a/src/gui/sdlmain.cpp b/src/gui/sdlmain.cpp
index 58cd8e4ce..e1e1a61a3 100644
--- a/src/gui/sdlmain.cpp
+++ b/src/gui/sdlmain.cpp
@@ -1334,7 +1334,7 @@ static void GUI_StartUp(Section * sec) {
MAPPER_AddHandler(CaptureMouse,MK_f10,MMOD1,"capmouse","Cap Mouse");
MAPPER_AddHandler(SwitchFullScreen,MK_return,MMOD2,"fullscr","Fullscreen");
MAPPER_AddHandler(Restart,MK_home,MMOD1|MMOD2,"restart","Restart");
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
/* Pause binds with activate-debugger */
#else
MAPPER_AddHandler(&PauseDOSBox, MK_pause, MMOD2, "pause", "Pause");
@@ -1698,7 +1698,7 @@ static void launcheditor() {
printf("can't find editor(s) specified at the command line.\n");
exit(1);
}
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
extern void DEBUG_ShutDown(Section * /*sec*/);
#endif
@@ -1712,7 +1712,7 @@ void restart_program(std::vector<std::string> & parameters) {
SDL_CloseAudio();
SDL_Delay(50);
SDL_Quit();
-#if C_DEBUG
+#if C_DEBUG || C_GDBSERVER
// shutdown curses
DEBUG_ShutDown(NULL);
#endif
diff --git a/src/gui/sdlmain.cpp.orig b/src/gui/sdlmain.cpp.orig
new file mode 100644
index 000000000..58cd8e4ce
--- /dev/null
+++ b/src/gui/sdlmain.cpp.orig
@@ -0,0 +1,2057 @@
+/*
+ * Copyright (C) 2002-2011 The DOSBox Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#ifdef WIN32
+#include <signal.h>
+#include <process.h>
+#endif
+
+#include "cross.h"
+#include "SDL.h"
+
+#include "dosbox.h"
+#include "video.h"
+#include "mouse.h"
+#include "pic.h"
+#include "timer.h"
+#include "setup.h"
+#include "support.h"
+#include "debug.h"
+#include "mapper.h"
+#include "vga.h"
+#include "keyboard.h"
+#include "cpu.h"
+#include "cross.h"
+#include "control.h"
+
+#define MAPPERFILE "mapper-" VERSION ".map"
+//#define DISABLE_JOYSTICK
+
+#if C_OPENGL
+#include "SDL_opengl.h"
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+
+#ifdef __WIN32__
+#define NVIDIA_PixelDataRange 1
+
+#ifndef WGL_NV_allocate_memory
+#define WGL_NV_allocate_memory 1
+typedef void * (APIENTRY * PFNWGLALLOCATEMEMORYNVPROC) (int size, float readfreq, float writefreq, float priority);
+typedef void (APIENTRY * PFNWGLFREEMEMORYNVPROC) (void *pointer);
+#endif
+
+PFNWGLALLOCATEMEMORYNVPROC db_glAllocateMemoryNV = NULL;
+PFNWGLFREEMEMORYNVPROC db_glFreeMemoryNV = NULL;
+
+#else
+
+#endif
+
+#if defined(NVIDIA_PixelDataRange)
+
+#ifndef GL_NV_pixel_data_range
+#define GL_NV_pixel_data_range 1
+#define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878
+typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer);
+typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target);
+#endif
+
+PFNGLPIXELDATARANGENVPROC glPixelDataRangeNV = NULL;
+
+#endif
+
+#endif //C_OPENGL
+
+#if !(ENVIRON_INCLUDED)
+extern char** environ;
+#endif
+
+#ifdef WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#if (HAVE_DDRAW_H)
+#include <ddraw.h>
+struct private_hwdata {
+ LPDIRECTDRAWSURFACE3 dd_surface;
+ LPDIRECTDRAWSURFACE3 dd_writebuf;
+};
+#endif
+
+#define STDOUT_FILE TEXT("stdout.txt")
+#define STDERR_FILE TEXT("stderr.txt")
+#define DEFAULT_CONFIG_FILE "/dosbox.conf"
+#elif defined(MACOSX)
+#define DEFAULT_CONFIG_FILE "/Library/Preferences/DOSBox Preferences"
+#else /*linux freebsd*/
+#define DEFAULT_CONFIG_FILE "/.dosboxrc"
+#endif
+
+#if C_SET_PRIORITY
+#include <sys/resource.h>
+#define PRIO_TOTAL (PRIO_MAX-PRIO_MIN)
+#endif
+
+#ifdef OS2
+#define INCL_DOS
+#define INCL_WIN
+#include <os2.h>
+#endif
+
+enum SCREEN_TYPES {
+ SCREEN_SURFACE,
+ SCREEN_SURFACE_DDRAW,
+ SCREEN_OVERLAY,
+ SCREEN_OPENGL
+};
+
+enum PRIORITY_LEVELS {
+ PRIORITY_LEVEL_PAUSE,
+ PRIORITY_LEVEL_LOWEST,
+ PRIORITY_LEVEL_LOWER,
+ PRIORITY_LEVEL_NORMAL,
+ PRIORITY_LEVEL_HIGHER,
+ PRIORITY_LEVEL_HIGHEST
+};
+
+
+struct SDL_Block {
+ bool inited;
+ bool active; //If this isn't set don't draw
+ bool updating;
+ struct {
+ Bit32u width;
+ Bit32u height;
+ Bit32u bpp;
+ Bitu flags;
+ double scalex,scaley;
+ GFX_CallBack_t callback;
+ } draw;
+ bool wait_on_error;
+ struct {
+ struct {
+ Bit16u width, height;
+ bool fixed;
+ } full;
+ struct {
+ Bit16u width, height;
+ } window;
+ Bit8u bpp;
+ bool fullscreen;
+ bool lazy_fullscreen;
+ bool lazy_fullscreen_req;
+ bool doublebuf;
+ SCREEN_TYPES type;
+ SCREEN_TYPES want_type;
+ } desktop;
+#if C_OPENGL
+ struct {
+ Bitu pitch;
+ void * framebuf;
+ GLuint texture;
+ GLuint displaylist;
+ GLint max_texsize;
+ bool bilinear;
+ bool packed_pixel;
+ bool paletted_texture;
+#if defined(NVIDIA_PixelDataRange)
+ bool pixel_data_range;
+#endif
+ } opengl;
+#endif
+ struct {
+ SDL_Surface * surface;
+#if (HAVE_DDRAW_H) && defined(WIN32)
+ RECT rect;
+#endif
+ } blit;
+ struct {
+ PRIORITY_LEVELS focus;
+ PRIORITY_LEVELS nofocus;
+ } priority;
+ SDL_Rect clip;
+ SDL_Surface * surface;
+ SDL_Overlay * overlay;
+ SDL_cond *cond;
+ struct {
+ bool autolock;
+ bool autoenable;
+ bool requestlock;
+ bool locked;
+ Bitu sensitivity;
+ } mouse;
+ SDL_Rect updateRects[1024];
+ Bitu num_joysticks;
+#if defined (WIN32)
+ bool using_windib;
+#endif
+ // state of alt-keys for certain special handlings
+ Bit8u laltstate;
+ Bit8u raltstate;
+};
+
+static SDL_Block sdl;
+
+extern const char* RunningProgram;
+extern bool CPU_CycleAutoAdjust;
+//Globals for keyboard initialisation
+bool startup_state_numlock=false;
+bool startup_state_capslock=false;
+void GFX_SetTitle(Bit32s cycles,Bits frameskip,bool paused){
+ char title[200]={0};
+ static Bit32s internal_cycles=0;
+ static Bits internal_frameskip=0;
+ if(cycles != -1) internal_cycles = cycles;
+ if(frameskip != -1) internal_frameskip = frameskip;
+ if(CPU_CycleAutoAdjust) {
+ sprintf(title,"DOSBox %s, CPU speed: max %3d%% cycles, Frameskip %2d, Program: %8s",VERSION,internal_cycles,internal_frameskip,RunningProgram);
+ } else {
+ sprintf(title,"DOSBox %s, CPU speed: %8d cycles, Frameskip %2d, Program: %8s",VERSION,internal_cycles,internal_frameskip,RunningProgram);
+ }
+
+ if(paused) strcat(title," PAUSED");
+ SDL_WM_SetCaption(title,VERSION);
+}
+
+static void KillSwitch(bool pressed) {
+ if (!pressed)
+ return;
+ throw 1;
+}
+
+static void PauseDOSBox(bool pressed) {
+ if (!pressed)
+ return;
+ GFX_SetTitle(-1,-1,true);
+ bool paused = true;
+ KEYBOARD_ClrBuffer();
+ SDL_Delay(500);
+ SDL_Event event;
+ while (SDL_PollEvent(&event)) {
+ // flush event queue.
+ }
+
+ while (paused) {
+ SDL_WaitEvent(&event); // since we're not polling, cpu usage drops to 0.
+ switch (event.type) {
+
+ case SDL_QUIT: KillSwitch(true); break;
+ case SDL_KEYDOWN: // Must use Pause/Break Key to resume.
+ case SDL_KEYUP:
+ if(event.key.keysym.sym == SDLK_PAUSE) {
+
+ paused = false;
+ GFX_SetTitle(-1,-1,false);
+ break;
+ }
+#if defined (MACOSX)
+ if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod == KMOD_RMETA || event.key.keysym.mod == KMOD_LMETA) ) {
+ /* On macs, all aps exit when pressing cmd-q */
+ KillSwitch(true);
+ break;
+ }
+#endif
+ }
+ }
+}
+
+#if defined (WIN32)
+bool GFX_SDLUsingWinDIB(void) {
+ return sdl.using_windib;
+}
+#endif
+
+/* Reset the screen with current values in the sdl structure */
+Bitu GFX_GetBestMode(Bitu flags) {
+ Bitu testbpp,gotbpp;
+ switch (sdl.desktop.want_type) {
+ case SCREEN_SURFACE:
+check_surface:
+ flags &= ~GFX_LOVE_8; //Disable love for 8bpp modes
+ /* Check if we can satisfy the depth it loves */
+ if (flags & GFX_LOVE_8) testbpp=8;
+ else if (flags & GFX_LOVE_15) testbpp=15;
+ else if (flags & GFX_LOVE_16) testbpp=16;
+ else if (flags & GFX_LOVE_32) testbpp=32;
+ else testbpp=0;
+#if (HAVE_DDRAW_H) && defined(WIN32)
+check_gotbpp:
+#endif
+ if (sdl.desktop.fullscreen) gotbpp=SDL_VideoModeOK(640,480,testbpp,SDL_FULLSCREEN|SDL_HWSURFACE|SDL_HWPALETTE);
+ else gotbpp=sdl.desktop.bpp;
+ /* If we can't get our favorite mode check for another working one */
+ switch (gotbpp) {
+ case 8:
+ if (flags & GFX_CAN_8) flags&=~(GFX_CAN_15|GFX_CAN_16|GFX_CAN_32);
+ break;
+ case 15:
+ if (flags & GFX_CAN_15) flags&=~(GFX_CAN_8|GFX_CAN_16|GFX_CAN_32);
+ break;
+ case 16:
+ if (flags & GFX_CAN_16) flags&=~(GFX_CAN_8|GFX_CAN_15|GFX_CAN_32);
+ break;
+ case 24:
+ case 32:
+ if (flags & GFX_CAN_32) flags&=~(GFX_CAN_8|GFX_CAN_15|GFX_CAN_16);
+ break;
+ }
+ flags |= GFX_CAN_RANDOM;
+ break;
+#if (HAVE_DDRAW_H) && defined(WIN32)
+ case SCREEN_SURFACE_DDRAW:
+ if (!(flags&(GFX_CAN_15|GFX_CAN_16|GFX_CAN_32))) goto check_surface;
+ if (flags & GFX_LOVE_15) testbpp=15;
+ else if (flags & GFX_LOVE_16) testbpp=16;
+ else if (flags & GFX_LOVE_32) testbpp=32;
+ else testbpp=0;
+ flags|=GFX_SCALING;
+ goto check_gotbpp;
+#endif
+ case SCREEN_OVERLAY:
+ if (flags & GFX_RGBONLY || !(flags&GFX_CAN_32)) goto check_surface;
+ flags|=GFX_SCALING;
+ flags&=~(GFX_CAN_8|GFX_CAN_15|GFX_CAN_16);
+ break;
+#if C_OPENGL
+ case SCREEN_OPENGL:
+ if (flags & GFX_RGBONLY || !(flags&GFX_CAN_32)) goto check_surface;
+ flags|=GFX_SCALING;
+ flags&=~(GFX_CAN_8|GFX_CAN_15|GFX_CAN_16);
+ break;
+#endif
+ default:
+ goto check_surface;
+ break;
+ }
+ return flags;
+}
+
+
+void GFX_ResetScreen(void) {
+ GFX_Stop();
+ if (sdl.draw.callback)
+ (sdl.draw.callback)( GFX_CallBackReset );
+ GFX_Start();
+ CPU_Reset_AutoAdjust();
+}
+
+void GFX_ForceFullscreenExit(void) {
+ if (sdl.desktop.lazy_fullscreen) {
+// sdl.desktop.lazy_fullscreen_req=true;
+ LOG_MSG("GFX LF: invalid screen change");
+ } else {
+ sdl.desktop.fullscreen=false;
+ GFX_ResetScreen();
+ }
+}
+
+static int int_log2 (int val) {
+ int log = 0;
+ while ((val >>= 1) != 0)
+ log++;
+ return log;
+}
+
+
+static SDL_Surface * GFX_SetupSurfaceScaled(Bit32u sdl_flags, Bit32u bpp) {
+ Bit16u fixedWidth;
+ Bit16u fixedHeight;
+
+ if (sdl.desktop.fullscreen) {
+ fixedWidth = sdl.desktop.full.fixed ? sdl.desktop.full.width : 0;
+ fixedHeight = sdl.desktop.full.fixed ? sdl.desktop.full.height : 0;
+ sdl_flags |= SDL_FULLSCREEN|SDL_HWSURFACE;
+ } else {
+ fixedWidth = sdl.desktop.window.width;
+ fixedHeight = sdl.desktop.window.height;
+ sdl_flags |= SDL_HWSURFACE;
+ }
+ if (fixedWidth && fixedHeight) {
+ double ratio_w=(double)fixedWidth/(sdl.draw.width*sdl.draw.scalex);
+ double ratio_h=(double)fixedHeight/(sdl.draw.height*sdl.draw.scaley);
+ if ( ratio_w < ratio_h) {
+ sdl.clip.w=fixedWidth;
+ sdl.clip.h=(Bit16u)(sdl.draw.height*sdl.draw.scaley*ratio_w);
+ } else {
+ sdl.clip.w=(Bit16u)(sdl.draw.width*sdl.draw.scalex*ratio_h);
+ sdl.clip.h=(Bit16u)fixedHeight;
+ }
+ if (sdl.desktop.fullscreen)
+ sdl.surface = SDL_SetVideoMode(fixedWidth,fixedHeight,bpp,sdl_flags);
+ else
+ sdl.surface = SDL_SetVideoMode(sdl.clip.w,sdl.clip.h,bpp,sdl_flags);
+ if (sdl.surface && sdl.surface->flags & SDL_FULLSCREEN) {
+ sdl.clip.x=(Sint16)((sdl.surface->w-sdl.clip.w)/2);
+ sdl.clip.y=(Sint16)((sdl.surface->h-sdl.clip.h)/2);
+ } else {
+ sdl.clip.x = 0;
+ sdl.clip.y = 0;
+ }
+ return sdl.surface;
+ } else {
+ sdl.clip.x=0;sdl.clip.y=0;
+ sdl.clip.w=(Bit16u)(sdl.draw.width*sdl.draw.scalex);
+ sdl.clip.h=(Bit16u)(sdl.draw.height*sdl.draw.scaley);
+ sdl.surface=SDL_SetVideoMode(sdl.clip.w,sdl.clip.h,bpp,sdl_flags);
+ return sdl.surface;
+ }
+}
+
+void GFX_TearDown(void) {
+ if (sdl.updating)
+ GFX_EndUpdate( 0 );
+
+ if (sdl.blit.surface) {
+ SDL_FreeSurface(sdl.blit.surface);
+ sdl.blit.surface=0;
+ }
+}
+
+Bitu GFX_SetSize(Bitu width,Bitu height,Bitu flags,double scalex,double scaley,GFX_CallBack_t callback) {
+ if (sdl.updating)
+ GFX_EndUpdate( 0 );
+
+ sdl.draw.width=width;
+ sdl.draw.height=height;
+ sdl.draw.callback=callback;
+ sdl.draw.scalex=scalex;
+ sdl.draw.scaley=scaley;
+
+ Bitu bpp=0;
+ Bitu retFlags = 0;
+
+ if (sdl.blit.surface) {
+ SDL_FreeSurface(sdl.blit.surface);
+ sdl.blit.surface=0;
+ }
+ switch (sdl.desktop.want_type) {
+ case SCREEN_SURFACE:
+dosurface:
+ if (flags & GFX_CAN_8) bpp=8;
+ if (flags & GFX_CAN_15) bpp=15;
+ if (flags & GFX_CAN_16) bpp=16;
+ if (flags & GFX_CAN_32) bpp=32;
+ sdl.desktop.type=SCREEN_SURFACE;
+ sdl.clip.w=width;
+ sdl.clip.h=height;
+ if (sdl.desktop.fullscreen) {
+ if (sdl.desktop.full.fixed) {
+ sdl.clip.x=(Sint16)((sdl.desktop.full.width-width)/2);
+ sdl.clip.y=(Sint16)((sdl.desktop.full.height-height)/2);
+ sdl.surface=SDL_SetVideoMode(sdl.desktop.full.width,sdl.desktop.full.height,bpp,
+ SDL_FULLSCREEN | ((flags & GFX_CAN_RANDOM) ? SDL_SWSURFACE : SDL_HWSURFACE) |
+ (sdl.desktop.doublebuf ? SDL_DOUBLEBUF|SDL_ASYNCBLIT : 0) | SDL_HWPALETTE);
+ if (sdl.surface == NULL) E_Exit("Could not set fullscreen video mode %ix%i-%i: %s",sdl.desktop.full.width,sdl.desktop.full.height,bpp,SDL_GetError());
+ } else {
+ sdl.clip.x=0;sdl.clip.y=0;
+ sdl.surface=SDL_SetVideoMode(width,height,bpp,
+ SDL_FULLSCREEN | ((flags & GFX_CAN_RANDOM) ? SDL_SWSURFACE : SDL_HWSURFACE) |
+ (sdl.desktop.doublebuf ? SDL_DOUBLEBUF|SDL_ASYNCBLIT : 0)|SDL_HWPALETTE);
+ if (sdl.surface == NULL)
+ E_Exit("Could not set fullscreen video mode %ix%i-%i: %s",width,height,bpp,SDL_GetError());
+ }
+ } else {
+ sdl.clip.x=0;sdl.clip.y=0;
+ sdl.surface=SDL_SetVideoMode(width,height,bpp,(flags & GFX_CAN_RANDOM) ? SDL_SWSURFACE : SDL_HWSURFACE);
+#ifdef WIN32
+ if (sdl.surface == NULL) {
+ SDL_QuitSubSystem(SDL_INIT_VIDEO);
+ if (!sdl.using_windib) {
+ LOG_MSG("Failed to create hardware surface.\nRestarting video subsystem with windib enabled.");
+ putenv("SDL_VIDEODRIVER=windib");
+ sdl.using_windib=true;
+ } else {
+ LOG_MSG("Failed to create hardware surface.\nRestarting video subsystem with directx enabled.");
+ putenv("SDL_VIDEODRIVER=directx");
+ sdl.using_windib=false;
+ }
+ SDL_InitSubSystem(SDL_INIT_VIDEO);
+ sdl.surface = SDL_SetVideoMode(width,height,bpp,SDL_HWSURFACE);
+ }
+#endif
+ if (sdl.surface == NULL)
+ E_Exit("Could not set windowed video mode %ix%i-%i: %s",width,height,bpp,SDL_GetError());
+ }
+ if (sdl.surface) {
+ switch (sdl.surface->format->BitsPerPixel) {
+ case 8:
+ retFlags = GFX_CAN_8;
+ break;
+ case 15:
+ retFlags = GFX_CAN_15;
+ break;
+ case 16:
+ retFlags = GFX_CAN_16;
+ break;
+ case 32:
+ retFlags = GFX_CAN_32;
+ break;
+ }
+ if (retFlags && (sdl.surface->flags & SDL_HWSURFACE))
+ retFlags |= GFX_HARDWARE;
+ if (retFlags && (sdl.surface->flags & SDL_DOUBLEBUF)) {
+ sdl.blit.surface=SDL_CreateRGBSurface(SDL_HWSURFACE,
+ sdl.draw.width, sdl.draw.height,
+ sdl.surface->format->BitsPerPixel,
+ sdl.surface->format->Rmask,
+ sdl.surface->format->Gmask,
+ sdl.surface->format->Bmask,
+ 0);
+ /* If this one fails be ready for some flickering... */
+ }
+ }
+ break;
+#if (HAVE_DDRAW_H) && defined(WIN32)
+ case SCREEN_SURFACE_DDRAW:
+ if (flags & GFX_CAN_15) bpp=15;
+ if (flags & GFX_CAN_16) bpp=16;
+ if (flags & GFX_CAN_32) bpp=32;
+ if (!GFX_SetupSurfaceScaled((sdl.desktop.doublebuf && sdl.desktop.fullscreen) ? SDL_DOUBLEBUF : 0,bpp)) goto dosurface;
+ sdl.blit.rect.top=sdl.clip.y;
+ sdl.blit.rect.left=sdl.clip.x;
+ sdl.blit.rect.right=sdl.clip.x+sdl.clip.w;
+ sdl.blit.rect.bottom=sdl.clip.y+sdl.clip.h;
+ sdl.blit.surface=SDL_CreateRGBSurface(SDL_HWSURFACE,sdl.draw.width,sdl.draw.height,
+ sdl.surface->format->BitsPerPixel,
+ sdl.surface->format->Rmask,
+ sdl.surface->format->Gmask,
+ sdl.surface->format->Bmask,
+ 0);
+ if (!sdl.blit.surface || (!sdl.blit.surface->flags&SDL_HWSURFACE)) {
+ if (sdl.blit.surface) {
+ SDL_FreeSurface(sdl.blit.surface);
+ sdl.blit.surface=0;
+ }
+ LOG_MSG("Failed to create ddraw surface, back to normal surface.");
+ goto dosurface;
+ }
+ switch (sdl.surface->format->BitsPerPixel) {
+ case 15:
+ retFlags = GFX_CAN_15 | GFX_SCALING | GFX_HARDWARE;
+ break;
+ case 16:
+ retFlags = GFX_CAN_16 | GFX_SCALING | GFX_HARDWARE;
+ break;
+ case 32:
+ retFlags = GFX_CAN_32 | GFX_SCALING | GFX_HARDWARE;
+ break;
+ }
+ sdl.desktop.type=SCREEN_SURFACE_DDRAW;
+ break;
+#endif
+ case SCREEN_OVERLAY:
+ if (sdl.overlay) {
+ SDL_FreeYUVOverlay(sdl.overlay);
+ sdl.overlay=0;
+ }
+ if (!(flags&GFX_CAN_32) || (flags & GFX_RGBONLY)) goto dosurface;
+ if (!GFX_SetupSurfaceScaled(0,0)) goto dosurface;
+ sdl.overlay=SDL_CreateYUVOverlay(width*2,height,SDL_UYVY_OVERLAY,sdl.surface);
+ if (!sdl.overlay) {
+ LOG_MSG("SDL:Failed to create overlay, switching back to surface");
+ goto dosurface;
+ }
+ sdl.desktop.type=SCREEN_OVERLAY;
+ retFlags = GFX_CAN_32 | GFX_SCALING | GFX_HARDWARE;
+ break;
+#if C_OPENGL
+ case SCREEN_OPENGL:
+ {
+ if (sdl.opengl.framebuf) {
+#if defined(NVIDIA_PixelDataRange)
+ if (sdl.opengl.pixel_data_range) db_glFreeMemoryNV(sdl.opengl.framebuf);
+ else
+#endif
+ free(sdl.opengl.framebuf);
+ }
+ sdl.opengl.framebuf=0;
+ if (!(flags&GFX_CAN_32) || (flags & GFX_RGBONLY)) goto dosurface;
+ int texsize=2 << int_log2(width > height ? width : height);
+ if (texsize>sdl.opengl.max_texsize) {
+ LOG_MSG("SDL:OPENGL:No support for texturesize of %d, falling back to surface",texsize);
+ goto dosurface;
+ }
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
+#if defined (WIN32) && SDL_VERSION_ATLEAST(1, 2, 11)
+ SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 0 );
+#endif
+ GFX_SetupSurfaceScaled(SDL_OPENGL,0);
+ if (!sdl.surface || sdl.surface->format->BitsPerPixel<15) {
+ LOG_MSG("SDL:OPENGL:Can't open drawing surface, are you running in 16bpp(or higher) mode?");
+ goto dosurface;
+ }
+ /* Create the texture and display list */
+#if defined(NVIDIA_PixelDataRange)
+ if (sdl.opengl.pixel_data_range) {
+ sdl.opengl.framebuf=db_glAllocateMemoryNV(width*height*4,0.0,1.0,1.0);
+ glPixelDataRangeNV(GL_WRITE_PIXEL_DATA_RANGE_NV,width*height*4,sdl.opengl.framebuf);
+ glEnableClientState(GL_WRITE_PIXEL_DATA_RANGE_NV);
+ } else {
+#else
+ {
+#endif
+ sdl.opengl.framebuf=malloc(width*height*4); //32 bit color
+ }
+ sdl.opengl.pitch=width*4;
+ glViewport(sdl.clip.x,sdl.clip.y,sdl.clip.w,sdl.clip.h);
+ glMatrixMode (GL_PROJECTION);
+ glDeleteTextures(1,&sdl.opengl.texture);
+ glGenTextures(1,&sdl.opengl.texture);
+ glBindTexture(GL_TEXTURE_2D,sdl.opengl.texture);
+ // No borders
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ if (sdl.opengl.bilinear) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texsize, texsize, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, 0);
+
+ glClearColor (0.0, 0.0, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ SDL_GL_SwapBuffers();
+ glClear(GL_COLOR_BUFFER_BIT);
+ glShadeModel (GL_FLAT);
+ glDisable (GL_DEPTH_TEST);
+ glDisable (GL_LIGHTING);
+ glDisable(GL_CULL_FACE);
+ glEnable(GL_TEXTURE_2D);
+ glMatrixMode (GL_MODELVIEW);
+ glLoadIdentity ();
+
+ GLfloat tex_width=((GLfloat)(width)/(GLfloat)texsize);
+ GLfloat tex_height=((GLfloat)(height)/(GLfloat)texsize);
+
+ if (glIsList(sdl.opengl.displaylist)) glDeleteLists(sdl.opengl.displaylist, 1);
+ sdl.opengl.displaylist = glGenLists(1);
+ glNewList(sdl.opengl.displaylist, GL_COMPILE);
+ glBindTexture(GL_TEXTURE_2D, sdl.opengl.texture);
+ glBegin(GL_QUADS);
+ // lower left
+ glTexCoord2f(0,tex_height); glVertex2f(-1.0f,-1.0f);
+ // lower right
+ glTexCoord2f(tex_width,tex_height); glVertex2f(1.0f, -1.0f);
+ // upper right
+ glTexCoord2f(tex_width,0); glVertex2f(1.0f, 1.0f);
+ // upper left
+ glTexCoord2f(0,0); glVertex2f(-1.0f, 1.0f);
+ glEnd();
+ glEndList();
+ sdl.desktop.type=SCREEN_OPENGL;
+ retFlags = GFX_CAN_32 | GFX_SCALING;
+#if defined(NVIDIA_PixelDataRange)
+ if (sdl.opengl.pixel_data_range)
+ retFlags |= GFX_HARDWARE;
+#endif
+ break;
+ }//OPENGL
+#endif //C_OPENGL
+ default:
+ goto dosurface;
+ break;
+ }//CASE
+ if (retFlags)
+ GFX_Start();
+ if (!sdl.mouse.autoenable) SDL_ShowCursor(sdl.mouse.autolock?SDL_DISABLE:SDL_ENABLE);
+ return retFlags;
+}
+
+void GFX_CaptureMouse(void) {
+ sdl.mouse.locked=!sdl.mouse.locked;
+ if (sdl.mouse.locked) {
+ SDL_WM_GrabInput(SDL_GRAB_ON);
+ SDL_ShowCursor(SDL_DISABLE);
+ } else {
+ SDL_WM_GrabInput(SDL_GRAB_OFF);
+ if (sdl.mouse.autoenable || !sdl.mouse.autolock) SDL_ShowCursor(SDL_ENABLE);
+ }
+ mouselocked=sdl.mouse.locked;
+}
+
+void GFX_UpdateSDLCaptureState(void) {
+ if (sdl.mouse.locked) {
+ SDL_WM_GrabInput(SDL_GRAB_ON);
+ SDL_ShowCursor(SDL_DISABLE);
+ } else {
+ SDL_WM_GrabInput(SDL_GRAB_OFF);
+ if (sdl.mouse.autoenable || !sdl.mouse.autolock) SDL_ShowCursor(SDL_ENABLE);
+ }
+ CPU_Reset_AutoAdjust();
+ GFX_SetTitle(-1,-1,false);
+}
+
+bool mouselocked; //Global variable for mapper
+static void CaptureMouse(bool pressed) {
+ if (!pressed)
+ return;
+ GFX_CaptureMouse();
+}
+
+#if defined (WIN32)
+STICKYKEYS stick_keys = {sizeof(STICKYKEYS), 0};
+void sticky_keys(bool restore){
+ static bool inited = false;
+ if (!inited){
+ inited = true;
+ SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &stick_keys, 0);
+ }
+ if (restore) {
+ SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &stick_keys, 0);
+ return;
+ }
+ //Get current sticky keys layout:
+ STICKYKEYS s = {sizeof(STICKYKEYS), 0};
+ SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &s, 0);
+ if ( !(s.dwFlags & SKF_STICKYKEYSON)) { //Not on already
+ s.dwFlags &= ~SKF_HOTKEYACTIVE;
+ SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &s, 0);
+ }
+}
+#endif
+
+void GFX_SwitchFullScreen(void) {
+ sdl.desktop.fullscreen=!sdl.desktop.fullscreen;
+ if (sdl.desktop.fullscreen) {
+ if (!sdl.mouse.locked) GFX_CaptureMouse();
+#if defined (WIN32)
+ sticky_keys(false); //disable sticky keys in fullscreen mode
+#endif
+ } else {
+ if (sdl.mouse.locked) GFX_CaptureMouse();
+#if defined (WIN32)
+ sticky_keys(true); //restore sticky keys to default state in windowed mode.
+#endif
+ }
+ GFX_ResetScreen();
+}
+
+static void SwitchFullScreen(bool pressed) {
+ if (!pressed)
+ return;
+
+ if (sdl.desktop.lazy_fullscreen) {
+// sdl.desktop.lazy_fullscreen_req=true;
+ LOG_MSG("GFX LF: fullscreen switching not supported");
+ } else {
+ GFX_SwitchFullScreen();
+ }
+}
+
+void GFX_SwitchLazyFullscreen(bool lazy) {
+ sdl.desktop.lazy_fullscreen=lazy;
+ sdl.desktop.lazy_fullscreen_req=false;
+}
+
+void GFX_SwitchFullscreenNoReset(void) {
+ sdl.desktop.fullscreen=!sdl.desktop.fullscreen;
+}
+
+bool GFX_LazyFullscreenRequested(void) {
+ if (sdl.desktop.lazy_fullscreen) return sdl.desktop.lazy_fullscreen_req;
+ return false;
+}
+
+void GFX_RestoreMode(void) {
+ GFX_SetSize(sdl.draw.width,sdl.draw.height,sdl.draw.flags,sdl.draw.scalex,sdl.draw.scaley,sdl.draw.callback);
+ GFX_UpdateSDLCaptureState();
+}
+
+
+bool GFX_StartUpdate(Bit8u * & pixels,Bitu & pitch) {
+ if (!sdl.active || sdl.updating)
+ return false;
+ switch (sdl.desktop.type) {
+ case SCREEN_SURFACE:
+ if (sdl.blit.surface) {
+ if (SDL_MUSTLOCK(sdl.blit.surface) && SDL_LockSurface(sdl.blit.surface))
+ return false;
+ pixels=(Bit8u *)sdl.blit.surface->pixels;
+ pitch=sdl.blit.surface->pitch;
+ } else {
+ if (SDL_MUSTLOCK(sdl.surface) && SDL_LockSurface(sdl.surface))
+ return false;
+ pixels=(Bit8u *)sdl.surface->pixels;
+ pixels+=sdl.clip.y*sdl.surface->pitch;
+ pixels+=sdl.clip.x*sdl.surface->format->BytesPerPixel;
+ pitch=sdl.surface->pitch;
+ }
+ sdl.updating=true;
+ return true;
+#if (HAVE_DDRAW_H) && defined(WIN32)
+ case SCREEN_SURFACE_DDRAW:
+ if (SDL_LockSurface(sdl.blit.surface)) {
+// LOG_MSG("SDL Lock failed");
+ return false;
+ }
+ pixels=(Bit8u *)sdl.blit.surface->pixels;
+ pitch=sdl.blit.surface->pitch;
+ sdl.updating=true;
+ return true;
+#endif
+ case SCREEN_OVERLAY:
+ if (SDL_LockYUVOverlay(sdl.overlay)) return false;
+ pixels=(Bit8u *)*(sdl.overlay->pixels);
+ pitch=*(sdl.overlay->pitches);
+ sdl.updating=true;
+ return true;
+#if C_OPENGL
+ case SCREEN_OPENGL:
+ pixels=(Bit8u *)sdl.opengl.framebuf;
+ pitch=sdl.opengl.pitch;
+ sdl.updating=true;
+ return true;
+#endif
+ default:
+ break;
+ }
+ return false;
+}
+
+
+void GFX_EndUpdate( const Bit16u *changedLines ) {
+#if (HAVE_DDRAW_H) && defined(WIN32)
+ int ret;
+#endif
+ if (!sdl.updating)
+ return;
+ sdl.updating=false;
+ switch (sdl.desktop.type) {
+ case SCREEN_SURFACE:
+ if (SDL_MUSTLOCK(sdl.surface)) {
+ if (sdl.blit.surface) {
+ SDL_UnlockSurface(sdl.blit.surface);
+ int Blit = SDL_BlitSurface( sdl.blit.surface, 0, sdl.surface, &sdl.clip );
+ LOG(LOG_MISC,LOG_WARN)("BlitSurface returned %d",Blit);
+ } else {
+ SDL_UnlockSurface(sdl.surface);
+ }
+ SDL_Flip(sdl.surface);
+ } else if (changedLines) {
+ Bitu y = 0, index = 0, rectCount = 0;
+ while (y < sdl.draw.height) {
+ if (!(index & 1)) {
+ y += changedLines[index];
+ } else {
+ SDL_Rect *rect = &sdl.updateRects[rectCount++];
+ rect->x = sdl.clip.x;
+ rect->y = sdl.clip.y + y;
+ rect->w = (Bit16u)sdl.draw.width;
+ rect->h = changedLines[index];
+#if 0
+ if (rect->h + rect->y > sdl.surface->h) {
+ LOG_MSG("WTF %d + %d >%d",rect->h,rect->y,sdl.surface->h);
+ }
+#endif
+ y += changedLines[index];
+ }
+ index++;
+ }
+ if (rectCount)
+ SDL_UpdateRects( sdl.surface, rectCount, sdl.updateRects );
+ }
+ break;
+#if (HAVE_DDRAW_H) && defined(WIN32)
+ case SCREEN_SURFACE_DDRAW:
+ SDL_UnlockSurface(sdl.blit.surface);
+ ret=IDirectDrawSurface3_Blt(
+ sdl.surface->hwdata->dd_writebuf,&sdl.blit.rect,
+ sdl.blit.surface->hwdata->dd_surface,0,
+ DDBLT_WAIT, NULL);
+ switch (ret) {
+ case DD_OK:
+ break;
+ case DDERR_SURFACELOST:
+ IDirectDrawSurface3_Restore(sdl.blit.surface->hwdata->dd_surface);
+ IDirectDrawSurface3_Restore(sdl.surface->hwdata->dd_surface);
+ break;
+ default:
+ LOG_MSG("DDRAW:Failed to blit, error %X",ret);
+ }
+ SDL_Flip(sdl.surface);
+ break;
+#endif
+ case SCREEN_OVERLAY:
+ SDL_UnlockYUVOverlay(sdl.overlay);
+ SDL_DisplayYUVOverlay(sdl.overlay,&sdl.clip);
+ break;
+#if C_OPENGL
+ case SCREEN_OPENGL:
+#if defined(NVIDIA_PixelDataRange)
+ if (sdl.opengl.pixel_data_range) {
+ glBindTexture(GL_TEXTURE_2D, sdl.opengl.texture);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
+ sdl.draw.width, sdl.draw.height, GL_BGRA_EXT,
+ GL_UNSIGNED_INT_8_8_8_8_REV, sdl.opengl.framebuf);
+ glCallList(sdl.opengl.displaylist);
+ SDL_GL_SwapBuffers();
+ } else
+#endif
+ if (changedLines) {
+ Bitu y = 0, index = 0;
+ glBindTexture(GL_TEXTURE_2D, sdl.opengl.texture);
+ while (y < sdl.draw.height) {
+ if (!(index & 1)) {
+ y += changedLines[index];
+ } else {
+ Bit8u *pixels = (Bit8u *)sdl.opengl.framebuf + y * sdl.opengl.pitch;
+ Bitu height = changedLines[index];
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, y,
+ sdl.draw.width, height, GL_BGRA_EXT,
+ GL_UNSIGNED_INT_8_8_8_8_REV, pixels );
+ y += height;
+ }
+ index++;
+ }
+ glCallList(sdl.opengl.displaylist);
+ SDL_GL_SwapBuffers();
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+
+void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries) {
+ /* I should probably not change the GFX_PalEntry :) */
+ if (sdl.surface->flags & SDL_HWPALETTE) {
+ if (!SDL_SetPalette(sdl.surface,SDL_PHYSPAL,(SDL_Color *)entries,start,count)) {
+ E_Exit("SDL:Can't set palette");
+ }
+ } else {
+ if (!SDL_SetPalette(sdl.surface,SDL_LOGPAL,(SDL_Color *)entries,start,count)) {
+ E_Exit("SDL:Can't set palette");
+ }
+ }
+}
+
+Bitu GFX_GetRGB(Bit8u red,Bit8u green,Bit8u blue) {
+ switch (sdl.desktop.type) {
+ case SCREEN_SURFACE:
+ case SCREEN_SURFACE_DDRAW:
+ return SDL_MapRGB(sdl.surface->format,red,green,blue);
+ case SCREEN_OVERLAY:
+ {
+ Bit8u y = ( 9797*(red) + 19237*(green) + 3734*(blue) ) >> 15;
+ Bit8u u = (18492*((blue)-(y)) >> 15) + 128;
+ Bit8u v = (23372*((red)-(y)) >> 15) + 128;
+#ifdef WORDS_BIGENDIAN
+ return (y << 0) | (v << 8) | (y << 16) | (u << 24);
+#else
+ return (u << 0) | (y << 8) | (v << 16) | (y << 24);
+#endif
+ }
+ case SCREEN_OPENGL:
+// return ((red << 0) | (green << 8) | (blue << 16)) | (255 << 24);
+ //USE BGRA
+ return ((blue << 0) | (green << 8) | (red << 16)) | (255 << 24);
+ }
+ return 0;
+}
+
+void GFX_Stop() {
+ if (sdl.updating)
+ GFX_EndUpdate( 0 );
+ sdl.active=false;
+}
+
+void GFX_Start() {
+ sdl.active=true;
+}
+
+static void GUI_ShutDown(Section * /*sec*/) {
+ GFX_Stop();
+ if (sdl.draw.callback) (sdl.draw.callback)( GFX_CallBackStop );
+ if (sdl.mouse.locked) GFX_CaptureMouse();
+ if (sdl.desktop.fullscreen) GFX_SwitchFullScreen();
+}
+
+
+static void SetPriority(PRIORITY_LEVELS level) {
+
+#if C_SET_PRIORITY
+// Do nothing if priorties are not the same and not root, else the highest
+// priority can not be set as users can only lower priority (not restore it)
+
+ if((sdl.priority.focus != sdl.priority.nofocus ) &&
+ (getuid()!=0) ) return;
+
+#endif
+ switch (level) {
+#ifdef WIN32
+ case PRIORITY_LEVEL_PAUSE: // if DOSBox is paused, assume idle priority
+ case PRIORITY_LEVEL_LOWEST:
+ SetPriorityClass(GetCurrentProcess(),IDLE_PRIORITY_CLASS);
+ break;
+ case PRIORITY_LEVEL_LOWER:
+ SetPriorityClass(GetCurrentProcess(),BELOW_NORMAL_PRIORITY_CLASS);
+ break;
+ case PRIORITY_LEVEL_NORMAL:
+ SetPriorityClass(GetCurrentProcess(),NORMAL_PRIORITY_CLASS);
+ break;
+ case PRIORITY_LEVEL_HIGHER:
+ SetPriorityClass(GetCurrentProcess(),ABOVE_NORMAL_PRIORITY_CLASS);
+ break;
+ case PRIORITY_LEVEL_HIGHEST:
+ SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
+ break;
+#elif C_SET_PRIORITY
+/* Linux use group as dosbox has mulitple threads under linux */
+ case PRIORITY_LEVEL_PAUSE: // if DOSBox is paused, assume idle priority
+ case PRIORITY_LEVEL_LOWEST:
+ setpriority (PRIO_PGRP, 0,PRIO_MAX);
+ break;
+ case PRIORITY_LEVEL_LOWER:
+ setpriority (PRIO_PGRP, 0,PRIO_MAX-(PRIO_TOTAL/3));
+ break;
+ case PRIORITY_LEVEL_NORMAL:
+ setpriority (PRIO_PGRP, 0,PRIO_MAX-(PRIO_TOTAL/2));
+ break;
+ case PRIORITY_LEVEL_HIGHER:
+ setpriority (PRIO_PGRP, 0,PRIO_MAX-((3*PRIO_TOTAL)/5) );
+ break;
+ case PRIORITY_LEVEL_HIGHEST:
+ setpriority (PRIO_PGRP, 0,PRIO_MAX-((3*PRIO_TOTAL)/4) );
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+extern Bit8u int10_font_14[256 * 14];
+static void OutputString(Bitu x,Bitu y,const char * text,Bit32u color,Bit32u color2,SDL_Surface * output_surface) {
+ Bit32u * draw=(Bit32u*)(((Bit8u *)output_surface->pixels)+((y)*output_surface->pitch))+x;
+ while (*text) {
+ Bit8u * font=&int10_font_14[(*text)*14];
+ Bitu i,j;
+ Bit32u * draw_line=draw;
+ for (i=0;i<14;i++) {
+ Bit8u map=*font++;
+ for (j=0;j<8;j++) {
+ if (map & 0x80) *((Bit32u*)(draw_line+j))=color; else *((Bit32u*)(draw_line+j))=color2;
+ map<<=1;
+ }
+ draw_line+=output_surface->pitch/4;
+ }
+ text++;
+ draw+=8;
+ }
+}
+
+static unsigned char logo[32*32*4]= {
+#include "dosbox_logo.h"
+};
+#include "dosbox_splash.h"
+
+//extern void UI_Run(bool);
+void Restart(bool pressed);
+
+static void GUI_StartUp(Section * sec) {
+ sec->AddDestroyFunction(&GUI_ShutDown);
+ Section_prop * section=static_cast<Section_prop *>(sec);
+ sdl.active=false;
+ sdl.updating=false;
+
+#if !defined(MACOSX)
+ /* Set Icon (must be done before any sdl_setvideomode call) */
+ /* But don't set it on OS X, as we use a nicer external icon there. */
+#if WORDS_BIGENDIAN
+ SDL_Surface* logos= SDL_CreateRGBSurfaceFrom((void*)logo,32,32,32,128,0xff000000,0x00ff0000,0x0000ff00,0);
+#else
+ SDL_Surface* logos= SDL_CreateRGBSurfaceFrom((void*)logo,32,32,32,128,0x000000ff,0x0000ff00,0x00ff0000,0);
+#endif
+ SDL_WM_SetIcon(logos,NULL);
+#endif
+
+ sdl.desktop.lazy_fullscreen=false;
+ sdl.desktop.lazy_fullscreen_req=false;
+
+ sdl.desktop.fullscreen=section->Get_bool("fullscreen");
+ sdl.wait_on_error=section->Get_bool("waitonerror");
+
+ Prop_multival* p=section->Get_multival("priority");
+ std::string focus = p->GetSection()->Get_string("active");
+ std::string notfocus = p->GetSection()->Get_string("inactive");
+
+ if (focus == "lowest") { sdl.priority.focus = PRIORITY_LEVEL_LOWEST; }
+ else if (focus == "lower") { sdl.priority.focus = PRIORITY_LEVEL_LOWER; }
+ else if (focus == "normal") { sdl.priority.focus = PRIORITY_LEVEL_NORMAL; }
+ else if (focus == "higher") { sdl.priority.focus = PRIORITY_LEVEL_HIGHER; }
+ else if (focus == "highest") { sdl.priority.focus = PRIORITY_LEVEL_HIGHEST; }
+
+ if (notfocus == "lowest") { sdl.priority.nofocus=PRIORITY_LEVEL_LOWEST; }
+ else if (notfocus == "lower") { sdl.priority.nofocus=PRIORITY_LEVEL_LOWER; }
+ else if (notfocus == "normal") { sdl.priority.nofocus=PRIORITY_LEVEL_NORMAL; }
+ else if (notfocus == "higher") { sdl.priority.nofocus=PRIORITY_LEVEL_HIGHER; }
+ else if (notfocus == "highest") { sdl.priority.nofocus=PRIORITY_LEVEL_HIGHEST; }
+ else if (notfocus == "pause") {
+ /* we only check for pause here, because it makes no sense
+ * for DOSBox to be paused while it has focus
+ */
+ sdl.priority.nofocus=PRIORITY_LEVEL_PAUSE;
+ }
+
+ SetPriority(sdl.priority.focus); //Assume focus on startup
+ sdl.mouse.locked=false;
+ mouselocked=false; //Global for mapper
+ sdl.mouse.requestlock=false;
+ sdl.desktop.full.fixed=false;
+ const char* fullresolution=section->Get_string("fullresolution");
+ sdl.desktop.full.width = 0;
+ sdl.desktop.full.height = 0;
+ if(fullresolution && *fullresolution) {
+ char res[100];
+ strncpy( res, fullresolution, sizeof( res ));
+ fullresolution = lowcase (res);//so x and X are allowed
+ if(strcmp(fullresolution,"original")) {
+ sdl.desktop.full.fixed = true;
+ char* height = const_cast<char*>(strchr(fullresolution,'x'));
+ if(height && * height) {
+ *height = 0;
+ sdl.desktop.full.height = (Bit16u)atoi(height+1);
+ sdl.desktop.full.width = (Bit16u)atoi(res);
+ }
+ }
+ }
+
+ sdl.desktop.window.width = 0;
+ sdl.desktop.window.height = 0;
+ const char* windowresolution=section->Get_string("windowresolution");
+ if(windowresolution && *windowresolution) {
+ char res[100];
+ strncpy( res,windowresolution, sizeof( res ));
+ windowresolution = lowcase (res);//so x and X are allowed
+ if(strcmp(windowresolution,"original")) {
+ char* height = const_cast<char*>(strchr(windowresolution,'x'));
+ if(height && *height) {
+ *height = 0;
+ sdl.desktop.window.height = (Bit16u)atoi(height+1);
+ sdl.desktop.window.width = (Bit16u)atoi(res);
+ }
+ }
+ }
+ sdl.desktop.doublebuf=section->Get_bool("fulldouble");
+ if (!sdl.desktop.full.width) {
+#ifdef WIN32
+ sdl.desktop.full.width=(Bit16u)GetSystemMetrics(SM_CXSCREEN);
+#else
+ sdl.desktop.full.width=1024;
+#endif
+ }
+ if (!sdl.desktop.full.height) {
+#ifdef WIN32
+ sdl.desktop.full.height=(Bit16u)GetSystemMetrics(SM_CYSCREEN);
+#else
+ sdl.desktop.full.height=768;
+#endif
+ }
+ sdl.mouse.autoenable=section->Get_bool("autolock");
+ if (!sdl.mouse.autoenable) SDL_ShowCursor(SDL_DISABLE);
+ sdl.mouse.autolock=false;
+ sdl.mouse.sensitivity=section->Get_int("sensitivity");
+ std::string output=section->Get_string("output");
+
+ /* Setup Mouse correctly if fullscreen */
+ if(sdl.desktop.fullscreen) GFX_CaptureMouse();
+
+ if (output == "surface") {
+ sdl.desktop.want_type=SCREEN_SURFACE;
+#if (HAVE_DDRAW_H) && defined(WIN32)
+ } else if (output == "ddraw") {
+ sdl.desktop.want_type=SCREEN_SURFACE_DDRAW;
+#endif
+ } else if (output == "overlay") {
+ sdl.desktop.want_type=SCREEN_OVERLAY;
+#if C_OPENGL
+ } else if (output == "opengl") {
+ sdl.desktop.want_type=SCREEN_OPENGL;
+ sdl.opengl.bilinear=true;
+ } else if (output == "openglnb") {
+ sdl.desktop.want_type=SCREEN_OPENGL;
+ sdl.opengl.bilinear=false;
+#endif
+ } else {
+ LOG_MSG("SDL:Unsupported output device %s, switching back to surface",output.c_str());
+ sdl.desktop.want_type=SCREEN_SURFACE;//SHOULDN'T BE POSSIBLE anymore
+ }
+
+ sdl.overlay=0;
+#if C_OPENGL
+ if(sdl.desktop.want_type==SCREEN_OPENGL){ /* OPENGL is requested */
+ sdl.surface=SDL_SetVideoMode(640,400,0,SDL_OPENGL);
+ if (sdl.surface == NULL) {
+ LOG_MSG("Could not initialize OpenGL, switching back to surface");
+ sdl.desktop.want_type=SCREEN_SURFACE;
+ } else {
+ sdl.opengl.framebuf=0;
+ sdl.opengl.texture=0;
+ sdl.opengl.displaylist=0;
+ glGetIntegerv (GL_MAX_TEXTURE_SIZE, &sdl.opengl.max_texsize);
+#if defined(__WIN32__) && defined(NVIDIA_PixelDataRange)
+ glPixelDataRangeNV = (PFNGLPIXELDATARANGENVPROC) wglGetProcAddress("glPixelDataRangeNV");
+ db_glAllocateMemoryNV = (PFNWGLALLOCATEMEMORYNVPROC) wglGetProcAddress("wglAllocateMemoryNV");
+ db_glFreeMemoryNV = (PFNWGLFREEMEMORYNVPROC) wglGetProcAddress("wglFreeMemoryNV");
+#endif
+ const char * gl_ext = (const char *)glGetString (GL_EXTENSIONS);
+ if(gl_ext && *gl_ext){
+ sdl.opengl.packed_pixel=(strstr(gl_ext,"EXT_packed_pixels") > 0);
+ sdl.opengl.paletted_texture=(strstr(gl_ext,"EXT_paletted_texture") > 0);
+#if defined(NVIDIA_PixelDataRange)
+ sdl.opengl.pixel_data_range=(strstr(gl_ext,"GL_NV_pixel_data_range") >0 ) &&
+ glPixelDataRangeNV && db_glAllocateMemoryNV && db_glFreeMemoryNV;
+ sdl.opengl.pixel_data_range = 0;
+#endif
+ } else {
+ sdl.opengl.packed_pixel=sdl.opengl.paletted_texture=false;
+ }
+ }
+ } /* OPENGL is requested end */
+
+#endif //OPENGL
+ /* Initialize screen for first time */
+ sdl.surface=SDL_SetVideoMode(640,400,0,0);
+ if (sdl.surface == NULL) E_Exit("Could not initialize video: %s",SDL_GetError());
+ sdl.desktop.bpp=sdl.surface->format->BitsPerPixel;
+ if (sdl.desktop.bpp==24) {
+ LOG_MSG("SDL:You are running in 24 bpp mode, this will slow down things!");
+ }
+ GFX_Stop();
+ SDL_WM_SetCaption("DOSBox",VERSION);
+
+/* The endian part is intentionally disabled as somehow it produces correct results without according to rhoenie*/
+//#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+// Bit32u rmask = 0xff000000;
+// Bit32u gmask = 0x00ff0000;
+// Bit32u bmask = 0x0000ff00;
+//#else
+ Bit32u rmask = 0x000000ff;
+ Bit32u gmask = 0x0000ff00;
+ Bit32u bmask = 0x00ff0000;
+//#endif
+
+/* Please leave the Splash screen stuff in working order in DOSBox. We spend a lot of time making DOSBox. */
+ SDL_Surface* splash_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 400, 32, rmask, gmask, bmask, 0);
+ if (splash_surf) {
+ SDL_FillRect(splash_surf, NULL, SDL_MapRGB(splash_surf->format, 0, 0, 0));
+
+ Bit8u* tmpbufp = new Bit8u[640*400*3];
+ GIMP_IMAGE_RUN_LENGTH_DECODE(tmpbufp,gimp_image.rle_pixel_data,640*400,3);
+ for (Bitu y=0; y<400; y++) {
+
+ Bit8u* tmpbuf = tmpbufp + y*640*3;
+ Bit32u * draw=(Bit32u*)(((Bit8u *)splash_surf->pixels)+((y)*splash_surf->pitch));
+ for (Bitu x=0; x<640; x++) {
+//#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+// *draw++ = tmpbuf[x*3+2]+tmpbuf[x*3+1]*0x100+tmpbuf[x*3+0]*0x10000+0x00000000;
+//#else
+ *draw++ = tmpbuf[x*3+0]+tmpbuf[x*3+1]*0x100+tmpbuf[x*3+2]*0x10000+0x00000000;
+//#endif
+ }
+ }
+
+ bool exit_splash = false;
+
+ static Bitu max_splash_loop = 600;
+ static Bitu splash_fade = 100;
+ static bool use_fadeout = true;
+
+ for (Bit32u ct = 0,startticks = GetTicks();ct < max_splash_loop;ct = GetTicks()-startticks) {
+ SDL_Event evt;
+ while (SDL_PollEvent(&evt)) {
+ if (evt.type == SDL_QUIT) {
+ exit_splash = true;
+ break;
+ }
+ }
+ if (exit_splash) break;
+
+ if (ct<1) {
+ SDL_FillRect(sdl.surface, NULL, SDL_MapRGB(sdl.surface->format, 0, 0, 0));
+ SDL_SetAlpha(splash_surf, SDL_SRCALPHA,255);
+ SDL_BlitSurface(splash_surf, NULL, sdl.surface, NULL);
+ SDL_Flip(sdl.surface);
+ } else if (ct>=max_splash_loop-splash_fade) {
+ if (use_fadeout) {
+ SDL_FillRect(sdl.surface, NULL, SDL_MapRGB(sdl.surface->format, 0, 0, 0));
+ SDL_SetAlpha(splash_surf, SDL_SRCALPHA, (Bit8u)((max_splash_loop-1-ct)*255/(splash_fade-1)));
+ SDL_BlitSurface(splash_surf, NULL, sdl.surface, NULL);
+ SDL_Flip(sdl.surface);
+ }
+ }
+
+ }
+
+ if (use_fadeout) {
+ SDL_FillRect(sdl.surface, NULL, SDL_MapRGB(sdl.surface->format, 0, 0, 0));
+ SDL_Flip(sdl.surface);
+ }
+ SDL_FreeSurface(splash_surf);
+ delete [] tmpbufp;
+
+ }
+
+ /* Get some Event handlers */
+ MAPPER_AddHandler(KillSwitch,MK_f9,MMOD1,"shutdown","ShutDown");
+ MAPPER_AddHandler(CaptureMouse,MK_f10,MMOD1,"capmouse","Cap Mouse");
+ MAPPER_AddHandler(SwitchFullScreen,MK_return,MMOD2,"fullscr","Fullscreen");
+ MAPPER_AddHandler(Restart,MK_home,MMOD1|MMOD2,"restart","Restart");
+#if C_DEBUG
+ /* Pause binds with activate-debugger */
+#else
+ MAPPER_AddHandler(&PauseDOSBox, MK_pause, MMOD2, "pause", "Pause");
+#endif
+ /* Get Keyboard state of numlock and capslock */
+ SDLMod keystate = SDL_GetModState();
+ if(keystate&KMOD_NUM) startup_state_numlock = true;
+ if(keystate&KMOD_CAPS) startup_state_capslock = true;
+}
+
+void Mouse_AutoLock(bool enable) {
+ sdl.mouse.autolock=enable;
+ if (sdl.mouse.autoenable) sdl.mouse.requestlock=enable;
+ else {
+ SDL_ShowCursor(enable?SDL_DISABLE:SDL_ENABLE);
+ sdl.mouse.requestlock=false;
+ }
+}
+
+static void HandleMouseMotion(SDL_MouseMotionEvent * motion) {
+ if (sdl.mouse.locked || !sdl.mouse.autoenable)
+ Mouse_CursorMoved((float)motion->xrel*sdl.mouse.sensitivity/100.0f,
+ (float)motion->yrel*sdl.mouse.sensitivity/100.0f,
+ (float)(motion->x-sdl.clip.x)/(sdl.clip.w-1)*sdl.mouse.sensitivity/100.0f,
+ (float)(motion->y-sdl.clip.y)/(sdl.clip.h-1)*sdl.mouse.sensitivity/100.0f,
+ sdl.mouse.locked);
+}
+
+static void HandleMouseButton(SDL_MouseButtonEvent * button) {
+ switch (button->state) {
+ case SDL_PRESSED:
+ if (sdl.mouse.requestlock && !sdl.mouse.locked) {
+ GFX_CaptureMouse();
+ // Dont pass klick to mouse handler
+ break;
+ }
+ if (!sdl.mouse.autoenable && sdl.mouse.autolock && button->button == SDL_BUTTON_MIDDLE) {
+ GFX_CaptureMouse();
+ break;
+ }
+ switch (button->button) {
+ case SDL_BUTTON_LEFT:
+ Mouse_ButtonPressed(0);
+ break;
+ case SDL_BUTTON_RIGHT:
+ Mouse_ButtonPressed(1);
+ break;
+ case SDL_BUTTON_MIDDLE:
+ Mouse_ButtonPressed(2);
+ break;
+ }
+ break;
+ case SDL_RELEASED:
+ switch (button->button) {
+ case SDL_BUTTON_LEFT:
+ Mouse_ButtonReleased(0);
+ break;
+ case SDL_BUTTON_RIGHT:
+ Mouse_ButtonReleased(1);
+ break;
+ case SDL_BUTTON_MIDDLE:
+ Mouse_ButtonReleased(2);
+ break;
+ }
+ break;
+ }
+}
+
+void GFX_LosingFocus(void) {
+ sdl.laltstate=SDL_KEYUP;
+ sdl.raltstate=SDL_KEYUP;
+ MAPPER_LosingFocus();
+}
+
+bool GFX_IsFullscreen(void) {
+ return sdl.desktop.fullscreen;
+}
+
+void GFX_Events() {
+ SDL_Event event;
+#if defined (REDUCE_JOYSTICK_POLLING)
+ static int poll_delay=0;
+ int time=GetTicks();
+ if (time-poll_delay>20) {
+ poll_delay=time;
+ if (sdl.num_joysticks>0) SDL_JoystickUpdate();
+ MAPPER_UpdateJoysticks();
+ }
+#endif
+ while (SDL_PollEvent(&event)) {
+ switch (event.type) {
+ case SDL_ACTIVEEVENT:
+ if (event.active.state & SDL_APPINPUTFOCUS) {
+ if (event.active.gain) {
+ if (sdl.desktop.fullscreen && !sdl.mouse.locked)
+ GFX_CaptureMouse();
+ SetPriority(sdl.priority.focus);
+ CPU_Disable_SkipAutoAdjust();
+ } else {
+ if (sdl.mouse.locked) {
+#ifdef WIN32
+ if (sdl.desktop.fullscreen) {
+ VGA_KillDrawing();
+ GFX_ForceFullscreenExit();
+ }
+#endif
+ GFX_CaptureMouse();
+ }
+ SetPriority(sdl.priority.nofocus);
+ GFX_LosingFocus();
+ CPU_Enable_SkipAutoAdjust();
+ }
+ }
+
+ /* Non-focus priority is set to pause; check to see if we've lost window or input focus
+ * i.e. has the window been minimised or made inactive?
+ */
+ if (sdl.priority.nofocus == PRIORITY_LEVEL_PAUSE) {
+ if ((event.active.state & (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) && (!event.active.gain)) {
+ /* Window has lost focus, pause the emulator.
+ * This is similar to what PauseDOSBox() does, but the exit criteria is different.
+ * Instead of waiting for the user to hit Alt-Break, we wait for the window to
+ * regain window or input focus.
+ */
+ bool paused = true;
+ SDL_Event ev;
+
+ GFX_SetTitle(-1,-1,true);
+ KEYBOARD_ClrBuffer();
+// SDL_Delay(500);
+// while (SDL_PollEvent(&ev)) {
+ // flush event queue.
+// }
+
+ while (paused) {
+ // WaitEvent waits for an event rather than polling, so CPU usage drops to zero
+ SDL_WaitEvent(&ev);
+
+ switch (ev.type) {
+ case SDL_QUIT: throw(0); break; // a bit redundant at linux at least as the active events gets before the quit event.
+ case SDL_ACTIVEEVENT: // wait until we get window focus back
+ if (ev.active.state & (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) {
+ // We've got focus back, so unpause and break out of the loop
+ if (ev.active.gain) {
+ paused = false;
+ GFX_SetTitle(-1,-1,false);
+ }
+
+ /* Now poke a "release ALT" command into the keyboard buffer
+ * we have to do this, otherwise ALT will 'stick' and cause
+ * problems with the app running in the DOSBox.
+ */
+ KEYBOARD_AddKey(KBD_leftalt, false);
+ KEYBOARD_AddKey(KBD_rightalt, false);
+ }
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case SDL_MOUSEMOTION:
+ HandleMouseMotion(&event.motion);
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ case SDL_MOUSEBUTTONUP:
+ HandleMouseButton(&event.button);
+ break;
+ case SDL_VIDEORESIZE:
+// HandleVideoResize(&event.resize);
+ break;
+ case SDL_QUIT:
+ throw(0);
+ break;
+ case SDL_VIDEOEXPOSE:
+ if (sdl.draw.callback) sdl.draw.callback( GFX_CallBackRedraw );
+ break;
+#ifdef WIN32
+ case SDL_KEYDOWN:
+ case SDL_KEYUP:
+ // ignore event alt+tab
+ if (event.key.keysym.sym==SDLK_LALT) sdl.laltstate = event.key.type;
+ if (event.key.keysym.sym==SDLK_RALT) sdl.raltstate = event.key.type;
+ if (((event.key.keysym.sym==SDLK_TAB)) &&
+ ((sdl.laltstate==SDL_KEYDOWN) || (sdl.raltstate==SDL_KEYDOWN))) break;
+#endif
+#if defined (MACOSX)
+ case SDL_KEYDOWN:
+ case SDL_KEYUP:
+ /* On macs CMD-Q is the default key to close an application */
+ if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod == KMOD_RMETA || event.key.keysym.mod == KMOD_LMETA) ) {
+ KillSwitch(true);
+ break;
+ }
+#endif
+ default:
+ void MAPPER_CheckEvent(SDL_Event * event);
+ MAPPER_CheckEvent(&event);
+ }
+ }
+}
+
+#if defined (WIN32)
+static BOOL WINAPI ConsoleEventHandler(DWORD event) {
+ switch (event) {
+ case CTRL_SHUTDOWN_EVENT:
+ case CTRL_LOGOFF_EVENT:
+ case CTRL_CLOSE_EVENT:
+ case CTRL_BREAK_EVENT:
+ raise(SIGTERM);
+ return TRUE;
+ case CTRL_C_EVENT:
+ default: //pass to the next handler
+ return FALSE;
+ }
+}
+#endif
+
+
+/* static variable to show wether there is not a valid stdout.
+ * Fixes some bugs when -noconsole is used in a read only directory */
+static bool no_stdout = false;
+void GFX_ShowMsg(char const* format,...) {
+ char buf[512];
+ va_list msg;
+ va_start(msg,format);
+ vsprintf(buf,format,msg);
+ strcat(buf,"\n");
+ va_end(msg);
+ if(!no_stdout) printf("%s",buf); //Else buf is parsed again.
+}
+
+
+void Config_Add_SDL() {
+ Section_prop * sdl_sec=control->AddSection_prop("sdl",&GUI_StartUp);
+ sdl_sec->AddInitFunction(&MAPPER_StartUp);
+ Prop_bool* Pbool;
+ Prop_string* Pstring;
+ Prop_int* Pint;
+ Prop_multival* Pmulti;
+
+ Pbool = sdl_sec->Add_bool("fullscreen",Property::Changeable::Always,false);
+ Pbool->Set_help("Start dosbox directly in fullscreen. (Press ALT-Enter to go back)");
+
+ Pbool = sdl_sec->Add_bool("fulldouble",Property::Changeable::Always,false);
+ Pbool->Set_help("Use double buffering in fullscreen. It can reduce screen flickering, but it can also result in a slow DOSBox.");
+
+ Pstring = sdl_sec->Add_string("fullresolution",Property::Changeable::Always,"original");
+ Pstring->Set_help("What resolution to use for fullscreen: original or fixed size (e.g. 1024x768).\n"
+ " Using your monitor's native resolution with aspect=true might give the best results.\n"
+ " If you end up with small window on a large screen, try an output different from surface.");
+
+ Pstring = sdl_sec->Add_string("windowresolution",Property::Changeable::Always,"original");
+ Pstring->Set_help("Scale the window to this size IF the output device supports hardware scaling.\n"
+ " (output=surface does not!)");
+
+ const char* outputs[] = {
+ "surface", "overlay",
+#if C_OPENGL
+ "opengl", "openglnb",
+#endif
+#if (HAVE_DDRAW_H) && defined(WIN32)
+ "ddraw",
+#endif
+ 0 };
+ Pstring = sdl_sec->Add_string("output",Property::Changeable::Always,"surface");
+ Pstring->Set_help("What video system to use for output.");
+ Pstring->Set_values(outputs);
+
+ Pbool = sdl_sec->Add_bool("autolock",Property::Changeable::Always,true);
+ Pbool->Set_help("Mouse will automatically lock, if you click on the screen. (Press CTRL-F10 to unlock)");
+
+ Pint = sdl_sec->Add_int("sensitivity",Property::Changeable::Always,100);
+ Pint->SetMinMax(1,1000);
+ Pint->Set_help("Mouse sensitivity.");
+
+ Pbool = sdl_sec->Add_bool("waitonerror",Property::Changeable::Always, true);
+ Pbool->Set_help("Wait before closing the console if dosbox has an error.");
+
+ Pmulti = sdl_sec->Add_multi("priority", Property::Changeable::Always, ",");
+ Pmulti->SetValue("higher,normal");
+ Pmulti->Set_help("Priority levels for dosbox. Second entry behind the comma is for when dosbox is not focused/minimized.\n"
+ " pause is only valid for the second entry.");
+
+ const char* actt[] = { "lowest", "lower", "normal", "higher", "highest", "pause", 0};
+ Pstring = Pmulti->GetSection()->Add_string("active",Property::Changeable::Always,"higher");
+ Pstring->Set_values(actt);
+
+ const char* inactt[] = { "lowest", "lower", "normal", "higher", "highest", "pause", 0};
+ Pstring = Pmulti->GetSection()->Add_string("inactive",Property::Changeable::Always,"normal");
+ Pstring->Set_values(inactt);
+
+ Pstring = sdl_sec->Add_path("mapperfile",Property::Changeable::Always,MAPPERFILE);
+ Pstring->Set_help("File used to load/save the key/event mappings from. Resetmapper only works with the defaul value.");
+
+ Pbool = sdl_sec->Add_bool("usescancodes",Property::Changeable::Always,true);
+ Pbool->Set_help("Avoid usage of symkeys, might not work on all operating systems.");
+}
+
+static void show_warning(char const * const message) {
+ bool textonly = true;
+#ifdef WIN32
+ textonly = false;
+ if ( !sdl.inited && SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE) < 0 ) textonly = true;
+ sdl.inited = true;
+#endif
+ printf(message);
+ if(textonly) return;
+ if(!sdl.surface) sdl.surface = SDL_SetVideoMode(640,400,0,0);
+ if(!sdl.surface) return;
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ Bit32u rmask = 0xff000000;
+ Bit32u gmask = 0x00ff0000;
+ Bit32u bmask = 0x0000ff00;
+#else
+ Bit32u rmask = 0x000000ff;
+ Bit32u gmask = 0x0000ff00;
+ Bit32u bmask = 0x00ff0000;
+#endif
+ SDL_Surface* splash_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 400, 32, rmask, gmask, bmask, 0);
+ if (!splash_surf) return;
+
+ int x = 120,y = 20;
+ std::string m(message),m2;
+ std::string::size_type a,b,c,d;
+
+ while(m.size()) { //Max 50 characters. break on space before or on a newline
+ c = m.find('\n');
+ d = m.rfind(' ',50);
+ if(c>d) a=b=d; else a=b=c;
+ if( a != std::string::npos) b++;
+ m2 = m.substr(0,a); m.erase(0,b);
+ OutputString(x,y,m2.c_str(),0xffffffff,0,splash_surf);
+ y += 20;
+ }
+
+ SDL_BlitSurface(splash_surf, NULL, sdl.surface, NULL);
+ SDL_Flip(sdl.surface);
+ SDL_Delay(12000);
+}
+
+static void launcheditor() {
+ std::string path,file;
+ Cross::CreatePlatformConfigDir(path);
+ Cross::GetPlatformConfigName(file);
+ path += file;
+ FILE* f = fopen(path.c_str(),"r");
+ if(!f && !control->PrintConfig(path.c_str())) {
+ printf("tried creating %s. but failed.\n",path.c_str());
+ exit(1);
+ }
+ if(f) fclose(f);
+/* if(edit.empty()) {
+ printf("no editor specified.\n");
+ exit(1);
+ }*/
+ std::string edit;
+ while(control->cmdline->FindString("-editconf",edit,true)) //Loop until one succeeds
+ execlp(edit.c_str(),edit.c_str(),path.c_str(),(char*) 0);
+ //if you get here the launching failed!
+ printf("can't find editor(s) specified at the command line.\n");
+ exit(1);
+}
+#if C_DEBUG
+extern void DEBUG_ShutDown(Section * /*sec*/);
+#endif
+
+void restart_program(std::vector<std::string> & parameters) {
+ char** newargs = new char* [parameters.size()+1];
+ // parameter 0 is the executable path
+ // contents of the vector follow
+ // last one is NULL
+ for(Bitu i = 0; i < parameters.size(); i++) newargs[i]=(char*)parameters[i].c_str();
+ newargs[parameters.size()] = NULL;
+ SDL_CloseAudio();
+ SDL_Delay(50);
+ SDL_Quit();
+#if C_DEBUG
+ // shutdown curses
+ DEBUG_ShutDown(NULL);
+#endif
+
+ execvp(newargs[0], newargs);
+ free(newargs);
+}
+void Restart(bool pressed) { // mapper handler
+ restart_program(control->startup_params);
+}
+
+static void launchcaptures(std::string const& edit) {
+ std::string path,file;
+ Section* t = control->GetSection("dosbox");
+ if(t) file = t->GetPropValue("captures");
+ if(!t || file == NO_SUCH_PROPERTY) {
+ printf("Config system messed up.\n");
+ exit(1);
+ }
+ Cross::CreatePlatformConfigDir(path);
+ path += file;
+ Cross::CreateDir(path);
+ struct stat cstat;
+ if(stat(path.c_str(),&cstat) || (cstat.st_mode & S_IFDIR) == 0) {
+ printf("%s doesn't exists or isn't a directory.\n",path.c_str());
+ exit(1);
+ }
+/* if(edit.empty()) {
+ printf("no editor specified.\n");
+ exit(1);
+ }*/
+
+ execlp(edit.c_str(),edit.c_str(),path.c_str(),(char*) 0);
+ //if you get here the launching failed!
+ printf("can't find filemanager %s\n",edit.c_str());
+ exit(1);
+}
+
+static void printconfiglocation() {
+ std::string path,file;
+ Cross::CreatePlatformConfigDir(path);
+ Cross::GetPlatformConfigName(file);
+ path += file;
+
+ FILE* f = fopen(path.c_str(),"r");
+ if(!f && !control->PrintConfig(path.c_str())) {
+ printf("tried creating %s. but failed",path.c_str());
+ exit(1);
+ }
+ if(f) fclose(f);
+ printf("%s\n",path.c_str());
+ exit(0);
+}
+
+static void eraseconfigfile() {
+ FILE* f = fopen("dosbox.conf","r");
+ if(f) {
+ fclose(f);
+ show_warning("Warning: dosbox.conf exists in current working directory.\nThis will override the configuration file at runtime.\n");
+ }
+ std::string path,file;
+ Cross::GetPlatformConfigDir(path);
+ Cross::GetPlatformConfigName(file);
+ path += file;
+ f = fopen(path.c_str(),"r");
+ if(!f) exit(0);
+ fclose(f);
+ unlink(path.c_str());
+ exit(0);
+}
+
+static void erasemapperfile() {
+ FILE* g = fopen("dosbox.conf","r");
+ if(g) {
+ fclose(g);
+ show_warning("Warning: dosbox.conf exists in current working directory.\nKeymapping might not be properly reset.\n"
+ "Please reset configuration as well and delete the dosbox.conf.\n");
+ }
+
+ std::string path,file=MAPPERFILE;
+ Cross::GetPlatformConfigDir(path);
+ path += file;
+ FILE* f = fopen(path.c_str(),"r");
+ if(!f) exit(0);
+ fclose(f);
+ unlink(path.c_str());
+ exit(0);
+}
+
+
+//extern void UI_Init(void);
+int main(int argc, char* argv[]) {
+ try {
+ CommandLine com_line(argc,argv);
+ Config myconf(&com_line);
+ control=&myconf;
+ /* Init the configuration system and add default values */
+ Config_Add_SDL();
+ DOSBOX_Init();
+
+ std::string editor;
+ if(control->cmdline->FindString("-editconf",editor,false)) launcheditor();
+ if(control->cmdline->FindString("-opencaptures",editor,true)) launchcaptures(editor);
+ if(control->cmdline->FindExist("-eraseconf")) eraseconfigfile();
+ if(control->cmdline->FindExist("-resetconf")) eraseconfigfile();
+ if(control->cmdline->FindExist("-erasemapper")) erasemapperfile();
+ if(control->cmdline->FindExist("-resetmapper")) erasemapperfile();
+
+ /* Can't disable the console with debugger enabled */
+#if defined(WIN32) && !(C_DEBUG)
+ if (control->cmdline->FindExist("-noconsole")) {
+ FreeConsole();
+ /* Redirect standard input and standard output */
+ if(freopen(STDOUT_FILE, "w", stdout) == NULL)
+ no_stdout = true; // No stdout so don't write messages
+ freopen(STDERR_FILE, "w", stderr);
+ setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* Line buffered */
+ setbuf(stderr, NULL); /* No buffering */
+ } else {
+ if (AllocConsole()) {
+ fclose(stdin);
+ fclose(stdout);
+ fclose(stderr);
+ freopen("CONIN$","r",stdin);
+ freopen("CONOUT$","w",stdout);
+ freopen("CONOUT$","w",stderr);
+ }
+ SetConsoleTitle("DOSBox Status Window");
+ }
+#endif //defined(WIN32) && !(C_DEBUG)
+ if (control->cmdline->FindExist("-version") ||
+ control->cmdline->FindExist("--version") ) {
+ printf("\nDOSBox version %s, copyright 2002-2011 DOSBox Team.\n\n",VERSION);
+ printf("DOSBox is written by the DOSBox Team (See AUTHORS file))\n");
+ printf("DOSBox comes with ABSOLUTELY NO WARRANTY. This is free software,\n");
+ printf("and you are welcome to redistribute it under certain conditions;\n");
+ printf("please read the COPYING file thoroughly before doing so.\n\n");
+ return 0;
+ }
+ if(control->cmdline->FindExist("-printconf")) printconfiglocation();
+
+#if C_DEBUG
+ DEBUG_SetupConsole();
+#endif
+
+#if defined(WIN32)
+ SetConsoleCtrlHandler((PHANDLER_ROUTINE) ConsoleEventHandler,TRUE);
+#endif
+
+#ifdef OS2
+ PPIB pib;
+ PTIB tib;
+ DosGetInfoBlocks(&tib, &pib);
+ if (pib->pib_ultype == 2) pib->pib_ultype = 3;
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+#endif
+
+ /* Display Welcometext in the console */
+ LOG_MSG("DOSBox version %s",VERSION);
+ LOG_MSG("Copyright 2002-2011 DOSBox Team, published under GNU GPL.");
+ LOG_MSG("---");
+
+ /* Init SDL */
+#if SDL_VERSION_ATLEAST(1, 2, 14)
+ /* Or debian/ubuntu with older libsdl version as they have done this themselves, but then differently.
+ * with this variable they will work correctly. I've only tested the 1.2.14 behaviour against the windows version
+ * of libsdl
+ */
+ putenv(const_cast<char*>("SDL_DISABLE_LOCK_KEYS=1"));
+#endif
+ if ( SDL_Init( SDL_INIT_AUDIO|SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_CDROM
+ |SDL_INIT_NOPARACHUTE
+ ) < 0 ) E_Exit("Can't init SDL %s",SDL_GetError());
+ sdl.inited = true;
+
+#ifndef DISABLE_JOYSTICK
+ //Initialise Joystick seperately. This way we can warn when it fails instead
+ //of exiting the application
+ if( SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0 ) LOG_MSG("Failed to init joystick support");
+#endif
+
+ sdl.laltstate = SDL_KEYUP;
+ sdl.raltstate = SDL_KEYUP;
+
+#if defined (WIN32)
+#if SDL_VERSION_ATLEAST(1, 2, 10)
+ sdl.using_windib=true;
+#else
+ sdl.using_windib=false;
+#endif
+ char sdl_drv_name[128];
+ if (getenv("SDL_VIDEODRIVER")==NULL) {
+ if (SDL_VideoDriverName(sdl_drv_name,128)!=NULL) {
+ sdl.using_windib=false;
+ if (strcmp(sdl_drv_name,"directx")!=0) {
+ SDL_QuitSubSystem(SDL_INIT_VIDEO);
+ putenv("SDL_VIDEODRIVER=directx");
+ if (SDL_InitSubSystem(SDL_INIT_VIDEO)<0) {
+ putenv("SDL_VIDEODRIVER=windib");
+ if (SDL_InitSubSystem(SDL_INIT_VIDEO)<0) E_Exit("Can't init SDL Video %s",SDL_GetError());
+ sdl.using_windib=true;
+ }
+ }
+ }
+ } else {
+ char* sdl_videodrv = getenv("SDL_VIDEODRIVER");
+ if (strcmp(sdl_videodrv,"directx")==0) sdl.using_windib = false;
+ else if (strcmp(sdl_videodrv,"windib")==0) sdl.using_windib = true;
+ }
+ if (SDL_VideoDriverName(sdl_drv_name,128)!=NULL) {
+ if (strcmp(sdl_drv_name,"windib")==0) LOG_MSG("SDL_Init: Starting up with SDL windib video driver.\n Try to update your video card and directx drivers!");
+ }
+#endif
+ sdl.num_joysticks=SDL_NumJoysticks();
+
+ /* Parse configuration files */
+ std::string config_file,config_path;
+ Cross::GetPlatformConfigDir(config_path);
+
+ //First parse -userconf
+ if(control->cmdline->FindExist("-userconf",true)){
+ config_file.clear();
+ Cross::GetPlatformConfigDir(config_path);
+ Cross::GetPlatformConfigName(config_file);
+ config_path += config_file;
+ control->ParseConfigFile(config_path.c_str());
+ if(!control->configfiles.size()) {
+ //Try to create the userlevel configfile.
+ config_file.clear();
+ Cross::CreatePlatformConfigDir(config_path);
+ Cross::GetPlatformConfigName(config_file);
+ config_path += config_file;
+ if(control->PrintConfig(config_path.c_str())) {
+ LOG_MSG("CONFIG: Generating default configuration.\nWriting it to %s",config_path.c_str());
+ //Load them as well. Makes relative paths much easier
+ control->ParseConfigFile(config_path.c_str());
+ }
+ }
+ }
+
+ //Second parse -conf switches
+ while(control->cmdline->FindString("-conf",config_file,true)) {
+ if(!control->ParseConfigFile(config_file.c_str())) {
+ // try to load it from the user directory
+ control->ParseConfigFile((config_path + config_file).c_str());
+ }
+ }
+ // if none found => parse localdir conf
+ if(!control->configfiles.size()) control->ParseConfigFile("dosbox.conf");
+
+ // if none found => parse userlevel conf
+ if(!control->configfiles.size()) {
+ config_file.clear();
+ Cross::GetPlatformConfigName(config_file);
+ control->ParseConfigFile((config_path + config_file).c_str());
+ }
+
+ if(!control->configfiles.size()) {
+ //Try to create the userlevel configfile.
+ config_file.clear();
+ Cross::CreatePlatformConfigDir(config_path);
+ Cross::GetPlatformConfigName(config_file);
+ config_path += config_file;
+ if(control->PrintConfig(config_path.c_str())) {
+ LOG_MSG("CONFIG: Generating default configuration.\nWriting it to %s",config_path.c_str());
+ //Load them as well. Makes relative paths much easier
+ control->ParseConfigFile(config_path.c_str());
+ } else {
+ LOG_MSG("CONFIG: Using default settings. Create a configfile to change them");
+ }
+ }
+
+
+#if (ENVIRON_LINKED)
+ control->ParseEnv(environ);
+#endif
+// UI_Init();
+// if (control->cmdline->FindExist("-startui")) UI_Run(false);
+ /* Init all the sections */
+ control->Init();
+ /* Some extra SDL Functions */
+ Section_prop * sdl_sec=static_cast<Section_prop *>(control->GetSection("sdl"));
+
+ if (control->cmdline->FindExist("-fullscreen") || sdl_sec->Get_bool("fullscreen")) {
+ if(!sdl.desktop.fullscreen) { //only switch if not already in fullscreen
+ GFX_SwitchFullScreen();
+ }
+ }
+
+ /* Init the keyMapper */
+ MAPPER_Init();
+ if (control->cmdline->FindExist("-startmapper")) MAPPER_RunInternal();
+ /* Start up main machine */
+ control->StartUp();
+ /* Shutdown everything */
+ } catch (char * error) {
+#if defined (WIN32)
+ sticky_keys(true);
+#endif
+ GFX_ShowMsg("Exit to error: %s",error);
+ fflush(NULL);
+ if(sdl.wait_on_error) {
+ //TODO Maybe look for some way to show message in linux?
+#if (C_DEBUG)
+ GFX_ShowMsg("Press enter to continue");
+ fflush(NULL);
+ fgetc(stdin);
+#elif defined(WIN32)
+ Sleep(5000);
+#endif
+ }
+
+ }
+ catch (int){
+ ;//nothing pressed killswitch
+ }
+ catch(...){
+#if defined (WIN32)
+ sticky_keys(true);
+#endif
+ //Force visible mouse to end user. Somehow this sometimes doesn't happen
+ SDL_WM_GrabInput(SDL_GRAB_OFF);
+ SDL_ShowCursor(SDL_ENABLE);
+ throw;//dunno what happened. rethrow for sdl to catch
+ }
+#if defined (WIN32)
+ sticky_keys(true); //Might not be needed if the shutdown function switches to windowed mode, but it doesn't hurt
+#endif
+ //Force visible mouse to end user. Somehow this sometimes doesn't happen
+ SDL_WM_GrabInput(SDL_GRAB_OFF);
+ SDL_ShowCursor(SDL_ENABLE);
+
+ SDL_Quit();//Let's hope sdl will quit as well when it catches an exception
+ return 0;
+}
+
+void GFX_GetSize(int &width, int &height, bool &fullscreen) {
+ width = sdl.draw.width;
+ height = sdl.draw.height;
+ fullscreen = sdl.desktop.fullscreen;
+}
diff --git a/src/misc/support.cpp b/src/misc/support.cpp
index cfcb64f68..5c4eb0163 100644
--- a/src/misc/support.cpp
+++ b/src/misc/support.cpp
@@ -171,7 +171,7 @@ double ConvDblWord(char * word) {
static char buf[1024]; //greater scope as else it doesn't always gets thrown right (linux/gcc2.95)
void E_Exit(const char * format,...) {
-#if C_DEBUG && C_HEAVY_DEBUG
+#if C_HEAVY_DEBUG || C_GDBSERVER
DEBUG_HeavyWriteLogInstruction();
#endif
va_list msg;