PowerShell/src/System.Management.Automation/engine/debugger/Breakpoint.cs

615 lines
22 KiB
C#
Raw Normal View History

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Collections;
using System.IO;
using System.Linq;
using System.Management.Automation.Internal;
using System.Management.Automation.Language;
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
using System.Threading;
namespace System.Management.Automation
{
/// <summary>
/// Holds the information for a given breakpoint.
/// </summary>
public abstract class Breakpoint
{
#region properties
/// <summary>
/// The action to take when the breakpoint is hit.
/// </summary>
public ScriptBlock Action { get; }
/// <summary>
/// Gets whether this breakpoint is enabled.
/// </summary>
public bool Enabled { get; private set; }
internal void SetEnabled(bool value)
{
Enabled = value;
}
/// <summary>
/// Records how many times this breakpoint has been triggered.
/// </summary>
public int HitCount { get; private set; }
/// <summary>
/// This breakpoint's Id.
/// </summary>
public int Id { get; }
/// <summary>
/// True if breakpoint is set on a script, false if the breakpoint is not scoped.
/// </summary>
internal bool IsScriptBreakpoint
{
get { return Script != null; }
}
/// <summary>
/// The script this breakpoint is on, or null if the breakpoint is not scoped.
/// </summary>
public string Script { get; }
#endregion properties
#region constructors
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="Breakpoint"/>
/// </summary>
protected Breakpoint(string script)
: this(script, null)
2019-04-24 16:27:22 +02:00
{ }
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="Breakpoint"/>
/// </summary>
protected Breakpoint(string script, ScriptBlock action)
{
Enabled = true;
Script = string.IsNullOrEmpty(script) ? null : script;
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
Id = Interlocked.Increment(ref s_lastID);
Action = action;
HitCount = 0;
}
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="Breakpoint"/>
/// </summary>
protected Breakpoint(string script, int id)
: this(script, null, id)
2019-04-24 16:27:22 +02:00
{ }
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="Breakpoint"/>
/// </summary>
protected Breakpoint(string script, ScriptBlock action, int id)
{
Enabled = true;
Script = string.IsNullOrEmpty(script) ? null : script;
Id = id;
Action = action;
HitCount = 0;
}
#endregion constructors
#region methods
internal BreakpointAction Trigger()
{
++HitCount;
if (Action == null)
{
return BreakpointAction.Break;
}
try
{
// Pass this to the action so the breakpoint. This could be used to
// implement a "trigger once" breakpoint that disables itself after first hit.
// One could also share an action across many breakpoints - and hence needs
// to know something about the breakpoint that is hit, e.g. in a poor mans code coverage tool.
Action.DoInvoke(dollarUnder: this, input: null, args: Array.Empty<object>());
}
catch (BreakException)
{
return BreakpointAction.Break;
}
catch (Exception)
{
}
return BreakpointAction.Continue;
}
internal virtual bool RemoveSelf(ScriptDebugger debugger) => false;
#endregion methods
#region enums
internal enum BreakpointAction
{
Continue = 0x0,
Break = 0x1
}
#endregion enums
#region private members
private static int s_lastID;
#endregion private members
}
/// <summary>
/// A breakpoint on a command.
/// </summary>
public class CommandBreakpoint : Breakpoint
{
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="CommandBreakpoint"/>
/// </summary>
public CommandBreakpoint(string script, WildcardPattern command, string commandString)
: this(script, command, commandString, null)
2019-04-24 16:27:22 +02:00
{ }
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="CommandBreakpoint"/>
/// </summary>
public CommandBreakpoint(string script, WildcardPattern command, string commandString, ScriptBlock action)
: base(script, action)
{
CommandPattern = command;
Command = commandString;
}
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="CommandBreakpoint"/>
/// </summary>
public CommandBreakpoint(string script, WildcardPattern command, string commandString, int id)
: this(script, command, commandString, null, id)
2019-04-24 16:27:22 +02:00
{ }
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="CommandBreakpoint"/>
/// </summary>
public CommandBreakpoint(string script, WildcardPattern command, string commandString, ScriptBlock action, int id)
: base(script, action, id)
{
CommandPattern = command;
Command = commandString;
}
/// <summary>
/// Which command this breakpoint is on.
/// </summary>
public string Command { get; }
internal WildcardPattern CommandPattern { get; }
/// <summary>
/// Gets a string representation of this breakpoint.
/// </summary>
/// <returns>A string representation of this breakpoint.</returns>
public override string ToString()
{
return IsScriptBreakpoint
? StringUtil.Format(DebuggerStrings.CommandScriptBreakpointString, Script, Command)
: StringUtil.Format(DebuggerStrings.CommandBreakpointString, Command);
}
internal override bool RemoveSelf(ScriptDebugger debugger) =>
debugger.RemoveCommandBreakpoint(this);
private bool CommandInfoMatches(CommandInfo commandInfo)
{
if (commandInfo == null)
return false;
if (CommandPattern.IsMatch(commandInfo.Name))
return true;
// If the breakpoint looks like it might have specified a module name and the command
// we're checking is in a module, try matching the module\command against the pattern
// in the breakpoint.
2020-03-18 14:38:55 +01:00
if (!string.IsNullOrEmpty(commandInfo.ModuleName) && Command.Contains('\\'))
{
if (CommandPattern.IsMatch(commandInfo.ModuleName + "\\" + commandInfo.Name))
return true;
}
var externalScript = commandInfo as ExternalScriptInfo;
if (externalScript != null)
{
if (externalScript.Path.Equals(Command, StringComparison.OrdinalIgnoreCase))
return true;
if (CommandPattern.IsMatch(Path.GetFileNameWithoutExtension(externalScript.Path)))
return true;
}
return false;
}
internal bool Trigger(InvocationInfo invocationInfo)
{
// invocationInfo.MyCommand can be null when invoked via ScriptBlock.Invoke()
if (CommandPattern.IsMatch(invocationInfo.InvocationName) || CommandInfoMatches(invocationInfo.MyCommand))
{
return (Script == null || Script.Equals(invocationInfo.ScriptName, StringComparison.OrdinalIgnoreCase));
}
Code cleanup: Add space after closing brace where needed (#8530) * Update TestService * Update WebListener * Update Controllers * Update ExpTest * Update MyApp * Update Logic * Update Logic * Update MyApp * Update Microsoft.Management.Infrastructure.CimCmdlets * Update Microsoft.PowerShell.Commands.Diagnostics * Update Microsoft.PowerShell.ScheduledJob * Update Microsoft.WSMan.Management * Update Microsoft.WSMan.Runtime * Update ResGen * Update TypeCatalogGen * Update commands * Update Eventing * Update Reader * Update utility * Update ShowCommand * Update trace * Update WebCmdlet * Update Common * Update CoreCLR * Update common * Update format-object * Update format-wide * Update out-file * Update out-printer * Update out-string * Update OutGridView * Update LocalAccounts * Update Commands * Update security * Update CoreCLR * Update DscSupport * Update engine * Update help * Update logging * Update namespaces * Update security * Update utils * Update config * Update perfCounters * Update tracing * Update cmdletization * Update other * Update cim * Update xml * Update CoreCLR * Update common * Update DefaultFormatters * Update out-console * Update out-textInterface * Update DisplayDatabase * Update Utilities * Update COM * Update ComInterop * Update CommandCompletion * Update debugger * Update ExperimentalFeature * Update hostifaces * Update interpreter * Update lang * Update Modules * Update parser * Update runtime * Update client * Update commands * Update common * Update fanin * Update server * Update WireDataFormat * Update Binding * Update Operations * Update interface * Update cmdletization * Update cim * Update management * Update WindowsTaskbarJumpList * Update msh
2018-12-24 07:20:06 +01:00
return false;
}
}
/// <summary>
/// The access type for variable breakpoints to break on.
/// </summary>
public enum VariableAccessMode
{
/// <summary>
/// Break on read access only.
/// </summary>
Read,
/// <summary>
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// Break on write access only (default).
/// </summary>
Write,
/// <summary>
/// Breakon read or write access.
/// </summary>
ReadWrite
}
/// <summary>
/// A breakpoint on a variable.
/// </summary>
public class VariableBreakpoint : Breakpoint
{
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="VariableBreakpoint"/>.
/// </summary>
public VariableBreakpoint(string script, string variable, VariableAccessMode accessMode)
: this(script, variable, accessMode, null)
2019-04-24 16:27:22 +02:00
{ }
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="VariableBreakpoint"/>.
/// </summary>
public VariableBreakpoint(string script, string variable, VariableAccessMode accessMode, ScriptBlock action)
: base(script, action)
{
Variable = variable;
AccessMode = accessMode;
}
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="VariableBreakpoint"/>.
/// </summary>
public VariableBreakpoint(string script, string variable, VariableAccessMode accessMode, int id)
: this(script, variable, accessMode, null, id)
2019-04-24 16:27:22 +02:00
{ }
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="VariableBreakpoint"/>.
/// </summary>
public VariableBreakpoint(string script, string variable, VariableAccessMode accessMode, ScriptBlock action, int id)
: base(script, action, id)
{
Variable = variable;
AccessMode = accessMode;
}
/// <summary>
/// The access mode to trigger this variable breakpoint on.
/// </summary>
public VariableAccessMode AccessMode { get; }
/// <summary>
/// Which variable this breakpoint is on.
/// </summary>
public string Variable { get; }
/// <summary>
/// Gets the string representation of this breakpoint.
/// </summary>
/// <returns>The string representation of this breakpoint.</returns>
public override string ToString()
{
return IsScriptBreakpoint
? StringUtil.Format(DebuggerStrings.VariableScriptBreakpointString, Script, Variable, AccessMode)
: StringUtil.Format(DebuggerStrings.VariableBreakpointString, Variable, AccessMode);
}
internal bool Trigger(string currentScriptFile, bool read)
{
if (!Enabled)
return false;
if (AccessMode != VariableAccessMode.ReadWrite && AccessMode != (read ? VariableAccessMode.Read : VariableAccessMode.Write))
return false;
if (Script == null || Script.Equals(currentScriptFile, StringComparison.OrdinalIgnoreCase))
{
return Trigger() == BreakpointAction.Break;
}
return false;
}
internal override bool RemoveSelf(ScriptDebugger debugger) =>
debugger.RemoveVariableBreakpoint(this);
}
/// <summary>
/// A breakpoint on a line or statement.
/// </summary>
public class LineBreakpoint : Breakpoint
{
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="LineBreakpoint"/>
/// </summary>
public LineBreakpoint(string script, int line)
: this(script, line, null)
2019-04-24 16:27:22 +02:00
{ }
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="LineBreakpoint"/>
/// </summary>
public LineBreakpoint(string script, int line, ScriptBlock action)
: base(script, action)
{
Diagnostics.Assert(!string.IsNullOrEmpty(script), "Caller to verify script parameter is not null or empty.");
Line = line;
Column = 0;
SequencePointIndex = -1;
}
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="LineBreakpoint"/>
/// </summary>
public LineBreakpoint(string script, int line, int column)
: this(script, line, column, null)
2019-04-24 16:27:22 +02:00
{ }
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="LineBreakpoint"/>
/// </summary>
public LineBreakpoint(string script, int line, int column, ScriptBlock action)
: base(script, action)
{
Diagnostics.Assert(!string.IsNullOrEmpty(script), "Caller to verify script parameter is not null or empty.");
Line = line;
Column = column;
SequencePointIndex = -1;
}
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="LineBreakpoint"/>
/// </summary>
public LineBreakpoint(string script, int line, int column, int id)
: this(script, line, column, null, id)
2019-04-24 16:27:22 +02:00
{ }
New `New-PSBreakpoint` cmdlet & new `-Breakpoint` parameter for `Debug-Runspace` (#8923) This PR does 4 things: * Adds a new cmdlet `New-PSBreakpoint` which creates new `Breakpoint` objects and writes them to the pipeline * Adds a `-Breakpoint` parameter to `Debug-Runspace` which will receive `Breakpoint` objects * Makes the constructors for `*Breakpoint` public for use with the API * Makes `Debugger.GetBreakpoint(string id)` and `Debugger.GetBreakpoints()` public since `SetBreakpoints` is public Note: `New-PSBreakpoint` and `Set-PSBreakpoint` (which already exists) are similar... but `Set-PSBreakpoint` also sets the breakpoints in the _current_ runspace. This is not ideal if we want to set breakpoints in a _different runspace than the current one_. ## PR Context The "Attach to process" debugging experience in the PowerShell extension for VSCode is _ok_ but it's not great. The reason it's not great is due to the `BreakAll` feature of PowerShell debugging which, when you run `Debug-Runspace`, will break at the first piece of code that gets run. This is not ideal when you "Attach to process" _and then_ run your code in the other runspace. Today, the experience drops you in `PSReadLine`'s psm1 if PSRL is available or in the vscode PowerShell helper psm1. It's unexpected for the user and not ideal. This PR will allow the extension to pass in the breakpoints that need to be set initially with `BreakAll` turned off for none of this silly behavior. ### Silly behavior example If you want a repro, try this: PowerShell instance 1: ``` Enter-PSHostProcess -Id $otherprocesspid Debug-Runspace 1 ``` PowerShell instance 2: ``` ./runfoo.ps1 ``` Note that you end up NOT `runfoo.ps1`
2019-04-14 04:14:53 +02:00
/// <summary>
/// Creates a new instance of a <see cref="LineBreakpoint"/>
/// </summary>
public LineBreakpoint(string script, int line, int column, ScriptBlock action, int id)
: base(script, action, id)
{
Diagnostics.Assert(!string.IsNullOrEmpty(script), "Caller to verify script parameter is not null or empty.");
Line = line;
Column = column;
SequencePointIndex = -1;
}
/// <summary>
/// Which column this breakpoint is on.
/// </summary>
public int Column { get; }
/// <summary>
/// Which line this breakpoint is on.
/// </summary>
public int Line { get; }
/// <summary>
/// Gets a string representation of this breakpoint.
/// </summary>
/// <returns>A string representation of this breakpoint.</returns>
public override string ToString()
{
return Column == 0
? StringUtil.Format(DebuggerStrings.LineBreakpointString, Script, Line)
: StringUtil.Format(DebuggerStrings.StatementBreakpointString, Script, Line, Column);
}
internal int SequencePointIndex { get; set; }
internal IScriptExtent[] SequencePoints { get; set; }
internal BitArray BreakpointBitArray { get; set; }
private sealed class CheckBreakpointInScript : AstVisitor
{
public static bool IsInNestedScriptBlock(Ast ast, LineBreakpoint breakpoint)
{
var visitor = new CheckBreakpointInScript { _breakpoint = breakpoint };
ast.InternalVisit(visitor);
return visitor._result;
}
private LineBreakpoint _breakpoint;
private bool _result;
public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)
{
if (functionDefinitionAst.Extent.ContainsLineAndColumn(_breakpoint.Line, _breakpoint.Column))
{
_result = true;
return AstVisitAction.StopVisit;
}
// We don't need to visit the body, we're just checking extents of the topmost functions.
// We'll visit the bodies eventually, but only when the nested function/script is executed.
return AstVisitAction.SkipChildren;
}
public override AstVisitAction VisitScriptBlockExpression(ScriptBlockExpressionAst scriptBlockExpressionAst)
{
if (scriptBlockExpressionAst.Extent.ContainsLineAndColumn(_breakpoint.Line, _breakpoint.Column))
{
_result = true;
return AstVisitAction.StopVisit;
}
// We don't need to visit the body, we're just checking extents of the topmost functions.
// We'll visit the bodies eventually, but only when the nested function/script is executed.
return AstVisitAction.SkipChildren;
}
}
internal bool TrySetBreakpoint(string scriptFile, FunctionContext functionContext)
{
Diagnostics.Assert(SequencePointIndex == -1, "shouldn't be trying to set on a pending breakpoint");
if (!scriptFile.Equals(this.Script, StringComparison.OrdinalIgnoreCase))
return false;
// A quick check to see if the breakpoint is within the scriptblock.
bool couldBeInNestedScriptBlock;
var scriptBlock = functionContext._scriptBlock;
if (scriptBlock != null)
{
var ast = scriptBlock.Ast;
if (!ast.Extent.ContainsLineAndColumn(Line, Column))
return false;
var sequencePoints = functionContext._sequencePoints;
if (sequencePoints.Length == 1 && sequencePoints[0] == scriptBlock.Ast.Extent)
{
// If there was no real executable code in the function (e.g. only function definitions),
// we added the entire scriptblock as a sequence point, but it shouldn't be allowed as a breakpoint.
return false;
}
couldBeInNestedScriptBlock = CheckBreakpointInScript.IsInNestedScriptBlock(((IParameterMetadataProvider)ast).Body, this);
}
else
{
couldBeInNestedScriptBlock = false;
}
int sequencePointIndex;
var sequencePoint = FindSequencePoint(functionContext, Line, Column, out sequencePointIndex);
if (sequencePoint != null)
{
// If the bp could be in a nested script block, we want to be careful and get the bp in the correct script block.
// If it's a simple line bp (no column specified), then the start line must match the bp line exactly, otherwise
// we assume the bp is in the nested script block.
if (!couldBeInNestedScriptBlock || (sequencePoint.StartLineNumber == Line && Column == 0))
{
SetBreakpoint(functionContext, sequencePointIndex);
return true;
}
}
// Before using heuristics, make sure the breakpoint isn't in a nested function/script block.
if (couldBeInNestedScriptBlock)
{
return false;
}
// Not found. First, we check if the line/column is before any real code. If so, we'll
// move the breakpoint to the first interesting sequence point (could be a dynamicparam,
// begin, process, or end block.)
if (scriptBlock != null)
{
var ast = scriptBlock.Ast;
var bodyAst = ((IParameterMetadataProvider)ast).Body;
if ((bodyAst.DynamicParamBlock == null || bodyAst.DynamicParamBlock.Extent.IsAfter(Line, Column)) &&
(bodyAst.BeginBlock == null || bodyAst.BeginBlock.Extent.IsAfter(Line, Column)) &&
(bodyAst.ProcessBlock == null || bodyAst.ProcessBlock.Extent.IsAfter(Line, Column)) &&
(bodyAst.EndBlock == null || bodyAst.EndBlock.Extent.IsAfter(Line, Column)))
{
SetBreakpoint(functionContext, 0);
return true;
}
}
// Still not found. Try fudging a bit, but only if it's a simple line breakpoint.
if (Column == 0 && FindSequencePoint(functionContext, Line + 1, 0, out sequencePointIndex) != null)
{
SetBreakpoint(functionContext, sequencePointIndex);
return true;
}
return false;
}
private static IScriptExtent FindSequencePoint(FunctionContext functionContext, int line, int column, out int sequencePointIndex)
{
var sequencePoints = functionContext._sequencePoints;
for (int i = 0; i < sequencePoints.Length; ++i)
{
var extent = sequencePoints[i];
if (extent.ContainsLineAndColumn(line, column))
{
sequencePointIndex = i;
return extent;
}
}
sequencePointIndex = -1;
return null;
}
private void SetBreakpoint(FunctionContext functionContext, int sequencePointIndex)
{
// Remember the bitarray so we when the last breakpoint is removed, we can avoid
// stopping at the sequence point.
this.BreakpointBitArray = functionContext._breakPoints;
this.SequencePoints = functionContext._sequencePoints;
SequencePointIndex = sequencePointIndex;
this.BreakpointBitArray.Set(SequencePointIndex, true);
}
internal override bool RemoveSelf(ScriptDebugger debugger)
{
if (this.SequencePoints != null)
{
// Remove ourselves from the list of bound breakpoints in this script. It's possible the breakpoint was never
// bound, in which case there is nothing to do.
var boundBreakPoints = debugger.GetBoundBreakpoints(this.SequencePoints);
if (boundBreakPoints != null)
{
Diagnostics.Assert(boundBreakPoints.Contains(this),
"If we set _scriptBlock, we should have also added the breakpoint to the bound breakpoint list");
boundBreakPoints.Remove(this);
if (boundBreakPoints.All(breakpoint => breakpoint.SequencePointIndex != this.SequencePointIndex))
{
// No other line breakpoints are at the same sequence point, so disable the breakpoint so
// we don't go looking for breakpoints the next time we hit the sequence point.
// This isn't strictly necessary, but script execution will be faster.
this.BreakpointBitArray.Set(SequencePointIndex, false);
}
}
}
Code cleanup: Add space after closing brace where needed (#8530) * Update TestService * Update WebListener * Update Controllers * Update ExpTest * Update MyApp * Update Logic * Update Logic * Update MyApp * Update Microsoft.Management.Infrastructure.CimCmdlets * Update Microsoft.PowerShell.Commands.Diagnostics * Update Microsoft.PowerShell.ScheduledJob * Update Microsoft.WSMan.Management * Update Microsoft.WSMan.Runtime * Update ResGen * Update TypeCatalogGen * Update commands * Update Eventing * Update Reader * Update utility * Update ShowCommand * Update trace * Update WebCmdlet * Update Common * Update CoreCLR * Update common * Update format-object * Update format-wide * Update out-file * Update out-printer * Update out-string * Update OutGridView * Update LocalAccounts * Update Commands * Update security * Update CoreCLR * Update DscSupport * Update engine * Update help * Update logging * Update namespaces * Update security * Update utils * Update config * Update perfCounters * Update tracing * Update cmdletization * Update other * Update cim * Update xml * Update CoreCLR * Update common * Update DefaultFormatters * Update out-console * Update out-textInterface * Update DisplayDatabase * Update Utilities * Update COM * Update ComInterop * Update CommandCompletion * Update debugger * Update ExperimentalFeature * Update hostifaces * Update interpreter * Update lang * Update Modules * Update parser * Update runtime * Update client * Update commands * Update common * Update fanin * Update server * Update WireDataFormat * Update Binding * Update Operations * Update interface * Update cmdletization * Update cim * Update management * Update WindowsTaskbarJumpList * Update msh
2018-12-24 07:20:06 +01:00
return debugger.RemoveLineBreakpoint(this);
}
}
}