目录 - gitee.com
Transcript of 目录 - gitee.com
134555556789
10101010101111111111111111111112121212131313131414141414141414151515151516
目录目录
目录
Architecture-of-the-MIEngineBuilding-the-MIEngineContributing-Code
Contributing CodeDeveloper WorkflowCreating New IssuesCoding ConventionsCode Formatter
Executing-custom-gdb-lldb-commandsHomeHow-Microsoft.DebugEngineHost-worksLogging
Using debug buildsVisual Studio 2017, and Linux Extension for VS 2015 1.0.7+Using shipping bitsAdditional notes:
Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio-Legacy-InstructionsYour feedbackMachine setup
Visual Studio ComputerLinux Computer
Setting up a transportDockerSSH
Sharing sources and compiled binariesBuilding on WindowsBuilding on LinuxTransferring file
Create launch options file:Using SSHAttaching to a process
Turn off Just My Code if you are retail debuggingStart debuggingDetaching
Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-StudioYour feedbackMachine setup
Visual Studio ComputerLinux Computer
Copying vsdbg from Windows to Linux using PowerShellSetting up a transport
SSHSharing sources and compiled binaries
Building on WindowsBuilding on LinuxTransferring file
Create launch configuration file:Turn off Just My Code if you are retail debugging
目录
1 / 32
16161616181818192020
20202121212121212121212122222222222324242424242424252525262626263031
Start debuggingTroubleshootingDetachingAttaching
Patching-Visual-StudioImportant notesInstructions
Portable-Class-Libraries-(PCL)-used-in-the-MIEngineQuick-tutorial-on-debugging-the-MIEngine
Setup steps:NOTE: If you are using Visual Studio 2017, you will need to find the file Microsoft.MIDebugPackage.pkgdef inside your VisualStudio installation directory. The file resides in <Visual Studio InstallDirectory>\Common7\IDE\CommonExtensions\Microsoft\MDD\Debugger.
Steps:RedistributionRedistributing MIEngine
Changes Required for RedistributionGUIDsStrong Name Signing KeyVSIX ManifestRenamingCommand WindowTestingAdditional Information
Start-debugging-other-platforms-using-the-MIEngineLaunch options XMLStart debuggingTroubleshootingKnown issuesChanging the MIEngine
Testing-with-GlassWhat is Glass?How do Glass tests work?
'expected' attribute on eventsVolatile/RegEx/IgnoreCase/Optional attributes
Debugging Android Glass testsDeveloping new Glass testsEvents that require special care
IDebugBreakpointBoundEvent2IDebugOutputStringEvent2
TestingMIEngine Testing
Running Android Glass TestsAuthoring Glass Tests
Troubleshoot-attaching-to-processes-using-GDBWhat-is-CLRDBG
目录
2 / 32
Let's dig into how the MIEngine is put together. To start, here is an architectural diagram for the various parts of the MIEngine:
The 'Visual Studio Core Debugger' and 'GDB/LLDB' are the two parts of the diagram that are external to this project.
The Visual Studio Core Debugger box represents the Visual Studio UI, and the rest of the core Visual Studio debugging logic. This will call into theMIDebugEngine through the AD7 interfaces (IDebugEngine2, IDebugProgram2, etc). The MIDebugEngine will also call back into AD7 interfaces tosend events (ex: a breakpoint was hit) or in some cases to obtain the objects needed to fulfill the contracts of the AD7 interfaces (ex: to obtain anIDebugProcess2 from the SDM for the newly launched process).
MIDebugEngine/AD7.Impl is the top layer of the MIEngine. This structure of having a layer of the debug engine to implement AD7 is inherited fromthe Debug Engine Sample which is the bases for this project. This layer contains the code required to implement the AD7 interfaces. If you want todig into this layer more, the debug engine sample contains documentation on how debug engines work.
MIDebugEngine/Engine.Impl is where most of the smarts of the MIEngine lives. It presents an object model to the AD7 layer to make it easy for theAD7 layer to do its job.
MICore contains the base functionality used by the Engine.Impl layer, though that definition is a bit fuzzy. There are essentially five things in MICore:
The Debugger class which is the central processor of the text that we get back from GDB/LLDB
The MICommandFactory abstract class and its derived classes. This is our preferred mechanism for dealing with differences between GDB,LLDB, and other MI based debuggers that we support.
The result parser (ResultValue, etc) which handles parsing MI results
The transport classes, which handle setting up the standard input/output connection with GDB
The launch options code, which handles processing the launch option XML, and loading up custom launchers
The only enforced boundary between MICore and Engine.Impl is that the various launchers only depend on MICore. So the types of functionality usedby the launchers must be defined there.
The Android Launch and iOS Launcher handle the details of getting everything prepped so that we can debug on those platforms.
Lastly, all of these dlls depend on Microsoft.DebugEngineHost. More information on how this work can be found here.
Architecture-of-the-MIEngineArchitecture-of-the-MIEngine
Architecture-of-the-MIEngine
3 / 32
Here are the requirements to build the MIEngine:
1. You need to be on Windows. The MIEngine cannot currently be compiled on Unix/MacOS.
2. You need to install Visual Studio 2017 or 2015 (Update 3 is recommended).
3. Verify that you have the right set of Visual Studio features/workloads installed. The MIEngine needs support for Visual Studio extensibility, C#portable class libraries, and you may also want to install the Android C++ support to be able to verify Android scenarios.
Visual Studio 2017Visual Studio 2017:Go to the Windows start menu and run the 'Visual Studio Installer'
Click the menu button on your installed Visual Studio instance, and invoke 'Modify'
Make sure these are checked:.NET desktop development
Visual Studio extension development
[Recommended] Mobile development with C++
Visual Studio 2015Visual Studio 2015:Open Windows Control Panel.
Open the Programs and Features applet.
Find Microsoft Visual Studio 2015 in the list.
Right click and invoke 'Change'.
Click the 'Modify' button.
Make sure these are checkedWindows and Web Development -> Universal Windows App Development Tools
Tools and Windows 10 SDK
Windows 10 SDK
Visual Studio Extensibility Tools
[Recommended] Programming Languages -> Visual C++ -> Common Tools for Visual C++ 2015
Cross Platform Mobile Development[Recommended] Visual C++ Mobile Development
[Recommended] Microsoft Visual Studio Emulator for Android
4. After opening the solution, make sure to switch to the 'Debug' configuration
5. If you find that IntelliSense or the resx designer doesn't work. Try building the solution (which will download all the dependent NuGet packages)and close and reopen the solution.
Building-the-MIEngineBuilding-the-MIEngine
Building-the-MIEngine
4 / 32
Before submitting a feature or substantial code contribution please discuss it with the team. The team reviews and tests all code submissions. Thesubmissions must meet a high bar for quality and design.
The MIEngine project follows a similar developer guide to .NET. The team enforces this by regularly running the .NET code formatter tool on the codebase. Contributors should ensure they follow these guidelines when making submissions.
The team has set the following limits on pull requests:
Contributions beyond the level of a bug fix must be discussed with the team first, or they will likely be declined.
Only contributions against the master branch will be accepted. Authors submitting pull requests that target experimental feature branches orrelease branches will likely be asked target their pull request at the master branch.
Pull requests that do not automatically merge with the tip of the master branch will be declined. The author will be asked to rebase to the tipand update the pull request.
Submissions must meet functional and performance expectations, including scenarios for which the team doesn’t yet have open source tests.This means you may be asked to fix and resubmit your pull request against a new open test case if it fails one of these tests.
Submissions must follow the .Net Foundation Coding Guidelines
Contributors must sign the Microsoft CLA
When you are ready to proceed with making a change, get set up to [[build|Building Testing and Debugging]] the code and familiarize yourself withour workflow and our coding conventions.
You must sign a Contributor License Agreement (CLA) before submitting your pull request. To complete the CLA, submit a request via the form andelectronically sign the CLA when you receive the email containing the link to the document. You need to complete the CLA only once to cover allMicrosoft Open Technologies OSS projects.
1. Work item is assigned to a developer during the triage process
2. Both MIEngine team members and external contributors are expected to do their work in a local fork and submit code for consideration via a pullrequest.
3. When the pull request process deems the change ready it will be merged directly into the tree.
Please follow these guidelines when creating new issues in the issue tracker:
Use a descriptive title that identifies the issue to be addressed or the requested feature.
Do not set any bug fields other than Impact.
Specify a detailed description of the issue or requested feature.
For bug reports, please also:Describe the expected behavior and the actual behavior. If it is not self-evident such as in the case of a crash, provide an explanation forwhy the expected behavior is expected.
Provide example code that reproduces the issue.
Specify any relevant exception messages and stack traces.
Subscribe to notifications for the created issue in case there are any follow up questions.
Use the coding style outlined in the .Net Foundation Coding Guidelines
Use plain code to validate parameters at public boundaries. Do not use Contracts or magic helpers.
if (argument == null){ throw new ArgumentNullException("argument");}
Use Debug.Assert() for checks not needed in retail builds. Always include a “message” string in your assert to identify failure conditions.
Contributing-CodeContributing-Code
Contributing CodeContributing Code
Developer WorkflowDeveloper Workflow
Creating New IssuesCreating New Issues
Coding ConventionsCoding Conventions
Contributing-Code
5 / 32
The MIEngine team regularly uses the .NET code formatter tool to ensure the code base maintains a consistent style over time. The specific optionswe pass to this tool are the following:
/nounicode : In general we follow this rule of not having unicode characters embedded in string literals. However there are a few cases wherethis is needed to verify compiler behavior hence this option is disabled for now.
Code FormatterCode Formatter
Contributing-Code
6 / 32
The MIEngine allows sending commands directly to the underlying debugger (gdb/lldb).
To do so:
View -> Other Windows -> Command Window
Run: Debug.MIDebugExec insert-your-gdb-command-here
Notes:
This is only supported when the target process is stopped
Don't run commands that cause the target process to run again. Visual Studio will still be stopped and everything will get very confused.
Executing-custom-gdb-lldb-commandsExecuting-custom-gdb-lldb-commands
Executing-custom-gdb-lldb-commands
7 / 32
Welcome to the MIEngine wiki. If this is your first time looking at the MIEngine, here are three topics to get you started --
Building the MIEngine
Quick tutorial on debugging the MIEngine
Start debugging other platforms using the MIEngine
Architecture of the MIEngine
HomeHome
Home
8 / 32
Most of the MIEngine assemblies depend on Microsoft.DebugEngineHost. Microsoft.DebugEngineHost provides a number of utility services to theMIEngine. Some examples include configuration, interface marshalling, and wait dialogs.
The basic design of this assembly is that we will actually have multiple versions of this assembly with the same public API, and assembly identity.Thus we can compile all of our other code once and have it work in both IDEs.
Contract versionContract version: The first version of Microsoft.DebugEngineHost is in MIEngine\src\DebugEngineHost.Stub\DebugEngineHost.ref.cs. This definesthe contract that the reset of the code is compiled against.
Visual Studio versionVisual Studio version: Under MIEngine\src\DebugEngineHost you can find the version of DebugEngineHost used when running in Visual Studio.
VS Code versionVS Code version: In a project that we expect to open source in the future (most likely early to mid 2016) you can find the VS Code version ofDebugEngineHost.
In the future Microsoft.DebugEngineHost will likely be turned into a NuGet package so that it can be consumed from any debug engine implementedin managed code. Though we don't have an immediate timeline for when we will do this.
How-Microsoft.DebugEngineHost-worksHow-Microsoft.DebugEngineHost-works
How-Microsoft.DebugEngineHost-works
9 / 32
The MIEngine has logging in it to make it easy to see what commands we are sending to GDB/LLDB, what output GDB/LLDB is returning, and howlong each command took.
If you have the MIEngine solution open and you are hitting F5 using the debug configuration, the logging is automatically on. Just open the outputwindow (Debug->Windows->Output) and you can see the interactions that MIEngine is having with the target debugger.
Open the Visual Studio Command Window (View->Other Windows->Command Window), and use this command to control logging:
Debug.MIDebugLog (/On[:<filename>] | /Off) [/OutputWindow]
Options:
/On[:] – Turn on MIEngine logging. Optionally specify a file to contain the log. Either the file must be supplied, or the “/OutputWindow” optionmust appear.
/Off -- Turn off MIEngine logging. If logging to a file the file is closed.
/OutputWindow -- Log to the “Debug” pane in the output Window.
The command may be issued at any point. Logging can be turned on and off as often as desired. If you have enabled logging viaSetMIDebugLogging.cmd this command will override those settings. Unlike SetMIDebugLogging.cmd, the MIDebugLog state is not rememberedbetween VS invocations.
Logging can also be enabled in a Visual Studio instance without needing to somehow patch the version of the MIEngine used by Visual Studio. To doso:
Clone the sources: git clone https://github.com/Microsoft/MIEngine.gitEnable logging: src\MICore\SetMIDebugLogging.cmd onRestart Visual Studio
Try the scenario
To turn logging back off, run src\MICore\SetMIDebugLogging.cmd offOpen %TMP%\Microsoft.MIDebug.log
SetMIDebugLogging.cmd has no dependencies, so you can copy it to another computer if you don't want to enlist on the target box.
If you are looking at Android scenarios, there is a '/serverlogging' argument to SetMIDebugLogging.cmd which can be used to turn on gdbserverlogging
LoggingLogging
Using debug buildsUsing debug builds
Visual Studio 2017, and Linux Extension for VS 2015 1.0.7+Visual Studio 2017, and Linux Extension for VS 2015 1.0.7+
Using shipping bitsUsing shipping bits
Additional notes:Additional notes:
Logging
10 / 32
The debugger platform has been expanded between Visual Studio 2017 15.3 and older versions of Visual Studio. These legacy instructions are forThe debugger platform has been expanded between Visual Studio 2017 15.3 and older versions of Visual Studio. These legacy instructions are forversion of Visual Studio older than 15.3. The current instructions are [[here|Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio]].version of Visual Studio older than 15.3. The current instructions are [[here|Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio]].
Microsoft and the .NET community have created a new version of .NET, .NET Core, which is designed to be cross-platform, modular, and optimizedfor the cloud.
If you want to develop on the target device itself, you can use Visual Studio Code by following these instructions. But it is also possible to stay inVisual Studio and still debug to Linux or OSX. For day-to-day development, especially if you intend to deploy to a Linux Docker container, VisualStudio 2017 included tools for publishing and debugging to a Docker container. You can also remotely attach to a process over SSH (see MSDN).
In the future, more scenarios are likely to get a more 'on-road' experience from Visual Studio. But for now, for folks who want to play around withnon-Docker scenarios launch, or non-SSH attach or just want to get under the hood and see how things work, this wiki page should walk youthrough how to get things to work in an offroad manner. Pay attention as this will be a bit bumpy.
File bugs and feature requests here. Many issues are likely to be in common with Visual Studio Code, so please also look in the VS Code C#extension github to see if the issue is already filed.
Install Visual Studio 2017 and select the Web workload.
1. Install the .NET Core Command line tools (CLI) .
2. Install CLRDBG by running the following command. Replace '~/clrdbg' with wherever you want clrdbg installed to.
curl -sSL https://aka.ms/getclrdbgsh | bash /dev/stdin -v vs2015u2 -l ~/clrdbg
Visual Studio relies on another executable to take care of remoting stdin/out between the Windows computer and the target computer. The niceside of this is that you can debug as long as you have some way to exchange messages between your two computers; The downside is that this willtake a bit of work to setup. Then again, you are reading the offroad instructions :). Here are some hints for getting things setup with Docker or SSH,but you can bring anything you want.
If your target is running in Docker, you want to install the Docker Toolbox, and configure the Docker client tools to connect to whatever host machineis running your container.
Test to make sure you have things setup correctly by running something like:
REM List the containers so you know which one to target"C:\Program Files\Docker Toolbox\docker.exe" ps"C:\Program Files\Docker Toolbox\docker.exe" exec -i <container-id> /bin/bash -c "echo hello world"REM 'hello world' should print
For SSH support, you will first want to enable SSH in your Linux server. For example, on Ubuntu you can do that by running:
sudo apt-get install openssh-server
Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio-Legacy-Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio-Legacy-InstructionsInstructions
Your feedbackYour feedback
Machine setupMachine setup
Visual Studio ComputerVisual Studio Computer
Linux ComputerLinux Computer
Setting up a transportSetting up a transport
DockerDocker
SSHSSH
Sharing sources and compiled binariesSharing sources and compiled binaries
Building on WindowsBuilding on Windows
Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio-Legacy-Instructions
11 / 32
If you are developing and compiling your app in Visual Studio, you need some way of getting the following on your Linux target machine:
The PDB files for any module you want to debug. Currently, by default, projects built on Windows will notnot generate PDBs that are readable onLinux, so you need to change your project to use Portable PDBs (instructions).
The app itself and any runtime dependencies it might have
The '<proj-name>.deps.json' file which is used by the 'dotnet' host executable to determine runtime dependencies
For simple projects, you can find these files in <SolutionDir>\artifacts\src\<ProjectName>\bin\Debug\netcoreapp1.0. For projects withdependencies, you can use 'dotnet publish' to assemble the files you are likely to need.
If you are compiling your app on Linux, you need some way of sharing sources back to Windows so that Visual Studio can open them. Keep in mindthat we don't yet support checks in the debugger to make sure the files match exactly, so make sure you are debugging with the right set of sourcefiles.
Obviously there any many options to transfer files between Windows and Linux. This document will not try and list all of them, but for those justtrying to kick the tires, here are a few commands you might find useful:
Connect to a Windows share from Ubuntu:
sudo apt-get install cifs-utilssudo mkdir /mnt/mysharesudo mount -t cifs //my-windows-computer/myshare /mnt/myshare -o domain=my-windows-domain,username=myalias,uid=$USER,gid=$USER# /mnt/myshare should now be mapped
To copy files using scp (SSH-based secure copy):
# NOTE: greggm is an example account namec:\mytools\pscp.exe -i c:\users\greggm\my-ssh-key.ppk c:\MyProject\artifacts\src\MyProject\bin\Debug\netcoreapp1.0\* greggm@mylinuxbox:/home/greggm/myproject
Next, you need to create an XML file that will tell Visual Studio how to debug. You may want to savehttps://github.com/Microsoft/MIEngine/blob/master/src/MICore/LaunchOptions.xsd to your project so that the XML editor will give youIntelliSense for the file. Here is an example launch option file which uses plink.exe to connect to the target over SSH and launch a project called'clicon':
<?xml version="1.0" encoding="utf-8" ?><PipeLaunchOptions xmlns="http://schemas.microsoft.com/vstudio/MDDDebuggerOptions/2014" PipePath="c:\mytools\plink.exe" PipeArguments="-i c:\users\greggm\ssh-key.ppk greggm@mylinuxbox -batch -t ~/clrdbg/clrdbg --interpreter=mi" TargetArchitecture="x64" MIMode="clrdbg" ExePath="dotnet" WorkingDirectory="~/clicon" ExeArguments="bin/Debug/netcoreapp1.0/MyExmapleApp.dll"></PipeLaunchOptions>
Let's look at how this works:
PipePath: this is the path to the executable that MIEngine will launch that will connect to the target computer, launch clrdbg, and establish thatstdin/out connection. If you are using Docker, you want this set to 'C:\Program Files\Docker Toolbox\docker.exe' (or wherever the Docker clienttools are installed).
PipeArguments: Any arguments that the executable specified in 'PipePath' takes. In my example, I am telling plink.exe the path to my privateSSH key, telling it to connect to my SSH Linux box, and telling it to run executable clrdbg from the '~/clrdbg' directory that I installed it to. If Iwas using Docker, I might set this to 'exec -i ~/clrdbg/clrdbg --interpreter=mi'.
ExePath: the path, on the Linux computer, to the executable I want to run. .NET Core provides a generic host executable ('dotnet') which theinstaller adds to the path. So as long as your application uses the default 'dotnet' host executable, you can leave this as-is.
ExeArguments: If you are using the 'dotnet' host executable, the first argument is the path to the dll you want to run. After that you can includeany command line arguments that your executable accepts.
As of VS 2017, you no longer need to use pipe launch options for SSH. Instead you can use this builtin SSH support like this:
Building on LinuxBuilding on Linux
Transferring fileTransferring file
Create launch options file:Create launch options file:
Using SSHUsing SSH
Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio-Legacy-Instructions
12 / 32
<?xml version="1.0" encoding="utf-8" ?><SSHLaunchOptions xmlns="http://schemas.microsoft.com/vstudio/MDDDebuggerOptions/2014" TargetMachine="169.254.2.3" TargetArchitecture="x64" MIMode="clrdbg" ExePath="dotnet" WorkingDirectory="~/clicon" ExeArguments="bin/Debug/netcoreapp1.0/MyExmapleApp.dll"></SSHLaunchOptions>
You can also use launch option files to attach to the target process. For example, here is how to attach to process id #13594 with a clrdbg installedto ~/clrdbg:
<PipeLaunchOptions xmlns="http://schemas.microsoft.com/vstudio/MDDDebuggerOptions/2014" PipePath="c:\mytools\plink.exe" PipeArguments="-i c:\users\greggm\my-ssh-key.ppk greggm@mylinuxbox -batch -t ~/clrdbg/clrdbg --interpreter=mi" TargetArchitecture="x64" MIMode="clrdbg" ProcessId="13594"> <LaunchCompleteCommand>None</LaunchCompleteCommand></PipeLaunchOptions>
If you are attempting to debug retail code, you will want to turn off Just My Code through Tools->Options->Debugging in Visual Studio. MIEngine hassome issues doing this on the fly still, so I would recommend doing it before start debugging.
1. Start Visual Studio
2. View->Other Windows->Command Window
3. Debug.MIDebugLaunch /Executable:dotnet /OptionsFile:<path-to-the-xml-file-you-saved>
Use 'Debug->Detach All' to detach from the process. Stop debugging will terminate the process. SSH AttachSSH Attach
Attaching to a processAttaching to a process
Turn off Just My Code if you are retail debuggingTurn off Just My Code if you are retail debugging
Start debuggingStart debugging
DetachingDetaching
Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio-Legacy-Instructions
13 / 32
Microsoft and the .NET community have created a new version of .NET, .NET Core, which is designed to be cross-platform, modular, and optimizedfor the cloud.
If you want to debug on the target device itself, you can use Visual Studio Code by following these instructions. But it is also possible to stay inVisual Studio and still debug to Linux or OSX. For day-to-day development, especially if you intend to deploy to a Linux Docker container, VisualStudio 2017+ included tools for publishing and debugging to a Docker container . You can also remotely attach to a process over SSH. As of VisualStudio 2019 version 16.3, Docker attach support is also included with Visual Studio.
In the future, more scenarios are likely to get a more 'on-road' experience from Visual Studio. But for now, for folks who want to play around withnon-Docker scenarios launch, or non-SSH/Docker attach or just want to get under the hood and see how things work, this wiki page should walkyou through how to get things to work in an offroad manner. Pay attention as this will be a bit bumpy.
The debugger platform has been expanded between Visual Studio 2017 15.3 and previous versions of Visual Studio. Visual Studio can nowcommunicate using the debug adapter protocol which is used by Visual Studio, Visual Studio Code and Visual Studio for Mac. This protocol is nowused for debugging cross-platform .NET Core applications. The following instructions apply to Visual Studio 15.3 (and newer). If you are constrainedto an older version of Visual Studio refer to the [[legacy instructions|Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio-Legacy-Instructions]].
File bugs and feature requests here. Many issues are likely to be in common with Visual Studio Code, so please also look in the VS CodeOmniSharp C# extension GitHub to see if the issue is already filed.
Install Visual Studio 2017 or newer and select the .NET Core workload. If you already have Visual Studio, you can do this from within the installer.
The Linux system needs to have the .NET CLI tools, dotnet , and a vsdbg debugger installed.
1. Install the .NET Core Command line tools (CLI) .
2. Install VSDBG by running the following command. Replace '~/vsdbg' with wherever you want vsdbg installed to.
# Using cURLcurl -sSL https://aka.ms/getvsdbgsh | bash /dev/stdin -v vs2017u5 -l ~/vsdbg# Alternatively, wgetwget https://aka.ms/getvsdbgsh -O - 2>/dev/null | /bin/sh /dev/stdin -v vs2017u5 -l ~/vsdbg
If you want to download vsdbg on Windows and then copy it to your Linux/Mac computer/container, you can use the .ps1 script with this one-liner.Other supported RuntimeID values are linux-musl-x64 , linux-arm and osx .
powershell -NoProfile -ExecutionPolicy unrestricted -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;&([scriptblock]::Create((Invoke-WebRequest -useb 'https://aka.ms/getvsdbgps1'))) -Version vs2017u5 -RuntimeID linux-x64 -InstallPathc:\vsdbg\linux-x64"
Visual Studio relies on another executable to take care of remoting stdin/out between the Windows computer and the target computer. The niceside of this is that you can debug as long as you have some way to exchange messages between your two computers; The downside is that this willtake a bit of work to setup. Then again, you are reading the offroad instructions :). Here are some hints for getting things setup with Docker or SSH,but you can bring anything you want.
For SSH support, you will first want to enable SSH in your Linux server. For example, on Ubuntu you can do that by running:
sudo apt-get install openssh-server
Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-StudioOffroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio
Your feedbackYour feedback
Machine setupMachine setup
Visual Studio ComputerVisual Studio Computer
Linux ComputerLinux Computer
Copying Copying vsdbg from Windows to Linux using PowerShell from Windows to Linux using PowerShell
Setting up a transportSetting up a transport
SSHSSH
Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio
14 / 32
Then, on Windows you need an SSH client designed to be used programmatically. Plink.exe from PuTTY fits the bill, though you can certainly useother tools too. If you are running on a recent version of Windows 10, you can use the built-in ssh.exe ( C:\Windows\sysnative\OpenSSH\ssh.exe ).Note: Using C:\Windows\System32\ will not work as expected.
Next, you need a scriptable way to authenticate. One option is to provide the password on the command line, but obviously there are some securityconcerns there. A more secure option is to use SSH keys --
1. Download puttygen.exe from PuTTY.
2. Run the tool and click 'Generate' and follow the instructions. Note: leave 'Key passphrase' empty, otherwise plink.exe will fail to open the key.
3. Save the generated private key to a file.
4. Copy the public key's text from the top part of the PuTTY Key Generator's Window.
5. Add this to the ~/.ssh/authorized_keys file on your server.
6. Test your connection from the command line. This will also allow you to accept the server's key on the client, which must be done the first time.
Example:
c:\mytools\plink.exe -i c:\users\greggm\ssh-key.ppk greggm@mylinuxbox -batch -T echo "hello world"# 'hello world' should print
If you are developing and compiling your app in Visual Studio, you need some way of getting the following on your Linux target machine:
The PDB files for any module you want to debug. Note that only Portable PDBs are supported.
The app itself and any runtime dependencies it might have
The '<proj-name>.deps.json' file which is used by the 'dotnet' host executable to determine runtime dependencies
For simple projects, you can find these files in <SolutionDir>\artifacts\src\<ProjectName>\bin\Debug\<TargetFramework>. For projects withdependencies, you can use 'dotnet publish' to assemble the files you are likely to need.
If you are compiling your app on Linux, you need some way of sharing sources back to Windows so that Visual Studio can open them.
Obviously there any many options to transfer files between Windows and Linux. This document will not try and list all of them, but for those justtrying to kick the tires, here are a few commands you might find useful:
Connect to a Windows share from Ubuntu:
sudo apt-get install cifs-utilssudo mkdir /mnt/mysharesudo mount -t cifs //my-windows-computer/myshare /mnt/myshare -o domain=my-windows-domain,username=myalias,uid=$USER,gid=$USER# /mnt/myshare should now be mapped
To copy files using scp (SSH-based secure copy):
# NOTE: greggm is an example account namec:\mytools\pscp.exe -i c:\users\greggm\my-ssh-key.ppk c:\MyProject\artifacts\src\MyProject\bin\Debug\netcoreapp1.0\* greggm@mylinuxbox:/home/greggm/myproject
Next, you need to create an launch.json file that will tell Visual Studio how to debug. Here is an example launch.json file which uses plink.exe toconnect to the target over SSH and launch a project called 'clicon':
{ "version": "0.2.0", "adapter": "c:\\mytools\\plink.exe", "adapterArgs": "-i c:\\users\\greggm\\ssh-key.ppk greggm@mylinuxbox -batch -T ~/vsdbg/vsdbg --interpreter=vscode", "configurations": [
Sharing sources and compiled binariesSharing sources and compiled binaries
Building on WindowsBuilding on Windows
Building on LinuxBuilding on Linux
Transferring fileTransferring file
Create launch configuration file:Create launch configuration file:
Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio
15 / 32
{ "name": ".NET Core Launch", "type": "coreclr", "cwd": "~/clicon", "program": "bin/Debug/netcoreapp1.0/clicon.dll", "request": "launch" } ]}
Let's look at how this works:
Adapter: This is the path to the executable that VSCodeDebugAdapterHost will launch that will connect to the target computer, launch vsdbg,and establish that stdin/out connection. Any tools that forward the stdin/stdout from vsdbg on a remote machine can be used.
AdapterArgs: Any arguments that the executable specified in 'Adapter' takes. In my example, I am telling plink.exe the path to my private SSHkey, telling it to connect to my SSH Linux box, and telling it to run executable vsdbg from the '~/vsdbg' directory that I installed it to. If you notusing plink, make sure to set any flags that preserve whitespace since the debug adapter protocol relies on the exact byte length of messages.The -T flags disables PTY allocation, which is important for byte length. Be sure to use -T and not -t .
Program: The path, on the Linux computer, to the executable I want to run. Since the debuggee is a .NET Core assembly, vsdbg willautomatically run the program with the dotnet host executable.
If you are attempting to debug retail code, you will want to turn off Just My Code through Tools->Options->Debugging in Visual Studio.
1. Start Visual Studio
2. View->Other Windows->Command Window
3. DebugAdapterHost.Launch /LaunchJson:"<path-to-the-launch.json-file-you-saved>" /EngineGuid:541B8A8A-6081-4506-9F0A-1CE771DEBC04
If you run into problems getting this to work, you can turn on logging by opening the VS Command Window (View->Other Windows->CommandWindow), and running: DebugAdapterHost.Logging /On /OutputWindow . This will then send logging messages to the output window ('DebugAdapter Host Log' pane). You can also add /Verbosity:debug for more information.
The error message 'The debug adapter exited unexpectedly' means that the transport executable (plink.exe in the above example) exitedunexpectedly. A few notes in troubleshooting this --
As noted in the first troubleshooting step, the logs are the first place to look. The transport may have written errors before it exited ( Debugadapter error output: lines).
If the target process is running in a Docker container, this could indicate that the container shutdown. For example because the additionalmemory used by the debugger caused the container to hit its memory limit.
This could also indicate that vsdbg running in the container is crashing or being aborted. You can confirm or deny this by modifying thetransport command line to run a script that would run vsdbg and then output vsdbg's exit code.
Use 'Debug->Detach All' to detach from the process. Stop debugging will terminate the process.
Instead of launching, it is also possible to attach in a similar way. Here is an example launch.json file that attaches to a process running in a Dockercontainer:
{ // NOTE: replace 'my_container_name' with the name of the container you want to connect to "version": "0.2.0", "adapter": "docker.exe", "adapterArgs": "exec -i my_container_name /remote_debugger/vsdbg --interpreter=vscode", "configurations": [ { "name": ".NET Core Docker Attach", "type": "coreclr", "request": "attach",
Turn off Just My Code if you are retail debuggingTurn off Just My Code if you are retail debugging
Start debuggingStart debugging
TroubleshootingTroubleshooting
DetachingDetaching
AttachingAttaching
Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio
16 / 32
// replace with the process id you want to attach to. You can find this by running 'pidof' in the container // ex: `docker exec -it my_container_name pidof dotnet` "processId": 93 } ]}
Notes:
1. Docker support is now built in to the Attach To Process dialog, so use this as a starting point if you need to use a custom transport (example:kubernetes). But please don't actually use this for Docker any longer.
2. This requires that vsdbg is installed to the container. In this case it assumes it is installed to the /remote_debugger folder (see 'adapterArgs'line above). See the Linux Computer section for more information on obtaining vsdbg.
{ "version": "0.2.0", "adapter": "c:\\mytools\\plink.exe", "adapterArgs": "-i \"c:\\users\\greggm\\ssh-key.ppk\" greggm@mylinuxbox -batch -T docker exec -i my_container_name /remote_debugger/vsdbg --interpreter=vscode", "configurations": [ { "name": ".NET Core Remote SSH Docker Attach", "type": "coreclr", "request": "attach", // NOTE: This assumes the Docker process is PID 1. Use `top` or `pidof` to check "processId": 1 } ]}
Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio
17 / 32
Patching an experimental VS instance with a new version of the MIEngine is super easy - just hit F5 in the MIEngine solution. But after you think yourchanges are ready, you might want to patch the regular (non-experimental) VS instance. This page provides instructions on how to do this.
The open source MI Engine project is not an official Microsoft product and therefore is not officially supported by Microsoft. Though you cancertainly open issues in this repo if you encounter problems.
This is not an appropriate mechanism to broadly distribute an updated MIEngine. This is meant for development and testing purposes only.
To avoid getting your Visual Studio instance in an inconsistent state, please restore back to an official version before installing Visual Studioupdates (see last step of instructions).
This will break parts of Visual Studio that depend on MIEngine. Currently this is Android Java debugging.
If you are only interested in doing a quick one-time test, you can just F5 the MIEngine solution instead. This will launch an 'Experimental'instance of VS. See the tutuorial for more information.
1. If you haven't already, clone this project. To clone from the Microsoft fork: git clone https://github.com/Microsoft/MIEngine.git2. Follow the instructions to build the project. For daily usage of MIEngine, you may want the Release configuration rather than Debug. The rest of
the instructions in this page will use Release.
3. Run C:\proj\MIEngine\bin\Release\drop\Install.cmd "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise" Where C:\proj\MIEngineshould be replaced with whatever the root of your MIEngine repository is and "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise"should be replaced with the root of a VS 2015 or VS 2017 install. See Install.cmd /? for more information.
4. When you are done with your private version of the MIEngine, restore back by running C:\proj\MIEngine\bin\Release\drop\Install.cmd"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise" /restore .
Patching-Visual-StudioPatching-Visual-Studio
Important notesImportant notes
InstructionsInstructions
Patching-Visual-Studio
18 / 32
Many of the MIEngine assemblies are Portable Class Library (PCL) projects. A PCL enables you to write and build managed assemblies that can becompiled once, but run against multiple versions of the .NET Framework. The MIEngine PCL projects are configured to support .NET Standard 1.3,which is supported by .NET Framework 4.6 and .NET Core Core 1.0.
PCLs work because the .NET Framework team took their API which was historically defined in a few different assemblies (ex: mscorlib.dll, System.dll,etc) and refactored the API definition (the assemblies that are compiled against) into a series of 'contract' assemblies (ex: System.Collections.dll)these assemblies define the shape of the API, but aren't used at runtime. At runtime, the implementation can either be in the full version of this dll,or, and this is always the case when running against the desktop CLR, the API can still be implemented in the traditional assembly (ex:mscorlib). Inthis later case there is a 'façade' version of the assembly that just forwards all the types back to the traditional assembly. There is a longerdescription of PCLs in a blog post from the .NET team (link).
The MIEngine uses PCLs to enable it to run both against the Desktop CLR (when used in Visual Studio) and CoreCLR so that it can run onMacOS/Linux/Windows for use in VS Code scenarios.
Portable-Class-Libraries-(PCL)-used-in-the-MIEnginePortable-Class-Libraries-(PCL)-used-in-the-MIEngine
Portable-Class-Libraries-(PCL)-used-in-the-MIEngine
19 / 32
This wiki page will give a quick overview on how you can get started digging into the source code of the MIEngine. In this tutorial, we are going todebug an Android native C++ project, as support for Android is built into Visual Studio. If you are interested in modifying the MIEngine to target someother platform, this tutorial is still probably useful to you so that you can see how to quickly test your code for the Android scenario.
1. Install Visual Studio on a real computer (not a VM), as this tutorial uses the Visual Studio Emulator for Android (see system requirements).
2. Follow the instruction in building the MIEngine. The Android tooling that this page talks about is required.
3. If you haven't already done so, clone the MIEngine repository.
1. In Microsoft.MIDebugPackage.pkgdef , locate the following lines:
[$RootKey$\BindingPaths\{7A28CEDA-DA3E-4172-B19A-BB9C810046A6}]"$PackageFolder$"=""
2. Comment those lines out by adding a ; in front of the lines like below:
; [$RootKey$\BindingPaths\{7A28CEDA-DA3E-4172-B19A-BB9C810046A6}]; "$PackageFolder$"=""
3. Open a Developer Command Prompt and run devenv.exe /updateConfiguration .
1. Start your main instance of Visual Studio, and open MIDebugEngine.sln.
2. In solution explorer, find the MIDebugEngine project, and open Engine.Impl\DebuggedProcess.cs.
3. Find the Initialize method of the class, and set a breakpoint.
4. Hit F5 to start debugging. This will launch an experimental instance of Visual Studio.
5. In The experimental instance:
i. File -> New Project, Visual C++ -> Cross Platform -> Native-Activity Application (Android).
ii. Open main.cpp from the created project.
iii. Set a breakpoint in the android_main method.
iv. F5 or Debug -> Start Debugging to start debugging. The Android emulator should startup. This will be slow the first time, but should besubsequently fast.
6. Your breakpoint in DebuggedProcess.Initialize will hit. You can step through and see the commands that are being sent to GDB if you like. If youopen the output window in your main Visual Studio instance, you can also see all the commands that we sent and the response/events thatcame back.
7. Hit F5 from this breakpoint and see your experimental instance stop at a breakpoint as well.
Quick-tutorial-on-debugging-the-MIEngineQuick-tutorial-on-debugging-the-MIEngine
Setup steps:Setup steps:
NOTE: If you are using Visual Studio 2017, you will need to find the file NOTE: If you are using Visual Studio 2017, you will need to find the file Microsoft.MIDebugPackage.pkgdef inside your Visual Studio inside your Visual Studioinstallation directory. The file resides in installation directory. The file resides in <Visual Studio Install Directory>\Common7\IDE\CommonExtensions\Microsoft\MDD\Debugger ..
Steps:Steps:
Quick-tutorial-on-debugging-the-MIEngine
20 / 32
The license of the MIEngine project allows for redistribution, but certain changes must be made in order to ensure different distributions do notconflict with Microsoft's. The VSIX package produced by the build is named MIDebugEngine.DoNotInstall.vsix because it will corrupt the MIEnginethat ships with Visual Studio if installed directly. With the correct changes, you can produce a VSIX that is installable side by side with the officialMIEngine distributed by Microsoft.
Multiple GUIDs need to be replaced in order to redistribute.
1. The COM Registration GUID must be replaced in AD7Engine.cs and two places in Microsoft.MIDebugEngine.pkgdef.
2. The EngineId GUID must be replaced in EngineConstants.cs and Microsoft.MIDebugEngine.pkgdef.
3. If redistributing the iOS or Android Launcher binaries, their COM Registration GUIDs must be changed on both their Launcher classes and theirpkgdef files. Unless you actually want to support Android/iOS we would suggest deleting or disabling these projects.
4. All GUIDs in the MIDebugPackage project must change. GUIDs are located in Guids.cs, MIDebugPackage.vsct, andsource.extension.vsixmanifext.
You will need to strong name sign your redistributable binaries with your own private key. The development key is checked in the Keys directory asExternalKey.snk. This key is referenced by miengine.settings.targets. For more information on signing binaries with your own key, see MSDN.
In addition to updating the GUIDs in source.extension.vsixmanifext, you will need to update all other pertinent information in the manifest to reflectyour distribution.
It is fine to use the MIEngine name in redistributions, we expect that 'Microsoft' would be removed from all binaries being redistributed. For exampleMicrosoft.MIEngine.dll -> YourNameHere.MIEngine.dll.
The easiest way to get this correct is to Find/Replace-In-Files (Ctrl+Shift+F and Ctrl+Shift+H) on the MIEngine directory.
The Microsoft version of the MIEngine will register the Debug.MIDebugLaunch and Debug.MIDebugExec command window commands. You will eitherneed to rename these commands (easy way) or remove the MIDebugPackage from the vsix (harder way) if you don't care about command windowintegration.
After completing these steps, please test your VSIX on a copy of Visual Studio that has the Microsoft MIEngine installed (in Visual Studio setup,'Cross Platform Mobile Development -> Visual C++ Mobile Development' is checked). Make sure that your version of the MIEngine isn't being usedfor Android scenarios and that the Android debugger still works.
If you would like to redistribute MIEngine and have additional questions, please contact us at [email protected].
RedistributionRedistribution
Redistributing MIEngineRedistributing MIEngine
Changes Required for RedistributionChanges Required for Redistribution
GUIDsGUIDs
Strong Name Signing KeyStrong Name Signing Key
VSIX ManifestVSIX Manifest
RenamingRenaming
Command WindowCommand Window
TestingTesting
Additional InformationAdditional Information
Redistribution
21 / 32
Visual Studio ships with support for debugging on Android or iOS, which is powered by this project. But even though MIEngine doesn't have officialsupport for other platforms yet, MIEngine is a very good start towards hooking Visual Studio to GDB/LLDB for debugging on other platforms as well.On this page we will walk though how to do this.
The MIEngine accepts a set of options when we start debugging to tell it what to debug. Here is an example:
<PipeLaunchOptions xmlns="http://schemas.microsoft.com/vstudio/MDDDebuggerOptions/2014" PipePath="plink.exe" PipeArguments="-i private.ppk user@server -batch -t gdb --interpreter=mi" ExePath="/home/user/YourDir/exe" ExeArguments="" TargetArchitecture="X64" WorkingDirectory="/home/user/YourDir" AdditionalSOLibSearchPath=""> </PipeLaunchOptions>
The MIEngine supports several different types of XML elements, here is a list:
PipeLaunchOptions - use some program to connect to a target device, and run gdb/lldb on that target device, passing back stdin/out. Anexample of such a program is plink.exe from the PuTTY project which can be used to connect to the target device over SSH. For anotherexample, the Docker client executable can also be used as a pipe to run commands inside the target container using 'docker exec'.
LocalLaunchOptions - runs gdb/lldb locally (on the same Windows computer where Visual Studio is running) and either connect to somegdbserver end point, or debug a local windows process.
TcpLaunchOptions - connect to a TCP/IP port that GDB input/output has been piped through.
SerialPortLaunchOptions - connect to a serial port that GDB input/output has been piped through.
More details on all the options can be found in MICore\LaunchOptions.xsd. If you open this file in Visual Studio before you start to author your ownlaunch options file, the XML language service will validate your XML against the schema, provide auto-complete and give you access to thedocumentation.
In the master branch, the launch options XML also supports replacing or adding custom launch commands. This is with the SetupCommands /CustomLaunchSetupCommands / LaunchCompleteCommand elements which are nested inside the top level option xml element. Note that thissupport didn't ship with VS 2015 RTM, but will be included in future releases of Visual Studio.
To start debugging, we need to call the Visual Studio start debugging API (IVsDebugger[2/3/4].LaunchDebugTargets[2/3/4]) passing in those XMLlaunch options in the 'bstrOptions' field, and setting the 'guidLaunchDebugEngine' to the engine Guid of the MIEngine.
Visual Studio ships with some basic support for calling this API without needing to write code so that you can easily experiment with launch options--
In Visual Studio, go to View->Other Windows->Command Window to open up the Visual Studio command window
Run the following command. Note that friendly name can be anything you want as long as the real path to the target is in the options file (or thedefault launch command are overridden so that the real path to the executable doesn't matter anyway). Debug.MIDebugLaunch /Executable:<friendly_name> /OptionsFile:<path-to-file>
Once you have everything working, its possible to make a Visual Studio extension to start debugging without needing to write the launch options todisk or use the command window. To see the source code for how Debug.MIDebugLaunch works so you can do this in your own extension openMIDebugPackagePackage.cs and look at the LaunchDebugTarget function. To create projects which will start debugging using your extension, youwant to create a Visual C++ 2015 Debugger Launch Extension. If you want something simpler, you could certainly also just add a Visual Studiomenu item.
If you are still using VS 2015 RC, I would recommend upgrading to something more recent (ex: pull down sources from master), as we have madeimprovements to our diagnostics since RC.
Beyond that, I would recommend starting by looking at logs. See Logging.
Start-debugging-other-platforms-using-the-MIEngineStart-debugging-other-platforms-using-the-MIEngine
Launch options XMLLaunch options XML
Start debuggingStart debugging
TroubleshootingTroubleshooting
Known issuesKnown issues
Start-debugging-other-platforms-using-the-MIEngine
22 / 32
We have a number of known issues with supporting other platforms that might be relevant to what you are trying to do. These are issues that weintend to fix, though if you are interested in working on these contributions are welcome.
Issues list
If you find you need to make changes to the MIEngine to support your platform, we are happy to accept high quality changes (see instructions).
If you then want to distribute your changes, you have a few options:
1. If you just are distributing changes to a couple of machines in your office, you can use Install.cmd (see instructions).
2. Visual Studio ships frequent updates, so you can wait for Microsoft to distribute your changes in the next update. We generally recommend thisapproach.
3. You can redistribute your own copy.
Changing the MIEngineChanging the MIEngine
Start-debugging-other-platforms-using-the-MIEngine
23 / 32
The MIEngine has a number of Glass-based tests. Glass is a console tool for testing Visual Studio debugger backend extensions (ex: debugengines, expression evaluators, and Concord components) outside of Visual Studio. It calls the debugger API's in a way that is very similar to whatthe UI would do, but in a way that is meant to be fast and easy to test.
The tests run glass2.exe against an XML input script. This input script (TestScript.xml) tells Glass what commands to run, and what should happenas a result of running the commands. Glass then produces two different output files - an error log (ErrorLog.xml) which contains differences betweenthe expected values and the observed values, and a session log (SessionLog.xml) which is a log of everything that happened. One useful thing isthat session logs have the same format as an input script, so you can also take a session log, tweak it a little bit, and now you have a test script.
Let's look at MIEngine\test\Android\Sanity\TestScript.xml as an example of how test scripts work. You can see that the script executes a numberof commands. In response to the 'launch' command, you can see that many events are generated. The last of these events isIDebugBreakpointEvent2. This is a stopping event, so when Glass receives this event, it will determine where it stopped and output thefunctionName/function/file/line/col attributes indicating where it stopped.
Now that you have a basic feel for the test script, let's cover the less obvious concepts --
In Glass, every event gets an 'expected' attribute which is set to 'True' or 'False'.
In an input script, 'expected="True"' tells Glass that it shouldn't move on to the next command until this expected event arrives. Conversely non-expected events are ignored by Glass if they are in an input script. They are only there because input scripts are just a session log.
In a session log, 'expected="True"' means that an event arrived that is in the set of events that Glass has been told to treat as an expected event.By default, an event is marked as expected if it is a stopping event (ex: breakpoint hit, set complete, etc), session destroy (which means debuggingstopped) or an error event (minor note: IDebugTimeContextChangeEvent100 is also expected, but the MIEngine will never send this). It's alsopossible to make other events expected using the setAsExpectedEvent/ignore Glass commands. If the session log was created because Glass isrunning a test (as opposed to running Glass interactively to develop a new test), and an expected event arrives that wasn't expected by the test,Glass will fail the test.
In addition to validating that the right set of expected events arrive, Glass determines if a test passes or fails by comparing the child XML elementsof 'Command' or 'Event' elements (ex: the functionName/function/file/line/col elements from the sanity test). However, sometimes we want Glassto do some sort of fuzzy match rather than requiring the text to exactly match. Glass supports the following attributes for doing a fuzzy match:
Volatile: This is for content that will change every run of the test, as long as this element shows up, consider it a match.
RegEx: Test the specified regular expression against the text. Note that this is considered a match as long as it matches anywhere in the text.So if you want to require the full text to match be sure to use '^' (start of the string) and '$' (end of the string). Ex, you could match to anunsigned base-10 integer with: ^[0-9]+$.
IgnoreCase: Use a case-insensitive comparison
Optional: It is okay if the element is missing
To debug Glass, you can set the 'GLASS_DEBUG=1' environment variable. Then you can attach a debugger to the glass2.exe process. You can alsopass the '/v' (Verbose) option to androidtest.cmd which will list the command line arguments being passed to Glass. You can then copy/pastethese into the debug settings in a project. You can also File->Open Project in Visual Studio and point to glass2.exe to create an exe project forGlass, and then set the working directory/command line arguments.
When debugging Glass it can be useful to make a few tweaks to the command line:
'-diag' will output extra diagnostics. You can open up the output window in your debugger to see what commands were executed. If you doubleclick on these lines, Visual Studio will navigate to that line in the TestScript/target app source code.
Use '-s CON' instead of '-s SessionLog.xml' to write the session log output to the console.
Testing-with-GlassTesting-with-Glass
What is Glass?What is Glass?
How do Glass tests work?How do Glass tests work?
'expected' attribute on events'expected' attribute on events
Volatile/RegEx/IgnoreCase/Optional attributesVolatile/RegEx/IgnoreCase/Optional attributes
Debugging Android Glass testsDebugging Android Glass tests
Developing new Glass testsDeveloping new Glass tests
Testing-with-Glass
24 / 32
There are two useful techniques for developing new Glass-based tests:
#1: Use a SessionLog.xml as a TestScript.xml -- Here you create a very minimal TestScript.xml (one that will not pass), run that to generate aSessionLog, and use the session log as your test script.
Steps:
Create a minimal TestScript.xml -- list the commands you want to run, and fill in the name of the expected events but don't bother getting anyof the details correct. You can usually start with an existing TestScript.xml and then modify what you want to change.
Run the test. This will fail but generate a SessionLog.xml.
Look at the SessionLog.xml. Make sure that the output is what you expect, and remove anything from the session log that you don't want totest. The most common thing that you need to tweak is to remove 'OutputString' elements.
Copy SessionLog.xml to TestScript.xml.
-or-
#2: Use Glass in interactive mode -- Glass can function as a basic command line debugger, and you can use that to develop tests.
Steps:
Start glass2.exe. You can start up glass2.exe without a test script at all, or with a minimal test script that uses the 'interact' command whenyou want to switch to interactive mode.
Issue commands to Glass like it is a regular debugger (ex: type 'step' to issue the 'step' command).
Use the 'help' command to list commands and get their syntax. The information here isn't perfect, but its a start. You can search through otherTestScript.xml's to see how other tests are using the command.
At the end, edit and save the session log just like technique #1.
When you are developing a glass test, there are a few events that you want to be a little careful about --
By default IDebugBreakpointBoundEvent2 is not considered an expected event and, in some tests, this can cause problems. The problem happensbecause glass will output a 'BoundBreakpoint' XML element when the event comes in. Example:
<Event name="IDebugBreakpointBoundEvent2" expected="False"> <BoundBreakpoint>24,0 to 24,0 in [Unknown]!break_test_1()</BoundBreakpoint> </Event>
If the IDebugBreakpointBoundEvent2 is not declared as expected and associated with the command that causes the bound breakpoint event thanthis can cause problems because glass is being told to expect information, but isn't being told to block for that information, so it is nondeterministic as to when this information shows up. See commit 3a4b643 for an example of this problem.
If the breakpoint is set before the launch command, generally this is not a problem as somewhere in the launch command the breakpoint will bind,and it will always bind as part of the launch command, so glass will always get the right output.
If the breakpoint is set in the middle of the test, one of the following should be done:
1. Remove the 'BoundBreakpoint' element from the test script. Now glass will not complain no matter when the breakpoint bind shows up.
-or-
2. Declare the IDebugBreakpointBoundEvent2 as expected, and make sure it in associated with the command that causes the breakpoint to bind.
IDebugOutputStringEvent2 is a similar problem to IDebugBreakpointBoundEvent2 in that when an output string event shows up, glass will output anXML node with data from the event (OutputString is this case). The other problem without output string events is that the core debugger cancombine multiple output string events together depending on timing. So if the target is sending multiple output string events, it may be nondeterministic how many events make it to glass.
Usually, the best solution for OutputString events is just to remove the OutputString from the test script.
Events that require special careEvents that require special care
IDebugBreakpointBoundEvent2IDebugBreakpointBoundEvent2
IDebugOutputStringEvent2IDebugOutputStringEvent2
Testing-with-Glass
25 / 32
MIEngine includes a suite of automated tests that can be run against an Android emulator or device. The tests can be found in test\Android.
These tests are called 'Glass Tests' because they are automated against a scriptable, command line debugger frontend called Glass (glass2.exe)that loads and uses the MIEngine binaries the same way that Visual Studio does. More information about Glass can be found here.
To run all tests against an android emulator:
Make sure the project has been built, either using build.cmd or building from within Visual Studio.
Start an Android emulator using the Visual Studio Emulator for Android application that comes with Visual Studio. See the tutorial forinformation on setting this up.
From an administrator Visual Studio Developer Command Prompt, cd to the test\Android\ directory.
Starting the tests requires the device ID of the emulator. Running androidtest.cmd with no arguments will use adb.exe to list connected androiddevices:
c:\MIEngine\test\Android>androidtest.cmd--- MIEngine Android Test Script ---Usage: androidtest.cmd /DeviceId <id> /Platform <platform> [/SdkRoot <path>] [/NdkRoot <path>] [/v] [<test 1> [<test 2> [...]]]
List of devices attached169.254.138.177:5555 device product:VS Emulator 7" KitKat (4.4) XHDPI Tablet model:7__KitKat__4_4__XHDPI_Tablet device:donatello
Run the androidtest.cmd script using the appropriate device ID and platform:
c:\MIEngine\test\Android>androidtest.cmd /DeviceId 169.254.138.177:5555 /Platform x86
To run a single test, use the /Tests flag. This flag must be the last flag specified on the command line.
c:\MIEngine\test\Android>androidtest.cmd /DeviceId 169.254.138.177:5555 /Platform x86 /Tests Sanity
A new glass tests requires at least three items:
A test 'debuggee', which is an Android application that MIEngine will debug in order to exercise it's code.
A LaunchOptions.xml.template file, which contains information needed to launch the debguggee, such as it's package name.
A TestScript.xml, which contains the commands for Glass and the expected output.
Here is an example of authoring a new test for setting a breakpoint, running to it, and evaluating a local variable.
The existing tests are all based on the Native Activity Project template for Android provided in Visual Studio 2015. The name of the project will
define the name of the test. It should be saved to the test\Android directory. For this test we will name the project Eval.
We will strip out all of the graphics code from the template project and insert our test code into the android_main function.
void android_main(struct android_app* state) { int i = 0xDEADBEEF;
i += 0; // bp here, line 29}
Next, copy the LaunchOptions.xml.template file from the Sanity test into the Eval test folder and make changes for the Eval project. Items suchas $SdkRoot$ are filled in by the androidtest.cmd script.
<AndroidLaunchOptions xmlns="http://schemas.microsoft.com/vstudio/MDDDebuggerOptions/2014"
TestingTesting
MIEngine TestingMIEngine Testing
Running Android Glass TestsRunning Android Glass Tests
Authoring Glass TestsAuthoring Glass Tests
Testing
26 / 32
Package="com.Eval" LaunchActivity="android.app.NativeActivity" SDKRoot="$SdkRoot$" NDKRoot="$NdkRoot$" TargetArchitecture="$TargetArchitecture$" IntermediateDirectory="$IntermediateDirectory$" AdditionalSOLibSearchPath="$AdditionalSOLibSearchPath$" DeviceId="$DeviceId$"/>
Author a TestScript.xml. This will contain the debug commands to glass as well as the expected output. The TestScript.xml for our simple evaltest will look like this:
<?xml version="1.0" encoding="utf-8"?><GlassEventLog> <Command name="setmode ShowParameterValues off" /> <Command name="SetLaunchOptionsString @LaunchOptions.xml" /> <Command name="bp main.cpp 29" /> <Command name="launch MIEngine app_process"> <Event name="IDebugSessionCreateEvent2" expected="False" /> <Event name="IDebugProcessCreateEvent2" expected="False" /> <Event name="IDebugProgramCreateEvent2" expected="False" /> <Event name="IDebugBreakpointErrorEvent2" expected="False"> <WarningMessage>module containing this breakpoint has not yet loaded or the breakpoint address could not be obtained.</WarningMessage> </Event> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" />
Testing
27 / 32
<Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugThreadCreateEvent2" expected="False" /> <Event name="IDebugThreadCreateEvent2" expected="False" /> <Event name="IDebugThreadCreateEvent2" expected="False" /> <Event name="IDebugThreadCreateEvent2" expected="False" /> <Event name="IDebugThreadCreateEvent2" expected="False" /> <Event name="IDebugThreadCreateEvent2" expected="False" /> <Event name="IDebugThreadCreateEvent2" expected="False" /> <Event name="IDebugThreadCreateEvent2" expected="False" /> <Event name="IDebugThreadCreateEvent2" expected="False" /> <Event name="IDebugThreadCreateEvent2" expected="False" /> <Event name="IDebugOutputStringEvent2" expected="False" /> <Event name="IDebugBreakpointBoundEvent2" expected="False"> <BoundBreakpoint>28,0 to 28,0 in [Unknown]!android_main(android_app*)</BoundBreakpoint> </Event> <Event name="IDebugModuleLoadEvent2" expected="False" /> <Event name="IDebugOutputStringEvent2" expected="False" /> <Event name="IDebugOutputStringEvent2" expected="False" /> <Event name="IDebugOutputStringEvent2" expected="False" /> <Event name="IDebugThreadCreateEvent2" expected="False" /> <Event name="IDebugBreakpointEvent2" expected="True"> <functionName>android_main</functionName> <function>android_main(android_app * state)</function> <file>main.cpp</file> <line>29</line> <col>0</col> </Event> </Command> <Command name="eval i"> <EvalResult>-559038737</EvalResult>
Testing
28 / 32
<EvalType>int</EvalType> <EvalName>i</EvalName> <EvalFullName>i</EvalFullName> <EvalIsExpandable>False</EvalIsExpandable> </Command> <Command name="eval i,x"> <EvalResult>0xdeadbeef</EvalResult> <EvalType>int</EvalType> <EvalName>i,x</EvalName> <EvalFullName>i</EvalFullName> <EvalIsExpandable>False</EvalIsExpandable> </Command> <Command name="eval i,o"> <EvalResult>033653337357</EvalResult> <EvalType>int</EvalType> <EvalName>i,o</EvalName> <EvalFullName>i</EvalFullName> <EvalIsExpandable>False</EvalIsExpandable> </Command> <Command name="go"> <Event name="IDebugProcessContinueEvent100" expected="False" /> </Command> <Command name="stopdebugging"> <Event name="IDebugOutputStringEvent2" expected="False" /> <Event name="IDebugProgramDestroyEvent2" expected="False" /> <Event name="IDebugProcessDestroyEvent2" expected="False" /> <Event name="IDebugSessionDestroyEvent2" expected="True" /> </Command> <Command name="quit" /></GlassEventLog>
Tips for authoring a TestScript.xml can be found here
Run our new test using the androidtest.cmd script
c:\MIEngine\test\Android>androidtest.cmd /DeviceId 169.254.138.177:5555 /Platform x86 /Tests Eval
Testing
29 / 32
Attaching to a process on Linux with GDB as a normal user may fail with "ptrace:Operation not permitted". By default Linux does not allow attachingto a process which wasn't launched by the debugger (see the Yama security documentation for more details).
There are three ways to workaround this:
Run the following command as super user: echo 0| sudo tee /proc/sys/kernel/yama/ptrace_scope
This will set the ptrace level to 0, after this just with user permissions you can attach to processes which are not launched by the debugger.
On distributions without Yama (such as Raspbian) you can use libcap2-bin to assign ptrace permissions to specific executables: sudo setcapcap_sys_ptrace=eip /usr/bin/gdb
Alternatively, launch GDB as super user and attach to processes. Use root@machine to login with a password or certificate. Note, many Linuxdistros are configured to disallow root login through SSH for security reasons. You may have to configure /etc/ssh/sshd_config to allow rootlogin with certificate or password. You can verify SSH connection via a client like putty.exe in windows.
Troubleshoot-attaching-to-processes-using-GDBTroubleshoot-attaching-to-processes-using-GDB
Troubleshoot-attaching-to-processes-using-GDB
30 / 32
CLRDBG is mentioned a few places in the documentation and the code. This is our new cross-platform command line debugger used for debuggingcode running on .NET Core. It is a port of the backend for Visual Studio's normal .NET debugger to run on other platforms + a new command linedebugger wrapper which speaks the MI protocol.
CLRDBG will release for the first time with .NET Core RC2. On Linux, you can obtain the latest version designed to run against VS 2015 Update 2with the following command. Replace '~/clrdbg' if you want to install it to a different directory.
curl -sSL https://aka.ms/getclrdbgsh | bash /dev/stdin vs2015u2 ~/clrdbg
CLRDBG + MI/Engine is what powered the CoreCLR Linux debugging demo that was shown in 2015 //Build/ conference day one keynote ( videolink).
It is also what powered the Visual Studio Code debugging on MacOS demo in the 2015 Connect() day one keynote ( video link).
What-is-CLRDBGWhat-is-CLRDBG
What-is-CLRDBG
31 / 32
What-is-CLRDBG
32 / 32