1
0
Fork 0

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:
diaxen 2020-05-11 17:59:02 -04:00 committed by Alex Page
parent eb0a3dffc2
commit cf4685e7aa
31 changed files with 7979 additions and 1006 deletions

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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();

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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();

View file

@ -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;

View file

@ -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:

View file

@ -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();

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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>

View file

@ -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
View 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
View 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

File diff suppressed because it is too large Load diff

595
src/debug/poll.cpp Normal file
View 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
View 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 */

View file

@ -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

View 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;
}

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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;