}
if (ModuleData.Count == 0)
- return RetCode.Fail;
+ return RetCode.OK;
int structModuleMethodsDataSize = Marshal.SizeOf<file_methods_data_t>();
module_methods_data_t managedData;
PVOID pSymbolReaderHandle = nullptr;
IfFailRet(Interop::LoadDeltaPdb(deltaPDB, &pSymbolReaderHandle, methodTokens));
+ // Note, even if methodTokens is empty, pSymbolReaderHandle must be added into vector (we use indexes that correspond to il/metadata apply number + will care about release it in proper way).
mdInfo.m_symbolReaderHandles.emplace_back(pSymbolReaderHandle);
+ if (methodTokens.empty())
+ return S_OK;
+
if (needJMC)
DisableJMCByAttributes(pModule, methodTokens);
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+ <ItemGroup>\r
+ <ProjectReference Include="..\NetcoreDbgTest\NetcoreDbgTest.csproj" />\r
+ <ProjectReference Include="..\TestAppHotReloadAsync\TestAppHotReloadAsync.csproj" />\r
+ </ItemGroup>\r
+\r
+ <PropertyGroup>\r
+ <OutputType>Exe</OutputType>\r
+ <TargetFramework>netcoreapp3.1</TargetFramework>\r
+ </PropertyGroup>\r
+\r
+</Project>\r
--- /dev/null
+using System;\r
+using System.IO;\r
+using System.Runtime.InteropServices;\r
+\r
+using NetcoreDbgTest;\r
+using NetcoreDbgTest.MI;\r
+using NetcoreDbgTest.Script;\r
+using NetcoreDbgTest.GetDeltaApi;\r
+\r
+namespace NetcoreDbgTest.Script\r
+{\r
+ class Context\r
+ {\r
+ public void Prepare(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-gdb-set enable-hot-reload 1").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-file-exec-and-symbols " + ControlInfo.CorerunPath).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-exec-arguments " + ControlInfo.TargetAssemblyPath).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-run").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ bool IsStoppedEvent(MIOutOfBandRecord record)\r
+ {\r
+ if (record.Type != MIOutOfBandRecordType.Async) {\r
+ return false;\r
+ }\r
+\r
+ var asyncRecord = (MIAsyncRecord)record;\r
+\r
+ if (asyncRecord.Class != MIAsyncRecordClass.Exec ||\r
+ asyncRecord.Output.Class != MIAsyncOutputClass.Stopped) {\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+ }\r
+\r
+ public void WasEntryPointHit(string realNamespace, string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "entry-point-hit") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var func = (MIConst)frame["func"];\r
+ if (func.CString == realNamespace + ".Program.<Main>d__0.MoveNext()") {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasBreakpointHit(string caller_trace, string bpFileName, int bpNumLine)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "breakpoint-hit") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var fileName = (MIConst)frame["file"];\r
+ var line = ((MIConst)frame["line"]).Int;\r
+\r
+ if (fileName.CString == bpFileName &&\r
+ line == bpNumLine) {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter),\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasStep(string caller_trace, int bpNumLine)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+ if (reason.CString != "end-stepping-range") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var line = ((MIConst)frame["line"]).Int;\r
+ if (bpNumLine == line) {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasStepInOutdatedCode(string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+ if (reason.CString != "end-stepping-range") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var func = ((MIConst)frame["func"]).CString;\r
+\r
+ if (func.StartsWith("[Outdated Code]")) {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasExit(string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "exited") {\r
+ return false;\r
+ }\r
+\r
+ var exitCode = (MIConst)output["exit-code"];\r
+\r
+ if (exitCode.CString == "0") {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void DebuggerExit(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Exit,\r
+ MIDebugger.Request("-gdb-exit").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void EnableBreakpoint(string caller_trace, string bpFileName, int bpNumLine)\r
+ {\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-break-insert -f " + bpFileName + ":" + bpNumLine).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void Continue(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-continue").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void StepOver(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-next").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void StepIn(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-step").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void StepOut(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-finish").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckHostRuntimeVersion(string caller_trace)\r
+ {\r
+ Assert.True(GetDeltaApi.CheckRuntimeVersion(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckHostOS(string caller_trace)\r
+ {\r
+ Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckTargetRuntimeVersion(string caller_trace)\r
+ {\r
+ var res = MIDebugger.Request("-var-create - * System.Environment.Version.Major>=6");\r
+ Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+ Assert.Equal("true", ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+ }\r
+\r
+ public void StartGenDeltaSession(string caller_trace)\r
+ {\r
+ string projectPath = Path.GetDirectoryName(ControlInfo.SourceFilesPath);\r
+ Assert.True(GetDeltaApi.StartGenDeltaSession(projectPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void EndGenDeltaSession(string caller_trace)\r
+ {\r
+ Assert.True(GetDeltaApi.EndGenDeltaSession(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void SdbPush(string caller_trace, string hostFullPath, string targetPath)\r
+ {\r
+ System.Diagnostics.Process process = new System.Diagnostics.Process();\r
+ process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;\r
+ process.StartInfo.RedirectStandardInput = true;\r
+ process.StartInfo.RedirectStandardOutput = true;\r
+ process.StartInfo.CreateNoWindow = true;\r
+ process.StartInfo.UseShellExecute = false;\r
+ \r
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+ {\r
+ process.StartInfo.FileName = "bash";\r
+ process.StartInfo.Arguments = "-c \"sdb push " + hostFullPath + " " + targetPath + "\"";\r
+ }\r
+ else\r
+ throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ process.Start();\r
+ process.WaitForExit();\r
+ Assert.Equal(0, process.ExitCode, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WriteDeltas(string caller_trace, string fileName)\r
+ {\r
+ string hostPath;\r
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+ hostPath = Path.Combine(@"/tmp", fileName);\r
+ else\r
+ throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ string targetPath = @"/tmp";\r
+ Assert.True(GetDeltaApi.WriteDeltas(hostPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".metadata", targetPath);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".il", targetPath);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".pdb", targetPath);\r
+ }\r
+\r
+ public void GetDelta(string caller_trace, string source, string sourceFileName)\r
+ {\r
+ Assert.True(GetDeltaApi.GetDeltas(source, sourceFileName, "", false), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void ApplyDeltas(string caller_trace, string fileName)\r
+ {\r
+ string targetPath = Path.Combine(@"/tmp", fileName);\r
+ string targetAssemblyName = Path.GetFileName(ControlInfo.TargetAssemblyPath);\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-apply-deltas " + targetAssemblyName + " " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public Context(ControlInfo controlInfo, NetcoreDbgTestCore.DebuggerClient debuggerClient)\r
+ {\r
+ ControlInfo = controlInfo;\r
+ MIDebugger = new MIDebugger(debuggerClient);\r
+ GetDeltaApi = new GetDeltaApi.GetDeltaApi();\r
+ }\r
+\r
+ ControlInfo ControlInfo;\r
+ MIDebugger MIDebugger;\r
+ GetDeltaApi.GetDeltaApi GetDeltaApi;\r
+ }\r
+}\r
+\r
+namespace MITestHotReloadAsyncStepping\r
+{\r
+ class Program\r
+ {\r
+ static void Main(string[] args)\r
+ {\r
+ Label.Checkpoint("init", "test_stepin_new_code", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.CheckHostRuntimeVersion(@"__FILE__:__LINE__");\r
+ Context.CheckHostOS(@"__FILE__:__LINE__");\r
+ Context.Prepare(@"__FILE__:__LINE__");\r
+ Context.WasEntryPointHit("TestAppHotReloadAsync", @"__FILE__:__LINE__");\r
+ // Note, target Hot Reload check must be after debuggee process start and stop at entry breakpoint.\r
+ Context.CheckTargetRuntimeVersion(@"__FILE__:__LINE__");\r
+ Context.StartGenDeltaSession(@"__FILE__:__LINE__");\r
+\r
+ Context.GetDelta(@"__FILE__:__LINE__",\r
+ @"using System;\r
+ using System.Threading.Tasks;\r
+ namespace TestAppHotReloadAsync\r
+ {\r
+ class Program\r
+ {\r
+ static async Task Main(string[] args)\r
+ {\r
+ Console.WriteLine(""Hello World!"");\r
+ await HotReloadTestAsync();\r
+ }\r
+ static async Task HotReloadTestAsync()\r
+ {\r
+ Console.WriteLine(""Updated string."");\r
+ await HotReloadStepTest1Async(); // line 15\r
+ }\r
+ static async Task HotReloadStepTest1Async()\r
+ { // line 18\r
+ Console.WriteLine(""Added line 1."");\r
+ await Task.Delay(100);\r
+ Console.WriteLine(""Added line 2."");\r
+ await Task.Delay(100);\r
+ Console.WriteLine(""Added line 3."");\r
+ }\r
+ }\r
+ }", @"Program.cs");\r
+ Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+ Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 15);\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ // Test step-in for new code.\r
+ Label.Checkpoint("test_stepin_new_code", "test_stepover_new_code", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 15);\r
+ Context.StepIn(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 18);\r
+ });\r
+\r
+ // Test step-over for new code.\r
+ Label.Checkpoint("test_stepover_new_code", "test_stepout_new_code", (Object context) => {\r
+ Context Context = (Context)context;\r
+ \r
+ Context.StepOver(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 19);\r
+ Context.StepOver(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 20);\r
+ Context.StepOver(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 21);\r
+ });\r
+\r
+ // Test step-out for new code.\r
+ Label.Checkpoint("test_stepout_new_code", "finish", (Object context) => {\r
+ Context Context = (Context)context;\r
+\r
+ Context.StepOut(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 16);\r
+\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ Label.Checkpoint("finish", "", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.EndGenDeltaSession(@"__FILE__:__LINE__");\r
+ Context.WasExit(@"__FILE__:__LINE__");\r
+ Context.DebuggerExit(@"__FILE__:__LINE__");\r
+ });\r
+ }\r
+ }\r
+}\r
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+ <ItemGroup>\r
+ <ProjectReference Include="..\NetcoreDbgTest\NetcoreDbgTest.csproj" />\r
+ <ProjectReference Include="..\TestAppHotReload\TestAppHotReload.csproj" />\r
+ </ItemGroup>\r
+\r
+ <PropertyGroup>\r
+ <OutputType>Exe</OutputType>\r
+ <TargetFramework>netcoreapp3.1</TargetFramework>\r
+ </PropertyGroup>\r
+\r
+</Project>\r
--- /dev/null
+using System;\r
+using System.IO;\r
+using System.Runtime.InteropServices;\r
+\r
+using NetcoreDbgTest;\r
+using NetcoreDbgTest.MI;\r
+using NetcoreDbgTest.Script;\r
+using NetcoreDbgTest.GetDeltaApi;\r
+\r
+namespace NetcoreDbgTest.Script\r
+{\r
+ class Context\r
+ {\r
+ public void Prepare(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-gdb-set enable-hot-reload 1").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-file-exec-and-symbols " + ControlInfo.CorerunPath).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-exec-arguments " + ControlInfo.TargetAssemblyPath).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-run").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ bool IsStoppedEvent(MIOutOfBandRecord record)\r
+ {\r
+ if (record.Type != MIOutOfBandRecordType.Async) {\r
+ return false;\r
+ }\r
+\r
+ var asyncRecord = (MIAsyncRecord)record;\r
+\r
+ if (asyncRecord.Class != MIAsyncRecordClass.Exec ||\r
+ asyncRecord.Output.Class != MIAsyncOutputClass.Stopped) {\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+ }\r
+\r
+ public void WasEntryPointHit(string realNamespace, string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "entry-point-hit") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var func = (MIConst)frame["func"];\r
+ if (func.CString == realNamespace + ".Program.Main()") {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasBreakpointHit(string caller_trace, string bpFileName, int bpNumLine)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "breakpoint-hit") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var fileName = (MIConst)frame["file"];\r
+ var line = ((MIConst)frame["line"]).Int;\r
+\r
+ if (fileName.CString == bpFileName &&\r
+ line == bpNumLine) {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter),\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasBreakHit(string caller_trace, string bpFileName, int bpNumLine)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+ var signal_name = (MIConst)output["signal-name"];\r
+\r
+ if (reason.CString != "signal-received" &&\r
+ signal_name.CString != "SIGINT") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var fileName = (MIConst)frame["file"];\r
+ var line = ((MIConst)frame["line"]).Int;\r
+\r
+ if (fileName.CString == bpFileName &&\r
+ line == bpNumLine) {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasBreakHitInOutdatedCode(string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+ var signal_name = (MIConst)output["signal-name"];\r
+\r
+ if (reason.CString != "signal-received" &&\r
+ signal_name.CString != "SIGINT") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var func = ((MIConst)frame["func"]).CString;\r
+\r
+ if (func.StartsWith("[Outdated Code]")) {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasStep(string caller_trace, int bpNumLine)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+ if (reason.CString != "end-stepping-range") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var line = ((MIConst)frame["line"]).Int;\r
+ if (bpNumLine == line) {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasExit(string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "exited") {\r
+ return false;\r
+ }\r
+\r
+ var exitCode = (MIConst)output["exit-code"];\r
+\r
+ if (exitCode.CString == "0") {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void DebuggerExit(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Exit,\r
+ MIDebugger.Request("-gdb-exit").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void EnableBreakpoint(string caller_trace, string bpFileName, int bpNumLine)\r
+ {\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-break-insert -f " + bpFileName + ":" + bpNumLine).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void Continue(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-continue").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void StepOver(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-next").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckHostRuntimeVersion(string caller_trace)\r
+ {\r
+ Assert.True(GetDeltaApi.CheckRuntimeVersion(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckHostOS(string caller_trace)\r
+ {\r
+ Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckTargetRuntimeVersion(string caller_trace)\r
+ {\r
+ var res = MIDebugger.Request("-var-create - * System.Environment.Version.Major>=6");\r
+ Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+ Assert.Equal("true", ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+ }\r
+\r
+ public void StartGenDeltaSession(string caller_trace)\r
+ {\r
+ string projectPath = Path.GetDirectoryName(ControlInfo.SourceFilesPath);\r
+ Assert.True(GetDeltaApi.StartGenDeltaSession(projectPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void EndGenDeltaSession(string caller_trace)\r
+ {\r
+ Assert.True(GetDeltaApi.EndGenDeltaSession(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void SdbPush(string caller_trace, string hostFullPath, string targetPath)\r
+ {\r
+ System.Diagnostics.Process process = new System.Diagnostics.Process();\r
+ process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;\r
+ process.StartInfo.RedirectStandardInput = true;\r
+ process.StartInfo.RedirectStandardOutput = true;\r
+ process.StartInfo.CreateNoWindow = true;\r
+ process.StartInfo.UseShellExecute = false;\r
+ \r
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+ {\r
+ process.StartInfo.FileName = "bash";\r
+ process.StartInfo.Arguments = "-c \"sdb push " + hostFullPath + " " + targetPath + "\"";\r
+ }\r
+ else\r
+ throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ process.Start();\r
+ process.WaitForExit();\r
+ Assert.Equal(0, process.ExitCode, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WriteDeltas(string caller_trace, string fileName)\r
+ {\r
+ string hostPath;\r
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+ hostPath = Path.Combine(@"/tmp", fileName);\r
+ else\r
+ throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ string targetPath = @"/tmp";\r
+ Assert.True(GetDeltaApi.WriteDeltas(hostPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".metadata", targetPath);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".il", targetPath);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".pdb", targetPath);\r
+ }\r
+\r
+ public void GetDelta(string caller_trace, string source, string sourceFileName)\r
+ {\r
+ Assert.True(GetDeltaApi.GetDeltas(source, sourceFileName, "", false), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void ApplyDeltas(string caller_trace, string fileName)\r
+ {\r
+ string targetPath = Path.Combine(@"/tmp", fileName);\r
+ string targetAssemblyName = Path.GetFileName(ControlInfo.TargetAssemblyPath);\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-apply-deltas " + targetAssemblyName + " " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public Context(ControlInfo controlInfo, NetcoreDbgTestCore.DebuggerClient debuggerClient)\r
+ {\r
+ ControlInfo = controlInfo;\r
+ MIDebugger = new MIDebugger(debuggerClient);\r
+ GetDeltaApi = new GetDeltaApi.GetDeltaApi();\r
+ }\r
+\r
+ ControlInfo ControlInfo;\r
+ MIDebugger MIDebugger;\r
+ GetDeltaApi.GetDeltaApi GetDeltaApi;\r
+ }\r
+}\r
+\r
+namespace MITestHotReloadBreak\r
+{\r
+ class Program\r
+ {\r
+ static void Main(string[] args)\r
+ {\r
+ Label.Checkpoint("init", "break_test1", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.CheckHostRuntimeVersion(@"__FILE__:__LINE__");\r
+ Context.CheckHostOS(@"__FILE__:__LINE__");\r
+ Context.Prepare(@"__FILE__:__LINE__");\r
+ Context.WasEntryPointHit("TestAppHotReload", @"__FILE__:__LINE__");\r
+ // Note, target Hot Reload check must be after debuggee process start and stop at entry breakpoint.\r
+ Context.CheckTargetRuntimeVersion(@"__FILE__:__LINE__");\r
+ Context.StartGenDeltaSession(@"__FILE__:__LINE__");\r
+\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 28);\r
+\r
+ Context.GetDelta(@"__FILE__:__LINE__",\r
+ @"using System;\r
+ using System.Diagnostics;\r
+ namespace TestAppHotReload\r
+ {\r
+ class Program\r
+ {\r
+ static void Main(string[] args)\r
+ {\r
+ Console.WriteLine(""Hello World!"");\r
+ HotReloadTest();\r
+ }\r
+ static void HotReloadTest()\r
+ {\r
+ Console.WriteLine(""Updated string."");\r
+ HotReloadBreakTest1();\r
+ HotReloadBreakTest2();\r
+ HotReloadBreakTest3();\r
+ Debugger.Break();\r
+ }\r
+ static void HotReloadBreakTest1()\r
+ {\r
+ Console.WriteLine(""Added break."");\r
+ Debugger.Break(); // line 23\r
+ }\r
+ static void HotReloadBreakTest2()\r
+ {\r
+ Console.WriteLine(""Added break + breakpoint (added before apply deltas)."");\r
+ Debugger.Break(); // line 28\r
+ Console.WriteLine(""Added break + breakpoint (added after apply deltas)."");\r
+ Debugger.Break(); // line 30\r
+ }\r
+ static void HotReloadBreakTest3()\r
+ {\r
+ Console.WriteLine(""Added break + step.""); // line 34\r
+ Debugger.Break(); // line 35\r
+ } // line 36\r
+ }\r
+ }", @"Program.cs");\r
+ Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+ Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 30);\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 34);\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ // Test, that debugger stop at Debugger.Break() in managed code.\r
+ Label.Checkpoint("break_test1", "break_test2", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.WasBreakHit(@"__FILE__:__LINE__", @"Program.cs", 23);\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ // Test, that debugger ignore Debugger.Break() on continue in case it already stop at breakpoint at this code line.\r
+ Label.Checkpoint("break_test2", "break_test3", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 28);\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 30);\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ // Test, that debugger ignore Debugger.Break() on step in case it already stop at step at this code.\r
+ Label.Checkpoint("break_test3", "break_test4", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 34);\r
+ Context.StepOver(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 35);\r
+ Context.StepOver(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 36);\r
+ });\r
+\r
+ // Stop on Break in outdated code.\r
+ Label.Checkpoint("break_test4", "finish", (Object context) => {\r
+ Context Context = (Context)context;\r
+\r
+ Context.GetDelta(@"__FILE__:__LINE__",\r
+ @"using System;\r
+ using System.Diagnostics;\r
+ namespace TestAppHotReload\r
+ {\r
+ class Program\r
+ {\r
+ static void Main(string[] args)\r
+ {\r
+ Console.WriteLine(""Hello World!"");\r
+ HotReloadTest();\r
+ }\r
+ static void HotReloadTest()\r
+ {\r
+ }\r
+ static void HotReloadBreakTest1()\r
+ {\r
+ }\r
+ static void HotReloadBreakTest2()\r
+ {\r
+ }\r
+ static void HotReloadBreakTest3()\r
+ {\r
+ }\r
+ }\r
+ }", @"Program.cs");\r
+ Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+ Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+\r
+ Context.WasBreakHitInOutdatedCode(@"__FILE__:__LINE__");\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ Label.Checkpoint("finish", "", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.EndGenDeltaSession(@"__FILE__:__LINE__");\r
+ Context.WasExit(@"__FILE__:__LINE__");\r
+ Context.DebuggerExit(@"__FILE__:__LINE__");\r
+ });\r
+ }\r
+ }\r
+}\r
@"__FILE__:__LINE__"+"\n"+caller_trace);\r
}\r
\r
- public string GetAndCheckValue(string caller_trace, string ExpectedResult, string ExpectedType, string Expression)\r
- {\r
- var res = MIDebugger.Request(String.Format("-var-create - * \"{0}\"", Expression));\r
- Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
-\r
- Assert.Equal(Expression, ((MIConst)res["exp"]).CString, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
- Assert.Equal(ExpectedType, ((MIConst)res["type"]).CString, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
- Assert.Equal(ExpectedResult, ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
-\r
- return ((MIConst)res["name"]).CString;\r
- }\r
-\r
- public void CheckErrorAtRequest(string caller_trace, string Expression, string errMsgStart)\r
- {\r
- var res = MIDebugger.Request(String.Format("-var-create - * \"{0}\"", Expression));\r
- Assert.Equal(MIResultClass.Error, res.Class, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
- Assert.True(((MIConst)res["msg"]).CString.StartsWith(errMsgStart), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
- }\r
-\r
public void CheckHostRuntimeVersion(string caller_trace)\r
{\r
Assert.True(GetDeltaApi.CheckRuntimeVersion(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
public void ApplyDeltas(string caller_trace, string fileName)\r
{\r
string targetPath = Path.Combine(@"/tmp", fileName);\r
+ string targetAssemblyName = Path.GetFileName(ControlInfo.TargetAssemblyPath);\r
Assert.Equal(MIResultClass.Done,\r
- MIDebugger.Request("-apply-deltas TestAppHotReload.dll " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
+ MIDebugger.Request("-apply-deltas " + targetAssemblyName + " " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
@"__FILE__:__LINE__"+"\n"+caller_trace);\r
}\r
\r
Context.CheckTargetRuntimeVersion(@"__FILE__:__LINE__");\r
Context.StartGenDeltaSession(@"__FILE__:__LINE__");\r
\r
+ // Debugger should remove breakpoint from old code and we never stop on it during old code execution.\r
+ // Note, at `Main()` update we execute `Main()` code (we stopped at entry point), so, we continue old `Main()` code execution.\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 8);\r
+\r
Context.GetDelta(@"__FILE__:__LINE__",\r
@"using System;\r
namespace TestAppHotReload\r
{\r
static void Main(string[] args)\r
{\r
- Console.WriteLine(""Hello World!"");\r
+ Console.WriteLine(""Hello World! Main updated.""); // line 8\r
HotReloadTest();\r
}\r
static void HotReloadTest()\r
{\r
Console.WriteLine(""Updated string."");\r
- HotReloadEvalTest1();\r
- HotReloadEvalTest1();\r
- }\r
- static void HotReloadEvalTest1()\r
+ HotReloadBreakpointTest1();\r
+ HotReloadBreakpointTest1(); // line 15\r
+ } // line 16\r
+ static void HotReloadBreakpointTest1()\r
{\r
- Console.WriteLine(""Added string."");\r
+ Console.WriteLine(""Added string.""); // line 19\r
}\r
}\r
}", @"Program.cs");\r
Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 16);\r
Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 19);\r
Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 25);\r
- Context.EnableFuncBreakpoint(@"__FILE__:__LINE__", "Program.HotReloadEvalTest1");\r
- Context.EnableFuncBreakpoint(@"__FILE__:__LINE__", "Program.HotReloadEvalTest2");\r
+ Context.EnableFuncBreakpoint(@"__FILE__:__LINE__", "Program.HotReloadBreakpointTest1");\r
+ Context.EnableFuncBreakpoint(@"__FILE__:__LINE__", "Program.HotReloadBreakpointTest2");\r
\r
Context.GetDelta(@"__FILE__:__LINE__",\r
@"using System;\r
static void HotReloadTest()\r
{\r
Console.WriteLine(""Updated string."");\r
- HotReloadEvalTest1();\r
- HotReloadEvalTest1();\r
+ HotReloadBreakpointTest1();\r
+ HotReloadBreakpointTest1(); // line 15\r
}\r
- static void HotReloadEvalTest1()\r
+ static void HotReloadBreakpointTest1()\r
{\r
- Console.WriteLine(""Updated added string."");\r
- HotReloadEvalTest2();\r
+ Console.WriteLine(""Updated added string.""); // line 19\r
+ HotReloadBreakpointTest2();\r
}\r
- static void HotReloadEvalTest2()\r
+ static void HotReloadBreakpointTest2()\r
{\r
Console.WriteLine(""Another added string."");\r
- Console.WriteLine(""One more added string."");\r
+ Console.WriteLine(""One more added string.""); // line 25\r
}\r
}\r
}", @"Program.cs");\r
\r
Label.Checkpoint("bp_test_old_func_resetup", "bp_test_old_line_resetup", (Object context) => {\r
Context Context = (Context)context;\r
- Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 18); // Program.HotReloadEvalTest1\r
+ Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 18); // Program.HotReloadBreakpointTest1\r
Context.Continue(@"__FILE__:__LINE__");\r
});\r
\r
\r
Label.Checkpoint("bp_test_func_added", "bp_test_line_added", (Object context) => {\r
Context Context = (Context)context;\r
- Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 23); // Program.HotReloadEvalTest2\r
+ Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 23); // Program.HotReloadBreakpointTest2\r
Context.Continue(@"__FILE__:__LINE__");\r
});\r
\r
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+ <ItemGroup>\r
+ <ProjectReference Include="..\NetcoreDbgTest\NetcoreDbgTest.csproj" />\r
+ <ProjectReference Include="..\TestAppHotReload\TestAppHotReload.csproj" />\r
+ </ItemGroup>\r
+\r
+ <PropertyGroup>\r
+ <OutputType>Exe</OutputType>\r
+ <TargetFramework>netcoreapp3.1</TargetFramework>\r
+ </PropertyGroup>\r
+\r
+</Project>\r
--- /dev/null
+using System;\r
+using System.IO;\r
+using System.Runtime.InteropServices;\r
+\r
+using NetcoreDbgTest;\r
+using NetcoreDbgTest.MI;\r
+using NetcoreDbgTest.Script;\r
+using NetcoreDbgTest.GetDeltaApi;\r
+\r
+namespace NetcoreDbgTest.Script\r
+{\r
+ class Context\r
+ {\r
+ public void Prepare(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-gdb-set enable-hot-reload 1").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-file-exec-and-symbols " + ControlInfo.CorerunPath).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-exec-arguments " + ControlInfo.TargetAssemblyPath).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-run").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ bool IsStoppedEvent(MIOutOfBandRecord record)\r
+ {\r
+ if (record.Type != MIOutOfBandRecordType.Async) {\r
+ return false;\r
+ }\r
+\r
+ var asyncRecord = (MIAsyncRecord)record;\r
+\r
+ if (asyncRecord.Class != MIAsyncRecordClass.Exec ||\r
+ asyncRecord.Output.Class != MIAsyncOutputClass.Stopped) {\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+ }\r
+\r
+ public void WasEntryPointHit(string realNamespace, string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "entry-point-hit") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var func = (MIConst)frame["func"];\r
+ if (func.CString == realNamespace + ".Program.Main()") {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasBreakpointHit(string caller_trace, string bpFileName, int bpNumLine)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "breakpoint-hit") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var fileName = (MIConst)frame["file"];\r
+ var line = ((MIConst)frame["line"]).Int;\r
+\r
+ if (fileName.CString == bpFileName &&\r
+ line == bpNumLine) {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter),\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasExit(string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "exited") {\r
+ return false;\r
+ }\r
+\r
+ var exitCode = (MIConst)output["exit-code"];\r
+\r
+ if (exitCode.CString == "0") {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void DebuggerExit(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Exit,\r
+ MIDebugger.Request("-gdb-exit").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void EnableBreakpoint(string caller_trace, string bpFileName, int bpNumLine)\r
+ {\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-break-insert -f " + bpFileName + ":" + bpNumLine).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void Continue(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-continue").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public string GetAndCheckValue(string caller_trace, string ExpectedResult, string ExpectedType, string Expression)\r
+ {\r
+ var res = MIDebugger.Request(String.Format("-var-create - * \"{0}\"", Expression));\r
+ Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(Expression, ((MIConst)res["exp"]).CString, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ Assert.Equal(ExpectedType, ((MIConst)res["type"]).CString, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ Assert.Equal(ExpectedResult, ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ return ((MIConst)res["name"]).CString;\r
+ }\r
+\r
+ public void CheckErrorAtRequest(string caller_trace, string Expression, string errMsgStart)\r
+ {\r
+ var res = MIDebugger.Request(String.Format("-var-create - * \"{0}\"", Expression));\r
+ Assert.Equal(MIResultClass.Error, res.Class, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ Assert.True(((MIConst)res["msg"]).CString.StartsWith(errMsgStart), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckHostRuntimeVersion(string caller_trace)\r
+ {\r
+ Assert.True(GetDeltaApi.CheckRuntimeVersion(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckHostOS(string caller_trace)\r
+ {\r
+ Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckTargetRuntimeVersion(string caller_trace)\r
+ {\r
+ var res = MIDebugger.Request("-var-create - * System.Environment.Version.Major>=6");\r
+ Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+ Assert.Equal("true", ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+ }\r
+\r
+ public void StartGenDeltaSession(string caller_trace)\r
+ {\r
+ string projectPath = Path.GetDirectoryName(ControlInfo.SourceFilesPath);\r
+ Assert.True(GetDeltaApi.StartGenDeltaSession(projectPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void EndGenDeltaSession(string caller_trace)\r
+ {\r
+ Assert.True(GetDeltaApi.EndGenDeltaSession(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void SdbPush(string caller_trace, string hostFullPath, string targetPath)\r
+ {\r
+ System.Diagnostics.Process process = new System.Diagnostics.Process();\r
+ process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;\r
+ process.StartInfo.RedirectStandardInput = true;\r
+ process.StartInfo.RedirectStandardOutput = true;\r
+ process.StartInfo.CreateNoWindow = true;\r
+ process.StartInfo.UseShellExecute = false;\r
+ \r
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+ {\r
+ process.StartInfo.FileName = "bash";\r
+ process.StartInfo.Arguments = "-c \"sdb push " + hostFullPath + " " + targetPath + "\"";\r
+ }\r
+ else\r
+ throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ process.Start();\r
+ process.WaitForExit();\r
+ Assert.Equal(0, process.ExitCode, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WriteDeltas(string caller_trace, string fileName)\r
+ {\r
+ string hostPath;\r
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+ hostPath = Path.Combine(@"/tmp", fileName);\r
+ else\r
+ throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ string targetPath = @"/tmp";\r
+ Assert.True(GetDeltaApi.WriteDeltas(hostPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".metadata", targetPath);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".il", targetPath);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".pdb", targetPath);\r
+ }\r
+\r
+ public void GetDelta(string caller_trace, string source, string sourceFileName)\r
+ {\r
+ Assert.True(GetDeltaApi.GetDeltas(source, sourceFileName, "", false), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void ApplyDeltas(string caller_trace, string fileName)\r
+ {\r
+ string targetPath = Path.Combine(@"/tmp", fileName);\r
+ string targetAssemblyName = Path.GetFileName(ControlInfo.TargetAssemblyPath);\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-apply-deltas " + targetAssemblyName + " " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public Context(ControlInfo controlInfo, NetcoreDbgTestCore.DebuggerClient debuggerClient)\r
+ {\r
+ ControlInfo = controlInfo;\r
+ MIDebugger = new MIDebugger(debuggerClient);\r
+ GetDeltaApi = new GetDeltaApi.GetDeltaApi();\r
+ }\r
+\r
+ ControlInfo ControlInfo;\r
+ MIDebugger MIDebugger;\r
+ GetDeltaApi.GetDeltaApi GetDeltaApi;\r
+ }\r
+}\r
+\r
+namespace MITestHotReloadEvaluate\r
+{\r
+ class Program\r
+ {\r
+ static void Main(string[] args)\r
+ {\r
+ Label.Checkpoint("init", "eval_test1", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.CheckHostRuntimeVersion(@"__FILE__:__LINE__");\r
+ Context.CheckHostOS(@"__FILE__:__LINE__");\r
+ Context.Prepare(@"__FILE__:__LINE__");\r
+ Context.WasEntryPointHit("TestAppHotReload", @"__FILE__:__LINE__");\r
+ // Note, target Hot Reload check must be after debuggee process start and stop at entry breakpoint.\r
+ Context.CheckTargetRuntimeVersion(@"__FILE__:__LINE__");\r
+ Context.StartGenDeltaSession(@"__FILE__:__LINE__");\r
+\r
+ Context.GetDelta(@"__FILE__:__LINE__",\r
+ @"using System;\r
+ namespace TestAppHotReload\r
+ {\r
+ class TestClass\r
+ {\r
+ int i = 5;\r
+ }\r
+\r
+ class Program\r
+ {\r
+ static int iStatic = 10;\r
+\r
+ static void Main(string[] args)\r
+ {\r
+ Console.WriteLine(""Hello World!"");\r
+ HotReloadTest();\r
+ }\r
+ static void HotReloadTest()\r
+ {\r
+ Console.WriteLine(""Updated string."");\r
+ HotReloadEvalTest1(555);\r
+ HotReloadEvalTest1(555);\r
+ }\r
+ static void HotReloadEvalTest1(int iArg)\r
+ {\r
+ int iLocal = 22;\r
+ var clLocal = new TestClass();\r
+ Console.WriteLine(""iArg="" + iArg.ToString());\r
+ Console.WriteLine(""iLocal="" + iLocal.ToString());\r
+ Console.WriteLine(""iStatic="" + iStatic.ToString());\r
+ {\r
+ int iLocalScope = 33;\r
+ Console.WriteLine(""iLocalScope="" + iLocalScope.ToString()); // line 33\r
+ }\r
+ } // line 35\r
+ }\r
+ }", @"Program.cs");\r
+ Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+ Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 33);\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 35);\r
+\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ Label.Checkpoint("eval_test1", "eval_test2", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 33);\r
+\r
+ // Check argument in added method.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "555", "int", "iArg");\r
+ // Check local variable in added method.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "22", "int", "iLocal");\r
+ // Check local variable in scope in added method.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "33", "int", "iLocalScope");\r
+ // Check added static field.\r
+ // Note, it have `0` since static constructor was called before we add this field.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "0", "int", "iStatic");\r
+ // Check field in added class.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "5", "int", "clLocal.i");\r
+\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ Label.Checkpoint("eval_test2", "eval_test3", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 35);\r
+\r
+ // Check argument in added method.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "555", "int", "iArg");\r
+ // Check local variable in added method.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "22", "int", "iLocal");\r
+ // Check local variable out of scope in added method.\r
+ Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "iLocalScope", "error");\r
+ // Check added static field.\r
+ // Note, it have `0` since static constructor was called before we add this field.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "0", "int", "iStatic");\r
+ // Check field in added class.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "5", "int", "clLocal.i");\r
+ });\r
+\r
+ Label.Checkpoint("eval_test3", "eval_test4", (Object context) => {\r
+ Context Context = (Context)context;\r
+\r
+ Context.GetDelta(@"__FILE__:__LINE__",\r
+ @"using System;\r
+ namespace TestAppHotReload\r
+ {\r
+ class TestClass\r
+ {\r
+ int i = 5;\r
+ }\r
+\r
+ class Program\r
+ {\r
+ static int iStatic = 10;\r
+\r
+ static void Main(string[] args)\r
+ {\r
+ Console.WriteLine(""Hello World!"");\r
+ HotReloadTest();\r
+ }\r
+ static void HotReloadTest()\r
+ {\r
+ Console.WriteLine(""Updated string."");\r
+ HotReloadEvalTest1(555);\r
+ HotReloadEvalTest1(555);\r
+ }\r
+ static void HotReloadEvalTest1(int iArg)\r
+ { // line 25\r
+ }\r
+ }\r
+ }", @"Program.cs");\r
+ Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+ Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+\r
+ // Check argument in added method.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "555", "int", "iArg");\r
+ // Check local variable in added method.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "22", "int", "iLocal");\r
+ // Check local variable out of scope in added method.\r
+ Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "iLocalScope", "error");\r
+ // Check added static field.\r
+ // Note, it have `0` since static constructor was called before we add this field.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "0", "int", "iStatic");\r
+ // Check field in added class.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "5", "int", "clLocal.i");\r
+\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 25);\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ Label.Checkpoint("eval_test4", "finish", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 25);\r
+\r
+ // Check argument in added method.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "555", "int", "iArg");\r
+ // Check local variable in added method.\r
+ Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "iLocal", "error");\r
+ // Check local variable out of scope in added method.\r
+ Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "iLocalScope", "error");\r
+ // Check added static field.\r
+ // Note, it have `0` since static constructor was called before we add this field.\r
+ Context.GetAndCheckValue(@"__FILE__:__LINE__", "0", "int", "iStatic");\r
+ // Check field in added class.\r
+ Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "clLocal.i", "error");\r
+\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ Label.Checkpoint("finish", "", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.EndGenDeltaSession(@"__FILE__:__LINE__");\r
+ Context.WasExit(@"__FILE__:__LINE__");\r
+ Context.DebuggerExit(@"__FILE__:__LINE__");\r
+ });\r
+ }\r
+ }\r
+}\r
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+ <ItemGroup>\r
+ <ProjectReference Include="..\NetcoreDbgTest\NetcoreDbgTest.csproj" />\r
+ <ProjectReference Include="..\TestAppHotReload\TestAppHotReload.csproj" />\r
+ </ItemGroup>\r
+\r
+ <PropertyGroup>\r
+ <OutputType>Exe</OutputType>\r
+ <TargetFramework>netcoreapp3.1</TargetFramework>\r
+ </PropertyGroup>\r
+\r
+</Project>\r
--- /dev/null
+using System;\r
+using System.IO;\r
+using System.Runtime.InteropServices;\r
+\r
+using NetcoreDbgTest;\r
+using NetcoreDbgTest.MI;\r
+using NetcoreDbgTest.Script;\r
+using NetcoreDbgTest.GetDeltaApi;\r
+\r
+namespace NetcoreDbgTest.Script\r
+{\r
+ class Context\r
+ {\r
+ public void Prepare(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-gdb-set enable-hot-reload 1").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ // Explicitly enable JMC for this test.\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-gdb-set just-my-code 1").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-file-exec-and-symbols " + ControlInfo.CorerunPath).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-exec-arguments " + ControlInfo.TargetAssemblyPath).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-run").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ bool IsStoppedEvent(MIOutOfBandRecord record)\r
+ {\r
+ if (record.Type != MIOutOfBandRecordType.Async) {\r
+ return false;\r
+ }\r
+\r
+ var asyncRecord = (MIAsyncRecord)record;\r
+\r
+ if (asyncRecord.Class != MIAsyncRecordClass.Exec ||\r
+ asyncRecord.Output.Class != MIAsyncOutputClass.Stopped) {\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+ }\r
+\r
+ public void WasEntryPointHit(string realNamespace, string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "entry-point-hit") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var func = (MIConst)frame["func"];\r
+ if (func.CString == realNamespace + ".Program.Main()") {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasBreakpointHit(string caller_trace, string bpFileName, int bpNumLine)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "breakpoint-hit") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var fileName = (MIConst)frame["file"];\r
+ var line = ((MIConst)frame["line"]).Int;\r
+\r
+ if (fileName.CString == bpFileName &&\r
+ line == bpNumLine) {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter),\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasStep(string caller_trace, int bpNumLine)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+ if (reason.CString != "end-stepping-range") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var line = ((MIConst)frame["line"]).Int;\r
+ if (bpNumLine == line) {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasExit(string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "exited") {\r
+ return false;\r
+ }\r
+\r
+ var exitCode = (MIConst)output["exit-code"];\r
+\r
+ if (exitCode.CString == "0") {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void DebuggerExit(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Exit,\r
+ MIDebugger.Request("-gdb-exit").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void EnableBreakpoint(string caller_trace, string bpFileName, int bpNumLine)\r
+ {\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-break-insert -f " + bpFileName + ":" + bpNumLine).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void Continue(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-continue").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void StepIn(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-step").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckHostRuntimeVersion(string caller_trace)\r
+ {\r
+ Assert.True(GetDeltaApi.CheckRuntimeVersion(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckHostOS(string caller_trace)\r
+ {\r
+ Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckTargetRuntimeVersion(string caller_trace)\r
+ {\r
+ var res = MIDebugger.Request("-var-create - * System.Environment.Version.Major>=6");\r
+ Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+ Assert.Equal("true", ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+ }\r
+\r
+ public void StartGenDeltaSession(string caller_trace)\r
+ {\r
+ string projectPath = Path.GetDirectoryName(ControlInfo.SourceFilesPath);\r
+ Assert.True(GetDeltaApi.StartGenDeltaSession(projectPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void EndGenDeltaSession(string caller_trace)\r
+ {\r
+ Assert.True(GetDeltaApi.EndGenDeltaSession(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void SdbPush(string caller_trace, string hostFullPath, string targetPath)\r
+ {\r
+ System.Diagnostics.Process process = new System.Diagnostics.Process();\r
+ process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;\r
+ process.StartInfo.RedirectStandardInput = true;\r
+ process.StartInfo.RedirectStandardOutput = true;\r
+ process.StartInfo.CreateNoWindow = true;\r
+ process.StartInfo.UseShellExecute = false;\r
+ \r
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+ {\r
+ process.StartInfo.FileName = "bash";\r
+ process.StartInfo.Arguments = "-c \"sdb push " + hostFullPath + " " + targetPath + "\"";\r
+ }\r
+ else\r
+ throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ process.Start();\r
+ process.WaitForExit();\r
+ Assert.Equal(0, process.ExitCode, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WriteDeltas(string caller_trace, string fileName)\r
+ {\r
+ string hostPath;\r
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+ hostPath = Path.Combine(@"/tmp", fileName);\r
+ else\r
+ throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ string targetPath = @"/tmp";\r
+ Assert.True(GetDeltaApi.WriteDeltas(hostPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".metadata", targetPath);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".il", targetPath);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".pdb", targetPath);\r
+ }\r
+\r
+ public void GetDelta(string caller_trace, string source, string sourceFileName)\r
+ {\r
+ Assert.True(GetDeltaApi.GetDeltas(source, sourceFileName, "", false), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void ApplyDeltas(string caller_trace, string fileName)\r
+ {\r
+ string targetPath = Path.Combine(@"/tmp", fileName);\r
+ string targetAssemblyName = Path.GetFileName(ControlInfo.TargetAssemblyPath);\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-apply-deltas " + targetAssemblyName + " " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public Context(ControlInfo controlInfo, NetcoreDbgTestCore.DebuggerClient debuggerClient)\r
+ {\r
+ ControlInfo = controlInfo;\r
+ MIDebugger = new MIDebugger(debuggerClient);\r
+ GetDeltaApi = new GetDeltaApi.GetDeltaApi();\r
+ }\r
+\r
+ ControlInfo ControlInfo;\r
+ MIDebugger MIDebugger;\r
+ GetDeltaApi.GetDeltaApi GetDeltaApi;\r
+ }\r
+}\r
+\r
+namespace MITestHotReloadJMC\r
+{\r
+ class Program\r
+ {\r
+ static void Main(string[] args)\r
+ {\r
+ Label.Checkpoint("init", "test_breakpoints", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.CheckHostRuntimeVersion(@"__FILE__:__LINE__");\r
+ Context.CheckHostOS(@"__FILE__:__LINE__");\r
+ Context.Prepare(@"__FILE__:__LINE__");\r
+ Context.WasEntryPointHit("TestAppHotReload", @"__FILE__:__LINE__");\r
+ // Note, target Hot Reload check must be after debuggee process start and stop at entry breakpoint.\r
+ Context.CheckTargetRuntimeVersion(@"__FILE__:__LINE__");\r
+ Context.StartGenDeltaSession(@"__FILE__:__LINE__");\r
+\r
+ Context.GetDelta(@"__FILE__:__LINE__",\r
+ @"using System;using System.Diagnostics;\r
+ namespace TestAppHotReload\r
+ {\r
+ class Program\r
+ {\r
+ static void Main(string[] args)\r
+ {\r
+ Console.WriteLine(""Hello World!"");\r
+ HotReloadTest();\r
+ }\r
+ static void HotReloadTest()\r
+ {\r
+ Console.WriteLine(""Updated string."");\r
+ test_attr_func1();\r
+ test_attr_func2();\r
+ test_attr_func3();\r
+ ctest_attr1.test_func();\r
+ ctest_attr2.test_func();\r
+ test_attr_func1(); // line 19\r
+ test_attr_func2(); // line 20\r
+ test_attr_func3(); // line 21\r
+ ctest_attr1.test_func(); // line 22\r
+ ctest_attr2.test_func(); // line 23\r
+ } // line 24\r
+\r
+ [DebuggerStepThroughAttribute()]\r
+ static void test_attr_func1()\r
+ { // line 28\r
+ }\r
+\r
+ [DebuggerNonUserCodeAttribute()]\r
+ static void test_attr_func2()\r
+ { // line 33\r
+ }\r
+\r
+ [DebuggerHiddenAttribute()]\r
+ static void test_attr_func3()\r
+ { // line 38\r
+ }\r
+ }\r
+\r
+ [DebuggerStepThroughAttribute()]\r
+ class ctest_attr1\r
+ {\r
+ public static void test_func()\r
+ { // line 46\r
+ }\r
+ }\r
+\r
+ [DebuggerNonUserCodeAttribute()]\r
+ class ctest_attr2\r
+ {\r
+ public static void test_func()\r
+ { // line 54\r
+ }\r
+ }\r
+\r
+ }", @"Program.cs");\r
+ Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+ Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 19);\r
+ });\r
+\r
+ Label.Checkpoint("test_breakpoints", "test_stepping", (Object context) => {\r
+ Context Context = (Context)context;\r
+\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 28);\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 33);\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 38);\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 46);\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 54);\r
+\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ Label.Checkpoint("test_stepping", "finish", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 19);\r
+\r
+ Context.StepIn(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 20);\r
+ Context.StepIn(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 21);\r
+ Context.StepIn(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 22);\r
+ Context.StepIn(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 23);\r
+ Context.StepIn(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 24);\r
+\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ Label.Checkpoint("finish", "", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.EndGenDeltaSession(@"__FILE__:__LINE__");\r
+ Context.WasExit(@"__FILE__:__LINE__");\r
+ Context.DebuggerExit(@"__FILE__:__LINE__");\r
+ });\r
+ }\r
+ }\r
+}\r
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+ <ItemGroup>\r
+ <ProjectReference Include="..\NetcoreDbgTest\NetcoreDbgTest.csproj" />\r
+ <ProjectReference Include="..\TestAppHotReload\TestAppHotReload.csproj" />\r
+ </ItemGroup>\r
+\r
+ <PropertyGroup>\r
+ <OutputType>Exe</OutputType>\r
+ <TargetFramework>netcoreapp3.1</TargetFramework>\r
+ </PropertyGroup>\r
+\r
+</Project>\r
--- /dev/null
+using System;\r
+using System.IO;\r
+using System.Runtime.InteropServices;\r
+\r
+using NetcoreDbgTest;\r
+using NetcoreDbgTest.MI;\r
+using NetcoreDbgTest.Script;\r
+using NetcoreDbgTest.GetDeltaApi;\r
+\r
+namespace NetcoreDbgTest.Script\r
+{\r
+ class Context\r
+ {\r
+ public void Prepare(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-gdb-set enable-hot-reload 1").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-file-exec-and-symbols " + ControlInfo.CorerunPath).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-exec-arguments " + ControlInfo.TargetAssemblyPath).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-run").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ bool IsStoppedEvent(MIOutOfBandRecord record)\r
+ {\r
+ if (record.Type != MIOutOfBandRecordType.Async) {\r
+ return false;\r
+ }\r
+\r
+ var asyncRecord = (MIAsyncRecord)record;\r
+\r
+ if (asyncRecord.Class != MIAsyncRecordClass.Exec ||\r
+ asyncRecord.Output.Class != MIAsyncOutputClass.Stopped) {\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+ }\r
+\r
+ public void WasEntryPointHit(string realNamespace, string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "entry-point-hit") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var func = (MIConst)frame["func"];\r
+ if (func.CString == realNamespace + ".Program.Main()") {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasBreakpointHit(string caller_trace, string bpFileName, int bpNumLine)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "breakpoint-hit") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var fileName = (MIConst)frame["file"];\r
+ var line = ((MIConst)frame["line"]).Int;\r
+\r
+ if (fileName.CString == bpFileName &&\r
+ line == bpNumLine) {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter),\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasStep(string caller_trace, int bpNumLine)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+ if (reason.CString != "end-stepping-range") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var line = ((MIConst)frame["line"]).Int;\r
+ if (bpNumLine == line) {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasStepInOutdatedCode(string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+ if (reason.CString != "end-stepping-range") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var func = ((MIConst)frame["func"]).CString;\r
+\r
+ if (func.StartsWith("[Outdated Code]")) {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasExit(string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "exited") {\r
+ return false;\r
+ }\r
+\r
+ var exitCode = (MIConst)output["exit-code"];\r
+\r
+ if (exitCode.CString == "0") {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void DebuggerExit(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Exit,\r
+ MIDebugger.Request("-gdb-exit").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void EnableBreakpoint(string caller_trace, string bpFileName, int bpNumLine)\r
+ {\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-break-insert -f " + bpFileName + ":" + bpNumLine).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void Continue(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-continue").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void StepOver(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-next").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void StepIn(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-step").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void StepOut(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-finish").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckHostRuntimeVersion(string caller_trace)\r
+ {\r
+ Assert.True(GetDeltaApi.CheckRuntimeVersion(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckHostOS(string caller_trace)\r
+ {\r
+ Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckTargetRuntimeVersion(string caller_trace)\r
+ {\r
+ var res = MIDebugger.Request("-var-create - * System.Environment.Version.Major>=6");\r
+ Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+ Assert.Equal("true", ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+ }\r
+\r
+ public void StartGenDeltaSession(string caller_trace)\r
+ {\r
+ string projectPath = Path.GetDirectoryName(ControlInfo.SourceFilesPath);\r
+ Assert.True(GetDeltaApi.StartGenDeltaSession(projectPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void EndGenDeltaSession(string caller_trace)\r
+ {\r
+ Assert.True(GetDeltaApi.EndGenDeltaSession(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void SdbPush(string caller_trace, string hostFullPath, string targetPath)\r
+ {\r
+ System.Diagnostics.Process process = new System.Diagnostics.Process();\r
+ process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;\r
+ process.StartInfo.RedirectStandardInput = true;\r
+ process.StartInfo.RedirectStandardOutput = true;\r
+ process.StartInfo.CreateNoWindow = true;\r
+ process.StartInfo.UseShellExecute = false;\r
+ \r
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+ {\r
+ process.StartInfo.FileName = "bash";\r
+ process.StartInfo.Arguments = "-c \"sdb push " + hostFullPath + " " + targetPath + "\"";\r
+ }\r
+ else\r
+ throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ process.Start();\r
+ process.WaitForExit();\r
+ Assert.Equal(0, process.ExitCode, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WriteDeltas(string caller_trace, string fileName)\r
+ {\r
+ string hostPath;\r
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+ hostPath = Path.Combine(@"/tmp", fileName);\r
+ else\r
+ throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ string targetPath = @"/tmp";\r
+ Assert.True(GetDeltaApi.WriteDeltas(hostPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".metadata", targetPath);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".il", targetPath);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".pdb", targetPath);\r
+ }\r
+\r
+ public void GetDelta(string caller_trace, string source, string sourceFileName)\r
+ {\r
+ Assert.True(GetDeltaApi.GetDeltas(source, sourceFileName, "", false), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void ApplyDeltas(string caller_trace, string fileName)\r
+ {\r
+ string targetPath = Path.Combine(@"/tmp", fileName);\r
+ string targetAssemblyName = Path.GetFileName(ControlInfo.TargetAssemblyPath);\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-apply-deltas " + targetAssemblyName + " " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public Context(ControlInfo controlInfo, NetcoreDbgTestCore.DebuggerClient debuggerClient)\r
+ {\r
+ ControlInfo = controlInfo;\r
+ MIDebugger = new MIDebugger(debuggerClient);\r
+ GetDeltaApi = new GetDeltaApi.GetDeltaApi();\r
+ }\r
+\r
+ ControlInfo ControlInfo;\r
+ MIDebugger MIDebugger;\r
+ GetDeltaApi.GetDeltaApi GetDeltaApi;\r
+ }\r
+}\r
+\r
+namespace MITestHotReloadStepping\r
+{\r
+ class Program\r
+ {\r
+ static void Main(string[] args)\r
+ {\r
+ Label.Checkpoint("init", "test_stepin_new_code", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.CheckHostRuntimeVersion(@"__FILE__:__LINE__");\r
+ Context.CheckHostOS(@"__FILE__:__LINE__");\r
+ Context.Prepare(@"__FILE__:__LINE__");\r
+ Context.WasEntryPointHit("TestAppHotReload", @"__FILE__:__LINE__");\r
+ // Note, target Hot Reload check must be after debuggee process start and stop at entry breakpoint.\r
+ Context.CheckTargetRuntimeVersion(@"__FILE__:__LINE__");\r
+ Context.StartGenDeltaSession(@"__FILE__:__LINE__");\r
+\r
+ Context.GetDelta(@"__FILE__:__LINE__",\r
+ @"using System;\r
+ namespace TestAppHotReload\r
+ {\r
+ class Program\r
+ {\r
+ static void Main(string[] args)\r
+ {\r
+ Console.WriteLine(""Hello World!"");\r
+ HotReloadTest();\r
+ }\r
+ static void HotReloadTest()\r
+ {\r
+ Console.WriteLine(""Updated string."");\r
+ HotReloadStepTest1(); // line 14\r
+ HotReloadStepTest1();\r
+ }\r
+ static void HotReloadStepTest1()\r
+ { // line 18\r
+ Console.WriteLine(""Added line 1."");\r
+ Console.WriteLine(""Added line 2."");\r
+ Console.WriteLine(""Added line 3."");\r
+ }\r
+ }\r
+ }", @"Program.cs");\r
+ Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+ Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 14);\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ // Test step-in for new code.\r
+ Label.Checkpoint("test_stepin_new_code", "update_code", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 14);\r
+ Context.StepIn(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 18);\r
+ });\r
+\r
+ Label.Checkpoint("update_code", "test_stepover_old_code", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.GetDelta(@"__FILE__:__LINE__",\r
+ @"using System;\r
+ namespace TestAppHotReload\r
+ {\r
+ class Program\r
+ {\r
+ static void Main(string[] args)\r
+ {\r
+ Console.WriteLine(""Hello World!"");\r
+ HotReloadTest();\r
+ }\r
+ static void HotReloadTest()\r
+ {\r
+ Console.WriteLine(""Updated string."");\r
+ HotReloadStepTest1();\r
+ HotReloadStepTest1(); // line 15\r
+ }\r
+ static void HotReloadStepTest1()\r
+ { // line 18\r
+ Console.WriteLine(""Updated line, removed 2 lines."");\r
+ }\r
+ }\r
+ }", @"Program.cs");\r
+ Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+ Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+ });\r
+\r
+ // Test step-over for old code.\r
+ Label.Checkpoint("test_stepover_old_code", "test_stepover_new_code", (Object context) => {\r
+ Context Context = (Context)context;\r
+\r
+ Context.StepOver(@"__FILE__:__LINE__");\r
+ Context.WasStepInOutdatedCode(@"__FILE__:__LINE__");\r
+ Context.StepOver(@"__FILE__:__LINE__");\r
+ Context.WasStepInOutdatedCode(@"__FILE__:__LINE__");\r
+ Context.StepOver(@"__FILE__:__LINE__");\r
+ Context.WasStepInOutdatedCode(@"__FILE__:__LINE__");\r
+\r
+ Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 15);\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ // Test step-over for new code.\r
+ Label.Checkpoint("test_stepover_new_code", "test_stepout_new_code", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 15);\r
+\r
+ Context.StepIn(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 18);\r
+ Context.StepOver(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 19);\r
+ });\r
+\r
+ // Test step-out for new code.\r
+ Label.Checkpoint("test_stepout_new_code", "finish", (Object context) => {\r
+ Context Context = (Context)context;\r
+\r
+ Context.StepOut(@"__FILE__:__LINE__");\r
+ Context.WasStep(@"__FILE__:__LINE__", 16);\r
+\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ Label.Checkpoint("finish", "", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.EndGenDeltaSession(@"__FILE__:__LINE__");\r
+ Context.WasExit(@"__FILE__:__LINE__");\r
+ Context.DebuggerExit(@"__FILE__:__LINE__");\r
+ });\r
+ }\r
+ }\r
+}\r
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+ <ItemGroup>\r
+ <ProjectReference Include="..\NetcoreDbgTest\NetcoreDbgTest.csproj" />\r
+ <ProjectReference Include="..\TestAppHotReload\TestAppHotReload.csproj" />\r
+ </ItemGroup>\r
+\r
+ <PropertyGroup>\r
+ <OutputType>Exe</OutputType>\r
+ <TargetFramework>netcoreapp3.1</TargetFramework>\r
+ </PropertyGroup>\r
+\r
+</Project>\r
--- /dev/null
+using System;\r
+using System.IO;\r
+using System.Runtime.InteropServices;\r
+\r
+using NetcoreDbgTest;\r
+using NetcoreDbgTest.MI;\r
+using NetcoreDbgTest.Script;\r
+using NetcoreDbgTest.GetDeltaApi;\r
+\r
+namespace NetcoreDbgTest.Script\r
+{\r
+ class Context\r
+ {\r
+ public void Prepare(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-gdb-set enable-hot-reload 1").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-file-exec-and-symbols " + ControlInfo.CorerunPath).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-exec-arguments " + ControlInfo.TargetAssemblyPath).Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-run").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ bool IsStoppedEvent(MIOutOfBandRecord record)\r
+ {\r
+ if (record.Type != MIOutOfBandRecordType.Async) {\r
+ return false;\r
+ }\r
+\r
+ var asyncRecord = (MIAsyncRecord)record;\r
+\r
+ if (asyncRecord.Class != MIAsyncRecordClass.Exec ||\r
+ asyncRecord.Output.Class != MIAsyncOutputClass.Stopped) {\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+ }\r
+\r
+ public void WasEntryPointHit(string realNamespace, string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "entry-point-hit") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var func = (MIConst)frame["func"];\r
+ if (func.CString == realNamespace + ".Program.Main()") {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasBreakHit(string caller_trace, string bpFileName, int bpNumLine)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+ var signal_name = (MIConst)output["signal-name"];\r
+\r
+ if (reason.CString != "signal-received" &&\r
+ signal_name.CString != "SIGINT") {\r
+ return false;\r
+ }\r
+\r
+ var frame = (MITuple)output["frame"];\r
+ var fileName = (MIConst)frame["file"];\r
+ var line = ((MIConst)frame["line"]).Int;\r
+\r
+ if (fileName.CString == bpFileName &&\r
+ line == bpNumLine) {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WasExit(string caller_trace)\r
+ {\r
+ Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+ if (!IsStoppedEvent(record)) {\r
+ return false;\r
+ }\r
+\r
+ var output = ((MIAsyncRecord)record).Output;\r
+ var reason = (MIConst)output["reason"];\r
+\r
+ if (reason.CString != "exited") {\r
+ return false;\r
+ }\r
+\r
+ var exitCode = (MIConst)output["exit-code"];\r
+\r
+ if (exitCode.CString == "0") {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ };\r
+\r
+ Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void DebuggerExit(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Exit,\r
+ MIDebugger.Request("-gdb-exit").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void Continue(string caller_trace)\r
+ {\r
+ Assert.Equal(MIResultClass.Running,\r
+ MIDebugger.Request("-exec-continue").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckHostRuntimeVersion(string caller_trace)\r
+ {\r
+ Assert.True(GetDeltaApi.CheckRuntimeVersion(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckHostOS(string caller_trace)\r
+ {\r
+ Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void CheckTargetRuntimeVersion(string caller_trace)\r
+ {\r
+ var res = MIDebugger.Request("-var-create - * System.Environment.Version.Major>=6");\r
+ Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+ Assert.Equal("true", ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+ }\r
+\r
+ public void StartGenDeltaSession(string caller_trace)\r
+ {\r
+ string projectPath = Path.GetDirectoryName(ControlInfo.SourceFilesPath);\r
+ Assert.True(GetDeltaApi.StartGenDeltaSession(projectPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void EndGenDeltaSession(string caller_trace)\r
+ {\r
+ Assert.True(GetDeltaApi.EndGenDeltaSession(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void SdbPush(string caller_trace, string hostFullPath, string targetPath)\r
+ {\r
+ System.Diagnostics.Process process = new System.Diagnostics.Process();\r
+ process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;\r
+ process.StartInfo.RedirectStandardInput = true;\r
+ process.StartInfo.RedirectStandardOutput = true;\r
+ process.StartInfo.CreateNoWindow = true;\r
+ process.StartInfo.UseShellExecute = false;\r
+ \r
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+ {\r
+ process.StartInfo.FileName = "bash";\r
+ process.StartInfo.Arguments = "-c \"sdb push " + hostFullPath + " " + targetPath + "\"";\r
+ }\r
+ else\r
+ throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ process.Start();\r
+ process.WaitForExit();\r
+ Assert.Equal(0, process.ExitCode, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void WriteDeltas(string caller_trace, string fileName)\r
+ {\r
+ string hostPath;\r
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+ hostPath = Path.Combine(@"/tmp", fileName);\r
+ else\r
+ throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+ string targetPath = @"/tmp";\r
+ Assert.True(GetDeltaApi.WriteDeltas(hostPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".metadata", targetPath);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".il", targetPath);\r
+ SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".pdb", targetPath);\r
+ }\r
+\r
+ public void GetDelta(string caller_trace, string source, string sourceFileName)\r
+ {\r
+ Assert.True(GetDeltaApi.GetDeltas(source, sourceFileName, "", false), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void ErrorGetDelta(string caller_trace, string source, string sourceFileName)\r
+ {\r
+ Assert.False(GetDeltaApi.GetDeltas(source, sourceFileName, "", false), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public void ApplyDeltas(string caller_trace, string fileName)\r
+ {\r
+ string targetPath = Path.Combine(@"/tmp", fileName);\r
+ string targetAssemblyName = Path.GetFileName(ControlInfo.TargetAssemblyPath);\r
+ Assert.Equal(MIResultClass.Done,\r
+ MIDebugger.Request("-apply-deltas " + targetAssemblyName + " " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
+ @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+ }\r
+\r
+ public Context(ControlInfo controlInfo, NetcoreDbgTestCore.DebuggerClient debuggerClient)\r
+ {\r
+ ControlInfo = controlInfo;\r
+ MIDebugger = new MIDebugger(debuggerClient);\r
+ GetDeltaApi = new GetDeltaApi.GetDeltaApi();\r
+ }\r
+\r
+ ControlInfo ControlInfo;\r
+ MIDebugger MIDebugger;\r
+ GetDeltaApi.GetDeltaApi GetDeltaApi;\r
+ }\r
+}\r
+\r
+namespace MITestHotReloadWithoutBreak\r
+{\r
+ class Program\r
+ {\r
+ static void Main(string[] args)\r
+ {\r
+ Label.Checkpoint("init", "apply_test1", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.CheckHostRuntimeVersion(@"__FILE__:__LINE__");\r
+ Context.CheckHostOS(@"__FILE__:__LINE__");\r
+ Context.Prepare(@"__FILE__:__LINE__");\r
+ Context.WasEntryPointHit("TestAppHotReload", @"__FILE__:__LINE__");\r
+ // Note, target Hot Reload check must be after debuggee process start and stop at entry breakpoint.\r
+ Context.CheckTargetRuntimeVersion(@"__FILE__:__LINE__");\r
+ Context.StartGenDeltaSession(@"__FILE__:__LINE__");\r
+\r
+ Context.GetDelta(@"__FILE__:__LINE__",\r
+ @"using System; using System.Threading;\r
+ namespace TestAppHotReload\r
+ {\r
+ class Program\r
+ {\r
+ static void Main(string[] args)\r
+ {\r
+ Console.WriteLine(""Hello World! Main updated."");\r
+ HotReloadTest();\r
+ }\r
+ static void HotReloadTest()\r
+ {\r
+ int count = 0;\r
+ while (count < 20)\r
+ {\r
+ HotReloadBreakpointTest1();\r
+ System.Threading.Thread.Sleep(1000);\r
+ count++;\r
+ }\r
+ }\r
+ static void HotReloadBreakpointTest1()\r
+ {\r
+ Console.WriteLine(""Added string."");\r
+ }\r
+ }\r
+ }", @"Program.cs");\r
+ Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+ Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ Label.Checkpoint("apply_test1", "apply_test2", (Object context) => {\r
+ Context Context = (Context)context;\r
+\r
+ System.Threading.Thread.Sleep(2000);\r
+\r
+ Context.GetDelta(@"__FILE__:__LINE__",\r
+ @"using System; using System.Diagnostics; using System.Threading;\r
+ namespace TestAppHotReload\r
+ {\r
+ class Program\r
+ {\r
+ static void Main(string[] args)\r
+ {\r
+ Console.WriteLine(""Hello World! Main updated."");\r
+ HotReloadTest();\r
+ }\r
+ static void HotReloadTest()\r
+ {\r
+ Console.WriteLine(""Updated string."");\r
+ int count = 0;\r
+ while (count < 20)\r
+ {\r
+ HotReloadBreakpointTest1();\r
+ System.Threading.Thread.Sleep(1000);\r
+ count++;\r
+ }\r
+ }\r
+ static void HotReloadBreakpointTest1()\r
+ {\r
+ Console.WriteLine(""Updated string."");\r
+ Debugger.Break(); // line 25\r
+ }\r
+ }\r
+ }", @"Program.cs");\r
+ Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+ Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+ });\r
+\r
+ Label.Checkpoint("apply_test2", "finish", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.WasBreakHit(@"__FILE__:__LINE__", @"Program.cs", 25);\r
+\r
+ Context.GetDelta(@"__FILE__:__LINE__",\r
+ @"using System; using System.Threading;\r
+ namespace TestAppHotReload\r
+ {\r
+ class Program\r
+ {\r
+ static void Main(string[] args)\r
+ {\r
+ Console.WriteLine(""Hello World! Main updated."");\r
+ HotReloadTest();\r
+ }\r
+ static void HotReloadTest()\r
+ {\r
+ int count = 0;\r
+ while (count < 20)\r
+ {\r
+ HotReloadBreakpointTest1();\r
+ System.Threading.Thread.Sleep(1000);\r
+ count++;\r
+ }\r
+ }\r
+ static void HotReloadBreakpointTest1()\r
+ {\r
+ Console.WriteLine(""Removed lines..."");\r
+ }\r
+ }\r
+ }", @"Program.cs");\r
+ Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta3");\r
+ Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta3");\r
+\r
+ Context.Continue(@"__FILE__:__LINE__");\r
+ });\r
+\r
+ Label.Checkpoint("finish", "", (Object context) => {\r
+ Context Context = (Context)context;\r
+ Context.EndGenDeltaSession(@"__FILE__:__LINE__");\r
+ Context.WasExit(@"__FILE__:__LINE__");\r
+ Context.DebuggerExit(@"__FILE__:__LINE__");\r
+ });\r
+ }\r
+ }\r
+}\r
-using System;\r
+using System;using System.Diagnostics;using System.Threading;\r
namespace TestAppHotReload\r
{\r
class Program\r
--- /dev/null
+using System;\r
+using System.Threading.Tasks;\r
+ namespace TestAppHotReloadAsync\r
+ {\r
+ class Program\r
+ {\r
+ static async Task Main(string[] args)\r
+ {\r
+ Console.WriteLine("Hello World!");\r
+ await HotReloadTestAsync();\r
+ }\r
+ static async Task HotReloadTestAsync()\r
+ {\r
+ Console.WriteLine("Initial string.");\r
+ await Task.Delay(100);\r
+ }\r
+ }\r
+ }\r
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+ <PropertyGroup>\r
+ <OutputType>Exe</OutputType>\r
+ <TargetFramework>netcoreapp3.1</TargetFramework>\r
+ </PropertyGroup>\r
+\r
+</Project>\r
"MITestNoJMCExceptionBreakpoint"
"MITestSizeof"
"MITestAsyncLambdaEvaluate"
+ "MITestHotReloadAsyncStepping"
+ "MITestHotReloadBreak"
"MITestHotReloadBreakpoint"
+ "MITestHotReloadEvaluate"
+ "MITestHotReloadStepping"
+ "MITestHotReloadJMC"
+ "MITestHotReloadWithoutBreak"
"VSCodeExampleTest"
"VSCodeTestBreakpoint"
"VSCodeTestFuncBreak"
# Build, push and run tests
for TEST_NAME in $TEST_NAMES; do
TEST_PROJ_NAME=$TEST_NAME;
- if [[ $TEST_NAME == MITestHotReload* ]] ;
+
+ if [[ $TEST_NAME == MITestHotReloadAsyncStepping ]] ;
+ then
+ TEST_PROJ_NAME="TestAppHotReloadAsync"
+ elif [[ $TEST_NAME == MITestHotReload* ]] ;
then
TEST_PROJ_NAME="TestAppHotReload"
fi