399 lines
11 KiB
C#
399 lines
11 KiB
C#
// BreakEvent.cs
|
|
//
|
|
// Author:
|
|
// Lluis Sanchez Gual <lluis@novell.com>
|
|
//
|
|
// 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<HitAction> (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<HitCountMode> (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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether this <see cref="Mono.Debugging.Client.BreakEvent"/> is enabled.
|
|
/// </summary>
|
|
/// <value>
|
|
/// <c>true</c> if enabled; otherwise, <c>false</c>.
|
|
/// </value>
|
|
/// <remarks>
|
|
/// Changes in this property are automatically applied. There is no need to call CommitChanges().
|
|
/// </remarks>
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the status of the break event
|
|
/// </summary>
|
|
/// <returns>
|
|
/// The status of the break event for the given debug session
|
|
/// </returns>
|
|
/// <param name='session'>
|
|
/// Session for which to get the status of the break event
|
|
/// </param>
|
|
public BreakEventStatus GetStatus (DebuggerSession session)
|
|
{
|
|
if (store == null || session == null)
|
|
return BreakEventStatus.Disconnected;
|
|
return session.GetBreakEventStatus (this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a message describing the status of the break event
|
|
/// </summary>
|
|
/// <returns>
|
|
/// The status message of the break event for the given debug session
|
|
/// </returns>
|
|
/// <param name='session'>
|
|
/// Session for which to get the status message of the break event
|
|
/// </param>
|
|
public string GetStatusMessage (DebuggerSession session)
|
|
{
|
|
if (store == null || session == null)
|
|
return string.Empty;
|
|
return session.GetBreakEventStatusMessage (this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the expression to be traced when the breakpoint is hit
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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.
|
|
/// </remarks>
|
|
public string TraceExpression {
|
|
get {
|
|
return traceExpression;
|
|
}
|
|
set {
|
|
traceExpression = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the last value traced.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This property returns the last evaluation of TraceExpression.
|
|
/// </remarks>
|
|
public string LastTraceValue {
|
|
get {
|
|
return lastTraceValue;
|
|
}
|
|
internal set {
|
|
lastTraceValue = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the action to be performed when the breakpoint is hit
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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.
|
|
/// </remarks>
|
|
public HitAction HitAction {
|
|
get {
|
|
return hitAction;
|
|
}
|
|
set {
|
|
hitAction = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the hit count mode.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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.
|
|
/// </remarks>
|
|
public HitCountMode HitCountMode {
|
|
get; set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the target hit count.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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.
|
|
/// </remarks>
|
|
///
|
|
/// FIXME: rename this to TargetHitCount
|
|
public int HitCount {
|
|
get {
|
|
return hitCount;
|
|
}
|
|
set {
|
|
hitCount = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the current hit count.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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.
|
|
/// </remarks>
|
|
public int CurrentHitCount {
|
|
get; set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the custom action identifier.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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.
|
|
/// </remarks>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public bool NonUserBreakpoint {
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Commits changes done in the break event properties
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This method must be called after doing changes in the break event properties.
|
|
/// </remarks>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clone this instance.
|
|
/// </summary>
|
|
public BreakEvent Clone ()
|
|
{
|
|
return (BreakEvent) MemberwiseClone ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes a copy of this instance
|
|
/// </summary>
|
|
/// <param name='ev'>
|
|
/// A break event from which to copy the data.
|
|
/// </param>
|
|
public virtual void CopyFrom (BreakEvent ev)
|
|
{
|
|
hitAction = ev.hitAction;
|
|
customActionId = ev.customActionId;
|
|
traceExpression = ev.traceExpression;
|
|
hitCount = ev.hitCount;
|
|
breakIfConditionChanges = ev.breakIfConditionChanges;
|
|
conditionExpression = ev.conditionExpression;
|
|
}
|
|
}
|
|
}
|