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