Using the Roslyn repo tool set to build (for now).
--- /dev/null
+###############################################################################
+# Set default behavior to:
+# automatically normalize line endings on check-in, and
+# convert to Windows-style line endings on check-out
+###############################################################################
+* text=auto encoding=UTF-8
+*.sh text eol=lf
+
+###############################################################################
+# Set file behavior to:
+# treat as text, and
+# diff as C# source code
+###############################################################################
+*.cs text diff=csharp
+
+###############################################################################
+# Set file behavior to:
+# treat as text
+###############################################################################
+*.cmd text
+*.config text
+*.csproj text
+*.groovy text
+*.json text
+*.md text
+*.nuspec text
+*.pkgdef text
+*.proj text
+*.projitems text
+*.props text
+*.ps1 text
+*.resx text
+*.ruleset text
+*.shproj text
+*.sln text
+*.targets text
+*.vb text
+*.vbproj text
+*.vcxproj text
+*.vcxproj.filters text
+*.vsct text
+*.vsixmanifest text
+
+###############################################################################
+# Set file behavior to:
+# treat as binary
+###############################################################################
+*.png binary
+*.snk binary
-syntax: glob
-
-[Bb]inaries/
-
-# Build tools related files
-/[Tt]ools/
-
-### VisualStudio ###
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
-*.userosscache
*.sln.docstates
-*.swp
+.vs/
+*.VC.db
# Build results
+[Aa]rtifacts/
[Dd]ebug/
-[Dd]ebugPublic/
[Rr]elease/
-[Rr]eleases/
x64/
-x86/
-build/
-bld/
[Bb]in/
[Oo]bj/
-msbuild.log
-
-# add back architecture directories ignored in 'Build results'
-!tests/x86
-!src/mscorlib/src/System/Runtime/Intrinsics/X86
-!tests/src/JIT/HardwareIntrinsics/X86
-
-# Visual Studio 2015
-.vs/
+.dotnet/
+.packages/
+.tools/
-# Visual Studio 2015 Pre-CTP6
-*.sln.ide
-*.ide/
-
-# MSTest test Results
-[Tt]est[Rr]esult*/
-[Bb]uild[Ll]og.*
-
-#NUNIT
-*.VisualState.xml
-TestResult.xml
-
-# Build Results of an ATL Project
-[Dd]ebugPS/
-[Rr]eleasePS/
-dlldata.c
+# Per-user project properties
+launchSettings.json
*_i.c
*_p.c
-*_i.h
*.ilk
*.meta
*.obj
*.pdb
*.pgc
*.pgd
-*.rsp
*.sbr
*.tlb
*.tli
*.tmp
*.tmp_proj
*.log
-*.html
+*.wrn
*.vspscc
*.vssscc
.builds
*.pidb
-*.svclog
+*.log
*.scc
-# Chutzpah Test files
-_Chutzpah*
-
# Visual C++ cache files
ipch/
*.aps
*.ncb
-*.opendb
*.opensdf
*.sdf
*.cachefile
-*.VC.db
+*.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
-# TFS 2012 Local Workspace
-$tf/
-
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
-*.DotSettings.user
-
-# JustCode is a .NET coding addin-in
-.JustCode
# TeamCity is a build add-in
_TeamCity*
*.dotCover
# NCrunch
-_NCrunch_*
+*.ncrunch*
.*crunch*.local.xml
-# MightyMoose
-*.mm.*
-AutoTest.Net/
-
-# Web workbench (sass)
-.sass-cache/
-
-# Installshield output folder
-[Ee]xpress/
-
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
-# Click-Once directory
-publish/
-
-# Publish Web Output
-*.[Pp]ublish.xml
-*.azurePubxml
-*.pubxml
-*.publishproj
-
-# NuGet Packages
-*.nupkg
-*.nuget.g.props
-*.nuget.g.targets
-*.nuget.cache
-**/packages/*
-project.lock.json
-project.assets.json
-
-# Windows Azure Build Output
-csx/
-*.build.csdef
-
-# Windows Store app package directory
-AppPackages/
-
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
+*~
*.dbmdl
-*.dbproj.schemaview
+*.[Pp]ublish.xml
*.pfx
*.publishsettings
-node_modules/
-*.metaproj
-*.metaproj.tmp
-.atom-build.json
-tags
-TAGS
-
-# RIA/Silverlight projects
-Generated_Code/
-
-# Backup & report files from converting an old project file
-# to a newer Visual Studio version. Backup files are not needed,
-# because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
-UpgradeLog*.htm
# SQL Server files
-*.mdf
-*.ldf
+App_Data/*.mdf
+App_Data/*.ldf
-# Business Intelligence projects
-*.rdl.data
-*.bim.layout
-*.bim_*.settings
-
-# Microsoft Fakes
-FakesAssemblies/
-
-# C/C++ extension for Visual Studio Code
-browse.VC.db
-
-# Local settings folder for Visual Studio Code
-.vscode/
-
-### MonoDevelop ###
-
-*.pidb
-*.userprefs
-
-### Windows ###
+# =========================
+# Windows detritus
+# =========================
# Windows image file caches
Thumbs.db
# Recycle Bin used on file shares
$RECYCLE.BIN/
-# Windows Installer files
-*.cab
-*.msi
-*.msm
-*.msp
-
-# Windows shortcuts
-*.lnk
-
-# Common binary extensions on Windows
-*.exe
-*.dll
-*.lib
-
-### Linux ###
-
-*~
-\#*\#
-
-# KDE directory preferences
-.directory
-
-### OSX ###
-
+# Mac desktop service store files
.DS_Store
-.AppleDouble
-.LSOverride
-
-# Icon must end with two \r
-Icon
-
-# Thumbnails
-._*
-
-# Files that might appear on external disk
-.Spotlight-V100
-.Trashes
-
-# Directories potentially created on remote AFP share
-.AppleDB
-.AppleDesktop
-Network Trash Folder
-Temporary Items
-.apdisk
-
-# We have some checked in prebuilt generated files
-!src/pal/prebuilt/idl/*_i.c
-
-# Valid 'debug' folder, that contains CLR debugging code
-!src/debug
-
-# Ignore folders created by the test build
-TestWrappers_x64_[d|D]ebug
-TestWrappers_x64_[c|C]hecked
-TestWrappers_x64_[r|R]elease
-TestWrappers_x86_[d|D]ebug
-TestWrappers_x86_[c|C]hecked
-TestWrappers_x86_[r|R]elease
-TestWrappers_arm_[d|D]ebug
-TestWrappers_arm_[c|C]hecked
-TestWrappers_arm_[r|R]elease
-TestWrappers_arm64_[d|D]ebug
-TestWrappers_arm64_[c|C]hecked
-TestWrappers_arm64_[r|R]elease
-tests/src/common/test_runtime/project.json
-
-Vagrantfile
-.vagrant
-
-# CMake files
-CMakeFiles/
-cmake_install.cmake
-CMakeCache.txt
-Makefile
-
-# Cross compilation
-cross/rootfs/*
-cross/android-rootfs/*
-# add x86 as it is ignored in 'Build results'
-!cross/x86
-
-#python import files
-*.pyc
-
-# JIT32 files
-src/jit32
-
-# performance testing sandbox
-sandbox
-
-#IL linker for testing
-linker
--- /dev/null
+@echo off
+powershell -ExecutionPolicy ByPass -command "& """%~dp0eng\common\Build.ps1""" -restore -build %*"
+exit /b %ErrorLevel%
--- /dev/null
+<!-- Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -->
+<Project>
+ <PropertyGroup>
+ <RepositoryUrl>https://github.com/dotnet/diagnostics.git</RepositoryUrl>
+ <RepositoryRawUrl>$(RepositoryUrl)</RepositoryRawUrl>
+ <PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl>
+ <PackageLicenseUrl>http://go.microsoft.com/fwlink/?LinkId=529443</PackageLicenseUrl>
+ <PackageIconUrl>http://go.microsoft.com/fwlink/?LinkID=288859</PackageIconUrl>
+ <IsPublishable>false</IsPublishable>
+ <NoPackageAnalysis>true</NoPackageAnalysis>
+ </PropertyGroup>
+</Project>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <!-- Only specify feed for RepoToolset SDK (see https://github.com/Microsoft/msbuild/issues/2982) -->
+ <packageSources>
+ <clear />
+ <add key="roslyn-tools" value="https://dotnet.myget.org/F/roslyn-tools/api/v3/index.json" />
+ </packageSources>
+</configuration>
--- /dev/null
+@echo off
+powershell -ExecutionPolicy ByPass -command "& """%~dp0eng\common\Build.ps1""" -restore %*"
+exit /b %ErrorLevel%
--- /dev/null
+@echo off
+powershell -ExecutionPolicy ByPass -command "& """%~dp0eng\common\Build.ps1""" -test %*"
+exit /b %ErrorLevel%
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $SOURCE until the file is no longer a symlink
+while [[ -h $source ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+"$scriptroot/eng/common/build.sh" --build --restore $@
\ No newline at end of file
--- /dev/null
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27004.2005
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SOS.NETCore", "src\SOS\NETCore\SOS.NETCore.csproj", "{20513BA2-A156-4A17-4C70-5AC2DBD4F833}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {46465737-C938-44FC-BE1A-4CE139EBB5E0}
+ EndGlobalSection
+EndGlobal
--- /dev/null
+{
+ "sign": [
+ {
+ "certificate": "MicrosoftSHA2",
+ "strongName": "MsSharedLib72",
+ "values": [
+ "bin/SOS.NETCore/netcoreapp1.0/SOS.NETCore.dll",
+ ]
+ },
+ {
+ "certificate": "NuGet",
+ "strongName": null,
+ "values": [
+ "packages/*.nupkg"
+ ]
+ }
+ ],
+ "exclude": [
+ "Microsoft.FileFormats.dll",
+ "Microsoft.SymbolStore.dll",
+ "System.Collections.Immutable.dll",
+ "System.Net.Http.dll",
+ "System.Reflection.Metadata.dll",
+ ]
+}
--- /dev/null
+<!-- Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -->
+<Project>
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+
+ <!-- This repo version -->
+ <VersionPrefix>1.0.0</VersionPrefix>
+ <PreReleaseVersionLabel>beta</PreReleaseVersionLabel>
+
+ <UsingToolNetFrameworkReferenceAssemblies>true</UsingToolNetFrameworkReferenceAssemblies>
+ <UsingToolXliff>false</UsingToolXliff>
+
+ <!-- CoreFX -->
+ <SystemReflectionMetadataVersion>1.6.0-preview2-26406-04</SystemReflectionMetadataVersion>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <RestoreSources>
+ $(RestoreSources);
+ https://dotnet.myget.org/F/symstore/api/v3/index.json;
+ https://dotnet.myget.org/F/roslyn-tools/api/v3/index.json;
+ https://dotnet.myget.org/F/dotnet-core/api/v3/index.json
+ </RestoreSources>
+ </PropertyGroup>
+</Project>
--- /dev/null
+@echo off
+powershell -ExecutionPolicy ByPass -command "& """%~dp0Build.ps1""" -restore -build -test -sign -pack -ci %*"
+exit /b %ErrorLevel%
--- /dev/null
+[CmdletBinding(PositionalBinding=$false)]
+Param(
+ [string] $configuration = "Debug",
+ [string] $solution = "",
+ [string] $verbosity = "minimal",
+ [switch] $restore,
+ [switch] $deployDeps,
+ [switch] $build,
+ [switch] $rebuild,
+ [switch] $deploy,
+ [switch] $test,
+ [switch] $integrationTest,
+ [switch] $sign,
+ [switch] $pack,
+ [switch] $ci,
+ [switch] $prepareMachine,
+ [switch] $help,
+ [Parameter(ValueFromRemainingArguments=$true)][String[]]$properties
+)
+
+set-strictmode -version 2.0
+$ErrorActionPreference = "Stop"
+[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+
+function Print-Usage() {
+ Write-Host "Common settings:"
+ Write-Host " -configuration <value> Build configuration Debug, Release"
+ Write-Host " -verbosity <value> Msbuild verbosity (q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic])"
+ Write-Host " -help Print help and exit"
+ Write-Host ""
+
+ Write-Host "Actions:"
+ Write-Host " -restore Restore dependencies"
+ Write-Host " -build Build solution"
+ Write-Host " -rebuild Rebuild solution"
+ Write-Host " -deploy Deploy built VSIXes"
+ Write-Host " -deployDeps Deploy dependencies (e.g. VSIXes for integration tests)"
+ Write-Host " -test Run all unit tests in the solution"
+ Write-Host " -integrationTest Run all integration tests in the solution"
+ Write-Host " -sign Sign build outputs"
+ Write-Host " -pack Package build outputs into NuGet packages and Willow components"
+ Write-Host ""
+
+ Write-Host "Advanced settings:"
+ Write-Host " -solution <value> Path to solution to build"
+ Write-Host " -ci Set when running on CI server"
+ Write-Host " -prepareMachine Prepare machine for CI run"
+ Write-Host ""
+ Write-Host "Command line arguments not listed above are passed thru to msbuild."
+ Write-Host "The above arguments can be shortened as much as to be unambiguous (e.g. -co for configuration, -t for test, etc.)."
+}
+
+if ($help -or (($properties -ne $null) -and ($properties.Contains("/help") -or $properties.Contains("/?")))) {
+ Print-Usage
+ exit 0
+}
+
+function Create-Directory([string[]] $path) {
+ if (!(Test-Path $path)) {
+ New-Item -path $path -force -itemType "Directory" | Out-Null
+ }
+}
+
+function InitializeDotNetCli {
+ # Don't resolve runtime, shared framework, or SDK from other locations to ensure build determinism
+ $env:DOTNET_MULTILEVEL_LOOKUP=0
+
+ # Disable first run since we do not need all ASP.NET packages restored.
+ $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
+
+ # Source Build uses DotNetCoreSdkDir variable
+ if ($env:DotNetCoreSdkDir -ne $null) {
+ $env:DOTNET_INSTALL_DIR = $env:DotNetCoreSdkDir
+ }
+
+ # Use dotnet installation specified in DOTNET_INSTALL_DIR if it contains the required SDK version,
+ # otherwise install the dotnet CLI and SDK to repo local .dotnet directory to avoid potential permission issues.
+ if (($env:DOTNET_INSTALL_DIR -ne $null) -and (Test-Path(Join-Path $env:DOTNET_INSTALL_DIR "sdk\$($GlobalJson.sdk.version)"))) {
+ $dotnetRoot = $env:DOTNET_INSTALL_DIR
+ } else {
+ $dotnetRoot = Join-Path $RepoRoot ".dotnet"
+ $env:DOTNET_INSTALL_DIR = $dotnetRoot
+
+ if ($restore) {
+ InstallDotNetCli $dotnetRoot
+ }
+ }
+
+ $global:BuildDriver = Join-Path $dotnetRoot "dotnet.exe"
+ $global:BuildArgs = "msbuild"
+}
+
+function InstallDotNetCli([string] $dotnetRoot) {
+ $installScript = "$dotnetRoot\dotnet-install.ps1"
+ if (!(Test-Path $installScript)) {
+ Create-Directory $dotnetRoot
+ Invoke-WebRequest "https://dot.net/v1/dotnet-install.ps1" -OutFile $installScript
+ }
+
+ & $installScript -Version $GlobalJson.sdk.version -InstallDir $dotnetRoot
+ if ($lastExitCode -ne 0) {
+ Write-Host "Failed to install dotnet cli (exit code '$lastExitCode')." -ForegroundColor Red
+ exit $lastExitCode
+ }
+}
+
+function InitializeVisualStudioBuild {
+ $inVSEnvironment = !($env:VS150COMNTOOLS -eq $null) -and (Test-Path $env:VS150COMNTOOLS)
+
+ if ($inVSEnvironment) {
+ $vsInstallDir = Join-Path $env:VS150COMNTOOLS "..\.."
+ } else {
+ $vsInstallDir = LocateVisualStudio
+
+ $env:VS150COMNTOOLS = Join-Path $vsInstallDir "Common7\Tools\"
+ $env:VSSDK150Install = Join-Path $vsInstallDir "VSSDK\"
+ $env:VSSDKInstall = Join-Path $vsInstallDir "VSSDK\"
+ }
+
+ $global:BuildDriver = Join-Path $vsInstallDir "MSBuild\15.0\Bin\msbuild.exe"
+ $global:BuildArgs = "/nodeReuse:$(!$ci)"
+}
+
+function LocateVisualStudio {
+ $vswhereVersion = $GlobalJson.vswhere.version
+ $toolsRoot = Join-Path $RepoRoot ".tools"
+ $vsWhereDir = Join-Path $toolsRoot "vswhere\$vswhereVersion"
+ $vsWhereExe = Join-Path $vsWhereDir "vswhere.exe"
+
+ if (!(Test-Path $vsWhereExe)) {
+ Create-Directory $vsWhereDir
+ Write-Host "Downloading vswhere"
+ Invoke-WebRequest "https://github.com/Microsoft/vswhere/releases/download/$vswhereVersion/vswhere.exe" -OutFile $vswhereExe
+ }
+
+ $vsInstallDir = & $vsWhereExe -latest -prerelease -property installationPath -requires Microsoft.Component.MSBuild -requires Microsoft.VisualStudio.Component.VSSDK -requires Microsoft.Net.Component.4.6.TargetingPack -requires Microsoft.VisualStudio.Component.Roslyn.Compiler -requires Microsoft.VisualStudio.Component.VSSDK
+
+ if ($lastExitCode -ne 0) {
+ Write-Host "Failed to locate Visual Studio (exit code '$lastExitCode')." -ForegroundColor Red
+ exit $lastExitCode
+ }
+
+ return $vsInstallDir
+}
+
+function InitializeToolset {
+ $toolsetVersion = $GlobalJson.'msbuild-sdks'.'RoslynTools.RepoToolset'
+ $toolsetLocationFile = Join-Path $ToolsetDir "$toolsetVersion.txt"
+
+ if (Test-Path $toolsetLocationFile) {
+ $path = Get-Content $toolsetLocationFile
+ if (Test-Path $path) {
+ $global:ToolsetBuildProj = $path
+ return
+ }
+ }
+
+ if (-not $restore) {
+ Write-Host "Toolset version $toolsetVersion has not been restored."
+ exit 1
+ }
+
+ $proj = Join-Path $ToolsetDir "restore.proj"
+
+ '<Project Sdk="RoslynTools.RepoToolset"/>' | Set-Content $proj
+ & $BuildDriver $BuildArgs $proj /t:__WriteToolsetLocation /m /nologo /clp:None /warnaserror /bl:$ToolsetRestoreLog /v:$verbosity /p:__ToolsetLocationOutputFile=$toolsetLocationFile
+
+ if ($lastExitCode -ne 0) {
+ Write-Host "Failed to restore toolset (exit code '$lastExitCode')." -Color Red
+ Write-Host "Build log: $ToolsetRestoreLog" -ForegroundColor DarkGray
+ exit $lastExitCode
+ }
+
+ $global:ToolsetBuildProj = Get-Content $toolsetLocationFile
+}
+
+function Build {
+ & $BuildDriver $BuildArgs $ToolsetBuildProj /m /nologo /clp:Summary /warnaserror /v:$verbosity /bl:$Log /p:Configuration=$configuration /p:Projects=$solution /p:RepoRoot=$RepoRoot /p:Restore=$restore /p:DeployDeps=$deployDeps /p:Build=$build /p:Rebuild=$rebuild /p:Deploy=$deploy /p:Test=$test /p:IntegrationTest=$integrationTest /p:Sign=$sign /p:Pack=$pack /p:CIBuild=$ci $properties
+ if ($lastExitCode -ne 0) {
+ Write-Host "Build log: $Log" -ForegroundColor DarkGray
+ exit $lastExitCode
+ }
+}
+
+function Stop-Processes() {
+ Write-Host "Killing running build processes..."
+ Get-Process -Name "msbuild" -ErrorAction SilentlyContinue | Stop-Process
+ Get-Process -Name "dotnet" -ErrorAction SilentlyContinue | Stop-Process
+ Get-Process -Name "vbcscompiler" -ErrorAction SilentlyContinue | Stop-Process
+}
+
+try {
+ $RepoRoot = Join-Path $PSScriptRoot "..\.."
+ $ArtifactsDir = Join-Path $RepoRoot "artifacts"
+ $ToolsetDir = Join-Path $ArtifactsDir "toolset"
+ $LogDir = Join-Path (Join-Path $ArtifactsDir $configuration) "log"
+ $Log = Join-Path $LogDir "Build.binlog"
+ $ToolsetRestoreLog = Join-Path $LogDir "ToolsetRestore.binlog"
+ $TempDir = Join-Path (Join-Path $ArtifactsDir $configuration) "tmp"
+ $GlobalJson = Get-Content(Join-Path $RepoRoot "global.json") | ConvertFrom-Json
+
+ if ($solution -eq "") {
+ $solution = Join-Path $RepoRoot "*.sln"
+ }
+
+ if ($env:NUGET_PACKAGES -eq $null) {
+ # Use local cache on CI to ensure deterministic build,
+ # use global cache in dev builds to avoid cost of downloading packages.
+ $env:NUGET_PACKAGES = if ($ci) { Join-Path $RepoRoot ".packages" }
+ else { Join-Path $env:UserProfile ".nuget\packages" }
+ }
+
+ Create-Directory $ToolsetDir
+ Create-Directory $LogDir
+
+ if ($ci) {
+ Create-Directory $TempDir
+ $env:TEMP = $TempDir
+ $env:TMP = $TempDir
+ }
+
+ # Presence of vswhere.version indicates the repo needs to build using VS msbuild
+ if ((Get-Member -InputObject $GlobalJson -Name "vswhere") -ne $null) {
+ InitializeVisualStudioBuild
+ } elseif ((Get-Member -InputObject $GlobalJson -Name "sdk") -ne $null) {
+ InitializeDotNetCli
+ } else {
+ Write-Host "/global.json must either specify 'sdk.version' or 'vswhere.version'." -ForegroundColor Red
+ exit 1
+ }
+
+ if ($ci) {
+ Write-Host "Using $BuildDriver"
+ }
+
+ InitializeToolset
+
+ Build
+}
+catch {
+ Write-Host $_
+ Write-Host $_.Exception
+ Write-Host $_.ScriptStackTrace
+ exit 1
+}
+finally {
+ Pop-Location
+ if ($ci -and $prepareMachine) {
+ Stop-Processes
+ }
+}
+
--- /dev/null
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $source until the file is no longer a symlink
+while [[ -h "$source" ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+build=false
+ci=false
+configuration='Debug'
+help=false
+pack=false
+prepare_machine=false
+rebuild=false
+restore=false
+sign=false
+solution=''
+test=false
+verbosity='minimal'
+properties=''
+
+repo_root="$scriptroot/../.."
+artifacts_dir="$repo_root/artifacts"
+artifacts_configuration_dir="$artifacts_dir/$configuration"
+toolset_dir="$artifacts_dir/toolset"
+log_dir="$artifacts_configuration_dir/log"
+log="$log_dir/Build.binlog"
+toolset_restore_log="$log_dir/ToolsetRestore.binlog"
+temp_dir="$artifacts_configuration_dir/tmp"
+
+global_json_file="$repo_root/global.json"
+build_driver=""
+toolset_build_proj=""
+
+while (($# > 0)); do
+ lowerI="$(echo $1 | awk '{print tolower($0)}')"
+ case $lowerI in
+ --build)
+ build=true
+ shift 1
+ ;;
+ --ci)
+ ci=true
+ shift 1
+ ;;
+ --configuration)
+ configuration=$2
+ shift 2
+ ;;
+ --help)
+ echo "Common settings:"
+ echo " --configuration <value> Build configuration Debug, Release"
+ echo " --verbosity <value> Msbuild verbosity (q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic])"
+ echo " --help Print help and exit"
+ echo ""
+ echo "Actions:"
+ echo " --restore Restore dependencies"
+ echo " --build Build solution"
+ echo " --rebuild Rebuild solution"
+ echo " --test Run all unit tests in the solution"
+ echo " --sign Sign build outputs"
+ echo " --pack Package build outputs into NuGet packages and Willow components"
+ echo ""
+ echo "Advanced settings:"
+ echo " --solution <value> Path to solution to build"
+ echo " --ci Set when running on CI server"
+ echo " --prepareMachine Prepare machine for CI run"
+ echo ""
+ echo "Command line arguments not listed above are passed through to MSBuild."
+ exit 0
+ ;;
+ --pack)
+ pack=true
+ shift 1
+ ;;
+ --preparemachine)
+ prepare_machine=true
+ shift 1
+ ;;
+ --rebuild)
+ rebuild=true
+ shift 1
+ ;;
+ --restore)
+ restore=true
+ shift 1
+ ;;
+ --sign)
+ sign=true
+ shift 1
+ ;;
+ --solution)
+ solution=$2
+ shift 2
+ ;;
+ --test)
+ test=true
+ shift 1
+ ;;
+ --verbosity)
+ verbosity=$2
+ shift 2
+ ;;
+ *)
+ properties="$properties $1"
+ shift 1
+ ;;
+ esac
+done
+
+# ReadJson [filename] [json key]
+# Result: Sets 'readjsonvalue' to the value of the provided json key
+# Note: this method may return unexpected results if there are duplicate
+# keys in the json
+function ReadJson {
+ local file=$1
+ local key=$2
+
+ local unamestr="$(uname)"
+ local sedextended='-r'
+ if [[ "$unamestr" == 'Darwin' ]]; then
+ sedextended='-E'
+ fi;
+
+ readjsonvalue="$(grep -m 1 "\"$key\"" $file | sed $sedextended 's/^ *//;s/.*: *"//;s/",?//')"
+ if [[ ! "$readjsonvalue" ]]; then
+ echo "Error: Cannot find \"$key\" in $file" >&2;
+ ExitWithExitCode 1
+ fi;
+}
+
+function InitializeDotNetCli {
+ # Disable first run since we want to control all package sources
+ export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
+
+ # Don't resolve runtime, shared framework, or SDK from other locations to ensure build determinism
+ export DOTNET_MULTILEVEL_LOOKUP=0
+
+ # Source Build uses DotNetCoreSdkDir variable
+ if [[ -n "$DotNetCoreSdkDir" ]]; then
+ export DOTNET_INSTALL_DIR="$DotNetCoreSdkDir"
+ fi
+
+ ReadJson "$global_json_file" "version"
+ local dotnet_sdk_version="$readjsonvalue"
+ local dotnet_root=""
+
+ # Use dotnet installation specified in DOTNET_INSTALL_DIR if it contains the required SDK version,
+ # otherwise install the dotnet CLI and SDK to repo local .dotnet directory to avoid potential permission issues.
+ if [[ -d "$DOTNET_INSTALL_DIR/sdk/$dotnet_sdk_version" ]]; then
+ dotnet_root="$DOTNET_INSTALL_DIR"
+ else
+ dotnet_root="$repo_root/.dotnet"
+ export DOTNET_INSTALL_DIR="$dotnet_root"
+
+ if [[ "$restore" == true ]]; then
+ InstallDotNetCli $dotnet_root $dotnet_sdk_version
+ fi
+ fi
+
+ build_driver="$dotnet_root/dotnet"
+}
+
+function InstallDotNetCli {
+ local dotnet_root=$1
+ local dotnet_sdk_version=$2
+ local dotnet_install_script="$dotnet_root/dotnet-install.sh"
+
+ if [[ ! -a "$dotnet_install_script" ]]; then
+ mkdir -p "$dotnet_root"
+
+ # Use curl if available, otherwise use wget
+ if command -v curl > /dev/null; then
+ curl "https://dot.net/v1/dotnet-install.sh" -sSL --retry 10 --create-dirs -o "$dotnet_install_script"
+ else
+ wget -q -O "$dotnet_install_script" "https://dot.net/v1/dotnet-install.sh"
+ fi
+ fi
+
+ bash "$dotnet_install_script" --version $dotnet_sdk_version --install-dir $dotnet_root
+ local lastexitcode=$?
+
+ if [[ $lastexitcode != 0 ]]; then
+ echo "Failed to install dotnet cli (exit code '$lastexitcode')."
+ ExitWithExitCode $lastexitcode
+ fi
+}
+
+function InitializeToolset {
+ ReadJson $global_json_file "RoslynTools.RepoToolset"
+ local toolset_version=$readjsonvalue
+ local toolset_location_file="$toolset_dir/$toolset_version.txt"
+
+ if [[ -a "$toolset_location_file" ]]; then
+ local path=`cat $toolset_location_file`
+ if [[ -a "$path" ]]; then
+ toolset_build_proj=$path
+ return
+ fi
+ fi
+
+ if [[ "$restore" != true ]]; then
+ echo "Toolset version $toolsetVersion has not been restored."
+ ExitWithExitCode 2
+ fi
+
+ local proj="$toolset_dir/restore.proj"
+
+ echo '<Project Sdk="RoslynTools.RepoToolset"/>' > $proj
+ "$build_driver" msbuild $proj /t:__WriteToolsetLocation /m /nologo /clp:None /warnaserror /bl:$toolset_restore_log /v:$verbosity /p:__ToolsetLocationOutputFile=$toolset_location_file
+ local lastexitcode=$?
+
+ if [[ $lastexitcode != 0 ]]; then
+ echo "Failed to restore toolset (exit code '$lastexitcode'). See log: $toolset_restore_log"
+ ExitWithExitCode $lastexitcode
+ fi
+
+ toolset_build_proj=`cat $toolset_location_file`
+}
+
+function Build {
+ "$build_driver" msbuild $toolset_build_proj /m /nologo /clp:Summary /warnaserror \
+ /v:$verbosity /bl:$log /p:Configuration=$configuration /p:Projects=$solution /p:RepoRoot="$repo_root" \
+ /p:Restore=$restore /p:Build=$build /p:Rebuild=$rebuild /p:Deploy=$deploy /p:Test=$test /p:Sign=$sign /p:Pack=$pack /p:CIBuild=$ci \
+ $properties
+ local lastexitcode=$?
+
+ if [[ $lastexitcode != 0 ]]; then
+ echo "Failed to build $toolset_build_proj"
+ ExitWithExitCode $lastexitcode
+ fi
+}
+
+function ExitWithExitCode {
+ if [[ "$ci" == true && "$prepare_machine" == true ]]; then
+ StopProcesses
+ fi
+ exit $1
+}
+
+function StopProcesses {
+ echo "Killing running build processes..."
+ pkill -9 "dotnet"
+ pkill -9 "vbcscompiler"
+}
+
+function Main {
+ # HOME may not be defined in some scenarios, but it is required by NuGet
+ if [[ -z $HOME ]]; then
+ export HOME="$repo_root/artifacts/.home/"
+ mkdir -p "$HOME"
+ fi
+
+ if [[ -z $solution ]]; then
+ solution="$repo_root/*.sln"
+ fi
+
+ if [[ -z $NUGET_PACKAGES ]]; then
+ if [[ $ci ]]; then
+ export NUGET_PACKAGES="$repo_root/.packages"
+ else
+ export NUGET_PACKAGES="$HOME/.nuget/packages"
+ fi
+ fi
+
+ mkdir -p "$toolset_dir"
+ mkdir -p "$log_dir"
+
+ if [[ $ci ]]; then
+ mkdir -p "$temp_dir"
+ export TEMP="$temp_dir"
+ export TMP="$temp_dir"
+ fi
+
+ InitializeDotNetCli
+ InitializeToolset
+
+ Build
+ ExitWithExitCode $?
+}
+
+Main
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $SOURCE until the file is no longer a symlink
+while [[ -h $source ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+
+ # if $source was a relative symlink, we need to resolve it relative to the path where
+ # the symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+. "$scriptroot/build.sh" --restore --build --test --ci $@
\ No newline at end of file
--- /dev/null
+{
+ "sdk": {
+ "version": "2.1.101"
+ },
+ "msbuild-sdks": {
+ "RoslynTools.RepoToolset": "1.0.0-beta2-62810-01"
+ }
+}
--- /dev/null
+// Groovy Script: http://www.groovy-lang.org/syntax.html
+// Jenkins DSL: https://github.com/jenkinsci/job-dsl-plugin/wiki
+
+import jobs.generation.Utilities;
+
+static getJobName(def opsysName, def configName) {
+ return "${opsysName}_${configName}"
+}
+
+static addArchival(def job, def filesToArchive, def filesToExclude) {
+ def doNotFailIfNothingArchived = false
+ def archiveOnlyIfSuccessful = false
+
+ Utilities.addArchival(job, filesToArchive, filesToExclude, doNotFailIfNothingArchived, archiveOnlyIfSuccessful)
+}
+
+static addGithubPRTriggerForBranch(def job, def branchName, def jobName) {
+ def prContext = "prtest/${jobName.replace('_', '/')}"
+ def triggerPhrase = "(?i)^\\s*(@?dotnet-bot\\s+)?(re)?test\\s+(${prContext})(\\s+please)?\\s*\$"
+ def triggerOnPhraseOnly = false
+
+ Utilities.addGithubPRTriggerForBranch(job, branchName, prContext, triggerPhrase, triggerOnPhraseOnly)
+}
+
+static addXUnitDotNETResults(def job, def configName) {
+ def resultFilePattern = "**/artifacts/${configName}/TestResults/*.xml"
+ def skipIfNoTestFiles = false
+
+ Utilities.addXUnitDotNETResults(job, resultFilePattern, skipIfNoTestFiles)
+}
+
+static addBuildSteps(def job, def projectName, def os, def configName, def isPR) {
+ def buildJobName = getJobName(os, configName)
+ def buildFullJobName = Utilities.getFullJobName(projectName, buildJobName, isPR)
+
+ job.with {
+ steps {
+ if (os == "Windows_NT") {
+ batchFile(""".\\eng\\common\\CIBuild.cmd -configuration ${configName} -prepareMachine""")
+ } else {
+ shell("./eng/common/cibuild.sh --configuration ${configName} --prepareMachine")
+ }
+ }
+ }
+}
+
+[true, false].each { isPR ->
+ ['Ubuntu16.04', 'Windows_NT'].each { os ->
+ ['Debug', 'Release'].each { configName ->
+ def projectName = GithubProject
+
+ def branchName = GithubBranchName
+
+ def filesToArchive = "**/artifacts/${configName}/**"
+
+ def jobName = getJobName(os, configName)
+ def fullJobName = Utilities.getFullJobName(projectName, jobName, isPR)
+ def myJob = job(fullJobName)
+
+ Utilities.standardJobSetup(myJob, projectName, isPR, "*/${branchName}")
+
+ if (isPR) {
+ addGithubPRTriggerForBranch(myJob, branchName, jobName)
+ } else {
+ Utilities.addGithubPushTrigger(myJob)
+ }
+
+ addArchival(myJob, filesToArchive, "")
+ addXUnitDotNETResults(myJob, configName)
+
+ if (os == 'Windows_NT') {
+ Utilities.setMachineAffinity(myJob, os, 'latest-dev15-3')
+ } else {
+ Utilities.setMachineAffinity(myJob, os, 'latest-or-auto')
+ }
+
+ addBuildSteps(myJob, projectName, os, configName, isPR)
+ }
+ }
+}
--- /dev/null
+@echo off
+powershell -ExecutionPolicy ByPass -command "& """%~dp0eng\common\Build.ps1""" -pack %*"
+exit /b %ErrorLevel%
--- /dev/null
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $SOURCE until the file is no longer a symlink
+while [[ -h $source ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+"$scriptroot/eng/common/build.sh" --restore $@
\ No newline at end of file
--- /dev/null
+<!-- Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -->
+<Project>
+ <Import Project="..\Directory.Build.props"/>
+
+ <PropertyGroup>
+ <LangVersion>Latest</LangVersion>
+ </PropertyGroup>
+
+ <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
+ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+ </PropertyGroup>
+
+ <PropertyGroup Condition="'$(Configuration)' == 'Release'">
+ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+ </PropertyGroup>
+
+ <PropertyGroup Condition="'$(TargetFramework)' == 'net45'">
+ <DebugType>full</DebugType>
+ </PropertyGroup>
+
+ <PropertyGroup Condition="'$(TargetFramework)' != 'net45'">
+ <DebugType>portable</DebugType>
+ </PropertyGroup>
+</Project>
--- /dev/null
+<!-- Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -->
+<Project>
+ <Target Name="PublishForPack" AfterTargets="PostBuildEvent" Condition="'$(NoPublishForPack)' != 'true' and '$(IsPackable)' == 'true'">
+ <Message Importance="High" Text="Executing Publish target on $(MSBuildProjectFullPath) for $(TargetFramework)" />
+ <MSBuild Targets="Publish" Projects="$(MSBuildProjectFullPath)" BuildInParallel="false" Properties="NoBuild=true;NoPublishForPack=true" />
+ </Target>
+</Project>
--- /dev/null
+<!-- Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -->
+<Project Sdk="RoslynTools.RepoToolset">
+ <PropertyGroup>
+ <TargetFramework>netcoreapp1.0</TargetFramework>
+ <AssemblyName>SOS.NETCore</AssemblyName>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <NoWarn>;1591;1701</NoWarn>
+ <IsPackable>true</IsPackable>
+ <Description>Managed SOS Services</Description>
+ <PackageReleaseNotes>$(Description)</PackageReleaseNotes>
+ <PackageTags>SOS</PackageTags>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="System.Reflection.Metadata" Version="$(SystemReflectionMetadataVersion)" />
+ </ItemGroup>
+</Project>
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+using System.Reflection.PortableExecutable;
+using System.Runtime.InteropServices;
+
+namespace SOS
+{
+ internal class SymbolReader
+ {
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ internal struct DebugInfo
+ {
+ public int lineNumber;
+ public int ilOffset;
+ public string fileName;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ internal struct LocalVarInfo
+ {
+ public int startOffset;
+ public int endOffset;
+ public string name;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct MethodDebugInfo
+ {
+ public IntPtr points;
+ public int size;
+ public IntPtr locals;
+ public int localsSize;
+
+ }
+
+ /// <summary>
+ /// Read memory callback
+ /// </summary>
+ /// <returns>number of bytes read or 0 for error</returns>
+ internal unsafe delegate int ReadMemoryDelegate(ulong address, byte* buffer, int count);
+
+ private sealed class OpenedReader : IDisposable
+ {
+ public readonly MetadataReaderProvider Provider;
+ public readonly MetadataReader Reader;
+
+ public OpenedReader(MetadataReaderProvider provider, MetadataReader reader)
+ {
+ Debug.Assert(provider != null);
+ Debug.Assert(reader != null);
+
+ Provider = provider;
+ Reader = reader;
+ }
+
+ public void Dispose() => Provider.Dispose();
+ }
+
+ /// <summary>
+ /// Stream implementation to read debugger target memory for in-memory PDBs
+ /// </summary>
+ private class TargetStream : Stream
+ {
+ readonly ulong _address;
+ readonly ReadMemoryDelegate _readMemory;
+
+ public override long Position { get; set; }
+ public override long Length { get; }
+ public override bool CanSeek { get { return true; } }
+ public override bool CanRead { get { return true; } }
+ public override bool CanWrite { get { return false; } }
+
+ public TargetStream(ulong address, int size, ReadMemoryDelegate readMemory)
+ : base()
+ {
+ _address = address;
+ _readMemory = readMemory;
+ Length = size;
+ Position = 0;
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (Position + count > Length)
+ {
+ throw new ArgumentOutOfRangeException();
+ }
+ unsafe
+ {
+ fixed (byte* p = &buffer[offset])
+ {
+ int read = _readMemory(_address + (ulong)Position, p, count);
+ Position += read;
+ return read;
+ }
+ }
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ switch (origin)
+ {
+ case SeekOrigin.Begin:
+ Position = offset;
+ break;
+ case SeekOrigin.End:
+ Position = Length + offset;
+ break;
+ case SeekOrigin.Current:
+ Position += offset;
+ break;
+ }
+ return Position;
+ }
+
+ public override void Flush()
+ {
+ }
+
+ public override void SetLength(long value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ /// <summary>
+ /// Quick fix for Path.GetFileName which incorrectly handles Windows-style paths on Linux
+ /// </summary>
+ /// <param name="pathName"> File path to be processed </param>
+ /// <returns>Last component of path</returns>
+ private static string GetFileName(string pathName)
+ {
+ int pos = pathName.LastIndexOfAny(new char[] { '/', '\\'});
+ if (pos < 0)
+ return pathName;
+ return pathName.Substring(pos + 1);
+ }
+
+ /// <summary>
+ /// Checks availability of debugging information for given assembly.
+ /// </summary>
+ /// <param name="assemblyPath">
+ /// File path of the assembly or null if the module is in-memory or dynamic (generated by Reflection.Emit)
+ /// </param>
+ /// <param name="isFileLayout">type of in-memory PE layout, if true, file based layout otherwise, loaded layout</param>
+ /// <param name="loadedPeAddress">
+ /// Loaded PE image address or zero if the module is dynamic (generated by Reflection.Emit).
+ /// Dynamic modules have their PDBs (if any) generated to an in-memory stream
+ /// (pointed to by <paramref name="inMemoryPdbAddress"/> and <paramref name="inMemoryPdbSize"/>).
+ /// </param>
+ /// <param name="loadedPeSize">loaded PE image size</param>
+ /// <param name="inMemoryPdbAddress">in memory PDB address or zero</param>
+ /// <param name="inMemoryPdbSize">in memory PDB size</param>
+ /// <returns>Symbol reader handle or zero if error</returns>
+ internal static IntPtr LoadSymbolsForModule(string assemblyPath, bool isFileLayout, ulong loadedPeAddress, int loadedPeSize,
+ ulong inMemoryPdbAddress, int inMemoryPdbSize, ReadMemoryDelegate readMemory)
+ {
+ try
+ {
+ TargetStream peStream = null;
+ if (assemblyPath == null && loadedPeAddress != 0)
+ {
+ peStream = new TargetStream(loadedPeAddress, loadedPeSize, readMemory);
+ }
+ TargetStream pdbStream = null;
+ if (inMemoryPdbAddress != 0)
+ {
+ pdbStream = new TargetStream(inMemoryPdbAddress, inMemoryPdbSize, readMemory);
+ }
+ OpenedReader openedReader = GetReader(assemblyPath, isFileLayout, peStream, pdbStream);
+ if (openedReader != null)
+ {
+ GCHandle gch = GCHandle.Alloc(openedReader);
+ return GCHandle.ToIntPtr(gch);
+ }
+ }
+ catch
+ {
+ }
+ return IntPtr.Zero;
+ }
+
+ /// <summary>
+ /// Cleanup and dispose of symbol reader handle
+ /// </summary>
+ /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param>
+ internal static void Dispose(IntPtr symbolReaderHandle)
+ {
+ Debug.Assert(symbolReaderHandle != IntPtr.Zero);
+ try
+ {
+ GCHandle gch = GCHandle.FromIntPtr(symbolReaderHandle);
+ ((OpenedReader)gch.Target).Dispose();
+ gch.Free();
+ }
+ catch
+ {
+ }
+ }
+
+ /// <summary>
+ /// Returns method token and IL offset for given source line number.
+ /// </summary>
+ /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param>
+ /// <param name="filePath">source file name and path</param>
+ /// <param name="lineNumber">source line number</param>
+ /// <param name="methodToken">method token return</param>
+ /// <param name="ilOffset">IL offset return</param>
+ /// <returns> true if information is available</returns>
+ internal static bool ResolveSequencePoint(IntPtr symbolReaderHandle, string filePath, int lineNumber, out int methodToken, out int ilOffset)
+ {
+ Debug.Assert(symbolReaderHandle != IntPtr.Zero);
+ methodToken = 0;
+ ilOffset = 0;
+
+ GCHandle gch = GCHandle.FromIntPtr(symbolReaderHandle);
+ MetadataReader reader = ((OpenedReader)gch.Target).Reader;
+
+ try
+ {
+ string fileName = GetFileName(filePath);
+ foreach (MethodDebugInformationHandle methodDebugInformationHandle in reader.MethodDebugInformation)
+ {
+ MethodDebugInformation methodDebugInfo = reader.GetMethodDebugInformation(methodDebugInformationHandle);
+ SequencePointCollection sequencePoints = methodDebugInfo.GetSequencePoints();
+ foreach (SequencePoint point in sequencePoints)
+ {
+ string sourceName = reader.GetString(reader.GetDocument(point.Document).Name);
+ if (point.StartLine == lineNumber && GetFileName(sourceName) == fileName)
+ {
+ methodToken = MetadataTokens.GetToken(methodDebugInformationHandle.ToDefinitionHandle());
+ ilOffset = point.Offset;
+ return true;
+ }
+ }
+ }
+ }
+ catch
+ {
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Returns source line number and source file name for given IL offset and method token.
+ /// </summary>
+ /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param>
+ /// <param name="methodToken">method token</param>
+ /// <param name="ilOffset">IL offset</param>
+ /// <param name="lineNumber">source line number return</param>
+ /// <param name="fileName">source file name return</param>
+ /// <returns> true if information is available</returns>
+ internal static bool GetLineByILOffset(IntPtr symbolReaderHandle, int methodToken, long ilOffset, out int lineNumber, out IntPtr fileName)
+ {
+ lineNumber = 0;
+ fileName = IntPtr.Zero;
+
+ string sourceFileName = null;
+
+ if (!GetSourceLineByILOffset(symbolReaderHandle, methodToken, ilOffset, out lineNumber, out sourceFileName))
+ {
+ return false;
+ }
+ fileName = Marshal.StringToBSTR(sourceFileName);
+ sourceFileName = null;
+ return true;
+ }
+
+ /// <summary>
+ /// Helper method to return source line number and source file name for given IL offset and method token.
+ /// </summary>
+ /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param>
+ /// <param name="methodToken">method token</param>
+ /// <param name="ilOffset">IL offset</param>
+ /// <param name="lineNumber">source line number return</param>
+ /// <param name="fileName">source file name return</param>
+ /// <returns> true if information is available</returns>
+ private static bool GetSourceLineByILOffset(IntPtr symbolReaderHandle, int methodToken, long ilOffset, out int lineNumber, out string fileName)
+ {
+ Debug.Assert(symbolReaderHandle != IntPtr.Zero);
+ lineNumber = 0;
+ fileName = null;
+
+ GCHandle gch = GCHandle.FromIntPtr(symbolReaderHandle);
+ MetadataReader reader = ((OpenedReader)gch.Target).Reader;
+
+ try
+ {
+ Handle handle = MetadataTokens.Handle(methodToken);
+ if (handle.Kind != HandleKind.MethodDefinition)
+ return false;
+
+ MethodDebugInformationHandle methodDebugHandle = ((MethodDefinitionHandle)handle).ToDebugInformationHandle();
+ if (methodDebugHandle.IsNil)
+ return false;
+
+ MethodDebugInformation methodDebugInfo = reader.GetMethodDebugInformation(methodDebugHandle);
+ SequencePointCollection sequencePoints = methodDebugInfo.GetSequencePoints();
+
+ SequencePoint nearestPoint = sequencePoints.GetEnumerator().Current;
+ foreach (SequencePoint point in sequencePoints)
+ {
+ if (point.Offset < ilOffset)
+ {
+ nearestPoint = point;
+ }
+ else
+ {
+ if (point.Offset == ilOffset)
+ nearestPoint = point;
+
+ if (nearestPoint.StartLine == 0 || nearestPoint.StartLine == SequencePoint.HiddenLine)
+ return false;
+
+ lineNumber = nearestPoint.StartLine;
+ fileName = reader.GetString(reader.GetDocument(nearestPoint.Document).Name);
+ return true;
+ }
+ }
+ }
+ catch
+ {
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Returns local variable name for given local index and IL offset.
+ /// </summary>
+ /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param>
+ /// <param name="methodToken">method token</param>
+ /// <param name="localIndex">local variable index</param>
+ /// <param name="localVarName">local variable name return</param>
+ /// <returns>true if name has been found</returns>
+ internal static bool GetLocalVariableName(IntPtr symbolReaderHandle, int methodToken, int localIndex, out IntPtr localVarName)
+ {
+ localVarName = IntPtr.Zero;
+
+ string localVar = null;
+ if (!GetLocalVariableByIndex(symbolReaderHandle, methodToken, localIndex, out localVar))
+ return false;
+
+ localVarName = Marshal.StringToBSTR(localVar);
+ localVar = null;
+ return true;
+ }
+
+ /// <summary>
+ /// Helper method to return local variable name for given local index and IL offset.
+ /// </summary>
+ /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param>
+ /// <param name="methodToken">method token</param>
+ /// <param name="localIndex">local variable index</param>
+ /// <param name="localVarName">local variable name return</param>
+ /// <returns>true if name has been found</returns>
+ internal static bool GetLocalVariableByIndex(IntPtr symbolReaderHandle, int methodToken, int localIndex, out string localVarName)
+ {
+ Debug.Assert(symbolReaderHandle != IntPtr.Zero);
+ localVarName = null;
+
+ GCHandle gch = GCHandle.FromIntPtr(symbolReaderHandle);
+ MetadataReader reader = ((OpenedReader)gch.Target).Reader;
+
+ try
+ {
+ Handle handle = MetadataTokens.Handle(methodToken);
+ if (handle.Kind != HandleKind.MethodDefinition)
+ return false;
+
+ MethodDebugInformationHandle methodDebugHandle = ((MethodDefinitionHandle)handle).ToDebugInformationHandle();
+ LocalScopeHandleCollection localScopes = reader.GetLocalScopes(methodDebugHandle);
+ foreach (LocalScopeHandle scopeHandle in localScopes)
+ {
+ LocalScope scope = reader.GetLocalScope(scopeHandle);
+ LocalVariableHandleCollection localVars = scope.GetLocalVariables();
+ foreach (LocalVariableHandle varHandle in localVars)
+ {
+ LocalVariable localVar = reader.GetLocalVariable(varHandle);
+ if (localVar.Index == localIndex)
+ {
+ if (localVar.Attributes == LocalVariableAttributes.DebuggerHidden)
+ return false;
+
+ localVarName = reader.GetString(localVar.Name);
+ return true;
+ }
+ }
+ }
+ }
+ catch
+ {
+ }
+ return false;
+ }
+ internal static bool GetLocalsInfoForMethod(string assemblyPath, int methodToken, out List<LocalVarInfo> locals)
+ {
+ locals = null;
+
+ OpenedReader openedReader = GetReader(assemblyPath, isFileLayout: true, peStream: null, pdbStream: null);
+ if (openedReader == null)
+ return false;
+
+ using (openedReader)
+ {
+ try
+ {
+ Handle handle = MetadataTokens.Handle(methodToken);
+ if (handle.Kind != HandleKind.MethodDefinition)
+ return false;
+
+ locals = new List<LocalVarInfo>();
+
+ MethodDebugInformationHandle methodDebugHandle =
+ ((MethodDefinitionHandle)handle).ToDebugInformationHandle();
+ LocalScopeHandleCollection localScopes = openedReader.Reader.GetLocalScopes(methodDebugHandle);
+ foreach (LocalScopeHandle scopeHandle in localScopes)
+ {
+ LocalScope scope = openedReader.Reader.GetLocalScope(scopeHandle);
+ LocalVariableHandleCollection localVars = scope.GetLocalVariables();
+ foreach (LocalVariableHandle varHandle in localVars)
+ {
+ LocalVariable localVar = openedReader.Reader.GetLocalVariable(varHandle);
+ if (localVar.Attributes == LocalVariableAttributes.DebuggerHidden)
+ continue;
+ LocalVarInfo info = new LocalVarInfo();
+ info.startOffset = scope.StartOffset;
+ info.endOffset = scope.EndOffset;
+ info.name = openedReader.Reader.GetString(localVar.Name);
+ locals.Add(info);
+ }
+ }
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ return true;
+
+ }
+ /// <summary>
+ /// Returns source name, line numbers and IL offsets for given method token.
+ /// </summary>
+ /// <param name="assemblyPath">file path of the assembly</param>
+ /// <param name="methodToken">method token</param>
+ /// <param name="debugInfo">structure with debug information return</param>
+ /// <returns>true if information is available</returns>
+ /// <remarks>used by the gdb JIT support (not SOS). Does not support in-memory PEs or PDBs</remarks>
+ internal static bool GetInfoForMethod(string assemblyPath, int methodToken, ref MethodDebugInfo debugInfo)
+ {
+ try
+ {
+ List<DebugInfo> points = null;
+ List<LocalVarInfo> locals = null;
+
+ if (!GetDebugInfoForMethod(assemblyPath, methodToken, out points))
+ {
+ return false;
+ }
+
+ if (!GetLocalsInfoForMethod(assemblyPath, methodToken, out locals))
+ {
+ return false;
+ }
+ var structSize = Marshal.SizeOf<DebugInfo>();
+
+ debugInfo.size = points.Count;
+ var ptr = debugInfo.points;
+
+ foreach (var info in points)
+ {
+ Marshal.StructureToPtr(info, ptr, false);
+ ptr = (IntPtr)(ptr.ToInt64() + structSize);
+ }
+
+ structSize = Marshal.SizeOf<LocalVarInfo>();
+
+ debugInfo.localsSize = locals.Count;
+ ptr = debugInfo.locals;
+
+ foreach (var info in locals)
+ {
+ Marshal.StructureToPtr(info, ptr, false);
+ ptr = (IntPtr)(ptr.ToInt64() + structSize);
+ }
+
+ return true;
+ }
+ catch
+ {
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Helper method to return source name, line numbers and IL offsets for given method token.
+ /// </summary>
+ /// <param name="assemblyPath">file path of the assembly</param>
+ /// <param name="methodToken">method token</param>
+ /// <param name="points">list of debug information for each sequence point return</param>
+ /// <returns>true if information is available</returns>
+ /// <remarks>used by the gdb JIT support (not SOS). Does not support in-memory PEs or PDBs</remarks>
+ private static bool GetDebugInfoForMethod(string assemblyPath, int methodToken, out List<DebugInfo> points)
+ {
+ points = null;
+
+ OpenedReader openedReader = GetReader(assemblyPath, isFileLayout: true, peStream: null, pdbStream: null);
+ if (openedReader == null)
+ return false;
+
+ using (openedReader)
+ {
+ try
+ {
+ Handle handle = MetadataTokens.Handle(methodToken);
+ if (handle.Kind != HandleKind.MethodDefinition)
+ return false;
+
+ points = new List<DebugInfo>();
+ MethodDebugInformationHandle methodDebugHandle = ((MethodDefinitionHandle)handle).ToDebugInformationHandle();
+ MethodDebugInformation methodDebugInfo = openedReader.Reader.GetMethodDebugInformation(methodDebugHandle);
+ SequencePointCollection sequencePoints = methodDebugInfo.GetSequencePoints();
+
+ foreach (SequencePoint point in sequencePoints)
+ {
+
+ DebugInfo debugInfo = new DebugInfo();
+ debugInfo.lineNumber = point.StartLine;
+ debugInfo.fileName = openedReader.Reader.GetString(openedReader.Reader.GetDocument(point.Document).Name);
+ debugInfo.ilOffset = point.Offset;
+ points.Add(debugInfo);
+ }
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Returns the portable PDB reader for the assembly path
+ /// </summary>
+ /// <param name="assemblyPath">file path of the assembly or null if the module is in-memory or dynamic</param>
+ /// <param name="isFileLayout">type of in-memory PE layout, if true, file based layout otherwise, loaded layout</param>
+ /// <param name="peStream">optional in-memory PE stream</param>
+ /// <param name="pdbStream">optional in-memory PDB stream</param>
+ /// <returns>reader/provider wrapper instance</returns>
+ /// <remarks>
+ /// Assumes that neither PE image nor PDB loaded into memory can be unloaded or moved around.
+ /// </remarks>
+ private static OpenedReader GetReader(string assemblyPath, bool isFileLayout, Stream peStream, Stream pdbStream)
+ {
+ return (pdbStream != null) ? TryOpenReaderForInMemoryPdb(pdbStream) : TryOpenReaderFromAssembly(assemblyPath, isFileLayout, peStream);
+ }
+
+ private static OpenedReader TryOpenReaderForInMemoryPdb(Stream pdbStream)
+ {
+ Debug.Assert(pdbStream != null);
+
+ byte[] buffer = new byte[sizeof(uint)];
+ if (pdbStream.Read(buffer, 0, sizeof(uint)) != sizeof(uint))
+ {
+ return null;
+ }
+ uint signature = BitConverter.ToUInt32(buffer, 0);
+
+ // quick check to avoid throwing exceptions below in common cases:
+ const uint ManagedMetadataSignature = 0x424A5342;
+ if (signature != ManagedMetadataSignature)
+ {
+ // not a Portable PDB
+ return null;
+ }
+
+ OpenedReader result = null;
+ MetadataReaderProvider provider = null;
+ try
+ {
+ pdbStream.Position = 0;
+ provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
+ result = new OpenedReader(provider, provider.GetMetadataReader());
+ }
+ catch (Exception e) when (e is BadImageFormatException || e is IOException)
+ {
+ return null;
+ }
+ finally
+ {
+ if (result == null)
+ {
+ provider?.Dispose();
+ }
+ }
+
+ return result;
+ }
+
+ private static OpenedReader TryOpenReaderFromAssembly(string assemblyPath, bool isFileLayout, Stream peStream)
+ {
+ if (assemblyPath == null && peStream == null)
+ return null;
+
+ PEStreamOptions options = isFileLayout ? PEStreamOptions.Default : PEStreamOptions.IsLoadedImage;
+ if (peStream == null)
+ {
+ peStream = TryOpenFile(assemblyPath);
+ if (peStream == null)
+ return null;
+
+ options = PEStreamOptions.Default;
+ }
+
+ try
+ {
+ using (var peReader = new PEReader(peStream, options))
+ {
+ DebugDirectoryEntry codeViewEntry, embeddedPdbEntry;
+ ReadPortableDebugTableEntries(peReader, out codeViewEntry, out embeddedPdbEntry);
+
+ // First try .pdb file specified in CodeView data (we prefer .pdb file on disk over embedded PDB
+ // since embedded PDB needs decompression which is less efficient than memory-mapping the file).
+ if (codeViewEntry.DataSize != 0)
+ {
+ var result = TryOpenReaderFromCodeView(peReader, codeViewEntry, assemblyPath);
+ if (result != null)
+ {
+ return result;
+ }
+ }
+
+ // if it failed try Embedded Portable PDB (if available):
+ if (embeddedPdbEntry.DataSize != 0)
+ {
+ return TryOpenReaderFromEmbeddedPdb(peReader, embeddedPdbEntry);
+ }
+ }
+ }
+ catch (Exception e) when (e is BadImageFormatException || e is IOException)
+ {
+ // nop
+ }
+
+ return null;
+ }
+
+ private static void ReadPortableDebugTableEntries(PEReader peReader, out DebugDirectoryEntry codeViewEntry, out DebugDirectoryEntry embeddedPdbEntry)
+ {
+ // See spec: https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PE-COFF.md
+
+ codeViewEntry = default(DebugDirectoryEntry);
+ embeddedPdbEntry = default(DebugDirectoryEntry);
+
+ foreach (DebugDirectoryEntry entry in peReader.ReadDebugDirectory())
+ {
+ if (entry.Type == DebugDirectoryEntryType.CodeView)
+ {
+ const ushort PortableCodeViewVersionMagic = 0x504d;
+ if (entry.MinorVersion != PortableCodeViewVersionMagic)
+ {
+ continue;
+ }
+
+ codeViewEntry = entry;
+ }
+ else if (entry.Type == DebugDirectoryEntryType.EmbeddedPortablePdb)
+ {
+ embeddedPdbEntry = entry;
+ }
+ }
+ }
+
+ private static OpenedReader TryOpenReaderFromCodeView(PEReader peReader, DebugDirectoryEntry codeViewEntry, string assemblyPath)
+ {
+ OpenedReader result = null;
+ MetadataReaderProvider provider = null;
+ try
+ {
+ var data = peReader.ReadCodeViewDebugDirectoryData(codeViewEntry);
+
+ string pdbPath = data.Path;
+ if (assemblyPath != null)
+ {
+ try
+ {
+ pdbPath = Path.Combine(Path.GetDirectoryName(assemblyPath), GetFileName(pdbPath));
+ }
+ catch
+ {
+ // invalid characters in CodeView path
+ return null;
+ }
+ }
+
+ var pdbStream = TryOpenFile(pdbPath);
+ if (pdbStream == null)
+ {
+ return null;
+ }
+
+ provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
+ var reader = provider.GetMetadataReader();
+
+ // Validate that the PDB matches the assembly version
+ if (data.Age == 1 && new BlobContentId(reader.DebugMetadataHeader.Id) == new BlobContentId(data.Guid, codeViewEntry.Stamp))
+ {
+ result = new OpenedReader(provider, reader);
+ }
+ }
+ catch (Exception e) when (e is BadImageFormatException || e is IOException)
+ {
+ return null;
+ }
+ finally
+ {
+ if (result == null)
+ {
+ provider?.Dispose();
+ }
+ }
+
+ return result;
+ }
+
+ private static OpenedReader TryOpenReaderFromEmbeddedPdb(PEReader peReader, DebugDirectoryEntry embeddedPdbEntry)
+ {
+ OpenedReader result = null;
+ MetadataReaderProvider provider = null;
+
+ try
+ {
+ // TODO: We might want to cache this provider globally (across stack traces),
+ // since decompressing embedded PDB takes some time.
+ provider = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(embeddedPdbEntry);
+ result = new OpenedReader(provider, provider.GetMetadataReader());
+ }
+ catch (Exception e) when (e is BadImageFormatException || e is IOException)
+ {
+ return null;
+ }
+ finally
+ {
+ if (result == null)
+ {
+ provider?.Dispose();
+ }
+ }
+
+ return result;
+ }
+
+ private static Stream TryOpenFile(string path)
+ {
+ if (!File.Exists(path))
+ {
+ return null;
+ }
+ try
+ {
+ return File.OpenRead(path);
+ }
+ catch
+ {
+ return null;
+ }
+ }
+ }
+}