protected void RebuildNamespaceAndSetLocationBasedOnDebuggerContext(bool outputRegisters,
                                                                            DbgRegisterSetBase baselineRegisters)
        {
            string newCurrentPath = DbgProvider.SetLocationByDebuggerContext();

            if (outputRegisters && (null != newCurrentPath))
            {
                // This basically just removes the leading whack.
                string providerPath = SessionState.Path.GetUnresolvedProviderPathFromPSPath(newCurrentPath);
                var    regSet       = DbgProvider.GetRegisterSetForPath(providerPath, baselineRegisters);
                if (null != regSet)
                {
                    // TODO: Set ReadDbgAssemblyCommand.NextAddrToDisassemble here? (and the others)
                    SafeWriteObject(regSet);
                }
            }
        } // end SetLocationBasedOnDebuggerContext()
Пример #2
0
        protected override void ProcessRecord()
        {
            using (SetDebuggerAndContextAndUpdateCallbacks())
            {
                EnsureTargetCanStep(Debugger);

                // In the native debugger, if you are in some other frame, your scope
                // is reset (to the top frame), but not your thread.
                Debugger.SetCurrentScopeFrame(0);

                switch (ResumeType)
                {
                case Dbg.ResumeType.ReverseStepBranch:
                case Dbg.ResumeType.ReverseStepInto:
                case Dbg.ResumeType.ReverseStepOver:
                case Dbg.ResumeType.StepBranch:
                case Dbg.ResumeType.StepInto:
                case Dbg.ResumeType.StepOver:
                case Dbg.ResumeType.StepOut:
                case Dbg.ResumeType.StepToCall:
                    m_baselineRegisters = DbgRegisterSetBase.GetRegisterSet(Debugger);
                    break;
                }

                if (ResumeType.Passive != ResumeType)
                {
                    try
                    {
                        Debugger.ResumeExecution(ResumeType);
                    }
                    catch (DbgEngAlreadyRunningException)
                    {
                        SafeWriteWarning("Target has already been resumed.");
                        //
                        // We'll just proceed, then, to wait...
                        //
                    }
                }

                bool noException = false;
                try
                {
                    Debugger.BreakpointHit += Debugger_BreakpointHit;

                    if (DbgProvider.IsInBreakpointCommand)
                    {
                        Util.Assert(DbgProvider.EntryDepth > 0);

                        // If we are executing as a breakpoint command, and someone is
                        // resuming execution, we have to handle it specially:
                        //
                        // 1. We need to cancel the rest of the pipeline. This is the same
                        //    way that dbgeng breakpoint commands work (if your bp command
                        //    is "!foo;g;!bar", then !bar will not ever be executed.
                        //
                        //    At first glance you might think that you are getting robbed
                        //    of some cool power by canceling any remaining commands, but
                        //    if you think a little more about it, you realize it would be
                        //    very difficult to reason about what should happen. For
                        //    example, consider:
                        //
                        //       bp myDll!Foo "!stuff ; g ; !otherStuff"
                        //
                        //    The first time you hit the breakpoint, "!stuff" is run, then
                        //    execution is resumed. The seocnd time the breakpoint is
                        //    hit... what should be run first--"!otherStuff", or "!stuff"?
                        //    And you could get nested much further. So we'll take the
                        //    same easy out as dbgeng, and treat "g" as an "exit" in a
                        //    breakpoint command.
                        //
                        //    TODO: we could run the script through the parser and warn
                        //    about unreachable code after a "g" command.
                        //
                        // 2. When a breakpoint hits and a breakpoint command is run, the
                        //    dbgeng thread is blocked, waiting for the breakpoint command
                        //    to finish. If we want to resume execution from within a
                        //    breakpoint command, we can tell dbgeng to resume, but if we
                        //    then turn around and call WaitForEvent (which is what we
                        //    normally do), then you're deadlocked--WaitForEvent can never
                        //    return, because before dbgeng can let the target resume,
                        //    your breakpoint command has to return, but it can't return
                        //    because it's waiting for WaitForEvent.
                        //
                        //    So in this case, once we've instructed dbgeng to execute, we
                        //    need to return from the command and let dbgeng let the
                        //    target resume. We will depend on the "host" (whether it be
                        //    windbg or DbgShell or something else) to do the
                        //    WaitForEvent. Fortunately, "exit" should get us what we want
                        //    for this case, too.
                        //
                        //    TODO: what if we are nested a few levels deep? i.e.
                        //
                        //       bp myDll!foo "!dbgshell -Bp !dbgshell write-host 'so nested!' -fore Yellow , g"
                        //
                        //    I'm not sure how we'd get the "exit" to propagate out from
                        //    the inner !dbgshell, through the outer one, so that we could
                        //    return to the host.
                        //
                        //    Also, if we are nested, and multiple levels use -Bp, we're
                        //    definitely broken--I'd need to change inBreakpointCommand to
                        //    be a count instead of a bool, for one thing.
                        //

                        if (null != m_baselineRegisters)  // <-- shortcut for determining if we are stepping
                        {
                            // If someone is trying to step while inside a breakpoint
                            // command, let's let them know what's going on.
                            this.InvokeCommand.InvokeScript("Write-Host 'Resuming execution from within a breakpoint " +
                                                            "command necessarily returns control to the host, for it " +
                                                            "to perform the wait.' -Fore Cyan");
                            this.InvokeCommand.InvokeScript("Write-Host '(it also acts like an 'exit'; terminating the " +
                                                            "current pipeline and discarding any remaining commands)' " +
                                                            " -Fore Cyan");
                            this.InvokeCommand.InvokeScript("Write-Host '(if you want to step in DbgShell instead of " +
                                                            "the host, just run !dbgshell again from the host and then " +
                                                            "step)' -Fore Cyan");

                            // Give them a chance to notice that a message was printed out
                            // before we switch the foreground window:
                            this.InvokeCommand.InvokeScript("Start-Sleep -Milliseconds 500");
                        }

                        if (!DbgProvider.IsInGuestMode)
                        {
                            // If DbgShell.exe is the host, then we need to let it know
                            // that it shouldn't exit all the way; we're just trying to
                            // terminate the current breakpoint script.
                            DbgProvider.DontExitAllTheWay = true;
                        }

                        // Throwing an ExitException would be much more direct, but there
                        // are no public constructors for it.
                        //throw new ExitException();
                        this.InvokeCommand.InvokeScript("exit");
                    }

                    base.ProcessRecord(); // sets up ctrl-c interception, performs wait.
                    noException = true;
                }
                finally
                {
                    Debugger.BreakpointHit -= Debugger_BreakpointHit;

                    _TryRemoveSpecialBp();

                    // We check NoTarget before setting the auto-repeat command, because
                    // if -skipFinalBreakpoint was used, the target might be completely
                    // gone (leaving you back with a working dir of "Dbg:\"), and it would
                    // be nice if hitting [ENTER] for a newline right there didn't try to
                    // auto-repeat your last "g" command (which would blow up with a "no
                    // target!" error).
                    if (noException && !Debugger.NoTarget)
                    {
                        DbgProvider.SetAutoRepeatCommand(MyInvocation.Line.Trim());
                    }
                }
                if (null != m_bea)
                {
                    // if( m_bea.Breakpoint.IsValid )
                    //     Console.WriteLine( "Breakpoint hit. The command was: {0}", m_bea.Breakpoint.Command );
                    // else
                    //     Console.WriteLine( "Breakpoint hit. (breakpoint no longer valid)" );

                    // TODO: Idea: I could accept ScriptBlocks as commands to be executed, and store
                    // them with dbgeng in the form of a string identifier, like "ScriptBlock_NNNN",
                    // or probably better, "!dbgshell ScriptBlock_NNNN". I need to figure out what
                    // happens with the breakpoint command when I'm just a debugger client.
                }
            }
        } // end ProcessRecord()
 protected void RebuildNamespaceAndSetLocationBasedOnDebuggerContext(DbgRegisterSetBase baselineRegisters)
 {
     RebuildNamespaceAndSetLocationBasedOnDebuggerContext(true, baselineRegisters);
 }