DebugProvider.Unix.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using Microsoft.Win32.SafeHandles;
  5. namespace System.Diagnostics
  6. {
  7. public partial class DebugProvider
  8. {
  9. private static readonly bool s_shouldWriteToStdErr = Environment.GetEnvironmentVariable("COMPlus_DebugWriteToStdErr") == "1";
  10. public static void FailCore(string stackTrace, string? message, string? detailMessage, string errorSource)
  11. {
  12. if (s_FailCore != null)
  13. {
  14. s_FailCore(stackTrace, message, detailMessage, errorSource);
  15. return;
  16. }
  17. if (Debugger.IsAttached)
  18. {
  19. Debugger.Break();
  20. }
  21. else
  22. {
  23. // In Core, we do not show a dialog.
  24. // Fail in order to avoid anyone catching an exception and masking
  25. // an assert failure.
  26. DebugAssertException ex = new DebugAssertException(message, detailMessage, stackTrace);
  27. Environment.FailFast(ex.Message, ex, errorSource);
  28. }
  29. }
  30. public static void WriteCore(string message)
  31. {
  32. if (s_WriteCore != null)
  33. {
  34. s_WriteCore(message);
  35. return;
  36. }
  37. WriteToDebugger(message);
  38. if (s_shouldWriteToStdErr)
  39. {
  40. WriteToStderr(message);
  41. }
  42. }
  43. private static void WriteToDebugger(string message)
  44. {
  45. if (Debugger.IsLogging())
  46. {
  47. Debugger.Log(0, null, message);
  48. }
  49. else
  50. {
  51. Interop.Sys.SysLog(Interop.Sys.SysLogPriority.LOG_USER | Interop.Sys.SysLogPriority.LOG_DEBUG, "%s", message);
  52. }
  53. }
  54. private static void WriteToStderr(string message)
  55. {
  56. // We don't want to write UTF-16 to a file like standard error. Ideally we would transcode this
  57. // to UTF8, but the downside of that is it pulls in a bunch of stuff into what is ideally
  58. // a path with minimal dependencies (as to prevent re-entrency), so we'll take the strategy
  59. // of just throwing away any non ASCII characters from the message and writing the rest
  60. const int BufferLength = 256;
  61. unsafe
  62. {
  63. byte* buf = stackalloc byte[BufferLength];
  64. int bufCount;
  65. int i = 0;
  66. while (i < message.Length)
  67. {
  68. for (bufCount = 0; bufCount < BufferLength && i < message.Length; i++)
  69. {
  70. if (message[i] <= 0x7F)
  71. {
  72. buf[bufCount] = (byte)message[i];
  73. bufCount++;
  74. }
  75. }
  76. int totalBytesWritten = 0;
  77. while (bufCount > 0)
  78. {
  79. int bytesWritten = Interop.Sys.Write(2 /* stderr */, buf + totalBytesWritten, bufCount);
  80. if (bytesWritten < 0)
  81. {
  82. // On error, simply stop writing the debug output. This could commonly happen if stderr
  83. // was piped to a program that ended before this program did, resulting in EPIPE errors.
  84. return;
  85. }
  86. bufCount -= bytesWritten;
  87. totalBytesWritten += bytesWritten;
  88. }
  89. }
  90. }
  91. }
  92. }
  93. }