Exemplo n.º 1
0
        public void TestMethod4()
        {
            ITracer tracer  = new StackTracer();
            var     thread1 = new Thread(StartSlowMethods);

            thread1.Start(tracer);
            StartSuperFastMethods(tracer);
            StartFastMethods(tracer);
            StartSuperSlowMethods(tracer);
            thread1.Join();

            var traceResult = tracer.GetTraceResult();

            int methodsAtAll = 0;

            foreach (var thread in traceResult.threads)
            {
                foreach (var method in thread.methods)
                {
                    methodsAtAll += 1 + countNestedMethods(method);
                }
            }

            Assert.AreEqual(6, methodsAtAll,
                            string.Format("Expected {0} methods at all, instead got {1}", 6, methodsAtAll));
        }
Exemplo n.º 2
0
        public IEnumerable <object> FetchParameters()
        {
            var st = new StackTracer(Source.Body, 1000);

            BadInstructions = st.TraceCall(Call).ToList();

            return(st.Stack.Select(entry => entry.Value.OptimizeValue()));
        }
Exemplo n.º 3
0
        public void TestMethod1()
        {
            ITracer tracer = new StackTracer();
            var     slow   = new SlowClass(tracer);

            slow.SuperSlow();
            var traceResult = tracer.GetTraceResult();

            Assert.IsNotNull(traceResult);
            Assert.AreEqual(1, traceResult.threads.Count,
                            string.Format("Expected {0} threads, instead got {1}", 1, traceResult.threads.Count));
        }
Exemplo n.º 4
0
        public void TestMethod3()
        {
            ITracer tracer = new StackTracer();

            StartFastMethods(tracer);
            StartSuperSlowMethods(tracer);
            StartFastMethods(tracer);
            StartSuperSlowMethods(tracer);

            var traceResult = tracer.GetTraceResult();

            Assert.AreEqual(4, traceResult.threads[0].methods.Count,
                            string.Format("Expected {0} root methods in main thread, instead got {1}", 4,
                                          traceResult.threads[0].methods.Count));
        }
Exemplo n.º 5
0
        public void TestMethod2()
        {
            ITracer tracer = new StackTracer();
            var     thread = new Thread(StartFastMethods);

            thread.Start(tracer);
            StartSuperSlowMethods(tracer);
            thread.Join();


            var traceResult = tracer.GetTraceResult();

            Assert.AreEqual(2, traceResult.threads.Count,
                            string.Format("Expected {0} threads, instead got {1}", 2, traceResult.threads.Count));
        }
Exemplo n.º 6
0
 public Spark(dynamic model)
 {
     _callingMethod =
         StackTracer.GetPreviousMethodName(GetType().GetConstructors().Where(ci => ci.GetParameters().Count() == 1).First());
     _model = model;
 }
Exemplo n.º 7
0
 public Spark()
 {
     _callingMethod = StackTracer.GetPreviousMethodName(GetType().GetConstructor(Type.EmptyTypes));
 }
Exemplo n.º 8
0
        private SpokeObject evaluateMethod(SpokeMethod fm, SpokeObject[] paras)
        {
            SpokeObject[] variables;

            #if stacktrace
            dfss.AppendLine( fm.Class.Name +" : : "+fm.MethodName+" Start");
            #endif

            SpokeObject lastStack;
            int stackIndex = 0;
            SpokeObject[] stack = new SpokeObject[3000];
            int index = 0;
            StackTracer st;
            if (reprintStackIndex == -1)
            {
                variables = new SpokeObject[fm.NumOfVars];

                for (int i = 0; i < fm.Parameters.Length; i++)
                {
                    variables[i] = paras[i];
                }

                stackTrace.Add(st = new StackTracer(stack, variables));
            }
            else
            {
                StackTracer rp = reprintStackTrace[stackTrace.Count];
                stack = rp.StackObjects;
                variables = rp.StackVariables;
                index = rp.InstructionIndex;
                stackIndex = rp.StackIndex;
                stackTrace.Add(st = new StackTracer(stack, variables));
                if (stackTrace.Count == reprintStackIndex)
                {
                    stack[stackIndex++] = rp.Answer;
                    reprintStackIndex = -1;
                    reprintStackTrace = null;
                }
            }

            for (; index < fm.Instructions.Length; index++)
            {
                var ins = fm.Instructions[index];
            #if stacktrace
                dfss.AppendLine(stackIndex + " ::  " + ins.ToString());
            #endif

                //        var fs = new fixStackTracer(stackTrace.ToArray());
                //       stackTrace = new List<StackTracer>(fs.Start(true));

                SpokeObject[] sps;

                SpokeObject bm;
                switch (ins.Type)
                {
                    case SpokeInstructionType.CreateReference:
                        stack[stackIndex++] = new SpokeObject(new SpokeObject[ins.Index], ins.StringVal);
                        break;
                    case SpokeInstructionType.CreateArray:
                        stack[stackIndex++] = new SpokeObject(new List<SpokeObject>(20));
                        break;
                    case SpokeInstructionType.CreateMethod:
                        stack[stackIndex++] = NULL;//new SpokeObject(ObjectType.Method) { AnonMethod = ins.anonMethod };
                        break;
                    case SpokeInstructionType.Label:
                        //   throw new NotImplementedException("");
                        break;
                    case SpokeInstructionType.Goto:

                        index = ins.Index;

                        break;
                    case SpokeInstructionType.Comment:

                        break;
                    case SpokeInstructionType.CallMethod:
                        st.InstructionIndex = index;
                        st.StackIndex = stackIndex;
                        sps = new SpokeObject[ins.Index3];
                        for (int i = ins.Index3 - 1; i >= 0; i--)
                        {
                            sps[i] = stack[--stackIndex];
                        }
                        stack[stackIndex++] = evaluateMethod(Methods[ins.Index], sps);
                        break;
                    case SpokeInstructionType.CallMethodFunc:
                        st.InstructionIndex = index;
                        st.StackIndex = stackIndex;
                        sps = new SpokeObject[ins.Index3];
                        for (int i = ins.Index3 - 1; i >= 0; i--)
                        {
                            sps[i] = stack[--stackIndex];
                        }

                        stack[stackIndex++] = Methods[ins.Index].MethodFunc(sps);
                        break;
                    case SpokeInstructionType.CallInternal:
                        sps = new SpokeObject[ins.Index3];
                        for (int i = ins.Index3 - 1; i >= 0; i--)
                        {
                            sps[i] = stack[--stackIndex];
                        }
                        st.InstructionIndex = index + 1;
                        st.StackIndex = stackIndex;

                        SpokeObject l = InternalMethods[ins.Index](sps);

                        if (ins.Index == 16)
                        {
                            GameBoard d = buildBoard(sps[4]);

                            throw new AskQuestionException(stackTrace,
                                                           new SpokeQuestion(sps[1].Variables[0].StringVal, sps[2].StringVal,
                                                                             sps[3].ArrayItems.Select(a => a.StringVal).ToArray()), d);
                        }
                        else
                        {
                            stack[stackIndex++] = l;
                        }

                        break;
                    case SpokeInstructionType.BreakpointInstruction:
                        Console.WriteLine("BreakPoint");
                        break;
                    case SpokeInstructionType.Return:
            #if stacktrace
                        dfss.AppendLine(fm.Class.Name + " : : " + fm.MethodName + " End");
            #endif
                        stackTrace.Remove(st);
                        return stack[--stackIndex];
                        break;
                    case SpokeInstructionType.IfTrueContinueElse:

                        if (stack[--stackIndex].BoolVal)
                            continue;

                        index = ins.Index;

                        break;
                    case SpokeInstructionType.Or:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].BoolVal || stack[stackIndex - 1].BoolVal) ? TRUE : FALSE;
                        stackIndex--;
                        break;
                    case SpokeInstructionType.And:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].BoolVal && stack[stackIndex - 1].BoolVal) ? TRUE : FALSE;
                        stackIndex--;
                        break;
                    case SpokeInstructionType.StoreLocalInt:
                        lastStack = stack[--stackIndex];
                        bm = variables[ins.Index];
                        variables[ins.Index] = new SpokeObject(ObjectType.Int) { IntVal = lastStack.IntVal };
                        break;
                    case SpokeInstructionType.StoreLocalFloat:
                        lastStack = stack[--stackIndex];
                        bm = variables[ins.Index];
                        variables[ins.Index] = new SpokeObject(ObjectType.Float) { FloatVal = lastStack.FloatVal };
                        break;
                    case SpokeInstructionType.StoreLocalBool:
                        lastStack = stack[--stackIndex];
                        bm = variables[ins.Index];
                        variables[ins.Index] = lastStack.BoolVal ? TRUE : FALSE;
                        break;
                    case SpokeInstructionType.StoreLocalString:
                        lastStack = stack[--stackIndex];
                        bm = variables[ins.Index];
                        variables[ins.Index] = new SpokeObject(ObjectType.String) { StringVal = lastStack.StringVal };
                        break;

                    case SpokeInstructionType.StoreLocalMethod:
                    case SpokeInstructionType.StoreLocalObject:
                        lastStack = stack[--stackIndex];
                        variables[ins.Index] = lastStack;
                        break;
                    case SpokeInstructionType.StoreLocalRef:
                        lastStack = stack[--stackIndex];
                        bm = variables[ins.Index];
                        bm.ClassName = lastStack.ClassName;
                        bm.Type = lastStack.Type;
                        //bm.Variables = lastStack.Variables;
                        //bm.ArrayItems = lastStack.ArrayItems;
                        bm.StringVal = lastStack.StringVal;
                        bm.IntVal = lastStack.IntVal;
                        bm.BoolVal = lastStack.BoolVal;
                        bm.FloatVal = lastStack.FloatVal;
                        break;

                    case SpokeInstructionType.StoreFieldBool:
                        lastStack = stack[--stackIndex];
                        lastStack.Variables[ins.Index] = stack[--stackIndex].BoolVal ? TRUE : FALSE;

                        break;
                    case SpokeInstructionType.StoreFieldInt:
                        lastStack = stack[--stackIndex];
                        lastStack.Variables[ins.Index] = new SpokeObject(ObjectType.Int) { IntVal = stack[--stackIndex].IntVal };

                        break;
                    case SpokeInstructionType.StoreFieldFloat:
                        lastStack = stack[--stackIndex];
                        lastStack.Variables[ins.Index] = new SpokeObject(ObjectType.Float) { FloatVal = stack[--stackIndex].FloatVal };

                        break;
                    case SpokeInstructionType.StoreFieldString:
                        lastStack = stack[--stackIndex];
                        lastStack.Variables[ins.Index] = new SpokeObject(ObjectType.String) { StringVal = stack[--stackIndex].StringVal };
                        break;

                    case SpokeInstructionType.StoreFieldMethod:
                    case SpokeInstructionType.StoreFieldObject:
                        lastStack = stack[--stackIndex];
                        lastStack.Variables[ins.Index] = stack[--stackIndex];

                        break;

                    case SpokeInstructionType.IfEqualsContinueAndPopElseGoto:

                        if (SpokeObject.Compare(stack[stackIndex - 2],
                                stack[stackIndex - 1]))
                        {
                            stackIndex = stackIndex - 2;
                            continue;
                        }

                        stackIndex = stackIndex - 1;
                        index = ins.Index;
                        break;
                    case SpokeInstructionType.StoreToReference:

                        lastStack = stack[--stackIndex];
                        stack[stackIndex - 1].Variables[ins.Index] = lastStack;
                        break;
                    case SpokeInstructionType.GetField:

                        stack[stackIndex - 1] = stack[stackIndex - 1].Variables[ins.Index];

                        break;
                    case SpokeInstructionType.GetLocal:

                        stack[stackIndex++] = variables[ins.Index];
                        break;
                    case SpokeInstructionType.PopStack:
                        stackIndex--;
                        break;
                    case SpokeInstructionType.Not:
                        stack[stackIndex - 1] = stack[stackIndex - 1].BoolVal ? FALSE : TRUE;
                        break;
                    case SpokeInstructionType.AddStringInt:
                        stack[stackIndex - 2] = new SpokeObject(ObjectType.String) { StringVal = stack[stackIndex - 2].StringVal + stack[stackIndex - 1].IntVal };
                        stackIndex--;

                        break;
                    case SpokeInstructionType.AddIntString:

                        stack[stackIndex - 2] = new SpokeObject(ObjectType.String) { StringVal = stack[stackIndex - 2].IntVal + stack[stackIndex - 1].StringVal };
                        stackIndex--;
                        break;
                    case SpokeInstructionType.IntConstant:
                        stack[stackIndex++] = intCache(ins.Index);
                        break;
                    case SpokeInstructionType.BoolConstant:

                        stack[stackIndex++] = ins.BoolVal ? TRUE : FALSE;
                        break;
                    case SpokeInstructionType.FloatConstant:
                        stack[stackIndex++] = new SpokeObject(ObjectType.Float) { FloatVal = ins.FloatVal };
                        break;
                    case SpokeInstructionType.StringConstant:

                        stack[stackIndex++] = new SpokeObject(ObjectType.String) { StringVal = ins.StringVal };
                        break;

                    case SpokeInstructionType.Null:
                        stack[stackIndex++] = NULL;
                        break;
                    case SpokeInstructionType.AddIntInt:
                        stack[stackIndex - 2] = intCache(stack[stackIndex - 2].IntVal + stack[stackIndex - 1].IntVal);
                        stackIndex--;
                        break;
                    case SpokeInstructionType.AddIntFloat:
                        break;
                    case SpokeInstructionType.AddFloatInt:
                        break;
                    case SpokeInstructionType.AddFloatFloat:
                        break;
                    case SpokeInstructionType.AddFloatString:
                        stack[stackIndex - 2] = new SpokeObject(ObjectType.String) { StringVal = stack[stackIndex - 2].FloatVal + stack[stackIndex - 1].StringVal };
                        stackIndex--;
                        break;
                    case SpokeInstructionType.AddStringFloat:
                        stack[stackIndex - 2] = new SpokeObject(ObjectType.String) { StringVal = stack[stackIndex - 2].StringVal + stack[stackIndex - 1].FloatVal };
                        stackIndex--;
                        break;
                    case SpokeInstructionType.AddStringString:
                        stack[stackIndex - 2] = new SpokeObject(ObjectType.String) { StringVal = stack[stackIndex - 2].StringVal + stack[stackIndex - 1].StringVal };
                        stackIndex--;
                        break;
                    case SpokeInstructionType.SubtractIntInt:
                        stack[stackIndex - 2] = intCache(stack[stackIndex - 2].IntVal - stack[stackIndex - 1].IntVal);
                        stackIndex--;

                        break;
                    case SpokeInstructionType.SubtractIntFloat:
                        break;
                    case SpokeInstructionType.SubtractFloatInt:
                        break;
                    case SpokeInstructionType.SubtractFloatFloat:
                        break;
                    case SpokeInstructionType.MultiplyIntInt:

                        stack[stackIndex - 2] = intCache(stack[stackIndex - 2].IntVal * stack[stackIndex - 1].IntVal);
                        stackIndex--;
                        break;
                    case SpokeInstructionType.MultiplyIntFloat:
                        break;
                    case SpokeInstructionType.MultiplyFloatInt:
                        break;
                    case SpokeInstructionType.MultiplyFloatFloat:
                        break;
                    case SpokeInstructionType.DivideIntInt:

                        stack[stackIndex - 2] = intCache(stack[stackIndex - 2].IntVal / stack[stackIndex - 1].IntVal);
                        stackIndex--;
                        break;
                    case SpokeInstructionType.DivideIntFloat:
                        break;
                    case SpokeInstructionType.DivideFloatInt:
                        break;
                    case SpokeInstructionType.DivideFloatFloat:
                        break;

                    case SpokeInstructionType.GreaterIntInt:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].IntVal > stack[stackIndex - 1].IntVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.GreaterIntFloat:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].IntVal > stack[stackIndex - 1].FloatVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.GreaterFloatInt:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].FloatVal > stack[stackIndex - 1].IntVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.GreaterFloatFloat:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].FloatVal > stack[stackIndex - 1].FloatVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.LessIntInt:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].IntVal < stack[stackIndex - 1].IntVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.LessIntFloat:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].IntVal < stack[stackIndex - 1].FloatVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.LessFloatInt:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].FloatVal < stack[stackIndex - 1].IntVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.LessFloatFloat:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].FloatVal < stack[stackIndex - 1].FloatVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.GreaterEqualIntInt:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].IntVal >= stack[stackIndex - 1].IntVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.GreaterEqualIntFloat:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].IntVal >= stack[stackIndex - 1].FloatVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.GreaterEqualFloatInt:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].FloatVal >= stack[stackIndex - 1].IntVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.GreaterEqualFloatFloat:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].FloatVal >= stack[stackIndex - 1].FloatVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.LessEqualIntInt:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].IntVal <= stack[stackIndex - 1].IntVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.LessEqualIntFloat:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].IntVal <= stack[stackIndex - 1].FloatVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.LessEqualFloatInt:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].FloatVal <= stack[stackIndex - 1].IntVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.LessEqualFloatFloat:
                        stack[stackIndex - 2] = (stack[stackIndex - 2].FloatVal <= stack[stackIndex - 1].FloatVal) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.Equal:
                        stack[stackIndex - 2] = SpokeObject.Compare(stack[stackIndex - 2], stack[stackIndex - 1]) ? TRUE : FALSE;
                        stackIndex = stackIndex - 1;
                        break;
                    case SpokeInstructionType.InsertToArray:
                        break;
                    case SpokeInstructionType.RemoveToArray:
                        break;
                    case SpokeInstructionType.AddToArray:
                        lastStack = stack[--stackIndex];
                        stack[stackIndex - 1].AddArray(lastStack);
                        break;
                    case SpokeInstructionType.AddRangeToArray:
                        lastStack = stack[--stackIndex];
                        stack[stackIndex - 1].AddRangeArray(lastStack);
                        break;
                    case SpokeInstructionType.LengthOfArray:
                        break;

                    case SpokeInstructionType.ArrayElem:

                        lastStack = stack[--stackIndex];
                        stack[stackIndex - 1] = stack[stackIndex - 1].ArrayItems[lastStack.IntVal];

                        break;
                    case SpokeInstructionType.StoreArrayElem:

                        var indexs = stack[--stackIndex];
                        var ars = stack[--stackIndex];

                        ars.ArrayItems[indexs.IntVal] = stack[--stackIndex];

                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }

            #if stacktrace
            dfss.AppendLine(fm.Class.Name + " : : " + fm.MethodName + " End");
            #endif
            stackTrace.Remove(st);
            return null;
        }
Exemplo n.º 9
0
        public static int Run(string[] args)
        {
            if (args == null)
            {
                throw new ArgumentNullException(nameof(args));
            }

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                EnsureProperDebugDllsAreLoadedForWindows();
            }

            _app = new CommandLineApplication
            {
                Name        = "Raven.Debug",
                Description = "Debugging tool from RavenDB"
            };

            _app.HelpOption(HelpOptionString);

            _app.Command("stack-traces", cmd =>
            {
                cmd.ExtendedHelpText = cmd.Description = "Prints stack traces for the given process.";
                cmd.HelpOption(HelpOptionString);

                var waitOption                = cmd.Option("--wait", "Wait for user input", CommandOptionType.NoValue);
                var pidOption                 = cmd.Option("--pid", "Process ID to which the tool will attach to", CommandOptionType.SingleValue);
                var attachTimeoutOption       = cmd.Option("--timeout", "Attaching to process timeout in milliseconds. Default 15000", CommandOptionType.SingleValue);
                var outputOption              = cmd.Option("--output", "Output file path", CommandOptionType.SingleValue);
                var threadIdsOption           = cmd.Option("--tid", "Thread ID to get the info about", CommandOptionType.MultipleValue);
                var includeStackObjectsOption = cmd.Option("--includeStackObjects", "Include the stack objects", CommandOptionType.NoValue);

                cmd.OnExecute(() =>
                {
                    if (waitOption.HasValue())
                    {
                        Console.ReadLine(); // wait for the caller to finish preparing for us
                    }
                    if (pidOption.HasValue() == false)
                    {
                        return(cmd.ExitWithError("Missing --pid option."));
                    }

                    if (int.TryParse(pidOption.Value(), out var pid) == false)
                    {
                        return(cmd.ExitWithError($"Could not parse --pid with value '{pidOption.Value()}' to number."));
                    }

                    HashSet <uint> threadIds = null;
                    if (threadIdsOption.HasValue())
                    {
                        foreach (var tid in threadIdsOption.Values)
                        {
                            if (uint.TryParse(tid, out var tidAsInt) == false)
                            {
                                return(cmd.ExitWithError($"Could not parse --tid with value '{tid}' to number."));
                            }

                            if (threadIds == null)
                            {
                                threadIds = new HashSet <uint>();
                            }

                            threadIds.Add(tidAsInt);
                        }
                    }

                    uint attachTimeout = 15000;
                    if (attachTimeoutOption.HasValue() && uint.TryParse(attachTimeoutOption.Value(), out attachTimeout) == false)
                    {
                        return(cmd.ExitWithError($"Could not parse --attachTimeout with value '{attachTimeoutOption.Value()}' to number."));
                    }

                    string output = null;
                    if (outputOption.HasValue())
                    {
                        output = outputOption.Value();
                    }

                    var includeStackObjects = includeStackObjectsOption.Values.FirstOrDefault() == "on";

                    try
                    {
                        StackTracer.ShowStackTrace(pid, attachTimeout, output, cmd, threadIds, includeStackObjects);
                        return(0);
                    }
                    catch (Exception e)
                    {
                        string desc;
                        if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) == false)
                        {
                            desc = "";
                        }
                        else
                        {
                            desc = $"Make sure to run enable-debugging.sh script as root from the main RavenDB directory.";
                        }

                        return(cmd.ExitWithError($"Failed to show the stacktrace. {desc}Error: {e}"));
                    }
                });
            });

            _app.Command("dump", cmd =>
            {
                cmd.ExtendedHelpText = cmd.Description = "Creates dump for the given process.";
                cmd.HelpOption(HelpOptionString);

                var pidOption    = cmd.Option("--pid", "Process ID to which the tool will attach to", CommandOptionType.SingleValue);
                var outputOption = cmd.Option("--output", "Output file path", CommandOptionType.SingleValue);
                var typeOption   = cmd.Option("--type", "Type of dump (Heap or Mini). ", CommandOptionType.SingleValue);

                cmd.OnExecuteAsync(async(_) =>
                {
                    if (pidOption.HasValue() == false)
                    {
                        return(cmd.ExitWithError("Missing --pid option."));
                    }

                    if (int.TryParse(pidOption.Value(), out var pid) == false)
                    {
                        return(cmd.ExitWithError($"Could not parse --pid with value '{pidOption.Value()}' to number."));
                    }

                    if (typeOption.HasValue() == false)
                    {
                        return(cmd.ExitWithError("Missing --type option."));
                    }

                    if (Enum.TryParse(typeOption.Value(), ignoreCase: true, out Dumper.DumpTypeOption type) == false)
                    {
                        return(cmd.ExitWithError($"Could not parse --type with value '{typeOption.Value()}' to one of supported dump types."));
                    }

                    string output = null;
                    if (outputOption.HasValue())
                    {
                        output = outputOption.Value();
                    }

                    try
                    {
                        var dumper = new Dumper();
                        await dumper.Collect(cmd, pid, output, diag: false, type).ConfigureAwait(false);
                        return(0);
                    }
                    catch (Exception e)
                    {
                        return(cmd.ExitWithError($"Failed to collect dump. Error: {e}"));
                    }
                });
            });

            _app.Command("gcdump", cmd =>
            {
                cmd.ExtendedHelpText = cmd.Description = "Creates GC dump for the given process.";
                cmd.HelpOption(HelpOptionString);

                var pidOption     = cmd.Option("--pid", "Process ID to which the tool will attach to", CommandOptionType.SingleValue);
                var outputOption  = cmd.Option("--output", "Output file path", CommandOptionType.SingleValue);
                var timeoutOption = cmd.Option("--timeout", "Give up on collecting the gcdump if it takes longer than this many seconds. The default value is. Default 30", CommandOptionType.SingleValue);
                var verboseOption = cmd.Option("--verbose", "Output the log while collecting the gcdump.", CommandOptionType.NoValue);

                cmd.OnExecuteAsync(async token =>
                {
                    if (pidOption.HasValue() == false)
                    {
                        return(cmd.ExitWithError("Missing --pid option."));
                    }

                    if (int.TryParse(pidOption.Value(), out var pid) == false)
                    {
                        return(cmd.ExitWithError($"Could not parse --pid with value '{pidOption.Value()}' to number."));
                    }

                    string output = null;
                    if (outputOption.HasValue())
                    {
                        output = outputOption.Value();
                    }

                    int timeout = 30;
                    if (timeoutOption.HasValue() && int.TryParse(timeoutOption.Value(), out timeout) == false)
                    {
                        return(cmd.ExitWithError($"Could not parse --timeout with value '{timeoutOption.Value()}' to number."));
                    }

                    var verbose = verboseOption.HasValue();

                    try
                    {
                        await GCHeapDumper.Collect(token, cmd, pid, output, timeout, verbose).ConfigureAwait(false);
                        return(0);
                    }
                    catch (Exception e)
                    {
                        return(cmd.ExitWithError($"Failed to collect GC dump. Error: {e}"));
                    }
                });
            });

            _app.OnExecute(() =>
            {
                _app.ShowHelp();
                return(1);
            });

            try
            {
                return(_app.Execute(args));
            }
            catch (CommandParsingException e)
            {
                return(_app.ExitWithError(e.Message));
            }
        }