// BreakEvent.cs // // Author: // Lluis Sanchez Gual // // Copyright (c) 2008 Novell, Inc (http://www.novell.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // using System; using System.Xml; namespace Mono.Debugging.Client { [Serializable] public class BreakEvent { bool breakIfConditionChanges; string conditionExpression; string lastConditionValue; [NonSerialized] BreakpointStore store; [NonSerialized] bool enabled = true; HitAction hitAction = HitAction.Break; string customActionId; string traceExpression; int hitCount; string lastTraceValue; public BreakEvent () { } internal BreakEvent (XmlElement elem, string baseDir) { string s = elem.GetAttribute ("enabled"); if (s.Length > 0) bool.TryParse (s, out enabled); s = elem.GetAttribute ("hitAction"); if (s.Length > 0) Enum.TryParse (s, out hitAction); s = elem.GetAttribute ("customActionId"); if (s.Length > 0) customActionId = s; s = elem.GetAttribute ("traceExpression"); if (s.Length > 0) traceExpression = s; s = elem.GetAttribute ("hitCountMode"); HitCountMode mode; if (s.Length > 0 && Enum.TryParse (s, out mode)) HitCountMode = mode; s = elem.GetAttribute ("hitCount"); if (s.Length > 0) int.TryParse (s, out hitCount); // this is to facilitate backward compatibility if (hitCount > 0 && HitCountMode == HitCountMode.None) HitCountMode = HitCountMode.GreaterThan; s = elem.GetAttribute ("conditionExpression"); if (!string.IsNullOrEmpty (s)) conditionExpression = s; s = elem.GetAttribute ("breakIfConditionChanges"); if (!string.IsNullOrEmpty (s) && !bool.TryParse (s, out breakIfConditionChanges)) breakIfConditionChanges = false; } internal virtual XmlElement ToXml (XmlDocument doc, string baseDir) { XmlElement elem = doc.CreateElement (GetType().Name); if (!enabled) elem.SetAttribute ("enabled", "false"); if ((hitAction & HitAction.Break) == HitAction.None) elem.SetAttribute ("hitAction", hitAction.ToString ()); if (!string.IsNullOrEmpty (customActionId)) elem.SetAttribute ("customActionId", customActionId); if (!string.IsNullOrEmpty (traceExpression)) elem.SetAttribute ("traceExpression", traceExpression); if (HitCountMode != HitCountMode.None) elem.SetAttribute ("hitCountMode", HitCountMode.ToString ()); if (hitCount > 0) elem.SetAttribute ("hitCount", hitCount.ToString ()); if (!string.IsNullOrEmpty (conditionExpression)) { elem.SetAttribute ("conditionExpression", conditionExpression); if (breakIfConditionChanges) elem.SetAttribute ("breakIfConditionChanges", "True"); } return elem; } internal static BreakEvent FromXml (XmlElement elem, string baseDir) { if (elem.Name == "FunctionBreakpoint") return new FunctionBreakpoint (elem, baseDir); if (elem.Name == "Breakpoint") return new Breakpoint (elem, baseDir); if (elem.Name == "Catchpoint") return new Catchpoint (elem, baseDir); return null; } /// /// Gets or sets a value indicating whether this is enabled. /// /// /// true if enabled; otherwise, false. /// /// /// Changes in this property are automatically applied. There is no need to call CommitChanges(). /// public bool Enabled { get { return enabled; } set { if (store != null && store.IsReadOnly) return; bool previous = enabled; enabled = value; if (store != null) store.EnableBreakEvent (this, previous, value); } } /// /// Gets the status of the break event /// /// /// The status of the break event for the given debug session /// /// /// Session for which to get the status of the break event /// public BreakEventStatus GetStatus (DebuggerSession session) { if (store == null || session == null) return BreakEventStatus.Disconnected; return session.GetBreakEventStatus (this); } /// /// Gets a message describing the status of the break event /// /// /// The status message of the break event for the given debug session /// /// /// Session for which to get the status message of the break event /// public string GetStatusMessage (DebuggerSession session) { if (store == null || session == null) return string.Empty; return session.GetBreakEventStatusMessage (this); } /// /// Gets or sets the expression to be traced when the breakpoint is hit /// /// /// If this break event is hit and the HitAction is TraceExpression, the debugger /// will evaluate and print the value of this property. /// The CommitChanges() method has to be called for changes in this /// property to take effect. /// public string TraceExpression { get { return traceExpression; } set { traceExpression = value; } } /// /// Gets the last value traced. /// /// /// This property returns the last evaluation of TraceExpression. /// public string LastTraceValue { get { return lastTraceValue; } internal set { lastTraceValue = value; } } /// /// Gets or sets the action to be performed when the breakpoint is hit /// /// /// If the value is Break, the debugger will pause the execution. /// If the value is PrintExpression, the debugger will evaluate and /// print the value of the TraceExpression property. /// If the value is CustomAction, the debugger will execute the /// CustomBreakEventHitHandler callback specified in DebuggerSession, /// and will provide the value of CustomActionId as argument. /// The CommitChanges() method has to be called for changes in this /// property to take effect. /// public HitAction HitAction { get { return hitAction; } set { hitAction = value; } } /// /// Gets or sets the hit count mode. /// /// /// When the break event is hit, the HitCountMode is used to compare the CurrentHitCount /// with the TargetHitCount to determine if the break event should trigger. /// public HitCountMode HitCountMode { get; set; } /// /// Gets or sets the target hit count. /// /// /// When the break event is hit, if the value of HitCountMode is not None, then /// the value of CurrentHitCount will be incremented. Execution will immediately /// resume if it is determined that the CurrentHitCount vs TargetHitCount /// comparison does not meet the requirements of HitCountMode. /// /// The CommitChanges() method has to be called for changes in this property /// to take effect. /// /// /// FIXME: rename this to TargetHitCount public int HitCount { get { return hitCount; } set { hitCount = value; } } /// /// Gets or sets the current hit count. /// /// /// When the break event is hit, the HitCountMode is used to compare the CurrentHitCount /// with the TargetHitCount to determine if the break event should trigger. /// public int CurrentHitCount { get; set; } /// /// Gets or sets the custom action identifier. /// /// /// If this break event is hit and the value of HitAction is CustomAction, /// the debugger will execute the CustomBreakEventHitHandler callback /// specified in DebuggerSession, and will provide the value of this property /// as argument. /// The CommitChanges() method has to be called for changes in this /// property to take effect. /// public string CustomActionId { get { return customActionId; } set { customActionId = value; } } internal BreakpointStore Store { get { return store; } set { store = value; } } public string ConditionExpression { get { return conditionExpression; } set { conditionExpression = value; } } public string LastConditionValue { get { return lastConditionValue; } set { lastConditionValue = value; } } public bool BreakIfConditionChanges { get { return breakIfConditionChanges; } set { breakIfConditionChanges = value; } } /// /// NonUserBreakpoint is special kind of breakpoint that is not placed by user but by IDE/Add-In. /// This breakpoint is usually used by AddIn to execute code on debugee at certain point in application execution. /// IDE must hide this breakpoint from user. In breakpoints list and it must not stop execution(show breakpoint hit location). /// WARNING: Code that adds this breakpoint must also make sure to call session.Continue(); when breakpoint is hit. /// public bool NonUserBreakpoint { get; set; } /// /// Commits changes done in the break event properties /// /// /// This method must be called after doing changes in the break event properties. /// public void CommitChanges () { if (store != null) store.NotifyBreakEventChanged (this); } internal void NotifyUpdate () { if (store != null) store.NotifyBreakEventUpdated (this); } public virtual bool Reset () { bool changed = CurrentHitCount != 0; CurrentHitCount = 0; lastConditionValue = null; return changed; } /// /// Clone this instance. /// public BreakEvent Clone () { return (BreakEvent) MemberwiseClone (); } /// /// Makes a copy of this instance /// /// /// A break event from which to copy the data. /// public virtual void CopyFrom (BreakEvent ev) { hitAction = ev.hitAction; customActionId = ev.customActionId; traceExpression = ev.traceExpression; hitCount = ev.hitCount; breakIfConditionChanges = ev.breakIfConditionChanges; conditionExpression = ev.conditionExpression; } } }