summaryrefslogtreecommitdiff
path: root/Documentation
diff options
context:
space:
mode:
authorJiyoung Yun <jy910.yun@samsung.com>2017-04-27 16:54:50 +0900
committerJiyoung Yun <jy910.yun@samsung.com>2017-04-27 16:54:50 +0900
commit5b975f8233e8c8d17b215372f89ca713b45d6a0b (patch)
tree0267bcc331458a01f4c26fafd28110a72273beb3 /Documentation
parenta56e30c8d33048216567753d9d3fefc2152af8ac (diff)
downloadcoreclr-5b975f8233e8c8d17b215372f89ca713b45d6a0b.tar.gz
coreclr-5b975f8233e8c8d17b215372f89ca713b45d6a0b.tar.bz2
coreclr-5b975f8233e8c8d17b215372f89ca713b45d6a0b.zip
Imported Upstream version 2.0.0.11599upstream/2.0.0.11599
Diffstat (limited to 'Documentation')
-rw-r--r--Documentation/botr/README.md1
-rw-r--r--Documentation/botr/clr-abi.md2
-rw-r--r--Documentation/botr/xplat-minidump-generation.md80
-rw-r--r--Documentation/building/linux-instructions.md14
-rw-r--r--Documentation/building/viewing-jit-dumps.md166
-rw-r--r--Documentation/building/windows-instructions.md2
-rw-r--r--Documentation/project-docs/contributing-workflow.md2
7 files changed, 174 insertions, 93 deletions
diff --git a/Documentation/botr/README.md b/Documentation/botr/README.md
index 99e4274802..3a91f8defa 100644
--- a/Documentation/botr/README.md
+++ b/Documentation/botr/README.md
@@ -26,6 +26,7 @@ Below is a table of contents.
- [What Every Dev needs to Know About Exceptions in the Runtime](exceptions.md)
- [ReadyToRun Overview](readytorun-overview.md)
- [CLR ABI](clr-abi.md)
+- [Cross-platform Minidumps](xplat-minidump-generation.md)
It may be possible that this table is not complete. You can get a complete list
diff --git a/Documentation/botr/clr-abi.md b/Documentation/botr/clr-abi.md
index 8a226ed590..a85bfa4c60 100644
--- a/Documentation/botr/clr-abi.md
+++ b/Documentation/botr/clr-abi.md
@@ -470,7 +470,7 @@ When the inner "throw new UserException4" is executed, the exception handling fi
## Filter GC semantics
-Filters are invoked in the 1st pass of EH processing and as such execution might resume back at the faulting address, or in the filter-handler, or someplace else. Because the VM must allow GC's to occur during and after a filter invocation, but before the EH subsystem knows where it will resume, we need to keep everything alive at both the faulting address **and** within the filter. This is accomplished by 3 means: (1) the VM's stackwalker and GCInfoDecoder report as live both the filter frame and its corresponding parent frame, (2) the JIT encodes all stack slots that are live within the filter as being pinned, and (3) the JIT reports as live (and possible zero-initializes) anything live-out of the filter. Because of (1) it is likely that a stack variable that is live within the filter and the try body will be double reported. During the mark phase of the GC double reporting is not a problem. The problem only arises if the object is relocated: if the same location is reported twice, the GC will try to relocate the address stored at that location twice. Thus we prevent the object from being relocated by pinning it, which leads us to why we must do (2). (3) is done so that after the filter returns, we can still safely incur a GC before executing the filter-handler or any outer handler within the same frame.
+Filters are invoked in the 1st pass of EH processing and as such execution might resume back at the faulting address, or in the filter-handler, or someplace else. Because the VM must allow GC's to occur during and after a filter invocation, but before the EH subsystem knows where it will resume, we need to keep everything alive at both the faulting address **and** within the filter. This is accomplished by 3 means: (1) the VM's stackwalker and GCInfoDecoder report as live both the filter frame and its corresponding parent frame, (2) the JIT encodes all stack slots that are live within the filter as being pinned, and (3) the JIT reports as live (and possible zero-initializes) anything live-out of the filter. Because of (1) it is likely that a stack variable that is live within the filter and the try body will be double reported. During the mark phase of the GC double reporting is not a problem. The problem only arises if the object is relocated: if the same location is reported twice, the GC will try to relocate the address stored at that location twice. Thus we prevent the object from being relocated by pinning it, which leads us to why we must do (2). (3) is done so that after the filter returns, we can still safely incur a GC before executing the filter-handler or any outer handler within the same frame. For the same reason, control must exit a filter region via its final block (in other words, a filter region must terminate with the instruction that leaves the filter region, and the program may not exit the filter region via other paths).
## Duplicated Clauses
diff --git a/Documentation/botr/xplat-minidump-generation.md b/Documentation/botr/xplat-minidump-generation.md
new file mode 100644
index 0000000000..78660b659c
--- /dev/null
+++ b/Documentation/botr/xplat-minidump-generation.md
@@ -0,0 +1,80 @@
+# Introduction #
+
+Core dump generation on Linux and other non-Windows platforms has several challenges. Dumps can be very large and the default name/location of a dump is not consistent across all our supported platforms. The size of a full core dumps can be controlled somewhat with the "coredump_filter" file/flags but even with the smallest settings may be still too large and may not contain all the managed state needed for debugging. By default, some platforms use _core_ as the name and place the core dump in the current directory from where the program is launched; others add the _pid_ to the name. Configuring the core name and location requires superuser permission. Requiring superuser to make this consistent is not a satisfactory option.
+
+Our goal is to generate core dumps that are on par with WER (Windows Error Reporting) crash dumps on any supported Linux platform. To the very least we want to enable the following:
+- automatic generation of minimal size minidumps. The quality and quantity of the information contained in the dump should be on par with the information contained in a traditional Windows mini-dump.
+- simple configurabilty by the user (not _su_!).
+
+Our solution at this time is to intercept any unhandled exception in the PAL layer of the runtime and have coreclr itself trigger and generate a "mini" core dump.
+
+# Design #
+
+We looked at the existing technologies like Breakpad and its derivatives (e.g.: an internal MS version called _msbreakpad_ from the SQL team....). Breakpad generates Windows minidumps but they are not compatible with existing tools like Windbg, etc. Msbreakpad even more so. There is a minidump to Linux core conversion utility but it seems like a wasted extra step. _Breakpad_ does allow the minidump to be generated in-process inside the signal handlers. It restricts the APIs to what was allowed in a "async" signal handler (like SIGSEGV) and has a small subset of the C++ runtime that was also similarly constrained. We also need to add the set of memory regions for the "managed" state which requires loading and using the _DAC_'s (*) enumerate memory interfaces. Loading modules is not allowed in an async signal handler but forking/execve is allowed so launching an utility that loads the _DAC_, enumerates the list of memory regions and writes the dump is the only reasonable option. It would also allow uploading the dump to a server too.
+
+\* The _DAC_ is a special build of parts of the coreclr runtime that allows inspection of the runtime's managed state (stacks, variables, GC state heaps) out of context. One of the many interfaces it provides is [ICLRDataEnumMemoryRegions](https://github.com/dotnet/coreclr/blob/master/src/debug/daccess/dacimpl.h) which enumerates all the managed state a minidump would require to enable a fuitful debugging experience.
+
+_Breakpad_ could have still been used out of context in the generation utility but there seemed no value to their Windows-like minidump format when it would have to be converted to the native Linux core format away because in most scenarios using the platform tools like _lldb_ is necessary. It also adds a coreclr build dependency on Google's _Breakpad_ or SQL's _msbreakpad_ source repo. The only advantage is that the breakpad minidumps may be a little smaller because minidumps memory regions are byte granule and Linux core memory regions need to be page granule.
+
+# Implementation Details #
+
+### Linux ###
+
+Core dump generation is triggered anytime coreclr is going to abort (via [PROCAbort()](https://github.com/dotnet/coreclr/blob/master/src/pal/src/include/pal/process.h)) the process because of an unhandled managed exception or an async signal like SIGSEGV, SIGILL, SIGFPE, etc. The _createdump_ utility is located in the same directory as libcoreclr.so and is launched with fork/execve. The child _createdump_ process is given permission to ptrace and access to the various special /proc files of the crashing process which waits until _createdump_ finishes.
+
+The _createdump_ utility starts by using ptrace to enumerate and suspend all the threads in the target process. The process and thread info (status, registers, etc.) is gathered. The auxv entries and _DSO_ info is enumerated. _DSO_ is the in memory data structures that described the shared modules loaded by the target. This memory is needed in the dump by gdb and lldb to enumerate the shared modules loaded and access their symbols. The module memory mappings are gathered from /proc/$pid/maps. None of the program or shared modules memory regions are explicitly added to dump's memory regions. The _DAC_ is loaded and the enumerate memory region interfaces are used to build the memory regions list just like on Windows. The threads stacks and one page of code around the IP are added. The byte sized regions are rounded up to pages and then combined into contagious regions.
+
+After all the process crash information has been gathered, the ELF core dump with written. The main ELF header created and written. The PT\_LOAD note section is written one entry for each memory region in the dump. The process info, auxv data and NT_FILE entries are written to core. The NT\_FILE entries are built from module memory mappings from /proc/$pid/maps. The threads state and registers are then written. Lastly all the memory regions gather above by the _DAC_, etc. are read from the target process and written to the core dump. All the threads in the target process are resumed and _createdump_ terminates.
+
+**Severe memory corruption**
+
+As long as control can making it to the signal/abort handler and the fork/execve of the utility succeeds then the _DAC_ memory enumeration interfaces can handle corruption to a point; the resulting dump just may not have enough managed state to be useful. We could investigate detecting this case and writing a full core dump.
+
+**Stack overflow exception**
+
+Like the severe memory corruption case, if the signal handler (`SIGSEGV`) gets control it can detect most stack overflow cases and does trigger a core dump. There are still many cases where this doesn't happen and the OS just terminates the process.
+
+### FreeBSD/OpenBSD/NetBSD ###
+
+There will be some differences gathering the crash information but these platforms still use ELF format core dumps so that part of the utility should be much different. The mechanism used for Linux to give _createdump_ permission to use ptrace and access the /proc doesn't exists on these platforms.
+
+### OS X ###
+
+Gathering the crash information on OS X will be quite a bit different than Linux and the core dump will be written in the Mach-O format instead of ELF. The OS X support currently has not been implemented.
+
+# Configuration/Policy #
+
+Any configuration or policy is set with environment variables which are passed as options to the _createdump_ utility.
+
+Environment variables supported:
+
+- `COMPlus_DbgEnableMiniDump`: if set to "1", enables this core dump generation. The default is NOT to generate a dump.
+- `COMPlus_DbgMiniDumpType`: if set to "1" generates _MiniDumpNormal_, "2" _MiniDumpWithPrivateReadWriteMemory_, "3" _MiniDumpFilterTriage_. Default is _MiniDumpNormal_.
+- `COMPlus_DbgMiniDumpName`: if set, use as the template to create the dump path and file name. The pid can be placed in the name with %d. The default is _/tmp/coredump.%d_.
+- `COMPlus_CreateDumpDiagnostics`: if set to "1", enables the _createdump_ utilities diagnostic messages (TRACE macro).
+
+(Please refer to MSDN for the meaning of the [minidump enum values](https://msdn.microsoft.com/en-us/library/windows/desktop/ms680519(v=vs.85).aspx) reported above)
+
+**Utility command line options**:
+
+ createdump [options] pid
+ -f, --name - dump path and file name. The pid can be placed in the name with %d. The default is "/tmp/coredump.%d"
+ -n, --normal - create minidump (default).
+ -h, --withheap - create minidump with heap.
+ -t, --triage - create triage minidump.
+ -d, --diag - enable diagnostic messages.
+
+# Testing #
+
+The test plan is to modify the SOS tests in the (still) private debuggertests repo to trigger and use the core minidumps generated. Debugging managed core dumps on Linux is not supported by _mdbg_ at this time until we have a ELF core dump reader so only the SOS tests (which use _lldb_ on Linux) will be modified.
+
+# Open Issues #
+
+- Do we need a full memory dump option? It would not use the _DAC_ to get the memory regions but all the readable memory from the shared module list. Do we include the shared modules' code?
+- May need more than just the pid for decorating dump names for docker containers because I think the _pid_ is always 1.
+- Do we need all the memory mappings from `/proc/$pid/maps` in the PT\_LOAD sections even though the memory is not actually in the dump? They have a file offset/size of 0. Full dumps generated by the system or _gdb_ do have these un-backed regions.
+- Don't know how to get the proper size/range of the non-main thread stacks. Currently uses 4 pages around the stack pointer. The main thread has a memory region in `/proc/$pid/maps`.
+- There is no way to get the signal number, etc. that causes the abort from the _createdump_ utility using _ptrace_ or a /proc file. It would have to be passed from CoreCLR on the command line.
+- Do we need the "dynamic" sections of each shared module in the core dump? It is part of the "link_map" entry enumerated when gathering the _DSO_ information.
+- There may be more versioning and/or build id information needed to be added to the dump.
+- It is unclear exactly what cases stack overflow does not get control in the signal handler and when the OS just aborts the process.
diff --git a/Documentation/building/linux-instructions.md b/Documentation/building/linux-instructions.md
index b14ab288ce..bacbe6d2f0 100644
--- a/Documentation/building/linux-instructions.md
+++ b/Documentation/building/linux-instructions.md
@@ -18,8 +18,8 @@ Toolchain Setup
Install the following packages for the toolchain:
- cmake
-- llvm-3.5
-- clang-3.5
+- llvm-3.5 (llvm-3.9 for ARM cross build)
+- clang-3.5 (clang-3.9 for ARM cross build)
- lldb-3.6
- lldb-3.6-dev
- libunwind8
@@ -39,6 +39,14 @@ ellismg@linux:~$ wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-
ellismg@linux:~$ sudo apt-get update
```
+If you are going to cross build for ARM, you need llvm-3.9 and clang-3.9 and please add below package source instead for Ubuntu 14.04.
+```
+hqueue@linux:~$ echo "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.9 main" | sudo tee /etc/apt/sources.list.d/llvm.list
+hqueue@linux:~$ wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
+hqueue@linux:~$ sudo apt-get update
+```
+For other version of Debian/Ubuntu, please visit http://apt.llvm.org/.
+
Then install the packages you need:
```
@@ -120,6 +128,8 @@ index 1ed3dbf..c643032 100644
How to enable -O3 optimization level for ARM/Linux
==================================================
+If you are using clang-3.9, -O3 optimization is enabled as default and you can skip this section.
+If you are using older version of clang, please follow instructions in this section to enable -O3 optimization.
Currently, we can build coreclr with -O1 flag of clang in release build mode for Linux/ARM without any bugfix of llvm-3.6. This instruction is to enable -O3 optimization level of clang on Linux/ARM by fixing the bug of llvm.
First, download latest version from the clang-3.6/llvm-3.6 upstream:
diff --git a/Documentation/building/viewing-jit-dumps.md b/Documentation/building/viewing-jit-dumps.md
index 607c5e63a0..be5f4064a5 100644
--- a/Documentation/building/viewing-jit-dumps.md
+++ b/Documentation/building/viewing-jit-dumps.md
@@ -8,115 +8,105 @@ To make sense of the results, it is recommended you also read the [Reading a Jit
The first thing we want to do is setup the .NET Core app we want to dump. Here are the steps to do this, if you don't have one ready:
-* Perform a debug build of the CoreCLR repo
-* Install the [.NET CLI](http://microsoft.com/net/core), which we'll use to compile/publish our app
-* `cd` to where you want your app to be placed, and run `dotnet new`
-* Modify your `project.json` file so that it contains a RID (runtime ID) corresponding to the OS you're using in the `runtimes` section. For example, I have a Windows 10 x64 machine, so here's my project file:
-
-```json
-{
- "buildOptions": {
- "emitEntryPoint": true
- },
- "dependencies": {
- "Microsoft.NETCore.App": "1.0.0-*"
- },
- "frameworks": {
- "netcoreapp1.0": {
- "imports": [
- "dnxcore50",
- "portable-net45+win8"
- ]
- }
- },
- "runtimes": {
- "win10-x64": {}
- }
-}
-```
+* Perform a debug build of the CoreCLR repo.
+* Install the [.NET CLI 2.0 preview](https://github.com/dotnet/corefx/blob/master/Documentation/project-docs/dogfooding.md), which we'll use to compile/publish our app.
+* `cd` to where you want your app to be placed, and run `dotnet new console`.
+* Modify your `csproj` file so that it contains a RID (runtime ID) corresponding to the OS you're using in the `<RuntimeIdentifier>` tag. For example, for Windows 10 x64 machine, the project file is:
+
+ ```xml
+ <Project Sdk="Microsoft.NET.Sdk">
-You can find a list of RIDs and their corresponding OSes [here](https://docs.microsoft.com/en-us/dotnet/articles/core/rid-catalog).
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>netcoreapp2.0</TargetFramework>
+ <RuntimeIdentifier>win10-x64</RuntimeIdentifier>
+ </PropertyGroup>
+
+ </Project>
+ ```
+
+ You can find a list of RIDs and their corresponding OSes [here](https://docs.microsoft.com/en-us/dotnet/articles/core/rid-catalog).
* Edit `Program.cs`, and call the method(s) you want to dump in there. Make sure they are, directly or indirectly, called from `Main`. In this example, we'll be looking at the disassembly of our custom function `InefficientJoin`:
-```cs
-using System;
-using System.Collections.Generic;
-using System.Runtime.CompilerServices;
+ ```cs
+ using System;
+ using System.Collections.Generic;
+ using System.Runtime.CompilerServices;
-namespace ConsoleApplication
-{
- public class Program
+ namespace ConsoleApplication
{
- public static void Main(string[] args)
+ public class Program
{
- Console.WriteLine(InefficientJoin(args));
- }
-
- // Add NoInlining to prevent this from getting
- // mixed up with the rest of the code in Main
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static string InefficientJoin(IEnumerable<string> args)
- {
- var result = string.Empty;
- foreach (var arg in args) result += (arg + ' ');
- return result.Substring(0, result.Length - 1);
+ public static void Main(string[] args)
+ {
+ Console.WriteLine(InefficientJoin(args));
+ }
+
+ // Add NoInlining to prevent this from getting
+ // mixed up with the rest of the code in Main
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static string InefficientJoin(IEnumerable<string> args)
+ {
+ var result = string.Empty;
+ foreach (var arg in args) result += (arg + ' ');
+ return result.Substring(0, Math.Max(0, result.Length - 1));
+ }
}
}
-}
-```
+ ```
-* After you've finished editing the code, run `dotnet publish -c Release`. This should drop all of the binaries needed to run your app in `bin/Release/<configuration>/<rid>/publish`.
+* After you've finished editing the code, run `dotnet restore` and `dotnet publish -c Release`. This should drop all of the binaries needed to run your app in `bin/Release/<configuration>/<rid>/publish`.
* Overwrite the CLR dlls with the ones you've built locally. If you're a fan of the command line, here are some shell commands for doing this:
-```shell
-# Windows
-robocopy /e <coreclr path>\bin\Product\Windows_NT.<arch>.Debug <app root>\bin\Release\netcoreapp1.0\<rid>\publish > NUL
+ ```shell
+ # Windows
+ robocopy /e <coreclr path>\bin\Product\Windows_NT.<arch>.Debug <app root>\bin\Release\netcoreapp2.0\<rid>\publish > NUL
-# Unix
-cp -rT <coreclr path>/bin/Product/<OS>.<arch>.Debug <app root>/bin/Release/netcoreapp1.0/<rid>/publish
-```
+ # Unix
+ cp -rT <coreclr path>/bin/Product/<OS>.<arch>.Debug <app root>/bin/Release/netcoreapp2.0/<rid>/publish
+ ```
* Set the configuration knobs you need (see below) and run your published app. The info you want should be dumped to stdout.
-Here's some sample output on my machine showing the disassembly for `InefficientJoin`:
-
-```asm
-G_M2530_IG01:
- 55 push rbp
- 4883EC40 sub rsp, 64
- 488D6C2440 lea rbp, [rsp+40H]
- 33C0 xor rax, rax
- 488945F8 mov qword ptr [rbp-08H], rax
- 488965E0 mov qword ptr [rbp-20H], rsp
-
-G_M2530_IG02:
- 49BB60306927E5010000 mov r11, 0x1E527693060
- 4D8B1B mov r11, gword ptr [r11]
- 4C895DF8 mov gword ptr [rbp-08H], r11
- 49BB200058F7FD7F0000 mov r11, 0x7FFDF7580020
- 3909 cmp dword ptr [rcx], ecx
- 41FF13 call gword ptr [r11]System.Collections.Generic.IEnumerable`1[__Canon][System.__Canon]:GetEnumerator():ref:this
- 488945F0 mov gword ptr [rbp-10H], rax
-
-; ...
-```
+ Here's some sample output on my machine showing the disassembly for `InefficientJoin`:
+
+ ```asm
+ G_M2530_IG01:
+ 55 push rbp
+ 4883EC40 sub rsp, 64
+ 488D6C2440 lea rbp, [rsp+40H]
+ 33C0 xor rax, rax
+ 488945F8 mov qword ptr [rbp-08H], rax
+ 488965E0 mov qword ptr [rbp-20H], rsp
+
+ G_M2530_IG02:
+ 49BB60306927E5010000 mov r11, 0x1E527693060
+ 4D8B1B mov r11, gword ptr [r11]
+ 4C895DF8 mov gword ptr [rbp-08H], r11
+ 49BB200058F7FD7F0000 mov r11, 0x7FFDF7580020
+ 3909 cmp dword ptr [rcx], ecx
+ 41FF13 call gword ptr [r11]System.Collections.Generic.IEnumerable`1[__Canon][System.__Canon]:GetEnumerator():ref:this
+ 488945F0 mov gword ptr [rbp-10H], rax
+
+ ; ...
+ ```
## Setting configuration variables
-The behavior of the JIT can be controlled via a number of configuration variables. These are declared in [inc/clrconfigvalues.h](https://github.com/dotnet/coreclr/blob/master/src/inc/clrconfigvalues.h). When used as an environment variable, the string name generally has “COMPlus_” prepended. When used as a registry value name, the configuration name is used directly.
+The behavior of the JIT can be controlled via a number of configuration variables. These are declared in [inc/clrconfigvalues.h](https://github.com/dotnet/coreclr/blob/master/src/inc/clrconfigvalues.h). When used as an environment variable, the string name generally has `COMPlus_` prepended. When used as a registry value name, the configuration name is used directly.
These can be set in one of three ways:
-* Setting the environment variable `COMPlus_<flagname>`. For example, the following will set the `JitDump` flag so that the compilation of all methods named ‘Main’ will be dumped:
+* Setting the environment variable `COMPlus_<flagname>`. For example, the following will set the `JitDump` flag so that the compilation of all methods named `Main` will be dumped:
-```shell
-# Windows
-set COMPlus_JitDump=Main
+ ```shell
+ # Windows
+ set COMPlus_JitDump=Main
-# Unix
-export COMPlus_JitDump=Main
-```
+ # Unix
+ export COMPlus_JitDump=Main
+ ```
* *Windows-only:* Setting the registry key `HKCU\Software\Microsoft\.NETFramework`, Value `<flagName>`, type `REG_SZ` or `REG_DWORD` (depending on the flag).
* *Windows-only:* Setting the registry key `HKLM\Software\Microsoft\.NETFramework`, Value `<flagName>`, type `REG_SZ` or `REG_DWORD` (depending on the flag).
@@ -143,13 +133,13 @@ Main
will match all methods named Main from any class and any number of arguments.
-<types> is a comma separated list of type names. Note that presently only the number of arguments and not the types themselves are used to distinguish methods. Thus, `Main(Foo, Bar)` and `Main(int, int)` will both match any main method with two arguments.
+`<types>` is a comma separated list of type names. Note that presently only the number of arguments and not the types themselves are used to distinguish methods. Thus, `Main(Foo, Bar)` and `Main(int, int)` will both match any main method with two arguments.
-The wildcard character ‘*’ can be used for <ClassName> and <MethodName>. In particular * by itself indicates every method.
+The wildcard character `*` can be used for `<ClassName>` and `<MethodName>`. In particular `*` by itself indicates every method.
## Useful COMPlus variables
-Below are some of the most useful `COMPlus` variables. Where {method-list} is specified in the list below, you can supply a space-separated list of either fully-qualified or simple method names (the former is useful when running something that has many methods of the same name), or you can specific ‘*’ to mean all methods.
+Below are some of the most useful `COMPlus` variables. Where {method-list} is specified in the list below, you can supply a space-separated list of either fully-qualified or simple method names (the former is useful when running something that has many methods of the same name), or you can specify `*` to mean all methods.
* `COMPlus_JitDump`={method-list} – dump lots of useful information about what the JIT is doing. See [Reading a JitDump](../botr/ryujit-overview.md#reading-a-jitdump) for more on how to analyze this data.
* `COMPlus_JitDisasm`={method-list} – dump a disassembly listing of each method.
diff --git a/Documentation/building/windows-instructions.md b/Documentation/building/windows-instructions.md
index d0e63270c0..303bec8cc0 100644
--- a/Documentation/building/windows-instructions.md
+++ b/Documentation/building/windows-instructions.md
@@ -15,7 +15,7 @@ Visual Studio must be installed. Supported versions:
- [Visual Studio 2017](https://www.visualstudio.com/downloads/) (Community, Professional, Enterprise). The community version is completely free.
For Visual Studio 2015:
-* To debug managed code, ensure you have installed at least [Visual Studio 2015 Update 3](https://www.visualstudio.com/en-us/news/releasenotes/vs2015-update3-vs).
+* Ensure you have installed at least [Visual Studio 2015 Update 3](https://www.visualstudio.com/en-us/news/releasenotes/vs2015-update3-vs).
* Make sure that you install "VC++ Tools". By default, they will not be installed.
* To build for Arm32, Make sure that you have the Windows SDK for Windows 10 installed (or selected to be installed as part of VS installation). To explicitly install Windows SDK, download it from here: [Windows SDK for Windows 10](https://developer.microsoft.com/en-us/windows/downloads)
diff --git a/Documentation/project-docs/contributing-workflow.md b/Documentation/project-docs/contributing-workflow.md
index d88e098ebf..ff21143d7a 100644
--- a/Documentation/project-docs/contributing-workflow.md
+++ b/Documentation/project-docs/contributing-workflow.md
@@ -62,7 +62,7 @@ the PR.
PR - CI Process
===============
-The [dotnet continuous integration](http://dotnet-ci.cloudapp.net/) (CI) system will automatically perform the required builds and run tests (including the ones you are expected to run) for PRs. Builds and test runs must be clean.
+The [dotnet continuous integration](http://ci.dot.net/) (CI) system will automatically perform the required builds and run tests (including the ones you are expected to run) for PRs. Builds and test runs must be clean.
If the CI build fails for any reason, the PR issue will be updated with a link that can be used to determine the cause of the failure.