} // end InterceptCtrlC() protected override void ProcessRecord() { if (!DbgProvider.IsInGuestMode) { throw new InvalidOperationException("This command is only intended to be used by the !dbgshell implementation."); } LogManager.Trace("WaitForBangDbgShellCommandCommand.ProcessRecord: DbgShell is going dormant."); using (var disposer = new ExceptionGuard()) { disposer.Protect(SetDebuggerAndContextAndUpdateCallbacks()); disposer.Protect(InterceptCtrlC()); disposer.Protect(Debugger.SuspendEventOutput()); // don't want our "modload" output etc. spewing while we are dormant base.ProcessRecord(); // We need to perform the wait on another thread, because we need to "pump" // on this thread, so that debug event callbacks can queue WriteObject calls // to this thread. _RegisterWaitForGuestModeEvent(disposer); // Give the user a hint about what's going on. var s = new ColorString(ConsoleColor.DarkGray, "(DbgShell will remain running in the background until you run !dbgshell again)").ToString(true); Host.UI.WriteLine(s); MsgLoop.Prepare(); // This will allow the extension command to return (it tells the dbgeng // thread that it can return). DbgProvider.GuestModePassivate(); MsgLoop.Run(); // This will complete when the guest mode event gets signaled. } // end using( disposer ) } // end ProcessRecord()
protected void ProcessRecord(bool callWaitForEventDespiteCurrentStatus) { base.ProcessRecord(); DEBUG_STATUS currentStatus = Debugger.GetExecutionStatus(); LogManager.Trace("ExecutionBaseCommand.ProcessRecord: Current status is {0}.", currentStatus); if (!callWaitForEventDespiteCurrentStatus && (DEBUG_STATUS.BREAK == currentStatus)) { // TODO: This is for attaching to a debugging server. Need to test it. Other cases? // Perhaps this logic should be changed to be more clear? LogManager.Trace("ExecutionBaseCommand: current status is already BREAK; will not call WaitForEvent."); return; // Don't need to call WaitForEvent. } using (InterceptCtrlC()) { // We need to perform the wait on another thread, because we need to "pump" // on this thread, so that debug event callbacks can queue WriteObject calls // to this thread. LogManager.Trace("ExecutionBaseCommand: calling WaitForEvent (on dbgeng thread)."); MsgLoop.Prepare(); Task waitTask = Debugger.WaitForEventAsync(); waitTask.ContinueWith((x) => { MsgLoop.SignalDone(); }); MsgLoop.Run(); Util.Await(waitTask); // in case it threw } // end using( InterceptCtrlC ) } // end ProcessRecord()
} // end _CallExtensionAsync() protected override void ProcessRecord() { var inputCallbacks = Debugger.GetInputCallbacks() as DebugInputCallbacks; if (null != inputCallbacks) { inputCallbacks.UpdateCmdlet(this); } // TODO: Why does this cmdlet even need to be an ExecutionBaseCommand? using (InterceptCtrlC()) using (Debugger.SetCurrentCmdlet(this)) { ulong hExt = 0; int dotIdx = ExtensionCommand.LastIndexOf('.'); if (dotIdx > 0) { if (dotIdx == (ExtensionCommand.Length - 1)) { throw new ArgumentException("ExtensionCommand cannot end with a '.'."); } string extName = ExtensionCommand.Substring(0, dotIdx); var elr = Debugger.GetExtensionDllHandle(extName, true); if (null == elr) { throw new DbgProviderException(Util.Sprintf("Could not find/load extension: {0}.", extName), "CouldNotLoadExtension", ErrorCategory.ObjectNotFound, extName); } if (!String.IsNullOrEmpty(elr.LoadOutput)) { SafeWriteObject(elr.LoadOutput); } ExtensionCommand = ExtensionCommand.Substring(dotIdx + 1); } MsgLoop.Prepare(); Task t = _CallExtensionAsync(hExt, ExtensionCommand, ExtensionArgs); MsgLoop.Run(); Host.UI.WriteLine(); Util.Await(t); // in case it threw } // end using( InterceptCtrlC ) } // end ProcessRecord()
} // end _FixPsPathsInSymbolPath() protected override void ProcessRecord() { base.ProcessRecord(); if (null == Path) { Path = String.Empty; } // // Fix PS-specific paths. // var fixedPath = _FixPsPathsInSymbolPath(Path, GetUnresolvedProviderPathFromPSPath); if (0 == fixedPath.Length) { WriteWarning("The symbol path is empty."); } Debugger.SymbolPath = fixedPath; if (PassThru) { WriteObject(Debugger.SymbolPath); } MsgLoop.Prepare(); // If the specified symbol path is inaccessible, the SetSymbolPathWide call // will generate some warning dbgeng output. But we'd also like to be able to // get output about the "expanded" symbol path. Unfortunately, there is no way // to get that, except to parse ".sympath" output. Since executing ".sympath" // will also repeat the warning about the inaccessible symbol path, we won't // start displaying dbgeng output until now. using (Debugger.HandleDbgEngOutput(_HandleDbgEngOutput)) { // TODO: Feature request: no way to get expanded symbol path except to parse ".sympath" output. var t = Debugger.InvokeDbgEngCommandAsync(".sympath", false); t.ContinueWith((x) => MsgLoop.SignalDone()); MsgLoop.Run(); Util.Await(t); // in case it threw } } // end ProcessRecord()
} // end BeginProcessing() protected override void ProcessRecord() { var inputCallbacks = Debugger.GetInputCallbacks() as DebugInputCallbacks; if (null != inputCallbacks) { inputCallbacks.UpdateCmdlet(this); } //var outputCallbacks = Debugger.GetOutputCallbacks() as DebugOutputCallbacks; //if( null != outputCallbacks ) // outputCallbacks.UpdateCmdlet( this ); using (var disposer = new ExceptionGuard()) { disposer.Protect(Debugger.SetCurrentCmdlet(this)); disposer.Protect(InterceptCtrlC()); MsgLoop.Prepare(); string actualCommand = string.Join(" ", Command); Task t = Debugger.InvokeDbgEngCommandAsync(actualCommand, OutputPrefix, _ConsumeLine); Task t2 = t.ContinueWith(async(x) => { DEBUG_STATUS execStatus = Debugger.GetExecutionStatus(); if (_StatusRequiresWait(execStatus)) { LogManager.Trace("InvokeDbgExtensionCommand: Current execution status ({0}) indicates that we should enter a wait.", execStatus); await WaitForBreakAsync(); } disposer.Dispose(); SignalDone(); }).Unwrap(); MsgLoop.Run(); Host.UI.WriteLine(); Util.Await(t); // in case it threw Util.Await(t2); // in case it threw } // end using( disposer ) } // end ProcessRecord()
protected override void ProcessRecord() { base.ProcessRecord(); using (var disposer = new ExceptionGuard(Debugger.HandleDbgEngOutput(_ConsumeLine))) { // Failure to load an extension should be a terminating error. // // Because the only reason to load an extension is so that you can call // commands in it. And if you didn't load it, then none of those commands // will work. string providerPath = PathOrName; if (providerPath.IndexOfAny(sm_dirSeparators) >= 0) { // We support PS paths. // // (we don't want to call GetUnresolvedProviderPathFromPSPath if it's // just a bare name, else PS will interpret that as a relative path, // which would be wrong) providerPath = GetUnresolvedProviderPathFromPSPath(PathOrName); } MsgLoop.Prepare(); var t = Debugger.AddExtensionAsync(providerPath); t.ContinueWith((x) => { disposer.Dispose(); SignalDone(); }); MsgLoop.Run(); var elr = Util.Await(t); // in case it threw if (!string.IsNullOrEmpty(elr.LoadOutput)) { SafeWriteObject(elr.LoadOutput); } SafeWriteVerbose("Loaded extension: {0}", PathOrName); } // end using( disposer ) } // end ProcessRecord()
// I think this should be for kernel-mode only. // [Parameter( Mandatory = false )] // public SwitchParameter IgnoreInaccessibleMemory { get; set; } protected override void ProcessRecord() { // Support relative paths in PS. string dumpFileResolved = SessionState.Path.GetUnresolvedProviderPathFromPSPath(DumpFile); DEBUG_FORMAT flags = DEBUG_FORMAT.DEFAULT; flags |= DEBUG_FORMAT.USER_SMALL_FULL_MEMORY | DEBUG_FORMAT.USER_SMALL_HANDLE_DATA | DEBUG_FORMAT.USER_SMALL_UNLOADED_MODULES | DEBUG_FORMAT.USER_SMALL_INDIRECT_MEMORY | DEBUG_FORMAT.USER_SMALL_DATA_SEGMENTS | DEBUG_FORMAT.USER_SMALL_PROCESS_THREAD_DATA | DEBUG_FORMAT.USER_SMALL_PRIVATE_READ_WRITE_MEMORY | DEBUG_FORMAT.USER_SMALL_FULL_MEMORY_INFO | DEBUG_FORMAT.USER_SMALL_THREAD_INFO | DEBUG_FORMAT.USER_SMALL_CODE_SEGMENTS | DEBUG_FORMAT.USER_SMALL_FULL_AUXILIARY_STATE; // TODO: Need to learn what this means // I think this should be for kernel-mode only. // if( IgnoreInaccessibleMemory ) // { // flags |= DEBUG_FORMAT.USER_SMALL_IGNORE_INACCESSIBLE_MEM; // } // TODO: Figure out these things, and see if there are new ones I don't know about: // DEBUG_FORMAT.USER_SMALL_FILTER_MEMORY | // DEBUG_FORMAT.USER_SMALL_FILTER_PATHS | // DEBUG_FORMAT.USER_SMALL_NO_OPTIONAL_DATA | // DEBUG_FORMAT.USER_SMALL_NO_AUXILIARY_STATE | if (!AllowClobber) { flags |= DEBUG_FORMAT.NO_OVERWRITE; } if (Compress) { flags |= DEBUG_FORMAT.WRITE_CAB; } if (CompressWithSymbols) { flags |= DEBUG_FORMAT.WRITE_CAB; flags |= DEBUG_FORMAT.CAB_SECONDARY_FILES; // TODO: What is CAB_SECONDARY_ALL_IMAGES for? DbgEng.h says // // "When creating a CAB with secondary images do searches // for all image files, regardless of whether they're // needed for the current session or not." // // but I don't know what it means for an image file to be "needed" for the // current session versus not. } if ((Compress || CompressWithSymbols) && !DumpFile.EndsWith(".cab", StringComparison.OrdinalIgnoreCase)) { WriteWarning("Output will be compressed, but output file name does not end in '.cab'."); WriteWarning("You will need to rename the resulting file to end with '.cab' if you want to be able to mount the dump file with Mount-DbgDumpFile."); } // TODO: Just let the API fail instead of doing this pre-check? if (File.Exists(dumpFileResolved)) { if (!AllowClobber) { // is there a better "already exists" exception? WriteError(new InvalidOperationException(Util.Sprintf("The file '{0}' already exists. Use -AllowClobber to overwrite it.", DumpFile)), "DumpFileAlreadyExists", ErrorCategory.ResourceExists, DumpFile); return; } } using (var disposer = new ExceptionGuard()) { disposer.Protect(Debugger.HandleDbgEngOutput((x) => SafeWriteVerbose(x.TrimEnd()))); disposer.Protect(new CtrlCInterceptor(_CtrlCHandler)); try { MsgLoop.Prepare(); var task = Debugger.WriteDumpAsync(DumpFile, flags, Comment, CancelTS.Token); task.ContinueWith((_t) => { disposer.Dispose(); SignalDone(); }); MsgLoop.Run(); Util.Await(task); // in case it threw } catch (DbgProviderException dpe) { if ((dpe.HResult == DebuggerObject.E_UNEXPECTED) && CancelTS.IsCancellationRequested) { WriteWarning("Dump file creation canceled."); } else { WriteError(dpe); } } } // end using( dbgeng output, CTRL-C ) } // end ProcessRecord()