program StepOverPrg; {$asmMode intel} uses {$IFDEF UNIX} cthreads, {$ENDIF} sysutils, Classes; type { TTestThread1 } TTestThread1 = class(TThread) procedure Execute; override; end; var x, BreakDummy: Integer; T1, T1Interfere: Integer; T1Stop: Boolean; label testasmlbl1, testasmlbl2; Procedure MyNorm; begin x := 1; end; Procedure StepOverEnd(a: integer); var b: integer; begin b := a; // end returns to the same line if a < 1 then StepOverEnd(a+1); end; // TEST_BREAKPOINT=StepOverEnd Procedure MyNested(ALvl: Integer = 0); var a: integer; begin if ALvl > 3 then exit; a := x; if ALvl = 0 then x := 1; // TEST_BREAKPOINT=BrkNested x := 3; MyNested(ALvl + 1); x := 4; if ALvl = 0 then // only reach "AfterNested" in most outer recurse x := 2; // TEST_BREAKPOINT=AfterNested x := 1; end; Procedure MySleep; begin Sleep(50); end; Procedure MyBrkDis; begin x := 1; // TEST_BREAKPOINT=BrkDisabled end; Procedure MyBrkHitCnt; begin x := 1; // TEST_BREAKPOINT=BrkHitCnt end; (* Try to step over a line, while another thread is also going through the line *) Procedure MyInterfereByThread(a: Boolean = false); Procedure MyInterfereSleep; begin if a then Sleep(10); // threads do not stop / while the test waits here, other threads should hit the calling line end; begin if a then x := 1; // TEST_BREAKPOINT=BrkInterfereByThread if a then InterLockedExchange(T1Interfere, 0); while (InterLockedExchangeAdd(T1Interfere,0)=0) do begin MyInterfereSleep; if not a then break; end; x := 1; // TEST_BREAKPOINT=AfterInterfereByThread InterLockedIncrement(T1Interfere); // Other threads will increment end; { TTestThread1 } procedure TTestThread1.Execute; begin InterLockedIncrement(T1); while not (Terminated or T1Stop) do MyInterfereByThread; InterLockedDecrement(T1); end; begin x := 1; x := x + 1; // TEST_BREAKPOINT=BrkStart x := x + 1; x := x + 2; x := x + 3; // TEST_BREAKPOINT=AfterStep MyNorm(); // TEST_BREAKPOINT=AfterStepLongLine x := 1; MyNorm(); x := x + 1; MyNorm(); x := x + 1; MyNorm(); x := x + 1; // TEST_BREAKPOINT=AfterStepProc MySleep(); // TEST_BREAKPOINT=AfterStepProcLong sleep(50); // TEST_BREAKPOINT=AfterStepSleepProc MyBrkDis; // TEST_BREAKPOINT=AfterStepSleep MyBrkHitCnt; // TEST_BREAKPOINT=AfterStepBrkDis MyBrkDis; // TEST_BREAKPOINT=AfterStepBrkHitCnt x := 1; // TEST_BREAKPOINT=AfterStepBrkDisAgain x := 1; MyNested; // TEST_BREAKPOINT=CallNested T1 := 0; T1Stop := False; TTestThread1.Create(False); while not (InterLockedExchangeAdd(T1,0)=1) do x:=1; // TEST_BREAKPOINT=BrkThreadCreateInStep x := 1; // TEST_BREAKPOINT=AfterThreadCreateInStep (* Prepare for threads to interfare with the hidden breakpoint *) // create a few threads to interfer TTestThread1.Create(False); TTestThread1.Create(False); TTestThread1.Create(False); TTestThread1.Create(False); TTestThread1.Create(False); TTestThread1.Create(False); while not (InterLockedExchangeAdd(T1,0)>=5) do sleep(10); // at least 5 running MyInterfereByThread(True); T1Stop := True; while not (InterLockedExchangeAdd(T1,0)<=1) do x:=1; // TEST_BREAKPOINT=BrkThreadExitInStep x := 1; // TEST_BREAKPOINT=AfterThreadExitInStep //sleep(500); BreakDummy := 1; StepOverEnd(0); // TEST_BREAKPOINT=CallStepOverEnd BreakDummy := 1; // TEST_BREAKPOINT=AfterCallStepOverEnd BreakDummy := 1; end.