Fix !soshelp for managed commands (#2963)
authorMike McLaughlin <mikem@microsoft.com>
Tue, 29 Mar 2022 16:23:33 +0000 (09:23 -0700)
committerGitHub <noreply@github.com>
Tue, 29 Mar 2022 16:23:33 +0000 (09:23 -0700)
* Fix !soshelp for managed commands

* Always return max screen width on dbgeng since it always returns 80

src/Microsoft.Diagnostics.DebugServices.Implementation/CommandService.cs
src/Microsoft.Diagnostics.DebugServices/IConsoleService.cs
src/Microsoft.Diagnostics.Repl/ConsoleService.cs
src/SOS/SOS.Extensions/ConsoleServiceFromDebuggerServices.cs
src/SOS/SOS.Extensions/DebuggerServices.cs
src/SOS/Strike/dbgengservices.cpp
src/SOS/Strike/dbgengservices.h
src/SOS/inc/debuggerservices.h
src/SOS/lldbplugin/services.cpp
src/SOS/lldbplugin/services.h

index 60fdbbbc3d25ea4c2b0c9afffdd42a3e5db029de..03e6a76400b691a5fc03de171853b2316251eff4 100644 (file)
@@ -507,7 +507,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
                 }
                 if (useHelpBuilder)
                 {
-                    var helpBuilder = new HelpBuilder(_console, maxWidth: Console.WindowWidth);
+                    var helpBuilder = new HelpBuilder(_console, maxWidth: LocalConsole.ToConsoleService(_console).WindowWidth);
                     helpBuilder.Write(command);
                 }
             }
@@ -520,15 +520,16 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         /// </summary>
         class LocalConsole : IConsole
         {
-            public static IServiceProvider ToServices(IConsole console) => ((LocalConsole)console).Services;
+            public static IServiceProvider ToServices(IConsole console) => ((LocalConsole)console)._services;
 
-            public readonly IServiceProvider Services;
+            public static IConsoleService ToConsoleService(IConsole console) => ((LocalConsole)console)._console;
 
+            private readonly IServiceProvider _services;
             private readonly IConsoleService _console;
 
             public LocalConsole(IServiceProvider services)
             {
-                Services = services;
+                _services = services;
                 _console = services.GetService<IConsoleService>();
                 Debug.Assert(_console != null);
                 Out = new StandardStreamWriter((text) => _console.Write(text));
index 7cde8b10728168b871f2bf9c0c2c60f8493301cf..726f0b919526b52755a8a77d963952792e6c7123 100644 (file)
@@ -33,5 +33,10 @@ namespace Microsoft.Diagnostics.DebugServices
         /// Cancellation token for current command
         /// </summary>
         CancellationToken CancellationToken { get; set; }
+
+        /// <summary>
+        /// Screen or window width or 0.
+        /// </summary>
+        int WindowWidth { get; }
     }
 }
index c2f96afdd8bdaf818f13083dc1e4f576a7227286..1519125b3d9b866c1ba325001c1931a3aaace20b 100644 (file)
@@ -6,6 +6,7 @@ using Microsoft.Diagnostics.DebugServices;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading;
@@ -551,6 +552,21 @@ namespace Microsoft.Diagnostics.Repl
 
         CancellationToken IConsoleService.CancellationToken { get; set; }
 
+        int IConsoleService.WindowWidth
+        {
+            get
+            {
+                try
+                {
+                    return Console.WindowWidth;
+                }
+                catch (Exception ex) when (ex is ArgumentOutOfRangeException || ex is IOException)
+                {
+                    return int.MaxValue;
+                }
+            }
+        }
+
         #endregion
     }
 }
index 6f4c440c318802ad925d9d6fc78d2e2dbd7606a1..48096ee6dee88ccff83ff61ac6109f67b0980cd2 100644 (file)
@@ -1,5 +1,6 @@
 using Microsoft.Diagnostics.DebugServices;
 using Microsoft.Diagnostics.Runtime.Interop;
+using System;
 using System.Threading;
 
 namespace SOS.Extensions
@@ -23,6 +24,8 @@ namespace SOS.Extensions
 
         public CancellationToken CancellationToken { get; set; }
 
+        int IConsoleService.WindowWidth => _debuggerServices.GetOutputWidth();
+
         #endregion
     }
 }
index d969df20ebceb150164bf174b4b248068b4a185d..cbb62bf7ccb41213623ca80fb719b0970b73c674 100644 (file)
@@ -327,6 +327,8 @@ namespace SOS
             }
         }
 
+        public int GetOutputWidth() => (int)VTable.GetOutputWidth(Self);
+
         [StructLayout(LayoutKind.Sequential)]
         private readonly unsafe struct IDebuggerServicesVTable
         {
@@ -352,6 +354,7 @@ namespace SOS
             public readonly delegate* unmanaged[Stdcall]<IntPtr, byte*, uint, out uint, HResult> GetSymbolPath;
             public readonly delegate* unmanaged[Stdcall]<IntPtr, int, ulong, byte*, int, out uint, out ulong, HResult> GetSymbolByOffset;
             public readonly delegate* unmanaged[Stdcall]<IntPtr, int, byte*, out ulong, HResult> GetOffsetBySymbol;
+            public readonly delegate* unmanaged[Stdcall]<IntPtr, uint> GetOutputWidth;
         }
     }
 }
index d1bcd52b87a7026ccaf49d414fa3acc957fc6e39..96ddf0b7d55c394523cfb0f251367abc9a1e5555 100644 (file)
@@ -439,6 +439,13 @@ DbgEngServices::GetOffsetBySymbol(
     return m_symbols->GetOffsetByName(symbolName.c_str(), offset);
 }
 
+ULONG
+DbgEngServices::GetOutputWidth()
+{
+    // m_client->GetOutputWidth() always returns 80 as the width under windbg, windbgx and cdb so just return the max.
+    return INT_MAX;
+}
+
 //----------------------------------------------------------------------------
 // IRemoteMemoryService
 //----------------------------------------------------------------------------
index 8dc7852a948b1fb774e18668128b685ee3f90e2e..8cd3e593d70e0ed35d0ae8b4c84ece2fa1b8da48 100644 (file)
@@ -180,6 +180,8 @@ public:
         PCSTR name,
         PULONG64 offset);
 
+    ULONG STDMETHODCALLTYPE GetOutputWidth();
+
     //----------------------------------------------------------------------------
     // IRemoteMemoryService
     //----------------------------------------------------------------------------
index 58060a344d9fa94f3a4df9cec6f445cfc4c873e0..427d013dece72300659c24266201279f2616c3be 100644 (file)
@@ -143,6 +143,8 @@ public:
         ULONG moduleIndex,
         PCSTR name,
         PULONG64 offset) = 0;
+
+    virtual ULONG STDMETHODCALLTYPE GetOutputWidth() = 0;
 };
 
 #ifdef __cplusplus
index e97ee53192617e6ebe64b01d4335bdc044e4053b..6c24506a9d25ddc4c7796e3005980a5b84ecc007 100644 (file)
@@ -2343,6 +2343,12 @@ exit:
     return hr;
 }
 
+ULONG
+LLDBServices::GetOutputWidth()
+{
+    return m_debugger.GetTerminalWidth();
+}
+
 //----------------------------------------------------------------------------
 // Helper functions
 //----------------------------------------------------------------------------
index 03eb4d3088e83192e4b15e70180722dc292ddc91..a9717f9008f9ef5486eb9167b3f1fd5a8325b0ac 100644 (file)
@@ -396,6 +396,8 @@ public:
         PCSTR name,
         PULONG64 offset);
 
+    ULONG STDMETHODCALLTYPE GetOutputWidth();
+
     //----------------------------------------------------------------------------
     // LLDBServices (internal)
     //----------------------------------------------------------------------------