/// <summary> /// Given an exception thrown by a process, determines whether the debugger should /// log, ignore, or stop on this exception, based on the type of exception and the /// existing exception settings. /// </summary> /// <returns>stop, log, or ignore</returns> protected DebuggerBehavior DetermineBehavior(string exceptionType) { ExceptionStopOptionPolicyItem currentItem; string regex; // Check entries in m_items to see if this exception type or a regular expression // matching it already exists in m_items. We loop backwards through the array because // entries added later have precedence over those added earlier. for (int i = m_items.Count - 1; i >= 0; i--) { currentItem = m_items[i]; if (MDbgUtil.IsRegex(currentItem.ExceptionType)) { // current entry in m_items is a regular expression regex = MDbgUtil.ConvertSimpleExpToRegExp(currentItem.ExceptionType); if (Regex.IsMatch(exceptionType, regex)) { return(currentItem.Behavior); } } else { if (currentItem.ExceptionType == exceptionType) { return(currentItem.Behavior); } } } return(m_default); }
/// <summary> /// Acts on the current callback, based on the current debugger behavior for this stop /// option policy. /// </summary> /// <param name="currentProcess">Current MDbgProcess.</param> /// <param name="args">Callback arguments.</param> public override void ActOnCallback(MDbgProcess currentProcess, CustomPostCallbackEventArgs args) { var eventArgs = args.CallbackArgs as CorEventArgs; switch (m_behavior) { case DebuggerBehavior.Stop: args.Controller.Stop(eventArgs.Thread, MDbgUtil.CreateStopReasonFromEventArgs(eventArgs, currentProcess)); break; case DebuggerBehavior.Log: CommandBase.WriteOutput(eventArgs + "\n"); break; } }
/// <summary> /// Modifies the exception settings, given an exception type and corresponding debugger behavior. /// </summary> /// <param name="behavior">stop, log, or ignore</param> /// <param name="arguments">A type of exception, or a regular expression.</param> public override void SetBehavior(DebuggerBehavior behavior, string arguments) { ExceptionStopOptionPolicyItem exceptionItem; string regex; int existingItemIndex = -1; bool redundantEntry = false; bool regexSubset = false; if (arguments == null) { // If no exception types are specified, then all existing settings are cleared and the // behavior becomes the default behavior for all exceptions. m_items.Clear(); m_default = behavior; if (behavior == DebuggerBehavior.Ignore) { // To preserve legacy behavior, ignoring all exceptions also turns the exception // enhanced switch off. m_exceptionEnhancedOn = false; } } else { // The arguments string can contain multiple exception types and regular expressions, // so the arguments are split into a string array. For example, if the arguments string // is "System.Exception System.A*", it is split into {"System.Exception", "System.A*"}. // The behavior for all of these arguments is then set to the given behavior. string[] exceptionTypes = arguments.Split(); string exceptionType; foreach (string type in exceptionTypes) { exceptionType = type.Trim(); if (MDbgUtil.IsRegex(exceptionType)) { // Input is a regular expression. Go through the existing exception items // and check if any of them match the input regular expression. If they do, // remove them, because the input regular expression is added after them // and has precedence. For example, if input is "System.*" and an exception // item already exists for "System.Exception", we remove the System.Exception // item. for (int i = 0; i < m_items.Count; i++) { exceptionItem = m_items[i]; regex = MDbgUtil.ConvertSimpleExpToRegExp(exceptionType); if (Regex.IsMatch(exceptionItem.ExceptionType, regex)) { m_items.Remove(exceptionItem); i--; } } } else { // Input is not a regular expression. Check if m_items already contains // an entry for this exception type. foreach (ExceptionStopOptionPolicyItem item in m_items) { if (item.ExceptionType == type) { existingItemIndex = m_items.IndexOf(item); break; } } } // Check if input is redundant. An input is redundant if it does not change the existing // behavior. There are two cases in which an input is redundant: // // - An exception item already exists that is a regular expression accepting the // input exception type, and specifying the same debugger behavior. For example, // if a "log System.*" exception item already exists, an input of "log System.Exception" // if redundant. However, an input of "ignore System.Exception" is NOT redundant, // because it is added after the "log System.*" item and has precedence over it. // // - The input behavior is the same as the default behavior. For example, if the // default behavior is ignore, an input of "ignore System.Exception" is redundant, // UNLESS the input matches some existing exception item regular expression (as in // the example above). for (int i = m_items.Count - 1; i >= 0; i--) { exceptionItem = m_items[i]; if (m_items.IndexOf(exceptionItem) == existingItemIndex) { break; } if (MDbgUtil.IsRegex(exceptionItem.ExceptionType)) { regex = MDbgUtil.ConvertSimpleExpToRegExp(exceptionItem.ExceptionType); if (Regex.IsMatch(type, regex)) { regexSubset = true; if (behavior == exceptionItem.Behavior) { redundantEntry = true; } break; } } } if (!regexSubset) { if (behavior == m_default) { redundantEntry = true; } } // If the input modifies some existing exception item existing entry and the behavior // is redundant, remove the existing item. If no matching item exists and the input // is redundant, do nothing. if (existingItemIndex != -1) { if (redundantEntry) { m_items.RemoveAt(existingItemIndex); } else { m_items[existingItemIndex].Behavior = behavior; } } else { if (!redundantEntry) { m_items.Add(new ExceptionStopOptionPolicyItem(type, behavior)); } } } } }