DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/debug/debug.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 #include "dosbox.h"
00021 #if C_DEBUG
00022 
00023 #include <string.h>
00024 #include <list>
00025 #include <vector>
00026 #include <ctype.h>
00027 #include <fstream>
00028 #include <iomanip>
00029 #include <string>
00030 #include <sstream>
00031 using namespace std;
00032 
00033 #include "debug.h"
00034 #include "cross.h" //snprintf
00035 #include "cpu.h"
00036 #include "fpu.h"
00037 #include "video.h"
00038 #include "pic.h"
00039 #include "vga.h"
00040 #include "mapper.h"
00041 #include "cpu.h"
00042 #include "pc98_gdc.h"
00043 #include "callback.h"
00044 #include "inout.h"
00045 #include "mixer.h"
00046 #include "timer.h"
00047 #include "paging.h"
00048 #include "support.h"
00049 #include "shell.h"
00050 #include "programs.h"
00051 #include "debug_inc.h"
00052 #include "../cpu/lazyflags.h"
00053 #include "keyboard.h"
00054 #include "setup.h"
00055 
00056 #ifdef WIN32
00057 void WIN32_Console();
00058 #else
00059 #include <termios.h>
00060 #include <unistd.h>
00061 static struct termios consolesettings;
00062 #endif
00063 int old_cursor_state;
00064 
00065 const char *egc_fgc_modes[4] = {
00066     "pattern",
00067     "background",
00068     "foreground",
00069     "(invalid)",
00070 };
00071 
00072 bool pc98_pegc_linear_framebuffer_enabled(void);
00073 void GFX_SetTitle(Bit32s cycles,Bits frameskip,Bits timing,bool paused);
00074 
00075 extern bool                 dos_kernel_disabled;
00076 extern bool                 is_paused;
00077 extern bool                 pc98_crt_mode;
00078 extern uint8_t              GDC_display_plane;
00079 extern uint8_t              GDC_display_plane_pending;
00080 extern bool                 pc98_256kb_boundary;
00081 extern bool                         gdc_5mhz_mode;
00082 extern bool                         enable_pc98_egc;
00083 extern bool                         enable_pc98_grcg;
00084 extern bool                         enable_pc98_16color;
00085 extern bool                         enable_pc98_256color;
00086 extern bool                         enable_pc98_256color_planar;
00087 extern bool                         enable_pc98_188usermod;
00088 extern bool                         GDC_vsync_interrupt;
00089 extern bool                         pc98_graphics_hide_odd_raster_200line;
00090 extern bool                         pc98_attr4_graphic;
00091 extern bool                         egc_enable_enable;
00092 extern uint8_t                      pc98_gdc_tile_counter;
00093 extern uint8_t                      pc98_gdc_modereg;
00094 extern egc_quad                     pc98_gdc_tiles;
00095 
00096 extern uint16_t                     pc98_egc_raw_values[8];
00097 
00098 extern uint16_t                     a1_font_load_addr;
00099 extern uint8_t                      a1_font_char_offset;
00100 
00101 extern egc_quad             pc98_egc_bgcm;
00102 extern egc_quad             pc98_egc_fgcm;
00103 
00104 extern uint8_t                     pc98_egc_access;
00105 extern uint8_t                     pc98_egc_srcmask[2]; /* host given (Neko: egc.srcmask) */
00106 extern uint8_t                     pc98_egc_maskef[2]; /* effective (Neko: egc.mask2) */
00107 extern uint8_t                     pc98_egc_mask[2]; /* host given (Neko: egc.mask) */
00108 
00109 extern uint8_t                     pc98_egc_fgc;
00110 extern uint8_t                     pc98_egc_lead_plane;
00111 extern uint8_t                     pc98_egc_compare_lead;
00112 extern uint8_t                     pc98_egc_lightsource;
00113 extern uint8_t                     pc98_egc_shiftinput;
00114 extern uint8_t                     pc98_egc_regload;
00115 extern uint8_t                     pc98_egc_rop;
00116 extern uint8_t                     pc98_egc_foreground_color;
00117 extern uint8_t                     pc98_egc_background_color;
00118 
00119 extern bool                        pc98_egc_shift_descend;
00120 extern uint8_t                     pc98_egc_shift_destbit;
00121 extern uint8_t                     pc98_egc_shift_srcbit;
00122 extern uint16_t                    pc98_egc_shift_length;
00123 
00124 extern unsigned char        pc98_text_first_row_scanline_start;  /* port 70h */
00125 extern unsigned char        pc98_text_first_row_scanline_end;    /* port 72h */
00126 extern unsigned char        pc98_text_row_scanline_blank_at;     /* port 74h */
00127 extern unsigned char        pc98_text_row_scroll_lines;          /* port 76h */
00128 extern unsigned char        pc98_text_row_scroll_count_start;    /* port 78h */
00129 extern unsigned char        pc98_text_row_scroll_num_lines;      /* port 7Ah */
00130 
00131 extern bool logBuffSuppressConsole;
00132 extern bool logBuffSuppressConsoleNeedUpdate;
00133 
00134 // Forwards
00135 static void DrawCode(void);
00136 static void DrawInput(void);
00137 static void DEBUG_RaiseTimerIrq(void);
00138 static void SaveMemory(Bit16u seg, Bit32u ofs1, Bit32u num);
00139 static void SaveMemoryBin(Bit16u seg, Bit32u ofs1, Bit32u num);
00140 static void LogMCBS(void);
00141 static void LogGDT(void);
00142 static void LogLDT(void);
00143 static void LogIDT(void);
00144 static void LogXMS(void);
00145 static void LogEMS(void);
00146 static void LogFNKEY(void);
00147 static void LogPages(char* selname);
00148 static void LogCPUInfo(void);
00149 static void OutputVecTable(char* filename);
00150 static void DrawVariables(void);
00151 static void LogDOSKernMem(void);
00152 static void LogBIOSMem(void);
00153 
00154 bool inhibit_int_breakpoint=false;
00155 
00156 void DEBUG_DrawInput(void) {
00157     DrawInput();
00158 }
00159 
00160 void DEBUG_BeginPagedContent(void);
00161 void DEBUG_EndPagedContent(void);
00162 Bitu MEM_PageMaskActive(void);
00163 Bit32u MEM_get_address_bits();
00164 Bitu MEM_TotalPages(void);
00165 Bitu MEM_PageMask(void);
00166 
00167 static void LogEMUMachine(void) {
00168     DEBUG_BeginPagedContent();
00169 
00170     DEBUG_ShowMsg("Emulator machine:");
00171 
00172     {
00173         const char *m = "?";
00174         const char *cardName = "";
00175 
00176         switch (machine) {
00177             case MCH_HERC:      m="Hercules";   break;
00178             case MCH_CGA:       m="CGA";        break;
00179             case MCH_TANDY:     m="Tandy";      break;
00180             case MCH_PCJR:      m="PCjr";       break;
00181             case MCH_EGA:       m="EGA";        break;
00182             case MCH_VGA:       m="VGA";        break;
00183             case MCH_AMSTRAD:   m="Amstrad";    break;
00184             case MCH_PC98:      m="PC-98";      break;
00185             case MCH_FM_TOWNS:  m="FM Towns";   break;
00186             case MCH_MCGA:      m="MCGA";       break;
00187             case MCH_MDA:       m="MDA";        break;
00188             default:            break;
00189         }
00190 
00191         switch (svgaCard) {
00192             case SVGA_None:             cardName ="";                break;
00193             case SVGA_S3Trio:           cardName ="S3 Trio";         break;
00194             case SVGA_TsengET4K:        cardName ="Tseng ET4000";    break;
00195             case SVGA_TsengET3K:        cardName ="Tseng ET3000";    break;
00196             case SVGA_ParadisePVGA1A:   cardName ="Paradise PVGA1A"; break;
00197         }
00198 
00199         DEBUG_ShowMsg("Machine: %s %s",m, cardName);
00200     }
00201 
00202     DEBUG_EndPagedContent();
00203 }
00204 
00205 static void LogEMUMem(void) {
00206     DEBUG_BeginPagedContent();
00207 
00208     DEBUG_ShowMsg("Emulator memory:");
00209     DEBUG_ShowMsg("A20 gate:                    %s",MEM_A20_Enabled() ? "ON" : "OFF");
00210     DEBUG_ShowMsg("CPU address bits:            %u",(unsigned int)MEM_get_address_bits());
00211     DEBUG_ShowMsg("CPU address mask:            0x%lx",((unsigned long)MEM_PageMask() << 12UL) | 0xFFFUL);
00212     DEBUG_ShowMsg("CPU address mask current:    0x%lx",((unsigned long)MEM_PageMaskActive() << 12UL) | 0xFFFUL);
00213     DEBUG_ShowMsg("Memory reported size:        %lu bytes",(unsigned long)MEM_TotalPages() << 12UL);
00214 
00215     DEBUG_EndPagedContent();
00216 }
00217 
00218 bool XMS_Active(void);
00219 
00220 Bitu XMS_GetTotalHandles(void);
00221 bool XMS_GetHandleInfo(Bitu &phys_location,Bitu &size,Bitu &lockcount,bool &free,Bitu handle);
00222 
00223 LoopHandler *old_loop = NULL;
00224 
00225 char* AnalyzeInstruction(char* inst, bool saveSelector);
00226 Bit32u GetHexValue(char* const str, char* &hex,bool *parsed=NULL);
00227 void SkipSpace(char*& hex);
00228 
00229 #if 0
00230 class DebugPageHandler : public PageHandler {
00231 public:
00232         Bit8u readb(PhysPt /*addr*/) {
00233         }
00234         Bit16u readw(PhysPt /*addr*/) {
00235         }
00236         Bit32u readd(PhysPt /*addr*/) {
00237         }
00238         void writeb(PhysPt /*addr*/,Bit8u /*val*/) {
00239         }
00240         void writew(PhysPt /*addr*/,Bit16u /*val*/) {
00241         }
00242         void writed(PhysPt /*addr*/,Bit32u /*val*/) {
00243         }
00244 };
00245 #endif
00246 
00247 
00248 class DEBUG;
00249 
00250 //DEBUG*        pDebugcom       = 0;
00251 bool    exitLoop        = false;
00252 
00253 
00254 // Heavy Debugging Vars for logging
00255 #if C_HEAVY_DEBUG
00256 static ofstream         cpuLogFile;
00257 static bool             cpuLog                  = false;
00258 static int              cpuLogCounter   = 0;
00259 static int              cpuLogType              = 1;    // log detail
00260 static bool zeroProtect = false;
00261 bool    logHeavy        = false;
00262 #endif
00263 
00264 
00265 
00266 static struct  {
00267         Bit32u eax,ebx,ecx,edx,esi,edi,ebp,esp,eip;
00268 } oldregs;
00269 
00270 static char curSelectorName[3] = { 0,0,0 };
00271 
00272 static Segment oldsegs[6];
00273 static Bitu oldflags,oldcpucpl;
00274 DBGBlock dbg;
00275 extern Bitu cycle_count;
00276 static bool debugging = false;
00277 static bool debug_running = false;
00278 static bool check_rescroll = false;
00279 
00280 bool IsDebuggerActive(void) {
00281     return debugging;
00282 }
00283 
00284 bool IsDebuggerRunwatch(void) {
00285     return debug_running;
00286 }
00287 
00288 static void SetColor(Bitu test) {
00289         if (test) {
00290                 if (has_colors()) { wattrset(dbg.win_reg,COLOR_PAIR(PAIR_BYELLOW_BLACK));}
00291         } else {
00292                 if (has_colors()) { wattrset(dbg.win_reg,0);}
00293         }
00294 }
00295 
00296 #define MAXCMDLEN 254 
00297 struct SCodeViewData {  
00298         int     cursorPos;
00299         Bit16u  firstInstSize;
00300         Bit16u  useCS;
00301         Bit32u  useEIPlast, useEIPmid;
00302         Bit32u  useEIP;
00303         Bit16u  cursorSeg;
00304         Bit32u  cursorOfs;
00305         bool    ovrMode;
00306         char    inputStr[MAXCMDLEN+1];
00307         char    suspInputStr[MAXCMDLEN+1];
00308         int     inputPos;
00309 } codeViewData;
00310 
00311 static Bit16u  dataSeg;
00312 static Bit32u  dataOfs;
00313 static bool    showExtend = true;
00314 
00315 static void ClearInputLine(void) {
00316         codeViewData.inputStr[0] = 0;
00317         codeViewData.inputPos = 0;
00318 }
00319 
00320 // History stuff
00321 #define MAX_HIST_BUFFER 50
00322 static list<string> histBuff;
00323 static list<string>::iterator histBuffPos = histBuff.end();
00324 
00325 /***********/
00326 /* Helpers */
00327 /***********/
00328 
00329 static const Bit64u mem_no_address = (Bit64u)(~0ULL);
00330 
00331 Bit64u LinMakeProt(Bit16u selector, Bit32u offset)
00332 {
00333         Descriptor desc;
00334 
00335     if (cpu.gdt.GetDescriptor(selector,desc)) {
00336         if (selector >= 8 && desc.Type() != 0) {
00337             if (offset <= desc.GetLimit())
00338                 return desc.GetBase()+(Bit64u)offset;
00339         }
00340     }
00341 
00342         return mem_no_address;
00343 }
00344 
00345 Bit64u GetAddress(Bit16u seg, Bit32u offset)
00346 {
00347         if (cpu.pmode && !(reg_flags & FLAG_VM))
00348         return LinMakeProt(seg,offset);
00349 
00350         if (seg==SegValue(cs)) return SegPhys(cs)+(Bit64u)offset;
00351         return ((Bit64u)seg<<4u)+offset;
00352 }
00353 
00354 static char empty_sel[] = { ' ',' ',0 };
00355 
00356 bool GetDescriptorInfo(char* selname, char* out1, char* out2)
00357 {
00358         Bitu sel;
00359         Descriptor desc;
00360 
00361         if (strstr(selname,"cs") || strstr(selname,"CS")) sel = SegValue(cs);
00362         else if (strstr(selname,"ds") || strstr(selname,"DS")) sel = SegValue(ds);
00363         else if (strstr(selname,"es") || strstr(selname,"ES")) sel = SegValue(es);
00364         else if (strstr(selname,"fs") || strstr(selname,"FS")) sel = SegValue(fs);
00365         else if (strstr(selname,"gs") || strstr(selname,"GS")) sel = SegValue(gs);
00366         else if (strstr(selname,"ss") || strstr(selname,"SS")) sel = SegValue(ss);
00367         else {
00368                 sel = GetHexValue(selname,selname);
00369                 if (*selname==0) selname=empty_sel;
00370         }
00371         if (cpu.gdt.GetDescriptor(sel,desc)) {
00372                 switch (desc.Type()) {
00373                         case DESC_TASK_GATE:
00374                                 sprintf(out1,"%s: s:%08lX type:%02X p",selname,(unsigned long)desc.GetSelector(),(int)desc.saved.gate.type);
00375                                 sprintf(out2,"    TaskGate   dpl : %01X %1X",desc.saved.gate.dpl,desc.saved.gate.p);
00376                                 return true;
00377                         case DESC_LDT:
00378                         case DESC_286_TSS_A:
00379                         case DESC_286_TSS_B:
00380                         case DESC_386_TSS_A:
00381                         case DESC_386_TSS_B:
00382                                 sprintf(out1,"%s: b:%08lX type:%02X pag",selname,(unsigned long)desc.GetBase(),(int)desc.saved.seg.type);
00383                                 sprintf(out2,"    l:%08lX dpl : %01X %1X%1X%1X",(unsigned long)desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.g);
00384                                 return true;
00385                         case DESC_286_CALL_GATE:
00386                         case DESC_386_CALL_GATE:
00387                                 sprintf(out1,"%s: s:%08lX type:%02X p params: %02X",selname,(unsigned long)desc.GetSelector(),desc.saved.gate.type,desc.saved.gate.paramcount);
00388                                 sprintf(out2,"    o:%08lX dpl : %01X %1X",(unsigned long)desc.GetOffset(),desc.saved.gate.dpl,desc.saved.gate.p);
00389                                 return true;
00390                         case DESC_286_INT_GATE:
00391                         case DESC_286_TRAP_GATE:
00392                         case DESC_386_INT_GATE:
00393                         case DESC_386_TRAP_GATE:
00394                                 sprintf(out1,"%s: s:%08lX type:%02X p",selname,(unsigned long)desc.GetSelector(),desc.saved.gate.type);
00395                                 sprintf(out2,"    o:%08lX dpl : %01X %1X",(unsigned long)desc.GetOffset(),desc.saved.gate.dpl,desc.saved.gate.p);
00396                                 return true;
00397                 }
00398                 sprintf(out1,"%s: b:%08lX type:%02X parbg",selname,(unsigned long)desc.GetBase(),desc.saved.seg.type);
00399                 sprintf(out2,"    l:%08lX dpl : %01X %1X%1X%1X%1X%1X",(unsigned long)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);
00400                 return true;
00401         } else {
00402                 strcpy(out1,"                                  ");
00403                 strcpy(out2,"                                  ");
00404         }
00405         return false;
00406 }
00407 
00408 /********************/
00409 /* DebugVar   stuff */
00410 /********************/
00411 
00412 class CDebugVar
00413 {
00414 public:
00415         CDebugVar(char* _name, PhysPt _adr) { adr=_adr; safe_strncpy(name,_name,16); hasvalue = false; value = 0; };
00416         
00417         char*  GetName (void)                 { return name; };
00418         PhysPt GetAdr  (void)                 { return adr; };
00419         void   SetValue(bool has, Bit16u val) { hasvalue = has; value=val; };
00420         Bit16u GetValue(void)                 { return value; };
00421         bool   HasValue(void)                 { return hasvalue; };
00422 
00423 private:
00424         PhysPt  adr;
00425         char    name[16];
00426         bool    hasvalue;
00427         Bit16u  value;
00428 
00429 public: 
00430         static void       InsertVariable(char* name, PhysPt adr);
00431         static CDebugVar* FindVar       (PhysPt pt);
00432         static void       DeleteAll     ();
00433         static bool       SaveVars      (char* name);
00434         static bool       LoadVars      (char* name);
00435 
00436         static std::vector<CDebugVar*> varList;
00437 };
00438 
00439 std::vector<CDebugVar*> CDebugVar::varList;
00440 
00441 
00442 /********************/
00443 /* Breakpoint stuff */
00444 /********************/
00445 
00446 bool mustCompleteInstruction = false;
00447 bool skipFirstInstruction = false;
00448 
00449 enum EBreakpoint { BKPNT_UNKNOWN, BKPNT_PHYSICAL, BKPNT_INTERRUPT, BKPNT_MEMORY, BKPNT_MEMORY_PROT, BKPNT_MEMORY_LINEAR };
00450 
00451 #define BPINT_ALL 0x100
00452 
00453 class CBreakpoint
00454 {
00455 public:
00456 
00457         CBreakpoint(void);
00458         void                                    SetAddress              (Bit16u seg, Bit32u off)        { location = (PhysPt)GetAddress(seg,off); type = BKPNT_PHYSICAL; segment = seg; offset = off; };
00459         void                                    SetAddress              (PhysPt adr)                            { location = adr; type = BKPNT_PHYSICAL; };
00460         void                                    SetInt                  (Bit8u _intNr, Bit16u ah, Bit16u al)    { intNr = _intNr, ahValue = ah; alValue = al; type = BKPNT_INTERRUPT; };
00461         void                                    SetOnce                 (bool _once)                            { once = _once; };
00462         void                                    SetType                 (EBreakpoint _type)                     { type = _type; };
00463         void                                    SetValue                (Bit8u value)                           { ahValue = value; };
00464         void                                    SetOther                (Bit8u other)                           { alValue = other; };   
00465 
00466         bool                                    IsActive                (void)                                          { return active; };
00467         void                                    Activate                (bool _active);
00468 
00469         EBreakpoint                             GetType                 (void)                                          { return type; };
00470         bool                                    GetOnce                 (void)                                          { return once; };
00471         PhysPt                                  GetLocation             (void)                                          { return location; };
00472         Bit16u                                  GetSegment              (void)                                          { return segment; };
00473         Bit32u                                  GetOffset               (void)                                          { return offset; };
00474         Bit8u                                   GetIntNr                (void)                                          { return intNr; };
00475         Bit16u                                  GetValue                (void)                                          { return ahValue; };
00476         Bit16u                                  GetOther                (void)                                          { return alValue; };
00477 
00478         // statics
00479         static CBreakpoint*             AddBreakpoint           (Bit16u seg, Bit32u off, bool once);
00480         static CBreakpoint*             AddIntBreakpoint        (Bit8u intNum, Bit16u ah, Bit16u al, bool once);
00481         static CBreakpoint*             AddMemBreakpoint        (Bit16u seg, Bit32u off);
00482         static void                             DeactivateBreakpoints();
00483         static void                             ActivateBreakpoints     ();
00484         static void                             ActivateBreakpointsExceptAt(PhysPt adr);
00485         static bool                             CheckBreakpoint         (Bit16u seg, Bit32u off);
00486         static bool                             CheckIntBreakpoint      (PhysPt adr, Bit8u intNr, Bit16u ahValue, Bit16u alValue);
00487         static CBreakpoint*             FindPhysBreakpoint      (Bit16u seg, Bit32u off, bool once);
00488         static CBreakpoint*             FindOtherActiveBreakpoint(PhysPt adr, CBreakpoint* skip);
00489         static bool                             IsBreakpoint            (Bit16u seg, Bit32u off);
00490         static bool                             DeleteBreakpoint        (Bit16u seg, Bit32u off);
00491         static bool                             DeleteByIndex           (Bit16u index);
00492         static void                             DeleteAll                       (void);
00493         static void                             ShowList                        (void);
00494 
00495 
00496 private:
00497         EBreakpoint     type;
00498         // Physical
00499         PhysPt          location;
00500 #if !C_HEAVY_DEBUG
00501         Bit8u           oldData;
00502 #endif
00503         Bit16u          segment;
00504         Bit32u          offset;
00505         // Int
00506         Bit8u           intNr;
00507         Bit16u          ahValue;
00508         Bit16u          alValue;
00509         // Shared
00510         bool            active;
00511         bool            once;
00512 
00513         static std::list<CBreakpoint*>  BPoints;
00514 };
00515 
00516 CBreakpoint::CBreakpoint(void):type(BKPNT_UNKNOWN),location(0),
00517 #if !C_HEAVY_DEBUG
00518 oldData(0xCC),
00519 #endif
00520 segment(0),offset(0),intNr(0),ahValue(0),alValue(0),active(false),once(false) { }
00521 
00522 void CBreakpoint::Activate(bool _active)
00523 {
00524 #if !C_HEAVY_DEBUG
00525         if (GetType() == BKPNT_PHYSICAL) {
00526                 if (_active) {
00527                         // Set 0xCC and save old value
00528                         Bit8u data = mem_readb(location);
00529                         if (data != 0xCC) {
00530                                 oldData = data;
00531                                 mem_writeb(location,0xCC);
00532                         } else if (!active) {
00533                                 // Another activate breakpoint is already here.
00534                                 // Find it, and copy its oldData value
00535                                 CBreakpoint *bp = FindOtherActiveBreakpoint(location, this);
00536 
00537                                 if (!bp || bp->oldData == 0xCC) {
00538                                         // This might also happen if there is a real 0xCC instruction here
00539                                         DEBUG_ShowMsg("DEBUG: Internal error while activating breakpoint.\n");
00540                                         oldData = 0xCC;
00541                                 } else
00542                                         oldData = bp->oldData;
00543                         };
00544                 } else {
00545                         if (mem_readb(location) == 0xCC) {
00546                                 if (oldData == 0xCC)
00547                                         DEBUG_ShowMsg("DEBUG: Internal error while deactivating breakpoint.\n");
00548 
00549                                 // Check if we are the last active breakpoint at this location
00550                                 bool otherActive = (FindOtherActiveBreakpoint(location, this) != 0);
00551 
00552                                 // If so, remove 0xCC and set old value
00553                                 if (!otherActive)
00554                                         mem_writeb(location, oldData);
00555                         };
00556                 }
00557         }
00558 #endif
00559         active = _active;
00560 }
00561 
00562 // Statics
00563 std::list<CBreakpoint*> CBreakpoint::BPoints;
00564 
00565 CBreakpoint* CBreakpoint::AddBreakpoint(Bit16u seg, Bit32u off, bool once)
00566 {
00567         CBreakpoint* bp = new CBreakpoint();
00568         bp->SetAddress          (seg,off);
00569         bp->SetOnce                     (once);
00570         BPoints.push_front      (bp);
00571         return bp;
00572 }
00573 
00574 CBreakpoint* CBreakpoint::AddIntBreakpoint(Bit8u intNum, Bit16u ah, Bit16u al, bool once)
00575 {
00576         CBreakpoint* bp = new CBreakpoint();
00577         bp->SetInt                      (intNum,ah,al);
00578         bp->SetOnce                     (once);
00579         BPoints.push_front      (bp);
00580         return bp;
00581 }
00582 
00583 CBreakpoint* CBreakpoint::AddMemBreakpoint(Bit16u seg, Bit32u off)
00584 {
00585         CBreakpoint* bp = new CBreakpoint();
00586         bp->SetAddress          (seg,off);
00587         bp->SetOnce                     (false);
00588         bp->SetType                     (BKPNT_MEMORY);
00589         BPoints.push_front      (bp);
00590         return bp;
00591 }
00592 
00593 void CBreakpoint::ActivateBreakpoints()
00594 {
00595         // activate all breakpoints
00596         std::list<CBreakpoint*>::iterator i;
00597         for (i = BPoints.begin(); i != BPoints.end(); ++i)
00598                 (*i)->Activate(true);
00599 }
00600 
00601 void CBreakpoint::DeactivateBreakpoints()
00602 {
00603         // deactivate all breakpoints
00604         std::list<CBreakpoint*>::iterator i;
00605         for (i = BPoints.begin(); i != BPoints.end(); ++i)
00606                 (*i)->Activate(false);
00607 }
00608 
00609 void CBreakpoint::ActivateBreakpointsExceptAt(PhysPt adr)
00610 {
00611         // activate all breakpoints, except those at adr
00612         std::list<CBreakpoint*>::iterator i;
00613         for (i = BPoints.begin(); i != BPoints.end(); ++i) {
00614                 CBreakpoint* bp = (*i);
00615                 // Do not activate breakpoints at adr
00616                 if (bp->GetType() == BKPNT_PHYSICAL && bp->GetLocation() == adr)
00617                         continue;
00618                 bp->Activate(true);
00619         }
00620 }
00621 
00622 bool CBreakpoint::CheckBreakpoint(Bit16u seg, Bit32u off)
00623 // Checks if breakpoint is valid and should stop execution
00624 {
00625         // Quick exit if there are no breakpoints
00626         if (BPoints.empty()) return false;
00627 
00628         // Search matching breakpoint
00629         std::list<CBreakpoint*>::iterator i;
00630         CBreakpoint* bp;
00631         for(i=BPoints.begin(); i != BPoints.end(); ++i) {
00632                 bp = (*i);
00633                 if ((bp->GetType()==BKPNT_PHYSICAL) && bp->IsActive() && (bp->GetSegment()==seg) && (bp->GetOffset()==off)) {
00634                         // Found, 
00635                         if (bp->GetOnce()) {
00636                                 // delete it, if it should only be used once
00637                                 (BPoints.erase)(i);
00638                                 bp->Activate(false);
00639                                 delete bp;
00640                         } else {
00641                                 // Also look for once-only breakpoints at this address
00642                                 bp = FindPhysBreakpoint(seg, off, true);
00643                                 if (bp) {
00644                                         BPoints.remove(bp);
00645                                         bp->Activate(false);
00646                                         delete bp;
00647                                 }
00648                         }
00649                         return true;
00650                 } 
00651 #if C_HEAVY_DEBUG
00652                 // Memory breakpoint support
00653                 else if (bp->IsActive()) {
00654                         if ((bp->GetType()==BKPNT_MEMORY) || (bp->GetType()==BKPNT_MEMORY_PROT) || (bp->GetType()==BKPNT_MEMORY_LINEAR)) {
00655                                 // Watch Protected Mode Memoryonly in pmode
00656                                 if (bp->GetType()==BKPNT_MEMORY_PROT) {
00657                                         // Check if pmode is active
00658                                         if (!cpu.pmode) return false;
00659                                         // Check if descriptor is valid
00660                                         Descriptor desc;
00661                                         if (!cpu.gdt.GetDescriptor(bp->GetSegment(),desc)) return false;
00662                                         if (desc.GetLimit()==0) return false;
00663                                 }
00664 
00665                                 Bitu address; 
00666                                 if (bp->GetType()==BKPNT_MEMORY_LINEAR) address = bp->GetOffset();
00667                                 else address = (Bitu)GetAddress(bp->GetSegment(),bp->GetOffset());
00668                                 Bit8u value=0;
00669                                 if (mem_readb_checked((PhysPt)address,&value)) return false;
00670                                 if (bp->GetValue() != value) {
00671                                         // Yup, memory value changed
00672                                         DEBUG_ShowMsg("DEBUG: Memory breakpoint %s: %04X:%04X - %02X -> %02X\n",(bp->GetType()==BKPNT_MEMORY_PROT)?"(Prot)":"",bp->GetSegment(),bp->GetOffset(),bp->GetValue(),value);
00673                                         bp->SetValue(value);
00674                                         return true;
00675                                 }               
00676                         }
00677                 }
00678 #endif
00679         }
00680         return false;
00681 }
00682 
00683 bool CBreakpoint::CheckIntBreakpoint(PhysPt adr, Bit8u intNr, Bit16u ahValue, Bit16u alValue)
00684 // Checks if interrupt breakpoint is valid and should stop execution
00685 {
00686         if (BPoints.empty()) return false;
00687 
00688     // unused
00689     (void)adr;
00690 
00691         // Search matching breakpoint
00692         std::list<CBreakpoint*>::iterator i;
00693         for(i=BPoints.begin(); i != BPoints.end(); ++i) {
00694                 CBreakpoint* bp = (*i);
00695                 if ((bp->GetType()==BKPNT_INTERRUPT) && bp->IsActive() && (bp->GetIntNr()==intNr)) {
00696                         if (((bp->GetValue()==BPINT_ALL) || (bp->GetValue()==ahValue)) && ((bp->GetOther()==BPINT_ALL) || (bp->GetOther()==alValue))) {
00697                                 // Ignore it once ?
00698                                 // Found
00699                                 if (bp->GetOnce()) {
00700                                         // delete it, if it should only be used once
00701                                         (BPoints.erase)(i);
00702                                         bp->Activate(false);
00703                                         delete bp;
00704                                 }
00705                                 return true;
00706                         }
00707                 }
00708         }
00709         return false;
00710 }
00711 
00712 void CBreakpoint::DeleteAll() 
00713 {
00714         std::list<CBreakpoint*>::iterator i;
00715         for(i=BPoints.begin(); i != BPoints.end(); ++i) {
00716                 CBreakpoint* bp = (*i);
00717                 bp->Activate(false);
00718                 delete bp;
00719         }
00720         (BPoints.clear)();
00721 }
00722 
00723 
00724 bool CBreakpoint::DeleteByIndex(Bit16u index) 
00725 {
00726         // Search matching breakpoint
00727         int nr = 0;
00728         std::list<CBreakpoint*>::iterator i;
00729         CBreakpoint* bp;
00730         for(i=BPoints.begin(); i != BPoints.end(); ++i) {
00731                 if (nr==index) {
00732                         bp = (*i);
00733                         (BPoints.erase)(i);
00734                         bp->Activate(false);
00735                         delete bp;
00736                         return true;
00737                 }
00738                 nr++;
00739         }
00740         return false;
00741 }
00742 
00743 CBreakpoint* CBreakpoint::FindPhysBreakpoint(Bit16u seg, Bit32u off, bool once)
00744 {
00745         if (BPoints.empty()) return 0;
00746 #if !C_HEAVY_DEBUG
00747         PhysPt adr = GetAddress(seg, off);
00748 #endif
00749         // Search for matching breakpoint
00750         std::list<CBreakpoint*>::iterator i;
00751         CBreakpoint* bp;
00752         for(i=BPoints.begin(); i != BPoints.end(); ++i) {
00753                 bp = (*i);
00754 #if C_HEAVY_DEBUG
00755                 // Heavy debugging breakpoints are triggered by matching seg:off
00756                 bool atLocation = bp->GetSegment() == seg && bp->GetOffset() == off;
00757 #else
00758                 // Normal debugging breakpoints are triggered at an address
00759                 bool atLocation = bp->GetLocation() == adr;
00760 #endif
00761 
00762                 if (bp->GetType() == BKPNT_PHYSICAL && atLocation && bp->GetOnce() == once)
00763                         return bp;
00764         }
00765 
00766         return 0;
00767 }
00768 
00769 CBreakpoint* CBreakpoint::FindOtherActiveBreakpoint(PhysPt adr, CBreakpoint* skip)
00770 {
00771         std::list<CBreakpoint*>::iterator i;
00772         for (i = BPoints.begin(); i != BPoints.end(); ++i) {
00773                 CBreakpoint* bp = (*i);
00774                 if (bp != skip && bp->GetType() == BKPNT_PHYSICAL && bp->GetLocation() == adr && bp->IsActive())
00775                         return bp;
00776         }
00777         return 0;
00778 }
00779 
00780 // is there a permanent breakpoint at address ?
00781 bool CBreakpoint::IsBreakpoint(Bit16u seg, Bit32u off)
00782 {
00783         return FindPhysBreakpoint(seg, off, false) != 0;
00784 }
00785 
00786 bool CBreakpoint::DeleteBreakpoint(Bit16u seg, Bit32u off)
00787 {
00788         CBreakpoint* bp = FindPhysBreakpoint(seg, off, false);
00789         if (bp) {
00790                 BPoints.remove(bp);
00791                 delete bp;
00792                 return true;
00793         }
00794 
00795         return false;
00796 }
00797 
00798 
00799 void CBreakpoint::ShowList(void)
00800 {
00801         // iterate list 
00802         int nr = 0;
00803         std::list<CBreakpoint*>::iterator i;
00804         for(i=BPoints.begin(); i != BPoints.end(); ++i) {
00805                 CBreakpoint* bp = (*i);
00806                 if (bp->GetType()==BKPNT_PHYSICAL) {
00807                         DEBUG_ShowMsg("%02X. BP %04X:%04X\n",nr,bp->GetSegment(),bp->GetOffset());
00808                 } else if (bp->GetType()==BKPNT_INTERRUPT) {
00809                         if (bp->GetValue()==BPINT_ALL) DEBUG_ShowMsg("%02X. BPINT %02X\n",nr,bp->GetIntNr());
00810                         else if (bp->GetOther()==BPINT_ALL) DEBUG_ShowMsg("%02X. BPINT %02X AH=%02X\n",nr,bp->GetIntNr(),bp->GetValue());
00811                         else DEBUG_ShowMsg("%02X. BPINT %02X AH=%02X AL=%02X\n",nr,bp->GetIntNr(),bp->GetValue(),bp->GetOther());
00812                 } else if (bp->GetType()==BKPNT_MEMORY) {
00813                         DEBUG_ShowMsg("%02X. BPMEM %04X:%04X (%02X)\n",nr,bp->GetSegment(),bp->GetOffset(),bp->GetValue());
00814                 } else if (bp->GetType()==BKPNT_MEMORY_PROT) {
00815                         DEBUG_ShowMsg("%02X. BPPM %04X:%08X (%02X)\n",nr,bp->GetSegment(),bp->GetOffset(),bp->GetValue());
00816                 } else if (bp->GetType()==BKPNT_MEMORY_LINEAR ) {
00817                         DEBUG_ShowMsg("%02X. BPLM %08X (%02X)\n",nr,bp->GetOffset(),bp->GetValue());
00818                 }
00819                 nr++;
00820         }
00821 }
00822 
00823 bool DEBUG_Breakpoint(void)
00824 {
00825         /* First get the physical address and check for a set Breakpoint */
00826         if (!CBreakpoint::CheckBreakpoint(SegValue(cs),reg_eip)) return false;
00827         // Found. Breakpoint is valid
00828 //      PhysPt where=(PhysPt)GetAddress(SegValue(cs),reg_eip);
00829         CBreakpoint::DeactivateBreakpoints();   // Deactivate all breakpoints
00830         return true;
00831 }
00832 
00833 bool DEBUG_IntBreakpoint(Bit8u intNum)
00834 {
00835     if (inhibit_int_breakpoint) return false; /* or else stepping over INT 21h when BPINT 21h does nothing */
00836         /* First get the physical address and check for a set Breakpoint */
00837         PhysPt where=(PhysPt)GetAddress(SegValue(cs),reg_eip);
00838         if (!CBreakpoint::CheckIntBreakpoint(where,intNum,reg_ah,reg_al)) return false;
00839         // Found. Breakpoint is valid
00840         CBreakpoint::DeactivateBreakpoints();   // Deactivate all breakpoints
00841         return true;
00842 }
00843 
00844 static bool StepOver()
00845 {
00846         exitLoop = false;
00847         PhysPt start=(PhysPt)GetAddress(SegValue(cs),reg_eip);
00848         char dline[200];Bitu size;
00849         size=DasmI386(dline, start, reg_eip, cpu.code.big);
00850 
00851         if (strstr(dline,"call") || strstr(dline,"int") || strstr(dline,"loop") || strstr(dline,"rep")) {
00852                 // Don't add a temporary breakpoint if there's already one here
00853                 if (!CBreakpoint::FindPhysBreakpoint(SegValue(cs), (Bit32u)(reg_eip+size), true))
00854                         CBreakpoint::AddBreakpoint(SegValue(cs),(Bit32u)(reg_eip+size), true);
00855                 debugging=false;
00856 
00857         logBuffSuppressConsole = false;
00858         if (logBuffSuppressConsoleNeedUpdate) {
00859             logBuffSuppressConsoleNeedUpdate = false;
00860             DEBUG_RefreshPage(0);
00861         }
00862 
00863                 DrawCode();
00864                 mainMenu.get_item("mapper_debugger").check(false).refresh_item(mainMenu);
00865                 return true;
00866         } 
00867         return false;
00868 }
00869 
00870 bool DEBUG_ExitLoop(void)
00871 {
00872 #if C_HEAVY_DEBUG
00873         DrawVariables();
00874 #endif
00875 
00876         if (exitLoop) {
00877                 exitLoop = false;
00878                 return true;
00879         }
00880         return false;
00881 }
00882 
00883 /********************/
00884 /*   Draw windows   */
00885 /********************/
00886 
00887 static void DrawData(void) {
00888         if (dbg.win_main == NULL || dbg.win_data == NULL)
00889                 return;
00890 
00891         Bit8u ch;
00892         Bit32u add = dataOfs;
00893         Bit64u address;
00894     int w,h,y;
00895 
00896         /* Data win */  
00897     getmaxyx(dbg.win_data,h,w);
00898 
00899     if ((paging.enabled || cpu.pmode) && dbg.data_view != DBGBlock::DATV_PHYSICAL) h--;
00900 
00901         for (y=0;y<h;y++) {
00902                 // Address
00903         if (dbg.data_view == DBGBlock::DATV_SEGMENTED) {
00904             wattrset (dbg.win_data,0);
00905             mvwprintw (dbg.win_data,y,0,"%04X:%08X ",dataSeg,add);
00906         }
00907         else {
00908             wattrset (dbg.win_data,0);
00909             mvwprintw (dbg.win_data,y,0,"     %08X ",add);
00910         }
00911 
00912         if (dbg.data_view == DBGBlock::DATV_PHYSICAL) {
00913             for (int x=0; x<16; x++) {
00914                 address = add;
00915 
00916                 /* save the original page addr.
00917                  * we must hack the phys page tlb to make the hardware handler map 1:1 the page for this call. */
00918                 PhysPt opg = paging.tlb.phys_page[address>>12];
00919 
00920                 paging.tlb.phys_page[address>>12] = (Bit32u)(address>>12);
00921 
00922                 PageHandler *ph = MEM_GetPageHandler((Bitu)(address>>12));
00923 
00924                 if (ph->flags & PFLAG_READABLE)
00925                         ch = ph->GetHostReadPt((Bitu)(address>>12))[address&0xFFF];
00926                 else
00927                     ch = ph->readb((PhysPt)address);
00928 
00929                 paging.tlb.phys_page[address>>12] = opg;
00930 
00931                 wattrset (dbg.win_data,0);
00932                 mvwprintw (dbg.win_data,y,14+3*x,"%02X",ch);
00933                 if (ch<32 || !isprint(*reinterpret_cast<unsigned char*>(&ch))) ch='.';
00934                 mvwprintw (dbg.win_data,y,63+x,"%c",ch);
00935 
00936                 add++;
00937             }
00938         }
00939         else {
00940             for (int x=0; x<16; x++) {
00941                 if (dbg.data_view == DBGBlock::DATV_SEGMENTED)
00942                     address = GetAddress(dataSeg,add);
00943                 else
00944                     address = add;
00945 
00946                 if (address != mem_no_address) {
00947                     if (!mem_readb_checked((PhysPt)address,&ch)) {
00948                         wattrset (dbg.win_data,0);
00949                         mvwprintw (dbg.win_data,y,14+3*x,"%02X",ch);
00950                         if (ch<32 || !isprint(*reinterpret_cast<unsigned char*>(&ch))) ch='.';
00951                         mvwprintw (dbg.win_data,y,63+x,"%c",ch);
00952                     }
00953                     else {
00954                         wattrset (dbg.win_data, COLOR_PAIR(PAIR_BYELLOW_BLACK));
00955                         mvwprintw (dbg.win_data,y,14+3*x,"pf");
00956                         mvwprintw (dbg.win_data,y,63+x,".");
00957                     }
00958                 }
00959                 else {
00960                     wattrset (dbg.win_data, COLOR_PAIR(PAIR_BYELLOW_BLACK));
00961                     mvwprintw (dbg.win_data,y,14+3*x,"na");
00962                     mvwprintw (dbg.win_data,y,63+x,".");
00963                 }
00964 
00965                 add++;
00966             }
00967         }
00968         }
00969 
00970     if ((paging.enabled || cpu.pmode) && dbg.data_view != DBGBlock::DATV_PHYSICAL) {
00971         /* one line was set aside for this information */
00972         wattrset (dbg.win_data,0);
00973         if (dbg.data_view == DBGBlock::DATV_SEGMENTED) {
00974             address = GetAddress(dataSeg,dataOfs);
00975             if (address != mem_no_address)
00976                 mvwprintw (dbg.win_data,y,0," LIN=%08X ",(unsigned int)address);
00977             else
00978                 mvwprintw (dbg.win_data,y,0," LIN=XXXXXXXX ");
00979         }
00980         else {
00981             address = dataOfs;
00982             mvwprintw (dbg.win_data,y,0,"              ");
00983         }
00984 
00985         if (!mem_readb_checked((PhysPt)address,&ch)) {
00986             Bitu naddr = PAGING_GetPhysicalAddress((PhysPt)address);
00987             mvwprintw (dbg.win_data,y,14,"PHY=%08X ",(unsigned int)naddr);
00988         }
00989         else {
00990             mvwprintw (dbg.win_data,y,14,"PHY=XXXXXXXX ");
00991         }
00992 
00993         wclrtoeol(dbg.win_data);
00994 
00995         y++;
00996     }
00997 
00998         wrefresh(dbg.win_data);
00999 }
01000 
01001 void DrawRegistersUpdateOld(void) {
01002         /* Main Registers */
01003         oldregs.eax=reg_eax;
01004         oldregs.ebx=reg_ebx;
01005         oldregs.ecx=reg_ecx;
01006         oldregs.edx=reg_edx;
01007 
01008         oldregs.esi=reg_esi;
01009         oldregs.edi=reg_edi;
01010         oldregs.ebp=reg_ebp;
01011         oldregs.esp=reg_esp;
01012         oldregs.eip=reg_eip;
01013 
01014         oldsegs[ds].val=SegValue(ds);
01015         oldsegs[es].val=SegValue(es);
01016         oldsegs[fs].val=SegValue(fs);
01017         oldsegs[gs].val=SegValue(gs);
01018         oldsegs[ss].val=SegValue(ss);
01019         oldsegs[cs].val=SegValue(cs);
01020 
01021         /*Individual flags*/
01022         oldflags = reg_flags;
01023 
01024         oldcpucpl=cpu.cpl;
01025 }
01026 
01027 static void DrawRegisters(void) {
01028         if (dbg.win_main == NULL || dbg.win_reg == NULL)
01029                 return;
01030 
01031         /* Main Registers */
01032         SetColor(reg_eax!=oldregs.eax);mvwprintw (dbg.win_reg,0,4,"%08X",reg_eax);
01033         SetColor(reg_ebx!=oldregs.ebx);mvwprintw (dbg.win_reg,1,4,"%08X",reg_ebx);
01034         SetColor(reg_ecx!=oldregs.ecx);mvwprintw (dbg.win_reg,2,4,"%08X",reg_ecx);
01035         SetColor(reg_edx!=oldregs.edx);mvwprintw (dbg.win_reg,3,4,"%08X",reg_edx);
01036 
01037         SetColor(reg_esi!=oldregs.esi);mvwprintw (dbg.win_reg,0,18,"%08X",reg_esi);
01038         SetColor(reg_edi!=oldregs.edi);mvwprintw (dbg.win_reg,1,18,"%08X",reg_edi);
01039         SetColor(reg_ebp!=oldregs.ebp);mvwprintw (dbg.win_reg,2,18,"%08X",reg_ebp);
01040         SetColor(reg_esp!=oldregs.esp);mvwprintw (dbg.win_reg,3,18,"%08X",reg_esp);
01041         SetColor(reg_eip!=oldregs.eip);mvwprintw (dbg.win_reg,1,42,"%08X",reg_eip);
01042 
01043         SetColor(SegValue(ds)!=oldsegs[ds].val);mvwprintw (dbg.win_reg,0,31,"%04X",SegValue(ds));
01044         SetColor(SegValue(es)!=oldsegs[es].val);mvwprintw (dbg.win_reg,0,41,"%04X",SegValue(es));
01045         SetColor(SegValue(fs)!=oldsegs[fs].val);mvwprintw (dbg.win_reg,0,51,"%04X",SegValue(fs));
01046         SetColor(SegValue(gs)!=oldsegs[gs].val);mvwprintw (dbg.win_reg,0,61,"%04X",SegValue(gs));
01047         SetColor(SegValue(ss)!=oldsegs[ss].val);mvwprintw (dbg.win_reg,0,71,"%04X",SegValue(ss));
01048         SetColor(SegValue(cs)!=oldsegs[cs].val);mvwprintw (dbg.win_reg,1,31,"%04X",SegValue(cs));
01049 
01050         /*Individual flags*/
01051         Bitu changed_flags = reg_flags ^ oldflags;
01052 
01053         SetColor(changed_flags&FLAG_CF);
01054         mvwprintw (dbg.win_reg,1,53,"%01X",GETFLAG(CF) ? 1:0);
01055         SetColor(changed_flags&FLAG_ZF);
01056         mvwprintw (dbg.win_reg,1,56,"%01X",GETFLAG(ZF) ? 1:0);
01057         SetColor(changed_flags&FLAG_SF);
01058         mvwprintw (dbg.win_reg,1,59,"%01X",GETFLAG(SF) ? 1:0);
01059         SetColor(changed_flags&FLAG_OF);
01060         mvwprintw (dbg.win_reg,1,62,"%01X",GETFLAG(OF) ? 1:0);
01061         SetColor(changed_flags&FLAG_AF);
01062         mvwprintw (dbg.win_reg,1,65,"%01X",GETFLAG(AF) ? 1:0);
01063         SetColor(changed_flags&FLAG_PF);
01064         mvwprintw (dbg.win_reg,1,68,"%01X",GETFLAG(PF) ? 1:0);
01065 
01066 
01067         SetColor(changed_flags&FLAG_DF);
01068         mvwprintw (dbg.win_reg,1,71,"%01X",GETFLAG(DF) ? 1:0);
01069         SetColor(changed_flags&FLAG_IF);
01070         mvwprintw (dbg.win_reg,1,74,"%01X",GETFLAG(IF) ? 1:0);
01071         SetColor(changed_flags&FLAG_TF);
01072         mvwprintw (dbg.win_reg,1,77,"%01X",GETFLAG(TF) ? 1:0);
01073 
01074         SetColor(changed_flags&FLAG_IOPL);
01075         mvwprintw (dbg.win_reg,2,72,"%01X",GETFLAG(IOPL)>>12);
01076 
01077 
01078         SetColor(cpu.cpl ^ oldcpucpl);
01079         mvwprintw (dbg.win_reg,2,78,"%01X",cpu.cpl);
01080 
01081         if (cpu.pmode) {
01082                 if (reg_flags & FLAG_VM) mvwprintw(dbg.win_reg,0,76,"VM86");
01083                 else if (cpu.code.big) mvwprintw(dbg.win_reg,0,76,"Pr32");
01084                 else mvwprintw(dbg.win_reg,0,76,"Pr16");
01085                 mvwprintw(dbg.win_reg,2,62,paging.enabled ? "PAGE" : "NOPG");
01086         } else {
01087                 mvwprintw(dbg.win_reg,0,76,"Real");
01088                 mvwprintw(dbg.win_reg,2,62,"NOPG");
01089     }
01090 
01091         // Selector info, if available
01092         if ((cpu.pmode) && curSelectorName[0]) {
01093                 char out1[200], out2[200];
01094                 GetDescriptorInfo(curSelectorName,out1,out2);
01095                 mvwprintw(dbg.win_reg,2,28,out1);
01096                 mvwprintw(dbg.win_reg,3,28,out2);
01097         }
01098 
01099         wattrset(dbg.win_reg,0);
01100         mvwprintw(dbg.win_reg,3,60,"%u       ",cycle_count);
01101         wrefresh(dbg.win_reg);
01102 }
01103 
01104 bool DEBUG_IsPagingOutput(void);
01105 
01106 static void DrawInput(void) {
01107     if (!debugging) {
01108         if (has_colors())
01109         {
01110         wbkgdset(dbg.win_inp,COLOR_PAIR(PAIR_GREEN_BLACK));
01111         wattrset(dbg.win_inp,COLOR_PAIR(PAIR_GREEN_BLACK));
01112         }
01113 
01114         mvwprintw(dbg.win_inp,0,0,"%s","(Running)");
01115         wclrtoeol(dbg.win_inp);
01116     } else if (debug_running) {
01117         if (has_colors())
01118         {
01119         wbkgdset(dbg.win_inp,COLOR_PAIR(PAIR_GREEN_BLACK));
01120         wattrset(dbg.win_inp,COLOR_PAIR(PAIR_GREEN_BLACK));
01121         }
01122 
01123         mvwprintw(dbg.win_inp,0,0,"%s","(Running/watching)");
01124         wclrtoeol(dbg.win_inp);
01125     } else if (DEBUG_IsPagingOutput()) {
01126         if (has_colors())
01127         {
01128         wbkgdset(dbg.win_inp,COLOR_PAIR(PAIR_GREEN_BLACK));
01129         wattrset(dbg.win_inp,COLOR_PAIR(PAIR_GREEN_BLACK));
01130         }
01131 
01132         mvwprintw(dbg.win_inp,0,0,"%s","^ Paged content: Hit ENTER to continue, Q to exit paging");
01133         wclrtoeol(dbg.win_inp);
01134     } else {
01135         //TODO long lines
01136         char* dispPtr = codeViewData.inputStr; 
01137         char* curPtr = &codeViewData.inputStr[codeViewData.inputPos];
01138 
01139         wbkgdset(dbg.win_inp,COLOR_PAIR(PAIR_BLACK_GREY));
01140         wattrset(dbg.win_inp,COLOR_PAIR(PAIR_BLACK_GREY));
01141         mvwprintw(dbg.win_inp,0,0,"%c-> %s%c",
01142                 (codeViewData.ovrMode?'O':'I'),dispPtr,(*curPtr?' ':'_'));
01143         wclrtoeol(dbg.win_inp); // not correct in pdcurses if full line
01144         mvwchgat(dbg.win_inp,10,0,3,0,(PAIR_BLACK_GREY),NULL);
01145         if (*curPtr) {
01146             mvwchgat(dbg.win_inp,0,(int)(curPtr-dispPtr+4),1,0,(PAIR_BLACK_GREY),NULL);
01147         } 
01148     }
01149 
01150     wattrset(dbg.win_inp,0);
01151     wrefresh(dbg.win_inp);
01152 }
01153 
01154 static void DrawCode(void) {
01155         if (dbg.win_main == NULL || dbg.win_code == NULL)
01156                 return;
01157 
01158         Bit32u disEIP = codeViewData.useEIP;
01159         char dline[200];Bitu size;Bitu c;
01160         static char line20[21] = "                    ";
01161     int w,h;
01162 
01163     getmaxyx(dbg.win_code,h,w);
01164         for (int i=0;i<h;i++) {
01165         Bit64u start = GetAddress(codeViewData.useCS,disEIP);
01166 
01167                 bool saveSel = false;
01168                 if (has_colors()) {
01169                         if ((codeViewData.useCS==SegValue(cs)) && (disEIP == reg_eip)) {
01170                                 if (codeViewData.cursorPos==-1) {
01171                                         codeViewData.cursorPos = i; // Set Cursor 
01172                                 }
01173                                 if (i == codeViewData.cursorPos) {
01174                                         codeViewData.cursorSeg = SegValue(cs);
01175                                         codeViewData.cursorOfs = disEIP;
01176                                 }
01177                                 saveSel = (i == codeViewData.cursorPos);
01178 
01179                 if (i == codeViewData.cursorPos) {
01180                     wbkgdset(dbg.win_code,COLOR_PAIR(PAIR_BLACK_GREEN));
01181                     wattrset(dbg.win_code,COLOR_PAIR(PAIR_BLACK_GREEN));
01182                 }
01183                 else {
01184                     wbkgdset(dbg.win_code,COLOR_PAIR(PAIR_GREEN_BLACK));
01185                     wattrset(dbg.win_code,COLOR_PAIR(PAIR_GREEN_BLACK));
01186                 }
01187             } else if (i == codeViewData.cursorPos) {
01188                 wbkgdset(dbg.win_code,COLOR_PAIR(PAIR_BLACK_GREY));
01189                                 wattrset(dbg.win_code,COLOR_PAIR(PAIR_BLACK_GREY));                     
01190                                 codeViewData.cursorSeg = codeViewData.useCS;
01191                                 codeViewData.cursorOfs = disEIP;
01192                                 saveSel = true;
01193                         } else if (CBreakpoint::IsBreakpoint(codeViewData.useCS, disEIP)) {
01194                 wbkgdset(dbg.win_code,COLOR_PAIR(PAIR_GREY_RED));
01195                                 wattrset(dbg.win_code,COLOR_PAIR(PAIR_GREY_RED));                       
01196                         } else {
01197                 wbkgdset(dbg.win_code,0);
01198                 wattrset(dbg.win_code,0);
01199                         }
01200                 }
01201 
01202 
01203                 bool toolarge = false;
01204         bool no_bytes = false;
01205                 Bitu drawsize;
01206 
01207         if (start != mem_no_address) {
01208             drawsize=size=DasmI386(dline, (PhysPt)start, disEIP, cpu.code.big);
01209         }
01210         else {
01211             drawsize=size=1;
01212             dline[0]=0;
01213         }
01214                 mvwprintw(dbg.win_code,i,0,"%04X:%08X ",codeViewData.useCS,disEIP);
01215 
01216                 if (drawsize>10) { toolarge = true; drawsize = 9; }
01217  
01218         if (start != mem_no_address) {
01219             for (c=0;c<drawsize;c++) {
01220                 Bit8u value;
01221                 if (!mem_readb_checked((PhysPt)(start+c),&value)) {
01222                     wattrset (dbg.win_code,0);
01223                     wprintw(dbg.win_code,"%02X",value);
01224                 }
01225                 else {
01226                     no_bytes = true;
01227                     wattrset (dbg.win_code, COLOR_PAIR(PAIR_BYELLOW_BLACK));
01228                     wprintw(dbg.win_code,"pf");
01229                 }
01230             }
01231         }
01232         else {
01233             wattrset (dbg.win_code, COLOR_PAIR(PAIR_BYELLOW_BLACK));
01234             wprintw(dbg.win_code,"na");
01235         }
01236 
01237         wattrset (dbg.win_code,0);
01238         if (toolarge) { waddstr(dbg.win_code,".."); drawsize++; }
01239                 // Spacepad up to 20 characters
01240                 if(drawsize && (drawsize < 11)) {
01241                         line20[20 - drawsize*2] = 0;
01242                         waddstr(dbg.win_code,line20);
01243                         line20[20 - drawsize*2] = ' ';
01244                 } else waddstr(dbg.win_code,line20);
01245 
01246                 char empty_res[] = { 0 };
01247                 char* res = empty_res;
01248         wattrset (dbg.win_code,0);
01249         if (showExtend) res = AnalyzeInstruction(dline, saveSel);
01250                 // Spacepad it up to 28 characters
01251         if (no_bytes) dline[0] = 0;
01252                 size_t dline_len = strlen(dline);
01253         if (dline_len < 28) {
01254             for (c = (Bitu)dline_len; c < 28; c++) dline[c] = ' ';
01255             dline[28] = 0;
01256         }
01257                 waddstr(dbg.win_code,dline);
01258                 // Spacepad it up to 20 characters
01259                 size_t res_len = strlen(res);
01260                 if(res_len && (res_len < 21)) {
01261                         waddstr(dbg.win_code,res);
01262                         line20[20-res_len] = 0;
01263                         waddstr(dbg.win_code,line20);
01264                         line20[20-res_len] = ' ';
01265                 } else  waddstr(dbg.win_code,line20);
01266 
01267         wclrtoeol(dbg.win_code);
01268 
01269         disEIP+=(Bit32u)size;
01270 
01271                 if (i==0) codeViewData.firstInstSize = (Bit16u)size;
01272                 if (i==4) codeViewData.useEIPmid         = disEIP;
01273         }
01274 
01275         codeViewData.useEIPlast = disEIP;
01276 
01277         wrefresh(dbg.win_code);
01278 }
01279 
01280 static void SetCodeWinStart()
01281 {
01282         if ((SegValue(cs)==codeViewData.useCS) && (reg_eip>=codeViewData.useEIP) && (reg_eip<=codeViewData.useEIPlast)) {
01283                 // in valid window - scroll ?
01284                 if (reg_eip>=codeViewData.useEIPmid) codeViewData.useEIP += codeViewData.firstInstSize;
01285                 
01286         } else {
01287                 // totally out of range.
01288                 codeViewData.useCS      = SegValue(cs);
01289                 codeViewData.useEIP     = reg_eip;
01290         }
01291         codeViewData.cursorPos = -1;    // Recalc Cursor position
01292 }
01293 
01294 void DEBUG_CheckCSIP() {
01295     SetCodeWinStart();
01296 }
01297 
01298 /********************/
01299 /*    User input    */
01300 /********************/
01301 
01302 void SkipSpace(char*& hex) {
01303     while (*hex == ' ') hex++;
01304 }
01305 
01306 Bit32u GetHexValue(char* const str, char* &hex,bool *parsed)
01307 {
01308     Bit32u      value = 0;
01309     Bit32u regval = 0;
01310     hex = str;
01311     while (*hex == ' ') hex++;
01312 
01313     // The user can enclose a value in double quotations to enter hex values that
01314     // would collide with a flag name (AC, AF, CF, and DF).
01315     if (*hex == '\"') { hex++; }
01316     else if (strncmp(hex, "EFLAGS", 6) == 0) { hex += 6; regval = (Bit32u)reg_flags; }
01317     else if (strncmp(hex, "FLAGS", 5) == 0) { hex += 5; regval = (Bit32u)reg_flags; }
01318     else if (strncmp(hex, "IOPL", 4) == 0) { hex += 4; regval = (reg_flags & FLAG_IOPL) >> 12u; }
01319     else if (strncmp(hex, "CR0", 3) == 0) { hex += 3; regval = (Bit32u)cpu.cr0; }
01320     else if (strncmp(hex, "CR2", 3) == 0) { hex += 3; regval = (Bit32u)paging.cr2; }
01321     else if (strncmp(hex, "CR3", 3) == 0) { hex += 3; regval = (Bit32u)paging.cr3; }
01322     else if (strncmp(hex, "EAX", 3) == 0) { hex += 3; regval = reg_eax; }
01323     else if (strncmp(hex, "EBX", 3) == 0) { hex += 3; regval = reg_ebx; }
01324     else if (strncmp(hex, "ECX", 3) == 0) { hex += 3; regval = reg_ecx; }
01325     else if (strncmp(hex, "EDX", 3) == 0) { hex += 3; regval = reg_edx; }
01326     else if (strncmp(hex, "ESI", 3) == 0) { hex += 3; regval = reg_esi; }
01327     else if (strncmp(hex, "EDI", 3) == 0) { hex += 3; regval = reg_edi; }
01328     else if (strncmp(hex, "EBP", 3) == 0) { hex += 3; regval = reg_ebp; }
01329     else if (strncmp(hex, "ESP", 3) == 0) { hex += 3; regval = reg_esp; }
01330     else if (strncmp(hex, "EIP", 3) == 0) { hex += 3; regval = reg_eip; }
01331     else if (strncmp(hex, "AX", 2) == 0) { hex += 2; regval = reg_ax; }
01332     else if (strncmp(hex, "BX", 2) == 0) { hex += 2; regval = reg_bx; }
01333     else if (strncmp(hex, "CX", 2) == 0) { hex += 2; regval = reg_cx; }
01334     else if (strncmp(hex, "DX", 2) == 0) { hex += 2; regval = reg_dx; }
01335     else if (strncmp(hex, "SI", 2) == 0) { hex += 2; regval = reg_si; }
01336     else if (strncmp(hex, "DI", 2) == 0) { hex += 2; regval = reg_di; }
01337     else if (strncmp(hex, "BP", 2) == 0) { hex += 2; regval = reg_bp; }
01338     else if (strncmp(hex, "SP", 2) == 0) { hex += 2; regval = reg_sp; }
01339     else if (strncmp(hex, "IP", 2) == 0) { hex += 2; regval = reg_ip; }
01340     else if (strncmp(hex, "AL", 2) == 0) { hex += 2; regval = reg_al; }
01341     else if (strncmp(hex, "BL", 2) == 0) { hex += 2; regval = reg_bl; }
01342     else if (strncmp(hex, "CL", 2) == 0) { hex += 2; regval = reg_cl; }
01343     else if (strncmp(hex, "DL", 2) == 0) { hex += 2; regval = reg_dl; }
01344     else if (strncmp(hex, "AH", 2) == 0) { hex += 2; regval = reg_ah; }
01345     else if (strncmp(hex, "BH", 2) == 0) { hex += 2; regval = reg_bh; }
01346     else if (strncmp(hex, "CH", 2) == 0) { hex += 2; regval = reg_ch; }
01347     else if (strncmp(hex, "DH", 2) == 0) { hex += 2; regval = reg_dh; }
01348     else if (strncmp(hex, "CS", 2) == 0) { hex += 2; regval = SegValue(cs); }
01349     else if (strncmp(hex, "DS", 2) == 0) { hex += 2; regval = SegValue(ds); }
01350     else if (strncmp(hex, "ES", 2) == 0) { hex += 2; regval = SegValue(es); }
01351     else if (strncmp(hex, "FS", 2) == 0) { hex += 2; regval = SegValue(fs); }
01352     else if (strncmp(hex, "GS", 2) == 0) { hex += 2; regval = SegValue(gs); }
01353     else if (strncmp(hex, "SS", 2) == 0) { hex += 2; regval = SegValue(ss); }
01354     else if (strncmp(hex, "AC", 2) == 0) { hex += 2; regval = GETFLAG(AC); }
01355     else if (strncmp(hex, "AF", 2) == 0) { hex += 2; regval = GETFLAG(AF); }
01356     else if (strncmp(hex, "CF", 2) == 0) { hex += 2; regval = GETFLAG(CF); }
01357     else if (strncmp(hex, "DF", 2) == 0) { hex += 2; regval = GETFLAG(DF); }
01358     else if (strncmp(hex, "ID", 2) == 0) { hex += 2; regval = GETFLAG(ID); }
01359     else if (strncmp(hex, "IF", 2) == 0) { hex += 2; regval = GETFLAG(IF); }
01360     else if (strncmp(hex, "NT", 2) == 0) { hex += 2; regval = GETFLAG(NT); }
01361     else if (strncmp(hex, "OF", 2) == 0) { hex += 2; regval = GETFLAG(OF); }
01362     else if (strncmp(hex, "PF", 2) == 0) { hex += 2; regval = GETFLAG(PF); }
01363     else if (strncmp(hex, "SF", 2) == 0) { hex += 2; regval = GETFLAG(SF); }
01364     else if (strncmp(hex, "TF", 2) == 0) { hex += 2; regval = GETFLAG(TF); }
01365     else if (strncmp(hex, "VM", 2) == 0) { hex += 2; regval = GETFLAG(VM); }
01366     else if (strncmp(hex, "ZF", 2) == 0) { hex += 2; regval = GETFLAG(ZF); }
01367 
01368     else if (strncmp(hex,"DTASEG", 6) == 0) { hex += 6; regval = (!dos_kernel_disabled) ? (dos.dta() >> 16u)    : 0; }
01369     else if (strncmp(hex,"DTAOFF", 6) == 0) { hex += 6; regval = (!dos_kernel_disabled) ? (dos.dta() & 0xFFFFu) : 0; }
01370     else if (strncmp(hex,"PSPSEG", 6) == 0) { hex += 6; regval = (!dos_kernel_disabled) ?  dos.psp()            : 0; }
01371 
01372     while (*hex && *hex != '\"') {
01373         if ((*hex >= '0') && (*hex <= '9')) value = (value << 4u) + ((Bit32u)(*hex)) - '0';
01374         else if ((*hex >= 'A') && (*hex <= 'F')) value = (value << 4u) + ((Bit32u)(*hex)) - 'A' + 10u;
01375         else {
01376             if (*hex == '+') { hex++; return regval + value + GetHexValue(hex, hex, parsed); }
01377             else
01378                 if (*hex == '-') { hex++; return regval + value - GetHexValue(hex, hex, parsed); }
01379                 else break; // No valid char
01380         }
01381         hex++;
01382     }
01383 
01384     // If there is a closing quote, skip over it.
01385     if (*hex == '\"') {
01386         hex++;
01387     }
01388 
01389     if (parsed != NULL)
01390         *parsed = (hex != str);
01391 
01392     return regval + value;
01393 }
01394 
01395 bool ChangeRegister(char* const str)
01396 {
01397         char* hex = str;
01398 
01399     while (*hex) {
01400         while (*hex==' ') hex++;
01401 
01402         if (strstr(hex,"EFLAGS")==hex) { hex+=6; CPU_SetFlags(GetHexValue(hex,hex),FMASK_ALL); } else
01403         if (strstr(hex,"FLAGS")==hex) { hex+=5; CPU_SetFlags(GetHexValue(hex,hex),FMASK_ALL & 0xFFFFu); } else
01404 
01405         //             "IOPL"
01406 
01407         if (strncmp(hex,"EAX",3) == 0) { hex+=3; reg_eax = GetHexValue(hex,hex); } else
01408         if (strncmp(hex,"EBX",3) == 0) { hex+=3; reg_ebx = GetHexValue(hex,hex); } else
01409         if (strncmp(hex,"ECX",3) == 0) { hex+=3; reg_ecx = GetHexValue(hex,hex); } else
01410         if (strncmp(hex,"EDX",3) == 0) { hex+=3; reg_edx = GetHexValue(hex,hex); } else
01411         if (strncmp(hex,"ESI",3) == 0) { hex+=3; reg_esi = GetHexValue(hex,hex); } else
01412         if (strncmp(hex,"EDI",3) == 0) { hex+=3; reg_edi = GetHexValue(hex,hex); } else
01413         if (strncmp(hex,"EBP",3) == 0) { hex+=3; reg_ebp = GetHexValue(hex,hex); } else
01414         if (strncmp(hex,"ESP",3) == 0) { hex+=3; reg_esp = GetHexValue(hex,hex); } else
01415         if (strncmp(hex,"EIP",3) == 0) { hex+=3; reg_eip = GetHexValue(hex,hex); } else
01416 
01417         if (strncmp(hex,"AX",2) == 0) { hex+=2; reg_ax = (Bit16u)GetHexValue(hex,hex); } else
01418         if (strncmp(hex,"BX",2) == 0) { hex+=2; reg_bx = (Bit16u)GetHexValue(hex,hex); } else
01419         if (strncmp(hex,"CX",2) == 0) { hex+=2; reg_cx = (Bit16u)GetHexValue(hex,hex); } else
01420         if (strncmp(hex,"DX",2) == 0) { hex+=2; reg_dx = (Bit16u)GetHexValue(hex,hex); } else
01421         if (strncmp(hex,"SI",2) == 0) { hex+=2; reg_si = (Bit16u)GetHexValue(hex,hex); } else
01422         if (strncmp(hex,"DI",2) == 0) { hex+=2; reg_di = (Bit16u)GetHexValue(hex,hex); } else
01423         if (strncmp(hex,"BP",2) == 0) { hex+=2; reg_bp = (Bit16u)GetHexValue(hex,hex); } else
01424         if (strncmp(hex,"SP",2) == 0) { hex+=2; reg_sp = (Bit16u)GetHexValue(hex,hex); } else
01425         if (strncmp(hex,"IP",2) == 0) { hex+=2; reg_ip = (Bit16u)GetHexValue(hex,hex); } else
01426 
01427             if (strncmp(hex,"AL",2) == 0) { hex+=2; reg_al = (Bit8u)GetHexValue(hex,hex); } else
01428         if (strncmp(hex,"BL",2) == 0) { hex+=2; reg_bl = (Bit8u)GetHexValue(hex,hex); } else
01429         if (strncmp(hex,"CL",2) == 0) { hex+=2; reg_cl = (Bit8u)GetHexValue(hex,hex); } else
01430         if (strncmp(hex,"DL",2) == 0) { hex+=2; reg_dl = (Bit8u)GetHexValue(hex,hex); } else
01431 
01432         if (strncmp(hex,"AH",2) == 0) { hex+=2; reg_ah = (Bit8u)GetHexValue(hex,hex); } else
01433         if (strncmp(hex,"BH",2) == 0) { hex+=2; reg_bh = (Bit8u)GetHexValue(hex,hex); } else
01434         if (strncmp(hex,"CH",2) == 0) { hex+=2; reg_ch = (Bit8u)GetHexValue(hex,hex); } else
01435         if (strncmp(hex,"DH",2) == 0) { hex+=2; reg_dh = (Bit8u)GetHexValue(hex,hex); } else
01436 
01437         if (strncmp(hex,"CS",2) == 0) { hex+=2; SegSet16(cs,(Bit16u)GetHexValue(hex,hex)); } else
01438         if (strncmp(hex,"DS",2) == 0) { hex+=2; SegSet16(ds,(Bit16u)GetHexValue(hex,hex)); } else
01439         if (strncmp(hex,"ES",2) == 0) { hex+=2; SegSet16(es,(Bit16u)GetHexValue(hex,hex)); } else
01440         if (strncmp(hex,"FS",2) == 0) { hex+=2; SegSet16(fs,(Bit16u)GetHexValue(hex,hex)); } else
01441         if (strncmp(hex,"GS",2) == 0) { hex+=2; SegSet16(gs,(Bit16u)GetHexValue(hex,hex)); } else
01442         if (strncmp(hex,"SS",2) == 0) { hex+=2; SegSet16(ss,(Bit16u)GetHexValue(hex,hex)); } else
01443 
01444         if (strncmp(hex,"AC",2) == 0) { hex+=2; SETFLAGBIT(AC,GetHexValue(hex,hex)); } else
01445         if (strncmp(hex,"AF",2) == 0) { hex+=2; SETFLAGBIT(AF,GetHexValue(hex,hex)); } else
01446         if (strncmp(hex,"CF",2) == 0) { hex+=2; SETFLAGBIT(CF,GetHexValue(hex,hex)); } else
01447         if (strncmp(hex,"DF",2) == 0) { hex+=2; SETFLAGBIT(DF,GetHexValue(hex,hex)); } else
01448         if (strncmp(hex,"ID",2) == 0) { hex+=2; SETFLAGBIT(ID,GetHexValue(hex,hex)); } else
01449         if (strncmp(hex,"IF",2) == 0) { hex+=2; SETFLAGBIT(IF,GetHexValue(hex,hex)); } else
01450         //             "NT"
01451         if (strncmp(hex,"OF",2) == 0) { hex+=2; SETFLAGBIT(OF,GetHexValue(hex,hex)); } else
01452         if (strncmp(hex,"PF",2) == 0) { hex+=2; SETFLAGBIT(PF,GetHexValue(hex,hex)); } else
01453         if (strncmp(hex,"SF",2) == 0) { hex+=2; SETFLAGBIT(SF,GetHexValue(hex,hex)); } else
01454         if (strncmp(hex,"TF",2) == 0) { hex+=2; SETFLAGBIT(TF,GetHexValue(hex,hex)); } else
01455         //             "VM"
01456             if (strncmp(hex,"ZF",2) == 0) { hex+=2; SETFLAGBIT(ZF,GetHexValue(hex,hex)); } else
01457         { return false; }
01458     }
01459 
01460         return true;
01461 }
01462 
01463 void DEBUG_GUI_Rebuild(void);
01464 void DBGUI_NextWindowIfActiveHidden(void);
01465 
01466 void DEBUG_BeginPagedContent(void);
01467 void DEBUG_EndPagedContent(void);
01468 
01469 std::string pc98_egc_shift_debug_status(void);
01470 
01471 static void LogFPUInfo(void);
01472 
01473 bool ParseCommand(char* str) {
01474     std::string copy_str = str;
01475     for (auto &c : copy_str) c = toupper(c);
01476     copy_str += '\0'; /* paranoid */
01477         char* found = &(copy_str[0]); /* cannot use std::string c_str(), that is const char* */
01478 
01479         found = trim(found);
01480         string s_found(found);
01481         istringstream stream(s_found);
01482         string command;
01483         stream >> command;
01484         string::size_type next = s_found.find_first_not_of(' ',command.size());
01485         if(next == string::npos) next = command.size();
01486         (s_found.erase)(0,next);
01487         found = const_cast<char*>(s_found.c_str());
01488 
01489     if (command == "QUIT") {
01490         void DoKillSwitch(void);
01491         DoKillSwitch();
01492         return true;
01493     }
01494 
01495     if (command == "MOVEWINDN") { // MOVE WINDOW DOWN (by swapping)
01496         int order1 = dbg.win_find_order((int)dbg.active_win);
01497         int order2 = dbg.win_next_by_order(order1);
01498 
01499         if (order1 >= 0 && order2 >= 0 && order1 < order2) {
01500             dbg.swap_order(order1,order2);
01501             DEBUG_GUI_Rebuild();
01502             DBGUI_NextWindowIfActiveHidden();
01503         }
01504 
01505         return true;
01506     }
01507 
01508     if (command == "MOVEWINUP") { // MOVE WINDOW UP (by swapping)
01509         int order1 = dbg.win_find_order((int)dbg.active_win);
01510         int order2 = dbg.win_prev_by_order(order1);
01511 
01512         if (order1 >= 0 && order2 >= 0 && order1 > order2) {
01513             dbg.swap_order(order1,order2);
01514             DEBUG_GUI_Rebuild();
01515             DBGUI_NextWindowIfActiveHidden();
01516         }
01517 
01518         return true;
01519     }
01520 
01521     if (command == "SHOWWIN") { // SHOW WINDOW <name>
01522         int win = dbg.name_to_win(found);
01523         if (win >= 0) {
01524             dbg.win_vis[win] = true;
01525 
01526             DEBUG_GUI_Rebuild();
01527             DBGUI_NextWindowIfActiveHidden();
01528             return true;
01529         }
01530         else {
01531             LOG_MSG("No such window '%s'. Windows are: %s",found,dbg.windowlist_by_name().c_str());
01532             return false;
01533         }
01534     }
01535 
01536     if (command == "HIDEWIN") { // HIDE WINDOW <name>
01537         int win = dbg.name_to_win(found);
01538         if (win >= 0) {
01539             dbg.win_vis[win] = false;
01540 
01541             DEBUG_GUI_Rebuild();
01542             DBGUI_NextWindowIfActiveHidden();
01543             return true;
01544         }
01545         else {
01546             LOG_MSG("No such window '%s'. Windows are: %s",found,dbg.windowlist_by_name().c_str());
01547             return false;
01548         }
01549     }
01550 
01551         if (command == "MEMDUMP") { // Dump memory to file
01552                 Bit16u seg = (Bit16u)GetHexValue(found,found); found++;
01553                 Bit32u ofs = GetHexValue(found,found); found++;
01554                 Bit32u num = GetHexValue(found,found); found++;
01555                 SaveMemory(seg,ofs,num);
01556                 return true;
01557         }
01558 
01559         if (command == "MEMDUMPBIN") { // Dump memory to file binary
01560                 Bit16u seg = (Bit16u)GetHexValue(found,found); found++;
01561                 Bit32u ofs = GetHexValue(found,found); found++;
01562                 Bit32u num = GetHexValue(found,found); found++;
01563                 SaveMemoryBin(seg,ofs,num);
01564                 return true;
01565         }
01566 
01567         if (command == "IV") { // Insert variable
01568                 Bit16u seg = (Bit16u)GetHexValue(found,found); found++;
01569                 Bit32u ofs = (Bit16u)GetHexValue(found,found); found++;
01570                 char name[16];
01571                 for (int i=0; i<16; i++) {
01572                         if (found[i] && (found[i]!=' ')) name[i] = found[i]; 
01573                         else { name[i] = 0; break; }
01574                 }
01575                 name[15] = 0;
01576 
01577                 if(!name[0]) return false;
01578                 DEBUG_ShowMsg("DEBUG: Created debug var %s at %04X:%04X\n",name,seg,ofs);
01579                 CDebugVar::InsertVariable(name,(PhysPt)GetAddress(seg,ofs));
01580                 return true;
01581         }
01582 
01583         if (command == "SV") { // Save variables
01584                 char name[13];
01585                 for (int i=0; i<12; i++) {
01586                         if (found[i] && (found[i]!=' ')) name[i] = found[i]; 
01587                         else { name[i] = 0; break; }
01588                 }
01589                 name[12] = 0;
01590                 if(!name[0]) return false;
01591                 DEBUG_ShowMsg("DEBUG: Variable list save (%s) : %s.\n",name,(CDebugVar::SaveVars(name)?"ok":"failure"));
01592                 return true;
01593         }
01594 
01595         if (command == "LV") { // load variables
01596                 char name[13];
01597                 for (int i=0; i<12; i++) {
01598                         if (found[i] && (found[i]!=' ')) name[i] = found[i]; 
01599                         else { name[i] = 0; break; }
01600                 }
01601                 name[12] = 0;
01602                 if(!name[0]) return false;
01603                 DEBUG_ShowMsg("DEBUG: Variable list load (%s) : %s.\n",name,(CDebugVar::LoadVars(name)?"ok":"failure"));
01604                 return true;
01605         }
01606 
01607     if (command == "EV") { // echo value (for viewing contents through GetHexValue
01608         std::string cpptmp;
01609         char tmp[128];
01610         bool parsed;
01611 
01612         SkipSpace(found);
01613         DEBUG_ShowMsg("EV of '%s' is:",found);
01614 
01615         while (*found) {
01616             Bit32u value = GetHexValue(found,found,&parsed); SkipSpace(found);
01617             if (!parsed) {
01618                 DEBUG_ShowMsg("GetHexValue parse error at %s",found);
01619                 break;
01620             }
01621             sprintf(tmp,"%lx",(unsigned long)value);
01622             if (!cpptmp.empty()) cpptmp += " ";
01623             cpptmp += tmp;
01624         }
01625 
01626         DEBUG_ShowMsg("%s",cpptmp.c_str());
01627         return true;
01628     }
01629         
01630         if (command == "ADDLOG") {
01631                 if(found && *found)     DEBUG_ShowMsg("NOTICE: %s\n",found);
01632                 return true;
01633         }
01634 
01635         if (command == "SR") { // Set register value
01636                 DEBUG_ShowMsg("DEBUG: Set Register %s.\n",(ChangeRegister(found)?"success":"failure"));
01637                 return true;
01638         }
01639 
01640         if (command == "SM") { // Set memory with following values
01641                 Bit16u seg = (Bit16u)GetHexValue(found,found);
01642         if (*found == ':') { // allow seg:off syntax
01643             found++;
01644             SkipSpace(found);
01645         }
01646                 Bit32u ofs = GetHexValue(found,found); SkipSpace(found);
01647                 Bit16u count = 0;
01648         bool parsed;
01649 
01650         while (*found) {
01651             char prefix = 'B';
01652             Bit32u value;
01653 
01654             /* allow d: w: b: prefixes */
01655             if ((*found == 'B' || *found == 'W' || *found == 'D') && found[1] == ':') {
01656                 prefix = *found; found += 2;
01657                 value = GetHexValue(found,found,&parsed);
01658             }
01659             else {
01660                 value = GetHexValue(found,found,&parsed);
01661             }
01662 
01663             SkipSpace(found);
01664             if (!parsed) {
01665                 DEBUG_ShowMsg("GetHexValue parse error at %s",found);
01666                 break;
01667             }
01668 
01669             if (prefix == 'D') {
01670                 mem_writed_checked((PhysPt)GetAddress(seg,ofs+count),value);
01671                 count += 4;
01672             }
01673             else if (prefix == 'W') {
01674                 mem_writew_checked((PhysPt)GetAddress(seg,ofs+count),value);
01675                 count += 2;
01676             }
01677             else if (prefix == 'B') {
01678                 mem_writeb_checked((PhysPt)GetAddress(seg,ofs+count),value);
01679                 count++;
01680             }
01681         }
01682 
01683         if (count > 0)
01684             DEBUG_ShowMsg("DEBUG: Memory changed (%u bytes)\n",(unsigned int)count);
01685 
01686                 return true;
01687         }
01688 
01689         if (command == "BP") { // Add new breakpoint
01690                 Bit16u seg = (Bit16u)GetHexValue(found,found);found++; // skip ":"
01691                 Bit32u ofs = GetHexValue(found,found);
01692                 CBreakpoint::AddBreakpoint(seg,ofs,false);
01693                 DEBUG_ShowMsg("DEBUG: Set breakpoint at %04X:%04X\n",seg,ofs);
01694                 return true;
01695         }
01696 
01697 #if C_HEAVY_DEBUG
01698 
01699         if (command == "BPM") { // Add new breakpoint
01700                 Bit16u seg = (Bit16u)GetHexValue(found,found);found++; // skip ":"
01701                 Bit32u ofs = GetHexValue(found,found);
01702                 CBreakpoint::AddMemBreakpoint(seg,ofs);
01703                 DEBUG_ShowMsg("DEBUG: Set memory breakpoint at %04X:%04X\n",seg,ofs);
01704                 return true;
01705         }
01706 
01707         if (command == "BPPM") { // Add new breakpoint
01708                 Bit16u seg = (Bit16u)GetHexValue(found,found);found++; // skip ":"
01709                 Bit32u ofs = GetHexValue(found,found);
01710                 CBreakpoint* bp = CBreakpoint::AddMemBreakpoint(seg,ofs);
01711                 if (bp) {
01712                         bp->SetType(BKPNT_MEMORY_PROT);
01713                         DEBUG_ShowMsg("DEBUG: Set prot-mode memory breakpoint at %04X:%08X\n",seg,ofs);
01714                 }
01715                 return true;
01716         }
01717 
01718         if (command == "BPLM") { // Add new breakpoint
01719                 Bit32u ofs = GetHexValue(found,found);
01720                 CBreakpoint* bp = CBreakpoint::AddMemBreakpoint(0,ofs);
01721                 if (bp) bp->SetType(BKPNT_MEMORY_LINEAR);
01722                 DEBUG_ShowMsg("DEBUG: Set linear memory breakpoint at %08X\n",ofs);
01723                 return true;
01724         }
01725 
01726 #endif
01727 
01728         if (command == "BPINT") { // Add Interrupt Breakpoint
01729                 Bit8u intNr     = (Bit8u)GetHexValue(found,found);
01730                 bool all = !(*found);
01731                 Bit8u valAH = (Bit8u)GetHexValue(found,found);
01732                 if ((valAH==0x00) && (*found=='*' || all)) {
01733                         CBreakpoint::AddIntBreakpoint(intNr,BPINT_ALL,BPINT_ALL,false);
01734                         DEBUG_ShowMsg("DEBUG: Set interrupt breakpoint at INT %02X\n",intNr);
01735                 } else {
01736                         all = !(*found);
01737                         Bit8u valAL = (Bit8u)GetHexValue(found,found);
01738                         if ((valAL==0x00) && (*found=='*' || all)) {
01739                                 CBreakpoint::AddIntBreakpoint(intNr,valAH,BPINT_ALL,false);
01740                                 DEBUG_ShowMsg("DEBUG: Set interrupt breakpoint at INT %02X AH=%02X\n",intNr,valAH);
01741                         } else {
01742                                 CBreakpoint::AddIntBreakpoint(intNr,valAH,valAL,false);
01743                                 DEBUG_ShowMsg("DEBUG: Set interrupt breakpoint at INT %02X AH=%02X AL=%02X\n",intNr,valAH,valAL);
01744                         }
01745                 }
01746                 return true;
01747         }
01748 
01749         if (command == "BPLIST") {
01750         DEBUG_BeginPagedContent();
01751                 DEBUG_ShowMsg("Breakpoint list:\n");
01752                 DEBUG_ShowMsg("-------------------------------------------------------------------------\n");
01753                 CBreakpoint::ShowList();
01754         DEBUG_EndPagedContent();
01755                 return true;
01756         }
01757 
01758         if (command == "BPDEL") { // Delete Breakpoints
01759                 Bit8u bpNr      = (Bit8u)GetHexValue(found,found); 
01760                 if ((bpNr==0x00) && (*found=='*')) { // Delete all
01761                         CBreakpoint::DeleteAll();               
01762                         DEBUG_ShowMsg("DEBUG: Breakpoints deleted.\n");
01763                 } else {                
01764                         // delete single breakpoint
01765                         DEBUG_ShowMsg("DEBUG: Breakpoint deletion %s.\n",(CBreakpoint::DeleteByIndex(bpNr)?"success":"failure"));
01766                 }
01767                 return true;
01768         }
01769 
01770     if (command == "RUN") {
01771         DrawRegistersUpdateOld();
01772         debugging=false;
01773 
01774         logBuffSuppressConsole = false;
01775         if (logBuffSuppressConsoleNeedUpdate) {
01776             logBuffSuppressConsoleNeedUpdate = false;
01777             DEBUG_RefreshPage(0);
01778         }
01779 
01780         Bits DEBUG_NullCPUCore(void);
01781 
01782         CPU_Cycles = 1;
01783         inhibit_int_breakpoint = true;
01784         if (cpudecoder != DEBUG_NullCPUCore)
01785             (*cpudecoder)();
01786 
01787         inhibit_int_breakpoint = false;
01788 
01789         void DEBUG_DrawScreen(void);
01790         DEBUG_DrawScreen();
01791 
01792         CBreakpoint::ActivateBreakpointsExceptAt(SegPhys(cs)+reg_eip);
01793                 mainMenu.get_item("mapper_debugger").check(false).refresh_item(mainMenu);
01794         DOSBOX_SetNormalLoop(); 
01795         GFX_SetTitle(-1,-1,-1,is_paused);
01796         return true;
01797     }
01798 
01799     if (command == "RUNWATCH") {
01800         debug_running = true;
01801         DEBUG_DrawScreen();
01802         return true;
01803     }
01804 
01805     if (command == "A20") {
01806         void MEM_A20_Enable(bool enabled);
01807         bool MEM_A20_Enabled(void);
01808 
01809         command.clear();
01810                 stream >> command;
01811 
01812         if (command == "ON" || command == "1")
01813             MEM_A20_Enable(true);
01814         else if (command == "OFF" || command == "0")
01815             MEM_A20_Enable(false);
01816         else if (command == "")
01817             DEBUG_ShowMsg("A20 gate is %s",MEM_A20_Enabled() ? "ON" : "OFF");
01818         else
01819             return false;
01820 
01821         return true;
01822     }
01823 
01824     if (command == "PIC") { // interrupt controller state/controls
01825         void DEBUG_PICSignal(int irq,bool raise);
01826         void DEBUG_PICMask(int irq,bool mask);
01827         void DEBUG_PICAck(int irq);
01828         void DEBUG_LogPIC(void);
01829 
01830         DEBUG_BeginPagedContent();
01831 
01832         command.clear();
01833                 stream >> command;
01834 
01835         if (command == "MASKIRQ") {
01836             std::string what;
01837             stream >> what;
01838             int irq = atoi(what.c_str());
01839             DEBUG_PICMask(irq,true);
01840         }
01841         else if (command == "UNMASKIRQ") {
01842             std::string what;
01843             stream >> what;
01844             int irq = atoi(what.c_str());
01845             DEBUG_PICMask(irq,false);
01846         }
01847         else if (command == "ACKIRQ") { /* debugging: manually acknowledge an IRQ where the DOS program failed to do so */
01848             std::string what;
01849             stream >> what;
01850             int irq = atoi(what.c_str());
01851             DEBUG_PICAck(irq);
01852         }
01853         else if (command == "LOWERIRQ") { /* manually lower an IRQ signal */
01854             std::string what;
01855             stream >> what;
01856             int irq = atoi(what.c_str());
01857             DEBUG_PICSignal(irq,false);
01858         }
01859         else if (command == "RAISEIRQ") { /* manually raise an IRQ signal */
01860             std::string what;
01861             stream >> what;
01862             int irq = atoi(what.c_str());
01863             DEBUG_PICSignal(irq,true);
01864         }
01865         else if (command == "") {
01866             DEBUG_LogPIC();
01867         }
01868         else {
01869             DEBUG_EndPagedContent();
01870             return false;
01871         }
01872 
01873         DEBUG_EndPagedContent();
01874 
01875         return true;
01876     }
01877 
01878         if (command == "C") { // Set code overview
01879                 Bit16u codeSeg = (Bit16u)GetHexValue(found,found); found++;
01880                 Bit32u codeOfs = GetHexValue(found,found);
01881                 DEBUG_ShowMsg("DEBUG: Set code overview to %04X:%04X\n",codeSeg,codeOfs);
01882                 codeViewData.useCS      = codeSeg;
01883                 codeViewData.useEIP = codeOfs;
01884                 codeViewData.cursorPos = 0;
01885                 return true;
01886         }
01887 
01888         if (command == "D") { // Set data overview
01889                 dataSeg = (Bit16u)GetHexValue(found,found); SkipSpace(found);
01890         if (*found == ':') { // allow seg:off syntax
01891             found++;
01892             SkipSpace(found);
01893         }
01894                 dataOfs = GetHexValue(found,found); SkipSpace(found);
01895         dbg.set_data_view(DBGBlock::DATV_SEGMENTED);
01896                 DEBUG_ShowMsg("DEBUG: Set data overview to %04X:%04X\n",dataSeg,dataOfs);
01897                 return true;
01898         }
01899 
01900         if (command == "DV") { // Set data overview
01901         dataSeg = 0;
01902                 dataOfs = GetHexValue(found,found); SkipSpace(found);
01903         dbg.set_data_view(DBGBlock::DATV_VIRTUAL);
01904                 DEBUG_ShowMsg("DEBUG: Set data overview to %04X:%04X\n",dataSeg,dataOfs);
01905                 return true;
01906         }
01907 
01908         if (command == "DP") { // Set data overview
01909         dataSeg = 0;
01910                 dataOfs = GetHexValue(found,found); SkipSpace(found);
01911         dbg.set_data_view(DBGBlock::DATV_PHYSICAL);
01912                 DEBUG_ShowMsg("DEBUG: Set data overview to %04X:%04X\n",dataSeg,dataOfs);
01913                 return true;
01914         }
01915 
01916 #if C_HEAVY_DEBUG
01917 
01918         if (command == "LOG") { // Create Cpu normal log file
01919                 cpuLogType = 1;
01920                 command = "logcode";
01921         }
01922 
01923         if (command == "LOGS") { // Create Cpu short log file
01924                 cpuLogType = 0;
01925                 command = "logcode";
01926         }
01927 
01928         if (command == "LOGL") { // Create Cpu long log file
01929                 cpuLogType = 2;
01930                 command = "logcode";
01931         }
01932 
01933         if (command == "logcode") { //Shared code between all logs
01934                 DEBUG_ShowMsg("DEBUG: Starting log\n");
01935                 cpuLogFile.open("LOGCPU.TXT");
01936                 if (!cpuLogFile.is_open()) {
01937                         DEBUG_ShowMsg("DEBUG: Logfile couldn't be created.\n");
01938                         return false;
01939                 }
01940                 //Initialize log object
01941                 cpuLogFile << hex << noshowbase << setfill('0') << uppercase;
01942                 cpuLog = true;
01943                 cpuLogCounter = (int)GetHexValue(found,found);
01944 
01945                 debugging = false;
01946                 CBreakpoint::ActivateBreakpointsExceptAt(SegPhys(cs)+reg_eip);
01947                 DOSBOX_SetNormalLoop(); 
01948                 return true;
01949         }
01950 
01951 #endif
01952 
01953         if (command == "INTT") { //trace int.
01954                 Bit8u intNr = (Bit8u)GetHexValue(found,found);
01955                 DEBUG_ShowMsg("DEBUG: Tracing INT %02X\n",intNr);
01956                 CPU_HW_Interrupt(intNr);
01957                 SetCodeWinStart();
01958                 return true;
01959         }
01960 
01961         if (command == "INT") { // start int.
01962                 Bit8u intNr = (Bit8u)GetHexValue(found,found);
01963                 DEBUG_ShowMsg("DEBUG: Starting INT %02X\n",intNr);
01964                 CBreakpoint::AddBreakpoint(SegValue(cs),reg_eip, true);
01965                 CBreakpoint::ActivateBreakpointsExceptAt(SegPhys(cs)+reg_eip-1);
01966                 debugging = false;
01967                 DrawCode();
01968                 mainMenu.get_item("mapper_debugger").check(false).refresh_item(mainMenu);
01969                 DOSBOX_SetNormalLoop();
01970                 CPU_HW_Interrupt(intNr);
01971                 return true;
01972         }
01973 
01974         if (command == "SELINFO") {
01975                 while (found[0] == ' ') found++;
01976                 char out1[200],out2[200];
01977                 GetDescriptorInfo(found,out1,out2);
01978                 DEBUG_ShowMsg("SelectorInfo %s:\n%s\n%s\n",found,out1,out2);
01979                 return true;
01980         }
01981 
01982         if (command == "DOS") {
01983                 stream >> command;
01984                 if (command == "MCBS") LogMCBS();
01985         else if (command == "KERN") LogDOSKernMem();
01986         else if (command == "XMS") LogXMS();
01987         else if (command == "EMS") LogEMS();
01988         else if (command == "FNKEY") LogFNKEY();
01989         else return false;
01990 
01991                 return true;
01992         }
01993 
01994     if (command == "BIOS") {
01995         stream >> command;
01996 
01997         if (command == "MEM") LogBIOSMem();
01998         else return false;
01999 
02000         return true;
02001     }
02002 
02003     if (command == "VGA") {
02004         stream >> command;
02005 
02006         if (IS_PC98_ARCH) {
02007             DEBUG_ShowMsg("VGA debugger commands not available in PC-98 mode");
02008             return false;
02009         }
02010 
02011         if (command == "CRTC") {
02012             DEBUG_ShowMsg("VGA CRTC info: index=%02xh readonly=%u",vga.crtc.index,vga.crtc.read_only?1:0);
02013             DEBUG_ShowMsg("htotal=%02xh hdend=%02xh strhb=%02xh endhb=%02xh strrt=%02xh endrt=%02xh",
02014                 vga.crtc.horizontal_total,              vga.crtc.horizontal_display_end,
02015                 vga.crtc.start_horizontal_blanking,     vga.crtc.end_horizontal_blanking,
02016                 vga.crtc.start_horizontal_retrace,      vga.crtc.end_horizontal_retrace);
02017             DEBUG_ShowMsg("vtotal=%02xh overflow=%02xh prerwscn=%02xh maxscnl=%02xh offset=%02xh",
02018                 vga.crtc.vertical_total,                vga.crtc.overflow,
02019                 vga.crtc.preset_row_scan,               vga.crtc.maximum_scan_line,
02020                 vga.crtc.offset);
02021             DEBUG_ShowMsg("curs-st=%02xh curs-en=%02xh start-addr=%02x%02xh curs-loc=%02x%02xh",
02022                 vga.crtc.cursor_start,                  vga.crtc.cursor_end,
02023                 vga.crtc.start_address_high,            vga.crtc.start_address_low,
02024                 vga.crtc.cursor_location_high,          vga.crtc.cursor_location_low);
02025             DEBUG_ShowMsg("strvrt=%02xh endvrt=%02xh vdend=%02xh underline=%02xh modectrl=%02xh",
02026                 vga.crtc.vertical_retrace_start,        vga.crtc.vertical_retrace_end,
02027                 vga.crtc.vertical_display_end,          vga.crtc.underline_location,
02028                 vga.crtc.mode_control);
02029             DEBUG_ShowMsg("strvhb=%02xh endvhb=%02xh linecomp=%02xh",
02030                 vga.crtc.start_vertical_blanking,       vga.crtc.end_vertical_blanking,
02031                 vga.crtc.line_compare);
02032         }
02033         else if (command == "GC") {
02034             DEBUG_ShowMsg("VGA Graphics controller info: index=%02xh setreset=%02xh",vga.gfx.index,vga.gfx.set_reset);
02035             DEBUG_ShowMsg("enablesetreset=%02xh color-comp=%02xh data-rotate=%02xh rdmapsel=%02xh",
02036                 vga.gfx.enable_set_reset,   vga.gfx.color_compare,  vga.gfx.data_rotate,
02037                 vga.gfx.read_map_select);
02038             DEBUG_ShowMsg("mode=%02xh misc=%02xh color-dont-care=%02xh bitmask=%02xh",
02039                 vga.gfx.mode,               vga.gfx.miscellaneous,  vga.gfx.color_dont_care,
02040                 vga.gfx.bit_mask);
02041         }
02042         else if (command == "DAC") {
02043             // FIXME: Remove this var, use vga.dac.bits == 8 instead!
02044             extern bool vga_8bit_dac;
02045 
02046             DEBUG_ShowMsg("VGA DAC info: bits=%u pel_mask=%02xh pel_index[RGB]=%02xh",
02047                 vga_8bit_dac ? 8 : 6,//FIXME
02048                 vga.dac.pel_mask,       vga.dac.pel_index);
02049             DEBUG_ShowMsg("state=%02xh write_index=%02xh read_index=%02xh first_changed=%u",
02050                 vga.dac.state,          vga.dac.write_index,
02051                 vga.dac.read_index,     (unsigned int)vga.dac.first_changed);
02052             DEBUG_ShowMsg("hidac_counter=%u reg02=%02xh",
02053                 vga.dac.hidac_counter,  vga.dac.reg02);
02054         }
02055         else if (command == "DACPAL") {
02056             std::string cpptmp;
02057             char tmp[64];
02058 
02059             DEBUG_BeginPagedContent();
02060 
02061             DEBUG_ShowMsg("VGA DAC palette (RGB):");
02062             for (unsigned int i=0;i < 256;i += 8) {
02063                 sprintf(tmp,"%02x: ",i);
02064                 cpptmp = tmp;
02065 
02066                 for (unsigned int c=0;c < 8;c++) {
02067                     sprintf(tmp,"%02x%02x%02x%c",
02068                         vga.dac.rgb[i+c].red,
02069                         vga.dac.rgb[i+c].green,
02070                         vga.dac.rgb[i+c].blue,
02071                         c == 3 ? '-' : ' '
02072                     );
02073                     cpptmp += tmp;
02074                 }
02075 
02076                 DEBUG_ShowMsg("%s",cpptmp.c_str());
02077             }
02078 
02079             DEBUG_EndPagedContent();
02080         }
02081         else if (command == "SEQ") {
02082             DEBUG_ShowMsg("VGA Sequencer info: index=%02xh",vga.seq.index);
02083             DEBUG_ShowMsg("reset=%02xh clockmode=%02xh map_mask=%02xh charmapsel=%02xh memmode=%02xh",
02084                 vga.seq.reset,      vga.seq.clocking_mode,      vga.seq.map_mask,
02085                 vga.seq.character_map_select,                   vga.seq.memory_mode);
02086         }
02087         else if (command == "AC") {
02088             std::string cpptmp;
02089             char tmp[64];
02090 
02091             DEBUG_ShowMsg("VGA Attribute Controller info: attrindexmode=%u",vga.internal.attrindex?1:0);
02092             DEBUG_ShowMsg("mode_control=%02xh horz-pel-pan=%02xh overscan-color=%02xh",
02093                 vga.attr.mode_control,  vga.attr.horizontal_pel_panning,
02094                 vga.attr.overscan_color);
02095             DEBUG_ShowMsg("color-plane-en=%02xh color-select=%02xh index=%02xh",
02096                 vga.attr.color_plane_enable,    vga.attr.color_select,  vga.attr.index);
02097             DEBUG_ShowMsg("disabled-by-index=%u disabled-by-idx1-bit5=%u index-written=%u",
02098                 (vga.attr.disabled & 1) ? 1 : 0,
02099                 (vga.attr.disabled & 2) ? 1 : 0,
02100                 vga.internal.attrindex);
02101 
02102             cpptmp = " ";
02103             for (unsigned int i=0;i < 16;i++) {
02104                 sprintf(tmp,"%02x%c",vga.attr.palette[i],((i&3) == 3 && i != 15) ? '-' : ' ');
02105                 cpptmp += tmp;
02106             }
02107 
02108             DEBUG_ShowMsg("palette={%s}",cpptmp.c_str());
02109         }
02110         else if (command == "DRAW") {
02111             DEBUG_ShowMsg("VGA draw info: resizing=%u width=%lu height=%lu blocks=%lu",
02112                 vga.draw.resizing?1:0,(unsigned long)vga.draw.width,(unsigned long)vga.draw.height,(unsigned long)vga.draw.blocks);
02113             DEBUG_ShowMsg("address=%lxh panning=%lu bytes-skip=%lu lin-mask=%lx pln-mask=%lx",
02114                 (unsigned long)vga.draw.address,(unsigned long)vga.draw.panning,(unsigned long)vga.draw.bytes_skip,
02115                 (unsigned long)vga.draw.linear_mask,(unsigned long)vga.draw.planar_mask);
02116             DEBUG_ShowMsg("addr-add=%lxh line-length=%lu addrline-total=%lu addrline=%lu",
02117                 (unsigned long)vga.draw.address_add,(unsigned long)vga.draw.line_length,
02118                 (unsigned long)vga.draw.address_line_total,(unsigned long)vga.draw.address_line);
02119             DEBUG_ShowMsg("line-total=%lu vblank-skip=%lu lines-done=%lu split-line=%lu",
02120                 (unsigned long)vga.draw.lines_total,(unsigned long)vga.draw.vblank_skip,
02121                 (unsigned long)vga.draw.lines_done,(unsigned long)vga.draw.split_line);
02122             DEBUG_ShowMsg("byte-pan-shft=%lu render-stop=%lu render-max=%lu scrn-ratio=%.3f",
02123                 (unsigned long)vga.draw.byte_panning_shift,(unsigned long)vga.draw.render_step,
02124                 (unsigned long)vga.draw.render_max,(double)vga.draw.screen_ratio);
02125             DEBUG_ShowMsg("blinking=%lu blink=%u char9dot=%u has-split=%u vret-trig=%u",
02126                 (unsigned long)vga.draw.blinking,vga.draw.blink?1:0,
02127                 vga.draw.char9dot?1:0,vga.draw.has_split?1:0,
02128                 vga.draw.vret_triggered?1:0);
02129             DEBUG_ShowMsg("bpp=%lu curs-addr=%lxh curs-s=%u curs-e=%u curs-c=%u curs-d=%u curs-en=%u",
02130                 (unsigned long)vga.draw.bpp,
02131                 (unsigned long)vga.draw.cursor.address,
02132                 vga.draw.cursor.sline,
02133                 vga.draw.cursor.eline,
02134                 vga.draw.cursor.count,
02135                 vga.draw.cursor.delay,
02136                 vga.draw.cursor.enabled);
02137 // TODO: Remove vga.draw.refresh, appears to be unused
02138         }
02139         else if (command == "MODE") {
02140             DEBUG_ShowMsg("VGA mode info:");
02141             DEBUG_ShowMsg("mode=%s vref=%.3fHz href=%.3fHz chrclk=%.3fHz dotclk=%.3fHz",
02142                 mode_texts[vga.mode],1000.0/vga.draw.delay.vtotal,1000.0/vga.draw.delay.htotal,
02143                 vga.draw.clock,vga.draw.oscclock);
02144             DEBUG_ShowMsg("disp-start=%lxh real-start=%lxh retrace=%u scanlen=%lu cursor-start=%lxh",
02145                 (unsigned long)vga.config.display_start,
02146                 (unsigned long)vga.config.real_start,
02147                 vga.config.retrace?1:0,
02148                 (unsigned long)vga.config.scan_len,
02149                 (unsigned long)vga.config.cursor_start);
02150             DEBUG_ShowMsg("line-compare=%lu chained=%u compat-chain4=%u pel-pan=%u hline-skip=%u",
02151                 (unsigned long)vga.config.line_compare,
02152                 vga.config.chained,
02153                 (unsigned int)vga.config.compatible_chain4,
02154                 (unsigned int)vga.config.pel_panning,
02155                 (unsigned int)vga.config.hlines_skip);
02156             DEBUG_ShowMsg("byte-skip=%u addr-shift=%u rd-mode=%u wr-mode=%u rdmap-sel=%u",
02157                 (unsigned int)vga.config.bytes_skip,
02158                 (unsigned int)vga.config.addr_shift,
02159                 (unsigned int)vga.config.read_mode,
02160                 (unsigned int)vga.config.write_mode,
02161                 (unsigned int)vga.config.read_map_select);
02162             DEBUG_ShowMsg("col-dont-care=%u color-compare=%u data-rotate=%u raster-op=%02xh",
02163                 (unsigned int)vga.config.color_dont_care,
02164                 (unsigned int)vga.config.color_compare,
02165                 (unsigned int)vga.config.data_rotate,
02166                 (unsigned int)vga.config.raster_op);
02167             DEBUG_ShowMsg("fbmsk=%x fmmsk=%x fnmmsk=%x fsr=%x fnesr=%x fesr=%x feasr=%x",
02168                 (unsigned int)vga.config.full_bit_mask,
02169                 (unsigned int)vga.config.full_map_mask,
02170                 (unsigned int)vga.config.full_not_map_mask,
02171                 (unsigned int)vga.config.full_set_reset,
02172                 (unsigned int)vga.config.full_not_enable_set_reset,
02173                 (unsigned int)vga.config.full_enable_set_reset,
02174                 (unsigned int)vga.config.full_enable_and_set_reset);
02175         }
02176         else {
02177             return false;
02178         }
02179 
02180         return true;
02181    }
02182 
02183     if (command == "PC98") {
02184         stream >> command;
02185 
02186         if (!IS_PC98_ARCH) {
02187             DEBUG_ShowMsg("PC-98 debugger commands not available except in PC-98 mode");
02188             return false;
02189         }
02190 
02191         if (command == "MODE") {
02192             DEBUG_ShowMsg("Mode info:");
02193             DEBUG_ShowMsg("mode=%s vref=%.3fHz href=%.3fHz chrclk=%.3fHz dotclk=%.3fHz",
02194                 mode_texts[vga.mode],1000.0/vga.draw.delay.vtotal,1000.0/vga.draw.delay.htotal,
02195                 vga.draw.clock,vga.draw.oscclock);
02196         }
02197         else if (command == "GRAPHICS") {
02198             const auto &gdc = pc98_gdc[GDC_SLAVE];
02199             std::string cpptmp;
02200 
02201             cpptmp.clear();
02202             if (gdc_analog) {
02203                 if (pc98_gdc_vramop & (1 << VOPBIT_VGA))
02204                     cpptmp += "'256-color packed' ";
02205                 else
02206                     cpptmp += "'16-color planar' ";
02207             }
02208             else {
02209                 cpptmp += "'8-color planar' ";
02210             }
02211 
02212             if (egc_enable_enable) /* Port 6Ah, 0x06/0x07 to enable EGC enable commands 0x04/0x05 */
02213                 cpptmp += "EGC-ENABL ";
02214             if (pc98_gdc_vramop & (1 << VOPBIT_EGC)) /* Port 6Ah, 0x04/0x05 */
02215                 cpptmp += "EGC ";
02216             if (pc98_gdc_vramop & (2 << VOPBIT_GRCG)) /* Port 7Ch, bits [7:6]. bit 7 (2 << VOPBIT_GRCG) is the enable. */
02217                 cpptmp += "GRCG ";
02218 
02219             if (gdc.display_enable)
02220                 cpptmp += "ENABLED ";
02221             else
02222                 cpptmp += "DISABLED ";
02223 
02224             if (gdc.doublescan) {
02225                 if (pc98_graphics_hide_odd_raster_200line)
02226                     cpptmp += "200-LINE-EVEN-SCAN ";
02227                 else
02228                     cpptmp += "DOUBLESCAN ";
02229             }
02230 
02231             if (pc98_pegc_linear_framebuffer_enabled())
02232                 cpptmp += "PEGC-LFB ";
02233 
02234             if (pc98_gdc_vramop & (1 << VOPBIT_PEGC_PLANAR))
02235                 cpptmp += "256-PLANAR ";
02236 
02237             DEBUG_ShowMsg("PC-98 graphics mode: %s",cpptmp.c_str());
02238 
02239             /*--------------------*/
02240 
02241             cpptmp.clear();
02242             DEBUG_ShowMsg("PC-98 page display: cpu=%u display-pending=%u display-active=%u pitch=%u",
02243                     (pc98_gdc_vramop & (1 << VOPBIT_ACCESS))?1:0,
02244                     GDC_display_plane_pending,
02245                     GDC_display_plane,
02246                     gdc.display_pitch);
02247 
02248             /*--------------------*/
02249 
02250             cpptmp.clear();
02251             DEBUG_ShowMsg("PC-98 status: gdc5mhz=%u vsync-int-trig=%u rowheight=%u lines-drawn=%u",
02252                 gdc_5mhz_mode,GDC_vsync_interrupt,gdc.row_height,(unsigned int)vga.draw.lines_done);
02253             DEBUG_ShowMsg("  cur-row-line=%u cur-scan=0x%x cur-partition=%u/%u part-remline=%u",
02254                 gdc.row_line,gdc.scan_address,gdc.display_partition,gdc.display_partition_mask+1,gdc.display_partition_rem_lines);
02255             DEBUG_ShowMsg("  vram-bound=%uKB",
02256                 pc98_256kb_boundary?256:128);
02257 
02258             /*--------------------*/
02259 
02260             cpptmp.clear();
02261             {
02262                 char tmp[16];
02263                 for (unsigned int i=0;i < 16;i++) {
02264                     sprintf(tmp,"%02x%c",gdc.param_ram[i],((i&3) == 3 && i != 15) ? '-' : ' ');
02265                     cpptmp += tmp;
02266                 }
02267             }
02268             DEBUG_ShowMsg("PC-98 GDC PRAM: wptr=%u %s",gdc.param_ram_wptr,cpptmp.c_str());
02269 
02270             /*---------------------*/
02271             cpptmp.clear();
02272             DEBUG_ShowMsg("PC-98 GRCG: active=%u mode=%s tilecount=%u modereg(7Ch)=%02xh",
02273                 (pc98_gdc_vramop & (2 << VOPBIT_GRCG))?1:0,
02274                 (pc98_gdc_vramop & (1 << VOPBIT_GRCG))?"Read/Modify/Write":"TCR/TDW",
02275                 pc98_gdc_tile_counter,
02276                 pc98_gdc_modereg);
02277 
02278             /*---------------------*/
02279             cpptmp.clear();
02280             DEBUG_ShowMsg("PC-98 GRGC tiles: [%02x %02x] [%02x %02x] [%02x %02x] [%02x %02x]",
02281                 pc98_gdc_tiles[0].b[0],
02282                 pc98_gdc_tiles[0].b[1],
02283                 pc98_gdc_tiles[1].b[0],
02284                 pc98_gdc_tiles[1].b[1],
02285                 pc98_gdc_tiles[2].b[0],
02286                 pc98_gdc_tiles[2].b[1],
02287                 pc98_gdc_tiles[3].b[0],
02288                 pc98_gdc_tiles[3].b[1]);
02289         }
02290         else if (command == "TEXT") {
02291             const auto &gdc = pc98_gdc[GDC_MASTER];
02292             std::string cpptmp;
02293 
02294             cpptmp.clear();
02295             if (gdc.display_enable)
02296                 cpptmp += "ENABLED ";
02297             else
02298                 cpptmp += "DISABLED ";
02299 
02300             if (gdc.doublescan)
02301                 cpptmp += "DOUBLESCAN ";
02302 
02303             if (pc98_attr4_graphic)
02304                 cpptmp += "SIMPLE-GRPH ";
02305             else
02306                 cpptmp += "VERT-LINE ";
02307 
02308             DEBUG_ShowMsg("PC-98 text mode: %s",cpptmp.c_str());
02309 
02310             /*--------------------*/
02311 
02312             cpptmp.clear();
02313             DEBUG_ShowMsg("PC-98 display/cursor: pitch=%u curs-en=%u curs-blink=%u curs-blinkrate=%u",
02314                 gdc.display_pitch,
02315                 gdc.cursor_enable,
02316                 gdc.cursor_blink,
02317                 gdc.cursor_blink_rate);
02318 
02319             DEBUG_ShowMsg("  curs-blink-count=%u curs-blink-state=%u/4 crt-mode=%u",
02320                 gdc.cursor_blink_count,
02321                 gdc.cursor_blink_state,
02322                 pc98_crt_mode?1:0);
02323 
02324             /*--------------------*/
02325 
02326             cpptmp.clear();
02327             DEBUG_ShowMsg("PC-98 status: gdc5mhz=%u vsync-int-trig=%u rowheight=%u lines-drawn=%u",
02328                 gdc_5mhz_mode,GDC_vsync_interrupt,gdc.row_height,(unsigned int)vga.draw.lines_done);
02329             DEBUG_ShowMsg("  cur-row-line=%u cur-scan=0x%x cur-partition=%u/%u part-remline=%u",
02330                 gdc.row_line,gdc.scan_address,gdc.display_partition,gdc.display_partition_mask+1,gdc.display_partition_rem_lines);
02331 
02332             /*--------------------*/
02333 
02334             cpptmp.clear();
02335             {
02336                 char tmp[16];
02337                 for (unsigned int i=0;i < 16;i++) {
02338                     sprintf(tmp,"%02x%c",gdc.param_ram[i],((i&3) == 3 && i != 15) ? '-' : ' ');
02339                     cpptmp += tmp;
02340                 }
02341             }
02342             DEBUG_ShowMsg("PC-98 GDC PRAM: wptr=%u %s",gdc.param_ram_wptr,cpptmp.c_str());
02343 
02344             /*--------------------*/
02345 
02346             DEBUG_ShowMsg("PC-98 CG raster: row-scan=[start=%u/32 end-incl=%u/32] blank-at-in-charcell=%u/32",
02347                     pc98_text_first_row_scanline_start,
02348                     pc98_text_first_row_scanline_end,
02349                     pc98_text_row_scanline_blank_at);
02350 
02351             DEBUG_ShowMsg("PC-98 CG scrollregion: countstart=%u char-rows=%u lines=%u",
02352                     pc98_text_row_scroll_count_start,
02353                     pc98_text_row_scroll_num_lines,
02354                     pc98_text_row_scroll_lines);
02355         }
02356         else if (command == "CGIO") {
02357             DEBUG_ShowMsg("PC-98 CG I/O port state (A1h-A9h odd): char-row=%u char-code=0x%04x",
02358                     a1_font_char_offset,
02359                     a1_font_load_addr);
02360         }
02361         else if (command == "EGC") {
02362             DEBUG_ShowMsg("PC-98 EGC Raw registers:");
02363             DEBUG_ShowMsg("  4A0h even: %04xh %04xh %04xh %04xh",
02364                 pc98_egc_raw_values[0],
02365                 pc98_egc_raw_values[1],
02366                 pc98_egc_raw_values[2],
02367                 pc98_egc_raw_values[3]);
02368             DEBUG_ShowMsg("  4A8h even: %04xh %04xh %04xh %04xh bitplane-access=%02xh",
02369                 pc98_egc_raw_values[4],
02370                 pc98_egc_raw_values[5],
02371                 pc98_egc_raw_values[6],
02372                 pc98_egc_raw_values[7],
02373                 pc98_egc_access);
02374             DEBUG_ShowMsg("  bg-color=%02xh bgcm=[%02xh %02xh] [%02xh %02xh] [%02xh %02xh] [%02xh %02xh]",
02375                 pc98_egc_background_color,
02376                 pc98_egc_bgcm[0].b[0],
02377                 pc98_egc_bgcm[0].b[1],
02378                 pc98_egc_bgcm[1].b[0],
02379                 pc98_egc_bgcm[1].b[1],
02380                 pc98_egc_bgcm[2].b[0],
02381                 pc98_egc_bgcm[2].b[1],
02382                 pc98_egc_bgcm[3].b[0],
02383                 pc98_egc_bgcm[3].b[1]);
02384             DEBUG_ShowMsg("  fg-color=%02xh fgcm=[%02xh %02xh] [%02xh %02xh] [%02xh %02xh] [%02xh %02xh]",
02385                 pc98_egc_foreground_color,
02386                 pc98_egc_fgcm[0].b[0],
02387                 pc98_egc_fgcm[0].b[1],
02388                 pc98_egc_fgcm[1].b[0],
02389                 pc98_egc_fgcm[1].b[1],
02390                 pc98_egc_fgcm[2].b[0],
02391                 pc98_egc_fgcm[2].b[1],
02392                 pc98_egc_fgcm[3].b[0],
02393                 pc98_egc_fgcm[3].b[1]);
02394             DEBUG_ShowMsg("  fgc-select=%d=%s lead-plane=%u srcmask=[%02xh %02xh]",
02395                 pc98_egc_fgc,
02396                 egc_fgc_modes[pc98_egc_fgc],
02397                 pc98_egc_lead_plane,
02398                 pc98_egc_srcmask[0],pc98_egc_srcmask[1]);
02399             DEBUG_ShowMsg("  mask=[%02xh %02xh] mask-effective=[%02xh %02xh] ROP=%02xh",
02400                 pc98_egc_mask[0],pc98_egc_mask[1],
02401                 pc98_egc_maskef[0],pc98_egc_maskef[1],
02402                 pc98_egc_rop);
02403             DEBUG_ShowMsg("  compare-lead-plane=%u lightsource=%u shiftinput=%u regload=%u",
02404                 pc98_egc_compare_lead,
02405                 pc98_egc_lightsource,
02406                 pc98_egc_shiftinput,
02407                 pc98_egc_regload);
02408             DEBUG_ShowMsg("  shift-desc=%u shf-destbit=%u shf-srcbit=%u shf-length=%u",
02409                 pc98_egc_shift_descend,
02410                 pc98_egc_shift_destbit,
02411                 pc98_egc_shift_srcbit,
02412                 pc98_egc_shift_length);
02413             DEBUG_ShowMsg("  %s",
02414                 pc98_egc_shift_debug_status().c_str());
02415         }
02416         else {
02417             return false;
02418         }
02419 
02420         return true;
02421     }
02422 
02423     if (command == "EMU") {
02424         stream >> command;
02425 
02426         if (command == "MEM") LogEMUMem();
02427         else if (command == "MACHINE") LogEMUMachine();
02428         else return false;
02429 
02430         return true;
02431     }
02432 
02433     if (command == "CALLBACKS") {
02434         DEBUG_BeginPagedContent();
02435 
02436         void DBG_CALLBACK_Dump(void);
02437         DBG_CALLBACK_Dump();
02438 
02439         DEBUG_EndPagedContent();
02440         return true;
02441     }
02442 
02443     if (command == "INP" || command == "INB") {
02444         Bit16u port = (Bit16u)GetHexValue(found,found);
02445         Bit8u r = IO_ReadB(port);
02446         DEBUG_ShowMsg("Result: %x",(unsigned int)r);
02447         return true;
02448     }
02449 
02450     if (command == "INW") {
02451         Bit16u port = (Bit16u)GetHexValue(found,found);
02452         Bit16u r = IO_ReadW(port);
02453         DEBUG_ShowMsg("Result: %x",(unsigned int)r);
02454         return true;
02455     }
02456 
02457     if (command == "IND") {
02458         Bit16u port = (Bit16u)GetHexValue(found,found);
02459         Bit32u r = IO_ReadD(port);
02460         DEBUG_ShowMsg("Result: %x",(unsigned int)r);
02461         return true;
02462     }
02463 
02464     if (command == "OUTP" || command == "OUTB") {
02465         Bit16u port = (Bit16u)GetHexValue(found,found);
02466         Bit8u r = (Bit8u)GetHexValue(found,found);
02467         IO_WriteB(port,r);
02468         return true;
02469     }
02470 
02471     if (command == "OUTW") {
02472         Bit16u port = (Bit16u)GetHexValue(found,found);
02473         Bit16u r = (Bit16u)GetHexValue(found,found);
02474         IO_WriteW(port,r);
02475         return true;
02476     }
02477 
02478     if (command == "OUTD") {
02479         Bit16u port = (Bit16u)GetHexValue(found,found);
02480         Bit32u r = (Bit32u)GetHexValue(found,found);
02481         IO_WriteD(port,r);
02482         return true;
02483     }
02484 
02485         if (command == "GDT") {LogGDT(); return true;}
02486         
02487         if (command == "LDT") {LogLDT(); return true;}
02488         
02489         if (command == "IDT") {LogIDT(); return true;}
02490         
02491         if (command == "PAGING") {LogPages(found); return true;}
02492 
02493         if (command == "CPU") {LogCPUInfo(); return true;}
02494 
02495         if (command == "FPU") {LogFPUInfo(); return true;}
02496 
02497         if (command == "INTVEC") {
02498                 if (found[0] != 0) {
02499                         OutputVecTable(found);
02500                         return true;
02501                 }
02502         }
02503 
02504         if (command == "INTHAND") {
02505                 if (found[0] != 0) {
02506                         Bit8u intNr = (Bit8u)GetHexValue(found,found);
02507                         DEBUG_ShowMsg("DEBUG: Set code overview to interrupt handler %X\n",intNr);
02508             if (cpu.pmode) {
02509                 Descriptor gate;
02510                 if (cpu.idt.GetDescriptor((Bitu)intNr<<3u,gate)) {
02511                     codeViewData.useCS  = (Bit16u)gate.GetSelector();
02512                     codeViewData.useEIP = (Bit32u)gate.GetOffset();
02513                 }
02514                 else {
02515                     DEBUG_ShowMsg("INTHAND unable to retrieve vector");
02516                 }
02517             }
02518             else {
02519                 codeViewData.useCS      = mem_readw(intNr*4u+2u);
02520                 codeViewData.useEIP = mem_readw(intNr*4u);
02521             }
02522                         codeViewData.cursorPos = 0;
02523                         return true;
02524                 }
02525         }
02526 
02527         if(command == "EXTEND") { //Toggle additional data.     
02528                 showExtend = !showExtend;
02529                 return true;
02530         }
02531 
02532         if(command == "TIMERIRQ") { //Start a timer irq
02533                 DEBUG_RaiseTimerIrq(); 
02534                 DEBUG_ShowMsg("Debug: Timer Int started.\n");
02535                 return true;
02536         }
02537 
02538 
02539 #if C_HEAVY_DEBUG
02540         if (command == "HEAVYLOG") { // Create Cpu log file
02541                 logHeavy = !logHeavy;
02542                 DEBUG_ShowMsg("DEBUG: Heavy cpu logging %s.\n",logHeavy?"on":"off");
02543                 return true;
02544         }
02545 
02546         if (command == "ZEROPROTECT") { //toggle zero protection
02547                 zeroProtect = !zeroProtect;
02548                 DEBUG_ShowMsg("DEBUG: Zero code execution protection %s.\n",zeroProtect?"on":"off");
02549                 return true;
02550         }
02551 
02552 #endif
02553         if (command == "HELP" || command == "?") {
02554         DEBUG_BeginPagedContent();
02555                 DEBUG_ShowMsg("Debugger commands (enter all values in hex or as register):\n");
02556                 DEBUG_ShowMsg("Commands------------------------------------------------\n");
02557                 DEBUG_ShowMsg("BP     [segment]:[offset] - Set breakpoint.\n");
02558                 DEBUG_ShowMsg("BPINT  [intNr] *          - Set interrupt breakpoint.\n");
02559                 DEBUG_ShowMsg("BPINT  [intNr] [ah] *     - Set interrupt breakpoint with ah.\n");
02560                 DEBUG_ShowMsg("BPINT  [intNr] [ah] [al]  - Set interrupt breakpoint with ah and al.\n");
02561 #if C_HEAVY_DEBUG
02562                 DEBUG_ShowMsg("BPM    [segment]:[offset] - Set memory breakpoint (memory change).\n");
02563                 DEBUG_ShowMsg("BPPM   [selector]:[offset]- Set pmode-memory breakpoint (memory change).\n");
02564                 DEBUG_ShowMsg("BPLM   [linear address]   - Set linear memory breakpoint (memory change).\n");
02565 #endif
02566                 DEBUG_ShowMsg("BPLIST                    - List breakpoints.\n");               
02567                 DEBUG_ShowMsg("BPDEL  [bpNr] / *         - Delete breakpoint nr / all.\n");
02568                 DEBUG_ShowMsg("C / D  [segment]:[offset] - Set code / data view address.\n");
02569                 DEBUG_ShowMsg("DOS MCBS                  - Show Memory Control Block chain.\n");
02570         DEBUG_ShowMsg("DOS KERN                  - Show DOS kernel memory blocks.\n");
02571         DEBUG_ShowMsg("DOS XMS                   - Show XMS memory handles.\n");
02572         DEBUG_ShowMsg("DOS EMS                   - Show EMS memory handles.\n");
02573         DEBUG_ShowMsg("DOS FNKEY                 - Show PC-98 FnKey mapping.\n");
02574         DEBUG_ShowMsg("BIOS MEM                  - Show BIOS memory blocks.\n");
02575                 DEBUG_ShowMsg("INT [nr] / INTT [nr]      - Execute / Trace into interrupt.\n");
02576 #if C_HEAVY_DEBUG
02577                 DEBUG_ShowMsg("LOG [num]                 - Write cpu log file.\n");
02578                 DEBUG_ShowMsg("LOGS/LOGL [num]           - Write short/long cpu log file.\n");
02579                 DEBUG_ShowMsg("HEAVYLOG                  - Enable/Disable automatic cpu log when dosbox exits.\n");
02580                 DEBUG_ShowMsg("ZEROPROTECT               - Enable/Disable zero code execution detection.\n");
02581 #endif
02582                 DEBUG_ShowMsg("SR [reg] [value]          - Set register value. Multiple pairs allowed.\n");
02583                 DEBUG_ShowMsg("SM [seg]:[off] [val] [.]..- Set memory with following values.\n");
02584         DEBUG_ShowMsg("EV [value [value] ...]    - Show register value(s).\n");
02585         
02586                 DEBUG_ShowMsg("IV [seg]:[off] [name]     - Create var name for memory address.\n");
02587                 DEBUG_ShowMsg("SV [filename]             - Save var list in file.\n");
02588                 DEBUG_ShowMsg("LV [filename]             - Load var list from file.\n");
02589                 
02590                 DEBUG_ShowMsg("ADDLOG [message]          - Add message to the log file.\n");
02591 
02592                 DEBUG_ShowMsg("MEMDUMP [seg]:[off] [len] - Write memory to file memdump.txt.\n");
02593                 DEBUG_ShowMsg("MEMDUMPBIN [s]:[o] [len]  - Write memory to file memdump.bin.\n");
02594                 DEBUG_ShowMsg("SELINFO [segName]         - Show selector info.\n");
02595 
02596                 DEBUG_ShowMsg("INTVEC [filename]         - Writes interrupt vector table to file.\n");
02597                 DEBUG_ShowMsg("INTHAND [intNum]          - Set code view to interrupt handler.\n");
02598 
02599                 DEBUG_ShowMsg("CPU                       - Display CPU status information.\n");
02600         DEBUG_ShowMsg("FPU                       - Display FPU status information.\n");
02601                 DEBUG_ShowMsg("GDT                       - Lists descriptors of the GDT.\n");
02602                 DEBUG_ShowMsg("LDT                       - Lists descriptors of the LDT.\n");
02603                 DEBUG_ShowMsg("IDT                       - Lists descriptors of the IDT.\n");
02604                 DEBUG_ShowMsg("PAGING [page]             - Display content of page table.\n");
02605                 DEBUG_ShowMsg("EXTEND                    - Toggle additional info.\n");
02606                 DEBUG_ShowMsg("TIMERIRQ                  - Run the system timer.\n");
02607 
02608         DEBUG_ShowMsg("IN[P|W|D] [port]          - I/O port read byte/word/dword.\n");
02609         DEBUG_ShowMsg("OUT[P|W|D] [port] [data]  - I/O port write byte/word/dword.\n");
02610 
02611                 DEBUG_ShowMsg("HELP                      - Help\n");
02612                 DEBUG_ShowMsg("Keys------------------------------------------------\n");
02613                 DEBUG_ShowMsg("F3/F6                     - Previous command in history.\n");
02614                 DEBUG_ShowMsg("F4/F7                     - Next command in history.\n");
02615                 DEBUG_ShowMsg("F5                        - Run.\n");
02616                 DEBUG_ShowMsg("F9                        - Set/Remove breakpoint.\n");
02617                 DEBUG_ShowMsg("F10/F11                   - Step over / trace into instruction.\n");
02618                 DEBUG_ShowMsg("ALT + D/E/S/X/B           - Set data view to DS:SI/ES:DI/SS:SP/DS:DX/ES:BX.\n");
02619                 DEBUG_ShowMsg("Escape                    - Clear input line.");
02620                 DEBUG_ShowMsg("Up/Down                   - Scroll up/down in the current window.\n");
02621                 DEBUG_ShowMsg("Page Up/Down              - Page up/down in the current window.\n");
02622                 DEBUG_ShowMsg("Home/End                  - Move to begin/end of the current window.\n");
02623         DEBUG_ShowMsg("TAB                       - Select next window\n");
02624         DEBUG_EndPagedContent();
02625                 
02626                 return true;
02627         }
02628 
02629         return false;
02630 }
02631 
02632 char* AnalyzeInstruction(char* inst, bool saveSelector) {
02633         static char result[256];
02634         
02635         char instu[256];
02636 
02637         strcpy(instu,inst);
02638         upcase(instu);
02639 
02640         result[0] = 0;
02641         char* pos = strchr(instu,'[');
02642         if (pos) {
02643                 char prefix[3];
02644                 Bit16u seg;
02645                 // Segment prefix ?
02646                 if (*(pos-1)==':') {
02647                         char* segpos = pos-3;
02648                         prefix[0] = tolower(*segpos);
02649                         prefix[1] = tolower(*(segpos+1));
02650                         prefix[2] = 0;
02651                         seg = (Bit16u)GetHexValue(segpos,segpos);
02652                 } else {
02653                         if (strstr(pos,"SP") || strstr(pos,"BP")) {
02654                                 seg = SegValue(ss);
02655                                 strcpy(prefix,"ss");
02656                         } else {
02657                                 seg = SegValue(ds);
02658                                 strcpy(prefix,"ds");
02659                         }
02660                 }
02661 
02662                 pos++;
02663                 Bit32u adr = GetHexValue(pos,pos);
02664                 while (*pos!=']') {
02665                         if (*pos=='+') {
02666                                 pos++;
02667                                 adr += GetHexValue(pos,pos);
02668                         } else if (*pos=='-') {
02669                                 pos++;
02670                                 adr -= GetHexValue(pos,pos); 
02671                         } else 
02672                                 pos++;
02673                 }
02674                 Bit32u address = (Bit32u)GetAddress(seg,adr);
02675                 if (!(get_tlb_readhandler(address)->flags & PFLAG_INIT)) {
02676                         static char outmask[] = "%s:[%04X]=%02X";
02677                         
02678                         if (cpu.pmode) outmask[6] = '8';
02679                                 switch (DasmLastOperandSize()) {
02680                                 case 8 : {      Bit8u val = mem_readb(address);
02681                                                         outmask[12] = '2';
02682                                                         sprintf(result,outmask,prefix,adr,val);
02683                                                 }       break;
02684                                 case 16: {      Bit16u val = mem_readw(address);
02685                                                         outmask[12] = '4';
02686                                                         sprintf(result,outmask,prefix,adr,val);
02687                                                 }       break;
02688                                 case 32: {      Bit32u val = mem_readd(address);
02689                                                         outmask[12] = '8';
02690                                                         sprintf(result,outmask,prefix,adr,val);
02691                                                 }       break;
02692                         }
02693                 } else {
02694                         sprintf(result,"[illegal]");
02695                 }
02696                 // Variable found ?
02697                 CDebugVar* var = CDebugVar::FindVar(address);
02698                 if (var) {
02699                         // Replace occurrence
02700                         char* pos1 = strchr(inst,'[');
02701                         char* pos2 = strchr(inst,']');
02702                         if (pos1 && pos2) {
02703                                 char temp[256];
02704                                 strcpy(temp,pos2);                              // save end
02705                                 pos1++; *pos1 = 0;                              // cut after '['
02706                                 strcat(inst,var->GetName());    // add var name
02707                                 strcat(inst,temp);                              // add end
02708                         }
02709                 }
02710                 // show descriptor info, if available
02711                 if ((cpu.pmode) && saveSelector) {
02712                         strcpy(curSelectorName,prefix);
02713                 }
02714         }
02715         // If it is a callback add additional info
02716         pos = strstr(inst,"callback");
02717         if (pos) {
02718                 pos += 9;
02719                 Bitu nr = GetHexValue(pos,pos);
02720                 const char* descr = CALLBACK_GetDescription(nr);
02721                 if (descr) {
02722                         strcat(inst,"  ("); strcat(inst,descr); strcat(inst,")");
02723                 }
02724         }
02725         // Must be a jump
02726         if (instu[0] == 'J')
02727         {
02728                 bool jmp = false;
02729                 switch (instu[1]) {
02730                 case 'A' :      {       jmp = (get_CF()?false:true) && (get_ZF()?false:true); // JA
02731                                         }       break;
02732                 case 'B' :      {       if (instu[2] == 'E') {
02733                                                         jmp = (get_CF()?true:false) || (get_ZF()?true:false); // JBE
02734                                                 } else {
02735                                                         jmp = get_CF()?true:false; // JB
02736                                                 }
02737                                         }       break;
02738                 case 'C' :      {       if (instu[2] == 'X') {
02739                                                         jmp = reg_cx == 0; // JCXZ
02740                                                 } else {
02741                                                         jmp = get_CF()?true:false; // JC
02742                                                 }
02743                                         }       break;
02744                 case 'E' :      {       jmp = get_ZF()?true:false; // JE
02745                                         }       break;
02746                 case 'G' :      {       if (instu[2] == 'E') {
02747                                                         jmp = (get_SF()?true:false)==(get_OF()?true:false); // JGE
02748                                                 } else {
02749                                                         jmp = (get_ZF()?false:true) && ((get_SF()?true:false)==(get_OF()?true:false)); // JG
02750                                                 }
02751                                         }       break;
02752                 case 'L' :      {       if (instu[2] == 'E') {
02753                                                         jmp = (get_ZF()?true:false) || ((get_SF()?true:false)!=(get_OF()?true:false)); // JLE
02754                                                 } else {
02755                                                         jmp = (get_SF()?true:false)!=(get_OF()?true:false); // JL
02756                                                 }
02757                                         }       break;
02758                 case 'M' :      {       jmp = true; // JMP
02759                                         }       break;
02760                 case 'N' :      {       switch (instu[2]) {
02761                                                 case 'B' :      
02762                                                 case 'C' :      {       jmp = get_CF()?false:true;      // JNB / JNC
02763                                                                         }       break;
02764                                                 case 'E' :      {       jmp = get_ZF()?false:true;      // JNE
02765                                                                         }       break;
02766                                                 case 'O' :      {       jmp = get_OF()?false:true;      // JNO
02767                                                                         }       break;
02768                                                 case 'P' :      {       jmp = get_PF()?false:true;      // JNP
02769                                                                         }       break;
02770                                                 case 'S' :      {       jmp = get_SF()?false:true;      // JNS
02771                                                                         }       break;
02772                                                 case 'Z' :      {       jmp = get_ZF()?false:true;      // JNZ
02773                                                                         }       break;
02774                                                 }
02775                                         }       break;
02776                 case 'O' :      {       jmp = get_OF()?true:false; // JO
02777                                         }       break;
02778                 case 'P' :      {       if (instu[2] == 'O') {
02779                                                         jmp = get_PF()?false:true; // JPO
02780                                                 } else {
02781                                                         jmp = get_SF()?true:false; // JP / JPE
02782                                                 }
02783                                         }       break;
02784                 case 'S' :      {       jmp = get_SF()?true:false; // JS
02785                                         }       break;
02786                 case 'Z' :      {       jmp = get_ZF()?true:false; // JZ
02787                                         }       break;
02788                 }
02789                 if (jmp) {
02790                         pos = strchr(instu,'$');
02791                         if (pos) {
02792                                 pos = strchr(instu,'+');
02793                                 if (pos) {
02794                                         strcpy(result,"(down)");
02795                                 } else {
02796                                         strcpy(result,"(up)");
02797                                 }
02798                         }
02799                 } else {
02800                         sprintf(result,"(no jmp)");
02801                 }
02802         }
02803         return result;
02804 }
02805 
02806 // data window
02807 void win_data_ui_down(int count) {
02808     if (count > 0)
02809         dataOfs += (unsigned)count * 16;
02810 }
02811 
02812 void win_data_ui_up(int count) {
02813     if (count > 0)
02814         dataOfs -= (unsigned)count * 16;
02815 }
02816 
02817 // code window
02818 void win_code_ui_down(int count) {
02819     if (dbg.win_code != NULL) {
02820         int y,x;
02821 
02822         getmaxyx(dbg.win_code,y,x);
02823 
02824         while (count-- > 0) {
02825             if (codeViewData.cursorPos < (y-1)) codeViewData.cursorPos++;
02826             else codeViewData.useEIP += codeViewData.firstInstSize;
02827         }
02828     }
02829 }
02830 
02831 void win_code_ui_up(int count) {
02832     if (dbg.win_code != NULL) {
02833         int y,x;
02834 
02835         getmaxyx(dbg.win_code,y,x);
02836 
02837         (void)y; // SET, BUT UNUSED
02838 
02839         while (count-- > 0) {
02840             if (codeViewData.cursorPos>0)
02841                 codeViewData.cursorPos--;
02842             else {
02843                 Bit32u newEIP = codeViewData.useEIP - 1;
02844                 if(codeViewData.useEIP) {
02845                     Bitu bytes = 0;
02846                     char dline[200];
02847                     for (; bytes < 10; bytes++) {
02848                         PhysPt start = (PhysPt)GetAddress(codeViewData.useCS,newEIP);
02849                         Bitu size = DasmI386(dline, start, newEIP, cpu.code.big);
02850                         if(codeViewData.useEIP == newEIP+size) break;
02851                         newEIP--;
02852                     }
02853                     if (bytes>=10) newEIP = codeViewData.useEIP - 1;
02854                 }
02855                 codeViewData.useEIP = newEIP;
02856             }
02857         }
02858     }
02859 }
02860 
02861 #ifdef WIN32
02862 extern "C" INPUT_RECORD * _pdcurses_hax_inputrecord(void);
02863 #endif
02864 
02865 Bit32u DEBUG_CheckKeys(void) {
02866         Bits ret=0;
02867         bool numberrun = false;
02868         bool skipDraw = false;
02869         int key=getch();
02870 
02871     if (key == KEY_RESIZE) {
02872 #ifdef WIN32 /* BUG: pdcurses notifies us immediately upon getting a resize event but does not update it's
02873                      internal structures to reflect the new console size. For example a Win32 console event
02874                      reporting a change to 80x41 would still return 80x40 if we asked pdcurses right now.
02875                      To make resizing the console window less painful, look at pdcurses internal structure
02876                      directly instead.
02877 
02878                      Note that we need to call resize_term() or pdcurses will never notify us about console
02879                      resize again. */
02880             /* FIXME: Windows will notify us if the user enlarges the window vertically, but will NOT notify
02881                       us if the user vertically shrinks the window (adds scrollbar instead). How do we disable
02882                       that behavior? */
02883         {
02884             INPUT_RECORD *r = _pdcurses_hax_inputrecord();
02885             if (r->EventType == WINDOW_BUFFER_SIZE_EVENT) {
02886                 resize_term(r->Event.WindowBufferSizeEvent.dwSize.Y, r->Event.WindowBufferSizeEvent.dwSize.X);
02887             }
02888         }
02889 #endif
02890         void DEBUG_GUI_OnResize(void);
02891         DEBUG_GUI_OnResize();
02892         DEBUG_DrawScreen();
02893         return 0;
02894     }
02895         
02896         if (key >='1' && key <='5' && strlen(codeViewData.inputStr) == 0) {
02897                 const Bit32s v[] ={5,500,1000,5000,10000};
02898                 CPU_Cycles= v[key - '1'];
02899 
02900                 skipFirstInstruction = true;
02901 
02902                 ret = (*cpudecoder)();
02903                 SetCodeWinStart();
02904 
02905                 /* Setup variables so we end up at the proper ret processing */
02906                 numberrun = true;
02907 
02908                 // Don't redraw the screen if it's going to get redrawn immediately
02909                 // afterwards, to avoid resetting oldregs.
02910                 if (ret == (Bits)debugCallback)
02911                         skipDraw = true;
02912                 key = -1;
02913         }
02914 
02915         if (key>0 || numberrun) {
02916 #if defined(WIN32) && defined(__PDCURSES__)
02917                 switch (key) {
02918                 case PADENTER:  key=0x0A;       break;
02919                 case PADSLASH:  key='/';        break;
02920                 case PADSTAR:   key='*';        break;
02921                 case PADMINUS:  key='-';        break;
02922                 case PADPLUS:   key='+';        break;
02923                 case ALT_D:
02924                         if (ungetch('D') != ERR) key=27;
02925                         break;
02926                 case ALT_E:
02927                         if (ungetch('E') != ERR) key=27;
02928                         break;
02929                 case ALT_X:
02930                         if (ungetch('X') != ERR) key=27;
02931                         break;
02932                 case ALT_B:
02933                         if (ungetch('B') != ERR) key=27;
02934                         break;
02935                 case ALT_S:
02936                         if (ungetch('S') != ERR) key=27;
02937                         break;
02938                 }
02939 #endif
02940                 switch (toupper(key)) {
02941                 case 27:        // escape (a bit slow): Clears line. and processes alt commands.
02942                         key=getch();
02943                         if(key < 0) { //Purely escape Clear line
02944                                 ClearInputLine();
02945                                 break;
02946                         }
02947 
02948                         switch(toupper(key)) {
02949                         case 'D' : // ALT - D: DS:SI
02950                                 dataSeg = SegValue(ds);
02951                                 if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_esi;
02952                                 else dataOfs = reg_si;
02953                                 break;
02954                         case 'E' : //ALT - E: es:di
02955                                 dataSeg = SegValue(es);
02956                                 if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_edi;
02957                                 else dataOfs = reg_di;
02958                                 break;
02959                         case 'X': //ALT - X: ds:dx
02960                                 dataSeg = SegValue(ds);
02961                                 if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_edx;
02962                                 else dataOfs = reg_dx;
02963                                 break;
02964                         case 'B' : //ALT -B: es:bx
02965                                 dataSeg = SegValue(es);
02966                                 if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_ebx;
02967                                 else dataOfs = reg_bx;
02968                                 break;
02969                         case 'S': //ALT - S: ss:sp
02970                                 dataSeg = SegValue(ss);
02971                                 if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_esp;
02972                                 else dataOfs = reg_sp;
02973                                 break;
02974                         default:
02975                                 break;
02976                         }
02977                         break;
02978         case KEY_PPAGE: // page up
02979             switch (dbg.active_win) {
02980                 case DBGBlock::WINI_CODE:
02981                     if (dbg.win_code != NULL) {
02982                         int w,h;
02983 
02984                         getmaxyx(dbg.win_code,h,w);
02985                         win_code_ui_up(h-1);
02986                     }
02987                     break;
02988                 case DBGBlock::WINI_DATA:
02989                      if (dbg.win_data != NULL) {
02990                         int w,h;
02991 
02992                         getmaxyx(dbg.win_data,h,w);
02993                         win_data_ui_up(h);
02994                     }
02995                     break;
02996                 case DBGBlock::WINI_OUT:
02997                     if (dbg.win_out != NULL) {
02998                         int w,h;
02999 
03000                         getmaxyx(dbg.win_out,h,w);
03001                         DEBUG_RefreshPage(-h);
03002                     }
03003                     break;
03004             }
03005             break;
03006 
03007         case KEY_NPAGE: // page down
03008             switch (dbg.active_win) {
03009                 case DBGBlock::WINI_CODE:
03010                     if (dbg.win_code != NULL) {
03011                         int w,h;
03012 
03013                         getmaxyx(dbg.win_code,h,w);
03014                         win_code_ui_down(h-1);
03015                     }
03016                     break;
03017                 case DBGBlock::WINI_DATA:
03018                      if (dbg.win_data != NULL) {
03019                         int w,h;
03020 
03021                         getmaxyx(dbg.win_data,h,w);
03022                         win_data_ui_down(h);
03023                     }
03024                     break;
03025                 case DBGBlock::WINI_OUT:
03026                     if (dbg.win_out != NULL) {
03027                         int w,h;
03028 
03029                         getmaxyx(dbg.win_out,h,w);
03030                         DEBUG_RefreshPage(h);
03031                     }
03032                     break;
03033             }
03034             break;
03035 
03036                 case KEY_DOWN:  // down
03037                 switch (dbg.active_win) {
03038                     case DBGBlock::WINI_CODE:
03039                         win_code_ui_down(1);
03040                         break;
03041                     case DBGBlock::WINI_DATA:
03042                         win_data_ui_down(1);
03043                         break;
03044                     case DBGBlock::WINI_OUT:
03045                         DEBUG_RefreshPage(1);
03046                         break;
03047                 }
03048                 break;
03049         case KEY_UP:    // up 
03050                 switch (dbg.active_win) {
03051                     case DBGBlock::WINI_CODE:
03052                         win_code_ui_up(1);
03053                         break;
03054                     case DBGBlock::WINI_DATA:
03055                         win_data_ui_up(1);
03056                         break;
03057                     case DBGBlock::WINI_OUT:
03058                         DEBUG_RefreshPage(-1);
03059                         break;
03060                 }
03061                                 break;
03062 
03063                 case KEY_HOME:  // Home
03064                 switch (dbg.active_win) {
03065                     case DBGBlock::WINI_CODE:
03066                         // and do what?
03067                         break;
03068                     case DBGBlock::WINI_DATA:
03069                         // and do what?
03070                         break;
03071                     case DBGBlock::WINI_OUT:
03072                         void DEBUG_ScrollHomeOutput(void);
03073                         DEBUG_ScrollHomeOutput();
03074                         break;
03075                 }
03076                                 break;
03077 
03078                 case KEY_END:   // End
03079                 switch (dbg.active_win) {
03080                     case DBGBlock::WINI_CODE:
03081                         // and do what?
03082                         break;
03083                     case DBGBlock::WINI_DATA:
03084                         // and do what?
03085                         break;
03086                     case DBGBlock::WINI_OUT:
03087                         void DEBUG_ScrollToEndOutput(void);
03088                         DEBUG_ScrollToEndOutput();
03089                         break;
03090                 }
03091                                 break;
03092 
03093         case KEY_IC:    // Insert: toggle insert/overwrite
03094                                 codeViewData.ovrMode = !codeViewData.ovrMode;
03095                                 break;
03096                 case KEY_LEFT:  // move to the left in command line
03097                                 if (codeViewData.inputPos > 0) codeViewData.inputPos--;
03098                                 break;
03099                 case KEY_RIGHT: // move to the right in command line
03100                                 if (codeViewData.inputStr[codeViewData.inputPos]) codeViewData.inputPos++;
03101                                 break;
03102                 case KEY_F(6):  // previous command (f1-f4 generate rubbish at my place)
03103                 case KEY_F(3):  // previous command 
03104                                 if (histBuffPos == histBuff.begin()) break;
03105                                 if (histBuffPos == histBuff.end()) {
03106                                         // copy inputStr to suspInputStr so we can restore it
03107                                         safe_strncpy(codeViewData.suspInputStr, codeViewData.inputStr, sizeof(codeViewData.suspInputStr));
03108                                 }
03109                                 safe_strncpy(codeViewData.inputStr,(*--histBuffPos).c_str(),sizeof(codeViewData.inputStr));
03110                                 codeViewData.inputPos = (int)strlen(codeViewData.inputStr);
03111                                 break;
03112                 case KEY_F(7):  // next command (f1-f4 generate rubbish at my place)
03113                 case KEY_F(4):  // next command
03114                                 if (histBuffPos == histBuff.end()) break;
03115                                 if (++histBuffPos != histBuff.end()) {
03116                                         safe_strncpy(codeViewData.inputStr,(*histBuffPos).c_str(),sizeof(codeViewData.inputStr));
03117                                 } else {
03118                                         // copy suspInputStr back into inputStr
03119                                         safe_strncpy(codeViewData.inputStr, codeViewData.suspInputStr, sizeof(codeViewData.inputStr));
03120                                 }
03121                                 codeViewData.inputPos = (int)strlen(codeViewData.inputStr);
03122                                 break; 
03123                 case KEY_F(5):  // Run Program
03124                 DrawRegistersUpdateOld();
03125                                 debugging=false;
03126                                 DrawCode();
03127                 DrawInput();
03128                 logBuffSuppressConsole = false;
03129                 if (logBuffSuppressConsoleNeedUpdate) {
03130                     logBuffSuppressConsoleNeedUpdate = false;
03131                     DEBUG_RefreshPage(0);
03132                 }
03133 
03134                 Bits DEBUG_NullCPUCore(void);
03135 
03136                                 CPU_Cycles = 1;
03137                 inhibit_int_breakpoint = true;
03138                 if (cpudecoder == DEBUG_NullCPUCore)
03139                     ret = -1; /* DEBUG_Loop() must exit */
03140                 else
03141                     ret = (*cpudecoder)();
03142 
03143                 inhibit_int_breakpoint = false;
03144                 mainMenu.get_item("mapper_debugger").check(false).refresh_item(mainMenu);
03145 
03146                                 skipFirstInstruction = true; // for heavy debugger
03147                                 CPU_Cycles = 1;
03148 
03149                                 // ensure all breakpoints are activated
03150                                 CBreakpoint::ActivateBreakpoints();
03151 
03152                                 skipDraw = true; // don't update screen after this instruction
03153 
03154                                 DOSBOX_SetNormalLoop();
03155                                 break;
03156                 case KEY_F(9):  // Set/Remove Breakpoint
03157                                 if (CBreakpoint::IsBreakpoint(codeViewData.cursorSeg, codeViewData.cursorOfs)) {
03158                                         if (CBreakpoint::DeleteBreakpoint(codeViewData.cursorSeg, codeViewData.cursorOfs))
03159                                                 DEBUG_ShowMsg("DEBUG: Breakpoint deletion success.\n");
03160                                         else
03161                                                 DEBUG_ShowMsg("DEBUG: Failed to delete breakpoint.\n");
03162                                 }
03163                                 else {
03164                                         CBreakpoint::AddBreakpoint(codeViewData.cursorSeg, codeViewData.cursorOfs, false);
03165                                         DEBUG_ShowMsg("DEBUG: Set breakpoint at %04X:%04X\n",codeViewData.cursorSeg,codeViewData.cursorOfs);
03166                                 }
03167                                 break;
03168                 case KEY_F(10): // Step over inst
03169                 DrawRegistersUpdateOld();
03170                                 if (StepOver()) {
03171                                         mustCompleteInstruction = true;
03172                                         inhibit_int_breakpoint = true;
03173                     skipFirstInstruction = true; // for heavy debugger
03174                                         CPU_Cycles = 1;
03175                                         ret=(*cpudecoder)();
03176                     inhibit_int_breakpoint = false;
03177                                         mustCompleteInstruction = false;
03178 
03179                                         DOSBOX_SetNormalLoop();
03180 
03181                                         // ensure all breakpoints are activated
03182                                         CBreakpoint::ActivateBreakpoints();
03183                                         skipDraw = true;
03184                                         break;
03185                                 }
03186                                 // If we aren't stepping over something, do a normal step.
03187                                 // NB: Fall-through
03188                 case KEY_F(11): // trace into
03189                 DrawRegistersUpdateOld();
03190                                 exitLoop = false;
03191                                 skipFirstInstruction = true; // for heavy debugger
03192                                 mustCompleteInstruction = true;
03193                                 CPU_Cycles = 1;
03194                                 ret = (*cpudecoder)();
03195                                 mustCompleteInstruction = false;
03196                                 SetCodeWinStart();
03197                                 break;
03198         case 0x09: //TAB
03199                 void DBGUI_NextWindow(void);
03200                 DBGUI_NextWindow();
03201                 break;
03202                 case 0x0A: //Parse typed Command
03203                 if (codeViewData.inputPos > 0) {
03204                     codeViewData.inputStr[MAXCMDLEN] = '\0';
03205                     if(ParseCommand(codeViewData.inputStr)) {
03206                         char* cmd = ltrim(codeViewData.inputStr);
03207                         if (histBuff.empty() || *--histBuff.end()!=cmd)
03208                             histBuff.push_back(cmd);
03209                         if (histBuff.size() > MAX_HIST_BUFFER) histBuff.pop_front();
03210                         histBuffPos = histBuff.end();
03211                         ClearInputLine();
03212                     } else {
03213                         DEBUG_ShowMsg("*** Debugger command not recognized");
03214                         codeViewData.inputPos = (int)strlen(codeViewData.inputStr);
03215                     }
03216                 }
03217                                 break;
03218                 case KEY_BACKSPACE: //backspace (linux)
03219                 case 0x7f:      // backspace in some terminal emulators (linux)
03220                 case 0x08:      // delete 
03221                                 if (codeViewData.inputPos == 0) break;
03222                                 codeViewData.inputPos--;
03223                                 // fallthrough
03224                 case KEY_DC: // delete character 
03225                                 if ((codeViewData.inputPos<0) || (codeViewData.inputPos>=MAXCMDLEN)) break;
03226                                 if (codeViewData.inputStr[codeViewData.inputPos] != 0) {
03227                                                 codeViewData.inputStr[MAXCMDLEN] = '\0';
03228                                                 for(char* p=&codeViewData.inputStr[codeViewData.inputPos];(*p=*(p+1));p++) {}
03229                                 }
03230                                 break;
03231                 default:
03232                                 if ((key>=32) && (key<127)) {
03233                                         if ((codeViewData.inputPos<0) || (codeViewData.inputPos>=MAXCMDLEN)) break;
03234                                         codeViewData.inputStr[MAXCMDLEN] = '\0';
03235                                         if (codeViewData.inputStr[codeViewData.inputPos] == 0) {
03236                                                         codeViewData.inputStr[codeViewData.inputPos++] = char(key);
03237                                                         codeViewData.inputStr[codeViewData.inputPos] = '\0';
03238                                         } else if (!codeViewData.ovrMode) {
03239                                                 int len = (int) strlen(codeViewData.inputStr);
03240                                                 if (len < MAXCMDLEN) { 
03241                                                         for(len++;len>codeViewData.inputPos;len--)
03242                                                                 codeViewData.inputStr[len]=codeViewData.inputStr[len-1];
03243                                                         codeViewData.inputStr[codeViewData.inputPos++] = char(key);
03244                                                 }
03245                                         } else {
03246                                                 codeViewData.inputStr[codeViewData.inputPos++] = char(key);
03247                                         }
03248                                 } else if (key==killchar()) {
03249                                         ClearInputLine();
03250                                 }
03251                                 break;
03252                 }
03253                 if (ret<0) return (Bit32u)ret;
03254                 if (ret>0) {
03255                         if (GCC_UNLIKELY(ret >= (Bits)CB_MAX)) 
03256                                 ret = 0;
03257                         else
03258                                 ret = (Bits)(*CallBack_Handlers[ret])();
03259                         if (ret) {
03260                                 exitLoop=true;
03261                                 CPU_Cycles=CPU_CycleLeft=0;
03262                                 return (Bit32u)ret;
03263                         }
03264                 }
03265                 ret=0;
03266                 if (!skipDraw)
03267                         DEBUG_DrawScreen();
03268         }
03269         return (Bit32u)ret;
03270 }
03271 
03272 Bitu DEBUG_LastRunningUpdate = 0;
03273 
03274 LoopHandler *DOSBOX_GetLoop(void);
03275 Bitu DEBUG_Loop(void);
03276 
03277 void DEBUG_Wait(void) {
03278     while (DOSBOX_GetLoop() == DEBUG_Loop)
03279         DOSBOX_RunMachine();
03280 }
03281 
03282 Bits DEBUG_NullCPUCore(void) {
03283     return CBRET_NONE;
03284 }
03285 
03286 void DEBUG_WaitNoExecute(void) {
03287     /* the caller uses this version to indicate a fatal error
03288      * in a condition where single-stepping or executing any
03289      * more x86 instructions is very unwise */
03290     auto oldcore = cpudecoder;
03291     cpudecoder = DEBUG_NullCPUCore;
03292     DEBUG_Wait();
03293     cpudecoder = oldcore;
03294 }
03295 
03296 Bitu DEBUG_Loop(void) {
03297     if (debug_running) {
03298         Bitu now = SDL_GetTicks();
03299 
03300         if ((DEBUG_LastRunningUpdate + 33) < now) {
03301             DEBUG_LastRunningUpdate = now;
03302             SetCodeWinStart();
03303             DEBUG_DrawScreen();
03304         }
03305 
03306         return old_loop();
03307     }
03308     else {
03309         //TODO Disable sound
03310         GFX_Events();
03311         // Interrupt started ? - then skip it
03312         Bit16u oldCS    = SegValue(cs);
03313         Bit32u oldEIP   = reg_eip;
03314         PIC_runIRQs();
03315         SDL_Delay(1);
03316         if ((oldCS!=SegValue(cs)) || (oldEIP!=reg_eip)) {
03317             CBreakpoint::AddBreakpoint(oldCS,oldEIP,true);
03318             CBreakpoint::ActivateBreakpointsExceptAt(SegPhys(cs)+reg_eip);
03319             debugging=false;
03320 
03321             logBuffSuppressConsole = false;
03322             if (logBuffSuppressConsoleNeedUpdate) {
03323                 logBuffSuppressConsoleNeedUpdate = false;
03324                 DEBUG_RefreshPage(0);
03325             }
03326 
03327                         mainMenu.get_item("mapper_debugger").check(false).refresh_item(mainMenu);
03328             DOSBOX_SetNormalLoop();
03329             DrawRegistersUpdateOld();
03330             return 0;
03331         }
03332 
03333         /* between DEBUG_Enable and DEBUG_Loop CS:EIP can change */
03334         if (check_rescroll) {
03335             Bit16u ocs;
03336             Bit32u oip;
03337             int ocr;
03338 
03339             check_rescroll = false;
03340             ocs = codeViewData.useCS;
03341             oip = codeViewData.useEIP;
03342             ocr = codeViewData.cursorPos;
03343             SetCodeWinStart();
03344             if (ocs != codeViewData.useCS ||
03345                     oip != codeViewData.useEIP) {
03346                 DEBUG_DrawScreen();
03347             }
03348             else {
03349                 /* SetCodeWinStart() resets cursor position */
03350                 codeViewData.cursorPos = ocr;
03351             }
03352         }
03353 
03354         if (logBuffSuppressConsoleNeedUpdate) {
03355             logBuffSuppressConsoleNeedUpdate = false;
03356             DEBUG_RefreshPage(0);
03357         }
03358 
03359         return DEBUG_CheckKeys();
03360     }
03361 }
03362 
03363 void DEBUG_FlushInput(void);
03364 
03365 void DEBUG_Enable_Handler(bool pressed) {
03366         if (!pressed)
03367                 return;
03368 
03369     /* this command is now a toggle! */
03370     /* However this should break back into the debugger if RUNWATCH is active */
03371     if (debug_running) {
03372         debug_running = false;
03373         DrawRegistersUpdateOld();
03374         SetCodeWinStart();
03375         DEBUG_DrawScreen();
03376         return;
03377     }
03378     else if (debugging) {
03379         DrawRegistersUpdateOld();
03380         debugging=false;
03381 
03382         logBuffSuppressConsole = false;
03383         if (logBuffSuppressConsoleNeedUpdate) {
03384             logBuffSuppressConsoleNeedUpdate = false;
03385             DEBUG_RefreshPage(0);
03386         }
03387 
03388         void DEBUG_DrawScreen(void);
03389         DEBUG_DrawScreen();
03390 
03391         CBreakpoint::ActivateBreakpointsExceptAt(SegPhys(cs)+reg_eip);
03392                 mainMenu.get_item("mapper_debugger").check(false).refresh_item(mainMenu);
03393         DOSBOX_SetNormalLoop(); 
03394         GFX_SetTitle(-1,-1,-1,is_paused);
03395         return;
03396     }
03397 
03398         static bool showhelp=false;
03399 
03400 #if defined(MACOSX) || defined(LINUX)
03401         /* Mac OS X does not have a console for us to just allocate on a whim like Windows does.
03402            So the debugger interface is useless UNLESS the user has started us from a terminal
03403            (whether over SSH or from the Terminal app). */
03404     bool allow = true;
03405 
03406     if (!isatty(0) || !isatty(1) || !isatty(2))
03407             allow = false;
03408 
03409     if (!allow) {
03410 # if defined(MACOSX)
03411             LOG_MSG("Debugger in Mac OS X is not available unless you start DOSBox-X from a terminal or from the Terminal application");
03412 # else
03413             LOG_MSG("Debugger is not available unless you start DOSBox-X from a terminal");
03414 # endif
03415             return;
03416     }
03417 #endif
03418 
03419     CPU_CycleLeft+=CPU_Cycles;
03420     CPU_Cycles=0;
03421 
03422     logBuffSuppressConsole = true;
03423 
03424     LoopHandler *ol = DOSBOX_GetLoop();
03425     if (ol != DEBUG_Loop) old_loop = ol;
03426 
03427         debugging=true;
03428     debug_running=false;
03429     check_rescroll=true;
03430     DrawRegistersUpdateOld();
03431     DEBUG_SetupConsole();
03432     DEBUG_FlushInput();
03433         SetCodeWinStart();
03434         DEBUG_DrawScreen();
03435         DOSBOX_SetLoop(&DEBUG_Loop);
03436         mainMenu.get_item("mapper_debugger").check(true).refresh_item(mainMenu);
03437         if(!showhelp) { 
03438                 showhelp=true;
03439                 DEBUG_ShowMsg("***| TYPE HELP (+ENTER) TO GET AN OVERVIEW OF ALL COMMANDS |***\n");
03440         }
03441         KEYBOARD_ClrBuffer();
03442     GFX_SetTitle(-1,-1,-1,false);
03443 }
03444 
03445 void DEBUG_DrawScreen(void) {
03446         DrawData();
03447         DrawCode();
03448     DrawInput();
03449         DrawRegisters();
03450         DrawVariables();
03451 }
03452 
03453 static void DEBUG_RaiseTimerIrq(void) {
03454         PIC_ActivateIRQ(0);
03455 }
03456 
03457 // Display the content of the MCB chain starting with the MCB at the specified segment.
03458 static void LogMCBChain(Bit16u mcb_segment) {
03459         DOS_MCB mcb(mcb_segment);
03460         char filename[9]; // 8 characters plus a terminating NUL
03461         const char *psp_seg_note;
03462         Bit16u DOS_dataOfs = static_cast<Bit16u>(dataOfs); //Realmode addressing only
03463         PhysPt dataAddr = PhysMake(dataSeg,DOS_dataOfs);// location being viewed in the "Data Overview"
03464 
03465         // loop forever, breaking out of the loop once we've processed the last MCB
03466         while (true) {
03467                 // verify that the type field is valid
03468                 if (mcb.GetType()!=0x4d && mcb.GetType()!=0x5a) {
03469                         DEBUG_ShowMsg("MCB chain broken at %04X:0000!",mcb_segment);
03470                         return;
03471                 }
03472 
03473                 mcb.GetFileName(filename);
03474 
03475                 // some PSP segment values have special meanings
03476                 switch (mcb.GetPSPSeg()) {
03477                         case MCB_FREE:
03478                                 psp_seg_note = "(free)";
03479                                 break;
03480                         case MCB_DOS:
03481                                 psp_seg_note = "(DOS)";
03482                                 break;
03483                         default:
03484                                 psp_seg_note = "";
03485                 }
03486 
03487         DEBUG_ShowMsg("   %04X  %12u     %04X %-7s  %s",mcb_segment,mcb.GetSize() << 4,mcb.GetPSPSeg(), psp_seg_note, filename);
03488 
03489                 // print a message if dataAddr is within this MCB's memory range
03490                 PhysPt mcbStartAddr = PhysMake(mcb_segment+1,0);
03491                 PhysPt mcbEndAddr = PhysMake(mcb_segment+1+mcb.GetSize(),0);
03492                 if (dataAddr >= mcbStartAddr && dataAddr < mcbEndAddr) {
03493             DEBUG_ShowMsg("   (data addr %04hX:%04X is %u bytes past this MCB)",dataSeg,DOS_dataOfs,dataAddr - mcbStartAddr);
03494                 }
03495 
03496                 // if we've just processed the last MCB in the chain, break out of the loop
03497                 if (mcb.GetType()==0x5a) {
03498                         break;
03499                 }
03500                 // else, move to the next MCB in the chain
03501                 mcb_segment+=mcb.GetSize()+1;
03502                 mcb.SetPt(mcb_segment);
03503         }
03504 }
03505 
03506 #include "regionalloctracking.h"
03507 
03508 extern bool dos_kernel_disabled;
03509 extern RegionAllocTracking rombios_alloc;
03510 
03511 static void LogBIOSMem(void) {
03512     char tmp[192];
03513 
03514     DEBUG_BeginPagedContent();
03515 
03516     DEBUG_ShowMsg("BIOS memory blocks:");
03517     DEBUG_ShowMsg("Region            Status What");
03518     for (auto i=rombios_alloc.alist.begin();i!=rombios_alloc.alist.end();i++) {
03519         sprintf(tmp,"%08lx-%08lx %s",
03520             (unsigned long)(i->start),
03521             (unsigned long)(i->end),
03522             i->free ? "FREE  " : "ALLOC ");
03523         DEBUG_ShowMsg("%s %s",tmp,i->who.c_str());
03524     }
03525 
03526     DEBUG_EndPagedContent();
03527 }
03528 
03529 Bitu XMS_GetTotalHandles(void);
03530 bool XMS_GetHandleInfo(Bitu &phys_location,Bitu &size,Bitu &lockcount,bool &free,Bitu handle);
03531 
03532 bool EMS_GetHandle(Bitu &size,PhysPt &addr,std::string &name,Bitu handle);
03533 const char *EMS_Type_String(void);
03534 Bitu EMS_Max_Handles(void);
03535 bool EMS_Active(void);
03536 
03537 static void LogFNKEY(void) {
03538     DEBUG_BeginPagedContent();
03539 
03540     void DEBUG_INTDC_FnKeyMapInfo(void);
03541     DEBUG_INTDC_FnKeyMapInfo();
03542 
03543     DEBUG_EndPagedContent();
03544 }
03545 
03546 static void LogEMS(void) {
03547     Bitu h_size;
03548     PhysPt xh_addr;
03549     std::string h_name;
03550 
03551     if (dos_kernel_disabled) {
03552         DEBUG_ShowMsg("Cannot enumerate EMS memory while DOS kernel is inactive.");
03553         return;
03554     }
03555 
03556     if (!EMS_Active()) {
03557         DEBUG_ShowMsg("Cannot enumerate EMS memory while EMS is inactive.");
03558         return;
03559     }
03560 
03561     DEBUG_BeginPagedContent();
03562 
03563     DEBUG_ShowMsg("EMS memory (type %s) handles:",EMS_Type_String());
03564     DEBUG_ShowMsg("Handle Address  Size (bytes)    Name");
03565     for (Bitu h=0;h < EMS_Max_Handles();h++) {
03566         if (EMS_GetHandle(/*&*/h_size,/*&*/xh_addr,/*&*/h_name,h)) {
03567             DEBUG_ShowMsg("%6lu %08lx %08lx %s",
03568                 (unsigned long)h,
03569                 (unsigned long)xh_addr,
03570                 (unsigned long)h_size,
03571                 h_name.c_str());
03572         }
03573     }
03574 
03575     bool EMS_GetMapping(Bitu &handle,Bit16u &log_page,Bitu ems_page);
03576     Bitu GetEMSPageFrameSegment(void);
03577     Bitu GetEMSPageFrameSize(void);
03578 
03579     DEBUG_ShowMsg("EMS page frame 0x%08lx-0x%08lx",
03580         GetEMSPageFrameSegment()*16UL,
03581         (GetEMSPageFrameSegment()*16UL)+GetEMSPageFrameSize()-1UL);
03582     DEBUG_ShowMsg("Handle Page(p/l) Address");
03583 
03584     for (Bitu p=0;p < (GetEMSPageFrameSize() >> 14UL);p++) {
03585         Bit16u log_page;
03586         Bitu handle;
03587 
03588         if (EMS_GetMapping(handle,log_page,p)) {
03589             char tmp[192] = {0};
03590 
03591             xh_addr = 0;
03592             h_size = 0;
03593             h_name.clear();
03594             EMS_GetHandle(/*&*/h_size,/*&*/xh_addr,/*&*/h_name,handle);
03595 
03596             if (xh_addr != 0)
03597                 sprintf(tmp," virt -> %08lx-%08lx phys",
03598                     (unsigned long)(xh_addr + ((PhysPt)log_page << 14u)),
03599                     (unsigned long)(xh_addr + ((PhysPt)log_page << 14u) + (1u << 14u) - 1u));
03600 
03601             DEBUG_ShowMsg("%6lu %4lu/%4lu %08lx-%08lx%s",(unsigned long)handle,
03602                 (unsigned long)p,(unsigned long)log_page,
03603                 (GetEMSPageFrameSegment()*16UL)+(p << 14UL),
03604                 (GetEMSPageFrameSegment()*16UL)+((p+1UL) << 14UL)-1,
03605                 tmp);
03606         }
03607         else {
03608             DEBUG_ShowMsg("--     %4lu/     %08lx-%08lx",(unsigned long)p,
03609                 (GetEMSPageFrameSegment()*16UL)+(p << 14UL),
03610                 (GetEMSPageFrameSegment()*16UL)+((p+1UL) << 14UL)-1);
03611         }
03612     }
03613 
03614     DEBUG_EndPagedContent();
03615 }
03616 
03617 static void LogXMS(void) {
03618     Bitu phys_location;
03619     Bitu lockcount;
03620     bool free;
03621     Bitu size;
03622 
03623     if (dos_kernel_disabled) {
03624         DEBUG_ShowMsg("Cannot enumerate XMS memory while DOS kernel is inactive.");
03625         return;
03626     }
03627 
03628     if (!XMS_Active()) {
03629         DEBUG_ShowMsg("Cannot enumerate XMS memory while XMS is inactive.");
03630         return;
03631     }
03632 
03633     DEBUG_BeginPagedContent();
03634 
03635     DEBUG_ShowMsg("XMS memory handles:");
03636     DEBUG_ShowMsg("Handle Status Location Size (bytes)");
03637     for (Bitu h = 1; h < XMS_GetTotalHandles(); h++) {
03638         if (XMS_GetHandleInfo(/*&*/phys_location,/*&*/size,/*&*/lockcount,/*&*/free, h)) {
03639             DEBUG_ShowMsg("%6lu %s 0x%08lx %lu",
03640                 (unsigned long)h,
03641                 free ? "FREE " : "ALLOC ",
03642                 (unsigned long)phys_location,
03643                 (unsigned long)size << 10UL); /* KB -> bytes */
03644         }
03645     }
03646 
03647     DEBUG_EndPagedContent();
03648 }
03649 
03650 static void LogDOSKernMem(void) {
03651     char tmp[192];
03652 
03653     if (dos_kernel_disabled) {
03654         DEBUG_ShowMsg("Cannot enumerate DOS kernel memory while DOS kernel is inactive.");
03655         return;
03656     }
03657 
03658     DEBUG_BeginPagedContent();
03659 
03660     DEBUG_ShowMsg("DOS kernel memory blocks:");
03661     DEBUG_ShowMsg("Seg      Size (bytes)     What");
03662     for (auto i=DOS_GetMemLog.begin();i!=DOS_GetMemLog.end();i++) {
03663         sprintf(tmp,"%04x     %8lu     ",
03664                 (unsigned int)(i->segbase),
03665                 (unsigned long)(i->pages << 4UL));
03666 
03667         DEBUG_ShowMsg("%s    %s",tmp,i->who.c_str());
03668     }
03669 
03670     DEBUG_EndPagedContent();
03671 }
03672 
03673 // Display the content of all Memory Control Blocks.
03674 static void LogMCBS(void)
03675 {
03676     if (dos_kernel_disabled) {
03677         if (boothax == BOOTHAX_MSDOS) {
03678             if (guest_msdos_LoL == 0 || guest_msdos_mcb_chain == 0) {
03679                 DEBUG_ShowMsg("Cannot enumerate MCB list while DOS kernel is inactive, and DOSBox-X has not yet determined the MCB list of the guest MS-DOS operating system");
03680                 return;
03681             }
03682 
03683             DEBUG_BeginPagedContent();
03684 
03685             try {
03686                 DEBUG_ShowMsg("MCB Seg  Size (bytes)  PSP Seg (notes)  Filename");
03687                 DEBUG_ShowMsg("Conventional memory:");
03688                 LogMCBChain(guest_msdos_mcb_chain);
03689             }
03690             catch (GuestPageFaultException &pf) {
03691                 (void)pf;//unused
03692                 DEBUG_ShowMsg("(Enumeration caused page fault within the guest)");
03693             }
03694 
03695             DEBUG_EndPagedContent();
03696             return;
03697         }
03698         else {
03699             DEBUG_ShowMsg("Cannot enumerate MCB list while DOS kernel is inactive.");
03700             return;
03701         }
03702     }
03703 
03704     DEBUG_BeginPagedContent();
03705 
03706     DEBUG_ShowMsg("MCB Seg  Size (bytes)  PSP Seg (notes)  Filename");
03707     DEBUG_ShowMsg("Conventional memory:");
03708     LogMCBChain(dos.firstMCB);
03709 
03710     if (dos_infoblock.GetStartOfUMBChain() != 0xFFFF) {
03711         DEBUG_ShowMsg("Upper memory:");
03712         LogMCBChain(dos_infoblock.GetStartOfUMBChain());
03713     }
03714 
03715     DEBUG_EndPagedContent();
03716 }
03717 
03718 static void LogGDT(void)
03719 {
03720         char out1[512];
03721         Descriptor desc;
03722         Bitu length = cpu.gdt.GetLimit();
03723         PhysPt address = cpu.gdt.GetBase();
03724         PhysPt max         = (PhysPt)(address + length);
03725         Bitu i = 0;
03726 
03727     DEBUG_BeginPagedContent();
03728 
03729     DEBUG_ShowMsg("GDT Base:%08lX Limit:%08lX",(unsigned long)address,(unsigned long)length);
03730         while (address<max) {
03731                 desc.Load(address);
03732                 sprintf(out1,"%04X: b:%08lX type: %02X parbg",(int)(i<<3),(unsigned long)desc.GetBase(),desc.saved.seg.type);
03733         DEBUG_ShowMsg("%s",out1);
03734                 sprintf(out1,"      l:%08lX dpl : %01X  %1X%1X%1X%1X%1X",(unsigned long)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);
03735         DEBUG_ShowMsg("%s",out1);
03736                 address+=8; i++;
03737         }
03738 
03739     DEBUG_EndPagedContent();
03740 }
03741 
03742 static void LogLDT(void) {
03743         char out1[512];
03744         Descriptor desc;
03745         Bitu ldtSelector = cpu.gdt.SLDT();
03746         if (!cpu.gdt.GetDescriptor(ldtSelector,desc)) return;
03747         Bitu length = desc.GetLimit();
03748         PhysPt address = desc.GetBase();
03749         PhysPt max         = (PhysPt)(address + length);
03750         Bitu i = 0;
03751 
03752     DEBUG_BeginPagedContent();
03753 
03754     DEBUG_ShowMsg("LDT Base:%08lX Limit:%08lX",(unsigned long)address,(unsigned long)length);
03755         while (address<max) {
03756                 desc.Load(address);
03757                 sprintf(out1,"%04X: b:%08lX type: %02X parbg",(int)((i<<3)|4),(unsigned long)desc.GetBase(),desc.saved.seg.type);
03758         DEBUG_ShowMsg("%s",out1);
03759                 sprintf(out1,"      l:%08lX dpl : %01X  %1X%1X%1X%1X%1X",(unsigned long)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);
03760         DEBUG_ShowMsg("%s",out1);
03761                 address+=8; i++;
03762         }
03763 
03764     DEBUG_EndPagedContent();
03765 }
03766 
03767 static void LogIDT(void) {
03768         char out1[512];
03769         Descriptor desc;
03770         Bitu address = 0;
03771 
03772     DEBUG_BeginPagedContent();
03773 
03774         while (address<256*8) {
03775                 if (cpu.idt.GetDescriptor(address,desc)) {
03776                         sprintf(out1,"%04X: sel:%04X off:%02X",(unsigned int)(address/8),(int)desc.GetSelector(),(int)desc.GetOffset());
03777             DEBUG_ShowMsg("%s",out1);
03778                 }
03779                 address+=8;
03780         }
03781 
03782     DEBUG_EndPagedContent();
03783 }
03784 
03785 void LogPages(char* selname) {
03786     DEBUG_BeginPagedContent();
03787 
03788         if (paging.enabled) {
03789                 char out1[512];
03790                 Bitu sel = GetHexValue(selname,selname);
03791                 if ((sel==0x00) && ((*selname==0) || (*selname=='*'))) {
03792                         for (unsigned int i=0; i<0xfffff; i++) {
03793                                 Bitu table_addr=((Bitu)paging.base.page<<12u)+(i >> 10u)*(Bitu)4u;
03794                                 X86PageEntry table;
03795                                 table.load=phys_readd((PhysPt)table_addr);
03796                                 if (table.block.p) {
03797                                         X86PageEntry entry;
03798                     PhysPt entry_addr=((PhysPt)table.block.base<<12u)+(i & 0x3ffu)* 4u;
03799                                         entry.load=phys_readd(entry_addr);
03800                                         if (entry.block.p) {
03801                                                 sprintf(out1,"page %05Xxxx -> %04Xxxx  flags [uw] %x:%x::%x:%x [d=%x|a=%x]",
03802                                                         i,entry.block.base,entry.block.us,table.block.us,
03803                                                         entry.block.wr,table.block.wr,entry.block.d,entry.block.a);
03804                         DEBUG_ShowMsg("%s",out1);
03805                                         }
03806                                 }
03807                         }
03808                 } else {
03809                         Bitu table_addr=(paging.base.page<<12u)+(sel >> 10u)*4u;
03810                         X86PageEntry table;
03811                         table.load=phys_readd((PhysPt)table_addr);
03812                         if (table.block.p) {
03813                                 X86PageEntry entry;
03814                                 Bitu entry_addr=((Bitu)table.block.base<<12u)+(sel & 0x3ffu)*4u;
03815                                 entry.load=phys_readd((PhysPt)entry_addr);
03816                                 sprintf(out1,"page %05lXxxx -> %04lXxxx  flags [puw] %x:%x::%x:%x::%x:%x",
03817                                         (unsigned long)sel,
03818                                         (unsigned long)entry.block.base,
03819                                         entry.block.p,table.block.p,entry.block.us,table.block.us,entry.block.wr,table.block.wr);
03820                 DEBUG_ShowMsg("%s",out1);
03821                         } else {
03822                                 sprintf(out1,"pagetable %03X not present, flags [puw] %x::%x::%x",
03823                                         (int)(sel >> 10),
03824                                         (int)table.block.p,
03825                                         (int)table.block.us,
03826                                         (int)table.block.wr);
03827                 DEBUG_ShowMsg("%s",out1);
03828                         }
03829                 }
03830         }
03831 
03832     DEBUG_EndPagedContent();
03833 }
03834 
03835 const char *FPU_tag(unsigned int i) {
03836     switch (i) {
03837         case TAG_Valid: return "Valid";
03838         case TAG_Zero:  return "Zero";
03839         case TAG_Weird: return "Weird";
03840         case TAG_Empty: return "Empty";
03841     }
03842 
03843     return "?";
03844 }
03845 
03846 static void LogFPUInfo(void) {
03847     DEBUG_BeginPagedContent();
03848 
03849     DEBUG_ShowMsg("FPU TOP=%u",(unsigned int)fpu.top);
03850 
03851     for (unsigned int i=0;i < 8;i++) {
03852         unsigned int adj = STV(i);
03853 
03854 #if defined(HAS_LONG_DOUBLE)//probably shouldn't allow struct to change size based on this
03855         DEBUG_ShowMsg(" st(%u): %s val=%.9f",i,FPU_tag(fpu.tags[adj]),(double)fpu.regs_80[adj].v);
03856 #else
03857         DEBUG_ShowMsg(" st(%u): %s use80=%u val=%.9f",i,FPU_tag(fpu.tags[adj]),fpu.use80[adj],fpu.regs[adj].d);
03858 #endif
03859     }
03860 
03861     DEBUG_EndPagedContent();
03862 }
03863 
03864 static void LogCPUInfo(void) {
03865         char out1[512];
03866 
03867     DEBUG_BeginPagedContent();
03868 
03869         sprintf(out1,"cr0:%08lX cr2:%08lX cr3:%08lX  cpl=%lx",
03870                 (unsigned long)cpu.cr0,
03871                 (unsigned long)paging.cr2,
03872                 (unsigned long)paging.cr3,
03873                 (unsigned long)cpu.cpl);
03874     DEBUG_ShowMsg("%s",out1);
03875         sprintf(out1,"eflags:%08lX [vm=%x iopl=%x nt=%x]",
03876                 (unsigned long)reg_flags,
03877                 (int)(GETFLAG(VM)>>17),
03878                 (int)(GETFLAG(IOPL)>>12),
03879                 (int)(GETFLAG(NT)>>14));
03880     DEBUG_ShowMsg("%s",out1);
03881         sprintf(out1,"GDT base=%08lX limit=%08lX",
03882                 (unsigned long)cpu.gdt.GetBase(),
03883                 (unsigned long)cpu.gdt.GetLimit());
03884     DEBUG_ShowMsg("%s",out1);
03885         sprintf(out1,"IDT base=%08lX limit=%08lX",
03886                 (unsigned long)cpu.idt.GetBase(),
03887                 (unsigned long)cpu.idt.GetLimit());
03888     DEBUG_ShowMsg("%s",out1);
03889 
03890         Bitu sel=CPU_STR();
03891         Descriptor desc;
03892         if (cpu.gdt.GetDescriptor(sel,desc)) {
03893                 sprintf(out1,"TR selector=%04X, base=%08lX limit=%08lX*%X",(int)sel,(unsigned long)desc.GetBase(),(unsigned long)desc.GetLimit(),desc.saved.seg.g?0x4000:1);
03894         DEBUG_ShowMsg("%s",out1);
03895         }
03896         sel=CPU_SLDT();
03897         if (cpu.gdt.GetDescriptor(sel,desc)) {
03898                 sprintf(out1,"LDT selector=%04X, base=%08lX limit=%08lX*%X",(int)sel,(unsigned long)desc.GetBase(),(unsigned long)desc.GetLimit(),desc.saved.seg.g?0x4000:1);
03899         DEBUG_ShowMsg("%s",out1);
03900         }
03901 
03902     DEBUG_EndPagedContent();
03903 }
03904 
03905 #if C_HEAVY_DEBUG
03906 static void LogInstruction(Bit16u segValue, Bit32u eipValue,  ofstream& out) {
03907         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 };
03908 
03909         PhysPt start = (PhysPt)GetAddress(segValue,eipValue);
03910         char dline[200];Bitu size;
03911         size = DasmI386(dline, start, reg_eip, cpu.code.big);
03912         char* res = empty;
03913         if (showExtend && (cpuLogType > 0) ) {
03914                 res = AnalyzeInstruction(dline,false);
03915                 if (!res || !(*res)) res = empty;
03916                 Bitu reslen = strlen(res);
03917         if (reslen < 22) {
03918             for (Bitu i = 0; i < 22 - reslen; i++) res[reslen + i] = ' ';
03919             res[22] = 0;
03920         }
03921         }
03922         Bitu len = strlen(dline);
03923     if (len < 30) {
03924         for (Bitu i = 0; i < 30 - len; i++) dline[len + i] = ' ';
03925         dline[30] = 0;
03926     }
03927 
03928         // Get register values
03929 
03930         if(cpuLogType == 0) {
03931                 out << setw(4) << SegValue(cs) << ":" << setw(4) << reg_eip << "  " << dline;
03932         } else if (cpuLogType == 1) {
03933                 out << setw(4) << SegValue(cs) << ":" << setw(8) << reg_eip << "  " << dline << "  " << res;
03934         } else if (cpuLogType == 2) {
03935                 char ibytes[200]="";    char tmpc[200];
03936                 for (Bitu i=0; i<size; i++) {
03937                         Bit8u value;
03938                         if (mem_readb_checked((PhysPt)(start+i),&value)) sprintf(tmpc,"%s","?? ");
03939                         else sprintf(tmpc,"%02X ",value);
03940                         strcat(ibytes,tmpc);
03941                 }
03942                 len = strlen(ibytes);
03943         if (len < 21) {
03944             for (Bitu i = 0; i < 21 - len; i++) ibytes[len + i] = ' ';
03945             ibytes[21] = 0;
03946         }
03947                 out << setw(4) << SegValue(cs) << ":" << setw(8) << reg_eip << "  " << dline << "  " << res << "  " << ibytes;
03948         }
03949    
03950         out << " EAX:" << setw(8) << reg_eax << " EBX:" << setw(8) << reg_ebx 
03951             << " ECX:" << setw(8) << reg_ecx << " EDX:" << setw(8) << reg_edx
03952             << " ESI:" << setw(8) << reg_esi << " EDI:" << setw(8) << reg_edi 
03953             << " EBP:" << setw(8) << reg_ebp << " ESP:" << setw(8) << reg_esp 
03954             << " DS:"  << setw(4) << SegValue(ds)<< " ES:"  << setw(4) << SegValue(es);
03955 
03956         if(cpuLogType == 0) {
03957                 out << " SS:"  << setw(4) << SegValue(ss) << " C"  << (get_CF()>0)  << " Z"   << (get_ZF()>0)  
03958                     << " S" << (get_SF()>0) << " O"  << (get_OF()>0) << " I"  << GETFLAGBOOL(IF);
03959         } else {
03960                 out << " FS:"  << setw(4) << SegValue(fs) << " GS:"  << setw(4) << SegValue(gs)
03961                     << " SS:"  << setw(4) << SegValue(ss)
03962                     << " CF:"  << (get_CF()>0)  << " ZF:"   << (get_ZF()>0)  << " SF:"  << (get_SF()>0)
03963                     << " OF:"  << (get_OF()>0)  << " AF:"   << (get_AF()>0)  << " PF:"  << (get_PF()>0)
03964                     << " IF:"  << GETFLAGBOOL(IF);
03965         }
03966         if(cpuLogType == 2) {
03967                 out << " TF:" << GETFLAGBOOL(TF) << " VM:" << GETFLAGBOOL(VM) <<" FLG:" << setw(8) << reg_flags 
03968                     << " CR0:" << setw(8) << cpu.cr0;   
03969         }
03970         out << endl;
03971 }
03972 #endif
03973 
03974 #if 0
03975 // DEBUG.COM stuff
03976 
03977 class DEBUG : public Program {
03978 public:
03979         DEBUG()         { pDebugcom     = this; active = false; };
03980         ~DEBUG()        { pDebugcom     = 0; };
03981 
03982         bool IsActive() { return active; };
03983 
03984         void Run(void)
03985         {
03986                 if(cmd->FindExist("/NOMOUSE",false)) {
03987                         real_writed(0,0x33<<2,0);
03988                         return;
03989                 }
03990            
03991                 char filename[128];
03992                 char args[256+1];
03993         
03994                 cmd->FindCommand(1,temp_line);
03995                 safe_strncpy(filename,temp_line.c_str(),128);
03996                 // Read commandline
03997                 Bit16u i        =2;
03998                 args[0]         = 0;
03999                 for (;cmd->FindCommand(i++,temp_line)==true;) {
04000                         strncat(args,temp_line.c_str(),256);
04001                         strncat(args," ",256);
04002                 }
04003                 // Start new shell and execute prog             
04004                 active = true;
04005                 // Save cpu state....
04006                 Bit16u oldcs    = SegValue(cs);
04007                 Bit32u oldeip   = reg_eip;      
04008                 Bit16u oldss    = SegValue(ss);
04009                 Bit32u oldesp   = reg_esp;
04010 
04011                 // Start shell
04012                 DOS_Shell shell;
04013                 shell.Execute(filename,args);
04014 
04015                 // set old reg values
04016                 SegSet16(ss,oldss);
04017                 reg_esp = oldesp;
04018                 SegSet16(cs,oldcs);
04019                 reg_eip = oldeip;
04020         };
04021 
04022 private:
04023         bool    active;
04024 };
04025 #endif
04026 
04027 #if C_DEBUG
04028 extern bool debugger_break_on_exec;
04029 #endif
04030 
04031 void DEBUG_CheckExecuteBreakpoint(Bit16u seg, Bit32u off)
04032 {
04033 #if C_DEBUG
04034     if (debugger_break_on_exec) {
04035                 CBreakpoint::AddBreakpoint(seg,off,true);               
04036                 CBreakpoint::ActivateBreakpointsExceptAt(SegPhys(cs)+reg_eip);
04037         debugger_break_on_exec = false;
04038     }
04039 #endif
04040 #if 0
04041         if (pDebugcom && pDebugcom->IsActive()) {
04042                 CBreakpoint::AddBreakpoint(seg,off,true);               
04043                 CBreakpoint::ActivateBreakpointsExceptAt(SegPhys(cs)+reg_eip);
04044                 pDebugcom = 0;
04045         };
04046 #endif
04047 }
04048 
04049 Bitu DEBUG_EnableDebugger(void)
04050 {
04051         exitLoop = true;
04052 
04053         if (!debugging)
04054                 DEBUG_Enable_Handler(true);
04055 
04056         CPU_Cycles=CPU_CycleLeft=0;
04057         return 0;
04058 }
04059 
04060 // INIT 
04061 
04062 void DBGBlock::set_data_view(unsigned int view) {
04063     void DrawBars(void);
04064 
04065     if (data_view != view) {
04066         data_view  = view;
04067 
04068         if (win_data) wclear(win_data);
04069 
04070         switch (view) {
04071             case DATV_SEGMENTED:
04072                 win_title[DBGBlock::WINI_DATA] = "Data view (segmented)";
04073                 break;
04074             case DATV_VIRTUAL:
04075                 win_title[DBGBlock::WINI_DATA] = "Data view (virtual)";
04076                 break;
04077             case DATV_PHYSICAL:
04078                 win_title[DBGBlock::WINI_DATA] = "Data view (physical)";
04079                 break;
04080         }
04081 
04082         DrawBars();
04083     }
04084 }
04085 
04086 void DEBUG_SetupConsole(void) {
04087         if (dbg.win_main == NULL) {
04088         LOG(LOG_MISC, LOG_DEBUG)("DEBUG_SetupConsole initializing GUI");
04089 
04090         dbg.set_data_view(DBGBlock::DATV_SEGMENTED);
04091 
04092 #ifdef WIN32
04093                 WIN32_Console();
04094 #else
04095                 tcgetattr(0,&consolesettings);
04096 #endif  
04097                 //      dbg.active_win=3;
04098                 /* Start the Debug Gui */
04099                 DBGUI_StartUp();
04100         }
04101 }
04102 
04103 void DEBUG_ShutDown(Section * /*sec*/) {
04104         CBreakpoint::DeleteAll();
04105         CDebugVar::DeleteAll();
04106         if (dbg.win_main != NULL) {
04107         LOG(LOG_MISC, LOG_DEBUG)("DEBUG_Shutdown freeing ncurses state");
04108                 curs_set(old_cursor_state);
04109 
04110         void DEBUG_GUI_DestroySubWindows(void);
04111         DEBUG_GUI_DestroySubWindows();
04112 
04113 //      if (dbg.win_main) delwin(dbg.win_main);
04114                 dbg.win_main = NULL;
04115 
04116         endwin();
04117 
04118 #ifndef WIN32
04119                 tcsetattr(0,TCSANOW,&consolesettings);
04120 #endif
04121         }
04122 }
04123 
04124 Bitu debugCallback;
04125 
04126 void DEBUG_ReinitCallback(void) {
04127     /* this is REQUIRED after loading a custom BIOS */
04128         debugCallback=CALLBACK_Allocate();
04129         CALLBACK_Setup(debugCallback,DEBUG_EnableDebugger,CB_RETF,"debugger");
04130 }
04131 
04132 void DEBUG_Init() {
04133         DOSBoxMenu::item *item;
04134 
04135     LOG(LOG_MISC, LOG_DEBUG)("Initializing debug system");
04136 
04137         /* Add some keyhandlers */
04138         #if defined(MACOSX)
04139                 // OSX NOTE: ALT-F12 to launch debugger. pause maps to F16 on macOS,
04140                 // which is not easy to input on a modern mac laptop
04141                 MAPPER_AddHandler(DEBUG_Enable_Handler,MK_f12,MMOD2,"debugger","Debugger", &item);
04142         #else
04143                 MAPPER_AddHandler(DEBUG_Enable_Handler,MK_pause,MMOD2,"debugger","Debugger",&item);
04144         #endif
04145         item->set_text("Debugger");
04146         /* Reset code overview and input line */
04147         memset((void*)&codeViewData,0,sizeof(codeViewData));
04148         /* Setup callback */
04149         debugCallback=CALLBACK_Allocate();
04150         CALLBACK_Setup(debugCallback,DEBUG_EnableDebugger,CB_RETF,"debugger");
04151 
04152 #if defined(MACOSX) || defined(LINUX)
04153         /* Mac OS X does not have a console for us to just allocate on a whim like Windows does.
04154            So the debugger interface is useless UNLESS the user has started us from a terminal
04155            (whether over SSH or from the Terminal app).
04156        
04157        Linux/X11 also does not have a console we can allocate on a whim. You either run
04158        this program from XTerm for the debugger, or not. */
04159     bool allow = true;
04160 
04161     if (!isatty(0) || !isatty(1) || !isatty(2))
04162             allow = false;
04163 
04164     mainMenu.get_item("mapper_debugger").enable(allow).refresh_item(mainMenu);
04165 #endif
04166 
04167         /* shutdown function */
04168         AddExitFunction(AddExitFunctionFuncPair(DEBUG_ShutDown));
04169 }
04170 
04171 // DEBUGGING VAR STUFF
04172 
04173 void CDebugVar::InsertVariable(char* name, PhysPt adr)
04174 {
04175         varList.push_back(new CDebugVar(name,adr));
04176 }
04177 
04178 void CDebugVar::DeleteAll(void) 
04179 {
04180         std::vector<CDebugVar*>::iterator i;
04181         for(i=varList.begin(); i != varList.end(); ++i) {
04182                 CDebugVar* bp = static_cast<CDebugVar*>(*i);
04183                 delete bp;
04184         }
04185         (varList.clear)();
04186 }
04187 
04188 CDebugVar* CDebugVar::FindVar(PhysPt pt)
04189 {
04190         if (varList.empty()) return 0;
04191 
04192         std::vector<CDebugVar*>::size_type s = varList.size();
04193         for(std::vector<CDebugVar*>::size_type i = 0; i != s; i++) {
04194                 CDebugVar* bp = static_cast<CDebugVar*>(varList[i]);
04195                 if (bp->GetAdr() == pt) return bp;
04196         }
04197         return 0;
04198 }
04199 
04200 bool CDebugVar::SaveVars(char* name) {
04201         if (varList.size() > 65535) return false;
04202 
04203         FILE* f = fopen(name,"wb+");
04204         if (!f) return false;
04205 
04206         // write number of vars
04207         Bit16u num = (Bit16u)varList.size();
04208         fwrite(&num,1,sizeof(num),f);
04209 
04210         std::vector<CDebugVar*>::iterator i;
04211         CDebugVar* bp;
04212         for(i=varList.begin(); i != varList.end(); ++i) {
04213                 bp = static_cast<CDebugVar*>(*i);
04214                 // name
04215                 fwrite(bp->GetName(),1,16,f);
04216                 // adr
04217                 PhysPt adr = bp->GetAdr();
04218                 fwrite(&adr,1,sizeof(adr),f);
04219         }
04220         fclose(f);
04221         return true;
04222 }
04223 
04224 bool CDebugVar::LoadVars(char* name)
04225 {
04226         FILE* f = fopen(name,"rb");
04227         if (!f) return false;
04228 
04229         // read number of vars
04230         Bit16u num;
04231         if (fread(&num,sizeof(num),1,f) != 1) {
04232                 fclose(f);
04233                 return false;
04234         }
04235 
04236         for (Bit16u i=0; i<num; i++) {
04237                 char name2[16];
04238                 // name
04239                 if (fread(name2,16,1,f) != 1) break;
04240                 // adr
04241                 PhysPt adr;
04242                 if (fread(&adr,sizeof(adr),1,f) != 1) break;
04243                 // insert
04244                 InsertVariable(name2,adr);
04245         }
04246         fclose(f);
04247         return true;
04248 }
04249 
04250 static void SaveMemory(Bit16u seg, Bit32u ofs1, Bit32u num) {
04251         FILE* f = fopen("MEMDUMP.TXT","wt");
04252         if (!f) {
04253                 DEBUG_ShowMsg("DEBUG: Memory dump failed.\n");
04254                 return;
04255         }
04256         
04257         char buffer[128];
04258         char temp[16];
04259 
04260         while (num>16) {
04261                 sprintf(buffer,"%04X:%04X   ",seg,ofs1);
04262                 for (Bit16u x=0; x<16; x++) {
04263                         Bit8u value;
04264                         if (mem_readb_checked((PhysPt)GetAddress(seg,ofs1+x),&value)) sprintf(temp,"%s","?? ");
04265                         else sprintf(temp,"%02X ",value);
04266                         strcat(buffer,temp);
04267                 }
04268                 ofs1+=16;
04269                 num-=16;
04270 
04271                 fprintf(f,"%s\n",buffer);
04272         }
04273         if (num>0) {
04274                 sprintf(buffer,"%04X:%04X   ",seg,ofs1);
04275                 for (Bit16u x=0; x<num; x++) {
04276                         Bit8u value;
04277                         if (mem_readb_checked((PhysPt)GetAddress(seg,ofs1+x),&value)) sprintf(temp,"%s","?? ");
04278                         else sprintf(temp,"%02X ",value);
04279                         strcat(buffer,temp);
04280                 }
04281                 fprintf(f,"%s\n",buffer);
04282         }
04283         fclose(f);
04284         DEBUG_ShowMsg("DEBUG: Memory dump success.\n");
04285 }
04286 
04287 static void SaveMemoryBin(Bit16u seg, Bit32u ofs1, Bit32u num) {
04288         FILE* f = fopen("MEMDUMP.BIN","wb");
04289         if (!f) {
04290                 DEBUG_ShowMsg("DEBUG: Memory binary dump failed.\n");
04291                 return;
04292         }
04293 
04294         for (Bit32u x = 0; x < num;x++) {
04295                 Bit8u val;
04296                 if (mem_readb_checked((PhysPt)GetAddress(seg,ofs1+x),&val)) val=0;
04297                 fwrite(&val,1,1,f);
04298         }
04299 
04300         fclose(f);
04301         DEBUG_ShowMsg("DEBUG: Memory dump binary success.\n");
04302 }
04303 
04304 static void OutputVecTable(char* filename) {
04305         FILE* f = fopen(filename, "wt");
04306         if (!f)
04307         {
04308                 DEBUG_ShowMsg("DEBUG: Output of interrupt vector table failed.\n");
04309                 return;
04310         }
04311 
04312         for (unsigned int i=0; i<256; i++)
04313                 fprintf(f,"INT %02X:  %04X:%04X\n", i, mem_readw(i * 4u + 2u), mem_readw(i * 4u));
04314 
04315         fclose(f);
04316         DEBUG_ShowMsg("DEBUG: Interrupt vector table written to %s.\n", filename);
04317 }
04318 
04319 #define DEBUG_VAR_BUF_LEN 16
04320 static void DrawVariables(void) {
04321         if (CDebugVar::varList.empty()) return;
04322 
04323         char buffer[DEBUG_VAR_BUF_LEN];
04324         std::vector<CDebugVar*>::size_type s = CDebugVar::varList.size();
04325         bool windowchanges = false;
04326 
04327         for(std::vector<CDebugVar*>::size_type i = 0; i != s; i++) {
04328 
04329                 if (i == 4*3) {
04330                         /* too many variables */
04331                         break;
04332                 }
04333 
04334                 CDebugVar *dv = static_cast<CDebugVar*>(CDebugVar::varList[i]);
04335                 Bit16u value;
04336                 bool varchanges = false;
04337                 bool has_no_value = mem_readw_checked(dv->GetAdr(),&value);
04338                 if (has_no_value) {
04339                         snprintf(buffer,DEBUG_VAR_BUF_LEN, "%s", "??????");
04340                         dv->SetValue(false,0);
04341                         varchanges = true;
04342                 } else {
04343                         if ( dv->HasValue() && dv->GetValue() == value) {
04344                                 //It already had a value and it didn't change (most likely case)
04345                         } else {
04346                                 dv->SetValue(true,value);
04347                                 snprintf(buffer,DEBUG_VAR_BUF_LEN, "0x%04x", value);
04348                                 varchanges = true;
04349                         }
04350                 }
04351 
04352                 if (varchanges) {
04353                         unsigned int y = (unsigned int)(i / 3u);
04354                         unsigned int x = (i % 3u) * 26u;
04355                         mvwprintw(dbg.win_var, (int)y,  (int)x, dv->GetName());
04356                         mvwprintw(dbg.win_var, (int)y, ((int)x + DEBUG_VAR_BUF_LEN + 1) , buffer);
04357                         windowchanges = true; //Something has changed in this window
04358                 }
04359         }
04360 
04361         if (windowchanges) wrefresh(dbg.win_var);
04362 }
04363 #undef DEBUG_VAR_BUF_LEN
04364 // HEAVY DEBUGGING STUFF
04365 
04366 #if C_HEAVY_DEBUG
04367 
04368 const Bit32u LOGCPUMAX = 20000;
04369 
04370 static Bit32u logCount = 0;
04371 
04372 struct TLogInst {
04373         Bit16u s_cs;
04374         Bit32u eip;
04375         Bit32u eax;
04376         Bit32u ebx;
04377         Bit32u ecx;
04378         Bit32u edx;
04379         Bit32u esi;
04380         Bit32u edi;
04381         Bit32u ebp;
04382         Bit32u esp;
04383         Bit16u s_ds;
04384         Bit16u s_es;
04385         Bit16u s_fs;
04386         Bit16u s_gs;
04387         Bit16u s_ss;
04388         bool c;
04389         bool z;
04390         bool s;
04391         bool o;
04392         bool a;
04393         bool p;
04394         bool i;
04395         char dline[31];
04396         char res[23];
04397 };
04398 
04399 TLogInst logInst[LOGCPUMAX];
04400 
04401 void DEBUG_HeavyLogInstruction(void) {
04402 
04403         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 };
04404 
04405         PhysPt start = (PhysPt)GetAddress(SegValue(cs),reg_eip);
04406         char dline[200];
04407         DasmI386(dline, start, reg_eip, cpu.code.big);
04408         char* res = empty;
04409         if (showExtend) {
04410                 res = AnalyzeInstruction(dline,false);
04411                 if (!res || !(*res)) res = empty;
04412                 Bitu reslen = strlen(res);
04413         if (reslen < 22) {
04414             for (Bitu i = 0; i < 22 - reslen; i++) res[reslen + i] = ' ';
04415             res[22] = 0;
04416         }
04417         }
04418 
04419         Bitu len = strlen(dline);
04420         if (len < 30) for (Bitu i=0; i < 30-len; i++) dline[len+i] = ' ';
04421         dline[30] = 0;
04422 
04423         TLogInst & inst = logInst[logCount];
04424         strcpy(inst.dline,dline);
04425         inst.s_cs = SegValue(cs);
04426         inst.eip  = reg_eip;
04427         strcpy(inst.res,res);
04428         inst.eax  = reg_eax;
04429         inst.ebx  = reg_ebx;
04430         inst.ecx  = reg_ecx;
04431         inst.edx  = reg_edx;
04432         inst.esi  = reg_esi;
04433         inst.edi  = reg_edi;
04434         inst.ebp  = reg_ebp;
04435         inst.esp  = reg_esp;
04436         inst.s_ds = SegValue(ds);
04437         inst.s_es = SegValue(es);
04438         inst.s_fs = SegValue(fs);
04439         inst.s_gs = SegValue(gs);
04440         inst.s_ss = SegValue(ss);
04441         inst.c    = get_CF()>0;
04442         inst.z    = get_ZF()>0;
04443         inst.s    = get_SF()>0;
04444         inst.o    = get_OF()>0;
04445         inst.a    = get_AF()>0;
04446         inst.p    = get_PF()>0;
04447         inst.i    = GETFLAGBOOL(IF);
04448 
04449         if (++logCount >= LOGCPUMAX) logCount = 0;
04450 }
04451 
04452 void DEBUG_HeavyWriteLogInstruction(void) {
04453         if (!logHeavy) return;
04454         logHeavy = false;
04455         
04456         DEBUG_ShowMsg("DEBUG: Creating cpu log LOGCPU_INT_CD.TXT\n");
04457 
04458         ofstream out("LOGCPU_INT_CD.TXT");
04459         if (!out.is_open()) {
04460                 DEBUG_ShowMsg("DEBUG: Failed.\n");      
04461                 return;
04462         }
04463         out << hex << noshowbase << setfill('0') << uppercase;
04464         Bit32u startLog = logCount;
04465         do {
04466                 // Write Instructions
04467                 TLogInst & inst = logInst[startLog];
04468                 out << setw(4) << inst.s_cs << ":" << setw(8) << inst.eip << "  " 
04469                     << inst.dline << "  " << inst.res << " EAX:" << setw(8)<< inst.eax
04470                     << " EBX:" << setw(8) << inst.ebx << " ECX:" << setw(8) << inst.ecx
04471                     << " EDX:" << setw(8) << inst.edx << " ESI:" << setw(8) << inst.esi
04472                     << " EDI:" << setw(8) << inst.edi << " EBP:" << setw(8) << inst.ebp
04473                     << " ESP:" << setw(8) << inst.esp << " DS:"  << setw(4) << inst.s_ds
04474                     << " ES:"  << setw(4) << inst.s_es<< " FS:"  << setw(4) << inst.s_fs
04475                     << " GS:"  << setw(4) << inst.s_gs<< " SS:"  << setw(4) << inst.s_ss
04476                     << " CF:"  << inst.c  << " ZF:"   << inst.z  << " SF:"  << inst.s
04477                     << " OF:"  << inst.o  << " AF:"   << inst.a  << " PF:"  << inst.p
04478                     << " IF:"  << inst.i  << endl;
04479 
04480 /*              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",
04481                         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,
04482                         logInst[startLog].s_ds,logInst[startLog].s_es,logInst[startLog].s_fs,logInst[startLog].s_gs,logInst[startLog].s_ss,
04483                         logInst[startLog].c,logInst[startLog].z,logInst[startLog].s,logInst[startLog].o,logInst[startLog].a,logInst[startLog].p,logInst[startLog].i);*/
04484                 if (++startLog >= LOGCPUMAX) startLog = 0;
04485         } while (startLog != logCount);
04486         
04487         out.close();
04488         DEBUG_ShowMsg("DEBUG: Done.\n");        
04489 }
04490 
04491 bool DEBUG_HeavyIsBreakpoint(void) {
04492         if (cpuLog) {
04493                 if (cpuLogCounter>0) {
04494                         LogInstruction(SegValue(cs),reg_eip,cpuLogFile);
04495                         cpuLogCounter--;
04496                 }
04497                 if (cpuLogCounter<=0) {
04498                         cpuLogFile.flush();
04499                         cpuLogFile.close();
04500                         DEBUG_ShowMsg("DEBUG: cpu log LOGCPU.TXT created\n");
04501                         cpuLog = false;
04502                         DEBUG_EnableDebugger();
04503                         return true;
04504                 }
04505         }
04506         // LogInstruction
04507         if (logHeavy) DEBUG_HeavyLogInstruction();
04508         if (zeroProtect) {
04509                 static Bitu zero_count = 0;
04510                 Bit32u value=0;
04511                 if (!mem_readd_checked(SegPhys(cs)+reg_eip,&value)) {
04512                         if (value == 0) zero_count++;
04513                         else zero_count = 0;
04514                 }
04515                 if (GCC_UNLIKELY(zero_count == 10)) E_Exit("running zeroed code");
04516         }
04517 
04518         if (skipFirstInstruction) {
04519                 skipFirstInstruction = false;
04520                 return false;
04521         }
04522         if (CBreakpoint::CheckBreakpoint(SegValue(cs),reg_eip)) {
04523                 return true;    
04524         }
04525         return false;
04526 }
04527 
04528 /* this is for the BIOS, to stop the log upon BIOS POST. */
04529 void DEBUG_StopLog(void) {
04530         if (cpuLog) {
04531         cpuLogCounter = 0;
04532         cpuLogFile.close();
04533         DEBUG_ShowMsg("DEBUG: cpu log LOGCPU.TXT stopped\n");
04534         cpuLog = false;
04535     }
04536 }
04537 
04538 #endif // HEAVY DEBUG
04539 
04540 
04541 #endif // DEBUG
04542 
04543