📄 accrun.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: Handles interfaces to Windows NT debugger functions
* to handle all debug events (single step, breakpoints etc).
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <direct.h>
#include "madregs.h"
#include "stdnt.h"
typedef enum {
T_OFF,
T_ON_CURR,
T_ON_NEXT
} set_t;
/*
* setATBit - control if we are tracing
*/
static void setATBit( thread_info *ti, set_t set )
{
CONTEXT con;
con.ContextFlags = CONTEXT_CONTROL;
MyGetThreadContext( ti, &con );
#if defined( MD_x86 )
if( set != T_OFF ) {
con.EFlags |= TRACE_BIT;
} else {
con.EFlags &= ~TRACE_BIT;
}
con.ContextFlags = CONTEXT_CONTROL;
MySetThreadContext( ti, &con );
#elif defined( MD_axp )
{
DWORD bytes;
brkpnt_type brk = BRK_POINT;
if( set != T_OFF ) {
ti->brk_addr = AdjustIP( &con, 0 );
if( set == T_ON_NEXT )
ti->brk_addr += 4;
ReadProcessMemory( ProcessInfo.process_handle,
( LPVOID )ti->brk_addr, ( LPVOID )&ti->brk_opcode,
sizeof( ti->brk_opcode ), ( LPDWORD )&bytes );
if( ti->brk_opcode != brk ) {
WriteProcessMemory( ProcessInfo.process_handle,
( LPVOID )ti->brk_addr, ( LPVOID )&brk, sizeof( brk ),
( LPDWORD )&bytes );
} else {
ti->brk_addr = 0;
}
} else if( ti->brk_addr != 0 ) {
WriteProcessMemory( ProcessInfo.process_handle,
( LPVOID )ti->brk_addr, ( LPVOID )&ti->brk_opcode,
sizeof( ti->brk_opcode ), ( LPDWORD )&bytes );
ti->brk_addr = 0;
}
}
#elif defined( MD_ppc )
if( set != T_OFF ) {
con.Msr |= TRACE_BIT;
} else {
con.Msr &= ~TRACE_BIT;
}
con.ContextFlags = CONTEXT_CONTROL;
MySetThreadContext( ti, &con );
#else
#error setATBit not configured
#endif
}
/*
* setTBitsetTBitInAllThreads - turn the t-bit on or off in all threads.
*/
static void setTBitInAllThreads( set_t set )
{
thread_info *ti;
ti = ProcessInfo.thread_list;
while( ti != NULL ) {
if( ti->alive ) {
SuspendThread( ti->thread_handle );
}
ti = ti->next;
}
ti = ProcessInfo.thread_list;
while( ti != NULL ) {
if( ti->alive ) {
setATBit( ti, set );
}
ti = ti->next;
}
ti = ProcessInfo.thread_list;
while( ti != NULL ) {
if( ti->alive ) {
ResumeThread( ti->thread_handle );
}
ti = ti->next;
}
}
void InterruptProgram( void )
{
setTBitInAllThreads( T_ON_CURR );
// a trick to make app execute long enough to hit a breakpoint
PostMessage( HWND_TOPMOST, WM_NULL, 0, 0 );
PendingProgramInterrupt = TRUE;
}
bool Terminate( void )
{
HANDLE hp;
hp = OpenProcess( PROCESS_ALL_ACCESS, FALSE, DebugeePid );
if( hp != NULL ) {
TerminateProcess( hp, 0 );
CloseHandle( hp );
return( TRUE );
} else {
return( FALSE );
}
}
/*
* consoleHandler - handle console ctrl c
*/
static BOOL WINAPI consoleHandler( DWORD type )
{
if( type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT ) {
/*
* Since NT has no way do an async stop of a process, this is the next
* best thing. By turning on the the T-bit in all threads, we force
* the process to stop the next time any one of its threads stop.
* If all threads are blocked waiting for an event, then the process
* will not stop until the event is satisfied. Most often, the
* main thread of the process will be blocked awaiting input, and
* just running the mouse over the window will cause the app to
* run and then trace-trap
*/
InterruptProgram();
return( TRUE );
} else {
return( FALSE );
}
}
/*
* setTBit - control if we are tracing
*/
static void setTBit( set_t set )
{
thread_info *ti;
ti = FindThread( DebugeeTid );
setATBit( ti, set );
}
/*
* handleInt3 - process an encountered break point
*/
#if defined( MD_x86 )
static DWORD BreakFixed;
#endif
static int handleInt3( DWORD state )
{
#if defined( MD_x86 )
thread_info *ti;
CONTEXT con;
(void)state; // Unused
ti = FindThread( DebugeeTid );
if( ti == NULL ) {
HANDLE th;
if( pOpenThread == NULL ) {
return( 0 );
}
th = pOpenThread( DebugeeTid );
AddThread( DebugeeTid, th, NULL );
ti = FindThread( DebugeeTid );
ti->is_foreign = TRUE;
}
if( ti->is_foreign ) {
HANDLE proc;
DWORD written;
BYTE ch;
MyGetThreadContext( ti, &con );
con.Eip--;
if( !FindBreak( ( WORD ) con.SegCs, ( DWORD ) con.Eip, &ch ) ) {
MySetThreadContext( ti, &con );
return( COND_BREAK );
}
BreakFixed = con.Eip;
proc = OpenProcess( PROCESS_ALL_ACCESS, FALSE, DebugeePid );
WriteProcessMemory( proc, ( LPVOID ) con.Eip, &ch, 1, &written );
con.EFlags |= TRACE_BIT;
MySetThreadContext( ti, &con );
CloseHandle( proc );
return( 0 );
} else {
MyGetThreadContext( ti, &con );
con.Eip--;
MySetThreadContext( ti, &con );
}
#elif defined( MD_axp )
thread_info *ti;
CONTEXT con;
ti = FindThread( DebugeeTid );
MyGetThreadContext( ti, &con );
if( ti->brk_addr != 0 && AdjustIP( &con, 0 ) == ti->brk_addr ) {
return( handleInt1( state ) );
}
#elif defined( MD_ppc )
/* nothing special to do */
#else
#error handleInt3 not configured
#endif
return( COND_BREAK );
}
/*
* handleInt1 - process a trace or watch point
*/
static int handleInt1( DWORD state )
{
if( PendingProgramInterrupt ) {
/*
* this was really an async stop request, so turn the t-bit
* off in all the threads
*/
setTBitInAllThreads( T_OFF );
PendingProgramInterrupt = FALSE;
return( COND_USER );
}
#if defined( MD_x86 )
if( state & STATE_WATCH_386 ) {
if( GetDR6() & 0xf ) {
return( COND_WATCH );
}
}
#endif
if( state & STATE_WATCH ) {
if( CheckWatchPoints() ) {
return( COND_WATCH );
}
} else {
#if defined( MD_x86 )
HANDLE proc;
DWORD written;
brkpnt_type ch;
thread_info *ti;
if( BreakFixed == 0 ) {
return( COND_TRACE );
}
ti = FindThread( DebugeeTid );
if( ti && !ti->is_foreign ) {
return( COND_TRACE );
}
ch = BRK_POINT;
proc = OpenProcess( PROCESS_ALL_ACCESS, FALSE, DebugeePid );
WriteProcessMemory( proc, ( LPVOID ) BreakFixed, &ch, 1, &written );
CloseHandle( proc );
BreakFixed = 0;
return( 0 );
#else
return( COND_TRACE );
#endif
}
return( 0 );
}
#ifdef WOW
/*
* getImageNote - get current image note structure (WOW)
*/
static void getImageNote( IMAGE_NOTE *pin )
{
ReadMem( FlatDS, ( DWORD ) DW3( DebugEvent.u.Exception.ExceptionRecord ),
pin, sizeof( IMAGE_NOTE ) );
}
#endif
/*
* DebugExecute - execute program under debug control
*/
int DebugExecute( DWORD state, int *tsc, bool stop_on_module_load )
{
DWORD continue_how;
DWORD code;
DWORD len;
msg_list **owner;
msg_list *new;
int cond;
char *p;
char *q;
bool rc;
#ifdef WOW
thread_info *ti;
DWORD subcode;
IMAGE_NOTE imgnote;
#endif
int returnCode;
if( tsc != NULL ) {
*tsc = FALSE;
}
/*
* "Slaying" gets set by AccKillProg. Because a dead WOW app
* will set the DebugeeEnded flag, and we still need to kill WOW,
* we ignore the DebugeeEnded setting if we are doing a kill
*/
if( !Slaying ) {
if( DebugeeEnded || DebugeePid == NULL ) {
returnCode = COND_TERMINATE;
goto done;
}
}
continue_how = DBG_CONTINUE;
for( ;; ) {
PendingProgramInterrupt = FALSE;
if( ( state & STATE_WATCH ) && !( state & STATE_WATCH_386 ) ) {
setTBit( T_OFF ); /* turn off previous T-bit */
#if defined( MD_axp )
/*
We're doing watch points on an Alpha. If we run into a
control transfer instruction, return a spurious watchpoint
indication. The debugger will simulate the instruction for
us. This keeps the trap file from having to figure out
if a conditional branch is going to happen or not.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -