📄 os2v2acc.c
字号:
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: OS/2 2.x specific debug core.
*
****************************************************************************/
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define INCL_DOSEXCEPTIONS
#define INCL_DOSPROCESS
#define INCL_DOSMISC
#define INCL_DOSERRORS
#define INCL_DOSSESMGR
#define INCL_DOSMODULEMGR
#include <os2.h>
#include "dosdebug.h"
#include "trpimp.h"
#include "os2trap.h"
#include "os2v2acc.h"
#include "bsexcpt.h"
#include "wdpmhelp.h"
#include "softmode.h"
#include "madregs.h"
#define ERROR_DEFINE_CONSTS
#include "os2err.h"
#include "exedos.h"
#include "exeos2.h"
#include "exeflat.h"
#include "x86cpu.h"
uDB_t Buff;
static BOOL stopOnSecond;
static BOOL isAttached;
USHORT TaskFS;
static byte saved_splice_bp;
static BOOL splice_bp_set;
static ULONG splice_bp_lin_addr;
extern VOID InitDebugThread( VOID );
#ifdef DEBUG_OUT
static void Out( char *str )
{
USHORT written;
DosWrite( 1, str, strlen( str ), &written );
}
#define NSIZE 20
static void OutNum( ULONG i )
{
char numbuff[NSIZE];
char *ptr;
ptr = numbuff+NSIZE;
*--ptr = '\0';
if( i == 0 ) {
*--ptr = '0';
}
while( i != 0 ) {
*--ptr = "0123456789abcdef"[i & 0x0f];
i >>= 4;
}
Out( ptr );
}
#endif
#define EXE_MZ 0x5a4d
#define EXE_NE 0x454e
#define EXE_LE 0x454c
#define EXE_LX 0x584c
#define OBJECT_IS_CODE 0x0004L
#define OBJECT_IS_BIG 0x2000L
#define EXE_IS_FULLSCREEN 0x0100
#define EXE_IS_PMC 0x0200
#define EXE_IS_PM 0x0300
/* Kernel memory not accessible via DosDebug */
#define KERNEL_MEM_OFFSET 0xE0000000
static ULONG ExceptLinear;
static UCHAR TypeProcess;
static BOOL Is32Bit;
static watch WatchPoints[MAX_WP];
static short WatchCount = 0;
static short DebugRegsNeeded = 0;
static unsigned_16 lastCS;
static unsigned_16 lastSS;
static unsigned_32 lastEIP;
static unsigned_32 lastESP;
bool ExpectingAFault;
char OS2ExtList[] = {".exe\0"};
static bool Is32BitSeg( unsigned seg )
{
if( IsFlatSeg( seg ) )
return( TRUE );
if( IsUnknownGDTSeg( seg ) )
return( TRUE );
return( FALSE );
}
/*
* RecordModHandle - save module handle for later reference
*/
static void RecordModHandle( ULONG value )
{
if( ModHandles == NULL ) {
DosAllocMem( &ModHandles, sizeof(ULONG) * 512, PAG_COMMIT | PAG_READ | PAG_WRITE );
}
ModHandles[NumModHandles] = value;
++NumModHandles;
}
/*
* SeekRead - seek to a file position, and read the data
*/
static BOOL SeekRead( HFILE handle, ULONG newpos, void *ptr, ULONG size )
{
ULONG read;
ULONG pos;
if( DosSetFilePtr(handle, newpos, 0, &pos) != 0 ) {
return( FALSE );
}
if( DosRead(handle, ptr, size, &read) != 0 ) {
return( FALSE );
}
if( read != size ) {
return( FALSE );
}
return( TRUE );
} /* SeekRead */
/*
* FindNewHeader - get a pointer to the new exe header
*/
static BOOL FindNewHeader( char *name, HFILE *hdl,
ULONG *new_head, USHORT *id )
{
long open_rc;
HFILE h;
BOOL rc;
USHORT data; /* MUST be 16-bit! */
open_rc = OpenFile( name, 0, OPEN_PRIVATE );
if( open_rc < 0 ) {
return( FALSE );
}
h = open_rc;
rc = FALSE;
while( 1 ) {
if( !SeekRead( h, 0x00, &data, sizeof( data ) ) ) {
break;
}
if( data != EXE_MZ ) break; /* MZ */
if( !SeekRead( h, 0x18, &data, sizeof( data ) ) ) {
break;
}
if( data < 0x40 ) /* offset of relocation header */
break;
if( !SeekRead( h, 0x3c, new_head, sizeof( ULONG ) ) ) {
break;
}
if( !SeekRead( h, *new_head, id, sizeof( USHORT ) ) ) {
break;
}
rc = TRUE;
break;
}
if( !rc ) {
DosClose( h );
}
*hdl = h;
return( rc );
} /* FindNewHeader */
#define MAX_OBJECTS 128
static ULONG LastMTE;
static unsigned NumObjects;
static object_record ObjInfo[MAX_OBJECTS];
static void GetObjectInfo( ULONG mte )
{
HFILE hdl;
ULONG new_head;
USHORT type;
unsigned_32 objoff;
unsigned_32 numobjs;
char buff[CCHMAXPATH];
if( mte == LastMTE ) {
return;
}
memset( ObjInfo, 0, sizeof( ObjInfo ) );
DosQueryModuleName( mte, sizeof( buff ), buff );
NumObjects = 0;
if( !FindNewHeader( buff, &hdl, &new_head, &type ) ) {
return;
}
if( type != EXE_LE && type != EXE_LX ) {
DosClose( hdl );
return;
}
SeekRead( hdl, new_head + 0x40, &objoff, sizeof( objoff ) );
SeekRead( hdl, new_head + 0x44, &numobjs, sizeof( numobjs ) );
if( numobjs <= MAX_OBJECTS ) {
SeekRead( hdl, new_head + objoff, ObjInfo, numobjs * sizeof( ObjInfo[0] ) );
NumObjects = numobjs;
}
LastMTE = mte;
DosClose( hdl );
}
bool DebugExecute( uDB_t *buff, ULONG cmd, bool stop_on_module_load )
{
EXCEPTIONREPORTRECORD ex;
ULONG value;
ULONG stopvalue;
ULONG notify = 0;
BOOL got_second_notification;
ULONG fcp;
CONTEXTRECORD fcr;
buff->Cmd = cmd;
value = buff->Value;
if( cmd == DBG_C_Go ) {
value = 0;
}
stopvalue = XCPT_CONTINUE_EXECUTION;
got_second_notification = FALSE;
if( cmd == DBG_C_Stop ) {
stopvalue = XCPT_CONTINUE_STOP;
}
for( ;; ) {
buff->Value = value;
buff->Cmd = cmd;
CallDosDebug( buff );
value = stopvalue;
cmd = DBG_C_Continue;
/*
* handle the preemptive notifications
*/
switch( buff->Cmd ) {
case DBG_N_ModuleLoad:
RecordModHandle( buff->Value );
if( stop_on_module_load )
return( TRUE );
break;
case DBG_N_ModuleFree:
break;
case DBG_N_NewProc:
break;
case DBG_N_ProcTerm:
value = XCPT_CONTINUE_STOP; /* halt us */
notify = DBG_N_ProcTerm;
break;
case DBG_N_ThreadCreate:
break;
case DBG_N_ThreadTerm:
break;
case DBG_N_AliasFree:
break;
case DBG_N_Exception:
ExceptLinear = buff->Addr;
if( buff->Value == DBG_X_STACK_INVALID ) {
value = XCPT_CONTINUE_SEARCH;
break;
}
fcp = buff->Len;
if( buff->Value == DBG_X_PRE_FIRST_CHANCE ) {
ExceptNum = buff->Buffer;
if( ExceptNum == XCPT_BREAKPOINT ) {
notify = DBG_N_Breakpoint;
value = XCPT_CONTINUE_STOP;
break;
} else if( ExceptNum == XCPT_SINGLE_STEP ) {
notify = DBG_N_SStep;
value = XCPT_CONTINUE_STOP;
break;
}
}
//
// NOTE: Going to second chance causes OS/2 to report the
// exception in the debugee. However, if you report
// the fault at the first chance notification, the
// debugee's own fault handlers will not get invoked!
//
if( buff->Value == DBG_X_FIRST_CHANCE && !ExpectingAFault ) {
if( stopOnSecond && !got_second_notification ) {
value = XCPT_CONTINUE_SEARCH;
break;
}
}
notify = DBG_N_Exception;
value = XCPT_CONTINUE_STOP;
/*
* Buffer contains the ptr to the exception block
*/
buff->Cmd = DBG_C_ReadMemBuf;
buff->Addr = buff->Buffer;
buff->Buffer = (ULONG)&ex;
buff->Len = sizeof( ex );
CallDosDebug( buff );
ExceptNum = ex.ExceptionNum;
if( ExceptNum == XCPT_PROCESS_TERMINATE ||
ExceptNum == XCPT_ASYNC_PROCESS_TERMINATE ||
ExceptNum == XCPT_GUARD_PAGE_VIOLATION ||
( ExceptNum & XCPT_CUSTOMER_CODE ) ) {
value = XCPT_CONTINUE_SEARCH;
break;
}
/*
* get the context record
*/
buff->Cmd = DBG_C_ReadMemBuf;
buff->Addr = fcp;
buff->Buffer = (ULONG)&fcr;
buff->Len = sizeof( fcr );
CallDosDebug( buff );
buff->EAX = fcr.ctx_RegEax;
buff->EBX = fcr.ctx_RegEbx;
buff->ECX = fcr.ctx_RegEcx;
buff->EDX = fcr.ctx_RegEdx;
buff->ESI = fcr.ctx_RegEsi;
buff->EDI = fcr.ctx_RegEdi;
buff->ESP = fcr.ctx_RegEsp;
buff->EBP = fcr.ctx_RegEbp;
buff->DS = fcr.ctx_SegDs;
buff->CS = fcr.ctx_SegCs;
buff->ES = fcr.ctx_SegEs;
buff->FS = fcr.ctx_SegFs;
buff->GS = fcr.ctx_SegGs;
buff->SS = fcr.ctx_SegSs;
buff->EIP = fcr.ctx_RegEip;
buff->EFlags = fcr.ctx_EFlags;
WriteRegs(buff);
if( ExpectingAFault || got_second_notification ) {
break;
}
if( stopOnSecond ) {
value = XCPT_CONTINUE_EXECUTION;
got_second_notification = TRUE;
}
break;
default:
if( notify != 0 ) {
buff->Cmd = notify;
// Check if we hit our splice DLL breakpoint
if( (notify == DBG_N_Breakpoint) && splice_bp_set && (splice_bp_lin_addr == ExceptLinear) ) {
uDB_t save;
// Remove breakpoint
WriteLinear( &saved_splice_bp, splice_bp_lin_addr, sizeof( byte ) );
splice_bp_set = FALSE;
splice_bp_lin_addr = 0;
// Attempt to load helper DLL
save.Pid = Pid;
save.Tid = 1;
ReadRegs( &save );
ExpectingAFault = TRUE;
// NB - the following will recursively call DebugExecute!
if( !CausePgmToLoadHelperDLL( ExceptLinear ) ) {
CanExecTask = FALSE;
} else {
CanExecTask = TRUE;
}
WriteRegs( &save );
break;
}
}
return( FALSE );
}
}
// return( FALSE );
}
void WriteRegs( uDB_t *buff )
{
buff->Cmd = DBG_C_WriteReg;
CallDosDebug( buff );
}
void ReadRegs( uDB_t *buff )
{
buff->Cmd = DBG_C_ReadReg;
CallDosDebug( buff );
}
void ReadXMMRegs( struct x86_xmm *xmm_regs )
{
TaskReadXMMRegs( xmm_regs );
}
void WriteXMMRegs( struct x86_xmm *xmm_regs )
{
TaskWriteXMMRegs( xmm_regs );
}
void ReadLinear( char *data, ULONG lin, USHORT size )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -