/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Collections.ObjectModel; namespace dnSpy.Contracts.Debugger.Breakpoints.Code { /// /// Code breakpoint settings /// public struct DbgCodeBreakpointSettings : IEquatable { /// /// true if the breakpoint is enabled /// public bool IsEnabled { get; set; } /// /// Condition /// public DbgCodeBreakpointCondition? Condition { get; set; } /// /// Hit count /// public DbgCodeBreakpointHitCount? HitCount { get; set; } /// /// Filter /// public DbgCodeBreakpointFilter? Filter { get; set; } /// /// Trace message /// public DbgCodeBreakpointTrace? Trace { get; set; } /// /// Labels /// public ReadOnlyCollection Labels { get; set; } #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public static bool operator ==(DbgCodeBreakpointSettings left, DbgCodeBreakpointSettings right) => left.Equals(right); public static bool operator !=(DbgCodeBreakpointSettings left, DbgCodeBreakpointSettings right) => !left.Equals(right); #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// /// Compares this instance to /// /// Other instance /// public bool Equals(DbgCodeBreakpointSettings other) => IsEnabled == other.IsEnabled && Condition == other.Condition && HitCount == other.HitCount && Filter == other.Filter && Trace == other.Trace && LabelsEquals(Labels, other.Labels); static bool LabelsEquals(ReadOnlyCollection? a, ReadOnlyCollection? b) { if (a is null) a = emptyLabels; if (b is null) b = emptyLabels; if (a == b) return true; if (a.Count != b.Count) return false; for (int i = 0; i < a.Count; i++) { if (!StringComparer.Ordinal.Equals(a[i], b[i])) return false; } return true; } static readonly ReadOnlyCollection emptyLabels = new ReadOnlyCollection(Array.Empty()); static int LabelsGetHashCode(ReadOnlyCollection a) { int hc = 0; foreach (var s in a ?? emptyLabels) hc ^= StringComparer.Ordinal.GetHashCode(s ?? string.Empty); return hc; } /// /// Compares this instance to /// /// Other instance /// public override bool Equals(object? obj) => obj is DbgCodeBreakpointSettings other && Equals(other); /// /// Gets the hash code /// /// public override int GetHashCode() => (IsEnabled ? 1 : 0) ^ Condition.GetValueOrDefault().GetHashCode() ^ HitCount.GetValueOrDefault().GetHashCode() ^ Filter.GetValueOrDefault().GetHashCode() ^ Trace.GetValueOrDefault().GetHashCode() ^ LabelsGetHashCode(Labels); } /// /// Code breakpoint condition kind /// public enum DbgCodeBreakpointConditionKind { /// /// Condition is true /// IsTrue, /// /// Condition is changed /// WhenChanged, } /// /// Code breakpoint condition /// public readonly struct DbgCodeBreakpointCondition : IEquatable { /// /// Condition kind /// public DbgCodeBreakpointConditionKind Kind { get; } /// /// Condition expression /// public string Condition { get; } /// /// Constructor /// /// Condition kind /// Condition expression public DbgCodeBreakpointCondition(DbgCodeBreakpointConditionKind kind, string condition) { Kind = kind; Condition = condition ?? throw new ArgumentNullException(nameof(condition)); } #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public static bool operator ==(DbgCodeBreakpointCondition left, DbgCodeBreakpointCondition right) => left.Equals(right); public static bool operator !=(DbgCodeBreakpointCondition left, DbgCodeBreakpointCondition right) => !left.Equals(right); #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// /// Compares this instance to /// /// Other instance /// public bool Equals(DbgCodeBreakpointCondition other) => Kind == other.Kind && StringComparer.Ordinal.Equals(Condition, other.Condition); /// /// Compares this instance to /// /// Other instance /// public override bool Equals(object? obj) => obj is DbgCodeBreakpointCondition other && Equals(other); /// /// Gets the hash code /// /// public override int GetHashCode() => (int)Kind ^ StringComparer.Ordinal.GetHashCode(Condition ?? string.Empty); /// /// ToString() /// /// public override string ToString() => $"{Kind} {Condition}"; } /// /// Hit count kind /// public enum DbgCodeBreakpointHitCountKind { /// /// Hit count == value /// Equals, /// /// (Hit count % value) == 0 /// MultipleOf, /// /// Hit count >= value /// GreaterThanOrEquals, } /// /// Hit count /// public readonly struct DbgCodeBreakpointHitCount : IEquatable { /// /// Hit count kind /// public DbgCodeBreakpointHitCountKind Kind { get; } /// /// Hit count /// public int Count { get; } /// /// Constructor /// /// Hit count kind /// Hit count public DbgCodeBreakpointHitCount(DbgCodeBreakpointHitCountKind kind, int count) { Kind = kind; Count = count; } #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public static bool operator ==(DbgCodeBreakpointHitCount left, DbgCodeBreakpointHitCount right) => left.Equals(right); public static bool operator !=(DbgCodeBreakpointHitCount left, DbgCodeBreakpointHitCount right) => !left.Equals(right); #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// /// Compares this instance to /// /// Other instance /// public bool Equals(DbgCodeBreakpointHitCount other) => Kind == other.Kind && Count == other.Count; /// /// Compares this instance to /// /// Other instance /// public override bool Equals(object? obj) => obj is DbgCodeBreakpointHitCount other && Equals(other); /// /// Gets the hash code /// /// public override int GetHashCode() => (int)Kind ^ Count; /// /// ToString() /// /// public override string ToString() => $"{Kind} {Count}"; } /// /// Code breakpoint filter /// public readonly struct DbgCodeBreakpointFilter : IEquatable { /// /// Filter /// public string Filter { get; } /// /// Constructor /// /// Filter public DbgCodeBreakpointFilter(string filter) => Filter = filter ?? throw new ArgumentNullException(nameof(filter)); #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public static bool operator ==(DbgCodeBreakpointFilter left, DbgCodeBreakpointFilter right) => left.Equals(right); public static bool operator !=(DbgCodeBreakpointFilter left, DbgCodeBreakpointFilter right) => !left.Equals(right); #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// /// Compares this instance to /// /// Other instance /// public bool Equals(DbgCodeBreakpointFilter other) => StringComparer.Ordinal.Equals(Filter, other.Filter); /// /// Compares this instance to /// /// Other instance /// public override bool Equals(object? obj) => obj is DbgCodeBreakpointFilter other && Equals(other); /// /// Gets the hash code /// /// public override int GetHashCode() => StringComparer.Ordinal.GetHashCode(Filter ?? string.Empty); /// /// ToString() /// /// public override string ToString() => Filter; } /// /// Code breakpoint trace message /// public readonly struct DbgCodeBreakpointTrace : IEquatable { /// /// Message /// public string Message { get; } /// /// true to continue execution (trace) or false to break (breakpoint) /// public bool Continue { get; } /// /// Constructor /// /// Message /// true to continue execution (tracepoint) or false to break (breakpoint) public DbgCodeBreakpointTrace(string message, bool @continue) { Message = message ?? throw new ArgumentNullException(nameof(message)); Continue = @continue; } #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public static bool operator ==(DbgCodeBreakpointTrace left, DbgCodeBreakpointTrace right) => left.Equals(right); public static bool operator !=(DbgCodeBreakpointTrace left, DbgCodeBreakpointTrace right) => !left.Equals(right); #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// /// Compares this instance to /// /// Other instance /// public bool Equals(DbgCodeBreakpointTrace other) => Continue == other.Continue && StringComparer.Ordinal.Equals(Message, other.Message); /// /// Compares this instance to /// /// Other instance /// public override bool Equals(object? obj) => obj is DbgCodeBreakpointTrace other && Equals(other); /// /// Gets the hash code /// /// public override int GetHashCode() => (Continue ? -1 : 0) ^ StringComparer.Ordinal.GetHashCode(Message ?? string.Empty); /// /// ToString() /// /// public override string ToString() => $"{(Continue ? "Continue" : "Break")}: {Message}"; } }