Using the Roslyn repo tool set to build (for now).
This commit is contained in:
Mike McLaughlin 2018-03-21 18:58:34 -07:00
Родитель a2ce91d916
Коммит ad99d3facd
23 изменённых файлов: 1690 добавлений и 233 удалений

49
.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1,49 @@
###############################################################################
# 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

255
.gitignore поставляемый
Просмотреть файл

@ -1,60 +1,29 @@
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
.dotnet/
.packages/
.tools/
# 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/
# 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
@ -62,7 +31,6 @@ dlldata.c
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
@ -70,45 +38,34 @@ dlldata.c
*.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*
@ -117,106 +74,28 @@ _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
@ -228,95 +107,5 @@ Desktop.ini
# 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

3
Build.cmd Normal file
Просмотреть файл

@ -0,0 +1,3 @@
@echo off
powershell -ExecutionPolicy ByPass -command "& """%~dp0eng\common\Build.ps1""" -restore -build %*"
exit /b %ErrorLevel%

12
Directory.Build.props Normal file
Просмотреть файл

@ -0,0 +1,12 @@
<!-- 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>

8
NuGet.Config Normal file
Просмотреть файл

@ -0,0 +1,8 @@
<?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>

3
Restore.cmd Normal file
Просмотреть файл

@ -0,0 +1,3 @@
@echo off
powershell -ExecutionPolicy ByPass -command "& """%~dp0eng\common\Build.ps1""" -restore %*"
exit /b %ErrorLevel%

3
Test.cmd Normal file
Просмотреть файл

@ -0,0 +1,3 @@
@echo off
powershell -ExecutionPolicy ByPass -command "& """%~dp0eng\common\Build.ps1""" -test %*"
exit /b %ErrorLevel%

16
build.sh Executable file
Просмотреть файл

@ -0,0 +1,16 @@
#!/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 $@

27
diagnostics.sln Normal file
Просмотреть файл

@ -0,0 +1,27 @@

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

25
eng/SignToolData.json Normal file
Просмотреть файл

@ -0,0 +1,25 @@
{
"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",
]
}

25
eng/Versions.props Normal file
Просмотреть файл

@ -0,0 +1,25 @@
<!-- 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>

3
eng/common/CIBuild.cmd Normal file
Просмотреть файл

@ -0,0 +1,3 @@
@echo off
powershell -ExecutionPolicy ByPass -command "& """%~dp0Build.ps1""" -restore -build -test -sign -pack -ci %*"
exit /b %ErrorLevel%

252
eng/common/build.ps1 Normal file
Просмотреть файл

@ -0,0 +1,252 @@
[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
}
}

289
eng/common/build.sh Executable file
Просмотреть файл

@ -0,0 +1,289 @@
#!/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

16
eng/common/cibuild.sh Executable file
Просмотреть файл

@ -0,0 +1,16 @@
#!/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 $@

8
global.json Normal file
Просмотреть файл

@ -0,0 +1,8 @@
{
"sdk": {
"version": "2.1.101"
},
"msbuild-sdks": {
"RoslynTools.RepoToolset": "1.0.0-beta2-62810-01"
}
}

80
netci.groovy Normal file
Просмотреть файл

@ -0,0 +1,80 @@
// 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)
}
}
}

3
pack.cmd Normal file
Просмотреть файл

@ -0,0 +1,3 @@
@echo off
powershell -ExecutionPolicy ByPass -command "& """%~dp0eng\common\Build.ps1""" -pack %*"
exit /b %ErrorLevel%

16
restore.sh Executable file
Просмотреть файл

@ -0,0 +1,16 @@
#!/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 $@

24
src/Directory.Build.props Normal file
Просмотреть файл

@ -0,0 +1,24 @@
<!-- 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>

Просмотреть файл

@ -0,0 +1,7 @@
<!-- 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>

Просмотреть файл

@ -0,0 +1,17 @@
<!-- 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>

Просмотреть файл

@ -0,0 +1,782 @@
// 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;
}
}
}
}