ionide-vscode-fsharp
ionide-vscode-fsharp copied to clipboard
Can Ionide debug fsx scripts?
Hi,
This is just a question. Can Ionide debug fsx scripts?
Hey @ktodyruik :wave:,
Thank you for opening an issue. We will get back to you as soon as we can. Also, check out our OpenCollective and consider backing us.
https://opencollective.com/ionide
PS.: We offer
backersupport for all backers. Don't forget to addbackerlabel when you start backing us :smile:
No, we don't support debugging fsx scripts at the moment
Do you think we can request support for script debugging? Would it be helpful in the script context and data/python/like context? cc @Krzysztof-Cieslak
Wouldn't be opposed to taking a PR for this.
As a workaround for now you can do something like:
open System.Diagnostics
let waitForDebuggerAttached (programName) =
if not (System.Diagnostics.Debugger.IsAttached) then
printfn
"Please attach a debugger for %s, PID: %d"
programName
(System.Diagnostics.Process.GetCurrentProcess().Id)
while not (System.Diagnostics.Debugger.IsAttached) do
System.Threading.Thread.Sleep(100)
let breakPoint () =
Debugger.Break ()
let main () =
printfn "doing something"
waitForDebuggerAttached "playground.fsx"
let foo = "42"
printfn "%A" fsi.CommandLineArgs
breakPoint ()
failwith "fail"
()
main ()
and having .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"requireExactSource" : false,
"justMyCode": false
}
]
}
Alternative - debugging a script in that way introduces new sources, could a launch request be used instead that launches the dotnet binary with [fsi, path/to/script.fsx] args and a debugOnStart flag set?
Alternative - debugging a script in that way introduces new sources, could a
launchrequestbe used instead that launches thedotnetbinary with[fsi, path/to/script.fsx]args and a debugOnStart flag set?
I think I remember from awhile ago, the issue is the fsx code gets run in another process so I don't think you end up debugging the right thing.
Oh that's right - dotnet fsi shells out to the fsi dll. We'd need to run fsi.dll in-proc. You can still simulate that though. Here's a configuration that mostly-worked for me:
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch FSI",
"request": "launch",
"type": "coreclr",
"program": "C:\\Program Files\\dotnet\\sdk\\8.0.100-preview.5.23303.2\\FSharp\\fsi.dll",
"args": ["${workspaceFolder}\\tryMakeTfmHashes.fsx", "--debug+", "--debug:portable", "--optimize-"],
"justMyCode": false
}
]
}
We should consider auto-creating this configuration when an FSI file is launched for debugging.
There are caveats here though - locals/watches seem to not work at all in this case. I've tried adding debugging flags to make the experience better but I'm not sure I've got the right combination. Locals inside loops/bindings/etc work, but once you're outside of that scope there's just nothing.
@baronfel tested the last approach it works, but indeed no watch or scope variables during debug!
Internal error in the C# compiler
here was my github codespace config for launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch FSI",
"request": "launch",
"type": "coreclr",
"program": "/home/codespace/.dotnet/sdk/7.0.302/FSharp/fsi.dll",
"args": ["${workspaceFolder}/program.fsx", "--debug+", "--debug:portable", "--optimize-"],
"justMyCode": false
}
]
}
is there a way to autodetect SDK version also, maybe with a ENV variable like ${workspaceFolder}, something like ${dotnetSdkVersion}, maybe exists...
I started a conversation with @vlza on the FSSF slack that had some pointers - private thread link is https://fsharp.slack.com/archives/C04AUG3RBGE/p1689174015344819?thread_ts=1689174015.344819&cid=C04AUG3RBGE for posterity.
A couple things to try:
Every submission for fsi generates another Assembly, with top levels being internal fields, and we emit IVT for next assemblies. Or at least we used to manually go check and have a module with public bindings in it, are they visible (as opposed to internal) Don't we emit things as internal in fsi assemblies? Does netcoredbg care about that?
If we can dig into what's going on here and get locals to show up, then Ionide/FSAC could generate the appropriate launch config for the user and we wouldn't need the SDK placeholder variables like @jkone27 was mentioning.
ah i see dotnet fsi debugging was implemented here - https://github.com/dotnet/fsharp/pull/12722 also locals error seems related or similar to this one - https://github.com/dotnet/vscode-csharp/issues/3926
added C#/dotnet debugger log
"logging": {
"engineLogging": true
}
in vscode launch.json and I see this msg
<- (E) {"seq":167,"type":"event","event":"output","body":{"category":"console","output":"Loaded '/usr/local/dotnet/7.0.302/shared/Microsoft.AspNetCore.App/7.0.5/Microsoft.Extensions.Configuration.EnvironmentVariables.dll'. Cannot find or open the PDB file.\n"}}
Loaded '/usr/local/dotnet/7.0.302/shared/Microsoft.AspNetCore.App/7.0.5/Microsoft.Extensions.Configuration.EnvironmentVariables.dll'. Cannot find or open the PDB file.
<- (E) {"seq":168,"type":"event","event":"module","body":{"reason":"new","module":{"id":1063,"name":"Microsoft.Extensions.Configuration.EnvironmentVariables.dll","path":"/usr/local/dotnet/7.0.302/shared/Microsoft.AspNetCore.App/7.0.5/Microsoft.Extensions.Configuration.EnvironmentVariables.dll","isOptimized":true,"isUserCode":false,"version":"7.00.22.51805","symbolStatus":"Cannot find or open the PDB file."}}}
<- (R) {"seq":313,"type":"response","request_seq":19,"success":true,"command":"scopes","body":{"scopes":[{"name":"Locals","variablesReference":1000,"expensive":false}]}}
-> (C) {"command":"variables","arguments":{"variablesReference":1000},"type":"request","seq":20}
<- (R) {"seq":314,"type":"response","request_seq":20,"success":false,"command":"variables","message":"Error processing 'variables' request. An exception was thrown from a debugger component."}
@jkone27 you should be able to set '--debug:portable' to generate portable symbols for the FSI session. That may also need '--multiemit' (which IIRC is the default) to emit each interaction as a separate assembly...
I tried these options a bit locally and still didn't get locals (but I may not have updated my initial comment here)
added Microsoft.Extensions.Configuration in open statement and nuget ref (in case that can add .pdb debug files), I see this exception at debug "startup" , not sure if related
<- (R) {"seq":69,"type":"response","request_seq":14,"success":true,"command":"variables","body":{"variables":[{"name":"$exception [InvalidOperationException]","value":
"{System.InvalidOperationException: Cannot see if a key has been pressed when either application does not have a console or when console input has been redirected from a file. Try Console.In.Peek.\n at System.Console.get_KeyAvailable()}","type":"System.InvalidOperationException","presentationHint":{"kind":"data","attributes":["canHaveObjectId","readOnly"]},
"evaluateName":"$exception","variablesReference":1001,"memoryReference":"0x00007EE2A144E2B0"},{"name":"console","value":"{FSharp.Compiler.Interactive.ReadLineConsole}",
"type":"FSharp.Compiler.Interactive.ReadLineConsole","presentationHint":{"kind":"data","attributes":["canHaveObjectId"]},"evaluateName":"console","variablesReference":1002,"memoryReference":"0x00007EE2A140E040"},{"name":"probeToSeeIfConsoleWorks [bool]","value":
"Cannot obtain value of the local variable or argument because it is not available at this instruction pointer, possibly because it has been optimized away.","type":"bool","presentationHint":{"attributes":["isBoolean","readOnly","failedEvaluation"]},"variablesReference":0}]}}
Sorry I see is in try catch so this seems for sure unrelated (?) probably
with --multiemit got this one instead :) seems related to Saturn lib
Exception has occurred: CLR/System.IO.FileNotFoundException
Exception thrown: 'System.IO.FileNotFoundException' in System.Private.CoreLib.dll: 'Could not load file or assembly '/home/codespace/.nuget/packages/saturn/0.16.1/lib/net6.0/Microsoft.Extensions.Logging.Abstractions.dll'. The system cannot find the file specified.'
at System.Runtime.Loader.AssemblyLoadContext.<LoadFromPath>g____PInvoke|5_0(IntPtr ptrNativeAssemblyBinder, UInt16* ilPath, UInt16* niPath, ObjectHandleOnStack retAssembly)
in my latest test run i cannot debug anymore, cannot open pdb files.. with the same settings, no breakpoints hit... regression.
Loaded '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/7.0.11/System.Private.CoreLib.dll'. Cannot find or open the PDB file.
Loaded '/usr/local/share/dotnet/sdk/7.0.401/FSharp/fsi.dll'.
Loaded '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/7.0.11/System.Runtime.dll'. Cannot find or open the PDB file.
Loaded '/usr/local/share/dotnet/sdk/7.0.401/FSharp/FSharp.Core.dll'.
Loaded '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/7.0.11/netstandard.dll'. Cannot find or open the PDB file.
Loaded '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/7.0.11/System.Console.dll'. Cannot find or open the PDB file.
Loaded '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/7.0.11/System.Threading.dll'. Cannot find or open the PDB file.
Loaded '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/7.0.11/System.Runtime.InteropServices.dll'. Cannot find or open the PDB file.
Unfortunately I don't think this is related to anything we control. This is probably an issue in fsi or the debugger for vscode itself.
Possibly relevant: https://github.com/dotnet/fsharp/issues/15820