vmware-tanzu / tanzu-toolkit-for-visual-studio

Apache License 2.0
10 stars 3 forks source link

Support remote debugging for .NET 4 apps #296

Open andrew-woosnam opened 2 years ago

andrew-woosnam commented 2 years ago

Currently, remote debugging only works with "newer" .NET apps (e.g. .NET Core, .NET 5, etc.). This is because dotnet publish doesn't work the same for those full-framework apps. MSBuild might be a good alternative for these apps:

msbuild "FrameworkApp\FrameworkApp.csproj" /p:DeployOnBuild=true /p:PublishUrl="c:\publish" /p:WebPublishMethod=FileSystem /p:DeployDefaultTarget=WebPublish
andrew-woosnam commented 2 years ago

Could also try these arguments to that msbuild command:

/p:DebugSymbols=true

/p:DebugType=full

/p:ExcludeGeneratedDebugSymbol=false
andrew-woosnam commented 2 years ago

msbuild command is working (more or less; the process is passing with exit code 0 but I don't think it's putting the "publish" folder in the right spot & idk if it's properly including PDBs or not...), but pushing https://github.com/SteeltoeOSS/Samples/tree/2.x/Configuration/src/AspDotNet4/Simple for remote debugging is still failing:

2022-04-04T16:41:04.57-0400 [APP/PROC/WEB/0] ERR '.\Simple' is not recognized as an internal or external command,

^ This is despite correcting the start command to use --server.urls instead of urls

TimHess commented 2 years ago

ASP.NET 4 apps don't include a webserver and aren't directly runnable (that's why the command isn't recognized), so they'll need to use the HWC buildpack, but shouldn't need the command specified. That Simple sample isn't actually completely set for Cloud Foundry. Try either SimpleCloudFoundry or this management sample

andrew-woosnam commented 2 years ago

Ah ok, yeah that makes sense -- I don't see an executable for Simple in the publish directory created by msbuild like I'm used to seeing for .net core apps published via dotnet publish.

andrew-woosnam commented 2 years ago

Trying again with the https://github.com/SteeltoeOSS/Samples/tree/2.x/Management/src/AspDotNet4/CloudFoundryWeb (<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>):

andrew-woosnam commented 2 years ago

Noticed that the MSBuild publish does produce PDB files in the publish/bin folder: image.png ^ That's with this command:

"C:\Users\awoosnam\source\repos\Samples\Management\src\AspDotNet4\CloudFoundryWeb\CloudFoundryWeb.csproj" /p:DeployOnBuild=true /p:PublishUrl="C:\Users\awoosnam\source\repos\Samples\Management\src\AspDotNet4\CloudFoundryWeb\publish" /p:WebPublishMethod=FileSystem /p:DeployDefaultTarget=WebPublish /p:DebugSymbols=true
andrew-woosnam commented 2 years ago

Adding 2 additional flags (/p:DebugType=full and /p:ExcludeGeneratedDebugSymbol=false) doesn't help the remote debugging process stop at breakpoints, nor does it do anything noticeable to the PDB files in publish/bin image.png

andrew-woosnam commented 2 years ago

Things to try next:

  1. Try to debug locally when the app is running via HWC (helpful cookbook page here) -- if this doesn't work either, I'll assume that HWC is responsible for the debugging difficulties
  2. Try uploading msvsmon.exe (from the local VS installation; mentioned in these docs) in place of vsdbg -- maybe that'll work better?
andrew-woosnam commented 2 years ago

I was just able to successfully bind to a local hwc.exe process following the steps explained here, so that leads me to believe HWC itself isn't the issue. Notably, I bound to the running process via the "Attach to Process" window in my local VS, which is a different flow than the one this vsix uses to attach the remote debugger: image.png

andrew-woosnam commented 2 years ago

Tried copying msvsmon.exe from C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\Remote Debugger\x64 to publish\ folder for this app before deploying it to longbeach. Confirmed that msvsmon.exe was present on the VM before attempting to launch debugger with this config:

{
    "version": "0.2.0",
    "adapter": "c:\\users\\awoosnam\\appdata\\local\\microsoft\\visualstudio\\17.0_a4444530exp\\extensions\\vmware tanzu .net experience\\tanzu toolkit for visual studio 2022\\1.0.0\\Resources\\cf7.exe",
    "adapterArgs": "ssh CloudFoundryWeb -c \u0022c:\\Users\\vcap\\app\\msvsmon.exe --interpreter=vscode\u0022",
    "languageMappings": {
        "C#": {
            "languageId": "3F5162F8-07C6-11D3-9053-00C04FA302A1",
            "extensions": [
                "*"
            ]
        }
    },
    "exceptionCategoryMappings": {
        "CLR": "449EC4CC-30D2-4032-9256-EE18EB41B62B",
        "MDA": "6ECE07A9-0EDE-45C4-8296-818D8FC401D4"
    },
    "configurations": [
        {
            "name": ".NET Core Launch",
            "type": "coreclr",
            "processName": "hwc.exe",
            "request": "attach",
            "justMyCode": false,
            "cwd": "/home/vcap/app",
            "logging": {
                "engineLogging": true
            }
        }
    ]
}

Result: image.png

andrew-woosnam commented 2 years ago

Same result when attempted without the extra "--interpreter" arg:

{
   "version": "0.2.0",
   "adapter": "c:\\users\\awoosnam\\appdata\\local\\microsoft\\visualstudio\\17.0_a4444530exp\\extensions\\vmware tanzu .net experience\\tanzu toolkit for visual studio 2022\\1.0.0\\Resources\\cf7.exe",
   "adapterArgs": "ssh CloudFoundryWeb -c \"c:\\Users\\vcap\\app\\msvsmon.exe\"",
   "languageMappings": {
      "C#": {
         "languageId": "3F5162F8-07C6-11D3-9053-00C04FA302A1",
         "extensions": [
            "*"
         ]
      }
   },
   "exceptionCategoryMappings": {
      "CLR": "449EC4CC-30D2-4032-9256-EE18EB41B62B",
      "MDA": "6ECE07A9-0EDE-45C4-8296-818D8FC401D4"
   },
   "configurations": [
      {
         "name": ".NET Core Launch",
         "type": "coreclr",
         "processName": "hwc.exe",
         "request": "attach",
         "justMyCode": false,
         "cwd": "/home/vcap/app/vsdbg",
         "logging": {
            "engineLogging": true
         }
      }
   ]
}

Result (Debug Adapter Host Log after same modal as above):

1> DebugAdapterHost version: 17.0.60104.1 commit:29d87ee38ccdbf780a0ea7b0c5d48fe162e35437
 1> Starting 'c:\users\awoosnam\appdata\local\microsoft\visualstudio\17.0_a4444530exp\extensions\vmware tanzu .net experience\tanzu toolkit for visual studio 2022\1.0.0\Resources\cf7.exe' with arguments 'ssh CloudFoundryWeb -c "c:\Users\vcap\app\msvsmon.exe"'
 1> [DebugAdapter] --> C (initialize-1): {"type":"request","command":"initialize","arguments":{"pathFormat":"path","clientID":"visualstudio","clientName":"Visual Studio","adapterID":"coreclr","locale":"en-US","linesStartAt1":true,"columnsStartAt1":true,"supportsVariableType":true,"supportsRunInTerminalRequest":true,"supportsMemoryReferences":true,"supportsProgressReporting":true,"SupportsMessageBox":true,"supportsHandshakeRequest":true,"supportsVsAdditionalBreakpointBinds":true,"supportsHitCountsChange":true,"supportsVsCustomMessages":true,"supportsVariableEnumerators":true},"seq":1}
 1> WARNING: Request 'initialize-1' has not received a response within 1000 ms!
 1> ERROR: Debug adapter error output: The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log or use the command-line sxstrace.exe tool for more detail.
 1> Debug adapter process exited.
 1> ERROR: Debug Adapter did not respond to initial requests.
 1> ERROR: Unexpected error

AggregateException: One or more errors occurred.

Aggregate exception: 
    DebugAdapterLaunchException: Failed to launch debug adapter.  Additional information may be available in the output window.

    Failure Location: UserCanceled
    Inner Exception: 
        OperationCanceledException: The operation was canceled.
Inner Exception: 
    DebugAdapterLaunchException: Failed to launch debug adapter.  Additional information may be available in the output window.

Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost.Engine.Implementation.DebuggedProcess.<StartDebugAdapter>b__114_3(Exception ex)
Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost.Utilities.TaskExtensions.<>c__DisplayClass11_0`1.<Catch>b__0(TException ex)
Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost.Utilities.TaskExtensions.<>c__DisplayClass10_0`1.<Catch>b__0(AggregateException ex)

    Failure Location: UserCanceled
    Inner Exception: 
        OperationCanceledException: The operation was canceled.

 1> ERROR: One or more errors occurred.

Failed to launch debug adapter.  Additional information may be available in the output window.

The operation was canceled.
andrew-woosnam commented 2 years ago

I see the same line of output as included in those logs above when trying to execute msvsmon.exe while ssh'd into the app via cf cli:

The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log or use the command-line sxstrace.exe tool for more detail.

andrew-woosnam commented 2 years ago

Including the entire contents of C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\Remote Debugger\x64 (msvsmon.exe + all other dlls, config files, etc) got the process to start on the VM from within Visual Studio (verified via tasklist through cf cli ssh), but breakpoints are still not being hit

Debug Adapter Host Log:

 1> DebugAdapterHost version: 17.0.60104.1 commit:29d87ee38ccdbf780a0ea7b0c5d48fe162e35437
 1> Starting 'c:\users\awoosnam\appdata\local\microsoft\visualstudio\17.0_a4444530exp\extensions\vmware tanzu .net experience\tanzu toolkit for visual studio 2022\1.0.0\Resources\cf7.exe' with arguments 'ssh CloudFoundryWeb -c "c:\Users\vcap\app\remotedebugger\msvsmon.exe"'
 1> [DebugAdapter] --> C (initialize-1): {"type":"request","command":"initialize","arguments":{"pathFormat":"path","clientID":"visualstudio","clientName":"Visual Studio","adapterID":"coreclr","locale":"en-US","linesStartAt1":true,"columnsStartAt1":true,"supportsVariableType":true,"supportsRunInTerminalRequest":true,"supportsMemoryReferences":true,"supportsProgressReporting":true,"SupportsMessageBox":true,"supportsHandshakeRequest":true,"supportsVsAdditionalBreakpointBinds":true,"supportsHitCountsChange":true,"supportsVsCustomMessages":true,"supportsVariableEnumerators":true},"seq":1}
 1> WARNING: Request 'initialize-1' has not received a response within 1000 ms!
andrew-woosnam commented 2 years ago

Just learned that only "Portable PDBs" are supported for remote debugging (at least with the method I'm using) -- wondering if this isn't working for this older .net472 app because the PDBs that get generated when MSBuild publishes the app aren't "portable"?

UPDATE: ^ That may only be true for debugging apps running on a linux/OSX remote? This blurb says:

Windows PDBs can only be written or read on Windows. All Windows tooling supports them, except for Visual Studio Code (as Visual Studio Code strives for consistent behavior across all platforms), and scenarios where Visual Studio is debugging to a remote Linux/OSX computer (as the PDBs must be read on the remote computer).

andrew-woosnam commented 2 years ago

Also of note: even when remote debugging apps running on windows, portable PDBs may not work if the app is old enough (i.e. targets anything earlier than (or equal to??) 4.7.2)

Portable PDBs can be read on any operating system, but there are a number of places where they aren't supported yet. Here are a few –

  • Older versions of the Visual Studio debugger (versions before VS 2015 Update 2).
  • Applications targeting .NET Framework 4.7.1 or earlier1: printing stack traces with mappings back to line numbers (such as in an ASP.NET error page). The name of methods is unaffected, only the source file names and line numbers are unsupported.
  • C# Code analysis (aka FxCop), note that this doesn't apply to Roslyn Analyzer.
  • Some symbol servers (ex: SymbolSource.org does not, nuget.org does)
  • Running post-compilation build step that consumes or modifies the PDB using older versions of tools such as CCI, CodeContracts.
  • Using .NET decompilers such as ILDASM or .NET Reflector and expecting to see source line mappings or local parameter names.
  • MS DIA-based tools such as WinDBG.

Over time we plan to shrink this list of non-supported scenarios so that portable PDB can become the default choice for most usage needs.

  1. When running on .NET Framework 4.7.2 with an app that targets earlier .NET Framework versions we anticipate having an opt-in configuration switch as an additional mechanism to enable support for older applications↩
andrew-woosnam commented 2 years ago

This section implies that the /p:DebugType=full flag for MSBuild specifies that PDBs should be generated in the "old" windows-only style (as opposed to the "new" portable style)

andrew-woosnam commented 2 years ago

Could these symbols not be loading because the HWC buildpack isn't starting the app in debug mode?? (no evidence for this; just a thought)

andrew-woosnam commented 2 years ago

Same results after retargeting .net4.8 -- debugger attaches but break points are not hit (for both vsdbg & msvsmon)

andrew-woosnam commented 2 years ago

One person on stack overflow mentioned that there's something important about the path to PDB files?

andrew-woosnam commented 2 years ago

This article mentions that vsdbg "supports CoreCLR debugging on Linux and macOS"

andrew-woosnam commented 2 years ago

Dave found that when locally debugging an ASP.NET app running in a windows container, this was the start command Docker used:

docker run -dt -v "C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\Remote Debugger:c:\remote_debugger:ro" -v "C:\workspace\WebApplication12\WebApplication12:c:\inetpub\wwwroot" -e "DEV_ENVIRONMENT=1" -e "VBCSCOMPILER_TTL=604800" -e "COMPLUS_ForceENC=1" -P --name WebApplication12 --entrypoint cmd webapplication12:dev /c "start /B C:\ServiceMonitor.exe w3svc & C:\remote_debugger\x64\msvsmon.exe /noauth /anyuser /silent /nostatus /noclrwarn /nosecuritywarn /nofirewallwarn /nowowwarn /fallbackloadremotemanagedpdbs /timeout:2147483646"

Of note:

andrew-woosnam commented 2 years ago

Latest logs from debug adapter host:

1> DebugAdapterHost version: 17.0.60104.1 commit:29d87ee38ccdbf780a0ea7b0c5d48fe162e35437
 1> Starting 'c:\users\awoosnam\appdata\local\microsoft\visualstudio\17.0_a4444530exp\extensions\vmware tanzu .net experience\tanzu toolkit for visual studio 2022\1.0.0\Resources\cf7.exe' with arguments 'ssh CloudFoundryWeb -c "c:\Users\vcap\app\remotedebugger\msvsmon.exe /noauth /anyuser /silent /nostatus /noclrwarn /nosecuritywarn /nofirewallwarn /nowowwarn /fallbackloadremotemanagedpdbs /timeout:2147483646"'
 1> [DebugAdapter] --> C (initialize-1): {"type":"request","command":"initialize","arguments":{"pathFormat":"path","clientID":"visualstudio","clientName":"Visual Studio","adapterID":"coreclr","locale":"en-US","linesStartAt1":true,"columnsStartAt1":true,"supportsVariableType":true,"supportsRunInTerminalRequest":true,"supportsMemoryReferences":true,"supportsProgressReporting":true,"SupportsMessageBox":true,"supportsHandshakeRequest":true,"supportsVsAdditionalBreakpointBinds":true,"supportsHitCountsChange":true,"supportsVsCustomMessages":true,"supportsVariableEnumerators":true},"seq":1}
 1> WARNING: Request 'initialize-1' has not received a response within 1000 ms!
andrew-woosnam commented 2 years ago

Noticed that every time I begin debugging via DebugAdapterHost.Launch using msvsmon.exe, 2 processes are always created (not sure if that's usual, but vsdbg only spun up 1 process) image.png

andrew-woosnam commented 2 years ago

msvsmon security note:

Leaving msvsmon.exe (the remote debugger monitor) unattended in ‘no authentication’ mode is not safe. As with any debugger, msvsmon.exe can start a process upon a request from the network.

andrew-woosnam commented 2 years ago

Confirmed that this app is running on an x64 chip & I'm bundling the x64 version of msvsmon.exe

andrew-woosnam commented 2 years ago

Here are some docs that describe how to remotely debug ASP.NET on a remote IIS server -- at first glance, this process seems way too involved to be easily replicated on our timeline for this extension