目录 - gitee.com

32
1 3 4 5 5 5 5 5 6 7 8 9 10 10 10 10 10 11 11 11 11 11 11 11 11 11 11 12 12 12 12 13 13 13 13 14 14 14 14 14 14 14 14 15 15 15 15 15 16 目录 目录 目录 Architecture-of-the-MIEngine Building-the-MIEngine Contributing-Code Contributing Code Developer Workflow Creating New Issues Coding Conventions Code Formatter Executing-custom-gdb-lldb-commands Home How-Microsoft.DebugEngineHost-works Logging Using debug builds Visual Studio 2017, and Linux Extension for VS 2015 1.0.7+ Using shipping bits Additional notes: Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio-Legacy-Instructions Your feedback Machine setup Visual Studio Computer Linux Computer Setting up a transport Docker SSH Sharing sources and compiled binaries Building on Windows Building on Linux Transferring file Create launch options file: Using SSH Attaching to a process Turn off Just My Code if you are retail debugging Start debugging Detaching Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio Your feedback Machine setup Visual Studio Computer Linux Computer Copying vsdbg from Windows to Linux using PowerShell Setting up a transport SSH Sharing sources and compiled binaries Building on Windows Building on Linux Transferring file Create launch configuration file: Turn off Just My Code if you are retail debugging 目录 1 / 32

Transcript of 目录 - gitee.com

Page 1: 目录 - 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

Page 2: 目录 - gitee.com

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

Page 3: 目录 - gitee.com

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

Page 4: 目录 - gitee.com

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

Page 5: 目录 - gitee.com

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

Page 6: 目录 - gitee.com

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

Page 7: 目录 - gitee.com

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

Page 8: 目录 - gitee.com

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

Page 9: 目录 - gitee.com

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

Page 10: 目录 - gitee.com

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

Page 11: 目录 - gitee.com

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

Page 12: 目录 - gitee.com

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

Page 13: 目录 - gitee.com

<?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

Page 14: 目录 - gitee.com

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

Page 15: 目录 - gitee.com

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

Page 16: 目录 - gitee.com

{ "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

Page 17: 目录 - gitee.com

// 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

Page 18: 目录 - gitee.com

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

Page 19: 目录 - gitee.com

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

Page 20: 目录 - gitee.com

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

Page 21: 目录 - gitee.com

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

Page 22: 目录 - gitee.com

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

Page 23: 目录 - gitee.com

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

Page 24: 目录 - gitee.com

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

Page 25: 目录 - gitee.com

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

Page 26: 目录 - gitee.com

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

Page 27: 目录 - gitee.com

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

Page 28: 目录 - gitee.com

<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

Page 29: 目录 - gitee.com

<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

Page 30: 目录 - gitee.com

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

Page 31: 目录 - gitee.com

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

Page 32: 目录 - gitee.com

What-is-CLRDBG

32 / 32