namespace System.Diagnostics
{
- // Intentionally excluding visibility so it defaults to internal except for
- // the one public version in System.Diagnostics.Debug which defines
- // another version of this partial class with the public visibility
- static partial class Debug
+ public static partial class Debug
{
private static string NewLine => "\n";
- // internal and not readonly so that the tests can swap this out.
- internal static IDebugLogger s_logger = new UnixDebugLogger();
+ private const string EnvVar_DebugWriteToStdErr = "COMPlus_DebugWriteToStdErr";
+ private static readonly bool s_shouldWriteToStdErr =
+ Internal.Runtime.Augments.EnvironmentAugments.GetEnvironmentVariable(EnvVar_DebugWriteToStdErr) == "1";
- // --------------
- // PAL ENDS HERE
- // --------------
-
- internal sealed class UnixDebugLogger : IDebugLogger
+ private static void ShowAssertDialog(string stackTrace, string message, string detailMessage)
{
- private const string EnvVar_DebugWriteToStdErr = "COMPlus_DebugWriteToStdErr";
- private static readonly bool s_shouldWriteToStdErr =
- Internal.Runtime.Augments.EnvironmentAugments.GetEnvironmentVariable(EnvVar_DebugWriteToStdErr) == "1";
-
- public void ShowAssertDialog(string stackTrace, string message, string detailMessage)
+ if (Debugger.IsAttached)
{
- if (Debugger.IsAttached)
- {
- Debugger.Break();
- }
- else
- {
- // TODO: #3708 Determine if/how to put up a dialog instead.
- var exc = new DebugAssertException(message, detailMessage, stackTrace);
- if (!s_shouldWriteToStdErr)
- {
- // We always want to print out Debug.Assert failures to stderr, even if
- // !s_shouldWriteToStdErr, so if it wouldn't have been printed in
- // WriteCore (only when s_shouldWriteToStdErr), print it here.
- WriteToStderr(exc.Message);
- }
- throw exc;
- }
+ Debugger.Break();
}
-
- public void WriteCore(string message)
+ else
{
- WriteToDebugger(message);
-
- if (s_shouldWriteToStdErr)
+ // TODO: #3708 Determine if/how to put up a dialog instead.
+ var exc = new DebugAssertException(message, detailMessage, stackTrace);
+ if (!s_shouldWriteToStdErr)
{
- WriteToStderr(message);
+ // We always want to print out Debug.Assert failures to stderr, even if
+ // !s_shouldWriteToStdErr, so if it wouldn't have been printed in
+ // WriteCore (only when s_shouldWriteToStdErr), print it here.
+ WriteToStderr(exc.Message);
}
+ throw exc;
}
+ }
+
+ private static void WriteCore(string message)
+ {
+ WriteToDebugger(message);
- private static void WriteToDebugger(string message)
+ if (s_shouldWriteToStdErr)
{
- if (Debugger.IsLogging())
- {
- Debugger.Log(0, null, message);
- }
- else
- {
- Interop.Sys.SysLog(Interop.Sys.SysLogPriority.LOG_USER | Interop.Sys.SysLogPriority.LOG_DEBUG, "%s", message);
- }
+ WriteToStderr(message);
}
+ }
- private static void WriteToStderr(string message)
+ private static void WriteToDebugger(string message)
+ {
+ if (Debugger.IsLogging())
+ {
+ Debugger.Log(0, null, message);
+ }
+ else
{
- // We don't want to write UTF-16 to a file like standard error. Ideally we would transcode this
- // to UTF8, but the downside of that is it pulls in a bunch of stuff into what is ideally
- // a path with minimal dependencies (as to prevent re-entrency), so we'll take the strategy
- // of just throwing away any non ASCII characters from the message and writing the rest
+ Interop.Sys.SysLog(Interop.Sys.SysLogPriority.LOG_USER | Interop.Sys.SysLogPriority.LOG_DEBUG, "%s", message);
+ }
+ }
+
+ private static void WriteToStderr(string message)
+ {
+ // We don't want to write UTF-16 to a file like standard error. Ideally we would transcode this
+ // to UTF8, but the downside of that is it pulls in a bunch of stuff into what is ideally
+ // a path with minimal dependencies (as to prevent re-entrency), so we'll take the strategy
+ // of just throwing away any non ASCII characters from the message and writing the rest
- const int BufferLength = 256;
+ const int BufferLength = 256;
- unsafe
- {
- byte* buf = stackalloc byte[BufferLength];
- int bufCount;
- int i = 0;
+ unsafe
+ {
+ byte* buf = stackalloc byte[BufferLength];
+ int bufCount;
+ int i = 0;
- while (i < message.Length)
+ while (i < message.Length)
+ {
+ for (bufCount = 0; bufCount < BufferLength && i < message.Length; i++)
{
- for (bufCount = 0; bufCount < BufferLength && i < message.Length; i++)
+ if (message[i] <= 0x7F)
{
- if (message[i] <= 0x7F)
- {
- buf[bufCount] = (byte)message[i];
- bufCount++;
- }
+ buf[bufCount] = (byte)message[i];
+ bufCount++;
}
+ }
- int totalBytesWritten = 0;
- while (bufCount > 0)
+ int totalBytesWritten = 0;
+ while (bufCount > 0)
+ {
+ int bytesWritten = Interop.Sys.Write(2 /* stderr */, buf + totalBytesWritten, bufCount);
+ if (bytesWritten < 0)
{
- int bytesWritten = Interop.Sys.Write(2 /* stderr */, buf + totalBytesWritten, bufCount);
- if (bytesWritten < 0)
- {
- // On error, simply stop writing the debug output. This could commonly happen if stderr
- // was piped to a program that ended before this program did, resulting in EPIPE errors.
- return;
- }
-
- bufCount -= bytesWritten;
- totalBytesWritten += bytesWritten;
+ // On error, simply stop writing the debug output. This could commonly happen if stderr
+ // was piped to a program that ended before this program did, resulting in EPIPE errors.
+ return;
}
+
+ bufCount -= bytesWritten;
+ totalBytesWritten += bytesWritten;
}
}
}
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Security;
-
namespace System.Diagnostics
{
- // Intentionally excluding visibility so it defaults to internal except for
- // the one public version in System.Diagnostics.Debug which defines
- // another version of this partial class with the public visibility
- static partial class Debug
+ public static partial class Debug
{
private static string NewLine => "\r\n";
- // internal and not read only so that the tests can swap this out.
- internal static IDebugLogger s_logger = new WindowsDebugLogger();
-
- // --------------
- // PAL ENDS HERE
- // --------------
+ private static void ShowAssertDialog(string stackTrace, string message, string detailMessage)
+ {
+ if (Debugger.IsAttached)
+ {
+ Debugger.Break();
+ }
+ else
+ {
+ // TODO: #3708 Determine if/how to put up a dialog instead.
+ throw new DebugAssertException(message, detailMessage, stackTrace);
+ }
+ }
- internal sealed class WindowsDebugLogger : IDebugLogger
+ private static void WriteCore(string message)
{
- [SecuritySafeCritical]
- public void ShowAssertDialog(string stackTrace, string message, string detailMessage)
+ // really huge messages mess up both VS and dbmon, so we chop it up into
+ // reasonable chunks if it's too big. This is the number of characters
+ // that OutputDebugstring chunks at.
+ const int WriteChunkLength = 4091;
+
+ // We don't want output from multiple threads to be interleaved.
+ lock (s_ForLock)
{
- if (Debugger.IsAttached)
+ if (message == null || message.Length <= WriteChunkLength)
{
- Debugger.Break();
+ WriteToDebugger(message);
}
else
{
- // TODO: #3708 Determine if/how to put up a dialog instead.
- throw new DebugAssertException(message, detailMessage, stackTrace);
- }
- }
-
- public void WriteCore(string message)
- {
- // really huge messages mess up both VS and dbmon, so we chop it up into
- // reasonable chunks if it's too big. This is the number of characters
- // that OutputDebugstring chunks at.
- const int WriteChunkLength = 4091;
-
- // We don't want output from multiple threads to be interleaved.
- lock (s_ForLock)
- {
- if (message == null || message.Length <= WriteChunkLength)
- {
- WriteToDebugger(message);
- }
- else
+ int offset;
+ for (offset = 0; offset < message.Length - WriteChunkLength; offset += WriteChunkLength)
{
- int offset;
- for (offset = 0; offset < message.Length - WriteChunkLength; offset += WriteChunkLength)
- {
- WriteToDebugger(message.Substring(offset, WriteChunkLength));
- }
- WriteToDebugger(message.Substring(offset));
+ WriteToDebugger(message.Substring(offset, WriteChunkLength));
}
+ WriteToDebugger(message.Substring(offset));
}
}
+ }
- [System.Security.SecuritySafeCritical]
- private static void WriteToDebugger(string message)
+ private static void WriteToDebugger(string message)
+ {
+ if (Debugger.IsLogging())
{
- if (Debugger.IsLogging())
- {
- Debugger.Log(0, null, message);
- }
- else
- {
- Interop.Kernel32.OutputDebugString(message ?? string.Empty);
- }
+ Debugger.Log(0, null, message);
+ }
+ else
+ {
+ Interop.Kernel32.OutputDebugString(message ?? string.Empty);
}
}
}
/// <summary>
/// Provides a set of properties and methods for debugging code.
/// </summary>
- static partial class Debug
+ public static partial class Debug
{
private static readonly object s_lock = new object();
}
WriteLine(FormatAssert(stackTrace, message, detailMessage));
- s_logger.ShowAssertDialog(stackTrace, message, detailMessage);
+ s_ShowAssertDialog(stackTrace, message, detailMessage);
}
}
{
if (message == null)
{
- WriteCore(string.Empty);
+ s_WriteCore(string.Empty);
return;
}
if (s_needIndent)
message = GetIndentString() + message;
s_needIndent = false;
}
- WriteCore(message);
+ s_WriteCore(message);
if (message.EndsWith(NewLine))
{
s_needIndent = true;
return s_indentString = new string(' ', indentCount);
}
- private static void WriteCore(string message)
- {
- s_logger.WriteCore(message);
- }
-
- internal interface IDebugLogger
- {
- void ShowAssertDialog(string stackTrace, string message, string detailMessage);
- void WriteCore(string message);
- }
-
private sealed class DebugAssertException : Exception
{
internal DebugAssertException(string message, string detailMessage, string stackTrace) :
{
}
}
+
+ // internal and not readonly so that the tests can swap this out.
+ internal static Action<string, string, string> s_ShowAssertDialog = ShowAssertDialog;
+ internal static Action<string> s_WriteCore = WriteCore;
}
}