Debugging Synergy .NET Code

This topic includes the following sections:

 

The Visual Studio debugger is used for debugging Synergy .NET applications on Windows and on Linux (via remote debugging). See Visual Studio documentation for more information on debugging, and note the following:

Remote debugging

With Visual Studio’s “Attach to Process” feature, you can use Visual Studio to debug the following:

The development machine must have the following:

The remote system must have the following:

The following is a brief summary of the steps for remote debugging Synergy .NET programs. See Microsoft documentation on attaching to running processes for details on this process. (Note that Microsoft’s documentation on attaching to processes includes information on features that are not supported for SDI, features such as attaching to a process running on Azure App Service, attaching to a process running in a Docker container, and reattaching to a process.)

1. In Visual Studio on the development machine, open the solution, project, or source file(s). Set breakpoints as needed.
2. If you are debugging a problem that occurs when the service starts, set the WAIT_FOR_DEBUGGER environment variable on the Linux system. Set it to any value.
3. Start the program on the remote machine or WSL 2 system.
4. In Visual Studio on the development machine, select Debug > Attach to Process.
5. In the “Attach to Process” dialog, select the connection type, connection target, and the remote process. (See Visual Studio documentation for details.) And for a .NET 6 or higher program on a Linux system or WSL 2, click the Select button to open the “Attach to...Select Code Type” dialog. In this dialog, select “Managed (.NET Core for Unix)” and click OK. Additionally,
  • for a program on a remote WSL 2 system, select “Windows Subsystem for Linux (WSL)” or SSH in the “Connect type” field.
  • for a program on a remote Linux machine, select SSH in the “Connect type” field.
6. In the “Available Processes” area of the “Attach to Process” dialog, select the name of the process you want to debug.
7. Click Attach and then start debugging (e.g., select Debug > Start Debugging from the Visual Studio menu).

Setting up the SynergyUnixExpressionEvaluator

In order for expression evaluation to be available when debugging a .NET 6 Harmony Core application on a remote Linux system or WSL 2, SynergyUnixExpressionEvaluator must be set up on the remote system. Without expression evaluation, the debugger will support only the most basic operations (e.g., basic breakpoints and stepping).

To set up the SynergyUnixExpressionEvaluator,

1. Ensure that the remote Linux machine or WSL 2 system has the folder $HOME/.vs-debugger/vs2022. This is created automatically the first time Visual Studio is used to attach to a process on the system. If this folder does not exist on the system, use Visual Studio to remotely attach to a process on that system. For information on attaching to processes, see Microsoft documentation on attaching to running processes with the Visual Studio debugger (e.g., learn.microsoft.com/en-us/visualstudio/debugger/attach-to-running-processes-with-the-visual-studio-debugger).
2. Clone or copy the SynergyUnixExpressionEvaluator repository (github.com/Synergex/SynergyUnixExpressionEvaluator) to the Linux machine or WSL 2 system.
3. On the Linux machine or WSL 2 system, run the CopyDebuggerFiles.sh script, which is in the SynergyUnixExpressionEvaluator repository. This adds Synergy DBL expression evaluation support for remote debugging.

Local variables and the Locals window

Note the following for local variables and the Locals window:

Determining whether a system option is set

To determine whether a system option is set for a Synergy .NET program, enter the following in the Visual Studio Immediate window, where OPTION is the number of the system option (see System Options):

Synergex.SynergyDE.SysRoutines.f_option(Synergex.SynergyDE.IntegerDesc.CreateLiteral(OPTION), Synergex.SynergyDE.VariantDesc.notPassedInteger);*

If the option is set, this returns 1. If the option is not set, it returns 0.

Examining the contents of a dynamic memory handle

1. Open the Locals window, expand the dm variable, locate the name of the dynamic memory handle you want to inspect, and note the integer value assigned to it.
2. In the Immediate window, run the following command, where ## is the number assigned to the dynamic memory handle:
Synergex.SynergyDE.SysRoutines.hatml(##).ToString()

The value for the dynamic memory handle will be displayed below the command you entered in the Immediate window.

If your dynamic memory handle contains null values, you will need to write the results to a file. For example:

System.IO.File.WriteAllText("filename", Synergex.SynergyDE.SysRoutines.hatml(##).ToString())

where filename is the path and name of the file you want to create and ## is the number assigned to the dynamic memory handle.

Synergy types in the Visual Studio Memory Usage Tool

The Visual Studio Memory Usage Tool displays information on Synergy types, but it uses different names for these types:

Synergex.SynergyDE.TypeDesc

Synergex.SynergyDE.PinTypeDesc

Synergex.SynergyDE.RefTypeDesc

For example, a decimal will appear as either Synergex.SynergyDE.DecimalDesc, Synergex.SynergyDE.PinDecimalDesc, or Synergex.SynergyDE.RefDecimalDesc.

Synergex.SynergyDE.Gen_Box<ns1.$$_struct1, ns1.$$_wrap_struct1>

The next example is for a boxed structure named struct2 in namespace ns1:

Synergex.SynergyDE.Gen_Couple<ns1.$$_struct2, ns1.$$_wrap_struct2>

Watch and Quickwatch windows

Synergy DBL Integration includes several Synergy-specific commands for use in the Visual Studio Watch and QuickWatch windows:

Command

Information displayed

^ADDR(expression)

The address for a descriptor type variable specified by expression. This works only for .NET types in Synergy records and i, d, and a Synergy types. It is used in a procedure that determines what changed a variable. See SET WATCH functionality in Visual Studio below.

Show channels

Channel information

Show handles

Handle information

Note the following:

.define g_select  Synergex.SynergyDE.UIToolkit.GlobalState.t_selection

So, to examine g_select you would enter the following in the Watch or QuickWatch window: Synergex.SynergyDE.UIToolkit.GlobalState.t_selection.

For information on the Synergy.SynergyDE.tklib.dll library, see Using UI Toolkit with the .NET Framework.

SET WATCH functionality in Visual Studio

In traditional Synergy, if a variable’s value changes, you can find out what changed it by using WATCH variable or SET WATCH variable. But for Synergy .NET, this functionality is not available as the default in the Visual Studio debugger. Instead, you must use the SOS debugging extension (which is installed with Visual Studio) as outlined in the following procedure. The SOS command !CLRStack dumps current stack traces for all threads at the point the variable changes. By examining these stack traces, you can find out which routine is writing to the variable.

1. Open your Synergy .NET project in Visual Studio, and locate or create a programmatic break or pause in execution (e.g., a point where the program waits for user input) that happens before the variable’s value is changed. You’ll need a programmatic break or pause to give you time to select Break All in step 7.
2. Set a Visual Studio breakpoint at or before the programmatic break.
3. Start debugging the program (Debug > Start Debugging).
4. When the program breaks, use the ^ADDR( ) command in a Watch or QuickWatch window to get the address of the variable. For example, if the name of your variable is my_alpha, enter the following in a Watch or QuickWatch window:
^ADDR(my_alpha)

Note (or copy) the address in the Value column of the Watch or QuickWatch window. You will use the hexadecimal form of this address to set a data breakpoint in step 8. (If a decimal value is displayed in the Value column, you can right-click on the value and select Hexadecimal Display from the context menu.)

5. Detach from the process (Debug > Detach All).
6. Reattach to the process in native mode: Select Debug > Attach to Process, select the process for your program in the Available Processes area of the Attach to Process window, and then click Select. In the Select Code Type window, select Native and clear all other options. Then click OK to close the Select Code Type window, and click Attach in the Attach to Process window.

Detaching and reattaching is necessary because the debugger runs in managed mode by default but must run in native mode for the data breakpoint set in step 8 to work correctly.

7. Select Debug > Break All. You may get an error (e.g., “The process appears to be deadlocked...”) and a “No Source Available” window. Ignore these; just click OK in the error message and close the “No Source Available” window.
8. Set a data breakpoint (Debug > New Breakpoint > New Data Breakpoint) using the hexadecimal address you got in step 4. For example, if the hexadecimal address from that step is 0x0288F0C0, enter this in the Address field of the New Breakpoint window.

1. Set a breakpoint using the hexadecimal address for the variable.

Set a breakpoint using the hexadecimal address for the variable

9. When the breakpoint is set, continue program execution (Debug > Continue).
10. When the debugger breaks at the breakpoint, you’ll see the message “The following breakpoint was hit....” Click OK in this message box.
11. Select Debug > Save Dump As, and then use the Save Dump As window to save a .dmp file.
12. Stop the debugging session (Debug > Stop Debugging).
13. In Visual Studio, select File > Open > File, and then in the Open File window, select the file you saved in the previous step and click Open.
14. A window opens with the title of the .dmp file. In the Actions section of this window, select Debug with Mixed.
15. Enter the following in the Immediate Window:
.load sos

This loads the SOS debugger extension.

16. Enter the following case-sensitive SOS command in the Immediate Window:
!CLRStack

This writes the stack traces to the Immediate Window.

Note that the program’s debugging session is over, so you won’t be able to continue debugging it.