Add gdb server to debugger
Here is a patch which 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. This patch applies against svn revision 3761. Once applied 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. Tested under GNU/Linux. Co-authored-by: ykhwong Imported-from: https://www.vogons.org/viewtopic.php?p=259378#p259378
This commit is contained in:
parent
eb0a3dffc2
commit
cf4685e7aa
31 changed files with 7979 additions and 1006 deletions
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
extern Bitu cycle_count;
|
||||
extern Bitu debugCallback;
|
||||
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 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
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
|
||||
|
|
File diff suppressed because it is too large
Load diff
2493
src/debug/debug.cpp.orig
Normal file
2493
src/debug/debug.cpp.orig
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
347
src/debug/debug_helpers.cpp
Normal file
347
src/debug/debug_helpers.cpp
Normal file
|
@ -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
|
502
src/debug/debug_log.cpp
Normal file
502
src/debug/debug_log.cpp
Normal file
|
@ -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
|
1090
src/debug/gdb_server.cpp
Normal file
1090
src/debug/gdb_server.cpp
Normal file
File diff suppressed because it is too large
Load diff
595
src/debug/poll.cpp
Normal file
595
src/debug/poll.cpp
Normal file
|
@ -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
|
||||
}
|
60
src/debug/poll.h
Normal file
60
src/debug/poll.h
Normal file
|
@ -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 */
|
|
@ -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
|
||||
|
|
504
src/dos/dos_execute.cpp.orig
Normal file
504
src/dos/dos_execute.cpp.orig
Normal file
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
2057
src/gui/sdlmain.cpp.orig
Normal file
2057
src/gui/sdlmain.cpp.orig
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue