void EventSuite::RunDebuggee( RefPtr<IProcess>& process ) { Exec exec; TEST_ASSERT_RETURN( SUCCEEDED( exec.Init( mCallback ) ) ); LaunchInfo info = { 0 }; wchar_t cmdLine[ MAX_PATH ] = L""; IProcess* proc = NULL; const wchar_t* Debuggee = EventsDebuggee; swprintf_s( cmdLine, L"\"%s\"", Debuggee ); info.CommandLine = cmdLine; info.Exe = Debuggee; TEST_ASSERT_RETURN( SUCCEEDED( exec.Launch( &info, proc ) ) ); uint32_t pid = proc->GetId(); mCallback->SetTrackEvents( true ); process = proc; proc->Release(); for ( int i = 0; !mCallback->GetProcessExited(); i++ ) { HRESULT hr = exec.WaitForEvent( DefaultTimeoutMillis ); // this should happen after process exit if ( hr == E_TIMEOUT ) break; TEST_ASSERT_RETURN( SUCCEEDED( hr ) ); TEST_ASSERT_RETURN( SUCCEEDED( exec.DispatchEvent() ) ); if ( process->IsStopped() ) TEST_ASSERT_RETURN( SUCCEEDED( exec.Continue( process, true ) ) ); } TEST_ASSERT( mCallback->GetLoadCompleted() ); TEST_ASSERT( mCallback->GetProcessExited() ); //AssertProcessFinished( pid ); }
void StepOneThreadSuite::RunDebuggee( Step* steps, int stepsCount ) { Exec exec; TEST_ASSERT_RETURN( SUCCEEDED( exec.Init( mCallback ) ) ); LaunchInfo info = { 0 }; wchar_t cmdLine[ MAX_PATH ] = L""; IProcess* proc = NULL; const wchar_t* Debuggee = StepOneThreadDebuggee; Symbol funcs[] = { { NULL, 0 }, { L"Scenario1Func0", 0 }, { L"Scenario1Func1", 0 }, { L"Scenario1Func2", 0 }, { L"Scenario1Func3", 0 }, }; TEST_ASSERT_RETURN( SUCCEEDED( FindSymbols( Debuggee, funcs, _countof( funcs ) ) ) ); swprintf_s( cmdLine, L"\"%s\" 1", Debuggee ); info.CommandLine = cmdLine; info.Exe = Debuggee; TEST_ASSERT_RETURN( SUCCEEDED( exec.Launch( &info, proc ) ) ); uint32_t pid = proc->GetId(); int nextStep = 0; char msg[1024] = ""; RefPtr<IProcess> process; process = proc; proc->Release(); mCallback->SetTrackLastEvent( true ); for ( int i = 0; !mCallback->GetProcessExited(); i++ ) { bool continued = false; HRESULT hr = exec.WaitForEvent( DefaultTimeoutMillis ); // this should happen after process exit if ( hr == E_TIMEOUT ) break; TEST_ASSERT_RETURN( SUCCEEDED( hr ) ); TEST_ASSERT_RETURN( SUCCEEDED( hr = exec.DispatchEvent() ) ); if ( !process->IsStopped() ) continue; if ( (mCallback->GetLastEvent()->Code != ExecEvent_ModuleLoad) && (mCallback->GetLastEvent()->Code != ExecEvent_ModuleUnload) && (mCallback->GetLastEvent()->Code != ExecEvent_ThreadStart) && (mCallback->GetLastEvent()->Code != ExecEvent_ThreadExit) && (mCallback->GetLastEvent()->Code != ExecEvent_LoadComplete) ) { Step* curStep = &steps[nextStep]; nextStep++; RefPtr<Thread> thread; CONTEXT_X86 context = { 0 }; if ( mCallback->GetLastThreadId() != 0 ) { TEST_ASSERT_RETURN( process->FindThread( mCallback->GetLastThreadId(), thread.Ref() ) ); TEST_ASSERT_RETURN( exec.GetThreadContext( process, thread->GetId(), CONTEXT_X86_FULL, 0, &context, sizeof context ) == S_OK ); } uintptr_t baseAddr = 0; RefPtr<IModule> procMod = mCallback->GetProcessModule(); if ( procMod.Get() != NULL ) baseAddr = (uintptr_t) procMod->GetImageBase(); // TODO: test threadId if ( mCallback->GetLastEvent()->Code != curStep->Event.Code ) { sprintf_s( msg, "Expected event '%s', got '%s'.", GetEventName( curStep->Event.Code ), GetEventName( mCallback->GetLastEvent()->Code ) ); TEST_FAIL_MSG( msg ); break; } else if ( (curStep->Event.Code == ExecEvent_Exception) && (curStep->Event.ExceptionCode != ((ExceptionEventNode*) mCallback->GetLastEvent().get())->Exception.ExceptionCode) ) { sprintf_s( msg, "Expected exception %08x, got %08x.", curStep->Event.ExceptionCode, ((ExceptionEventNode*) mCallback->GetLastEvent().get())->Exception.ExceptionCode ); TEST_FAIL_MSG( msg ); break; } else if ( (curStep->Event.Code == ExecEvent_Exception) || (curStep->Event.Code == ExecEvent_StepComplete) || (curStep->Event.Code == ExecEvent_Breakpoint) ) { uintptr_t funcRva = funcs[curStep->Event.FunctionIndex].RelativeAddress; uintptr_t addr = (funcRva + curStep->Event.AddressOffset + baseAddr); if ( context.Eip != addr ) { sprintf_s( msg, "Expected instruction pointer at %08x, got %08x.", addr, context.Eip ); TEST_FAIL_MSG( msg ); break; } } mCallback->SetCanStepInFunctionReturnValue( curStep->Action.CanStepInFunction ); if ( curStep->Action.BPAddressOffset != 0 ) { uintptr_t funcRva = funcs[curStep->Action.FunctionIndex].RelativeAddress; uintptr_t addr = (funcRva + curStep->Action.BPAddressOffset + baseAddr); TEST_ASSERT_RETURN( SUCCEEDED( exec.SetBreakpoint( process.Get(), addr ) ) ); } if ( curStep->Action.Action == Action_StepInstruction ) { TEST_ASSERT_RETURN( SUCCEEDED( exec.StepInstruction( process.Get(), curStep->Action.StepIn, true ) ) ); continued = true; } else if ( curStep->Action.Action == Action_StepRange ) { AddressRange range = { context.Eip, context.Eip }; TEST_ASSERT_RETURN( SUCCEEDED( exec.StepRange( process.Get(), curStep->Action.StepIn, range, true ) ) ); continued = true; } } if ( !continued ) TEST_ASSERT_RETURN( SUCCEEDED( exec.Continue( process, true ) ) ); } TEST_ASSERT( mCallback->GetLoadCompleted() ); TEST_ASSERT( mCallback->GetProcessExited() ); }
int _tmain( int argc, _TCHAR* argv[] ) { BOOL bRet = FALSE; STARTUPINFO startupInfo = { sizeof startupInfo }; PROCESS_INFORMATION procInfo = { 0 }; DEBUG_EVENT event = { 0 }; _EventCallback callback; Exec exec; HRESULT hr = S_OK; LaunchInfo info = { 0 }; InitDebug(); //char* s1 = new ( _NORMAL_BLOCK, __FILE__, __LINE__ ) char[100]; //strcpy( s1, "hello, yo!" ); //char* s2 = (char*) malloc( 300 ); //strcpy( s2, "say what?" ); callback.SetExec( &exec ); hr = exec.Init( &callback ); if ( FAILED( hr ) ) goto Error; #if 0 bRet = CreateProcess( L"F:\\Users\\Magus\\Documents\\Visual Studio 2008\\Projects\\test1\\Debug\\test1.exe", //bRet = CreateProcess( L"F:\\Users\\Magus\\Documents\\Visual Studio 2008\\Projects\\test1\\x64\\Debug\\test1.exe", NULL, NULL, NULL, FALSE, DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &startupInfo, &procInfo ); if ( !bRet ) goto Error; #else //#define TEST_APP64 #ifndef TEST_APP64 info.CommandLine = L"\"F:\\Users\\Magus\\Documents\\Visual Studio 2008\\Projects\\Debugger1\\Debug\\test1.exe\""; info.Exe = L"F:\\Users\\Magus\\Documents\\Visual Studio 2008\\Projects\\Debugger1\\Debug\\test1.exe"; #else info.CommandLine =L"\"F:\\Users\\Magus\\Documents\\Visual Studio 2008\\Projects\\Debugger1\\x64\\Debug\\test1.exe\""; info.Exe = L"\"F:\\Users\\Magus\\Documents\\Visual Studio 2008\\Projects\\Debugger1\\x64\\Debug\\test1.exe\""; #endif IProcess* proc = NULL; //hr = exec.Attach( 5336, proc ); hr = exec.Launch( &info, proc ); if ( FAILED( hr ) ) goto Error; #endif #if 0 bRet = WaitForDebugEvent( &event, INFINITE ); if ( !bRet ) goto Error; #else int stepCount = 0; for ( int i = 0; /* doesn't end */ ; i++ ) { hr = exec.WaitForEvent( 1000 ); if ( FAILED( hr ) ) goto Error; hr = exec.DispatchEvent(); if ( FAILED( hr ) ) goto Error; #if 1 if ( proc->IsStopped() ) { if ( callback.GetHitBp() ) { stepCount++; //11728 IModule* mod = NULL; UINT_PTR baseAddr = 0; callback.GetModule( mod ); baseAddr = (UINT_PTR) mod->GetImageBase(); mod->Release(); //hr = exec.StepOut( proc, (void*) (baseAddr + 0x00011728) ); //hr = exec.StepInstruction( proc, true ); if ( stepCount > 1 ) hr = exec.StepInstruction( proc, true, true ); else { //113A5 AddressRange range = { baseAddr + 0x0001137A, baseAddr + 0x000113A5 }; hr = exec.StepRange( proc, false, range, true ); } if ( FAILED( hr ) ) goto Error; } else { hr = exec.Continue( proc, true ); if ( FAILED( hr ) ) goto Error; } } #endif #if 1 if ( i == 0 ) { IModule* mod = NULL; UINT_PTR baseAddr = 0; callback.GetModule( mod ); baseAddr = (UINT_PTR) mod->GetImageBase(); // 0x003C137A, 0x003C1395 // 1137A, 11395 //exec.SetBreakpoint( proc, baseAddr + 0x0001138C, 255 ); exec.SetBreakpoint( proc, baseAddr + 0x0001137A ); //exec.SetBreakpoint( proc, baseAddr + 0x00011395, 129 ); mod->Release(); } #endif } #endif Error: //exec.Detach( proc ); // when the debugger goes away, so does the debuggee automatically //if ( procInfo.hThread != NULL ) //{ // CloseHandle( procInfo.hThread ); //} //if ( procInfo.hProcess != NULL ) //{ // TerminateProcess( procInfo.hProcess, MAXINT ); // CloseHandle( procInfo.hProcess ); //} if ( proc != NULL ) proc->Release(); return 0; }
void EventSuite::TestExceptionNotHandledAllChances() { enum State { State_Init, State_FirstNotHandled, State_SecondNotHandled, State_Done }; Exec exec; State state = State_Init; TEST_ASSERT_RETURN( SUCCEEDED( exec.Init( mCallback ) ) ); LaunchInfo info = { 0 }; wchar_t cmdLine[ MAX_PATH ] = L""; IProcess* proc = NULL; const wchar_t* Debuggee = EventsDebuggee; swprintf_s( cmdLine, L"\"%s\" exception 1", Debuggee ); info.CommandLine = cmdLine; info.Exe = Debuggee; TEST_ASSERT_RETURN( SUCCEEDED( exec.Launch( &info, proc ) ) ); uint32_t pid = proc->GetId(); RefPtr<IProcess> process( proc ); proc->Release(); mCallback->SetTrackLastEvent( true ); for ( int i = 0; !mCallback->GetProcessExited(); i++ ) { bool handled = true; uint32_t timeoutMillis = DefaultTimeoutMillis; // it can take more than half a second to get the ProcessExit event // after an unhandled exception if ( state == State_SecondNotHandled ) timeoutMillis = 5 * 1000; HRESULT hr = exec.WaitForEvent( timeoutMillis ); // this should happen after process exit if ( hr == E_TIMEOUT ) { // Timing out is still an error, but it's only expected sometimes // after SecondNotHandled, if the timeout to wait for the process // to end is still not enough. See where the timeout is set above. TEST_ASSERT( state == State_SecondNotHandled ); break; } TEST_ASSERT_RETURN( SUCCEEDED( hr ) ); TEST_ASSERT_RETURN( SUCCEEDED( exec.DispatchEvent() ) ); if ( state == State_SecondNotHandled ) { TEST_ASSERT( mCallback->GetProcessExited() ); state = State_Done; } if ( process->IsStopped() ) { if ( (mCallback->GetLastEvent().get() != NULL) && (mCallback->GetLastEvent()->Code == ExecEvent_Exception) ) { ExceptionEventNode* node = (ExceptionEventNode*) mCallback->GetLastEvent().get(); if ( node->Exception.ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO ) { if ( state == State_Init ) { TEST_ASSERT( node->FirstChance ); state = State_FirstNotHandled; handled = false; } else if ( state == State_FirstNotHandled ) { TEST_ASSERT( !node->FirstChance ); state = State_SecondNotHandled; handled = false; } else { TEST_FAIL( "Too many Integer divides by zero." ); exec.Terminate( process.Get() ); } } else { TEST_FAIL( "Unexpected exception." ); exec.Terminate( process.Get() ); } } TEST_ASSERT_RETURN( SUCCEEDED( exec.Continue( process, handled ) ) ); } } TEST_ASSERT( mCallback->GetLoadCompleted() ); TEST_ASSERT( mCallback->GetProcessExited() ); TEST_ASSERT( state == State_Done ); }
void EventSuite::TestExceptionNotHandledFirstChanceCaught() { enum State { State_Init, State_FirstNotHandled, State_Done }; Exec exec; State state = State_Init; TEST_ASSERT_RETURN( SUCCEEDED( exec.Init( mCallback ) ) ); LaunchInfo info = { 0 }; wchar_t cmdLine[ MAX_PATH ] = L""; IProcess* proc = NULL; const wchar_t* Debuggee = EventsDebuggee; swprintf_s( cmdLine, L"\"%s\" exception 2", Debuggee ); info.CommandLine = cmdLine; info.Exe = Debuggee; TEST_ASSERT_RETURN( SUCCEEDED( exec.Launch( &info, proc ) ) ); uint32_t pid = proc->GetId(); RefPtr<IProcess> process( proc ); proc->Release(); mCallback->SetTrackLastEvent( true ); for ( int i = 0; !mCallback->GetProcessExited(); i++ ) { bool handled = true; HRESULT hr = exec.WaitForEvent( DefaultTimeoutMillis ); // this should happen after process exit if ( hr == E_TIMEOUT ) break; TEST_ASSERT_RETURN( SUCCEEDED( hr ) ); TEST_ASSERT_RETURN( SUCCEEDED( exec.DispatchEvent() ) ); if ( process->IsStopped() ) { if ( (mCallback->GetLastEvent().get() != NULL) && (mCallback->GetLastEvent()->Code == ExecEvent_Exception) ) { ExceptionEventNode* node = (ExceptionEventNode*) mCallback->GetLastEvent().get(); TEST_ASSERT( node->FirstChance ); if ( node->Exception.ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO ) { if ( state == State_Init ) { state = State_FirstNotHandled; handled = false; } else { TEST_FAIL( "Too many Integer divides by zero." ); exec.Terminate( process.Get() ); } } else { TEST_FAIL( "Unexpected exception." ); exec.Terminate( process.Get() ); } } else if ( (mCallback->GetLastEvent().get() != NULL) && (mCallback->GetLastEvent()->Code == ExecEvent_Breakpoint) && (state == State_FirstNotHandled) ) { state = State_Done; CONTEXT_X86 context = { 0 }; RefPtr<Thread> thread; TEST_ASSERT_RETURN( process->FindThread( mCallback->GetLastThreadId(), thread.Ref() ) ); context.ContextFlags = CONTEXT_X86_FULL; TEST_ASSERT_RETURN( GetThreadContextX86( thread->GetHandle(), &context ) ); TEST_ASSERT( context.Eax == 1877514773 ); } TEST_ASSERT_RETURN( SUCCEEDED( exec.Continue( process, handled ) ) ); } } TEST_ASSERT( mCallback->GetLoadCompleted() ); TEST_ASSERT( mCallback->GetProcessExited() ); TEST_ASSERT( state == State_Done ); }