-
Notifications
You must be signed in to change notification settings - Fork 508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Debug Support for Any Exceptions and Uncaught Exceptions #298
Comments
I'm not sure how this would work in the case of PowerShell. What do you think, @rkeithhill? |
I've wanted this for a while but I think PowerShell would need to be modified to support this. Who's the debugger expert on the team? Paul H? FYI, I filed a UserVoice suggestion on this back in March - please vote it up: https://windowsserver.uservoice.com/forums/301869-powershell/suggestions/12843021-enhance-set-psbreakpoint-to-allow-us-to-set-except |
Yep, @PaulHigin is the PowerShell debugging expert. |
This is a fairly common request and something we have in our backlog, but is impossible to implement with our current script debugger. The reason is that the script debugger runs on the script execution thread and requires running script to work. But once an exception is thrown on the script execution thread the script is no longer running and the script debugger no longer works. At this point you need a managed/native debugger. We could have script debugger break for non-terminating errors since script execution continues and the script debugger is working. But I am not sure how useful that would be. Jason, @lzybkr, has experimented with a mixed managed code/script debugger and it would be ideal for this kind of thing. When the managed exception is thrown this debugger could show both managed and PowerShell script stacks. |
The mixed code/script debugger would be extremely nice to have and would be pretty easy to surface in VS Code. |
That prototype generated a pdb and code that the C# debugger could consume - it was useful, but not a PowerShell experience. |
@PaulHigin What do you think about this workaround by @nightroman? https://github.com/nightroman/PowerShelf/blob/master/Debug-Error.ps1 |
Very clever. I like it. But I believe this just handles the case where PowerShell is throwing the exception (either through throw keyword or -ErrorAction Stop). @lzybkr can you confirm? I was thinking in terms of a general exception being thrown in managed code. Still this looks to be very useful and something we could support internally. |
Unfortunately, |
Any movement on this? At the moment I'm reduced to stepping through my module (and all of its dependencies) line by line trying to find where the exception is being thrown. Or adding a load of Write-Host statements to see which ones get hit. |
There is a way to break before the terminating error is thrown, but after it's been written to Set-PSBreakpoint -Variable StackTrace -Mode Write -Action {
$null = Set-PSBreakpoint -Variable ErrorActionPreference -Mode Read
}
throw 'test'
# In debugger:
$Error[0]
# Returns:
# test
# At line:1 char:1
# + throw 'test'
# + ~~~~~~~~~~~~
# + CategoryInfo : OperationStopped: (test:String) [], RuntimeException
# + FullyQualifiedErrorId : test After For this to be reliable you would need to store state between the two breakpoints to ensure they fire on the same sequence point (in case the script later reads the preference directly). It would also need to handle situations where the break point already exists and be able to remove itself after the first hit. I'll start looking into the feasibility of adding support for this. |
To follow up on @SeeminglyScience's work:
Effective Workaround |
OK, I've come up with a pretty effective function to break on exceptions in lieu of a proper implementation (PowerShell/PowerShell#2830) https://gist.github.com/JustinGrote/52cf75ea75f2888dbaf4b0c86519d0a6 Features
Quick Start
Example launch.json entry{
"name": "PowerShell Trap Exceptions",
"type": "PowerShell",
"request": "launch",
"script": "Debug-OnException",
"args": [
"${file}"
],
"cwd": "${file}"
} DemosVSCode Unsaved FileVSCode Run Selection (F8)Foreach LoopForeach (More Real-World Example)Exception Inside ModuleAzure Cloud ShellPowershell 5 (Windows Terminal, Works in VSCode too)VSCode Extension IntegrationWill need help here as I suck at typescript. The script itself or the breakpoints it generates need to be wired up to a custom breakpoint "Terminating Exceptions" per @sgtoj's example. @TylerLeonhardt @SeeminglyScience @rjmholt maybe? |
@JustinGrote thanks for all your work here, this looks great. The change here will need to happen in Editor Services, probably in this chunk of code , using this https://microsoft.github.io/debug-adapter-protocol/specification#Requests_SetExceptionBreakpoints ....it would be awesome if you opened up a PR in that repo and we can help you iron out the details...Thanks! |
The script @JustinGrote created did not helps if the code itself also throws exceptions that are catched by intention. The script terminates in that case, where it would continue without the script.
and placed a breakpoint in that trap. This worked perfectly for me. |
There is also a PR to PowerShell 7 to specifically add this functionality to set-breakpoint, so it will be easier to support going forward. |
Three years later ... But hey, I'll be happy to finally have this support in the PS engine. :-) |
Hopefully, that can be configured. Debuggers typically over the ability break on both unhandled ( |
Not yet. I break into the debugger the moment the exception is raised. I'll have to think about how that could be done. The only thing that comes to mind at the moment is reverse traversal of the AST to check for traps or catch blocks, but figuring out what handles what via inspection could be pretty complicated. Actually, how would that even be possible in an interpreted language? How could I reliably identify that a catch all does or does not handle an exception, for example, when variables used in that catch all could come from anywhere? |
I think a exception could be considered unhandled when it reaches this code block in |
@SeeminglyScience: Even if that would work, I'm also concerned about the user experience. Today If we defer entering the debugger for unhandled exceptions until such a time that we know the exception is considered unhandled, where are we in our call stack? We may have unwound quite a bit to get to that point. IMHO it is far better for this community to bring users to the origin of the exception, so that they can understand what is going on. That said, I'm all for efficient debugging (it's something I continue to actively work on in many areas), so I'd like to offer both, but I would want to do so with the debugger still breaking at the point of exception. We could do more work in the script block compiler so that we know the explicit types of exceptions that can be caught when an exception is first raised, to identify whether or not that exception is going to be handled, but then I'm not sure how to reliably identify if a catch all will handle an exception or not. |
Maybe, but the snippet I linked is at the end of a very long chain of try/catch's. With some experimentation you can probably find one where the stack is mostly intact and you can still determine if it's unhandled. |
Now that Powershell 7 is out, perhaps it's as "easy" as just wiring up the "Uncaught Exceptions" button to set ErrorActionPreference = 'break' for now? My current "workaround" is: @SeeminglyScience @KirkMunro @rkeithhill I'll be able to take a stab at a PR in a couple weeks, knowing basically no Typescript and just enough C# to read it and interpret it into powershell :). |
Very happy to help with that. The hard won't be the language as much as navigating the code, but I think we have a fair idea of where things should go. |
The other hard part is managing the version-specificity. It's a pain writing code that works in 7 but fails gracefully and informatively in older PowerShells. |
@KirkMunro do you know if there's a way to only break on uncaught errors? Or otherwise determine that an error was uncaught? Also determine whether the error was terminating? Right now it's all errors, even if caught. That's still awesome and way better than no error breakpoints period though. |
@SeeminglyScience You're right! For some reason I thought it was working on uncaught exceptions only. Sounds like more of a upstream (Powershell) bug to me, since ErrorActionPreference = 'stop' doesn't stop on uncaught exceptions so the behavior is inconsistent. |
@JustinGrote Yeah for sure, there's still great value in enabling "All Exceptions". |
Do you mean If so, what really happens is that it does "Stop" (by which I mean throw a terminating error), but then that error is caught. To change the behaviour of Anyway, didn't mean to sidetrack you. |
My thought here is to add something to the compiler to emit something when processing a Edit: You were talking about |
[Aside]
I noticed this comment because I'm looking for a way to step through C# in my own PS module (dll) called by PowerShell script being debugged in vscode-powershell. At the moment I can't debug the PowerShell and C# together so @lzybkr if you ever chose to make available something that supports this I'd be grateful for one. 😊 |
@markm77 you are able to have the PowerShell debugger and C# debugger running at the same time.... so feasibly you can launch debug a PowerShell script and attach the C# debugger... but it doesn't give you the ideal behavior of "stepping into C# from PowerShell". |
@markm77 - mixed debugging is a little painful but possible today if you attach a C# debugger, set breakpoints where you care about, then debug the PowerShell code with the PowerShell debugger. You don't get a nice shared stack but it's better than nothing. My prototypes were based on the Desktop version of .Net, I have no idea if they are even possible now. |
Thanks guys for interesting comments. To do mixed debugging do I have to re-attach the debugger each time the PowerShell script calls into a C# module cmdlet? Or can I attach the debugger just once following module import and it will re-attach as the DLL is called (much better)? Also is there any recommended way for dropping the lock on the DLL to allow DLL re-build following any C# update? At the moment I run pwsh inside PowerShell before module import, then run exit to drop the lock on the DLL before C# re-build. Cheers! |
Attaching once is fine, but you must exit the process to rebuild - this is a limitation in .Net. |
Thanks! I think I'm going to experiment with debugging an outer PS script that calls pwsh to do the import and run the inner PS script, hopefully the PowerShell debugger can hop to the inner process.... Otherwise I'll set up VS Code tasks. Have a great day! |
I'm not sure if I get the current situation right … According to https://github.com/PowerShell/PowerShell/issues/2830, PowerShell seems to now support breaking into the debugger on uncaught exceptions. Yet, I can't find this working in the current version of VS Code PowerShell extension. I have written a recursive function and I have no clue what's causing a "Collection was modified; enumeration operation may not execute." error without seeing the current stack trace and variable values. |
@SetTrend I don't know if we've wired up the button specifically but if you do @SeeminglyScience has a breakpoint PR we are waiting that changes a lot of things that we are waiting on before we make any breakpoint feature changes. |
Is it possible to debug support to enable break points for: Any Exceptions or Uncaught Exceptions?
The text was updated successfully, but these errors were encountered: