예제 #1
0
        } // end _NormalModeMainWrapper()

        private static int _GuestAndHostModeMainWrapper(ExceptionGuard entryPointStateDisposer,
                                                        string[] args)
        {
            // We should have two things:
            //    args[ 0 ]: "shareConsole"
            //    args[ 1 ]: command args should all should get passed in one big string.
            //
            // Unlike plain guest mode, we know we are "sharing" the console (because
            // DbgShell.exe is the host!), but it's convenient for the caller to still
            // pass the console ownership arg.
            Util.Assert(2 == args.Length);

            if (0 != StringComparer.Ordinal.Compare(args[0], c_guestModeShareConsole))
            {
                var msg = "Unexpected arg: I expected to see \"shareConsole\".";
                Util.Fail(msg);
                throw new Exception(msg);
            }

            //
            // We're getting called on the dbgeng thread, which should be a background
            // thread, but the API we use from DbgShellExt.dll (RunAssembly) causes this
            // thread to get marked as non-background, so we need to put that back.
            //
            Thread.CurrentThread.IsBackground = true;

            try
            {
                // We'll always pretend it's the first time for the purpose of parsing
                // arguments--on the one hand, -NoProfile doesn't make sense (it can't
                // /ever/ make sense in guestAndHostMode; the profile was run or not
                // when DbgShell.exe started), but we don't want to warn about it.
                //
                // TODO: Is that the right decision?

                bool   noProfile;
                bool   inBreakpointCommand;
                string command = _ParseGuestModeArgs(args[1],
                                                     /* firstTime = */ true,
                                                     out noProfile,
                                                     out inBreakpointCommand);

                if (inBreakpointCommand && !DbgProvider.IsInBreakpointCommand)
                {
                    DbgProvider.IsInBreakpointCommand = true;
                    entryPointStateDisposer.Protect((Disposable)(() => DbgProvider.IsInBreakpointCommand = false));
                }

                // Re-entrant case: DbgShell is already running, but something called
                // the debugger "!dbgshell" extension command (for instance, a
                // breakpoint command).
                LogManager.Trace("_GuestAndHostModeMainWrapper: re-entering (entryDepth: {0}).", DbgProvider.EntryDepth);
                if (null == DbgProvider.CurrentActionQueue)
                {
                    var msg = "(_GuestAndHostModeMainWrapper) DbgShell is already running, but I don't have a CurrentActionQueue to inject commands.";
                    Util.Fail(msg);
                    throw new Exception(msg);
                }
                var transferTicket = entryPointStateDisposer.Transfer();
                DbgProvider.CurrentActionQueue.PostCommand((cii) =>
                {
                    // TODO: BUGBUG: I need to do something here to separate CTRL+C
                    // handling for 'command' versus the cmdlet that is running the
                    // CurrentActionQueue. That is, if we post a command here that
                    // does a naked "Get-Content", it will prompt you for a path, and
                    // if you then do a CTRL+C, I want it to only cancel 'command',
                    // not the entire pipeline including the Resume-Exection command
                    // or whatever it is that is running the CurrentActionQueue.
                    //
                    // Besides just to behave as the user wants/expects, it throws a
                    // wrench in things for execution commands to get canceled--it's
                    // very important, so they do their own CTRL+C handling.
                    using (transferTicket.Redeem())
                    {
                        LogManager.Trace("Executing injected (reentrant) commands:");
                        LogManager.Trace(command.Replace("\n", "\n > "));
                        cii.InvokeScript(command,
                                         false,
                                         PipelineResultTypes.Error |
                                         PipelineResultTypes.Output,
                                         sm_noInput);
                    }     // end using( new disposer )
                });
                transferTicket.CommitTransfer();

                LogManager.Trace("_GuestAndHostModeMainWrapper: returning {0}.",
                                 Util.FormatErrorCode(sm_exitCode));
                return(sm_exitCode);
            }
            finally
            {
                LogManager.Trace("_GuestAndHostModeMainWrapper: leaving.");
            }
        } // end _GuestAndHostModeMainWrapper()
예제 #2
0
        private static int _GuestModeMainWrapper(ExceptionGuard entryPointStateDisposer,
                                                 string[] args)
        {
            // We should have two things:
            //    args[ 0 ]: either "consoleOwner" or "shareConsole" (windbg versus ntsd, for instance)
            //    args[ 1 ]: command args should all should get passed in one big string.
            Util.Assert(2 == args.Length);

            bool shareConsole = false;

            if (0 == StringComparer.Ordinal.Compare(args[0], c_guestModeShareConsole))
            {
                shareConsole = true;
            }
            else
            {
                if (0 != StringComparer.Ordinal.Compare(args[0], c_guestModeConsoleOwner))
                {
                    var msg = "Unexpected arg: I expected to see \"consoleOwner\".";
                    Util.Fail(msg);
                    throw new Exception(msg);
                }
            }

            bool firstTime      = null == sm_altMainThread;
            bool alreadyRunning = DbgProvider.EntryDepth > 1;

            try
            {
                bool   noProfile;
                bool   inBreakpointCommand;
                string command = _ParseGuestModeArgs(args[1],
                                                     firstTime,
                                                     out noProfile,
                                                     out inBreakpointCommand);

                if (inBreakpointCommand && !DbgProvider.IsInBreakpointCommand)
                {
                    DbgProvider.IsInBreakpointCommand = true;
                    entryPointStateDisposer.Protect((Disposable)(() => DbgProvider.IsInBreakpointCommand = false));
                }

                if (firstTime)
                {
                    Util.Assert(!alreadyRunning);
                    ColorConsoleHost.GuestModeInjectCommand(command);

                    LogManager.Trace("_GuestModeMainWrapper: initial entry.");
                    // This is the first time we've been run, so we need to start everything
                    // up, pretty much the same as when running as a normal EXE.
                    sm_altMainThread = new Thread(_AltMainThread);

                    DbgProvider.SetGuestMode(shareConsole);

                    string[] mainArgs = null;
                    if (noProfile)
                    {
                        mainArgs = new string[] { "-NoProfile" }
                    }
                    ;

                    sm_altMainThread.Start(mainArgs);

                    // This will get signaled when things have been initialized enough to
                    // where we can start the guest mode thread activity.
                    DbgProvider.GuestModeEvent.WaitOne();
                    DbgProvider.GuestModeEvent.Reset();
                }
                else
                {
                    if (alreadyRunning)
                    {
                        // Re-entrant case: DbgShell is already running, but something called
                        // the debugger "!dbgshell" extension command (for instance, a
                        // breakpoint command).
                        LogManager.Trace("_GuestModeMainWrapper: re-entering (entryDepth: {0}).", DbgProvider.EntryDepth);
                        if (null == DbgProvider.CurrentActionQueue)
                        {
                            Util.Fail("DbgShell is already running, but I don't have a CurrentActionQueue to inject commands.");
                            throw new Exception("DbgShell is already running, but I don't have a CurrentActionQueue to inject commands.");
                        }
                        var transferTicket = entryPointStateDisposer.Transfer();
                        DbgProvider.CurrentActionQueue.PostCommand((cii) =>
                        {
                            using (transferTicket.Redeem())
                            {
                                LogManager.Trace("Executing injected (reentrant) commands:");
                                LogManager.Trace(command.Replace("\n", "\n > "));
                                cii.InvokeScript(command,
                                                 false,
                                                 PipelineResultTypes.Error |
                                                 PipelineResultTypes.Output,
                                                 sm_noInput);
                            }     // end using( new disposer )
                        });
                        transferTicket.CommitTransfer();
                    }
                    else
                    {
                        LogManager.Trace("_GuestModeMainWrapper: resuming.");
                        ColorConsoleHost.GuestModeInjectCommand(command);

                        // We already have an alternate main thread, which is "paused" (blocked),
                        // waiting to resume.

                        DbgProvider.GuestModeResume();
                    }
                }

                if (!alreadyRunning)
                {
                    LogManager.Trace("_GuestModeMainWrapper: entering GuestModeGuestThreadActivity.");
                    // The guest mode thread activity is to pump the DbgEngThread (this thread is
                    // the thread that the debugger extension was called on, and we need to use
                    // this thread to interact with dbgeng).
                    //
                    // (if alreadyRunning, then we are already running the
                    // GuestModeGuestThreadActivity (it's below us on the stack))
                    DbgProvider.GuestModeGuestThreadActivity();
                }

                LogManager.Trace("_GuestModeMainWrapper: returning {0}.",
                                 Util.FormatErrorCode(sm_exitCode));
                return(sm_exitCode);
            }
            finally
            {
                LogManager.Trace("_GuestModeMainWrapper: leaving.");
            }
        } // end _GuestModeMainWrapper()