Example #1
0
        internal static DebuggerContext?GetDebuggerContext(IntPtr ptrClient)
        {
            // On our first call to the API:
            //   1. Store a copy of IDebugClient in DebugClient.
            //   2. Replace Console's output stream to be the debugger window.
            //   3. Create an instance of DataTarget using the IDebugClient.
            if (instance is null)
            {
                object client      = Marshal.GetUniqueObjectForIUnknown(ptrClient);
                var    debugClient = (IDebugClient)client;

                var output = new DebuggerOutput(debugClient);

#pragma warning disable CA2000 // Dispose objects before losing scope
                var dataTarget = DataTarget.CreateFromDbgEng(ptrClient);
#pragma warning restore CA2000 // Dispose objects before losing scope

                ClrRuntime?runtime = null;

                // If our ClrRuntime instance is null, it means that this is our first call, or
                // that the dac wasn't loaded on any previous call.  Find the dac loaded in the
                // process (the user must use .cordll), then construct our runtime from it.

                // Just find a module named mscordacwks and assume it's the one the user
                // loaded into windbg.
                Process p = Process.GetCurrentProcess();
                foreach (ProcessModule module in p.Modules)
                {
                    if (module.FileName.ToUpperInvariant().Contains("MSCORDACWKS"))
                    {
                        // TODO:  This does not support side-by-side CLRs.
                        runtime = dataTarget.ClrVersions.Single().CreateRuntime(module.FileName);
                        break;
                    }
                }

                // Otherwise, the user didn't run .cordll.
                if (runtime is null)
                {
                    output.WriteLine("Mscordacwks.dll not loaded into the debugger.");
                    output.WriteLine("Run .cordll to load the dac before running this command.");
                }

                if (runtime is object)
                {
                    instance = new DebuggerContext(debugClient, dataTarget, runtime, output);
                }
            }
            else
            {
                // If we already had a runtime, flush it for this use.  This is ONLY required
                // for a live process or iDNA trace.  If you use the IDebug* apis to detect
                // that we are debugging a crash dump you may skip this call for better perf.
                // instance.Runtime.Flush();
            }

            return(instance);
        }
Example #2
0
        private static bool PrintAsyncStateMachineChain(DebuggerOutput output, AsyncStateMachine node, HashSet <AsyncStateMachine> printedMachines)
        {
            int  nLevel            = 0;
            bool multipleLineBlock = false;

            var loopDetection = new HashSet <AsyncStateMachine>();

            for (AsyncStateMachine?p = node; p is object; p = p.Next)
            {
                printedMachines.Add(p);

                if (nLevel > 0)
                {
                    output.WriteString("..");
                    multipleLineBlock = true;
                }
                else if (p.AlterPrevious is object)
                {
                    output.WriteObjectAddress(p.AlterPrevious.StateMachine.Address);
                    output.WriteString($" <{p.AlterPrevious.State}> * {p.AlterPrevious.StateMachine.Type?.Name} @ ");
                    output.WriteMethodInfo($"{p.AlterPrevious.CodeAddress:x}", p.AlterPrevious.CodeAddress);
                    output.WriteLine(string.Empty);
                    output.WriteString("..");
                    multipleLineBlock = true;
                }
                else if (!p.SwitchToMainThreadTask.IsNull)
                {
                    output.WriteObjectAddress(p.SwitchToMainThreadTask.Address);
                    output.WriteLine(".SwitchToMainThreadAsync");
                    output.WriteString("..");
                    multipleLineBlock = true;
                }

                output.WriteObjectAddress(p.StateMachine.Address);
                string doubleDependentTaskMark = p.DependentCount > 1 ? " * " : " ";
                output.WriteString($" <{p.State}>{doubleDependentTaskMark}{p.StateMachine.Type?.Name} @ ");
                output.WriteMethodInfo($"{p.CodeAddress:x}", p.CodeAddress);
                output.WriteLine(string.Empty);

                if (!loopDetection.Add(p))
                {
                    output.WriteLine("!!Loop task dependencies");
                    break;
                }

                if (p.Next is null && p.BlockedThread.HasValue)
                {
                    output.WriteString("-- ");
                    output.WriteThreadLink(p.BlockedThread.Value);
                    output.WriteString(" - JoinableTask: ");
                    output.WriteObjectAddress(p.BlockedJoinableTask.Address);

                    int state = p.BlockedJoinableTask.ReadField <int>("state");
                    if ((state & 0x20) == 0x20)
                    {
                        output.WriteLine(" SynchronouslyBlockingMainThread");
                    }
                    else
                    {
                        output.WriteLine(string.Empty);
                    }

                    multipleLineBlock = true;
                }

                nLevel++;
            }

            return(multipleLineBlock);
        }
Example #3
0
        private static void PrintOutStateMachines(List <AsyncStateMachine> allStateMachines, DebuggerOutput output)
        {
            int loopMark = -1;

            foreach (var stateMachine in allStateMachines)
            {
                int depth = 0;
                if (stateMachine.Previous is null)
                {
                    AsyncStateMachine?p = stateMachine;
                    while (p is object)
                    {
                        depth++;
                        if (p.Depth == loopMark)
                        {
                            break;
                        }

                        p.Depth = loopMark;
                        p       = p.Next;
                    }
                }

                if (stateMachine.AlterPrevious is object)
                {
                    depth++;
                }

                stateMachine.Depth = depth;
                loopMark--;
            }

            var printedMachines = new HashSet <AsyncStateMachine>();

            foreach (var node in allStateMachines
                     .Where(m => m.Depth > 0)
                     .OrderByDescending(m => m.Depth)
                     .ThenByDescending(m => m.SwitchToMainThreadTask.Address))
            {
                bool multipleLineBlock = PrintAsyncStateMachineChain(output, node, printedMachines);

                if (multipleLineBlock)
                {
                    output.WriteLine(string.Empty);
                }
            }

            // Print nodes which we didn't print because of loops.
            if (allStateMachines.Count > printedMachines.Count)
            {
                output.WriteLine("States form dependencies loop -- could be an error caused by the analysis tool");
                foreach (var node in allStateMachines)
                {
                    if (!printedMachines.Contains(node))
                    {
                        PrintAsyncStateMachineChain(output, node, printedMachines);
                        output.WriteLine(string.Empty);
                    }
                }
            }
        }