public static void SetIPCmd(string arguments) { const string IlOpt = "il"; ArgParser ap = new ArgParser(arguments, IlOpt); if (ap.OptionPassed(IlOpt)) { Debugger.Processes.Active.Threads.Active.CurrentFrame.CorFrame.SetIP(ap.AsInt(0)); } else { int ilOffset; if (!Debugger.Processes.Active.Threads.Active.CurrentFrame.Function.GetIPFromLine(ap.AsInt(0), out ilOffset)) { throw new MDbgShellException("cannot find correct function mapping"); } int hresult; if (!Debugger.Processes.Active.Threads.Active.CurrentFrame.CorFrame.CanSetIP(ilOffset, out hresult)) { string reason; switch ((HResult)hresult) { case HResult.CORDBG_S_BAD_START_SEQUENCE_POINT: reason = "Attempt to SetIP from non-sequence point."; break; case HResult.CORDBG_S_BAD_END_SEQUENCE_POINT: reason = "Attempt to SetIP from non-sequence point."; break; case HResult.CORDBG_S_INSUFFICIENT_INFO_FOR_SET_IP: reason = "Insufficient information to fix program flow."; break; case HResult.CORDBG_E_CANT_SET_IP_INTO_FINALLY: reason = "Attempt to SetIP into finally block."; break; case HResult.CORDBG_E_CANT_SET_IP_OUT_OF_FINALLY: case HResult.CORDBG_E_CANT_SET_IP_OUT_OF_FINALLY_ON_WIN64: reason = "Attempt to SetIP out of finally block."; break; case HResult.CORDBG_E_CANT_SET_IP_INTO_CATCH: reason = "Attempt to SetIP into catch block."; break; case HResult.CORDBG_E_CANT_SET_IP_OUT_OF_CATCH_ON_WIN64: reason = "Attempt to SetIP out of catch block."; break; case HResult.CORDBG_E_SET_IP_NOT_ALLOWED_ON_NONLEAF_FRAME: reason = "Attempt to SetIP on non-leaf frame."; break; case HResult.CORDBG_E_SET_IP_IMPOSSIBLE: reason = "The operation cannot be completed."; break; case HResult.CORDBG_E_CANT_SETIP_INTO_OR_OUT_OF_FILTER: reason = "Attempt to SetIP into or out of filter."; break; case HResult.CORDBG_E_SET_IP_NOT_ALLOWED_ON_EXCEPTION: reason = "SetIP is not allowed on exception."; break; default: reason = "Reason unknown."; break; } throw new MDbgShellException("Cannot set IP as requested. " + reason); } Debugger.Processes.Active.Threads.Active.CurrentFrame.CorFrame.SetIP(ilOffset); } Debugger.Processes.Active.Threads.InvalidateAllStacks(); Shell.DisplayCurrentLocation(); }
public static void WhereCmd(string arguments) { const int default_depth = 100; // default number of frames to print const string countOpt = "c"; const string verboseOpt = "v"; ArgParser ap = new ArgParser(arguments, countOpt + ":1;" + verboseOpt); int depth = default_depth; if (ap.OptionPassed(countOpt)) { ArgToken countArg = ap.GetOption(countOpt); if (countArg.AsString == "all") { depth = 0; // 0 means print entire stack } else { depth = countArg.AsInt; if (depth <= 0) { throw new MDbgShellException("Depth must be positive number or string \"all\""); } } } if (ap.Count != 0 && ap.Count != 1) { throw new MDbgShellException("Wrong # of arguments."); } if (ap.Count == 0) { // print current thread only InternalWhereCommand(Debugger.Processes.Active.Threads.Active, depth, ap.OptionPassed(verboseOpt)); } else if (ap.AsString(0).Equals("all")) { foreach (MDbgThread t in Debugger.Processes.Active.Threads) InternalWhereCommand(t, depth, ap.OptionPassed(verboseOpt)); } else { MDbgThread t = Debugger.Processes.Active.Threads[ap.AsInt(0)]; if (t == null) { throw new MDbgShellException("Wrong thread number"); } else { InternalWhereCommand(t, depth, ap.OptionPassed(verboseOpt)); } } }
public static void DownCmd(string arguments) { string frameNum = "f"; ArgParser ap = new ArgParser(arguments, frameNum); if (ap.OptionPassed(frameNum)) { SwitchToFrame(ap.AsInt(0)); } else { int count = 1; if (ap.Exists(0)) { count = ap.AsInt(0); } while (--count >= 0) { Debugger.Processes.Active.Threads.Active.MoveCurrentFrame(true); } } if (Debugger.Processes.Active.Threads.Active.CurrentFrame.IsManaged) { WriteOutput("Current Frame:" + Debugger.Processes.Active.Threads.Active.CurrentFrame.Function.FullName ); } Shell.DisplayCurrentLocation(); }
public static void XCmd(string arguments) { if (arguments.Length == 0) { WriteOutput("Please specify module."); ListCmd("mo"); } else { const int default_count = 100; // default number of frames to print const string countOpt = "c"; ArgParser ap = new ArgParser(arguments, countOpt + ":1"); int count = default_count; if (ap.OptionPassed(countOpt)) { ArgToken countArg = ap.GetOption(countOpt); if (countArg.AsString == "all") { count = 0; // 0 means print all symbols } else { count = countArg.AsInt; if (count <= 0) { throw new MDbgShellException("Count must be positive number or string \"all\""); } } } string moduleName, substrPart; string expr = ap.AsString(0); int i = expr.IndexOf('!'); if (i == -1) { moduleName = expr; substrPart = null; } else { moduleName = expr.Substring(0, i); substrPart = expr.Substring(i + 1); } SymbolCache.Clear(); // enum functions from the module MDbgModule m = Debugger.Processes.Active.Modules.Lookup(moduleName); if (m == null) { throw new MDbgShellException("module not found!"); } bool shouldPrint = substrPart == null; Regex r = null; if (substrPart != null) { r = new Regex(ConvertSimpleExpToRegExp(substrPart)); } foreach (Type t in m.Importer.DefinedTypes) { foreach (MethodInfo mi in t.GetMethods()) { StringBuilder sb = new StringBuilder(); sb.Append(t.Name).Append(".").Append(mi.Name).Append("("); bool needComma = false; foreach (ParameterInfo pi in mi.GetParameters()) { if (needComma) { sb.Append(","); } sb.Append(pi.Name); needComma = true; } sb.Append(")"); string fullFunctionName = sb.ToString(); if (r != null) { shouldPrint = r.IsMatch(fullFunctionName); } if (shouldPrint) { int idx = SymbolCache.Add(new MdbgSymbol(m.Number, t.Name, mi.Name, 0)); WriteOutput("~" + idx + ". " + fullFunctionName); if (count != 0 && idx >= count) { WriteOutput(string.Format(CultureInfo.CurrentUICulture, "displayed only first {0} hits. For more symbols use -c switch", count)); return; } } } } } }
public static void OpendumpCmd(string arguments) { const string pathArg = "path"; ArgParser ap = new ArgParser(arguments, pathArg + ":1"); if (ap.Count > 1) { throw new MDbgShellException("Wrong # of arguments."); } if (!ap.Exists(0) && !ap.OptionPassed(pathArg)) { throw new MDbgShellException("Specify a dump file to open"); } string path; if (ap.Exists(0)) path = ap.AsString(0); else path = ap.GetOption(pathArg).AsString; DumpReader dump = new DumpReader(path); MDbgProcess process = Debugger.Processes.CreateProcess(); // An exception partway through attaching can leave the debugger in an odd in-between state. // We need to attempt to detach. bool success = false; try { process.AttachToDump(dump, null); success = true; } finally { // Fault handler (emulate with finally & success bool since C# doesn't support fault blocks) // Detach on failure so we're not left with a partially attached process if (!success) process.Detach(); } WriteOutput("DBI path: " + ((LibraryProvider)process.LibraryProvider).LastLoadedDbi); // If there's an exception of interest stored in the dump, use it. // Otherwise, fall back on going to the first thread with managed code. if (dump.IsExceptionStream()) { uint TID = dump.ExceptionStreamThreadId(); WriteOutput("OS TID from last exception in dump was 0n" + TID); MDbgThread thread = process.Threads.GetThreadFromThreadId((int)TID); if (null == thread) { WriteOutput("Could not find a managed thread corresponding to native TID!\n" + "This should indicate that the last event was a native event on an unmanaged thread.\n" ); } else { process.Threads.Active = thread; WriteOutput("Active thread set to " + process.Threads.Active.Id); } } else { WriteOutput("No exception in dump, current thread will be chosen randomly."); // Set the currently active thread to the first thread we find with managed code on it. bool foundThread = false; for (int i = 0; i < process.Threads.Count && !foundThread; i++) { foreach (MDbgFrame frame in process.Threads[i].Frames) { if (frame != null && frame.IsManaged) { process.Threads.Active = process.Threads[i]; foundThread = true; } } } if (!foundThread) { WriteOutput("Warning: couldn't find thread with managed frame at base in dump"); } } // This can fail silently if we can't walk the first frame of the stack. process.AsyncStop(); process.Threads.Active.InvalidateStackWalker(); WriteOutput("Dump loaded successfully."); }
public static void AttachCmd(string arguments) { const string versionArg = "ver"; const string continuationEventArg = "attachEvent"; const string pidArg = "pid"; ArgParser ap = new ArgParser(arguments, versionArg + ":1;" + continuationEventArg + ":1;" + pidArg + ":1"); if (ap.Count > 1) { throw new MDbgShellException("Wrong # of arguments."); } if (!ap.Exists(0) && !ap.OptionPassed(pidArg)) { WriteOutput("Please choose some process to attach"); ProcessEnumCmd(""); return; } int pid; if (ap.Exists(0)) { pid = ap.AsInt(0); if (ap.OptionPassed(pidArg)) { WriteOutput("Do not specify pid option when also passing pid as last argument"); return; } } else { Debug.Assert(ap.OptionPassed(pidArg)); // verified above pid = ap.GetOption(pidArg).AsInt; } // // Do some sanity checks to give useful end-user errors. // // Can't attach to ourselves! if (Process.GetCurrentProcess().Id == pid) { throw new MDbgShellException("Cannot attach to myself!"); } // Can't attach to a process that we're already debugging. // ICorDebug may enforce this, but the error may not be very descriptive for an end-user. // For example, ICD may propogate an error from the OS, and the OS may return // something like AccessDenied if another debugger is already attached. // This only checks for cases where this same instance of MDbg is already debugging // the process of interest. foreach (MDbgProcess procOther in Debugger.Processes) { if (pid == procOther.CorProcess.Id) { throw new MDbgShellException("Can't attach to process " + pid + " because it's already being debugged"); } } // Get the OS handle if there was one SafeWin32Handle osEventHandle = null; if (ap.OptionPassed(continuationEventArg)) { osEventHandle = new SafeWin32Handle(new IntPtr(ap.GetOption(continuationEventArg).AsHexOrDecInt)); } // determine the version to attach to string version = null; if (ap.OptionPassed(versionArg)) { version = ap.GetOption(versionArg).AsString; } else { version = MdbgVersionPolicy.GetDefaultAttachVersion(pid); } if (version == null) { throw new MDbgShellException("Can't determine what version of the CLR to attach to in process " + pid + ". Use -ver to specify a version"); } // attach MDbgProcess p; p = Debugger.Attach(pid, osEventHandle, version); p.Go().WaitOne(); if (osEventHandle != null) { osEventHandle.Dispose(); } }
public static void ListCmd(string arguments) { const string verboseOpt = "v"; bool bVerbose; ArgParser ap = new ArgParser(arguments, verboseOpt); string listWhat = ap.AsCommand(0, new CommandArgument("modules", "appdomains", "assemblies")); switch (listWhat) { case "modules": bVerbose = ap.OptionPassed(verboseOpt); if (ap.Exists(1)) { // user specified module to display info for MDbgModule m = Debugger.Processes.Active.Modules.Lookup(ap.AsString(1)); if (m == null) { throw new MDbgShellException("No such module."); } ListModuleInternal(m, true); } else { // we list all modules WriteOutput("Loaded Modules:"); foreach (MDbgModule m in Debugger.Processes.Active.Modules) { ListModuleInternal(m, bVerbose); } } break; case "appdomains": WriteOutput("Current appDomains:"); foreach (MDbgAppDomain ad in Debugger.Processes.Active.AppDomains) { WriteOutput(ad.Number + ". - " + ad.CorAppDomain.Name); } break; case "assemblies": WriteOutput("Current assemblies:"); foreach (MDbgAppDomain ad in Debugger.Processes.Active.AppDomains) { foreach (CorAssembly assem in ad.CorAppDomain.Assemblies) { WriteOutput("\t" + assem.Name); } } break; default: Debug.Assert(false); break; } }
public static void FuncEvalCmd(string arguments) { const string appDomainOption = "ad"; ArgParser ap = new ArgParser(arguments, appDomainOption + ":1"); if (!(ap.Count >= 1)) { throw new MDbgShellException("Not Enough arguments"); } // Currently debugger picks first function -- we have not implementing resolving overloaded functions. // Good example is Console.WriteLine -- there is 18 different types: // 1) [06000575] Void WriteLine() // 2) [06000576] Void WriteLine(Boolean) // 3) [06000577] Void WriteLine(Char) // 4) [06000578] Void WriteLine(Char[]) // 5) [06000579] Void WriteLine(Char[], Int32, Int32) // 6) [0600057a] Void WriteLine(Decimal) // 7) [0600057b] Void WriteLine(Double) // 8) [0600057c] Void WriteLine(Single) // 9) [0600057d] Void WriteLine(Int32) // 10) [0600057e] Void WriteLine(UInt32) // 11) [0600057f] Void WriteLine(Int64) // 12) [06000580] Void WriteLine(UInt64) // 13) [06000581] Void WriteLine(Object) // 14) [06000582] Void WriteLine(String) // 15) [06000583] Void WriteLine(String, Object) // 16) [06000584] Void WriteLine(String, Object, Object) // 17) [06000585] Void WriteLine(String, Object, Object, Object) // 18) [06000586] Void WriteLine(String, Object, Object, Object, Object, ...) // 19) [06000587] Void WriteLine(String, Object[]) // CorAppDomain appDomain; if (ap.OptionPassed(appDomainOption)) { MDbgAppDomain ad = Debugger.Processes.Active.AppDomains[ap.GetOption(appDomainOption).AsInt]; if (ad == null) { throw new ArgumentException("Invalid Appdomain Number"); } appDomain = ad.CorAppDomain; } else { appDomain = Debugger.Processes.Active.Threads.Active.CorThread.AppDomain; } MDbgFunction func = Debugger.Processes.Active.ResolveFunctionNameFromScope(ap.AsString(0), appDomain); if (null == func) { throw new MDbgShellException(String.Format(CultureInfo.InvariantCulture, "Could not resolve {0}", new Object[] { ap.AsString(0) })); } CorEval eval = Debugger.Processes.Active.Threads.Active.CorThread.CreateEval(); // Get Variables ArrayList vars = new ArrayList(); String arg; for (int i = 1; i < ap.Count; i++) { arg = ap.AsString(i); CorValue v = Shell.ExpressionParser.ParseExpression2(arg, Debugger.Processes.Active, Debugger.Processes.Active.Threads.Active.CurrentFrame); if (v == null) { throw new MDbgShellException("Cannot resolve expression or variable " + ap.AsString(i)); } if (v is CorGenericValue) { vars.Add(v as CorValue); } else { CorHeapValue hv = v.CastToHeapValue(); if (hv != null) { // we cannot pass directly heap values, we need to pass reference to heap valus CorReferenceValue myref = eval.CreateValue(CorElementType.ELEMENT_TYPE_CLASS, null).CastToReferenceValue(); myref.Value = hv.Address; vars.Add(myref); } else { vars.Add(v); } } } eval.CallFunction(func.CorFunction, (CorValue[])vars.ToArray(typeof(CorValue))); Debugger.Processes.Active.Go().WaitOne(); // now display result of the funceval if (!(Debugger.Processes.Active.StopReason is EvalCompleteStopReason)) { // we could have received also EvalExceptionStopReason but it's derived from EvalCompleteStopReason WriteOutput("Func-eval not fully completed and debuggee has stopped"); WriteOutput("Result of funceval won't be printed when finished."); } else { eval = (Debugger.Processes.Active.StopReason as EvalCompleteStopReason).Eval; Debug.Assert(eval != null); CorValue cv = eval.Result; if (cv != null) { MDbgValue mv = new MDbgValue(Debugger.Processes.Active, cv); WriteOutput("result = " + mv.GetStringValue(1)); if (cv.CastToReferenceValue() != null) if (Debugger.Processes.Active.DebuggerVars.SetEvalResult(cv)) WriteOutput("results saved to $result"); } } Shell.DisplayCurrentLocation(); }
public static void PrintCmd(string arguments) { const string debuggerVarsOpt = "d"; const string noFuncevalOpt = "nf"; const string expandDepthOpt = "r"; ArgParser ap = new ArgParser(arguments, debuggerVarsOpt + ";" + noFuncevalOpt + ";" + expandDepthOpt + ":1"); bool canDoFunceval = !ap.OptionPassed(noFuncevalOpt); int? expandDepth = null; // we use optional here because // different codes bellow has different // default values. if (ap.OptionPassed(expandDepthOpt)) { expandDepth = ap.GetOption(expandDepthOpt).AsInt; if (expandDepth < 0) throw new MDbgShellException("Depth cannot be negative."); } MDbgFrame frame = Debugger.Processes.Active.Threads.Active.CurrentFrame; if (ap.OptionPassed(debuggerVarsOpt)) { // let's print all debugger variables MDbgProcess p = Debugger.Processes.Active; foreach (MDbgDebuggerVar dv in p.DebuggerVars) { MDbgValue v = new MDbgValue(p, dv.CorValue); WriteOutput(dv.Name + "=" + v.GetStringValue(expandDepth == null ? 0 : (int)expandDepth, canDoFunceval)); } } else { if (ap.Count == 0) { // get all active variables MDbgFunction f = frame.Function; ArrayList vars = new ArrayList(); MDbgValue[] vals = f.GetActiveLocalVars(frame); if (vals != null) { vars.AddRange(vals); } vals = f.GetArguments(frame); if (vals != null) { vars.AddRange(vals); } foreach (MDbgValue v in vars) { WriteOutput(v.Name + "=" + v.GetStringValue(expandDepth == null ? 0 : (int)expandDepth, canDoFunceval)); } } else { // user requested printing of specific variables for (int j = 0; j < ap.Count; ++j) { MDbgValue var = Debugger.Processes.Active.ResolveVariable(ap.AsString(j), frame); if (var != null) { WriteOutput(ap.AsString(j) + "=" + var.GetStringValue(expandDepth == null ? 1 : (int)expandDepth, canDoFunceval)); } else { throw new MDbgShellException("Variable not found"); } } } } }
public static void SuspendCmd(string arguments) { string quietOpt = "q"; ArgParser ap = new ArgParser(arguments, quietOpt); ThreadResumeSuspendHelper(ap, CorDebugThreadState.THREAD_SUSPEND, !ap.OptionPassed(quietOpt)); }
public static void ThreadCmd(string arguments) { const string nickNameStr = "nick"; ArgParser ap = new ArgParser(arguments, nickNameStr + ":1"); if (ap.Count == 0) { if (ap.OptionPassed(nickNameStr)) { g_threadNickNames.SetThreadNickName(ap.GetOption(nickNameStr).AsString, Debugger.Processes.Active.Threads.Active); } else { // we want to display active threads MDbgProcess p = Debugger.Processes.Active; WriteOutput("Active threads:"); foreach (MDbgThread t in p.Threads) { string stateDescription = GetThreadStateDescriptionString(t); WriteOutput(string.Format("th #:{0} (ID:{1}){2}", g_threadNickNames.GetThreadName(t), t.Id, stateDescription.Length == 0 ? String.Empty : " " + stateDescription)); } } } else { MDbgThread t = g_threadNickNames.GetThreadByNickName(ap.AsString(0)); if (t == null) { throw new MDbgShellException("No such thread"); } Debugger.Processes.Active.Threads.Active = t; string currentThreadStateString = GetThreadStateDescriptionString(t); if (currentThreadStateString.Length > 0) currentThreadStateString = currentThreadStateString.Insert(0, " "); WriteOutput(string.Format(CultureInfo.InvariantCulture, "Current thread is #{0}{1}.", t.Number, currentThreadStateString)); Shell.DisplayCurrentLocation(); } }