Merge main into release/stable (#3089)
authorMike McLaughlin <mikem@microsoft.com>
Tue, 24 May 2022 01:14:08 +0000 (18:14 -0700)
committerGitHub <noreply@github.com>
Tue, 24 May 2022 01:14:08 +0000 (18:14 -0700)
* Update dependencies from https://github.com/dotnet/aspnetcore build 20220406.3 (#2990)

[main] Update dependencies from dotnet/aspnetcore

* Update dependencies from https://github.com/dotnet/runtime build 20220406.5 (#2991)

[main] Update dependencies from dotnet/runtime

* Set the build ID using arcade's scripts instead of retrieving it from another job (#2993)

* Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20220328.1 (#2967)

[main] Update dependencies from dotnet/source-build-reference-packages

* Update dependencies from https://github.com/dotnet/arcade build 20220406.10 (#3000)

[main] Update dependencies from dotnet/arcade

* Update dependencies from https://github.com/dotnet/symstore build 20220410.1 (#3002)

Microsoft.SymbolStore
 From Version 1.0.320401 -> To Version 1.0.321001

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
* Update dependencies from https://github.com/dotnet/installer build 20220410.6 (#3001)

Microsoft.Dotnet.Sdk.Internal
 From Version 6.0.104-servicing.22181.15 -> To Version 6.0.104-servicing.22210.6

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
* Update dependencies from https://github.com/dotnet/symstore build 20220411.1 (#3007)

[main] Update dependencies from dotnet/symstore

* Update dependencies from https://github.com/dotnet/aspnetcore build 20220411.2 (#3006)

[main] Update dependencies from dotnet/aspnetcore

* Update dependencies from https://github.com/dotnet/runtime build 20220411.4 (#3008)

[main] Update dependencies from dotnet/runtime

* Update dependencies from https://github.com/dotnet/runtime build 20220412.7 (#3011)

[main] Update dependencies from dotnet/runtime

* Update dependencies from https://github.com/dotnet/symstore build 20220412.1 (#3010)

[main] Update dependencies from dotnet/symstore

* Rewrite DumpAsync in C# (#2964)

* Rewrite DumpAsync in C#

This rewrites the dumpasync command as a C# SOS extension.  Doing so makes the code easier to maintain and add features to in the future.  Along with the rewrite, a variety of requests for the feature have been satisfied:
- Added a "coalesced stacks" view (`--coalesce`) that coalesces stacks together to create a high-level view of the state of the process
- Improved filtering so that a specified filter (address, method table, substring) applies to any frame of a stack and not just to the top frame
- Improved stack stitching to always consider task objects from the heap and not just if `--tasks` was specified.  This helps to better connect state machines separated by constructs like Task.Run.
- Added synthesized frames to try to show what's being awaited in the case where the top frame is an async method.
- Added DML links for more things to better navigate through results.

* Fix tests

* Fix tests for DumpAsync on WebApp3

* Skip visiting tasks multiple times

* Special case completion sentinnel

* Only synthesize faux awaiter frame if the task is not completed.

* PR feedback

Co-authored-by: Juan Sebastian Hoyos Ayala <juan.hoyos@microsoft.com>
* Update dependencies from https://github.com/dotnet/runtime build 20220413.11 (#3014)

Microsoft.NETCore.App.Runtime.win-x64 , VS.Redist.Common.NetCore.SharedFramework.x64.6.0
 From Version 6.0.5 -> To Version 6.0.5

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
* Update dependencies from https://github.com/dotnet/aspnetcore build 20220413.12 (#3013)

[main] Update dependencies from dotnet/aspnetcore

* Use symstore retry changes in tests (#2968)

* Create clear error messages for dotnet-trace (#3012)

* Catch UnauthorizedAccessException, Win32Exception and simplify for loop

* altered to conventional C# style

* Set symstore HTTP retry count in all test cases (#3015)

* Set symstore HTTP retry count in all test cases

* Update src/Microsoft.Diagnostics.DebugServices/ISymbolService.cs

Co-authored-by: Juan Hoyos <juan.hoyos@microsoft.com>
* Code review feedback

Co-authored-by: Juan Hoyos <juan.hoyos@microsoft.com>
* Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20220415.1 (#3016)

[main] Update dependencies from dotnet/source-build-reference-packages

* Update dependencies from https://github.com/dotnet/arcade build 20220415.2 (#3017)

[main] Update dependencies from dotnet/arcade

* Update lldb instuctions (#3020)

Mostly just delete distro versions that are not supported for any supported .NET version.

* Use minipal in more places (#3019)

* Port minipal/getexepath.h from runtime repo

* Use ARRAY_SIZE from minipal in more places

* Fix C4996 warning on windows

* Introspect sys/auxv.h in SOS configuration

* Fix include

* [main] Update dependencies from dotnet/installer (#3018)

* Update dependencies from https://github.com/dotnet/installer build 20220415.3

Microsoft.Dotnet.Sdk.Internal
 From Version 6.0.104-servicing.22210.6 -> To Version 6.0.105-servicing.22215.3

* Fix single-file runtime version

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Mike McLaughlin <mikem@microsoft.com>
* Update dependencies from https://github.com/dotnet/symstore build 20220418.1 (#3022)

[main] Update dependencies from dotnet/symstore

* Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20220419.2 (#3023)

[main] Update dependencies from dotnet/source-build-reference-packages

* Create EventPipeFormat.md (#3024)

* Update dependencies from https://github.com/dotnet/arcade build 20220422.4 (#3027)

[main] Update dependencies from dotnet/arcade

* Update dependencies from https://github.com/dotnet/installer build 20220419.37 (#3028)

[main] Update dependencies from dotnet/installer

* dotent-trace report - account for missing symbol (#3021)

* Update dependencies from https://github.com/microsoft/clrmd build 20220426.1 (#3035)

[main] Update dependencies from microsoft/clrmd

* Write temp files to tempdir (#3031)

* update to use viewport-relative coordinates (#3034)

This fixes some rendering issues of dontet-counters, however, dotnet-counters renders incorrectly when:
- terminal changes size while the tool is running
- terminal is not wide enough to print the output

As noted in #3036

* Update dependencies from https://github.com/dotnet/installer build 20220429.9 (#3038)

[main] Update dependencies from dotnet/installer

* Update dependencies from https://github.com/dotnet/arcade build 20220425.6 (#3037)

[main] Update dependencies from dotnet/arcade

* Update dependencies from https://github.com/dotnet/symstore build 20220502.1 (#3040)

[main] Update dependencies from dotnet/symstore

* Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20220503.1 (#3043)

[main] Update dependencies from dotnet/source-build-reference-packages

* Update dependencies from https://github.com/dotnet/aspnetcore build 20220503.6 (#3041)

[main] Update dependencies from dotnet/aspnetcore

* Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20220504.3 (#3045)

[main] Update dependencies from dotnet/source-build-reference-packages

* Update dependencies from https://github.com/dotnet/aspnetcore build 20220504.26 (#3044)

[main] Update dependencies from dotnet/aspnetcore

* Update dependencies from https://github.com/dotnet/aspnetcore build 20220505.18 (#3046)

[main] Update dependencies from dotnet/aspnetcore

* Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20220505.1 (#3048)

[main] Update dependencies from dotnet/source-build-reference-packages

* Update dependencies from https://github.com/microsoft/clrmd build 20220505.1 (#3047)

[main] Update dependencies from microsoft/clrmd

* Update EventPipeStress (#3049)

* Update dependencies from https://github.com/dotnet/arcade build 20220505.2 (#3052)

[main] Update dependencies from dotnet/arcade

* Update dependencies from https://github.com/dotnet/installer build 20220504.12 (#3053)

[main] Update dependencies from dotnet/installer

* Update dependencies from https://github.com/microsoft/clrmd build 20220509.1 (#3056)

[main] Update dependencies from microsoft/clrmd

* Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20220509.4 (#3058)

[main] Update dependencies from dotnet/source-build-reference-packages

* Update dependencies from https://github.com/dotnet/symstore build 20220509.1 (#3057)

[main] Update dependencies from dotnet/symstore

* Update dependencies from https://github.com/dotnet/aspnetcore build 20220509.8 (#3055)

[main] Update dependencies from dotnet/aspnetcore

* Port setsymbolserver command to C# (#3050)

* Port setsymbolserver command to C#

Fixes issue: https://github.com/dotnet/diagnostics/issues/3032

Removes quite a bit of native and interop code.

Remove some noisy logging in success paths.

Rename ISymbolService.DownloadModule to DownloadModuleFile. Add ISymbolService.DownloadSymbolFile.

Rename some IModule properties to functions. Add IModule.LoadSymbols().

Fix MacOS test failures

Make setsymbolserver a global command

* Update dependencies from https://github.com/dotnet/aspnetcore build 20220510.8 (#3063)

[main] Update dependencies from dotnet/aspnetcore

* Enable SDL required warnings explicitly (#3054)

* Enable SDL required warnings explicitly
* Fix build issues that don't escape on failure properly

* Add devcontainer infra to diagnostics repo (#2986)

* Pass by reference (#3066)

* Update dependencies from https://github.com/dotnet/aspnetcore build 20220512.8 (#3070)

[main] Update dependencies from dotnet/aspnetcore

* Fix Typo (#3071)

* Misc dbgshim and SOS fixes (#3072)

* Fix some issues found with netcoredbg

* Fix some sign-extension issues on alpine arm32

* Fix DbgShim.UnitTest's Microsoft.Diagnostics.DbgShimAPI+NativeRuntimeStartupCallbackDelegate being called after collected by the GC

* Code review feedback

* [main] Update dependencies from dotnet/installer (#3076)

[main] Update dependencies from dotnet/installer

 - Update single-file version

* Update dependencies from https://github.com/dotnet/symstore build 20220516.1 (#3079)

[main] Update dependencies from dotnet/symstore

* Update dependencies from https://github.com/dotnet/arcade build 20220512.8 (#3075)

[main] Update dependencies from dotnet/arcade

* Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20220511.1 (#3068)

[main] Update dependencies from dotnet/source-build-reference-packages

* Update dependencies from https://github.com/dotnet/arcade build 20220519.3 (#3086)

[main] Update dependencies from dotnet/arcade

* Enable shipping dbgshim packages (#3088)

Co-authored-by: dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Juan Hoyos <juan.s.hoyos@outlook.com>
Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Stephen Toub <stoub@microsoft.com>
Co-authored-by: Juan Sebastian Hoyos Ayala <juan.hoyos@microsoft.com>
Co-authored-by: mikelle-rogers <45022607+mikelle-rogers@users.noreply.github.com>
Co-authored-by: Dan Moseley <danmose@microsoft.com>
Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com>
Co-authored-by: John Salem <josalem@microsoft.com>
Co-authored-by: Andrew Au <andrewau@microsoft.com>
Co-authored-by: Martin-Molinero <martin@quantconnect.com>
120 files changed:
.devcontainer/Dockerfile [new file with mode: 0644]
.devcontainer/devcontainer.json [new file with mode: 0644]
.gitignore
NuGet.config
documentation/EventPipeFormat.md [new file with mode: 0644]
documentation/building/official-build-instructions.md
documentation/lldb/linux-instructions.md
eng/Build-Native.cmd
eng/Version.Details.xml
eng/Versions.props
eng/build.sh
eng/common/cross/build-rootfs.sh
eng/common/dotnet-install.sh
eng/common/init-tools-native.ps1
eng/common/internal/Tools.csproj
eng/common/sdk-task.ps1
eng/common/templates/job/onelocbuild.yml
eng/common/templates/job/publish-build-assets.yml
eng/common/templates/job/source-index-stage1.yml
eng/common/templates/jobs/jobs.yml
eng/common/templates/post-build/post-build.yml
eng/common/tools.ps1
eng/native/configurecompiler.cmake
eng/set-cmake-path.ps1 [deleted file]
global.json
src/Microsoft.Diagnostics.DebugServices.Implementation/CommandService.cs
src/Microsoft.Diagnostics.DebugServices.Implementation/ElfModule.cs [new file with mode: 0644]
src/Microsoft.Diagnostics.DebugServices.Implementation/ImageMappingMemoryService.cs
src/Microsoft.Diagnostics.DebugServices.Implementation/MachOModule.cs [new file with mode: 0644]
src/Microsoft.Diagnostics.DebugServices.Implementation/Module.cs
src/Microsoft.Diagnostics.DebugServices.Implementation/ModuleService.cs
src/Microsoft.Diagnostics.DebugServices.Implementation/ModuleServiceFromDataReader.cs
src/Microsoft.Diagnostics.DebugServices.Implementation/RuntimeService.cs
src/Microsoft.Diagnostics.DebugServices.Implementation/SymbolService.cs
src/Microsoft.Diagnostics.DebugServices.Implementation/Utilities.cs
src/Microsoft.Diagnostics.DebugServices/IConsoleService.cs
src/Microsoft.Diagnostics.DebugServices/IModule.cs
src/Microsoft.Diagnostics.DebugServices/ISymbolService.cs
src/Microsoft.Diagnostics.DebugServices/MemoryServiceExtensions.cs
src/Microsoft.Diagnostics.ExtensionCommands/ClrModulesCommand.cs
src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs [new file with mode: 0644]
src/Microsoft.Diagnostics.ExtensionCommands/Host/ModulesCommand.cs
src/Microsoft.Diagnostics.ExtensionCommands/Host/SetSymbolServerCommand.cs [new file with mode: 0644]
src/Microsoft.Diagnostics.Repl/ConsoleService.cs
src/Microsoft.Diagnostics.TestHelpers/TestHost/TestDataWriter.cs
src/Microsoft.Diagnostics.TestHelpers/TestHost/TestDump.cs
src/SOS/SOS.Extensions/ConsoleServiceFromDebuggerServices.cs
src/SOS/SOS.Extensions/DebuggerServices.cs
src/SOS/SOS.Extensions/HostServices.cs
src/SOS/SOS.Extensions/ModuleServiceFromDebuggerServices.cs
src/SOS/SOS.Hosting/Commands/SOSCommand.cs
src/SOS/SOS.Hosting/RuntimeWrapper.cs
src/SOS/SOS.Hosting/SOSHost.cs
src/SOS/SOS.Hosting/SymbolServiceWrapper.cs
src/SOS/SOS.UnitTests/Scripts/WebApp.script
src/SOS/Strike/ExpressionNode.cpp
src/SOS/Strike/dbgengservices.cpp
src/SOS/Strike/dbgengservices.h
src/SOS/Strike/disasm.cpp
src/SOS/Strike/disasm.h
src/SOS/Strike/disasmARM.cpp
src/SOS/Strike/disasmARM64.cpp
src/SOS/Strike/disasmX86.cpp
src/SOS/Strike/eeheap.cpp
src/SOS/Strike/gchist.cpp
src/SOS/Strike/gcroot.cpp
src/SOS/Strike/metadata.cpp
src/SOS/Strike/platform/runtimeimpl.cpp
src/SOS/Strike/platform/runtimeimpl.h
src/SOS/Strike/platform/targetimpl.cpp
src/SOS/Strike/sildasm.cpp
src/SOS/Strike/sos.cpp
src/SOS/Strike/sos.h
src/SOS/Strike/sos_md.h
src/SOS/Strike/sosdocs.txt
src/SOS/Strike/sosdocsunix.txt
src/SOS/Strike/stressLogDump.cpp
src/SOS/Strike/strike.cpp
src/SOS/Strike/strike.h
src/SOS/Strike/symbols.cpp
src/SOS/Strike/symbols.h
src/SOS/Strike/util.cpp
src/SOS/Strike/util.h
src/SOS/Strike/vm.cpp
src/SOS/extensions/config.h.in
src/SOS/extensions/configure.cmake
src/SOS/extensions/hostcoreclr.cpp
src/SOS/inc/debuggerservices.h
src/SOS/inc/symbolservice.h
src/SOS/lldbplugin/services.cpp
src/SOS/lldbplugin/services.h
src/SOS/lldbplugin/soscommand.cpp
src/Tools/dotnet-counters/CounterMonitor.cs
src/Tools/dotnet-counters/Exporters/ConsoleWriter.cs
src/Tools/dotnet-dump/Analyzer.cs
src/Tools/dotnet-stack/ReportCommand.cs
src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs
src/Tools/dotnet-trace/CommandLine/PrintReportHelper.cs
src/dbgshim/dbgshim.cpp
src/dbgshim/debugshim.cpp
src/dbgshim/pkg/Directory.Build.props
src/shared/dbgutil/dbgutil.cpp
src/shared/gcdump/gcinfodumper.cpp
src/shared/gcdump/i386/gcdumpx86.cpp
src/shared/minipal/getexepath.h [new file with mode: 0644]
src/shared/pal/src/include/pal/palinternal.h
src/shared/pal/src/misc/errorstrings.cpp
src/shared/pal/src/safecrt/input.inl
src/shared/pal/src/synchmgr/wait.cpp
src/shared/pal/src/thread/process.cpp
src/shared/utilcode/longfilepathwrappers.cpp
src/shared/utilcode/sstring.cpp
src/tests/DbgShim.UnitTests/DbgShimAPI.cs
src/tests/DbgShim.UnitTests/DbgShimTests.cs
src/tests/DbgShim.UnitTests/LibraryProviderWrapper.cs
src/tests/EventPipeStress/Orchestrator/Orchestrator.csproj
src/tests/EventPipeStress/Orchestrator/Program.cs
src/tests/EventPipeStress/Stress/Stress.csproj
src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/SymbolServiceTests.cs
src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/TestDbgEng.cs

diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
new file mode 100644 (file)
index 0000000..cc806a9
--- /dev/null
@@ -0,0 +1,12 @@
+# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.192.0/containers/dotnet/.devcontainer/base.Dockerfile
+# For specifics about the dotnet base container see: https://github.com/microsoft/vscode-dev-containers/tree/main/containers/dotnet
+
+# [Choice] .NET version: 6.0, 5.0, 3.1, 2.1
+ARG VARIANT="6.0-focal"
+FROM mcr.microsoft.com/vscode/devcontainers/dotnet:0-${VARIANT}
+
+# Set up machine requirements to build the repo
+RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
+    && apt-get -y install --no-install-recommends cmake clang \
+    curl gdb gettext git libicu-dev lldb liblldb-dev libunwind8 \
+    llvm make python python-lldb tar wget zip 
\ No newline at end of file
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644 (file)
index 0000000..cba68c3
--- /dev/null
@@ -0,0 +1,37 @@
+// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
+// https://github.com/microsoft/vscode-dev-containers/tree/v0.192.0/containers/dotnet
+{
+       "name": "C# (.NET)",
+       "build": {
+               "dockerfile": "Dockerfile",
+               "args": {
+                       // Update 'VARIANT' to pick a .NET Core version: 2.1, 3.1, 5.0, 6.0
+                       "VARIANT": "6.0-focal",
+               }
+       },
+
+       "settings": {
+               // Loading projects on demand is better for larger codebases
+               "omnisharp.enableMsBuildLoadProjectsOnDemand": true,
+               "omnisharp.enableRoslynAnalyzers": true,
+               "omnisharp.enableEditorConfigSupport": true,
+               "omnisharp.enableAsyncCompletion": true,
+       },
+
+       // Add the IDs of extensions you want installed when the container is created.
+       "extensions": [
+               "ms-dotnettools.csharp",
+               "ms-vscode.cpptools-extension-pack"
+       ],
+
+       // Add the locally installed dotnet to the path to ensure that it is activated
+       // This allows developers to just use 'dotnet build' on the command-line, and the local dotnet version will be used.
+       // Add the global tools dir to the PATH so that globally installed tools will work
+       "remoteEnv": {
+               "PATH": "${containerWorkspaceFolder}/.dotnet:${containerWorkspaceFolder}/.dotnet-tools-global:${containerEnv:PATH}",
+               "DOTNET_MULTILEVEL_LOOKUP": "0"
+       },
+
+       // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
+       "remoteUser": "vscode"
+}
index 35750237228aa2e7e6269a8f21edb0b9a091bc22..6c05f8d89c5dd955a89c622f168c7cf692ca47a4 100644 (file)
@@ -7,6 +7,7 @@
 *.sln.docstates
 .vs/
 *.VC.db
+.venv/
 
 # Build results
 [Aa]rtifacts/
@@ -22,6 +23,7 @@ x64/
 .packages/
 .tools/
 .vscode/
+build/
 
 # Per-user project properties
 launchSettings.json
index 11d13157ead614c631141ceefff968d235a5f32e..68ed20a98418c5c62ff48e8e3c7964c1bd557355 100644 (file)
@@ -7,10 +7,9 @@
     <clear />
     <!--Begin: Package sources managed by Dependency Flow automation. Do not edit the sources below.-->
     <!--  Begin: Package sources from dotnet-aspnetcore -->
-    <add key="darc-pub-dotnet-aspnetcore-14468ef" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-dotnet-aspnetcore-14468ef1/nuget/v3/index.json" />
+    <add key="darc-pub-dotnet-aspnetcore-fac970d" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-dotnet-aspnetcore-fac970de/nuget/v3/index.json" />
     <!--  End: Package sources from dotnet-aspnetcore -->
     <!--  Begin: Package sources from dotnet-runtime -->
-    <add key="darc-pub-dotnet-runtime-0bb27bd" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-dotnet-runtime-0bb27bd5/nuget/v3/index.json" />
     <!--  End: Package sources from dotnet-runtime -->
     <!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
     <!-- Feeds used in Maestro/Arcade publishing -->
diff --git a/documentation/EventPipeFormat.md b/documentation/EventPipeFormat.md
new file mode 100644 (file)
index 0000000..738b436
--- /dev/null
@@ -0,0 +1 @@
+Please see the [EventPipeFormat documentation in Perfview](https://github.com/Microsoft/perfview/blob/master/src/TraceEvent/EventPipe/EventPipeFormat.md)
index a21343b0f15e377025584741687ae745170f2988..42461707e414e170d0ea450580feed31b726df67 100644 (file)
@@ -13,6 +13,7 @@ This signs and publishes the following packages to the tools feed (https://pkgs.
  - dotnet-counters
  - dotnet-monitor
  - Microsoft.Diagnostics.NETCore.Client
+ - Microsoft.Diagnostics.DbgShim
 
 To release the latest tools:
 
index efb15082a6f131600d16fb421e52afd20aa48aee..b91043c5aecf3e9a02d900761abcf2f76539f888 100644 (file)
@@ -1,32 +1,13 @@
 Installing LLDB on Linux
 ========================
 
-These instructions will lead you through installing or building the best version of lldb for your distro to use with SOS. If you have already followed the diagnostics repo build [prerequisites](../building/linux-instructions.md) and built the diagnostics repo, then the best version of lldb is already installed.
+These instructions will lead you through installing or building the best version of lldb for your distro to use with SOS. 
 
-SOS needs at least lldb 3.9 or greater. Some distros only have older versions available by default so there are directions and scripts to build lldb 3.9 for that platform. These instructions assume that you have dotnet cli and its prerequisites installed.
+If you have already followed the diagnostics repo build [prerequisites](../building/linux-instructions.md) and built the diagnostics repo, then the best version of lldb is already installed.
 
-The libsosplugin.so built for lldb 3.9 does work with lldb 4.0 and greater but most of the testing has been on lldb 3.9. 
+You need lldb 3.9 or later to use SOS. Some distros only have older versions available by default so there are directions and scripts to build lldb 3.9 for that platform. These instructions assume that you have dotnet cli and its prerequisites installed.
 
-lldb 10.0 or greater is recommended if available for the distro version. For arm32, it is recommended to debug on Ubuntu 18.04 if possible with lldb 10.0 which is the only version of lldb found that works with SOS on arm32.
-
-#### Ubuntu 14.04 ####
-
-In order to get lldb-3.9, we need to add additional package sources (see [http://llvm.org/apt/](http://llvm.org/apt/) for the other Ubuntu versions not listed here):
-
-    sudo apt-get update
-    sudo apt-get install wget
-    echo "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty main" | sudo tee /etc/apt/sources.list.d/llvm.list
-    echo "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.9 main" | sudo tee -a /etc/apt/sources.list.d/llvm.list
-    wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
-    sudo apt-get update
-
-Install the lldb packages:
-
-    sudo apt-get install lldb-3.9 python-lldb-3.9
-
-To launch lldb:
-
-    lldb-3.9
+lldb 10.0 or later is best if your distro has that available. In particular if you are debugging for Arm32 you should use Ubuntu 18.04 or later if possible and lldb 10.0 or later.
 
 #### Ubuntu 16.04 ####
 
@@ -47,25 +28,6 @@ To launch lldb:
 
     lldb-3.9
 
-#### Ubuntu 17.10 ####
-
-Add the additional package sources:
-
-    sudo apt-get update
-    sudo apt-get install wget
-    echo "deb http://llvm.org/apt/artful/ llvm-toolchain-artful main" | sudo tee /etc/apt/sources.list.d/llvm.list
-    echo "deb http://llvm.org/apt/artful/ llvm-toolchain-artful-3.9 main" | sudo tee -a /etc/apt/sources.list.d/llvm.list
-    wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
-    sudo apt-get update
-
-Install the lldb packages:
-
-    sudo apt-get install lldb-3.9 python-lldb-3.9
-
-To launch lldb:
-
-    lldb-3.9
-
 #### Ubuntu 18.04 ####
 
 To install the lldb packages:
@@ -77,24 +39,23 @@ To launch lldb:
 
     lldb-3.9
 
-10.0 is the only version of lldb found that works with SOS for arm32 on Ubuntu 18.04.
+lldb 10.0 is the only version of lldb that works with SOS for Arm32 on Ubuntu 18.04.
 
-#### Ubuntu 20.04 ####
+#### Ubuntu 20.04 and later ####
 
 To install the lldb packages:
 
-    sudo get-get update
+    sudo apt-get update
     sudo apt-get install lldb
 
-This installs lldb version 10.0.0.
+This installs lldb version 10.0.
 
-#### Alpine 3.9 to 3.12 ####
+#### Alpine 3.9 and later ####
 
-lldb 10.0 is available and works for these Apline versions.
-
-#### CentOS 6 ####
-
-[TBD]
+    apk update
+    apk add lldb
+    
+This installs lldb version 10.0.
 
 #### CentOS 7 ####
 
@@ -122,27 +83,12 @@ This will take some time to complete. After the build is finished, run these com
 To launch lldb:
 
     lldb-3.9.1
+    
+#### Centos Stream 8 and later ####
 
-#### Debian 8.2/8.7 ####
-
-In order to get lldb-5.0 (3.9 doesn't seem to work that well), we need to add additional package sources:
-
-    sudo apt-get update
-    sudo apt-get install wget
-    echo "deb http://llvm.org/apt/jessie/ llvm-toolchain-jessie main" | sudo tee /etc/apt/sources.list.d/llvm.list
-    echo "deb http://llvm.org/apt/jessie/ llvm-toolchain-jessie-5.0 main" | sudo tee -a /etc/apt/sources.list.d/llvm.list
-    wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
-    sudo apt-get update
-
-Install the lldb packages:
-
-    sudo apt-get install lldb-5.0 python-lldb-5.0
-
-To launch lldb:
-
-    lldb-5.0
+[TBD]
 
-#### Debian 9 (Stretch) ####
+#### Debian 9 and later ####
 
     sudo apt-get install lldb-3.9 python-lldb-3.9
 
@@ -150,29 +96,7 @@ To launch lldb:
 
     lldb-3.9
 
-#### Fedora 24 ####
-
-    sudo dnf install clang cmake findutils git libicu libunwind make python tar wget which zip
-    sudo dnf install doxygen libedit-devel libxml2-devel python-argparse python-devel readline-devel swig xz
-
-Now build and install llvm/lldb 3.9 using the script provided here: [build-install-lldb.sh](../lldb/fedora24/build-install-lldb.sh).
-
-WARNING: This script installs llvm and lldb as root (via sudo) and may overwrite any previously installed versions.
-
-    cd $HOME
-    git clone https://github.com/dotnet/diagnostics.git
-    $HOME/diagnostics/documentation/lldb/fedora24/build-install-lldb.sh
-
-This will take some time to complete. After the build is finished, run these commands to remove the no longer needed packages:
-
-    sudo dnf remove doxygen libedit-devel libxml2-devel readline-devel swig
-    sudo dnf clean all
-
-To launch lldb:
-
-    lldb
-
-#### Fedora 27, 28, 29 ####
+#### Fedora 29 and later ####
 
     sudo dnf install lldb python2-lldb
 
@@ -204,7 +128,7 @@ To launch lldb:
 
 #### RHEL 7.5 ####
 
-See [LLDB](https://access.redhat.com/documentation/en-us/red_hat_developer_tools/2018.2/html/using_clang_and_llvm_toolset/chap-lldb) on RedHat's web site.
+See [LLDB](https://access.redhat.com/documentation/en-us/red_hat_developer_tools/1/html/using_llvm_12.0.1_toolset/assembly_llvm#proc_installing-comp-toolset_assembly_llvm) on RedHat's web site.
 
 #### SLES ####
 
index d9d5b46f79e1dc65aedff6de291257af94ac1380..d72b33f390b9b207777327dd5c04a8e5bccbe63b 100644 (file)
@@ -12,6 +12,11 @@ set __ThisScriptDir="%~dp0"
 call "%__ThisScriptDir%"\native\init-vs-env.cmd
 if NOT '%ERRORLEVEL%' == '0' goto ExitWithError
 
+if defined VS170COMNTOOLS (
+    set "__VSToolsRoot=%VS170COMNTOOLS%"
+    set "__VCToolsRoot=%VS170COMNTOOLS%\..\..\VC\Auxiliary\Build"
+    set __VSVersion=vs2022
+)
 if defined VS160COMNTOOLS (
     set "__VSToolsRoot=%VS160COMNTOOLS%"
     set "__VCToolsRoot=%VS160COMNTOOLS%\..\..\VC\Auxiliary\Build"
@@ -137,7 +142,7 @@ echo %__MsgPrefix%Commencing diagnostics repo build
 
 echo %__MsgPrefix%Checking prerequisites
 :: Eval the output from probe-win1.ps1
-for /f "delims=" %%a in ('powershell -NoProfile -ExecutionPolicy ByPass "& ""%__ProjectDir%\eng\set-cmake-path.ps1"""') do %%a
+for /f "delims=" %%a in ('powershell -NoProfile -ExecutionPolicy ByPass "& ""%__ProjectDir%\eng\native\set-cmake-path.ps1"""') do %%a
 
 REM =========================================================================================
 REM ===
@@ -148,11 +153,7 @@ REM ============================================================================
 @if defined _echo @echo on
 
 :: Parse the optdata package versions out of msbuild so that we can pass them on to CMake
-set __DotNetCli=%__ProjectDir%\.dotnet\dotnet.exe
-if not exist "%__DotNetCli%" (
-    echo %__MsgPrefix%Assertion failed: dotnet cli not found at path "%__DotNetCli%"
-    goto ExitWithError
-)
+set __DotNetCli=%__ProjectDir%\dotnet.cmd
 
 REM =========================================================================================
 REM ===
@@ -198,7 +199,7 @@ if /i %__BuildCrossArch% EQU 1 (
     popd
 
 :SkipConfigureCrossBuild
-    if not exist "%__CrossCompIntermediatesDir%\install.vcxproj" (
+    if not exist "%__CrossCompIntermediatesDir%\CMakeCache.txt" (
         echo %__MsgPrefix%Error: failed to generate cross-arch components build project!
         goto ExitWithError
     )
@@ -206,8 +207,8 @@ if /i %__BuildCrossArch% EQU 1 (
 
     set __BuildLog="%__LogDir%\Cross.Build.binlog"
 
-    :: MSBuild.exe is the only one that has the C++ targets. "%__DotNetCli% msbuild" fails because VCTargetsPath isn't defined.
-    msbuild.exe %__CrossCompIntermediatesDir%\install.vcxproj /bl:!__BuildLog! %__CommonBuildArgs%
+    echo running "%CMakePath%" --build %__CrossCompIntermediatesDir% --target install --config %__BuildType% -- /bl:!__BuildLog! !__CommonBuildArgs!
+    "%CMakePath%" --build %__CrossCompIntermediatesDir% --target install --config %__BuildType% -- /bl:!__BuildLog! !__CommonBuildArgs!
 
     if not !ERRORLEVEL! == 0 (
         echo %__MsgPrefix%Error: cross-arch components build failed. Refer to the build log files for details:
@@ -273,14 +274,14 @@ if %__Build% EQU 1 (
 :SkipConfigure
     if defined __ConfigureOnly goto SkipNativeBuild
 
-    if not exist "%__IntermediatesDir%\install.vcxproj" (
+    if not exist "%__IntermediatesDir%\CMakeCache.txt" (
         echo %__MsgPrefix%Error: failed to generate native component build project!
         goto ExitWithError
     )
     set __BuildLog="%__LogDir%\Native.Build.binlog"
 
-    :: MSBuild.exe is the only one that has the C++ targets. "%__DotNetCli% msbuild" fails because VCTargetsPath isn't defined.
-    msbuild.exe %__IntermediatesDir%\install.vcxproj /bl:!__BuildLog! %__CommonBuildArgs%
+    echo running "%CMakePath%" --build %__IntermediatesDir% --target install --config %__BuildType% -- /bl:!__BuildLog! !__CommonBuildArgs!
+    "%CMakePath%" --build %__IntermediatesDir% --target install --config %__BuildType% -- /bl:!__BuildLog! !__CommonBuildArgs!
 
     if not !ERRORLEVEL! == 0 (
         echo %__MsgPrefix%Error: native component build failed. Refer to the build log files for details:
index 6713e2ecfa35d95e1359f0c76e513b07332201e9..07d6ba866a50563cd9a3d8f086586533a24e15f2 100644 (file)
@@ -1,52 +1,52 @@
 <Dependencies>
   <ProductDependencies>
-    <Dependency Name="Microsoft.SymbolStore" Version="1.0.320401">
+    <Dependency Name="Microsoft.SymbolStore" Version="1.0.326601">
       <Uri>https://github.com/dotnet/symstore</Uri>
-      <Sha>aebde3c78a70fbbc067a059a98f27f7c4d0abbd5</Sha>
+      <Sha>073abc4f492cbc6795989e4a813b0d32017a8623</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.Diagnostics.Runtime" Version="2.0.317902">
+    <Dependency Name="Microsoft.Diagnostics.Runtime" Version="2.0.325901">
       <Uri>https://github.com/microsoft/clrmd</Uri>
-      <Sha>5444e45c321f681bdd6b5fbfb4d2115de19c39a2</Sha>
+      <Sha>a64d9ac11086f28fbd4b2b2337c19be7826fbfa9</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.Diagnostics.Runtime.Utilities" Version="2.0.317902">
+    <Dependency Name="Microsoft.Diagnostics.Runtime.Utilities" Version="2.0.325901">
       <Uri>https://github.com/microsoft/clrmd</Uri>
-      <Sha>5444e45c321f681bdd6b5fbfb4d2115de19c39a2</Sha>
+      <Sha>a64d9ac11086f28fbd4b2b2337c19be7826fbfa9</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.SourceBuild.Intermediate.source-build-reference-packages" Version="7.0.0-alpha.1.22173.1">
+    <Dependency Name="Microsoft.SourceBuild.Intermediate.source-build-reference-packages" Version="7.0.0-alpha.1.22261.1">
       <Uri>https://github.com/dotnet/source-build-reference-packages</Uri>
-      <Sha>e7f2964ac4a556d2ba99a185f52aa93dcbba4f7e</Sha>
+      <Sha>c71ce108eda9f657c9f58a613a1fe56b6b08235d</Sha>
       <SourceBuild RepoName="source-build-reference-packages" ManagedOnly="true" />
     </Dependency>
   </ProductDependencies>
   <ToolsetDependencies>
-    <Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="7.0.0-beta.22181.2">
+    <Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="7.0.0-beta.22269.3">
       <Uri>https://github.com/dotnet/arcade</Uri>
-      <Sha>e0b311bcd81fc9e27bcf7715dcda62fa38dfa49a</Sha>
+      <Sha>0403b0d07aff1b103256cfbe082c97a5c8846d20</Sha>
       <SourceBuild RepoName="arcade" ManagedOnly="true" />
     </Dependency>
-    <Dependency Name="Microsoft.DotNet.RemoteExecutor" Version="7.0.0-beta.22181.2">
+    <Dependency Name="Microsoft.DotNet.RemoteExecutor" Version="7.0.0-beta.22269.3">
       <Uri>https://github.com/dotnet/arcade</Uri>
-      <Sha>e0b311bcd81fc9e27bcf7715dcda62fa38dfa49a</Sha>
+      <Sha>0403b0d07aff1b103256cfbe082c97a5c8846d20</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.Dotnet.Sdk.Internal" Version="6.0.104-servicing.22181.15">
+    <Dependency Name="Microsoft.Dotnet.Sdk.Internal" Version="6.0.106-servicing.22263.13">
       <Uri>https://github.com/dotnet/installer</Uri>
-      <Sha>f6e3766b7adfac2863e91ba6453912d24d0fbd9e</Sha>
+      <Sha>ee1b7085a6eb99c97851ed67fc3fd52b8bda3ba0</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.AspNetCore.App.Ref.Internal" Version="6.0.5-servicing.22205.16">
+    <Dependency Name="Microsoft.AspNetCore.App.Ref.Internal" Version="6.0.6-servicing.22262.8">
       <Uri>https://github.com/dotnet/aspnetcore</Uri>
-      <Sha>14468ef10b172da67df3e452ade3d7e0f7e256ca</Sha>
+      <Sha>fac970ded3047f63328ff56f59a874bcabf18126</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.AspNetCore.App.Ref" Version="6.0.5">
+    <Dependency Name="Microsoft.AspNetCore.App.Ref" Version="6.0.6">
       <Uri>https://github.com/dotnet/aspnetcore</Uri>
-      <Sha>14468ef10b172da67df3e452ade3d7e0f7e256ca</Sha>
+      <Sha>fac970ded3047f63328ff56f59a874bcabf18126</Sha>
     </Dependency>
     <Dependency Name="Microsoft.NETCore.App.Runtime.win-x64" Version="6.0.5">
       <Uri>https://github.com/dotnet/runtime</Uri>
-      <Sha>0bb27bd5aa461aea3d8a0ab58c6cb1369534f8f6</Sha>
+      <Sha>a21b9a2dd4c31cf5bd37626562b7612faf21cee6</Sha>
     </Dependency>
-    <Dependency Name="VS.Redist.Common.NetCore.SharedFramework.x64.6.0" Version="6.0.5-servicing.22205.8">
+    <Dependency Name="VS.Redist.Common.NetCore.SharedFramework.x64.6.0" Version="6.0.5-servicing.22213.11">
       <Uri>https://github.com/dotnet/runtime</Uri>
-      <Sha>0bb27bd5aa461aea3d8a0ab58c6cb1369534f8f6</Sha>
+      <Sha>a21b9a2dd4c31cf5bd37626562b7612faf21cee6</Sha>
     </Dependency>
   </ToolsetDependencies>
 </Dependencies>
index 50833274dcb2743fd035b950842a37028ba138ac..08c1bc22e91b989dcf8163aec000f57dcd6c2fa9 100644 (file)
   </PropertyGroup>
   <PropertyGroup>
     <!-- The SDK runtime version used to build single-file apps (currently hardcoded) -->
-    <SingleFileRuntimeVersion>6.0.3</SingleFileRuntimeVersion>
+    <SingleFileRuntimeVersion>6.0.5</SingleFileRuntimeVersion>
     <!-- Latest symstore version updated by darc -->
-    <MicrosoftSymbolStoreVersion>1.0.320401</MicrosoftSymbolStoreVersion>
+    <MicrosoftSymbolStoreVersion>1.0.326601</MicrosoftSymbolStoreVersion>
     <!-- Runtime versions to test -->
     <MicrosoftNETCoreApp31Version>3.1.18</MicrosoftNETCoreApp31Version>
     <MicrosoftAspNetCoreApp31Version>$(MicrosoftNETCoreApp31Version)</MicrosoftAspNetCoreApp31Version>
     <MicrosoftNETCoreApp50Version>5.0.9</MicrosoftNETCoreApp50Version>
     <MicrosoftAspNetCoreApp50Version>$(MicrosoftNETCoreApp50Version)</MicrosoftAspNetCoreApp50Version>
     <!-- Latest shared runtime version updated by darc -->
-    <VSRedistCommonNetCoreSharedFrameworkx6460Version>6.0.5-servicing.22205.8</VSRedistCommonNetCoreSharedFrameworkx6460Version>
+    <VSRedistCommonNetCoreSharedFrameworkx6460Version>6.0.5-servicing.22213.11</VSRedistCommonNetCoreSharedFrameworkx6460Version>
     <MicrosoftNETCoreAppRuntimewinx64Version>6.0.5</MicrosoftNETCoreAppRuntimewinx64Version>
     <!-- Latest shared aspnetcore version updated by darc -->
-    <MicrosoftAspNetCoreAppRefInternalVersion>6.0.5-servicing.22205.16</MicrosoftAspNetCoreAppRefInternalVersion>
-    <MicrosoftAspNetCoreAppRefVersion>6.0.5</MicrosoftAspNetCoreAppRefVersion>
+    <MicrosoftAspNetCoreAppRefInternalVersion>6.0.6-servicing.22262.8</MicrosoftAspNetCoreAppRefInternalVersion>
+    <MicrosoftAspNetCoreAppRefVersion>6.0.6</MicrosoftAspNetCoreAppRefVersion>
     <!-- dotnet/installer: Testing version of the SDK. Needed for the signed & entitled host. -->
-    <MicrosoftDotnetSdkInternalVersion>6.0.104-servicing.22181.15</MicrosoftDotnetSdkInternalVersion>
+    <MicrosoftDotnetSdkInternalVersion>6.0.106-servicing.22263.13</MicrosoftDotnetSdkInternalVersion>
   </PropertyGroup>
   <PropertyGroup>
     <!-- Opt-in/out repo features -->
@@ -44,8 +44,8 @@
     <MicrosoftWin32PrimitivesVersion>4.3.0</MicrosoftWin32PrimitivesVersion>
     <!-- Other libs -->
     <MicrosoftBclAsyncInterfacesVersion>1.1.0</MicrosoftBclAsyncInterfacesVersion>
-    <MicrosoftDiagnosticsRuntimeVersion>2.0.317902</MicrosoftDiagnosticsRuntimeVersion>
-    <MicrosoftDiagnosticsRuntimeUtilitiesVersion>2.0.317902</MicrosoftDiagnosticsRuntimeUtilitiesVersion>
+    <MicrosoftDiagnosticsRuntimeVersion>2.0.325901</MicrosoftDiagnosticsRuntimeVersion>
+    <MicrosoftDiagnosticsRuntimeUtilitiesVersion>2.0.325901</MicrosoftDiagnosticsRuntimeUtilitiesVersion>
     <MicrosoftDiaSymReaderNativePackageVersion>16.9.0-beta1.21055.5</MicrosoftDiaSymReaderNativePackageVersion>
     <MicrosoftDiagnosticsTracingTraceEventVersion>2.0.64</MicrosoftDiagnosticsTracingTraceEventVersion>
     <MicrosoftExtensionsLoggingVersion>2.1.1</MicrosoftExtensionsLoggingVersion>
@@ -58,7 +58,7 @@
     <SystemTextEncodingsWebVersion>4.7.2</SystemTextEncodingsWebVersion>
     <SystemTextJsonVersion>4.7.1</SystemTextJsonVersion>
     <XUnitAbstractionsVersion>2.0.3</XUnitAbstractionsVersion>
-    <MicrosoftDotNetRemoteExecutorVersion>7.0.0-beta.22181.2</MicrosoftDotNetRemoteExecutorVersion>
+    <MicrosoftDotNetRemoteExecutorVersion>7.0.0-beta.22269.3</MicrosoftDotNetRemoteExecutorVersion>
     <cdbsosversion>10.0.18362</cdbsosversion>
     <NewtonSoftJsonVersion>12.0.2</NewtonSoftJsonVersion>
   </PropertyGroup>
index 61824484c1741141a7fb903dbe39d6a387013204..654ab0c0f594a6b66d5743278a595a1f7020b2ab 100755 (executable)
@@ -218,6 +218,11 @@ if [[ "$__NativeBuild" == 1 ]]; then
     fi
 
     build_native "$__TargetOS" "$__BuildArch" "$__RepoRootDir" "$__IntermediatesDir" "install" "$__ExtraCmakeArgs" "diagnostic component" | tee "$__LogsDir"/make.log
+
+    if [ "$?" != 0 ]; then
+        echo "Native build FAILED"
+        exit 1
+    fi
 fi
 
 #
index e784c9c005a2a19a8d4e1cd3f5accb2db46d18f5..5a59dcff28fb350b9b0d37ab848a20d2479d397a 100644 (file)
@@ -4,12 +4,13 @@ set -e
 
 usage()
 {
-    echo "Usage: $0 [BuildArch] [CodeName] [lldbx.y] [--skipunmount] --rootfsdir <directory>]"
+    echo "Usage: $0 [BuildArch] [CodeName] [lldbx.y] [llvmx[.y]] [--skipunmount] --rootfsdir <directory>]"
     echo "BuildArch can be: arm(default), armel, arm64, x86"
     echo "CodeName - optional, Code name for Linux, can be: xenial(default), zesty, bionic, alpine, alpine3.13 or alpine3.14. If BuildArch is armel, LinuxCodeName is jessie(default) or tizen."
     echo "                              for FreeBSD can be: freebsd12, freebsd13"
     echo "                              for illumos can be: illumos."
     echo "lldbx.y - optional, LLDB version, can be: lldb3.9(default), lldb4.0, lldb5.0, lldb6.0 no-lldb. Ignored for alpine and FreeBSD"
+    echo "llvmx[.y] - optional, LLVM version for LLVM related packages."
     echo "--skipunmount - optional, will skip the unmount of rootfs folder."
     echo "--use-mirror - optional, use mirror URL to fetch resources, when available."
     exit 1
@@ -48,6 +49,7 @@ __AlpinePackages+=" gettext-dev"
 __AlpinePackages+=" icu-dev"
 __AlpinePackages+=" libunwind-dev"
 __AlpinePackages+=" lttng-ust-dev"
+__AlpinePackages+=" compiler-rt-static"
 
 # CoreFX dependencies
 __UbuntuPackages+=" libcurl4-openssl-dev"
@@ -164,6 +166,15 @@ while :; do
         no-lldb)
             unset __LLDB_Package
             ;;
+        llvm*)
+            version="$(echo "$lowerI" | tr -d '[:alpha:]-=')"
+            parts=(${version//./ })
+            __LLVM_MajorVersion="${parts[0]}"
+            __LLVM_MinorVersion="${parts[1]}"
+            if [[ -z "$__LLVM_MinorVersion" && "$__LLVM_MajorVersion" -le 6 ]]; then
+                __LLVM_MinorVersion=0;
+            fi
+            ;;
         xenial) # Ubuntu 16.04
             if [ "$__CodeName" != "jessie" ]; then
                 __CodeName=xenial
@@ -261,6 +272,10 @@ if [ "$__BuildArch" == "armel" ]; then
 fi
 __UbuntuPackages+=" ${__LLDB_Package:-}"
 
+if [ ! -z "$__LLVM_MajorVersion" ]; then
+    __UbuntuPackages+=" libclang-common-${__LLVM_MajorVersion}${__LLVM_MinorVersion:+.$__LLVM_MinorVersion}-dev"
+fi
+
 if [ -z "$__RootfsDir" ] && [ ! -z "$ROOTFS_DIR" ]; then
     __RootfsDir=$ROOTFS_DIR
 fi
index 5c94e98632a0a7cc6710883fde275e625f909717..abd045a3247f0260ecaa49f8537524290d89b7d9 100755 (executable)
@@ -52,7 +52,7 @@ done
 # Use uname to determine what the CPU is, see https://en.wikipedia.org/wiki/Uname#Examples
 cpuname=$(uname -m)
 case $cpuname in
-  aarch64)
+  arm64|aarch64)
     buildarch=arm64
     ;;
   loongarch64)
@@ -64,7 +64,7 @@ case $cpuname in
   armv*l)
     buildarch=arm
     ;;
-  i686)
+  i[3-6]86)
     buildarch=x86
     ;;
   *)
index db830c00a6f8d895705454c3507171b2f0f94705..24a5e65de1b3e38d4489a7dd3b6933c9bb426fe1 100644 (file)
@@ -31,6 +31,10 @@ Wait time between retry attempts in seconds
 .PARAMETER GlobalJsonFile
 File path to global.json file
 
+.PARAMETER PathPromotion
+Optional switch to enable either promote native tools specified in the global.json to the path (in Azure Pipelines)
+or break the build if a native tool is not found on the path (on a local dev machine)
+
 .NOTES
 #>
 [CmdletBinding(PositionalBinding=$false)]
@@ -41,7 +45,8 @@ Param (
   [switch] $Force = $False,
   [int] $DownloadRetries = 5,
   [int] $RetryWaitTimeInSeconds = 30,
-  [string] $GlobalJsonFile
+  [string] $GlobalJsonFile,
+  [switch] $PathPromotion
 )
 
 if (!$GlobalJsonFile) {
@@ -77,53 +82,98 @@ try {
                     ConvertFrom-Json |
                     Select-Object -Expand 'native-tools' -ErrorAction SilentlyContinue
   if ($NativeTools) {
-    $NativeTools.PSObject.Properties | ForEach-Object {
-      $ToolName = $_.Name
-      $ToolVersion = $_.Value
-      $LocalInstallerArguments =  @{ ToolName = "$ToolName" }
-      $LocalInstallerArguments += @{ InstallPath = "$InstallBin" }
-      $LocalInstallerArguments += @{ BaseUri = "$BaseUri" }
-      $LocalInstallerArguments += @{ CommonLibraryDirectory = "$EngCommonBaseDir" }
-      $LocalInstallerArguments += @{ Version = "$ToolVersion" }
-
-      if ($Verbose) {
-        $LocalInstallerArguments += @{ Verbose = $True }
-      }
-      if (Get-Variable 'Force' -ErrorAction 'SilentlyContinue') {
-        if($Force) {
-          $LocalInstallerArguments += @{ Force = $True }
-        }
-      }
-      if ($Clean) {
-        $LocalInstallerArguments += @{ Clean = $True }
-      }
-
-      Write-Verbose "Installing $ToolName version $ToolVersion"
-      Write-Verbose "Executing '$InstallerPath $($LocalInstallerArguments.Keys.ForEach({"-$_ '$($LocalInstallerArguments.$_)'"}) -join ' ')'"
-      & $InstallerPath @LocalInstallerArguments
-      if ($LASTEXITCODE -Ne "0") {
-        $errMsg = "$ToolName installation failed"
-        if ((Get-Variable 'DoNotAbortNativeToolsInstallationOnFailure' -ErrorAction 'SilentlyContinue') -and $DoNotAbortNativeToolsInstallationOnFailure) {
-            $showNativeToolsWarning = $true
-            if ((Get-Variable 'DoNotDisplayNativeToolsInstallationWarnings' -ErrorAction 'SilentlyContinue') -and $DoNotDisplayNativeToolsInstallationWarnings) {
-                $showNativeToolsWarning = $false
+    if ($PathPromotion -eq $True) {
+      if ($env:SYSTEM_TEAMPROJECT) { # check to see if we're in an Azure pipelines build
+        $NativeTools.PSObject.Properties | ForEach-Object {
+          $ToolName = $_.Name
+          $ToolVersion = $_.Value
+
+          if ((Get-Command "$ToolName" -ErrorAction SilentlyContinue) -eq $null) {
+            if ($ToolVersion -eq "latest") {
+              $ToolVersion = ""
+            }
+            $ArcadeToolsDirectory = "C:\arcade-tools"
+            if (-not (Test-Path $ArcadeToolsDirectory)) {
+              Write-Error "Arcade tools directory '$ArcadeToolsDirectory' was not found; artifacts were not properly installed."
+              exit 1
             }
-            if ($showNativeToolsWarning) {
-                Write-Warning $errMsg
+            $ToolDirectory = (Get-ChildItem -Path "$ArcadeToolsDirectory" -Filter "$ToolName-$ToolVersion*" | Sort-Object -Descending)[0]
+            if ([string]::IsNullOrWhiteSpace($ToolDirectory)) {
+              Write-Error "Unable to find directory for $ToolName $ToolVersion; please make sure the tool is installed on this image."
+              exit 1
             }
-            $toolInstallationFailure = $true
-        } else {
-            # We cannot change this to Write-PipelineTelemetryError because of https://github.com/dotnet/arcade/issues/4482
-            Write-Host $errMsg
-            exit 1
+            $BinPathFile = "$($ToolDirectory.FullName)\binpath.txt"
+            if (-not (Test-Path -Path "$BinPathFile")) {
+              Write-Error "Unable to find binpath.txt in '$($ToolDirectory.FullName)' ($ToolName $ToolVersion); artifact is either installed incorrectly or is not a bootstrappable tool."
+              exit 1
+            }
+            $BinPath = Get-Content "$BinPathFile"
+            $ToolPath = Convert-Path -Path $BinPath
+            Write-Host "Adding $ToolName to the path ($ToolPath)..."
+            Write-Host "##vso[task.prependpath]$ToolPath"
+          }
+        }
+        exit 0
+      } else {
+        $NativeTools.PSObject.Properties | ForEach-Object {
+          $ToolName = $_.Name
+          $ToolVersion = $_.Value
+
+          if ((Get-Command "$ToolName" -ErrorAction SilentlyContinue) -eq $null) {
+            Write-PipelineTelemetryError -Category 'NativeToolsBootstrap' -Message "$ToolName not found on path. Please install $ToolName $ToolVersion before proceeding."
+          }
         }
+        exit 0
+      }
+    } else {
+      $NativeTools.PSObject.Properties | ForEach-Object {
+        $ToolName = $_.Name
+        $ToolVersion = $_.Value
+        $LocalInstallerArguments =  @{ ToolName = "$ToolName" }
+        $LocalInstallerArguments += @{ InstallPath = "$InstallBin" }
+        $LocalInstallerArguments += @{ BaseUri = "$BaseUri" }
+        $LocalInstallerArguments += @{ CommonLibraryDirectory = "$EngCommonBaseDir" }
+        $LocalInstallerArguments += @{ Version = "$ToolVersion" }
+  
+        if ($Verbose) {
+          $LocalInstallerArguments += @{ Verbose = $True }
+        }
+        if (Get-Variable 'Force' -ErrorAction 'SilentlyContinue') {
+          if($Force) {
+            $LocalInstallerArguments += @{ Force = $True }
+          }
+        }
+        if ($Clean) {
+          $LocalInstallerArguments += @{ Clean = $True }
+        }
+  
+        Write-Verbose "Installing $ToolName version $ToolVersion"
+        Write-Verbose "Executing '$InstallerPath $($LocalInstallerArguments.Keys.ForEach({"-$_ '$($LocalInstallerArguments.$_)'"}) -join ' ')'"
+        & $InstallerPath @LocalInstallerArguments
+        if ($LASTEXITCODE -Ne "0") {
+          $errMsg = "$ToolName installation failed"
+          if ((Get-Variable 'DoNotAbortNativeToolsInstallationOnFailure' -ErrorAction 'SilentlyContinue') -and $DoNotAbortNativeToolsInstallationOnFailure) {
+              $showNativeToolsWarning = $true
+              if ((Get-Variable 'DoNotDisplayNativeToolsInstallationWarnings' -ErrorAction 'SilentlyContinue') -and $DoNotDisplayNativeToolsInstallationWarnings) {
+                  $showNativeToolsWarning = $false
+              }
+              if ($showNativeToolsWarning) {
+                  Write-Warning $errMsg
+              }
+              $toolInstallationFailure = $true
+          } else {
+              # We cannot change this to Write-PipelineTelemetryError because of https://github.com/dotnet/arcade/issues/4482
+              Write-Host $errMsg
+              exit 1
+          }
+        }
+      }
+  
+      if ((Get-Variable 'toolInstallationFailure' -ErrorAction 'SilentlyContinue') -and $toolInstallationFailure) {
+          # We cannot change this to Write-PipelineTelemetryError because of https://github.com/dotnet/arcade/issues/4482
+          Write-Host 'Native tools bootstrap failed'
+          exit 1
       }
-    }
-
-    if ((Get-Variable 'toolInstallationFailure' -ErrorAction 'SilentlyContinue') -and $toolInstallationFailure) {
-        # We cannot change this to Write-PipelineTelemetryError because of https://github.com/dotnet/arcade/issues/4482
-        Write-Host 'Native tools bootstrap failed'
-        exit 1
     }
   }
   else {
@@ -139,7 +189,7 @@ try {
     Write-Host "##vso[task.prependpath]$(Convert-Path -Path $InstallBin)"
     return $InstallBin
   }
-  else {
+  elseif (-not ($PathPromotion)) {
     Write-PipelineTelemetryError -Category 'NativeToolsBootstrap' -Message 'Native tools install directory does not exist, installation failed'
     exit 1
   }
index beb9c4648ea19ac938f01628cd549eb3ace8635b..7f5ce6d608133851c2a69a897cb88d0099e1b29a 100644 (file)
@@ -8,6 +8,9 @@
   <ItemGroup>
     <!-- Clear references, the SDK may add some depending on UsuingToolXxx settings, but we only want to restore the following -->
     <PackageReference Remove="@(PackageReference)"/>
+    <PackageReference Include="Microsoft.ManifestTool.CrossPlatform" Version="$(MicrosoftManifestToolCrossPlatformVersion)" />
+    <PackageReference Include="Microsoft.VisualStudioEng.MicroBuild.Core" Version="$(MicrosoftVisualStudioEngMicroBuildCoreVersion)" />
+    <PackageReference Include="Microsoft.VisualStudioEng.MicroBuild.Plugins.SwixBuild" Version="$(MicrosoftVisualStudioEngMicroBuildPluginsSwixBuildVersion)" />
     <PackageReference Include="Microsoft.DotNet.IBCMerge" Version="$(MicrosoftDotNetIBCMergeVersion)" Condition="'$(UsingToolIbcOptimization)' == 'true'" />
     <PackageReference Include="Drop.App" Version="$(DropAppVersion)" ExcludeAssets="all" Condition="'$(UsingToolVisualStudioIbcTraining)' == 'true'"/>
   </ItemGroup>
index b1bca63ab1d82c4025c2ed3b04fa4397728326f5..119a6c660d1a4d4ad203f35bee2b709c8532e5a0 100644 (file)
@@ -64,7 +64,7 @@ try {
       $GlobalJson.tools | Add-Member -Name "vs" -Value (ConvertFrom-Json "{ `"version`": `"16.5`" }") -MemberType NoteProperty
     }
     if( -not ($GlobalJson.tools.PSObject.Properties.Name -match "xcopy-msbuild" )) {
-      $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "16.10.0-preview2" -MemberType NoteProperty
+      $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "17.1.0" -MemberType NoteProperty
     }
     if ($GlobalJson.tools."xcopy-msbuild".Trim() -ine "none") {
         $xcopyMSBuildToolsFolder = InitializeXCopyMSBuild $GlobalJson.tools."xcopy-msbuild" -install $true
index 9d1e3042d8a6c05ad0691774d2551a37e78482a8..3bcd243c46b6781bd26b6dc66deba6df5016bf7e 100644 (file)
@@ -72,8 +72,8 @@ jobs:
         lclSource: ${{ parameters.LclSource }}
         lclPackageId: ${{ parameters.LclPackageId }}
         isCreatePrSelected: ${{ parameters.CreatePr }}
+        isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }}
         ${{ if eq(parameters.CreatePr, true) }}:
-          isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }}
           isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }}
           ${{ if eq(parameters.RepoType, 'gitHub') }}:
             isShouldReusePrSelected: ${{ parameters.ReusePr }}
index d91bf9147116f0aa68c98ccd94234e87ea43cc3d..1cbb6a0c560038cff5b0cea75096d09ed9d77cb8 100644 (file)
@@ -23,23 +23,33 @@ parameters:
   # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing
   publishUsingPipelines: false
 
+  # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing
+  publishAssetsImmediately: false
+
+  artifactsPublishingAdditionalParameters: ''
+
+  signingValidationAdditionalParameters: ''
+
 jobs:
 - job: Asset_Registry_Publish
 
   dependsOn: ${{ parameters.dependsOn }}
 
-  displayName: Publish to Build Asset Registry
+  ${{ if eq(parameters.publishAssetsImmediately, 'true') }}:
+    displayName: Publish Assets
+  ${{ else }}:
+    displayName: Publish to Build Asset Registry
 
   pool: ${{ parameters.pool }}
 
   variables:
   - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
-    - name: _BuildConfig
-      value: ${{ parameters.configuration }}
     - group: Publish-Build-Assets
     - group: AzureDevOps-Artifact-Feeds-Pats
     - name: runCodesignValidationInjection
       value: false
+    - ${{ if eq(parameters.publishAssetsImmediately, 'true') }}:
+      - template: /eng/common/templates/post-build/common-variables.yml
 
   steps:
   - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
@@ -52,14 +62,13 @@ jobs:
       condition: ${{ parameters.condition }}
       continueOnError: ${{ parameters.continueOnError }}
     
-    - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
-      - task: NuGetAuthenticate@0
+    - task: NuGetAuthenticate@0
 
-      - task: PowerShell@2 
-        displayName: Enable cross-org NuGet feed authentication 
-        inputs: 
-          filePath: $(Build.SourcesDirectory)/eng/common/enable-cross-org-publishing.ps1 
-          arguments: -token $(dn-bot-all-orgs-artifact-feeds-rw) 
+    - task: PowerShell@2 
+      displayName: Enable cross-org NuGet feed authentication 
+      inputs: 
+        filePath: $(Build.SourcesDirectory)/eng/common/enable-cross-org-publishing.ps1 
+        arguments: -token $(dn-bot-all-orgs-artifact-feeds-rw) 
 
     - task: PowerShell@2
       displayName: Publish Build Assets
@@ -70,7 +79,6 @@ jobs:
           /p:BuildAssetRegistryToken=$(MaestroAccessToken)
           /p:MaestroApiEndpoint=https://maestro-prod.westus2.cloudapp.azure.com
           /p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }}
-          /p:Configuration=$(_BuildConfig)
           /p:OfficialBuildId=$(Build.BuildNumber)
       condition: ${{ parameters.condition }}
       continueOnError: ${{ parameters.continueOnError }}
@@ -114,7 +122,25 @@ jobs:
         PathtoPublish: '$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt'
         PublishLocation: Container
         ArtifactName: ReleaseConfigs
-        
+
+    - ${{ if eq(parameters.publishAssetsImmediately, 'true') }}:
+      - template: /eng/common/templates/post-build/setup-maestro-vars.yml
+        parameters:
+          BARBuildId: ${{ parameters.BARBuildId }}
+          PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+      - task: PowerShell@2
+        displayName: Publish Using Darc
+        inputs:
+          filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
+          arguments: -BuildId $(BARBuildId) 
+            -PublishingInfraVersion 3
+            -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
+            -MaestroToken '$(MaestroApiAccessToken)'
+            -WaitPublishingFinish true
+            -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'
+            -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'
+
     - ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}:
       - template: /eng/common/templates/steps/publish-logs.yml
         parameters:
index 4af724eb1a9ec9691b824796619f67822fbae2b2..c2d51098d35cb199923dbeba7a9c9612da694232 100644 (file)
@@ -7,6 +7,7 @@ parameters:
   binlogPath: artifacts/log/Debug/Build.binlog
   condition: ''
   dependsOn: ''
+  pool: ''
 
 jobs:
 - job: SourceIndexStage1
@@ -22,13 +23,17 @@ jobs:
   - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
     - group: source-dot-net stage1 variables
 
-  pool:
-    ${{ if eq(variables['System.TeamProject'], 'public') }}:
-      name: NetCore1ESPool-Public
-      demands: ImageOverride -equals Build.Server.Amd64.VS2019.Open
-    ${{ if eq(variables['System.TeamProject'], 'internal') }}:
-      name: NetCore1ESPool-Internal
-      demands: ImageOverride -equals Build.Server.Amd64.VS2019
+  ${{ if ne(parameters.pool, '') }}:
+    pool: ${{ parameters.pool }}
+  ${{ if eq(parameters.pool, '') }}:
+    pool:
+      ${{ if eq(variables['System.TeamProject'], 'public') }}:
+        name: NetCore1ESPool-Public
+        demands: ImageOverride -equals Build.Server.Amd64.VS2019.Open
+      ${{ if eq(variables['System.TeamProject'], 'internal') }}:
+        name: NetCore1ESPool-Internal
+        demands: ImageOverride -equals Build.Server.Amd64.VS2019
+
   steps:
   - ${{ each preStep in parameters.preSteps }}:
     - ${{ preStep }}
index 554e71cfc436dd5889ffae0631aeb213080c5a96..2cca53c2d1d53142094eae60be5d3ae7fff2acb0 100644 (file)
@@ -27,6 +27,13 @@ parameters:
   # Optional: Override automatically derived dependsOn value for "publish build assets" job
   publishBuildAssetsDependsOn: ''
 
+  # Optional: Publish the assets as soon as the publish to BAR stage is complete, rather doing so in a separate stage.
+  publishAssetsImmediately: false
+
+  # Optional: If using publishAssetsImmediately and additional parameters are needed, can be used to send along additional parameters (normally sent to post-build.yml)
+  artifactsPublishingAdditionalParameters: ''
+  signingValidationAdditionalParameters: ''
+
   # Optional: should run as a public build even in the internal project
   #           if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects.
   runAsPublic: false
@@ -68,7 +75,6 @@ jobs:
         ${{ parameter.key }}: ${{ parameter.value }}
 
 - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
-  
   - ${{ if or(eq(parameters.enablePublishBuildAssets, true), eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}:
     - template: ../job/publish-build-assets.yml
       parameters:
@@ -94,4 +100,7 @@ jobs:
 
         runAsPublic: ${{ parameters.runAsPublic }}
         publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }}
+        publishAssetsImmediately: ${{ parameters.publishAssetsImmediately }}
         enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }}
+        artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+        signingValidationAdditionalParameters: ${{ parameters.signingValidationAdditionalParameters }}
index 2f176571f020cf1253593f4457a2c795fa2b4851..5a9056f6b2fb5088ec3acf5db9c5fb1383f1f771 100644 (file)
@@ -82,6 +82,11 @@ parameters:
     default:
     - Validate
 
+  # Optional: Call asset publishing rather than running in a separate stage
+  - name: publishAssetsImmediately
+    type: boolean
+    default: false
+
 stages:
 - ${{ if or(eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}:
   - stage: Validate
@@ -99,7 +104,7 @@ stages:
           name: VSEngSS-MicroBuild2022-1ES
           demands: Cmd
         # If it's not devdiv, it's dnceng
-        ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:
+        ${{ else }}:
           name: NetCore1ESPool-Internal
           demands: ImageOverride -equals Build.Server.Amd64.VS2019
 
@@ -136,7 +141,7 @@ stages:
           name: VSEngSS-MicroBuild2022-1ES
           demands: Cmd
         # If it's not devdiv, it's dnceng
-        ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:
+        ${{ else }}:
           name: NetCore1ESPool-Internal
           demands: ImageOverride -equals Build.Server.Amd64.VS2019
       steps:
@@ -196,7 +201,7 @@ stages:
           name: VSEngSS-MicroBuild2022-1ES
           demands: Cmd
         # If it's not devdiv, it's dnceng
-        ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:
+        ${{ else }}:
           name: NetCore1ESPool-Internal
           demands: ImageOverride -equals Build.Server.Amd64.VS2019
       steps:
@@ -235,43 +240,44 @@ stages:
         artifactNames: ${{ parameters.SDLValidationParameters.artifactNames }}
         downloadArtifacts: ${{ parameters.SDLValidationParameters.downloadArtifacts }}
 
-- stage: publish_using_darc
-  ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}:
-    dependsOn: ${{ parameters.publishDependsOn }}
-  ${{ if and(ne(parameters.enableNugetValidation, 'true'), ne(parameters.enableSigningValidation, 'true'), ne(parameters.enableSourceLinkValidation, 'true'), ne(parameters.SDLValidationParameters.enable, 'true')) }}:
-    dependsOn: ${{ parameters.validateDependsOn }}
-  displayName: Publish using Darc
-  variables:
-    - template: common-variables.yml
-  jobs:
-  - job:
-    displayName: Publish Using Darc
-    timeoutInMinutes: 120
-    pool:
-      # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)
+- ${{ if ne(parameters.publishAssetsImmediately, 'true') }}:
+  - stage: publish_using_darc
+    ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}:
+      dependsOn: ${{ parameters.publishDependsOn }}
+    ${{ else }}:
+      dependsOn: ${{ parameters.validateDependsOn }}
+    displayName: Publish using Darc
+    variables:
+      - template: common-variables.yml
+    jobs:
+    - job:
+      displayName: Publish Using Darc
+      timeoutInMinutes: 120
+      pool:
+        # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)
         ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:
           name: VSEngSS-MicroBuild2022-1ES
           demands: Cmd
         # If it's not devdiv, it's dnceng
-        ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:
+        ${{ else }}:
           name: NetCore1ESPool-Internal
           demands: ImageOverride -equals Build.Server.Amd64.VS2019
-    steps:
-      - template: setup-maestro-vars.yml
-        parameters:
-          BARBuildId: ${{ parameters.BARBuildId }}
-          PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+      steps:
+        - template: setup-maestro-vars.yml
+          parameters:
+            BARBuildId: ${{ parameters.BARBuildId }}
+            PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
 
-      - task: NuGetAuthenticate@0
+        - task: NuGetAuthenticate@0
 
-      - task: PowerShell@2
-        displayName: Publish Using Darc
-        inputs:
-          filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
-          arguments: -BuildId $(BARBuildId) 
-            -PublishingInfraVersion ${{ parameters.publishingInfraVersion }}
-            -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
-            -MaestroToken '$(MaestroApiAccessToken)'
-            -WaitPublishingFinish true
-            -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'
-            -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'
\ No newline at end of file
+        - task: PowerShell@2
+          displayName: Publish Using Darc
+          inputs:
+            filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
+            arguments: -BuildId $(BARBuildId) 
+              -PublishingInfraVersion ${{ parameters.publishingInfraVersion }}
+              -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
+              -MaestroToken '$(MaestroApiAccessToken)'
+              -WaitPublishingFinish true
+              -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'
+              -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'
\ No newline at end of file
index f1e1cb53953bccd2900951db040f0799a78a6522..797f05292a8515814e4631470374d698566efc87 100644 (file)
@@ -365,8 +365,8 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements =
 
   # If the version of msbuild is going to be xcopied,
   # use this version. Version matches a package here:
-  # https://dev.azure.com/dnceng/public/_packaging?_a=package&feed=dotnet-eng&package=RoslynTools.MSBuild&protocolType=NuGet&version=16.10.0-preview2&view=overview
-  $defaultXCopyMSBuildVersion = '16.10.0-preview2'
+  # https://dev.azure.com/dnceng/public/_packaging?_a=package&feed=dotnet-eng&package=RoslynTools.MSBuild&protocolType=NuGet&version=17.1.0&view=overview
+  $defaultXCopyMSBuildVersion = '17.1.0'
 
   if (!$vsRequirements) { $vsRequirements = $GlobalJson.tools.vs }
   $vsMinVersionStr = if ($vsRequirements.version) { $vsRequirements.version } else { $vsMinVersionReqdStr }
index b67594cb60fb2a88633a0a7432648607d873ff2c..c3e757ccdef01218362ab7147cd318ae36f32a9d 100644 (file)
@@ -78,6 +78,11 @@ if (MSVC)
   set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /PDBCOMPRESS")
   set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:1572864")
 
+  if(EXISTS ${CLR_SOURCELINK_FILE_PATH})
+    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /sourcelink:${CLR_SOURCELINK_FILE_PATH}")
+    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /sourcelink:${CLR_SOURCELINK_FILE_PATH}")
+  endif(EXISTS ${CLR_SOURCELINK_FILE_PATH})
+
   # Checked build specific flags
   add_linker_flag(/INCREMENTAL:NO CHECKED) # prevent "warning LNK4075: ignoring '/INCREMENTAL' due to '/OPT:REF' specification"
   add_linker_flag(/OPT:REF CHECKED)
@@ -390,6 +395,10 @@ if (CLR_CMAKE_HOST_UNIX)
 
   add_compile_options(-Wno-unused-but-set-variable)
 
+  # Turn off floating point expression contraction because it is considered a value changing
+  # optimization in the IEEE 754 specification and is therefore considered unsafe.
+  add_compile_options(-ffp-contract=off)
+
   if (CMAKE_C_COMPILER_ID MATCHES "Clang")
     add_compile_options(-Wno-unknown-warning-option)
 
@@ -489,10 +498,16 @@ if(CLR_CMAKE_TARGET_UNIX)
     add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_ANDROID>)
   elseif(CLR_CMAKE_TARGET_LINUX)
     add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_LINUX>)
+    if(CLR_CMAKE_TARGET_LINUX_MUSL)
+        add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_LINUX_MUSL>)
+    endif()
   elseif(CLR_CMAKE_TARGET_NETBSD)
     add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_NETBSD>)
   elseif(CLR_CMAKE_TARGET_SUNOS)
     add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_SUNOS>)
+    if(CLR_CMAKE_TARGET_OS_ILLUMOS)
+      add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_ILLUMOS>)
+    endif()
   endif()
 else(CLR_CMAKE_TARGET_UNIX)
   add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_WINDOWS>)
@@ -541,8 +556,10 @@ if (MSVC)
   # /W3 is added by default by CMake, so remove it
   string(REPLACE "/W3" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
   string(REPLACE "/W3" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
-  # set default warning level to 3 but allow targets to override it.
-  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/W$<GENEX_EVAL:$<IF:$<BOOL:$<TARGET_PROPERTY:MSVC_WARNING_LEVEL>>,$<TARGET_PROPERTY:MSVC_WARNING_LEVEL>,3>>>)
+
+  # [[! Microsoft.Security.SystemsADM.10086 !]] - SDL required warnings
+  # set default warning level to 4 but allow targets to override it.
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/W$<GENEX_EVAL:$<IF:$<BOOL:$<TARGET_PROPERTY:MSVC_WARNING_LEVEL>>,$<TARGET_PROPERTY:MSVC_WARNING_LEVEL>,4>>>)
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/WX>) # treat warnings as errors
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/Oi>) # enable intrinsics
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/Oy->) # disable suppressing of the creation of frame pointers on the call stack for quicker function calls
@@ -577,6 +594,7 @@ if (MSVC)
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/wd4456>) # declaration of 'identifier' hides previous local declaration
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/wd4457>) # declaration of 'identifier' hides function parameter
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/wd4458>) # declaration of 'identifier' hides class member
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/wd4702>) # unreachable code
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/wd4733>) # Inline asm assigning to 'FS:0' : handler not registered as safe handler
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/wd4838>) # conversion from 'type_1' to 'type_2' requires a narrowing conversion
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/wd4960>) # 'function' is too big to be profiled
@@ -586,11 +604,30 @@ if (MSVC)
   # Treat Warnings as Errors:
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4007>) # 'main' : must be __cdecl.
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4013>) # 'function' undefined - assuming extern returning int.
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4018>) # 'expression' : signed/unsigned mismatch
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4055>) # 'conversion' : from data pointer 'type1' to function pointer 'type2'
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4102>) # "'%$S' : unreferenced label".
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4146>) # unary minus operator applied to unsigned type, result still unsigned
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4242>) # 'identifier' : conversion from 'type1' to 'type2', possible loss of data
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4244>) # 'conversion' conversion from 'type1' to 'type2', possible loss of data
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4267>) # 'var' : conversion from 'size_t' to 'type', possible loss of data
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4302>) # 'conversion' : truncation from 'type 1' to 'type 2'
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4308>) # negative integral constant converted to unsigned type
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4509>) # nonstandard extension used: 'function' uses SEH and 'object' has destructor
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4510>) # 'class' : default constructor could not be generated
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4532>) # 'continue' : jump out of __finally/finally block has undefined behavior during termination handling
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4533>) # initialization of 'variable' is skipped by 'instruction'
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4551>) # Function call missing argument list.
-  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4700>) # Local used w/o being initialized.
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4610>) # object 'class' can never be instantiated - user-defined constructor required
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4611>) # interaction between 'function' and C++ object destruction is non-portable
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4640>) # 'instance' : construction of local static object is not thread-safe
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4700>) # Local used w/o being initialized.
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4701>) # Potentially uninitialized local variable 'name' used
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4703>) # Potentially uninitialized local pointer variable 'name' used
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4789>) # destination of memory copy is too small
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4806>) # Unsafe operation involving type 'bool'.
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4995>) # 'function': name was marked as #pragma deprecated
+  add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4996>) # 'function': was declared deprecated also 'std::': Function call with parameters that are potentially unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'
 
   # Set Warning Level 3:
   add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/w34092>) # Sizeof returns 'unsigned long'.
@@ -727,4 +764,4 @@ if (CLR_CMAKE_HOST_WIN32)
 elseif (NOT CLR_CMAKE_HOST_BROWSER)
     enable_language(ASM)
 
-endif(CLR_CMAKE_HOST_WIN32)
+endif(CLR_CMAKE_HOST_WIN32)
\ No newline at end of file
diff --git a/eng/set-cmake-path.ps1 b/eng/set-cmake-path.ps1
deleted file mode 100644 (file)
index 5fc499a..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-# This file probes for the prerequisites for the build system, and outputs commands for eval'ing
-# from the cmd scripts to set variables (and exit on error)
-
-function GetCMakeVersions
-{
-  $items = @()
-  $items += @(Get-ChildItem hklm:\SOFTWARE\Wow6432Node\Kitware -ErrorAction SilentlyContinue)
-  $items += @(Get-ChildItem hklm:\SOFTWARE\Kitware -ErrorAction SilentlyContinue)
-  return $items | where { $_.PSChildName.StartsWith("CMake") }
-}
-
-function GetCMakeInfo($regKey)
-{
-  try {
-    $version = [System.Version] $regKey.PSChildName.Split(' ')[1]
-  }
-  catch {
-    return $null
-  }
-  $itemProperty = Get-ItemProperty $regKey.PSPath;
-  if (Get-Member -inputobject $itemProperty -name "InstallDir" -Membertype Properties) {
-    $cmakeDir = $itemProperty.InstallDir
-  }
-  else {
-    $cmakeDir = $itemProperty.'(default)'
-  }
-  $cmakePath = [System.IO.Path]::Combine($cmakeDir, "bin\cmake.exe")
-  if (![System.IO.File]::Exists($cmakePath)) {
-    return $null
-  }
-  return @{'version' = $version; 'path' = $cmakePath}
-}
-
-function LocateCMake
-{
-  $errorMsg = "CMake is a pre-requisite to build this repository but it was not found on the path. Please install CMake from http://www.cmake.org/download/ and ensure it is on your path."
-  $inPathPath = (get-command cmake.exe -ErrorAction SilentlyContinue)
-  if ($inPathPath -ne $null) {
-    # Resolve the first version of CMake if multiple commands are found
-    if ($inPathPath.Length -gt 1) {
-      return $inPathPath[0].Path
-    }
-    return $inPathPath.Path
-  }
-  # Let us hope that CMake keep using their current version scheme
-  $validVersions = @()
-  foreach ($regKey in GetCMakeVersions) {
-    $info = GetCMakeInfo($regKey)
-    if ($info -ne $null) {
-      $validVersions += @($info)
-    }
-  }
-  $newestCMakePath = ($validVersions |
-    Sort-Object -property @{Expression={$_.version}; Ascending=$false} |
-    select -first 1).path
-  if ($newestCMakePath -eq $null) {
-    Throw $errorMsg
-  }
-  return $newestCMakePath
-}
-
-try {
-  $cmakePath = LocateCMake
-  [System.Console]::WriteLine("set CMakePath=" + $cmakePath)
-
-}
-catch {
-  [System.Console]::Error.WriteLine($_.Exception.Message)
-  [System.Console]::WriteLine("exit /b 1")
-}
index 0d4a3d4fd0c58b9977e551ba33769f40de9b3668..37472ac52b6a536d68c8d4f95864438c6b097a9c 100644 (file)
@@ -16,6 +16,6 @@
   },
   "msbuild-sdks": {
     "Microsoft.Build.NoTargets": "2.0.1",
-    "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.22181.2"
+    "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.22269.3"
   }
 }
index 03e6a76400b691a5fc03de171853b2316251eff4..bfb2bc5720d01eab2ede3152526d5b6793afe27e 100644 (file)
@@ -485,13 +485,13 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         class LocalHelpBuilder : IHelpBuilder
         {
             private readonly CommandService _commandService;
-            private readonly IConsole _console;
+            private readonly LocalConsole _console;
             private readonly bool _useHelpBuilder;
 
             public LocalHelpBuilder(CommandService commandService, IConsole console, bool useHelpBuilder)
             {
                 _commandService = commandService;
-                _console = console;
+                _console = (LocalConsole)console;
                 _useHelpBuilder = useHelpBuilder;
             }
 
@@ -500,14 +500,14 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
                 bool useHelpBuilder = _useHelpBuilder;
                 if (_commandService._commandHandlers.TryGetValue(command.Name, out CommandHandler handler))
                 {
-                    if (handler.InvokeHelp(_commandService.Parser, LocalConsole.ToServices(_console))) {
+                    if (handler.InvokeHelp(_commandService.Parser, _console.Services)) {
                         return;
                     }
                     useHelpBuilder = true;
                 }
                 if (useHelpBuilder)
                 {
-                    var helpBuilder = new HelpBuilder(_console, maxWidth: LocalConsole.ToConsoleService(_console).WindowWidth);
+                    var helpBuilder = new HelpBuilder(_console, maxWidth: _console.ConsoleService.WindowWidth);
                     helpBuilder.Write(command);
                 }
             }
@@ -520,20 +520,27 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         /// </summary>
         class LocalConsole : IConsole
         {
-            public static IServiceProvider ToServices(IConsole console) => ((LocalConsole)console)._services;
+            private IConsoleService _console;
 
-            public static IConsoleService ToConsoleService(IConsole console) => ((LocalConsole)console)._console;
+            public LocalConsole(IServiceProvider services)
+            {
+                Services = services;
+                Out = new StandardStreamWriter((text) => ConsoleService.Write(text));
+                Error = new StandardStreamWriter((text) => ConsoleService.WriteError(text));
+            }
 
-            private readonly IServiceProvider _services;
-            private readonly IConsoleService _console;
+            internal readonly IServiceProvider Services;
 
-            public LocalConsole(IServiceProvider services)
+            internal IConsoleService ConsoleService
             {
-                _services = services;
-                _console = services.GetService<IConsoleService>();
-                Debug.Assert(_console != null);
-                Out = new StandardStreamWriter((text) => _console.Write(text));
-                Error = new StandardStreamWriter((text) => _console.WriteError(text));
+                get
+                {
+                    if (_console is null)
+                    {
+                        _console = Services.GetService<IConsoleService>();
+                    }
+                    return _console;
+                }
             }
 
             #region IConsole
diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/ElfModule.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/ElfModule.cs
new file mode 100644 (file)
index 0000000..66f786f
--- /dev/null
@@ -0,0 +1,56 @@
+// 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 Microsoft.FileFormats;
+using Microsoft.FileFormats.ELF;
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Microsoft.Diagnostics.DebugServices.Implementation
+{
+    /// <summary>
+    /// Disposable ELFFile wrapper around the module file.
+    /// </summary>
+    public class ELFModule : ELFFile, IDisposable
+    {
+        private readonly Stream _stream;
+
+        /// <summary>
+        /// Opens and returns an ELFFile instance from the local file path
+        /// </summary>
+        /// <param name="filePath">ELF file to open</param>
+        /// <returns>ELFFile instance or null</returns>
+        public static ELFModule OpenFile(string filePath)
+        {
+            Stream stream = Utilities.TryOpenFile(filePath);
+            if (stream is not null)
+            {
+                try
+                {
+                    ELFModule elfModule = new(stream);
+                    if (!elfModule.IsValid())
+                    {
+                        Trace.TraceError($"OpenELFFile: not a valid file");
+                        return null;
+                    }
+                    return elfModule;
+                }
+                catch (Exception ex) when (ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException)
+                {
+                    Trace.TraceError($"OpenELFFile: exception {ex.Message}");
+                }
+            }
+            return null;
+        }
+
+        public ELFModule(Stream stream) :
+            base(new StreamAddressSpace(stream), position: 0, isDataSourceVirtualAddressSpace: false)
+        {
+            _stream = stream;
+        }
+
+        public void Dispose() => _stream.Dispose();
+    }
+}
\ No newline at end of file
index 2c9015129134cf59b859710629161a15b2e1c1be..c27f5d4df14adf7944ed71f65bbb6a845b5477ad 100644 (file)
@@ -169,11 +169,11 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
                         else
                         {
                             // Find or download the ELF image, if one.
-                            Reader virtualAddressReader = module.Services.GetService<ELFFile>()?.VirtualAddressReader;
+                            Reader virtualAddressReader = module.Services.GetService<ELFModule>()?.VirtualAddressReader;
                             if (virtualAddressReader is null)
                             {
                                 // Find or download the MachO image, if one.
-                                virtualAddressReader = module.Services.GetService<MachOFile>()?.VirtualAddressReader;
+                                virtualAddressReader = module.Services.GetService<MachOModule>()?.VirtualAddressReader;
                             }
                             if (virtualAddressReader is not null)
                             {
diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/MachOModule.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/MachOModule.cs
new file mode 100644 (file)
index 0000000..f530888
--- /dev/null
@@ -0,0 +1,56 @@
+// 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 Microsoft.FileFormats;
+using Microsoft.FileFormats.MachO;
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Microsoft.Diagnostics.DebugServices.Implementation
+{
+    /// <summary>
+    /// Disposable MachOFile wrapper around the module file.
+    /// </summary>
+    public class MachOModule : MachOFile, IDisposable
+    {
+        private readonly Stream _stream;
+
+        /// <summary>
+        /// Opens and returns an MachOFile instance from the local file path
+        /// </summary>
+        /// <param name="filePath">MachO file to open</param>
+        /// <returns>MachOFile instance or null</returns>
+        public static MachOModule OpenFile(string filePath)
+        {
+            Stream stream = Utilities.TryOpenFile(filePath);
+            if (stream is not null)
+            {
+                try
+                {
+                    var machoModule = new MachOModule(stream);
+                    if (!machoModule.IsValid())
+                    {
+                        Trace.TraceError($"OpenMachOFile: not a valid file");
+                        return null;
+                    }
+                    return machoModule;
+                }
+                catch (Exception ex) when (ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException)
+                {
+                    Trace.TraceError($"OpenMachOFile: exception {ex.Message}");
+                }
+            }
+            return null;
+        }
+
+        public MachOModule(Stream stream) :
+            base(new StreamAddressSpace(stream), position: 0, dataSourceIsVirtualAddressSpace: false)
+        {
+            _stream = stream;
+        }
+
+        public void Dispose() => _stream.Dispose();
+    }
+}
index ec5c3f3a31627ce69499d84fc41541887e78185f..dde7210a419f0af0f3d60174b2f7201ddc2134d0 100644 (file)
@@ -33,6 +33,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
             InitializePEInfo = 0x10,
             InitializeVersion = 0x20,
             InitializeProductVersion = 0x40,
+            InitializeSymbolFileName = 0x80
         }
 
         private readonly IDisposable _onChangeEvent;
@@ -40,6 +41,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         private IEnumerable<PdbFileInfo> _pdbFileInfos;
         protected ImmutableArray<byte> _buildId;
         private PEFile _peFile;
+        private string _symbolFileName;
 
         public readonly ServiceProvider ServiceProvider;
 
@@ -47,20 +49,50 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         {
             ServiceProvider = new ServiceProvider();
             ServiceProvider.AddServiceFactoryWithNoCaching<PEFile>(() => GetPEInfo());
+            ServiceProvider.AddService<IExportSymbols>(this);
 
-            ServiceProvider.AddServiceFactory<PEReader>(() => Utilities.OpenPEReader(ModuleService.SymbolService.DownloadModule(this)));
-            if (target.OperatingSystem == OSPlatform.Linux) {
-                ServiceProvider.AddServiceFactory<ELFFile>(() => Utilities.OpenELFFile(ModuleService.SymbolService.DownloadModule(this)));
+            ServiceProvider.AddServiceFactory<PEReader>(() => {
+                if (!IndexTimeStamp.HasValue || !IndexFileSize.HasValue) {
+                    return null;
+                }
+                return Utilities.OpenPEReader(ModuleService.SymbolService.DownloadModuleFile(this));
+            });
+
+            if (target.OperatingSystem == OSPlatform.Linux) 
+            {
+                ServiceProvider.AddServiceFactory<ELFModule>(() => {
+                    if (BuildId.IsDefaultOrEmpty) {
+                        return null;
+                    }
+                    return ELFModule.OpenFile(ModuleService.SymbolService.DownloadModuleFile(this));
+                });
+                ServiceProvider.AddServiceFactory<ELFFile>(() => {
+                    Stream stream = ModuleService.MemoryService.CreateMemoryStream();
+                    var elfFile = new ELFFile(new StreamAddressSpace(stream), ImageBase, true);
+                    return elfFile.IsValid() ? elfFile : null;
+                });
             }
-            if (target.OperatingSystem == OSPlatform.OSX) {
-                ServiceProvider.AddServiceFactory<MachOFile>(() => Utilities.OpenMachOFile(ModuleService.SymbolService.DownloadModule(this)));
+
+            if (target.OperatingSystem == OSPlatform.OSX) 
+            {
+                ServiceProvider.AddServiceFactory<MachOModule>(() => {
+                    if (BuildId.IsDefaultOrEmpty) {
+                        return null;
+                    }
+                    return MachOModule.OpenFile(ModuleService.SymbolService.DownloadModuleFile(this));
+                });
+                ServiceProvider.AddServiceFactory<MachOFile>(() => {
+                    Stream stream = ModuleService.MemoryService.CreateMemoryStream();
+                    var machoFile = new MachOFile(new StreamAddressSpace(stream), ImageBase, true);
+                    return machoFile.IsValid() ? machoFile : null;
+                });
             }
+
             _onChangeEvent = target.Services.GetService<ISymbolService>()?.OnChangeEvent.Register(() => {
-                ServiceProvider.RemoveService(typeof(MachOFile)); 
-                ServiceProvider.RemoveService(typeof(ELFFile));
+                ServiceProvider.RemoveService(typeof(MachOModule)); 
+                ServiceProvider.RemoveService(typeof(ELFModule));
                 ServiceProvider.RemoveService(typeof(PEReader));
             });
-            ServiceProvider.AddService<IExportSymbols>(this);
          }
 
         public void Dispose()
@@ -134,16 +166,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
             }
         }
 
-        public IEnumerable<PdbFileInfo> PdbFileInfos
-        {
-            get
-            {
-                GetPEInfo();
-                Debug.Assert(_pdbFileInfos is not null);
-                return _pdbFileInfos;
-            }
-        }
-
         public virtual ImmutableArray<byte> BuildId
         {
             get
@@ -164,9 +186,51 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
             }
         }
 
-        public abstract VersionData VersionData { get; }
+        public IEnumerable<PdbFileInfo> GetPdbFileInfos()
+        {
+            GetPEInfo();
+            Debug.Assert(_pdbFileInfos is not null);
+            return _pdbFileInfos;
+        }
 
-        public abstract string VersionString { get; }
+        public string GetSymbolFileName()
+        {
+            if (InitializeValue(Flags.InitializeSymbolFileName))
+            {
+                if (Target.OperatingSystem == OSPlatform.Linux)
+                {
+                    try
+                    {
+                        Stream stream = ModuleService.RawMemoryService.CreateMemoryStream();
+                        var elfFile = new ELFFile(new StreamAddressSpace(stream), ImageBase, true);
+                        if (elfFile.IsValid())
+                        {
+                            ELFSection section = elfFile.FindSectionByName(".gnu_debuglink");
+                            if (section != null)
+                            {
+                                _symbolFileName = section.Contents.Read<string>(0);
+                            }
+                        }
+                    }
+                    catch (Exception ex) when
+                       (ex is InvalidVirtualAddressException ||
+                        ex is ArgumentOutOfRangeException ||
+                        ex is IndexOutOfRangeException ||
+                        ex is BadInputFormatException)
+
+                    {
+                        Trace.TraceWarning("ELF .gnu_debuglink section in {0}: {1}", this, ex.Message);
+                    }
+                }
+            }
+            return _symbolFileName;
+        }
+
+        public abstract VersionData GetVersionData();
+
+        public abstract string GetVersionString();
+
+        public abstract string LoadSymbols();
 
         #endregion
 
@@ -176,9 +240,8 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         {
             if (Target.OperatingSystem == OSPlatform.Windows)
             {
-                Stream stream = ModuleService.MemoryService.CreateMemoryStream(ImageBase, ImageSize);
-                PEFile image = new(new StreamAddressSpace(stream), isDataSourceVirtualAddressSpace: true);
-                if (image.IsValid())
+                PEFile image = Services.GetService<PEFile>();
+                if (image is not null)
                 { 
                     if (image.TryGetExportSymbol(name, out ulong offset))
                     {
@@ -244,7 +307,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
             else 
             {
                 // If we can't get the version from the PE, search for version string embedded in the module data
-                string versionString = VersionString;
+                string versionString = GetVersionString();
                 if (versionString != null)
                 {
                     int spaceIndex = versionString.IndexOf(' ');
@@ -271,10 +334,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
                         }
                     }
                 }
-                else
-                {
-                    Trace.TraceInformation($"Module.GetVersion no version string");
-                }
             }
 
             return versionData;
index 746ce1ecb11f242f7310857ec407c1d9b390b823..d58bf78cc54c0d84b9d2265aa23ba6f6dbdc6859 100644 (file)
@@ -216,23 +216,29 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
             {
                 // First try getting the PE info as loaded layout (native Windows DLLs and most managed PEs).
                 peFile = GetPEInfo(isVirtual: true, address, size, out List<PdbFileInfo> pdbs, out Module.Flags flags);
-                if (peFile is null || pdbs.Count == 0)
+
+                // Continue only if marked as a PE. This bit regardless of the layout if the module has a PE header/signature.
+                if ((flags & Module.Flags.IsPEImage) != 0)
                 {
-                    // If PE file is invalid or there are no PDB records, try getting the PE info as file layout. No PDB records can mean
-                    // that either the layout is wrong or that there really no PDB records. If file layout doesn't have any pdb records
-                    // either default to loaded layout PEFile.
-                    PEFile peFileLayout = GetPEInfo(isVirtual: false, address, size, out List<PdbFileInfo> pdbsFileLayout, out Module.Flags flagsFileLayout);
-                    if (peFileLayout is not null && (peFile is null || pdbsFileLayout.Count > 0))
+                    if (peFile is null || pdbs.Count == 0)
                     {
-                        flags = flagsFileLayout;
-                        pdbs = pdbsFileLayout;
-                        peFile = peFileLayout;
+                        // If PE file is invalid or there are no PDB records, try getting the PE info as file layout. No PDB records can mean
+                        // that either the layout is wrong or that there really no PDB records. If file layout doesn't have any pdb records
+                        // either default to loaded layout PEFile.
+                        PEFile peFileLayout = GetPEInfo(isVirtual: false, address, size, out List<PdbFileInfo> pdbsFileLayout, out Module.Flags flagsFileLayout);
+                        Debug.Assert((flagsFileLayout & Module.Flags.IsPEImage) != 0);
+                        if (peFileLayout is not null && (peFile is null || pdbsFileLayout.Count > 0))
+                        {
+                            flags = flagsFileLayout;
+                            pdbs = pdbsFileLayout;
+                            peFile = peFileLayout;
+                        }
+                    }
+                    if (peFile is not null)
+                    {
+                        moduleFlags |= flags;
+                        pdbFileInfos = pdbs;
                     }
-                }
-                if (peFile is not null)
-                {
-                    moduleFlags |= flags;
-                    pdbFileInfos = pdbs;
                 }
             }
 
@@ -264,10 +270,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
                     flags |= isVirtual ? Module.Flags.IsLoadedLayout : Module.Flags.IsFileLayout;
                     return peFile;
                 }
-                else
-                {
-                    Trace.TraceError($"GetPEInfo: PE invalid {address:X16} isVirtual {isVirtual}");
-                }
             }
             catch (Exception ex) when (ex is InvalidVirtualAddressException || ex is BadInputFormatException)
             {
@@ -283,6 +285,9 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         /// <returns>build id or null</returns>
         internal byte[] GetBuildId(ulong address)
         {
+            // This code is called by the image mapping memory service so it needs to use the
+            // original or raw memory service to prevent recursion so it can't use the ELFFile
+            // or MachOFile instance that is available from the IModule.Services provider.
             Stream stream = RawMemoryService.CreateMemoryStream();
             byte[] buildId = null;
             try
@@ -294,10 +299,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
                     {
                         buildId = elfFile.BuildID;
                     }
-                    else
-                    {
-                        Trace.TraceError($"GetBuildId: invalid ELF file {address:X16}");
-                    }
                 }
                 else if (Target.OperatingSystem == OSPlatform.OSX)
                 {
@@ -306,10 +307,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
                     {
                         buildId = machOFile.Uuid;
                     }
-                    else
-                    {
-                        Trace.TraceError($"GetBuildId: invalid MachO file {address:X16}");
-                    }
                 }
             }
             catch (Exception ex) when (ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException)
@@ -322,48 +319,40 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         /// <summary>
         /// Get the version string from a Linux or MacOS image
         /// </summary>
-        /// <param name="address">image base</param>
+        /// <param name="module">module to get version string</param>
         /// <returns>version string or null</returns>
-        protected string GetVersionString(ulong address)
+        protected string GetVersionString(IModule module)
         {
-            Stream stream = MemoryService.CreateMemoryStream();
             try
             {
-                if (Target.OperatingSystem == OSPlatform.Linux)
+                ELFFile elfFile = module.Services.GetService<ELFFile>();
+                if (elfFile is not null)
                 {
-                    var elfFile = new ELFFile(new StreamAddressSpace(stream), address, true);
-                    if (elfFile.IsValid())
+                    foreach (ELFProgramHeader programHeader in elfFile.Segments.Select((segment) => segment.Header))
                     {
-                        foreach (ELFProgramHeader programHeader in elfFile.Segments.Select((segment) => segment.Header))
+                        uint flags = MemoryService.PointerSize == 8 ? programHeader.Flags : programHeader.Flags32;
+                        if (programHeader.Type == ELFProgramHeaderType.Load &&
+                           (flags & (uint)ELFProgramHeaderAttributes.Writable) != 0)
                         {
-                            uint flags = MemoryService.PointerSize == 8 ? programHeader.Flags : programHeader.Flags32;
-                            if (programHeader.Type == ELFProgramHeaderType.Load &&
-                               (flags & (uint)ELFProgramHeaderAttributes.Writable) != 0)
+                            ulong loadAddress = programHeader.VirtualAddress.Value;
+                            long loadSize = (long)programHeader.VirtualSize;
+                            if (SearchVersionString(module.ImageBase + loadAddress, loadSize, out string productVersion))
                             {
-                                ulong loadAddress = programHeader.VirtualAddress.Value;
-                                long loadSize = (long)programHeader.VirtualSize;
-                                if (SearchVersionString(address + loadAddress, loadSize, out string productVersion))
-                                {
-                                    return productVersion;
-                                }
+                                return productVersion;
                             }
                         }
-                        Trace.TraceInformation($"GetVersionString: not found in ELF file {address:X16}");
-                    }
-                    else
-                    {
-                        Trace.TraceError($"GetVersionString: invalid ELF file {address:X16}");
                     }
+                    Trace.TraceInformation($"GetVersionString: not found in ELF file {module}");
                 }
-                else if (Target.OperatingSystem == OSPlatform.OSX)
+                else
                 {
-                    var machOFile = new MachOFile(new StreamAddressSpace(stream), address, true);
-                    if (machOFile.IsValid())
+                    MachOFile machOFile = module.Services.GetService<MachOFile>();
+                    if (machOFile is not null)
                     {
                         foreach (MachSegmentLoadCommand loadCommand in machOFile.Segments.Select((segment) => segment.LoadCommand))
                         {
                             if (loadCommand.Command == LoadCommandType.Segment64 &&
-                               (loadCommand.InitProt & VmProtWrite) != 0 && 
+                               (loadCommand.InitProt & VmProtWrite) != 0 &&
                                 loadCommand.SegName.ToString() != "__LINKEDIT")
                             {
                                 ulong loadAddress = loadCommand.VMAddress + machOFile.PreferredVMBaseAddress;
@@ -374,21 +363,17 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
                                 }
                             }
                         }
-                        Trace.TraceInformation($"GetVersionString: not found in MachO file {address:X16}");
+                        Trace.TraceInformation($"GetVersionString: not found in MachO file {module}");
                     }
                     else
                     {
-                        Trace.TraceError($"GetVersionString: invalid MachO file {address:X16}");
+                        Trace.TraceError($"GetVersionString: unsupported module {module} or platform {Target.OperatingSystem}");
                     }
                 }
-                else
-                {
-                    Trace.TraceError("GetVersionString: unsupported platform {0}", Target.OperatingSystem);
-                }
             }
             catch (Exception ex) when (ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException)
             {
-                Trace.TraceError($"GetVersionString: {address:X16} exception {ex.Message}");
+                Trace.TraceError($"GetVersionString: {module} exception {ex.Message}");
             }
             return null;
         }
index 7fd2e230ffa0c348935e4cd9bd25f96e448ba6cf..4624b94a22339273faf89aa90dc0bf72b4da119f 100644 (file)
@@ -68,41 +68,40 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
                 }
             }
 
-            public override VersionData VersionData
+            public override VersionData GetVersionData()
             {
-                get 
+                if (InitializeValue(Module.Flags.InitializeVersion))
                 {
-                    if (InitializeValue(Module.Flags.InitializeVersion))
+                    if (_moduleInfo.Version != EmptyVersionInfo)
                     {
-                        if (_moduleInfo.Version != EmptyVersionInfo)
-                        {
-                            _versionData = _moduleInfo.Version.ToVersionData();
-                        }
-                        else
+                        _versionData = _moduleInfo.Version.ToVersionData();
+                    }
+                    else
+                    {
+                        if (_moduleService.Target.OperatingSystem != OSPlatform.Windows)
                         {
-                            if (_moduleService.Target.OperatingSystem != OSPlatform.Windows)
-                            {
-                                _versionData = GetVersion();
-                            }
+                            _versionData = GetVersion();
                         }
                     }
-                    return _versionData;
                 }
+                return _versionData;
             }
 
-            public override string VersionString
+            public override string GetVersionString()
             {
-                get
+                if (InitializeValue(Module.Flags.InitializeProductVersion))
                 {
-                    if (InitializeValue(Module.Flags.InitializeProductVersion))
+                    if (_moduleService.Target.OperatingSystem != OSPlatform.Windows && !IsPEImage)
                     {
-                        if (_moduleService.Target.OperatingSystem != OSPlatform.Windows && !IsPEImage)
-                        {
-                            _versionString = _moduleService.GetVersionString(ImageBase);
-                        }
+                        _versionString = _moduleService.GetVersionString(this);
                     }
-                    return _versionString;
                 }
+                return _versionString;
+            }
+
+            public override string LoadSymbols()
+            {
+                return _moduleService.SymbolService.DownloadSymbolFile(this);
             }
 
             #endregion
index a29d69484514cafb3574730bd26500672943320a..8892e8bb3c641522e315b5a4c7b7855d3d6d5c4c 100644 (file)
@@ -135,7 +135,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         {
             try
             {
-                VersionData versionData = ModuleService.GetModuleFromBaseAddress(baseAddress).VersionData;
+                VersionData versionData = ModuleService.GetModuleFromBaseAddress(baseAddress).GetVersionData();
                 if (versionData is not null)
                 {
                     version = versionData.ToVersionInfo();
index fad23056283716965c6c4df282cf92e5c27551f8..97b82ac458f2084a1410cf0f9acf2d96af1a3385 100644 (file)
@@ -90,6 +90,21 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
             }
         }
 
+        /// <summary>
+        /// The time out in minutes passed to the HTTP symbol store when not overridden in AddSymbolServer.
+        /// </summary>
+        public int DefaultTimeout { get; set; } = 4;
+
+        /// <summary>
+        /// The retry count passed to the HTTP symbol store when not overridden in AddSymbolServer.
+        /// </summary>
+        public int DefaultRetryCount { get; set; } = 0;
+
+        /// <summary>
+        /// Reset any HTTP symbol stores marked with a client failure
+        /// </summary>
+        public void Reset() => ForEachSymbolStore<HttpSymbolStore>((httpSymbolStore) => httpSymbolStore.ResetClientFailure());
+
         /// <summary>
         /// Parses the Windows debugger symbol path (srv*, cache*, etc.).
         /// </summary>
@@ -186,7 +201,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
                     }
                     if (symbolServerPath != null)
                     {
-                        if (!AddSymbolServer(msdl: false, symweb: false, symbolServerPath.Trim(), authToken: null, timeoutInMinutes: 0))
+                        if (!AddSymbolServer(msdl: false, symweb: false, symbolServerPath.Trim()))
                         {
                             return false;
                         }
@@ -211,15 +226,17 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         /// <param name="msdl">if true, use the public Microsoft server</param>
         /// <param name="symweb">if true, use symweb internal server and protocol (file.ptr)</param>
         /// <param name="symbolServerPath">symbol server url (optional)</param>
-        /// <param name="authToken"></param>
-        /// <param name="timeoutInMinutes">symbol server timeout in minutes (optional)</param>
+        /// <param name="authToken">PAT for secure symbol server (optional)</param>
+        /// <param name="timeoutInMinutes">symbol server timeout in minutes (optional uses <see cref="DefaultTimeout"/> if null)</param>
+        /// <param name="retryCount">number of retries (optional uses <see cref="DefaultRetryCount"/> if null)</param>
         /// <returns>if false, failure</returns>
         public bool AddSymbolServer(
             bool msdl,
             bool symweb,
-            string symbolServerPath,
-            string authToken,
-            int timeoutInMinutes)
+            string symbolServerPath = null,
+            string authToken = null,
+            int? timeoutInMinutes = null,
+            int? retryCount = null)
         {
             bool internalServer = false;
 
@@ -274,10 +291,8 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
                     {
                         httpSymbolStore = new HttpSymbolStore(Tracer.Instance, store, uri, personalAccessToken: authToken);
                     }
-                    if (timeoutInMinutes != 0)
-                    {
-                        httpSymbolStore.Timeout = TimeSpan.FromMinutes(timeoutInMinutes);
-                    }
+                    httpSymbolStore.Timeout = TimeSpan.FromMinutes(timeoutInMinutes.GetValueOrDefault(DefaultTimeout));
+                    httpSymbolStore.RetryCount = retryCount.GetValueOrDefault(DefaultRetryCount);
                     SetSymbolStore(httpSymbolStore);
                 }
             }
@@ -334,18 +349,40 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         /// </summary>
         /// <param name="module">module interface</param>
         /// <returns>module path or null</returns>
-        public string DownloadModule(IModule module)
+        public string DownloadModuleFile(IModule module)
         {
-            string downloadFilePath = DownloadPE(module);
+            string downloadFilePath = DownloadPE(module, KeyTypeFlags.IdentityKey);
             if (downloadFilePath is null)
             {
                 if (module.Target.OperatingSystem == OSPlatform.Linux)
                 {
-                    downloadFilePath = DownloadELF(module);
+                    downloadFilePath = DownloadELF(module, KeyTypeFlags.IdentityKey);
                 }
                 else if (module.Target.OperatingSystem == OSPlatform.OSX)
                 {
-                    downloadFilePath = DownloadMachO(module);
+                    downloadFilePath = DownloadMachO(module, KeyTypeFlags.IdentityKey);
+                }
+            }
+            return downloadFilePath;
+        }
+
+        /// <summary>
+        /// Downloads the symbol file for module
+        /// </summary>
+        /// <param name="module">module interface</param>
+        /// <returns>module path or null</returns>
+        public string DownloadSymbolFile(IModule module)
+        {
+            string downloadFilePath = DownloadPE(module, KeyTypeFlags.SymbolKey);
+            if (downloadFilePath is null)
+            {
+                if (module.Target.OperatingSystem == OSPlatform.Linux)
+                {
+                    downloadFilePath = DownloadELF(module, KeyTypeFlags.SymbolKey);
+                }
+                else if (module.Target.OperatingSystem == OSPlatform.OSX)
+                {
+                    downloadFilePath = DownloadMachO(module, KeyTypeFlags.SymbolKey);
                 }
             }
             return downloadFilePath;
@@ -550,43 +587,92 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         /// Finds or downloads the PE module
         /// </summary>
         /// <param name="module">module instance</param>
+        /// <param name="flags"></param>
         /// <returns>module path or null</returns>
-        private string DownloadPE(IModule module)
+        private string DownloadPE(IModule module, KeyTypeFlags flags)
         {
-            if (!module.IndexTimeStamp.HasValue || !module.IndexFileSize.HasValue)
+            SymbolStoreKey fileKey = null;
+            string fileName = null;
+            if ((flags & KeyTypeFlags.IdentityKey) != 0)
             {
-                Trace.TraceWarning($"DownLoadPE: module {module.FileName} has no index timestamp/filesize");
-                return null;
+                if (!module.IndexTimeStamp.HasValue || !module.IndexFileSize.HasValue)
+                {
+                    return null;
+                }
+                fileName = module.FileName;
+                fileKey = PEFileKeyGenerator.GetKey(Path.GetFileName(fileName), module.IndexTimeStamp.Value, module.IndexFileSize.Value);
+                if (fileKey is null)
+                {
+                    Trace.TraceWarning($"DownLoadPE: no key generated for module {fileName} ");
+                    return null;
+                }
+            } 
+            else if ((flags & KeyTypeFlags.SymbolKey) != 0)
+            {
+                IEnumerable<PdbFileInfo> pdbInfos = module.GetPdbFileInfos();
+                if (!pdbInfos.Any())
+                {
+                    return null;
+                }
+                foreach (PdbFileInfo pdbInfo in pdbInfos)
+                {
+                    if (pdbInfo.IsPortable)
+                    {
+                        fileKey = PortablePDBFileKeyGenerator.GetKey(pdbInfo.Path, pdbInfo.Guid);
+                        if (fileKey is not null)
+                        {
+                            fileName = pdbInfo.Path;
+                            break;
+                        }
+                    }
+                }
+                if (fileKey is null)
+                {
+                    foreach (PdbFileInfo pdbInfo in pdbInfos)
+                    {
+                        if (!pdbInfo.IsPortable)
+                        {
+                            fileKey = PDBFileKeyGenerator.GetKey(pdbInfo.Path, pdbInfo.Guid, pdbInfo.Revision);
+                            if (fileKey is not null)
+                            {
+                                fileName = pdbInfo.Path;
+                                break;
+                            }
+                        }
+                    }
+                }
+                if (fileKey is null)
+                {
+                    Trace.TraceWarning($"DownLoadPE: no key generated for module PDB {module.FileName} ");
+                    return null;
+                }
             }
-
-            SymbolStoreKey moduleKey = PEFileKeyGenerator.GetKey(Path.GetFileName(module.FileName), module.IndexTimeStamp.Value, module.IndexFileSize.Value);
-            if (moduleKey is null)
+            else 
             {
-                Trace.TraceWarning($"DownLoadPE: no index generated for module {module.FileName} ");
-                return null;
+                throw new ArgumentException($"Key flag not supported {flags}");
             }
 
-            if (File.Exists(module.FileName))
+            // Check if the file is local and the key matches the module
+            if (File.Exists(fileName))
             {
-                using Stream stream = Utilities.TryOpenFile(module.FileName);
+                using Stream stream = Utilities.TryOpenFile(fileName);
                 if (stream is not null)
                 {
                     var peFile = new PEFile(new StreamAddressSpace(stream), false);
-                    var generator = new PEFileKeyGenerator(Tracer.Instance, peFile, module.FileName);
-                    IEnumerable<SymbolStoreKey> keys = generator.GetKeys(KeyTypeFlags.IdentityKey);
-                    foreach (SymbolStoreKey key in keys)
+                    var generator = new PEFileKeyGenerator(Tracer.Instance, peFile, fileName);
+                    foreach (SymbolStoreKey key in generator.GetKeys(flags))
                     {
-                        if (moduleKey.Equals(key))
+                        if (fileKey.Equals(key))
                         {
-                            Trace.TraceInformation("DownloadPE: local file match {0}", module.FileName);
-                            return module.FileName;
+                            Trace.TraceInformation($"DownloadPE: local file match {fileName}");
+                            return fileName;
                         }
                     }
                 }
             }
 
             // Now download the module from the symbol server if local file doesn't exists or doesn't have the right key
-            string downloadFilePath = DownloadFile(moduleKey);
+            string downloadFilePath = DownloadFile(fileKey);
             if (!string.IsNullOrEmpty(downloadFilePath))
             {
                 Trace.TraceInformation("DownloadPE: downloaded {0}", downloadFilePath);
@@ -600,42 +686,49 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         /// Finds or downloads the ELF module
         /// </summary>
         /// <param name="module">module instance</param>
+        /// <param name="flags"></param>
         /// <returns>module path or null</returns>
-        private string DownloadELF(IModule module)
+        private string DownloadELF(IModule module, KeyTypeFlags flags)
         {
+            if ((flags & (KeyTypeFlags.IdentityKey | KeyTypeFlags.SymbolKey)) == 0)
+            {
+                throw new ArgumentException($"Key flag not supported {flags}");
+            }
+
             if (module.BuildId.IsDefaultOrEmpty)
             {
                 Trace.TraceWarning($"DownloadELF: module {module.FileName} has no build id");
                 return null;
             }
 
-            SymbolStoreKey moduleKey = ELFFileKeyGenerator.GetKeys(KeyTypeFlags.IdentityKey, module.FileName, module.BuildId.ToArray(), symbolFile: false, symbolFileName: null).SingleOrDefault();
-            if (moduleKey is null)
+            SymbolStoreKey fileKey = ELFFileKeyGenerator.GetKeys(flags, module.FileName, module.BuildId.ToArray(), symbolFile: false, module.GetSymbolFileName()).SingleOrDefault();
+            if (fileKey is null)
             {
                 Trace.TraceWarning($"DownloadELF: no index generated for module {module.FileName} ");
                 return null;
             }
 
-            if (File.Exists(module.FileName))
+            // Check if the file is local and the key matches the module
+            string fileName = fileKey.FullPathName;
+            if (File.Exists(fileName))
             {
-                using Utilities.ELFModule elfModule = Utilities.OpenELFFile(module.FileName);
+                using ELFModule elfModule = ELFModule.OpenFile(fileName);
                 if (elfModule is not null)
                 {
-                    var generator = new ELFFileKeyGenerator(Tracer.Instance, elfModule, module.FileName);
-                    IEnumerable<SymbolStoreKey> keys = generator.GetKeys(KeyTypeFlags.IdentityKey);
-                    foreach (SymbolStoreKey key in keys)
+                    var generator = new ELFFileKeyGenerator(Tracer.Instance, elfModule, fileName);
+                    foreach (SymbolStoreKey key in generator.GetKeys(flags))
                     {
-                        if (moduleKey.Equals(key))
+                        if (fileKey.Equals(key))
                         {
-                            Trace.TraceInformation("DownloadELF: local file match {0}", module.FileName);
-                            return module.FileName;
+                            Trace.TraceInformation("DownloadELF: local file match {0}", fileName);
+                            return fileName;
                         }
                     }
                 }
             }
 
             // Now download the module from the symbol server if local file doesn't exists or doesn't have the right key
-            string downloadFilePath = DownloadFile(moduleKey);
+            string downloadFilePath = DownloadFile(fileKey);
             if (!string.IsNullOrEmpty(downloadFilePath))
             {
                 Trace.TraceInformation("DownloadELF: downloaded {0}", downloadFilePath);
@@ -649,42 +742,50 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         /// Finds or downloads the MachO module.
         /// </summary>
         /// <param name="module">module instance</param>
+        /// <param name="flags"></param>
         /// <returns>module path or null</returns>
-        private string DownloadMachO(IModule module)
+        private string DownloadMachO(IModule module, KeyTypeFlags flags)
         {
+            if ((flags & (KeyTypeFlags.IdentityKey | KeyTypeFlags.SymbolKey)) == 0)
+            {
+                throw new ArgumentException($"Key flag not supported {flags}");
+            }
+
             if (module.BuildId.IsDefaultOrEmpty)
             {
                 Trace.TraceWarning($"DownloadMachO: module {module.FileName} has no build id");
                 return null;
             }
 
-            SymbolStoreKey moduleKey = MachOFileKeyGenerator.GetKeys(KeyTypeFlags.IdentityKey, module.FileName, module.BuildId.ToArray(), symbolFile: false, symbolFileName: null).SingleOrDefault();
-            if (moduleKey is null)
+            SymbolStoreKey fileKey = MachOFileKeyGenerator.GetKeys(flags, module.FileName, module.BuildId.ToArray(), symbolFile: false, module.GetSymbolFileName()).SingleOrDefault();
+            if (fileKey is null)
             {
                 Trace.TraceWarning($"DownloadMachO: no index generated for module {module.FileName} ");
                 return null;
             }
 
-            if (File.Exists(module.FileName))
+            // Check if the file is local and the key matches the module
+            string fileName = fileKey.FullPathName;
+            if (File.Exists(fileName))
             {
-                using Utilities.MachOModule machOModule = Utilities.OpenMachOFile(module.FileName);
+                using MachOModule machOModule = MachOModule.OpenFile(fileName);
                 if (machOModule is not null)
                 {
-                    var generator = new MachOFileKeyGenerator(Tracer.Instance, machOModule, module.FileName);
-                    IEnumerable<SymbolStoreKey> keys = generator.GetKeys(KeyTypeFlags.IdentityKey);
+                    var generator = new MachOFileKeyGenerator(Tracer.Instance, machOModule, fileName);
+                    IEnumerable<SymbolStoreKey> keys = generator.GetKeys(flags);
                     foreach (SymbolStoreKey key in keys)
                     {
-                        if (moduleKey.Equals(key))
+                        if (fileKey.Equals(key))
                         {
-                            Trace.TraceInformation("DownloadMachO: local file match {0}", module.FileName);
-                            return module.FileName;
+                            Trace.TraceInformation("DownloadMachO: local file match {0}", fileName);
+                            return fileName;
                         }
                     }
                 }
             }
 
             // Now download the module from the symbol server if local file doesn't exists or doesn't have the right key
-            string downloadFilePath = DownloadFile(moduleKey);
+            string downloadFilePath = DownloadFile(fileKey);
             if (!string.IsNullOrEmpty(downloadFilePath))
             {
                 Trace.TraceInformation("DownloadMachO: downloaded {0}", downloadFilePath);
@@ -815,12 +916,17 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         public override string ToString()
         {
             StringBuilder sb = new StringBuilder();
-            Microsoft.SymbolStore.SymbolStores.SymbolStore symbolStore = _symbolStore;
-            while (symbolStore != null)
+            ForEachSymbolStore<Microsoft.SymbolStore.SymbolStores.SymbolStore>((symbolStore) => 
             {
-                sb.AppendLine(symbolStore.ToString());
-                symbolStore = symbolStore.BackingStore;
-            }
+                if (symbolStore is HttpSymbolStore httpSymbolStore)
+                {
+                    sb.AppendLine($"{httpSymbolStore} Timeout: {httpSymbolStore.Timeout.Minutes} RetryCount: {httpSymbolStore.RetryCount}");
+                }
+                else
+                {
+                    sb.AppendLine(symbolStore.ToString());
+                }
+            });
             return sb.ToString();
         }
 
@@ -874,6 +980,25 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
             return false;
         }
 
+        /// <summary>
+        /// Enumerates the symbol stores.
+        /// </summary>
+        /// <typeparam name="T">type of symbol store or SymbolStore for all</typeparam>
+        /// <param name="callback">called for each store found</param>
+        public void ForEachSymbolStore<T>(Action<T> callback)
+            where T : Microsoft.SymbolStore.SymbolStores.SymbolStore
+        {
+            Microsoft.SymbolStore.SymbolStores.SymbolStore symbolStore = _symbolStore;
+            while (symbolStore != null)
+            {
+                if (symbolStore is T store)
+                {
+                    callback(store);
+                }
+                symbolStore = symbolStore.BackingStore;
+            }
+        }
+
         /// <summary>
         /// Quick fix for Path.GetFileName which incorrectly handles Windows-style paths on Linux
         /// </summary>
index 71acaf5390fb515bdfa1093f48717ae5b2255119..2646ea90cfd2032403747a9629aa3a37f03dd209 100644 (file)
@@ -2,9 +2,6 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-using Microsoft.FileFormats;
-using Microsoft.FileFormats.ELF;
-using Microsoft.FileFormats.MachO;
 using Microsoft.FileFormats.PE;
 using System;
 using System.Diagnostics;
@@ -80,7 +77,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
                     var reader = new PEReader(stream);
                     if (reader.PEHeaders == null || reader.PEHeaders.PEHeader == null)
                     {
-                        Trace.TraceError($"OpenPEReader: PEReader invalid headers");
+                        Trace.TraceWarning($"OpenPEReader: PEReader invalid headers");
                         return null;
                     }
                     return reader;
@@ -93,94 +90,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
             return null;
         }
 
-        /// <summary>
-        /// Disposable ELFFile wrapper
-        /// </summary>
-        public class ELFModule : ELFFile, IDisposable
-        {
-            private readonly Stream _stream;
-
-            public ELFModule(Stream stream) :
-                base(new StreamAddressSpace(stream), position: 0, isDataSourceVirtualAddressSpace: false)
-            {
-                _stream = stream;
-            }
-
-            public void Dispose() => _stream.Dispose();
-        }
-
-        /// <summary>
-        /// Opens and returns an ELFFile instance from the local file path
-        /// </summary>
-        /// <param name="filePath">ELF file to open</param>
-        /// <returns>ELFFile instance or null</returns>
-        public static ELFModule OpenELFFile(string filePath)
-        {
-            Stream stream = TryOpenFile(filePath);
-            if (stream is not null)
-            {
-                try
-                {
-                    ELFModule elfModule = new (stream);
-                    if (!elfModule.IsValid())
-                    {
-                        Trace.TraceError($"OpenELFFile: not a valid file");
-                        return null;
-                    }
-                    return elfModule;
-                }
-                catch (Exception ex) when (ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException)
-                {
-                    Trace.TraceError($"OpenELFFile: exception {ex.Message}");
-                }
-            }
-            return null;
-        }
-
-        /// <summary>
-        /// Disposable MachOFile wrapper
-        /// </summary>
-        public class MachOModule : MachOFile, IDisposable
-        {
-            private readonly Stream _stream;
-
-            public MachOModule(Stream stream) :
-                base(new StreamAddressSpace(stream), position: 0, dataSourceIsVirtualAddressSpace: false)
-            {
-                _stream = stream;
-            }
-
-            public void Dispose() => _stream.Dispose();
-        }
-
-        /// <summary>
-        /// Opens and returns an MachOFile instance from the local file path
-        /// </summary>
-        /// <param name="filePath">MachO file to open</param>
-        /// <returns>MachOFile instance or null</returns>
-        public static MachOModule OpenMachOFile(string filePath)
-        {
-            Stream stream = TryOpenFile(filePath);
-            if (stream is not null)
-            {
-                try
-                {
-                    var machoModule = new MachOModule(stream);
-                    if (!machoModule.IsValid())
-                    {
-                        Trace.TraceError($"OpenMachOFile: not a valid file");
-                        return null;
-                    }
-                    return machoModule;
-                }
-                catch (Exception ex) when (ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException)
-                {
-                    Trace.TraceError($"OpenMachOFile: exception {ex.Message}");
-                }
-            }
-            return null;
-        }
-
         /// <summary>
         /// Attempt to open a file stream.
         /// </summary>
index 726f0b919526b52755a8a77d963952792e6c7123..0e8f467703ebefec726192573c4fd2a1a2552c60 100644 (file)
@@ -29,6 +29,12 @@ namespace Microsoft.Diagnostics.DebugServices
         /// <param name="value"></param>
         void WriteError(string value);
 
+        /// <summary>Writes Debugger Markup Language (DML) markup text.</summary>
+        void WriteDml(string text);
+
+        /// <summary>Gets whether <see cref="WriteDml"/> is supported.</summary>
+        bool SupportsDml { get; }
+
         /// <summary>
         /// Cancellation token for current command
         /// </summary>
index 3f4746cd77a49fa79e0d7cc56ca8d40bce826247..b40badf3164eabf4d1525969b4453fa5f6925271 100644 (file)
@@ -74,18 +74,29 @@ namespace Microsoft.Diagnostics.DebugServices
         bool? IsFileLayout { get; }
 
         /// <summary>
-        /// PDB information for Windows PE modules (managed or native).
+        /// Returns PDB information for Windows PE modules (managed or native).
         /// </summary>
-        IEnumerable<PdbFileInfo> PdbFileInfos { get; }
+        IEnumerable<PdbFileInfo> GetPdbFileInfos();
 
         /// <summary>
-        /// Version information for Window PE modules (managed or native). 
+        /// Returns the Linux or MacOS symbol file name.
         /// </summary>
-        VersionData VersionData { get; }
+        string GetSymbolFileName();
 
         /// <summary>
-        /// This is the file version string containing the build version and commit id.
+        /// Returns the version information for the modules. 
         /// </summary>
-        string VersionString { get; }
+        VersionData GetVersionData();
+
+        /// <summary>
+        /// Returns the file version string containing the build version and commit id.
+        /// </summary>
+        string GetVersionString();
+
+        /// <summary>
+        /// Loads or downloads the module's symbol file and registers it with the underlying host debugger.
+        /// </summary>
+        /// <returns>the symbol file name</returns>
+        string LoadSymbols();
     }
 }
index 4900510cc548073dfba32c8c5c6bbf688a9ce3f0..db33607979b824878dfd402df92c8b5de428feb4 100644 (file)
@@ -11,16 +11,6 @@ namespace Microsoft.Diagnostics.DebugServices
 {
     public interface ISymbolService
     {
-        /// <summary>
-        /// Symbol file reader instance
-        /// </summary>
-        public class SymbolFile : IDisposable
-        {
-            public virtual void Dispose() 
-            { 
-            }
-        }
-
         /// <summary>
         /// Invoked when anything changes in the symbol service (adding servers, caches, or directories, clearing store, etc.)
         /// </summary>
@@ -40,6 +30,21 @@ namespace Microsoft.Diagnostics.DebugServices
         /// </summary>
         string DefaultSymbolCache { get; set; }
 
+        /// <summary>
+        /// The time out in minutes passed to the HTTP symbol store when not overridden in AddSymbolServer.
+        /// </summary>
+        int DefaultTimeout { get; set; }
+
+        /// <summary>
+        /// The retry count passed to the HTTP symbol store when not overridden in AddSymbolServer.
+        /// </summary>
+        int DefaultRetryCount { get; set; }
+
+        /// <summary>
+        /// Reset any HTTP symbol stores marked with a client failure
+        /// </summary>
+        void Reset();
+
         /// <summary>
         /// Parses the Windows debugger symbol path (srv*, cache*, etc.).
         /// </summary>
@@ -53,10 +58,11 @@ namespace Microsoft.Diagnostics.DebugServices
         /// <param name="msdl">if true, use the public Microsoft server</param>
         /// <param name="symweb">if true, use symweb internal server and protocol (file.ptr)</param>
         /// <param name="symbolServerPath">symbol server url (optional)</param>
-        /// <param name="authToken"></param>
-        /// <param name="timeoutInMinutes">symbol server timeout in minutes (optional)</param>
+        /// <param name="authToken">PAT for secure symbol server (optional)</param>
+        /// <param name="timeoutInMinutes">symbol server timeout in minutes (optional uses <see cref="DefaultTimeout"/> if null)</param>
+        /// <param name="retryCount">number of retries (optional uses <see cref="DefaultRetryCount"/> if null)</param>
         /// <returns>if false, failure</returns>
-        bool AddSymbolServer(bool msdl, bool symweb, string symbolServerPath, string authToken, int timeoutInMinutes);
+        bool AddSymbolServer(bool msdl, bool symweb, string symbolServerPath = null, string authToken = null, int? timeoutInMinutes = null, int? retryCount = null);
 
         /// <summary>
         /// Add cache path to symbol search path
@@ -76,11 +82,18 @@ namespace Microsoft.Diagnostics.DebugServices
         void DisableSymbolStore();
 
         /// <summary>
-        /// Downloads module file
+        /// Downloads the module file
+        /// </summary>
+        /// <param name="module">module interface</param>
+        /// <returns>module path or null</returns>
+        string DownloadModuleFile(IModule module);
+
+        /// <summary>
+        /// Downloads the symbol file for module
         /// </summary>
         /// <param name="module">module interface</param>
         /// <returns>module path or null</returns>
-        string DownloadModule(IModule module);
+        string DownloadSymbolFile(IModule module);
         
         /// <summary>
         /// Download a file from the symbol stores/server.
index 2674d567ac534281aa40f4969a2c5c298302e180..bf65e9d58c2cfcdf22481c95e9cb3290870b9e3f 100644 (file)
@@ -125,6 +125,7 @@ namespace Microsoft.Diagnostics.DebugServices
         {
             Debug.Assert(address != 0);
             Debug.Assert(size != 0);
+            Debug.Assert((address & ~memoryService.SignExtensionMask()) == 0);
             return new TargetStream(memoryService, address, size);
         }
 
index 435e38402926a820dd8d9ece701d530e996dbc55..35fabd1ebe4bead9c86c3365a570b352af00a962 100644 (file)
@@ -49,7 +49,7 @@ namespace Microsoft.Diagnostics.ExtensionCommands
                         VersionData version = null;
                         try
                         {
-                            version = ModuleService.GetModuleFromBaseAddress(module.ImageBase).VersionData;
+                            version = ModuleService.GetModuleFromBaseAddress(module.ImageBase).GetVersionData();
                         }
                         catch (DiagnosticsException)
                         {
diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs
new file mode 100644 (file)
index 0000000..b5d2c54
--- /dev/null
@@ -0,0 +1,1187 @@
+// 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.
+
+#nullable enable
+using Microsoft.Diagnostics.DebugServices;
+using Microsoft.Diagnostics.Runtime;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+
+namespace Microsoft.Diagnostics.ExtensionCommands
+{
+    [Command(Name = CommandName, Help = "Displays information about async \"stacks\" on the garbage-collected heap.")]
+    public sealed class DumpAsyncCommand : ExtensionCommandBase
+    {
+        /// <summary>The name of the command.</summary>
+        private const string CommandName = "dumpasync";
+
+        /// <summary>Indent width.</summary>
+        private const int TabWidth = 2;
+        /// <summary>The command invocation syntax when used in Debugger Markup Language (DML) commands.</summary>
+        private const string DmlCommandInvoke = $"!{CommandName}";
+
+        /// <summary>The help text to render when asked for help.</summary>
+        private static readonly string s_detailedHelpText =
+            $"Usage: {CommandName} [--stats] [--coalesce] [--address <object address>] [--methodtable <mt address>] [--type <partial type name>] [--tasks] [--completed] [--fields]" + Environment.NewLine +
+            Environment.NewLine +
+            "Displays information about async \"stacks\" on the garbage-collected heap. Stacks" + Environment.NewLine +
+            "are synthesized by finding all task objects (including async state machine box" + Environment.NewLine +
+            "objects) on the GC heap and chaining them together based on continuations." + Environment.NewLine +
+            Environment.NewLine +
+            "Options:" + Environment.NewLine +
+            "  --stats        Summarize all async frames found rather than showing detailed stacks." + Environment.NewLine +
+            "  --coalesce     Coalesce stacks and portions of stacks that are the same." + Environment.NewLine +
+            "  --address      Only show stacks that include the object with the specified address." + Environment.NewLine +
+            "  --methodtable  Only show stacks that include objects with the specified method table." + Environment.NewLine +
+            "  --type         Only show stacks that include objects whose type includes the specified name in its name." + Environment.NewLine +
+            "  --tasks        Include stacks that contain only non-state machine task objects." + Environment.NewLine +
+            "  --completed    Include completed tasks in stacks." + Environment.NewLine +
+            "  --fields       Show fields for each async stack frame." + Environment.NewLine +
+            Environment.NewLine +
+            "Examples:" + Environment.NewLine +
+            $"Summarize all async frames associated with a specific method table address:        !{CommandName} --stats --methodtable 0x00007ffbcfbe0970" + Environment.NewLine +
+            $"Show all stacks coalesced by common frames:                                        !{CommandName} --coalesce" + Environment.NewLine +
+            $"Show each stack that includes \"ReadAsync\":                                         !{CommandName} --type ReadAsync" + Environment.NewLine +
+            $"Show each stack that includes an object at a specific address, and include fields: !{CommandName} --address 0x000001264adce778 --fields";
+
+        /// <summary>Gets the runtime for the process.  Set by the command framework.</summary>
+        public ClrRuntime? Runtime { get; set; }
+
+        /// <summary>Gets whether to only show stacks that include the object with the specified address.</summary>
+        [Option(Name = "--address", Aliases = new string[] { "-addr" }, Help = "Only show stacks that include the object with the specified address.")]
+        public ulong? ObjectAddress { get; set; }
+
+        /// <summary>Gets whether to only show stacks that include objects with the specified method table.</summary>
+        [Option(Name = "--methodtable", Aliases = new string[] { "-mt" }, Help = "Only show stacks that include objects with the specified method table.")]
+        public ulong? MethodTableAddress { get; set; }
+
+        /// <summary>Gets whether to only show stacks that include objects whose type includes the specified name in its name.</summary>
+        [Option(Name = "--type", Help = "Only show stacks that include objects whose type includes the specified name in its name.")]
+        public string? NameSubstring { get; set; }
+
+        /// <summary>Gets whether to include stacks that contain only non-state machine task objects.</summary>
+        [Option(Name = "--tasks", Aliases = new string[] { "-t" }, Help = "Include stacks that contain only non-state machine task objects.")]
+        public bool IncludeTasks { get; set; }
+
+        /// <summary>Gets whether to include completed tasks in stacks.</summary>
+        [Option(Name = "--completed", Aliases = new string[] { "-c" }, Help = "Include completed tasks in stacks.")]
+        public bool IncludeCompleted { get; set; }
+
+        /// <summary>Gets whether to show state machine fields for every async stack frame that has them.</summary>
+        [Option(Name = "--fields", Aliases = new string[] { "-f" }, Help = "Show state machine fields for every async stack frame that has them.")]
+        public bool DisplayFields { get; set; }
+
+        /// <summary>Gets whether to summarize all async frames found rather than showing detailed stacks.</summary>
+        [Option(Name = "--stats", Help = "Summarize all async frames found rather than showing detailed stacks.")]
+        public bool Summarize { get; set; }
+
+        /// <summary>Gets whether to coalesce stacks and portions of stacks that are the same.</summary>
+        [Option(Name = "--coalesce", Help = "Coalesce stacks and portions of stacks that are the same.")]
+        public bool CoalesceStacks { get; set; }
+
+        /// <summary>Invokes the command.</summary>
+        public override void ExtensionInvoke()
+        {
+            ClrRuntime? runtime = Runtime;
+            if (runtime is null)
+            {
+                WriteLineError("Unable to access runtime.");
+                return;
+            }
+
+            ClrHeap heap = runtime.Heap;
+            if (!heap.CanWalkHeap)
+            {
+                WriteLineError("Unable to examine the heap.");
+                return;
+            }
+
+            ClrType? taskType = runtime.BaseClassLibrary.GetTypeByName("System.Threading.Tasks.Task");
+            if (taskType is null)
+            {
+                WriteLineError("Unable to find required type.");
+                return;
+            }
+
+            ClrStaticField? taskCompletionSentinelType = taskType.GetStaticFieldByName("s_taskCompletionSentinel");
+
+            ClrObject taskCompletionSentinel = default;
+
+            if (taskCompletionSentinelType is not null)
+            {
+                Debug.Assert(taskCompletionSentinelType.IsObjectReference);
+                taskCompletionSentinel = taskCompletionSentinelType.ReadObject(runtime.BaseClassLibrary.AppDomain);
+            }
+
+            // Enumerate the heap, gathering up all relevant async-related objects.
+            Dictionary<ClrObject, AsyncObject> objects = CollectObjects();
+
+            // Render the data according to the options specified.
+            if (Summarize)
+            {
+                RenderStats();
+            }
+            else if (CoalesceStacks)
+            {
+                RenderCoalescedStacks();
+            }
+            else
+            {
+                RenderStacks();
+            }
+            return;
+
+            // <summary>Group frames and summarize how many of each occurred.</summary>
+            void RenderStats()
+            {
+                // Enumerate all of the "frames", and create a mapping from a rendering of that
+                // frame to its associated type and how many times that frame occurs.
+                var typeCounts = new Dictionary<string, (ClrType Type, int Count)>();
+                foreach (KeyValuePair<ClrObject, AsyncObject> pair in objects)
+                {
+                    ClrObject obj = pair.Key;
+                    if (obj.Type is null)
+                    {
+                        continue;
+                    }
+
+                    string description = Describe(obj);
+
+                    if (!typeCounts.TryGetValue(description, out (ClrType Type, int Count) value))
+                    {
+                        value = (obj.Type, 0);
+                    }
+                    
+                    value.Count++;
+                    typeCounts[description] = value;
+                }
+
+                // Render one line per frame.
+                WriteHeaderLine($"{"MT",-16} {"Count",-8} Type");
+                foreach (KeyValuePair<string, (ClrType Type, int Count)> entry in typeCounts.OrderByDescending(e => e.Value.Count))
+                {
+                    WriteMethodTable(entry.Value.Type.MethodTable, asyncObject: true);
+                    WriteLine($" {entry.Value.Count,-8:N0} {entry.Key}");
+                }
+            }
+
+            // <summary>Group stacks at each frame in order to render a tree of coalesced stacks.</summary>
+            void RenderCoalescedStacks()
+            {
+                // Find all stacks to include.
+                var startingList = new List<ClrObject>();
+                foreach (KeyValuePair<ClrObject, AsyncObject> entry in objects)
+                {
+                    Console.CancellationToken.ThrowIfCancellationRequested();
+
+                    AsyncObject obj = entry.Value;
+                    if (obj.TopLevel && ShouldIncludeStack(obj))
+                    {
+                        startingList.Add(entry.Key);
+                    }
+                }
+
+                // If we found any, render them.
+                if (startingList.Count > 0)
+                {
+                    RenderLevel(startingList, 0);
+                }
+
+                // <summary>Renders the next level of frames for coalesced stacks.</summary>
+                void RenderLevel(List<ClrObject> frames, int depth)
+                {
+                    Console.CancellationToken.ThrowIfCancellationRequested();
+                    List<ClrObject> nextLevel = new List<ClrObject>();
+
+                    // Grouping function.  We want to treat all objects that render the same as the same entity.
+                    // For async state machines, we include the await state, both because we want it to render
+                    // and because we want to see state machines at different positions as part of different groups.
+                    Func<ClrObject, string> groupBy = o =>
+                    {
+                        string description = Describe(o);
+                        if (objects.TryGetValue(o, out AsyncObject asyncObject) && asyncObject.IsStateMachine)
+                        {
+                            description = $"({asyncObject.AwaitState}) {description}";
+                        }
+                        return description;
+                    };
+
+                    // Group all of the frames, rendering each group as a single line with a count.
+                    // Then recur for each.
+                    int stackId = 1;
+                    foreach (IGrouping<string, ClrObject> group in frames.GroupBy(groupBy).OrderByDescending(g => g.Count()))
+                    {
+                        int count = group.Count();
+                        Debug.Assert(count > 0);
+
+                        // For top-level frames, write out a header.
+                        if (depth == 0)
+                        {
+                            WriteHeaderLine($"STACKS {stackId++}");
+                        }
+
+                        // Write out the count and frame.
+                        Write($"{Tabs(depth)}[{count}] ");
+                        WriteMethodTable(group.First().Type?.MethodTable ?? 0, asyncObject: true);
+                        WriteLine($" {group.Key}");
+
+                        // Gather up all of the next level of frames.
+                        nextLevel.Clear();
+                        foreach (ClrObject next in group)
+                        {
+                            if (objects.TryGetValue(next, out AsyncObject asyncObject))
+                            {
+                                // Note that the merging of multiple continuations can lead to numbers increasing at a particular
+                                // level of the coalesced stacks.  It's not clear there's a better answer.
+                                nextLevel.AddRange(asyncObject.Continuations);
+                            }
+                        }
+
+                        // If we found any, recur.
+                        if (nextLevel.Count != 0)
+                        {
+                            RenderLevel(nextLevel, depth + 1);
+                        }
+
+                        if (depth == 0)
+                        {
+                            WriteLine("");
+                        }
+                    }
+                }
+            }
+
+            // <summary>Render each stack of frames.</summary>
+            void RenderStacks()
+            {
+                var stack = new Stack<(AsyncObject AsyncObject, int Depth)>();
+
+                // Find every top-level object (ones that nothing else has as a continuation) and output
+                // a stack starting from each.
+                int stackId = 1;
+                foreach (KeyValuePair<ClrObject, AsyncObject> entry in objects)
+                {
+                    Console.CancellationToken.ThrowIfCancellationRequested();
+                    AsyncObject top = entry.Value;
+                    if (!top.TopLevel || !ShouldIncludeStack(top))
+                    {
+                        continue;
+                    }
+
+                    int depth = 0;
+
+                    WriteHeaderLine($"STACK {stackId++}");
+
+                    // If the top-level frame is an async method that's paused at an await, it must be waiting on
+                    // something.  Try to synthesize a frame to represent that thing, just to provide a little more information.
+                    if (top.IsStateMachine && top.AwaitState >= 0 && !IsCompleted(top.TaskStateFlags) &&
+                        top.StateMachine is IAddressableTypedEntity stateMachine &&
+                        stateMachine.Type is not null)
+                    {
+                        // Short of parsing the method's IL, we don't have a perfect way to know which awaiter field
+                        // corresponds to the current await state, as awaiter fields are shared across all awaits that
+                        // use the same awaiter type.  We instead employ a heuristic.  If the await state is 0, the
+                        // associated field will be the first one (<>u__1); even if other awaits share it, it's fine
+                        // to use.  Similarly, if there's only one awaiter field, we know that must be the one being
+                        // used.  In all other situations, we can't know which of the multiple awaiter fields maps
+                        // to the await state, so we instead employ a heuristic of looking for one that's non-zero.
+                        // The C# compiler zero's out awaiter fields when it's done with them, so if we find an awaiter
+                        // field with any non-zero bytes, it must be the one in use.  This can have false negatives,
+                        // as it's perfectly valid for an awaiter to be all zero bytes, but it's better than nothing.
+
+                        if ((top.AwaitState == 0) ||
+                            stateMachine.Type.Fields.Count(f => f.Name is null || f.Name.StartsWith("<>u__", StringComparison.Ordinal) == true) == 1) // if the name is null, we have to assume it's an awaiter
+                        {
+                            if (stateMachine.Type.GetFieldByName("<>u__1") is ClrInstanceField field &&
+                                TrySynthesizeAwaiterFrame(field))
+                            {
+                                depth++;
+                            }
+                        }
+                        else
+                        {
+                            foreach (ClrInstanceField field in stateMachine.Type.Fields)
+                            {
+                                // Look for awaiter fields.  This is the naming convention employed by the C# compiler.
+                                if (field.Name?.StartsWith("<>u__") == true)
+                                {
+                                    if (field.IsObjectReference)
+                                    {
+                                        if (stateMachine.ReadObjectField(field.Name) is ClrObject { IsNull: false } awaiter)
+                                        {
+                                            if (TrySynthesizeAwaiterFrame(field))
+                                            {
+                                                depth++;
+                                            }
+                                            break;
+                                        }
+                                    }
+                                    else if (field.IsValueType &&
+                                        stateMachine.ReadValueTypeField(field.Name) is ClrValueType { IsValid: true } awaiter &&
+                                        awaiter.Type is not null)
+                                    {
+                                        byte[] awaiterBytes = new byte[awaiter.Type.StaticSize - (runtime.DataTarget!.DataReader.PointerSize * 2)];
+                                        if (runtime.DataTarget!.DataReader.Read(awaiter.Address, awaiterBytes) == awaiterBytes.Length && !AllZero(awaiterBytes))
+                                        {
+                                            if (TrySynthesizeAwaiterFrame(field))
+                                            {
+                                                depth++;
+                                            }
+                                            break;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+
+                        // <summary>Writes out a frame for the specified awaiter field, if possible.</summary>
+                        bool TrySynthesizeAwaiterFrame(ClrInstanceField field)
+                        {
+                            if (field?.Name is string name)
+                            {
+                                if (field.IsObjectReference)
+                                {
+                                    ClrObject awaiter = stateMachine.ReadObjectField(name);
+                                    if (awaiter.Type is not null)
+                                    {
+                                        Write("<< Awaiting: ");
+                                        WriteAddress(awaiter.Address, asyncObject: false);
+                                        Write(" ");
+                                        WriteMethodTable(awaiter.Type.MethodTable, asyncObject: false);
+                                        Write(awaiter.Type.Name);
+                                        WriteLine(" >>");
+                                        return true;
+                                    }
+                                }
+                                else if (field.IsValueType)
+                                {
+                                    ClrValueType awaiter = stateMachine.ReadValueTypeField(name);
+                                    if (awaiter.Type is not null)
+                                    {
+                                        Write("<< Awaiting: ");
+                                        WriteValueTypeAddress(awaiter.Address, awaiter.Type.MethodTable);
+                                        Write(" ");
+                                        WriteMethodTable(awaiter.Type.MethodTable, asyncObject: false);
+                                        Write($" {awaiter.Type.Name}");
+                                        WriteLine(" >>");
+                                        return true;
+                                    }
+                                }
+                            }
+
+                            return false;
+                        }
+                    }
+
+                    // Push the root node onto the stack to start the iteration.  Then as long as there are nodes left
+                    // on the stack, pop the next, render it, and push any continuations it may have back onto the stack.
+                    Debug.Assert(stack.Count == 0);
+                    stack.Push((top, depth));
+                    while (stack.Count > 0)
+                    {
+                        (AsyncObject frame, depth) = stack.Pop();
+
+                        Write($"{Tabs(depth)}");
+                        WriteAddress(frame.Object.Address, asyncObject: true);
+                        Write(" ");
+                        WriteMethodTable(frame.Object.Type?.MethodTable ?? 0, asyncObject: true);
+                        Write($" {(frame.IsStateMachine ? $"({frame.AwaitState})" : $"({DescribeTaskFlags(frame.TaskStateFlags)})")} {Describe(frame.Object)}");
+                        WriteCodeLink(frame.NativeCode);
+                        WriteLine("");
+
+                        if (DisplayFields)
+                        {
+                            RenderFields(frame.StateMachine ?? frame.Object, depth + 4); // +4 for extra indent for fields
+                        }
+
+                        foreach (ClrObject continuation in frame.Continuations)
+                        {
+                            if (objects.TryGetValue(continuation, out AsyncObject asyncContinuation))
+                            {
+                                stack.Push((asyncContinuation, depth + 1));
+                            }
+                            else
+                            {
+                                string state = TryGetTaskStateFlags(continuation, out int flags) ? DescribeTaskFlags(flags) : "";
+                                Write($"{Tabs(depth + 1)}");
+                                WriteAddress(continuation.Address, asyncObject: true);
+                                Write(" ");
+                                WriteMethodTable(continuation.Type?.MethodTable ?? 0, asyncObject: true);
+                                WriteLine($" ({state}) {Describe(continuation)}");
+                            }
+                        }
+                    }
+
+                    WriteLine("");
+                }
+            }
+
+            // <summary>Determine whether the stack rooted in this object should be rendered.</summary>
+            bool ShouldIncludeStack(AsyncObject obj)
+            {
+                // We want to render the stack for this object once we find any node that should be
+                // included based on the criteria specified as arguments _and_ if the include tasks
+                // options wasn't specified, once we find any node that's an async state machine.
+                // That way, we scope the output down to just stacks that contain something the
+                // user is interested in seeing.
+                bool sawShouldInclude = false;
+                bool sawStateMachine = IncludeTasks;
+
+                var stack = new Stack<AsyncObject>();
+                stack.Push(obj);
+                while (stack.Count > 0)
+                {
+                    obj = stack.Pop();
+                    sawShouldInclude |= obj.IncludeInOutput;
+                    sawStateMachine |= obj.IsStateMachine;
+
+                    if (sawShouldInclude && sawStateMachine)
+                    {
+                        return true;
+                    }
+
+                    foreach (ClrObject continuation in obj.Continuations)
+                    {
+                        if (objects.TryGetValue(continuation, out AsyncObject asyncContinuation))
+                        {
+                            stack.Push(asyncContinuation);
+                        }
+                    }
+                }
+
+                return false;
+            }
+
+            // <summary>Outputs a line of information for each instance field on the object.</summary>
+            void RenderFields(IAddressableTypedEntity? obj, int depth)
+            {
+                if (obj is not null)
+                {
+                    string depthTab = new string(' ', depth * TabWidth);
+
+                    WriteHeaderLine($"{depthTab}{"Address",16} {"MT",16} {"Type",-32} {"Value",16} Name");
+                    foreach (ClrInstanceField field in obj.Type.Fields)
+                    {
+                        if (field.Type is not null)
+                        {
+                            Write($"{depthTab}");
+                            if (field.IsObjectReference)
+                            {
+                                ClrObject objRef = field.ReadObject(obj.Address, obj.Type.IsValueType);
+                                WriteAddress(objRef.Address, asyncObject: false);
+                            }
+                            else
+                            {
+                                WriteValueTypeAddress(field.GetAddress(obj.Address, obj.Type.IsValueType), field.Type.MethodTable);
+                            }
+                            Write(" ");
+                            WriteMethodTable(field.Type.MethodTable, asyncObject: false);
+                            WriteLine($" {Truncate(field.Type.Name, 32),-32} {Truncate(GetDisplay(obj, field).ToString(), 16),16} {field.Name}");
+                        }
+                    }
+                }
+            }
+
+            // <summary>Gets a printable description for the specified object.</summary>
+            string Describe(ClrObject obj)
+            {
+                // Default the description to the type name.
+                string description = obj.Type.Name;
+
+                if (IsStateMachineBox(obj.Type))
+                {
+                    // Remove the boilerplate box type from the name.
+                    int pos = description.IndexOf("StateMachineBox<", StringComparison.Ordinal);
+                    if (pos >= 0)
+                    {
+                        ReadOnlySpan<char> slice = description.AsSpan(pos + "StateMachineBox<".Length);
+                        slice = slice.Slice(0, slice.Length - 1); // remove trailing >
+                        description = slice.ToString();
+                    }
+                }
+                else if (TryGetValidObjectField(obj, "m_action", out ClrObject taskDelegate))
+                {
+                    // If we can figure out what the task's delegate points to, append the method signature.
+                    if (TryGetMethodFromDelegate(runtime, taskDelegate, out ClrMethod? method))
+                    {
+                        description = $"{description} {{{method!.Signature}}}";
+                    }
+                }
+                else if (obj.Address != 0 && taskCompletionSentinel.Address == obj.Address)
+                {
+                    description = "TaskCompletionSentinel";
+                }
+
+                return description;
+            }
+
+            // <summary>Determines whether the specified object is of interest to the user based on their criteria provided as command arguments.</summary>
+            bool IncludeInOutput(ClrObject obj)
+            {
+                if (ObjectAddress is ulong addr && obj.Address != addr)
+                {
+                    return false;
+                }
+
+                if (MethodTableAddress is ulong mt && obj.Type.MethodTable != mt)
+                {
+                    return false;
+                }
+
+                if (NameSubstring is not null && !obj.Type.Name.Contains(NameSubstring))
+                {
+                    return false;
+                }
+
+                return true;
+            }
+
+            // <summary>Finds all of the relevant async-related objects on the heap.</summary>
+            Dictionary<ClrObject, AsyncObject> CollectObjects()
+            {
+                var found = new Dictionary<ClrObject, AsyncObject>();
+
+                // Enumerate the heap, looking for all relevant objects.
+                foreach (ClrObject obj in heap.EnumerateObjects())
+                {
+                    Console.CancellationToken.ThrowIfCancellationRequested();
+
+                    if (!obj.IsValid || obj.Type is null)
+                    {
+                        Trace.TraceError($"(Skipping invalid object {obj})");
+                        continue;
+                    }
+
+                    // Skip objects too small to be state machines or tasks, simply to help with performance.
+                    if (obj.Size <= 24)
+                    {
+                        continue;
+                    }
+
+                    // We only care about task-related objects (all boxes are tasks).
+                    if (!IsTask(obj.Type))
+                    {
+                        continue;
+                    }
+
+                    // This is currently working around an issue that result in enumerating segments multiple times in 6.0 runtimes
+                    // up to 6.0.5. The PR that fixes it is https://github.com/dotnet/runtime/pull/67995, but we have this here for back compat.
+                    if (found.ContainsKey(obj))
+                    {
+                        continue;
+                    }
+
+                    // If we're only going to render a summary (which only considers objects individually and not
+                    // as part of chains) and if this object shouldn't be included, we don't need to do anything more.
+                    if (Summarize &&
+                        (!IncludeInOutput(obj) || (!IncludeTasks && !IsStateMachineBox(obj.Type))))
+                    {
+                        continue;
+                    }
+
+                    // If we couldn't get state flags for the task, something's wrong; skip it.
+                    if (!TryGetTaskStateFlags(obj, out int taskStateFlags))
+                    {
+                        continue;
+                    }
+
+                    // If we're supposed to ignore already completed tasks and this one is completed, skip it.
+                    if (!IncludeCompleted && IsCompleted(taskStateFlags))
+                    {
+                        continue;
+                    }
+
+                    // Gather up the necessary data for the object and store it.
+                    AsyncObject result = new()
+                    {
+                        Object = obj,
+                        IsStateMachine = IsStateMachineBox(obj.Type),
+                        IncludeInOutput = IncludeInOutput(obj),
+                        TaskStateFlags = taskStateFlags,
+                    };
+
+                    if (result.IsStateMachine && TryGetStateMachine(obj, out result.StateMachine))
+                    {
+                        bool gotState = TryRead(result.StateMachine!, "<>1__state", out result.AwaitState);
+                        Debug.Assert(gotState);
+
+                        if (result.StateMachine?.Type is ClrType stateMachineType)
+                        {
+                            foreach (ClrMethod method in stateMachineType.Methods)
+                            {
+                                if (method.NativeCode != ulong.MaxValue)
+                                {
+                                    result.NativeCode = method.NativeCode;
+                                    if (method.Name == "MoveNext")
+                                    {
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                    if (TryGetContinuation(obj, out ClrObject continuation))
+                    {
+                        AddContinuation(continuation, result.Continuations);
+                    }
+
+                    found.Add(obj, result);
+                }
+
+                // Mark off objects that are referenced by others and thus aren't top level
+                foreach (KeyValuePair<ClrObject, AsyncObject> entry in found)
+                {
+                    foreach (ClrObject continuation in entry.Value.Continuations)
+                    {
+                        if (found.TryGetValue(continuation, out AsyncObject asyncContinuation))
+                        {
+                            asyncContinuation.TopLevel = false;
+                        }
+                    }
+                }
+
+                return found;
+            }
+
+            // <summary>Adds the continuation into the list of continuations.</summary>
+            // <remarks>
+            // If the continuation is actually a List{object}, enumerate the list to add
+            // each of the individual continuations to the continuations list.
+            // </remarks>
+            void AddContinuation(ClrObject continuation, List<ClrObject> continuations)
+            {
+                if (continuation.Type.Name.StartsWith("System.Collections.Generic.List<", StringComparison.Ordinal))
+                {
+                    if (continuation.Type.GetFieldByName("_items") is ClrInstanceField itemsField)
+                    {
+                        ClrObject itemsObj = itemsField.ReadObject(continuation.Address, interior: false);
+                        if (!itemsObj.IsNull)
+                        {
+                            ClrArray items = itemsObj.AsArray();
+                            if (items.Rank == 1)
+                            {
+                                for (int i = 0; i < items.Length; i++)
+                                {
+                                    if (items.GetObjectValue(i) is ClrObject { IsValid: true } c)
+                                    {
+                                        continuations.Add(ResolveContinuation(c));
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    continuations.Add(continuation);
+                }
+            }
+
+            // <summary>Tries to get the object contents of a Task's continuations field</summary>
+            bool TryGetContinuation(ClrObject obj, out ClrObject continuation)
+            {
+                if (obj.Type.GetFieldByName("m_continuationObject") is ClrInstanceField continuationObjectField &&
+                    continuationObjectField.ReadObject(obj.Address, interior: false) is ClrObject { IsValid: true } continuationObject)
+                {
+                    continuation = ResolveContinuation(continuationObject);
+                    return true;
+                }
+
+                continuation = default;
+                return false;
+            }
+
+            // <summary>Analyzes a continuation object to try to follow to the actual continuation target.</summary>
+            ClrObject ResolveContinuation(ClrObject continuation)
+            {
+                ClrObject tmp;
+
+                // If the continuation is an async method box, there's nothing more to resolve.
+                if (IsTask(continuation.Type) && IsStateMachineBox(continuation.Type))
+                {
+                    return continuation;
+                }
+
+                // If it's a standard task continuation, get its task field.
+                if (TryGetValidObjectField(continuation, "m_task", out tmp))
+                {
+                    return tmp;
+                }
+
+                // If it's storing an action wrapper, try to follow to that action's target.
+                if (TryGetValidObjectField(continuation, "m_action", out tmp))
+                {
+                    continuation = tmp;
+                }
+
+                // If we now have an Action, try to follow through to the delegate's target.
+                if (TryGetValidObjectField(continuation, "_target", out tmp))
+                {
+                    continuation = tmp;
+
+                    // In some cases, the delegate's target might be a ContinuationWrapper, in which case we want to unwrap that as well.
+                    if (continuation.Type?.Name == "System.Runtime.CompilerServices.AsyncMethodBuilderCore+ContinuationWrapper" &&
+                        TryGetValidObjectField(continuation, "_continuation", out tmp))
+                    {
+                        continuation = tmp;
+                        if (TryGetValidObjectField(continuation, "_target", out tmp))
+                        {
+                            continuation = tmp;
+                        }
+                    }
+                }
+
+                // Use whatever we ended with.
+                return continuation;
+            }
+
+            // <summary>Determines if a type is or is derived from Task.</summary>
+            bool IsTask(ClrType? type)
+            {
+                while (type is not null)
+                {
+                    if (type.MetadataToken == taskType.MetadataToken &&
+                        type.Module == taskType.Module)
+                    {
+                        return true;
+                    }
+
+                    type = type.BaseType;
+                }
+
+                return false;
+            }
+        }
+
+        /// <summary>Writes out a header line.  If DML is supported, this will be bolded.</summary>
+        private void WriteHeaderLine(string text)
+        {
+            if (Console.SupportsDml)
+            {
+                Console.WriteDml($"<b>{text}</b>{Environment.NewLine}");
+            }
+            else
+            {
+                WriteLine(text);
+            }
+        }
+
+        /// <summary>Writes out a method table address.  If DML is supported, this will be linked.</summary>
+        /// <param name="mt">The method table address.</param>
+        /// <param name="asyncObject">
+        /// true if this is an async-related object; otherwise, false.  If true and if DML is supported,
+        /// a link to dumpasync will be generated.  If false and if DML is supported, a link to dumpmt
+        /// will be generated.
+        /// </param>
+        private void WriteMethodTable(ulong mt, bool asyncObject)
+        {
+            string completed = IncludeCompleted ? "--completed" : "";
+            string tasks = IncludeTasks ? "--tasks" : "";
+
+            switch ((Console.SupportsDml, asyncObject, IntPtr.Size))
+            {
+                case (false, _, 4):
+                    Console.Write($"{mt,16:x8}");
+                    break;
+
+                case (false, _, 8):
+                    Console.Write($"{mt:x16}");
+                    break;
+
+                case (true, true, 4):
+                    Console.WriteDml($"<exec cmd=\"{DmlCommandInvoke} --methodtable 0x{mt:x8} {tasks} {completed}\">{mt,16:x8}</exec>");
+                    break;
+
+                case (true, true, 8):
+                    Console.WriteDml($"<exec cmd=\"{DmlCommandInvoke} --methodtable 0x{mt:x16} {tasks} {completed}\">{mt:x16}</exec>");
+                    break;
+
+                case (true, false, 4):
+                    Console.WriteDml($"<exec cmd=\"!DumpMT /d 0x{mt:x8}\">{mt,16:x8}</exec>");
+                    break;
+
+                case (true, false, 8):
+                    Console.WriteDml($"<exec cmd=\"!DumpMT /d 0x{mt:x16}\">{mt:x16}</exec>");
+                    break;
+            }
+        }
+
+        /// <summary>Writes out an object address.  If DML is supported, this will be linked.</summary>
+        /// <param name="addr">The object address.</param>
+        /// <param name="asyncObject">
+        /// true if this is an async-related object; otherwise, false.  If true and if DML is supported,
+        /// a link to dumpasync will be generated.  If false and if DML is supported, a link to dumpobj
+        /// will be generated.
+        /// </param>
+        private void WriteAddress(ulong addr, bool asyncObject)
+        {
+            string completed = IncludeCompleted ? "--completed" : "";
+            string tasks = IncludeTasks ? "--tasks" : "";
+
+            switch ((Console.SupportsDml, asyncObject, IntPtr.Size))
+            {
+                case (false, _, 4):
+                    Console.Write($"{addr,16:x8}");
+                    break;
+
+                case (false, _, 8):
+                    Console.Write($"{addr:x16}");
+                    break;
+
+                case (true, true, 4):
+                    Console.WriteDml($"<exec cmd=\"{DmlCommandInvoke} --address 0x{addr:x8} {tasks} {completed} --fields\">{addr,16:x8}</exec>");
+                    break;
+
+                case (true, true, 8):
+                    Console.WriteDml($"<exec cmd=\"{DmlCommandInvoke} --address 0x{addr:x16} {tasks} {completed} --fields\">{addr:x16}</exec>");
+                    break;
+
+                case (true, false, 4):
+                    Console.WriteDml($"<exec cmd=\"!DumpObj /d 0x{addr:x8}\">{addr,16:x8}</exec>");
+                    break;
+
+                case (true, false, 8):
+                    Console.WriteDml($"<exec cmd=\"!DumpObj /d 0x{addr:x16}\">{addr:x16}</exec>");
+                    break;
+            }
+        }
+
+        /// <summary>Writes out a value type address.  If DML is supported, this will be linked.</summary>
+        /// <param name="addr">The value type's address.</param>
+        /// <param name="mt">The value type's method table address.</param>
+        private void WriteValueTypeAddress(ulong addr, ulong mt)
+        {
+            switch ((Console.SupportsDml, IntPtr.Size))
+            {
+                case (false, 4):
+                    Console.Write($"{addr,16:x8}");
+                    break;
+
+                case (false, 8):
+                    Console.Write($"{addr:x16}");
+                    break;
+
+                case (true, 4):
+                    Console.WriteDml($"<exec cmd=\"!DumpVC /d 0x{mt:x8} 0x{addr:x8}\">{addr,16:x8}</exec>");
+                    break;
+
+                case (true, 8):
+                    Console.WriteDml($"<exec cmd=\"!DumpVC /d 0x{mt:x16} 0x{addr:x16}\">{addr:x16}</exec>");
+                    break;
+            }
+        }
+
+        /// <summary>Writes out a link that should open the source code for an address, if available.</summary>
+        /// <remarks>If DML is not supported, this is a nop.</remarks>
+        private void WriteCodeLink(ulong address)
+        {
+            if (address != 0 && address != ulong.MaxValue &&
+                Console.SupportsDml)
+            {
+                Console.WriteDml($" <link cmd=\".open -a 0x{address:x}\" alt=\"Source link\">@ {address:x}</link>");
+            }
+        }
+
+        /// <summary>Gets whether the specified type is an AsyncStateMachineBox{T}.</summary>
+        private static bool IsStateMachineBox(ClrType type)
+        {
+            // Ideally we would compare the metadata token and module for the generic template for the type,
+            // but that information isn't fully available via ClrMd, nor can it currently find DebugFinalizableAsyncStateMachineBox
+            // due to various limitations.  So we're left with string comparison.
+            const string Prefix = "System.Runtime.CompilerServices.AsyncTaskMethodBuilder<";
+            return
+                type?.Name is string name &&
+                name.StartsWith(Prefix, StringComparison.Ordinal) &&
+                name.IndexOf("AsyncStateMachineBox", Prefix.Length, StringComparison.Ordinal) >= 0;
+        }
+
+        /// <summary>Tries to get the compiler-generated state machine instance from a state machine box.</summary>
+        private static bool TryGetStateMachine(ClrObject obj, out IAddressableTypedEntity? stateMachine)
+        {
+            // AsyncStateMachineBox<T> has a StateMachine field storing the compiler-generated instance.
+            if (obj.Type?.GetFieldByName("StateMachine") is ClrInstanceField field)
+            {
+                if (field.IsValueType)
+                {
+                    if (obj.ReadValueTypeField("StateMachine") is ClrValueType { IsValid: true } t)
+                    {
+                        stateMachine = t;
+                        return true;
+                    }
+                }
+                else if (field.ReadObject(obj.Address, interior: false) is ClrObject { IsValid: true } t)
+                {
+                    stateMachine = t;
+                    return true;
+                }
+            }
+
+            stateMachine = null;
+            return false;
+        }
+
+        /// <summary>Extract from the specified field of the specified object something that can be ToString'd.</summary>
+        private static object GetDisplay(IAddressableTypedEntity obj, ClrInstanceField field)
+        {
+            if (field.Name is string fieldName)
+            {
+                switch (field.ElementType)
+                {
+                    case ClrElementType.Boolean:
+                        return obj.ReadField<bool>(fieldName) ? "true" : "false";
+
+                    case ClrElementType.Char:
+                        char c = obj.ReadField<char>(fieldName);
+                        return c >= 32 && c < 127 ? $"'{c}'" : $"'\\u{(int)c:X4}'";
+
+                    case ClrElementType.Int8:
+                        return obj.ReadField<sbyte>(fieldName);
+
+                    case ClrElementType.UInt8:
+                        return obj.ReadField<byte>(fieldName);
+
+                    case ClrElementType.Int16:
+                        return obj.ReadField<short>(fieldName);
+
+                    case ClrElementType.UInt16:
+                        return obj.ReadField<ushort>(fieldName);
+
+                    case ClrElementType.Int32:
+                        return obj.ReadField<int>(fieldName);
+
+                    case ClrElementType.UInt32:
+                        return obj.ReadField<uint>(fieldName);
+
+                    case ClrElementType.Int64:
+                        return obj.ReadField<long>(fieldName);
+
+                    case ClrElementType.UInt64:
+                        return obj.ReadField<ulong>(fieldName);
+
+                    case ClrElementType.Float:
+                        return obj.ReadField<float>(fieldName);
+
+                    case ClrElementType.Double:
+                        return obj.ReadField<double>(fieldName);
+
+                    case ClrElementType.String:
+                        return $"\"{obj.ReadStringField(fieldName)}\"";
+
+                    case ClrElementType.Pointer:
+                    case ClrElementType.NativeInt:
+                    case ClrElementType.NativeUInt:
+                    case ClrElementType.FunctionPointer:
+                        return obj.ReadField<ulong>(fieldName).ToString(IntPtr.Size == 8 ? "x16" : "x8");
+
+                    case ClrElementType.SZArray:
+                        ClrObject arrayObj = obj.ReadObjectField(fieldName);
+                        if (!arrayObj.IsNull)
+                        {
+                            ClrArray arrayObjAsArray = arrayObj.AsArray();
+                            return $"{arrayObj.Type?.ComponentType?.ToString() ?? "unknown"}[{arrayObjAsArray.Length}]";
+                        }
+                        return "null";
+
+                    case ClrElementType.Struct:
+                        return field.GetAddress(obj.Address).ToString(IntPtr.Size == 8 ? "x16" : "x8");
+
+                    case ClrElementType.Array:
+                    case ClrElementType.Object:
+                    case ClrElementType.Class:
+                        ClrObject classObj = obj.ReadObjectField(fieldName);
+                        return classObj.IsNull ? "null" : classObj.Address.ToString(IntPtr.Size == 8 ? "x16" : "x8");
+
+                    case ClrElementType.Var:
+                        return "(var)";
+
+                    case ClrElementType.GenericInstantiation:
+                        return "(generic instantiation)";
+
+                    case ClrElementType.MVar:
+                        return "(mvar)";
+
+                    case ClrElementType.Void:
+                        return "(void)";
+                }
+            }
+
+            return "(unknown)";
+        }
+
+        /// <summary>Tries to get a ClrMethod for the method wrapped by a delegate object.</summary>
+        private static bool TryGetMethodFromDelegate(ClrRuntime runtime, ClrObject delegateObject, out ClrMethod? method)
+        {
+            ClrInstanceField? methodPtrField = delegateObject.Type?.GetFieldByName("_methodPtr");
+            ClrInstanceField? methodPtrAuxField = delegateObject.Type?.GetFieldByName("_methodPtrAux");
+
+            if (methodPtrField is not null && methodPtrAuxField is not null)
+            {
+                ulong methodPtr = methodPtrField.Read<UIntPtr>(delegateObject.Address, interior: false).ToUInt64();
+                if (methodPtr != 0)
+                {
+                    method = runtime.GetMethodByInstructionPointer(methodPtr);
+                    if (method is null)
+                    {
+                        methodPtr = methodPtrAuxField.Read<UIntPtr>(delegateObject.Address, interior: false).ToUInt64();
+                        if (methodPtr != 0)
+                        {
+                            method = runtime.GetMethodByInstructionPointer(methodPtr);
+                        }
+                    }
+
+                    return method is not null;
+                }
+            }
+
+            method = null;
+            return false;
+        }
+
+        /// <summary>Creates an indenting string.</summary>
+        /// <param name="count">The number of tabs.</param>
+        private static string Tabs(int count) => new string(' ', count * TabWidth);
+
+        /// <summary>Shortens a string to a maximum length by eliding part of the string with ...</summary>
+        private static string? Truncate(string? value, int maxLength)
+        {
+            if (value is not null && value.Length > maxLength)
+            {
+                value = $"...{value.Substring(value.Length - maxLength + 3)}";
+            }
+
+            return value;
+        }
+
+        /// <summary>Tries to get the state flags from a task.</summary>
+        private static bool TryGetTaskStateFlags(ClrObject obj, out int flags)
+        {
+            if (obj.Type?.GetFieldByName("m_stateFlags") is ClrInstanceField field)
+            {
+                flags = field.Read<int>(obj.Address, interior: false);
+                return true;
+            }
+
+            flags = 0;
+            return false;
+        }
+
+        /// <summary>Tries to read the specified value from the field of an entity.</summary>
+        private static bool TryRead<T>(IAddressableTypedEntity entity, string fieldName, out T result) where T : unmanaged
+        {
+            if (entity.Type?.GetFieldByName(fieldName) is not null)
+            {
+                result = entity.ReadField<T>(fieldName);
+                return true;
+            }
+
+            result = default;
+            return false;
+        }
+
+        /// <summary>Tries to read an object from a field of another object.</summary>
+        private static bool TryGetValidObjectField(ClrObject obj, string fieldName, out ClrObject result)
+        {
+            if (obj.Type?.GetFieldByName(fieldName) is ClrInstanceField field &&
+                field.ReadObject(obj.Address, interior: false) is { IsValid: true } validObject)
+            {
+                result = validObject;
+                return true;
+            }
+
+            result = default;
+            return false;
+        }
+
+        /// <summary>Gets whether a task has completed, based on its state flags.</summary>
+        private static bool IsCompleted(int taskStateFlags)
+        {
+            const int TASK_STATE_COMPLETED_MASK = 0x1600000;
+            return (taskStateFlags & TASK_STATE_COMPLETED_MASK) != 0;
+        }
+
+        /// <summary>Determines whether a span contains all zeros.</summary>
+        private static bool AllZero(ReadOnlySpan<byte> bytes)
+        {
+            for (int i = 0; i < bytes.Length; i++)
+            {
+                if (bytes[i] != 0)
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        /// <summary>Gets a string representing interesting aspects of the specified task state flags.</summary>
+        /// <remarks>
+        /// The goal of this method isn't to detail every flag value (there are a lot).
+        /// Rather, we only want to render flags that are likely to be valuable, e.g.
+        /// we don't render WaitingForActivation, as that's the expected state for any
+        /// task that's showing up in a stack.
+        /// </remarks>
+        private static string DescribeTaskFlags(int stateFlags)
+        {
+            if (stateFlags != 0)
+            {
+                StringBuilder? sb = null;
+                void Append(string s)
+                {
+                    sb ??= new StringBuilder();
+                    if (sb.Length != 0) sb.Append("|");
+                    sb.Append(s);
+                }
+
+                if ((stateFlags & 0x10000) != 0) Append("Started");
+                if ((stateFlags & 0x20000) != 0) Append("DelegateInvoked");
+                if ((stateFlags & 0x40000) != 0) Append("Disposed");
+                if ((stateFlags & 0x80000) != 0) Append("ExceptionObservedByParent");
+                if ((stateFlags & 0x100000) != 0) Append("CancellationAcknowledged");
+                if ((stateFlags & 0x200000) != 0) Append("Faulted");
+                if ((stateFlags & 0x400000) != 0) Append("Canceled");
+                if ((stateFlags & 0x800000) != 0) Append("WaitingOnChildren");
+                if ((stateFlags & 0x1000000) != 0) Append("RanToCompletion");
+                if ((stateFlags & 0x4000000) != 0) Append("CompletionReserved");
+
+                if (sb is not null)
+                {
+                    return sb.ToString();
+                }
+            }
+
+            return " ";
+        }
+
+        /// <summary>Gets detailed help for the command.</summary>
+        protected override string GetDetailedHelp() => s_detailedHelpText;
+
+        /// <summary>Represents an async object to be used as a frame in an async "stack".</summary>
+        private sealed class AsyncObject
+        {
+            /// <summary>The actual object on the heap.</summary>
+            public ClrObject Object;
+            /// <summary>true if <see cref="Object"/> is an AsyncStateMachineBox.</summary>
+            public bool IsStateMachine;
+            /// <summary>A compiler-generated state machine extracted from the object, if one exists.</summary>
+            public IAddressableTypedEntity? StateMachine;
+            /// <summary>The state of the state machine, if the object contains a state machine.</summary>
+            public int AwaitState;
+            /// <summary>The <see cref="Object"/>'s Task state flags, if it's a task.</summary>
+            public int TaskStateFlags;
+            /// <summary>Whether this object meets the user-specified criteria for inclusion.</summary>
+            public bool IncludeInOutput;
+            /// <summary>true if this is a top-level instance that nothing else continues to.</summary>
+            /// <remarks>This starts off as true and then is flipped to false when we find a continuation to this object.</remarks>
+            public bool TopLevel = true;
+            /// <summary>The address of the native code for a method on the object (typically MoveNext for a state machine).</summary>
+            public ulong NativeCode;
+            /// <summary>This object's continuations.</summary>
+            public readonly List<ClrObject> Continuations = new();
+        }
+    }
+}
index 3db956e323f6c1cc3eaa001e57e610891df577b3..9a450ea1ad2fb04b66aee31489768ab266b73293 100644 (file)
@@ -50,13 +50,13 @@ namespace Microsoft.Diagnostics.ExtensionCommands
                         WriteLine("    IsFileLayout:    {0}", module.IsFileLayout?.ToString() ?? "<unknown>");
                         WriteLine("    IndexFileSize:   {0}", module.IndexFileSize?.ToString("X8") ?? "<none>");
                         WriteLine("    IndexTimeStamp:  {0}", module.IndexTimeStamp?.ToString("X8") ?? "<none>");
-                        WriteLine("    Version:         {0}", module.VersionData?.ToString() ?? "<none>");
-                        string versionString = module.VersionString;
+                        WriteLine("    Version:         {0}", module.GetVersionData()?.ToString() ?? "<none>");
+                        string versionString = module.GetVersionString();
                         if (!string.IsNullOrEmpty(versionString))
                         {
                             WriteLine("                     {0}", versionString);
                         }
-                        foreach (PdbFileInfo pdbFileInfo in module.PdbFileInfos)
+                        foreach (PdbFileInfo pdbFileInfo in module.GetPdbFileInfos())
                         {
                             WriteLine("    PdbInfo:         {0}", pdbFileInfo);
                         }
@@ -68,7 +68,7 @@ namespace Microsoft.Diagnostics.ExtensionCommands
                     }
                     if (Segment)
                     {
-                        DisplaySegments(module.ImageBase);
+                        DisplaySegments(module);
                     }
                 }
             }
@@ -79,32 +79,27 @@ namespace Microsoft.Diagnostics.ExtensionCommands
 
         public IMemoryService MemoryService { get; set; }
 
-        void DisplaySegments(ulong address)
+        void DisplaySegments(IModule module)
         {
             try
             {
-                if (Target.OperatingSystem == OSPlatform.Linux)
+                ELFFile elfFile = module.Services.GetService<ELFFile>();
+                if (elfFile is not null)
                 {
-                    Stream stream = MemoryService.CreateMemoryStream();
-                    var elfFile = new ELFFile(new StreamAddressSpace(stream), address, true);
-                    if (elfFile.IsValid())
+                    foreach (ELFProgramHeader programHeader in elfFile.Segments.Select((segment) => segment.Header))
                     {
-                        foreach (ELFProgramHeader programHeader in elfFile.Segments.Select((segment) => segment.Header))
-                        {
-                            uint flags = MemoryService.PointerSize == 8 ? programHeader.Flags : programHeader.Flags32;
-                            ulong loadAddress = programHeader.VirtualAddress;
-                            ulong loadSize = programHeader.VirtualSize;
-                            ulong fileOffset = programHeader.FileOffset;
-                            string type = programHeader.Type.ToString();
-                            WriteLine($"        Segment: {loadAddress:X16} {loadSize:X16} {fileOffset:X16} {flags:x2} {type}");
-                        }
+                        uint flags = MemoryService.PointerSize == 8 ? programHeader.Flags : programHeader.Flags32;
+                        ulong loadAddress = programHeader.VirtualAddress;
+                        ulong loadSize = programHeader.VirtualSize;
+                        ulong fileOffset = programHeader.FileOffset;
+                        string type = programHeader.Type.ToString();
+                        WriteLine($"        Segment: {loadAddress:X16} {loadSize:X16} {fileOffset:X16} {flags:x2} {type}");
                     }
                 }
-                else if (Target.OperatingSystem == OSPlatform.OSX)
+                else
                 {
-                    Stream stream = MemoryService.CreateMemoryStream();
-                    MachOFile machOFile = new(new StreamAddressSpace(stream), address, true);
-                    if (machOFile.IsValid())
+                    MachOFile machOFile = module.Services.GetService<MachOFile>();
+                    if (machOFile is not null)
                     {
                         WriteLine("    LoadAddress:     {0:X16}", machOFile.LoadAddress);
                         WriteLine("    LoadBias:        {0:X16}", machOFile.PreferredVMBaseAddress);
diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Host/SetSymbolServerCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Host/SetSymbolServerCommand.cs
new file mode 100644 (file)
index 0000000..756b302
--- /dev/null
@@ -0,0 +1,105 @@
+// 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 Microsoft.Diagnostics.DebugServices;
+
+namespace Microsoft.Diagnostics.ExtensionCommands
+{
+    [Command(
+        Name = "setsymbolserver",
+        Aliases = new string[] { "SetSymbolServer" },
+        Help = "Enable and set symbol server support for symbols and module download",
+        Platform = CommandPlatform.Global)]
+    public class SetSymbolServerCommand : CommandBase
+    {
+        public ISymbolService SymbolService { get; set; }
+
+        public IModuleService ModuleService { get; set; }
+
+        [Option(Name = "--ms", Aliases = new string[] { "-ms" }, Help = "Use the public Microsoft symbol server.")]
+        public bool MicrosoftSymbolServer { get; set; }
+
+        [Option(Name = "--mi", Aliases = new string[] { "-mi" }, Help = "Use the internal symweb symbol server.")]
+        public bool InternalSymbolServer { get; set; }
+
+        [Option(Name = "--disable", Aliases = new string[] { "-disable" }, Help = "Clear or disable symbol download support.")]
+        public bool Disable { get; set; }
+
+        [Option(Name = "--reset", Aliases = new string[] { "-reset" }, Help = "Reset the HTTP symbol servers clearing any cached failures.")]
+        public bool Reset { get; set; }
+
+        [Option(Name = "--cache", Aliases = new string[] { "-cache" }, Help = "Specify a symbol cache directory.")]
+        public string Cache { get; set; }
+
+        [Option(Name = "--directory", Aliases = new string[] { "-directory" }, Help = "Specify a directory to search for symbols.")]
+        public string Directory { get; set; }
+
+        [Option(Name = "--pat", Aliases = new string[] { "-pat" }, Help = "Access token to the authenticated server.")]
+        public string AccessToken { get; set; }
+
+        [Option(Name = "--timeout", Aliases = new string[] { "-timeout" }, Help = "Specify the symbol server timeout in minutes.")]
+        public int? Timeout { get; set; }
+
+        [Option(Name = "--retrycount", Aliases = new string[] { "-retrycount" }, Help = "Specify the symbol server timeout retry count.")]
+        public int? RetryCount { get; set; }
+
+        [Option(Name = "--loadsymbols", Aliases = new string[] { "-loadsymbols" }, Help = "Attempt to load native symbols for all modules.")]
+        public bool LoadSymbols { get; set; }
+
+        [Argument(Name = "url", Help = "Symbol server URL.")]
+        public string SymbolServerUrl { get; set; }
+
+        public override void Invoke()
+        {
+            if (MicrosoftSymbolServer && InternalSymbolServer)
+            {
+                throw new DiagnosticsException("Cannot have both -ms and -mi options");
+            }
+            if ((MicrosoftSymbolServer || InternalSymbolServer) && !string.IsNullOrEmpty(SymbolServerUrl))
+            {
+                throw new DiagnosticsException("Cannot have -ms or -mi option and a symbol server path");
+            }
+            if (Disable)
+            {
+                SymbolService.DisableSymbolStore();
+            }
+            if (Reset)
+            {
+                SymbolService.Reset();
+            }
+            if (MicrosoftSymbolServer || InternalSymbolServer || !string.IsNullOrEmpty(SymbolServerUrl))
+            {
+                if (string.IsNullOrEmpty(Cache))
+                {
+                    Cache = SymbolService.DefaultSymbolCache;
+                }
+                SymbolService.AddSymbolServer(MicrosoftSymbolServer, InternalSymbolServer, SymbolServerUrl, AccessToken, Timeout, RetryCount);
+            }
+            if (!string.IsNullOrEmpty(Cache))
+            {
+                SymbolService.AddCachePath(Cache);
+            }
+            if (!string.IsNullOrEmpty(Directory))
+            {
+                SymbolService.AddDirectoryPath(Directory);
+            }
+            if (LoadSymbols)
+            {
+                foreach (IModule module in ModuleService.EnumerateModules())
+                {
+                    if (!module.IsManaged)
+                    {
+                        Write($"Downloading symbol file for {module.FileName}");
+                        string downloadedModulePath = module.LoadSymbols();
+                        WriteLine(" {0}", downloadedModulePath != null ? "SUCCEEDED" : "FAILED");
+                    }
+                }
+            }
+            else
+            {
+                Write(SymbolService.ToString());
+            }
+        }
+    }
+}
index 1519125b3d9b866c1ba325001c1931a3aaace20b..fa4687baea4f2a8329ee9b28c6ef148082ff6a22 100644 (file)
@@ -550,6 +550,10 @@ namespace Microsoft.Diagnostics.Repl
 
         void IConsoleService.WriteError(string text) => WriteOutput(OutputType.Error, text);
 
+        bool IConsoleService.SupportsDml => false;
+
+        void IConsoleService.WriteDml(string text) => throw new NotSupportedException();
+
         CancellationToken IConsoleService.CancellationToken { get; set; }
 
         int IConsoleService.WindowWidth
index 5e6b284aadc8ff0f1e85a9eeb2a5c42d9e0e4a00..adc4c668ffaffafa78e5cd9623d3ec48be704da3 100644 (file)
@@ -93,7 +93,7 @@ namespace Microsoft.Diagnostics.TestHelpers
 
         private void AddModuleMembers(XElement element, IModule module, string symbolModuleName)
         {
-            AddMembers(element, typeof(IModule), module, nameof(IModule.ModuleIndex), nameof(IModule.PdbFileInfos), nameof(IModule.VersionString));
+            AddMembers(element, typeof(IModule), module, nameof(IModule.ModuleIndex), nameof(IModule.GetPdbFileInfos), nameof(IModule.GetVersionString));
 
             if (symbolModuleName != null && IsModuleEqual(module, symbolModuleName))
             {
index 33a64ddb8c562b4ecf5f096d3c7ac8f4036be374..2df8072ee9e98ddf98bee0dbd51161753fc6303d 100644 (file)
@@ -26,7 +26,7 @@ namespace Microsoft.Diagnostics.TestHelpers
             _serviceProvider.AddService<ISymbolService>(_symbolService);
 
             // Automatically enable symbol server support
-            _symbolService.AddSymbolServer(msdl: true, symweb: false, symbolServerPath: null, authToken: null, timeoutInMinutes: 0);
+            _symbolService.AddSymbolServer(msdl: true, symweb: false, timeoutInMinutes: 6, retryCount: 5);
             _symbolService.AddCachePath(_symbolService.DefaultSymbolCache);
         }
 
index 48096ee6dee88ccff83ff61ac6109f67b0980cd2..927f21b8f2f119545dcf923ef46538abca211583 100644 (file)
@@ -1,6 +1,5 @@
 ï»¿using Microsoft.Diagnostics.DebugServices;
 using Microsoft.Diagnostics.Runtime.Interop;
-using System;
 using System.Threading;
 
 namespace SOS.Extensions
@@ -8,6 +7,7 @@ namespace SOS.Extensions
     internal class ConsoleServiceFromDebuggerServices : IConsoleService
     {
         private readonly DebuggerServices _debuggerServices;
+        private bool? _supportsDml;
 
         public ConsoleServiceFromDebuggerServices(DebuggerServices debuggerServices)
         {
@@ -22,6 +22,10 @@ namespace SOS.Extensions
 
         public void WriteError(string text) => _debuggerServices.OutputString(DEBUG_OUTPUT.ERROR, text);
 
+        public void WriteDml(string text) => _debuggerServices.OutputDmlString(DEBUG_OUTPUT.NORMAL, text);
+
+        public bool SupportsDml => _supportsDml ??= _debuggerServices.SupportsDml;
+
         public CancellationToken CancellationToken { get; set; }
 
         int IConsoleService.WindowWidth => _debuggerServices.GetOutputWidth();
index cbb62bf7ccb41213623ca80fb719b0970b73c674..eb8d85b19c5aab8ca8b0ae83838bfa22639bd162 100644 (file)
@@ -329,6 +329,40 @@ namespace SOS
 
         public int GetOutputWidth() => (int)VTable.GetOutputWidth(Self);
 
+        public bool SupportsDml
+        {
+            get
+            {
+                uint supported = 0;
+                VTable.SupportsDml(Self, &supported);
+                return supported != 0;
+            }
+        }
+
+        public void OutputDmlString(DEBUG_OUTPUT mask, string message)
+        {
+            if (message == null) throw new ArgumentNullException(nameof(message));
+
+            byte[] messageBytes = Encoding.ASCII.GetBytes(message + "\0");
+            fixed (byte* messagePtr = messageBytes)
+            {
+                VTable.OutputDmlString(Self, mask, messagePtr);
+            }
+        }
+
+        public HResult AddModuleSymbol(string symbolFileName)
+        {
+            if (symbolFileName == null) 
+            {
+                throw new ArgumentNullException(nameof(symbolFileName));
+            }
+            byte[] symbolFileNameBytes = Encoding.ASCII.GetBytes(symbolFileName + "\0");
+            fixed (byte* ptr = symbolFileNameBytes)
+            {
+                return VTable.AddModuleSymbol(Self, IntPtr.Zero, ptr);
+            }
+        }
+
         [StructLayout(LayoutKind.Sequential)]
         private readonly unsafe struct IDebuggerServicesVTable
         {
@@ -355,6 +389,9 @@ namespace SOS
             public readonly delegate* unmanaged[Stdcall]<IntPtr, int, ulong, byte*, int, out uint, out ulong, HResult> GetSymbolByOffset;
             public readonly delegate* unmanaged[Stdcall]<IntPtr, int, byte*, out ulong, HResult> GetOffsetBySymbol;
             public readonly delegate* unmanaged[Stdcall]<IntPtr, uint> GetOutputWidth;
+            public readonly delegate* unmanaged[Stdcall]<IntPtr, uint*, HResult> SupportsDml;
+            public readonly delegate* unmanaged[Stdcall]<IntPtr, DEBUG_OUTPUT, byte*, void> OutputDmlString;
+            public readonly delegate* unmanaged[Stdcall]<IntPtr, IntPtr, byte*, HResult> AddModuleSymbol;
         }
     }
 }
index 4a062b55518a73187eb29ccd039e95c062abc55d..41b9947ac8a574f9a6b08f9e5febee2371028d71 100644 (file)
@@ -61,6 +61,16 @@ namespace SOS.Extensions
         /// </summary>
         public static HostServices Instance { get; private set; }
 
+        /// <summary>
+        /// The time out in minutes passed to the HTTP symbol store
+        /// </summary>
+        public static int DefaultTimeout { get; set; } = 4;
+
+        /// <summary>
+        /// The retry count passed to the HTTP symbol store
+        /// </summary>
+        public static int DefaultRetryCount { get; set; } = 0;
+
         /// <summary>
         /// This is the main managed entry point that the native hosting code calls. It needs to be a single function
         /// and is restricted to just a string parameter because host APIs (i.e. desktop clr) have this narrow interface.
@@ -97,6 +107,8 @@ namespace SOS.Extensions
         {
             _serviceProvider = new ServiceProvider();
             _symbolService = new SymbolService(this);
+            _symbolService.DefaultTimeout = DefaultTimeout;
+            _symbolService.DefaultRetryCount = DefaultRetryCount;
             _commandService = new CommandService(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ">!ext" : null);
             _commandService.AddCommands(new Assembly[] { typeof(HostServices).Assembly });
             _commandService.AddCommands(new Assembly[] { typeof(ClrMDHelper).Assembly });
index 74ee74b8502547a1047f1baf5d5a46e97f7a7a14..ef097f3f3d861ecb182108d7b3befa539e97d746 100644 (file)
@@ -61,50 +61,54 @@ namespace SOS.Extensions
 
             public override uint? IndexTimeStamp { get; }
 
-            public override VersionData VersionData
+            public override VersionData GetVersionData()
             {
-                get
+                if (InitializeValue(Module.Flags.InitializeVersion))
                 {
-                    if (InitializeValue(Module.Flags.InitializeVersion))
+                    HResult hr = _moduleService._debuggerServices.GetModuleVersionInformation(ModuleIndex, out VS_FIXEDFILEINFO fileInfo);
+                    if (hr.IsOK)
                     {
-                        int hr = _moduleService._debuggerServices.GetModuleVersionInformation(ModuleIndex, out VS_FIXEDFILEINFO fileInfo);
-                        if (hr == HResult.S_OK)
-                        {
-                            int major = (int)(fileInfo.dwFileVersionMS >> 16);
-                            int minor = (int)(fileInfo.dwFileVersionMS & 0xffff);
-                            int revision = (int)(fileInfo.dwFileVersionLS >> 16);
-                            int patch = (int)(fileInfo.dwFileVersionLS & 0xffff);
-                            _versionData = new VersionData(major, minor, revision, patch);
-                        }
-                        else
+                        int major = (int)(fileInfo.dwFileVersionMS >> 16);
+                        int minor = (int)(fileInfo.dwFileVersionMS & 0xffff);
+                        int revision = (int)(fileInfo.dwFileVersionLS >> 16);
+                        int patch = (int)(fileInfo.dwFileVersionLS & 0xffff);
+                        _versionData = new VersionData(major, minor, revision, patch);
+                    }
+                    else
+                    {
+                        if (_moduleService.Target.OperatingSystem != OSPlatform.Windows)
                         {
-                            if (_moduleService.Target.OperatingSystem != OSPlatform.Windows)
-                            {
-                                _versionData = GetVersion();
-                            }
+                            _versionData = GetVersion();
                         }
                     }
-                    return _versionData;
                 }
+                return _versionData;
             }
 
-            public override string VersionString
+            public override string GetVersionString()
             {
-                get
+                if (InitializeValue(Module.Flags.InitializeProductVersion))
                 {
-                    if (InitializeValue(Module.Flags.InitializeProductVersion))
+                    HResult hr = _moduleService._debuggerServices.GetModuleVersionString(ModuleIndex, out _versionString);
+                    if (!hr.IsOK)
                     {
-                        int hr = _moduleService._debuggerServices.GetModuleVersionString(ModuleIndex, out _versionString);
-                        if (hr != HResult.S_OK)
+                        if (_moduleService.Target.OperatingSystem != OSPlatform.Windows && !IsPEImage)
                         {
-                            if (_moduleService.Target.OperatingSystem != OSPlatform.Windows && !IsPEImage)
-                            {
-                                _versionString = _moduleService.GetVersionString(ImageBase);
-                            }
+                            _versionString = _moduleService.GetVersionString(this);
                         }
                     }
-                    return _versionString;
                 }
+                return _versionString;
+            }
+
+            public override string LoadSymbols()
+            {
+                string symbolFile = _moduleService.SymbolService.DownloadSymbolFile(this);
+                if (symbolFile is not null)
+                {
+                    _moduleService._debuggerServices.AddModuleSymbol(symbolFile);
+                }
+                return symbolFile;
             }
 
             #endregion
@@ -113,19 +117,19 @@ namespace SOS.Extensions
 
             bool IModuleSymbols.TryGetSymbolName(ulong address, out string symbol, out ulong displacement)
             {
-                return _moduleService._debuggerServices.GetSymbolByOffset(ModuleIndex, address, out symbol, out displacement) == HResult.S_OK;
+                return _moduleService._debuggerServices.GetSymbolByOffset(ModuleIndex, address, out symbol, out displacement).IsOK;
             }
 
             bool IModuleSymbols.TryGetSymbolAddress(string name, out ulong address)
             {
-                return _moduleService._debuggerServices.GetOffsetBySymbol(ModuleIndex, name, out address) == HResult.S_OK;
+                return _moduleService._debuggerServices.GetOffsetBySymbol(ModuleIndex, name, out address).IsOK;
             }
 
             #endregion
 
             protected override bool TryGetSymbolAddressInner(string name, out ulong address)
             {
-                return _moduleService._debuggerServices.GetOffsetBySymbol(ModuleIndex, name, out address) == HResult.S_OK;
+                return _moduleService._debuggerServices.GetOffsetBySymbol(ModuleIndex, name, out address).IsOK;
             }
 
             protected override ModuleService ModuleService => _moduleService;
@@ -148,12 +152,12 @@ namespace SOS.Extensions
             var modules = new Dictionary<ulong, IModule>();
 
             HResult hr = _debuggerServices.GetNumberModules(out uint loadedModules, out uint unloadedModules);
-            if (hr == HResult.S_OK)
+            if (hr.IsOK)
             {
                 for (int moduleIndex = 0; moduleIndex < loadedModules; moduleIndex++)
                 {
                     hr = _debuggerServices.GetModuleInfo(moduleIndex, out ulong imageBase, out ulong imageSize, out uint timestamp, out uint checksum);
-                    if (hr == HResult.S_OK)
+                    if (hr.IsOK)
                     {
                         hr = _debuggerServices.GetModuleName(moduleIndex, out string imageName);
                         if (hr < HResult.S_OK)
index 741c105107c06a1500e6d49f573c67b2a00720ab..d3eb44e128dcda843a25262b3061fd509e4259b3 100644 (file)
@@ -15,7 +15,6 @@ namespace SOS.Hosting
     [Command(Name = "dbgout",           DefaultOptions = "dbgout",              Help = "Enable/disable (-off) internal SOS logging.")]
     [Command(Name = "dumpalc",          DefaultOptions = "DumpALC",             Help = "Displays details about a collectible AssemblyLoadContext into which the specified object is loaded.")]
     [Command(Name = "dumparray",        DefaultOptions = "DumpArray",           Help = "Displays details about a managed array.")]
-    [Command(Name = "dumpasync",        DefaultOptions = "DumpAsync",           Help = "Displays info about async state machines on the garbage-collected heap.")]
     [Command(Name = "dumpassembly",     DefaultOptions = "DumpAssembly",        Help = "Displays details about an assembly.")]
     [Command(Name = "dumpclass",        DefaultOptions = "DumpClass",           Help = "Displays information about a EE class structure at the specified address.")]
     [Command(Name = "dumpdelegate",     DefaultOptions = "DumpDelegate",        Help = "Displays information about a delegate.")]
@@ -43,7 +42,6 @@ namespace SOS.Hosting
     [Command(Name = "histobj",          DefaultOptions = "HistObj",             Help = "Examines all stress log relocation records and displays the chain of garbage collection relocations that may have led to the address passed in as an argument.")]
     [Command(Name = "histobjfind",      DefaultOptions = "HistObjFind",         Help = "Displays all the log entries that reference an object at the specified address.")]
     [Command(Name = "histroot",         DefaultOptions = "HistRoot",            Help = "Displays information related to both promotions and relocations of the specified root.")]
-    [Command(Name = "setsymbolserver",  DefaultOptions = "SetSymbolServer",     Help = "Enables the symbol server support.")]
     [Command(Name = "verifyheap",       DefaultOptions = "VerifyHeap",          Help = "Checks the GC heap for signs of corruption.")]
     [Command(Name = "threadpool",       DefaultOptions = "ThreadPool",          Help = "Lists basic information about the thread pool.")]
     [Command(Name = "soshelp",          DefaultOptions = "Help",                Help = "Displays help for a specific SOS command.")]
index c10e74136c58bbf65aaff194ba76bdedfc61f29c..4cd6d655df94013b3702e8ef0fd6ee036e28e4da 100644 (file)
@@ -252,7 +252,8 @@ namespace SOS.Hosting
             {
                 return HResult.E_FAIL;
             }
-            if (module.VersionData is null)
+            VersionData versionData = module.GetVersionData();
+            if (versionData is null)
             {
                 return HResult.E_FAIL;
             }
@@ -260,8 +261,6 @@ namespace SOS.Hosting
             pFileInfo->dwStrucVersion = 0;
             pFileInfo->dwFileFlagsMask = 0;
             pFileInfo->dwFileFlags = 0;
-
-            VersionData versionData = module.VersionData;
             pFileInfo->dwFileVersionMS = (uint)versionData.Minor | (uint)versionData.Major << 16;
             pFileInfo->dwFileVersionLS = (uint)versionData.Patch | (uint)versionData.Revision << 16;
 
@@ -271,7 +270,7 @@ namespace SOS.Hosting
                 if (fileVersionBufferSizeInBytes > 0) {
                     *fileVersionBuffer = 0;
                 }
-                string versionString = module.VersionString;
+                string versionString = module.GetVersionString();
                 if (versionString != null)
                 {
                     try
index 171cb364e17729179064eaffaa22770681f1c70d..bc46c91bb1e38c3d701b31169214d0fdb706c048 100644 (file)
@@ -480,7 +480,8 @@ namespace SOS.Hosting
                 {
                     return HResult.E_INVALIDARG;
                 }
-                if (module.VersionData is null)
+                VersionData versionData = module.GetVersionData();
+                if (versionData is null)
                 {
                     return HResult.E_FAIL;
                 }
@@ -489,15 +490,13 @@ namespace SOS.Hosting
                 fileInfo->dwStrucVersion = 0;
                 fileInfo->dwFileFlagsMask = 0;
                 fileInfo->dwFileFlags = 0;
-
-                VersionData versionData = module.VersionData;
                 fileInfo->dwFileVersionMS = (uint)versionData.Minor | (uint)versionData.Major << 16;
                 fileInfo->dwFileVersionLS = (uint)versionData.Patch | (uint)versionData.Revision << 16;
             }
             else if (item == "\\StringFileInfo\\040904B0\\FileVersion")
             {
                 *buffer = 0;
-                string versionString = module.VersionString;
+                string versionString = module.GetVersionString();
                 if (versionString == null)
                 {
                     return HResult.E_FAIL;
index b3316bbb4da92c156f741b1695c32294e9d5028e..ca1292ae108dc0d3a4611e8421b0c3733ceadd21 100644 (file)
@@ -53,6 +53,7 @@ namespace SOS.Hosting
 
         private readonly ISymbolService _symbolService;
         private readonly IMemoryService _memoryService;
+        private readonly ulong _ignoreAddressBitsMask;
 
         public SymbolServiceWrapper(ISymbolService symbolService, IMemoryService memoryService)
         {
@@ -60,16 +61,11 @@ namespace SOS.Hosting
             Debug.Assert(memoryService != null);
             _symbolService = symbolService;
             _memoryService = memoryService;
+            _ignoreAddressBitsMask = memoryService.SignExtensionMask();
             Debug.Assert(_symbolService != null);
 
             VTableBuilder builder = AddInterface(IID_ISymbolService, validate: false);
-            builder.AddMethod(new IsSymbolStoreEnabledDelegate((IntPtr self) => _symbolService.IsSymbolStoreEnabled));
-            builder.AddMethod(new InitializeSymbolStoreDelegate(InitializeSymbolStore));
             builder.AddMethod(new ParseSymbolPathDelegate(ParseSymbolPath));
-            builder.AddMethod(new DisplaySymbolStoreDelegate(DisplaySymbolStore));
-            builder.AddMethod(new DisableSymbolStoreDelegate((IntPtr self) => _symbolService.DisableSymbolStore()));
-            builder.AddMethod(new LoadNativeSymbolsDelegate(LoadNativeSymbols));
-            builder.AddMethod(new LoadNativeSymbolsFromIndexDelegate(LoadNativeSymbolsFromIndex));
             builder.AddMethod(new LoadSymbolsForModuleDelegate(LoadSymbolsForModule));
             builder.AddMethod(new DisposeDelegate(Dispose));
             builder.AddMethod(new ResolveSequencePointDelegate(ResolveSequencePoint));
@@ -88,50 +84,6 @@ namespace SOS.Hosting
             Trace.TraceInformation("SymbolServiceWrapper.Destroy");
         }
 
-        /// <summary>
-        /// Initializes symbol loading. Adds the symbol server and/or the cache path (if not null) to the list of
-        /// symbol servers. This API can be called more than once to add more servers to search.
-        /// </summary>
-        /// <param name="msdl">if true, use the public Microsoft server</param>
-        /// <param name="symweb">if true, use symweb internal server and protocol (file.ptr)</param>
-        /// <param name="symbolServerPath">symbol server url (optional)</param>
-        /// <param name="timeoutInMinutes">symbol server timeout in minutes (optional)</param>
-        /// <param name="symbolCachePath">symbol cache directory path (optional)</param>
-        /// <param name="symbolDirectoryPath">symbol directory path to search (optional)</param>
-        /// <returns>if false, failure</returns>
-        private bool InitializeSymbolStore(
-            IntPtr self,
-            bool msdl,
-            bool symweb,
-            string symbolServerPath,
-            string authToken,
-            int timeoutInMinutes,
-            string symbolCachePath,
-            string symbolDirectoryPath)
-        {
-            if (msdl || symweb || symbolServerPath != null)
-            {
-                // Add the default symbol cache if no cache specified and adding server
-                if (symbolCachePath == null)
-                {
-                    symbolCachePath = _symbolService.DefaultSymbolCache;
-                }
-                if (!_symbolService.AddSymbolServer(msdl, symweb, symbolServerPath, authToken, timeoutInMinutes))
-                {
-                    return false;
-                }
-            }
-            if (symbolCachePath != null)
-            {
-                _symbolService.AddCachePath(symbolCachePath);
-            }
-            if (symbolDirectoryPath != null)
-            {
-                _symbolService.AddDirectoryPath(symbolDirectoryPath);
-            }
-            return true;
-        }
-
         /// <summary>
         /// Parse the Windows sympath format
         /// </summary>
@@ -144,164 +96,10 @@ namespace SOS.Hosting
             if (string.IsNullOrWhiteSpace(symbolPath)) {
                 return false;
             }
+            _symbolService.DisableSymbolStore();
             return _symbolService.ParseSymbolPathFixDefault(symbolPath);
         }
 
-        /// <summary>
-        /// Displays the symbol server and cache configuration
-        /// </summary>
-        private void DisplaySymbolStore(IntPtr self, WriteLine writeLine)
-        {
-            writeLine(_symbolService.ToString());
-        }
-
-        /// <summary>
-        /// Load native symbols and modules (i.e. DAC, DBI).
-        /// </summary>
-        /// <param name="callback">called back for each symbol file loaded</param>
-        /// <param name="parameter">callback parameter</param>
-        /// <param name="config">Target configuration: Windows, Linux or OSX</param>
-        /// <param name="moduleFilePath">module path</param>
-        /// <param name="address">module base address</param>
-        /// <param name="size">module size</param>
-        /// <param name="readMemory">read memory callback delegate</param>
-        private void LoadNativeSymbols(
-            IntPtr self,
-            SymbolFileCallback callback,
-            IntPtr parameter,
-            RuntimeConfiguration config,
-            string moduleFilePath,
-            ulong address,
-            uint size)
-        {
-            if (_symbolService.IsSymbolStoreEnabled)
-            {
-                try
-                {
-                    KeyGenerator generator = null;
-                    if (config == RuntimeConfiguration.UnixCore)
-                    {
-                        Stream stream = _memoryService.CreateMemoryStream();
-                        var elfFile = new ELFFile(new StreamAddressSpace(stream), address, true);
-                        generator = new ELFFileKeyGenerator(Tracer.Instance, elfFile, moduleFilePath);
-                    }
-                    else if (config == RuntimeConfiguration.OSXCore)
-                    {
-                        Stream stream = _memoryService.CreateMemoryStream();
-                        var machOFile = new MachOFile(new StreamAddressSpace(stream), address, true);
-                        generator = new MachOFileKeyGenerator(Tracer.Instance, machOFile, moduleFilePath);
-                    }
-                    else if (config == RuntimeConfiguration.WindowsCore || config ==  RuntimeConfiguration.WindowsDesktop)
-                    {
-                        Stream stream = _memoryService.CreateMemoryStream(address, size);
-                        var peFile = new PEFile(new StreamAddressSpace(stream), true);
-                        generator = new PEFileKeyGenerator(Tracer.Instance, peFile, moduleFilePath);
-                    }
-                    else
-                    {
-                        Trace.TraceError("LoadNativeSymbols: unsupported config {0}", config);
-                    }
-                    if (generator != null)
-                    {
-                        IEnumerable<SymbolStoreKey> keys = generator.GetKeys(KeyTypeFlags.SymbolKey | KeyTypeFlags.DacDbiKeys);
-                        foreach (SymbolStoreKey key in keys)
-                        {
-                            string moduleFileName = Path.GetFileName(key.FullPathName);
-                            Trace.TraceInformation("{0} {1}", key.FullPathName, key.Index);
-
-                            string downloadFilePath = _symbolService.DownloadFile(key);
-                            if (downloadFilePath != null)
-                            {
-                                Trace.TraceInformation("{0}: {1}", moduleFileName, downloadFilePath);
-                                callback(parameter, moduleFileName, downloadFilePath);
-                            }
-                        }
-                    }
-                }
-                catch (Exception ex) when 
-                   (ex is DiagnosticsException || 
-                    ex is BadInputFormatException || 
-                    ex is InvalidVirtualAddressException || 
-                    ex is ArgumentOutOfRangeException ||
-                    ex is IndexOutOfRangeException ||
-                    ex is TaskCanceledException)
-                {
-                    Trace.TraceError("{0} address {1:X16}: {2}", moduleFilePath, address, ex.Message);
-                }
-            }
-        }
-
-        /// <summary>
-        /// Load native modules (i.e. DAC, DBI) from the runtime build id.
-        /// </summary>
-        /// <param name="callback">called back for each symbol file loaded</param>
-        /// <param name="parameter">callback parameter</param>
-        /// <param name="config">Target configuration: Windows, Linux or OSX</param>
-        /// <param name="moduleFilePath">module path</param>
-        /// <param name="specialKeys">if true, returns the DBI/DAC keys, otherwise the identity key</param>
-        /// <param name="moduleIndexSize">build id size</param>
-        /// <param name="moduleIndex">pointer to build id</param>
-        private void LoadNativeSymbolsFromIndex(
-            IntPtr self,
-            SymbolFileCallback callback,
-            IntPtr parameter,
-            RuntimeConfiguration config,
-            string moduleFilePath,
-            bool specialKeys,
-            int moduleIndexSize,
-            IntPtr moduleIndex)
-        {
-            if (_symbolService.IsSymbolStoreEnabled)
-            {
-                try
-                {
-                    KeyTypeFlags flags = specialKeys ? KeyTypeFlags.DacDbiKeys : KeyTypeFlags.IdentityKey;
-                    byte[] id = new byte[moduleIndexSize];
-                    Marshal.Copy(moduleIndex, id, 0, moduleIndexSize);
-
-                    IEnumerable<SymbolStoreKey> keys = null;
-                    switch (config)
-                    {
-                        case RuntimeConfiguration.UnixCore:
-                            keys = ELFFileKeyGenerator.GetKeys(flags, moduleFilePath, id, symbolFile: false, symbolFileName: null);
-                            break;
-
-                        case RuntimeConfiguration.OSXCore:
-                            keys = MachOFileKeyGenerator.GetKeys(flags, moduleFilePath, id, symbolFile: false, symbolFileName: null);
-                            break;
-
-                        case RuntimeConfiguration.WindowsCore:
-                        case RuntimeConfiguration.WindowsDesktop:
-                            uint timeStamp = BitConverter.ToUInt32(id, 0);
-                            uint fileSize = BitConverter.ToUInt32(id, 4);
-                            SymbolStoreKey key = PEFileKeyGenerator.GetKey(moduleFilePath, timeStamp, fileSize);
-                            keys = new SymbolStoreKey[] { key };
-                            break;
-
-                        default:
-                            Trace.TraceError("LoadNativeSymbolsFromIndex: unsupported platform {0}", config);
-                            return;
-                    }
-                    foreach (SymbolStoreKey key in keys)
-                    {
-                        string moduleFileName = Path.GetFileName(key.FullPathName);
-                        Trace.TraceInformation("{0} {1}", key.FullPathName, key.Index);
-
-                        string downloadFilePath = _symbolService.DownloadFile(key);
-                        if (downloadFilePath != null)
-                        {
-                            Trace.TraceInformation("{0}: {1}", moduleFileName, downloadFilePath);
-                            callback(parameter, moduleFileName, downloadFilePath);
-                        }
-                    }
-                }
-                catch (Exception ex) when (ex is BadInputFormatException || ex is InvalidVirtualAddressException || ex is TaskCanceledException)
-                {
-                    Trace.TraceError("{0} - {1}", ex.Message, moduleFilePath);
-                }
-            }
-        }
-
         /// <summary>
         /// Get expression helper for native SOS.
         /// </summary>
@@ -351,11 +149,13 @@ namespace SOS.Hosting
                 ISymbolFile symbolFile = null;
                 if (loadedPeAddress != 0)
                 {
+                    loadedPeAddress &= _ignoreAddressBitsMask;
                     Stream peStream = _memoryService.CreateMemoryStream(loadedPeAddress, loadedPeSize);
                     symbolFile = _symbolService.OpenSymbolFile(assemblyPath, isFileLayout, peStream);
                 }
                 if (inMemoryPdbAddress != 0)
                 {
+                    inMemoryPdbAddress &= _ignoreAddressBitsMask;
                     Stream pdbStream = _memoryService.CreateMemoryStream(inMemoryPdbAddress, inMemoryPdbSize);
                     symbolFile = _symbolService.OpenSymbolFile(pdbStream);
                 }
index 38b619de929be431c696de9bcf3b1635f7c4461c..f5e7e5eef76ebfa8bedb723fc2d4e74c54c5234c 100644 (file)
@@ -117,16 +117,24 @@ VERIFY:\s*<HEXVAL>\s+<DECVAL>\s+<DECVAL>\s+.*
 VERIFY:\s*Total\s+<DECVAL>\s+objects\s+
 !VERIFY:.*UNKNOWN.*
 
-SOSCOMMAND:DumpAsync
-VERIFY:\s*Statistics:\s+
-VERIFY:\s+MT\s+Count\s+TotalSize\s+Class Name\s+
-VERIFY:\s*<HEXVAL>\s+<DECVAL>\s+<DECVAL>\s+.*
-VERIFY:\s*Total\s+<DECVAL>\s+objects\s+
+SOSCOMMAND:DumpAsync --completed
+VERIFY:\s*STACK <DECVAL>\s*
+VERIFY?:\s*<< Awaiting: <HEXVAL>\s+<HEXVAL>\s+.* >>\s+
+VERIFY:\s*<HEXVAL>\s+<HEXVAL>\s+\((<DECVAL>)?\)\s+.*
+
+SOSCOMMAND:DumpAsync --stats
+VERIFY:\s+MT\s+Count\s+Type\s+
+VERIFY:\s*<HEXVAL>\s+<DECVAL>\s+.*
+!VERIFY:.*UNKNOWN.*
 
-SOSCOMMAND:DumpAsync -mt <POUT>\s+MT\s+Count\s+TotalSize\s+Class Name\s+(<HEXVAL>)\s+<DECVAL>\s+<DECVAL>\s+.*<POUT>
-VERIFY:\s*Statistics:\s+
-VERIFY:\s+MT\s+Count\s+TotalSize\s+Class Name\s+
-VERIFY:\s*<HEXVAL>\s+<DECVAL>\s+<DECVAL>\s+.*
-VERIFY:\s*Total\s+<DECVAL>\s+objects\s+
+SOSCOMMAND:DumpAsync --methodtable 0x<POUT>\s+MT\s+Count\s+Type\s+(<HEXVAL>)\s+<DECVAL>\s+.*<POUT>
+VERIFY:\s*STACK <DECVAL>\s*
+VERIFY?:\s*<< Awaiting: <HEXVAL>\s+<HEXVAL>\s+.* >>\s+
+VERIFY:\s*<HEXVAL>\s+<HEXVAL>\s+\((<DECVAL>)?\)\s+.*
+
+SOSCOMMAND:DumpMT --stats <PREVPOUT>
+!VERIFY:\s*<HEXVAL> is not a MethodTable
 
-SOSCOMMAND:DumpAsync -mt <PREVOUT> -fields
+SOSCOMMAND:DumpAsync --coalesce
+VERIFY:\s*STACKS <DECVAL>\s*
+VERIFY:\s*\[<DECVAL>\]\s+<HEXVAL>\s+\((<DECVAL>)?\)\s+.*
\ No newline at end of file
index 850784346a2a6bea776841fa74f165381d482bdb..bc260ae2419d32334bbc4748e5e4a05fba517e5f 100644 (file)
@@ -645,7 +645,7 @@ HRESULT ExpressionNode::ExpandFields(ICorDebugValue* pInnerValue, __in_z WCHAR*
 
     if(varToExpand[0] == L'(' && pEndCast != NULL)
     {
-        int cchCastTypeName = ((int)(pEndCast-1-varToExpand))/2;
+        size_t cchCastTypeName = ((size_t)(pEndCast-1-varToExpand))/2;
         PopulateType();
         if(_wcslen(pTypeName) != (cchCastTypeName) ||
             _wcsncmp(varToExpand+1, pTypeName, cchCastTypeName) != 0)
@@ -922,7 +922,7 @@ HRESULT ExpressionNode::PopulateTextValueHelper()
 
     BOOL isNull = TRUE;
     ToRelease<ICorDebugValue> pInnerValue;
-    CorElementType corElemType;
+    CorElementType corElemType = ELEMENT_TYPE_MAX;
     ULONG32 cbSize = 0;
     if(pValue != NULL)
     {
@@ -954,7 +954,7 @@ HRESULT ExpressionNode::PopulateTextValueHelper()
         // one piece of data ICorDebugType will tell us if needed.
         if(FAILED(GetCanonicalElementTypeForTypeName(GetTypeName(), &corElemType)))
         {
-            pTypeCast->GetType(&corElemType);
+            IfFailRet(pTypeCast->GetType(&corElemType));
         }
 
         switch(corElemType)
@@ -2153,23 +2153,23 @@ HRESULT ExpressionNode::IsTokenValueTypeOrEnum(mdToken token, IMetaDataImport* p
     {
         ULONG chTypeDef;
         pMetadata->GetTypeRefProps(token, NULL, NULL, 0, &chTypeDef);
-        if(chTypeDef > _countof(nameBuffer))
+        if(chTypeDef > ARRAY_SIZE(nameBuffer))
         {
             *pResult = FALSE;
             return Status;
         }
-        IfFailRet(pMetadata->GetTypeRefProps(token, NULL, nameBuffer, _countof(nameBuffer), &chTypeDef));
+        IfFailRet(pMetadata->GetTypeRefProps(token, NULL, nameBuffer, ARRAY_SIZE(nameBuffer), &chTypeDef));
     }
     else if(type == mdtTypeDef)
     {
         ULONG chTypeDef;
         pMetadata->GetTypeDefProps(token, NULL, 0, &chTypeDef, NULL, NULL);
-        if(chTypeDef > _countof(nameBuffer))
+        if(chTypeDef > ARRAY_SIZE(nameBuffer))
         {
             *pResult = FALSE;
             return Status;
         }
-        IfFailRet(pMetadata->GetTypeDefProps(token, nameBuffer, _countof(nameBuffer), &chTypeDef, NULL, NULL));
+        IfFailRet(pMetadata->GetTypeDefProps(token, nameBuffer, ARRAY_SIZE(nameBuffer), &chTypeDef, NULL, NULL));
     }
 
     if(_wcscmp(nameBuffer, L"System.ValueType") == 0 ||
index 96ddf0b7d55c394523cfb0f251367abc9a1e5555..4fd5ad7bc95eb03952bfbddd2d3f56c190a612dc 100644 (file)
@@ -446,6 +446,31 @@ DbgEngServices::GetOutputWidth()
     return INT_MAX;
 }
 
+HRESULT
+DbgEngServices::SupportsDml(PULONG supported)
+{
+    ULONG opts = 0;
+    HRESULT hr = m_control->GetEngineOptions(&opts);
+    *supported = (SUCCEEDED(hr) && (opts & DEBUG_ENGOPT_PREFER_DML) == DEBUG_ENGOPT_PREFER_DML) ? 1 : 0;
+    return hr;
+}
+
+void
+DbgEngServices::OutputDmlString(
+    ULONG mask,
+    PCSTR message)
+{
+    m_control->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, mask, "%s", message);
+}
+
+HRESULT 
+DbgEngServices::AddModuleSymbol(
+    void* param,
+    const char* symbolFileName)
+{
+    return S_OK;
+}
+
 //----------------------------------------------------------------------------
 // IRemoteMemoryService
 //----------------------------------------------------------------------------
@@ -665,8 +690,6 @@ DbgEngServices::InitializeSymbolStoreFromSymPath()
             {
                 if (strlen(symbolPath) > 0)
                 {
-                    symbolService->DisableSymbolStore();
-
                     if (!symbolService->ParseSymbolPath(symbolPath))
                     {
                         m_control->Output(DEBUG_OUTPUT_ERROR, "Windows symbol path parsing FAILED %s\n", symbolPath.GetPtr());
index 8cd3e593d70e0ed35d0ae8b4c84ece2fa1b8da48..18bd585edb81babf8703a58afd08d58925466a54 100644 (file)
@@ -182,6 +182,17 @@ public:
 
     ULONG STDMETHODCALLTYPE GetOutputWidth();
 
+    HRESULT STDMETHODCALLTYPE SupportsDml(
+        PULONG supported);
+
+    void STDMETHODCALLTYPE OutputDmlString(
+        ULONG mask,
+        PCSTR message);
+
+    HRESULT STDMETHODCALLTYPE AddModuleSymbol(
+        void* param,
+        const char* symbolFileName);
+
     //----------------------------------------------------------------------------
     // IRemoteMemoryService
     //----------------------------------------------------------------------------
index 1bfebed6e50bd93fbdabea30ae60117d2f34440b..434c1b69deac09b89de87286092d3c6b3436bd3a 100644 (file)
@@ -188,7 +188,7 @@ char* PrintOneLine (__in_z char *begin, __in_z char *limit)
                 if (n > 127) {
                     n = 127;
                 }
-                strncpy_s (line,_countof(line), begin, n);
+                strncpy_s (line,ARRAY_SIZE(line), begin, n);
                 line[n] = '\0';
                 ExtOut ("%s", line);
                 begin += n;
@@ -839,7 +839,7 @@ void PrintNativeStack(DWORD_PTR ip, BOOL bSuppressLines)
     char symbol[1024];
     ULONG64 displacement;
 
-    HRESULT hr = g_ExtSymbols->GetNameByOffset(TO_CDADDR(ip), symbol, _countof(symbol), NULL, &displacement);
+    HRESULT hr = g_ExtSymbols->GetNameByOffset(TO_CDADDR(ip), symbol, ARRAY_SIZE(symbol), NULL, &displacement);
     if (SUCCEEDED(hr) && symbol[0] != '\0')
     {
         ExtOut("%s", symbol);
@@ -852,7 +852,7 @@ void PrintNativeStack(DWORD_PTR ip, BOOL bSuppressLines)
         if (!bSuppressLines)
         {
             ULONG line;
-            hr = g_ExtSymbols->GetLineByOffset(TO_CDADDR(ip), &line, filename, _countof(filename), NULL, NULL);
+            hr = g_ExtSymbols->GetLineByOffset(TO_CDADDR(ip), &line, filename, ARRAY_SIZE(filename), NULL, NULL);
             if (SUCCEEDED(hr))
             {
                 ExtOut(" [%s:%d]", filename, line);
index d20cd8b2d9003ee19bf5f70c46e0da252b5fae66..a43e2d3cf4523ca7ea2d96cda7d037ab21a5e694 100644 (file)
@@ -175,7 +175,7 @@ public:
     virtual LPCSTR GetDumpStackObjectsHeading() const   { return s_DSOHeading; }
     virtual LPCSTR GetSPName() const                    { return s_SPName; }
     virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const
-    { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs); }
+    { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = ARRAY_SIZE(s_GCRegs); }
 
     virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
 
@@ -247,7 +247,7 @@ public:
     virtual LPCSTR GetDumpStackObjectsHeading() const   { return s_DSOHeading; }
     virtual LPCSTR GetSPName() const                    { return s_SPName; }
     virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const
-    { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs); }
+    { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = ARRAY_SIZE(s_GCRegs); }
 
     virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
 
@@ -320,7 +320,7 @@ public:
     virtual LPCSTR GetDumpStackObjectsHeading() const   { return s_DSOHeading; }
     virtual LPCSTR GetSPName() const                    { return s_SPName; }
     virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const
-    { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs); }
+    { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = ARRAY_SIZE(s_GCRegs); }
 
     virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
 
@@ -390,7 +390,7 @@ public:
     virtual LPCSTR GetDumpStackObjectsHeading() const   { return s_DSOHeading; }
     virtual LPCSTR GetSPName() const                    { return s_SPName; }
     virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const
-    { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs);}
+    { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = ARRAY_SIZE(s_GCRegs);}
 
     virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
 
index 795b568bc6612f31b0cae447a3b9d05296ad2a3f..2f9b8793c99436597fd513d3da35c73de68203e2 100644 (file)
@@ -419,7 +419,7 @@ void ARMMachine::Unassembly (
         }
 
         ULONG_PTR prevPC = PC;
-        DisasmAndClean (PC, line, _countof(line));
+        DisasmAndClean (PC, line, ARRAY_SIZE(line));
 
         // look at the disassembled bytes
         ptr = line;
@@ -451,7 +451,7 @@ void ARMMachine::Unassembly (
             ULONG_PTR OrigInstrAddr = GCStressCodeCopy + (InstrAddr - PCBegin);
             ULONG_PTR OrigPC = OrigInstrAddr;
 
-            DisasmAndClean(OrigPC, line, _countof(line));
+            DisasmAndClean(OrigPC, line, ARRAY_SIZE(line));
 
             //
             // Increment the real PC based on the size of the unmodifed
index ba68dda69ee7934b24a4992ef4ac23141c23ee93..31f5ccb870a5bffc6c9d27dc3371849a804f9b47 100644 (file)
@@ -163,7 +163,7 @@ void ARM64Machine::Unassembly (
     while(PC < PCEnd)
     {
         ULONG_PTR currentPC = PC;
-        DisasmAndClean (PC, line, _countof(line));
+        DisasmAndClean (PC, line, ARRAY_SIZE(line));
 
         // This is the closing of the previous run. 
         // Check the next instruction. if it's not a the last movk, handle the accumulated value
@@ -265,7 +265,7 @@ void ARM64Machine::Unassembly (
             ULONG_PTR OrigInstrAddr = GCStressCodeCopy + (InstrAddr - PCBegin);
             ULONG_PTR OrigPC = OrigInstrAddr;
 
-            DisasmAndClean(OrigPC, line, _countof(line));
+            DisasmAndClean(OrigPC, line, ARRAY_SIZE(line));
 
             //
             // Increment the real PC based on the size of the unmodifed
index 166cc9ecf0b85c294e2e0ac4415b22f7c3bbddd2..7db5d264deb29c734c2984160c2aaaed2912eaa5 100644 (file)
@@ -150,7 +150,7 @@ inline RegIndex FindReg (___in __in_z char *ptr, __out_opt int *plen = NULL, __o
 
     };
 
-    for (size_t i = 0; i < sizeof(rgRegNames)/sizeof(rgRegNames[0]); i++)
+    for (size_t i = 0; i < ARRAY_SIZE(rgRegNames); i++)
     {
         if (!strncmp(ptr, rgRegNames[i].pszName, rgRegNames[i].cchName))
         {
@@ -577,7 +577,7 @@ void
 
         ULONG_PTR InstrAddr = IP;
 
-        DisasmAndClean (IP, line, _countof(line));
+        DisasmAndClean (IP, line, ARRAY_SIZE(line));
 
         // look at key word
         ptr = line;
@@ -605,7 +605,7 @@ void
             ULONG_PTR OrigInstrAddr = GCStressCodeCopy + (InstrAddr - IPBegin);
             ULONG_PTR OrigIP = OrigInstrAddr;
 
-            DisasmAndClean(OrigIP, line, _countof(line));
+            DisasmAndClean(OrigIP, line, ARRAY_SIZE(line));
 
             //
             // Increment the real IP based on the size of the unmodifed
index 3fcec0382936fba3129d83bb1b12b6317646ad13..2642d0a755619879bde954bd9dee2cc5cd40ed80 100644 (file)
@@ -593,7 +593,7 @@ void GCPrintLargeHeapSegmentInfo(const GCHeapDetails &heap, DWORD_PTR &total_all
     }
 }
 
-void GCPrintPinnedHeapSegmentInfo(const GCHeapDetails &heap, DWORD_PTR &total_allocated_size, DWORD_PTR total_committed_size)
+void GCPrintPinnedHeapSegmentInfo(const GCHeapDetails &heap, DWORD_PTR &total_allocated_size, DWORD_PTR& total_committed_size)
 {
     DWORD_PTR dwAddrSeg;
     DacpHeapSegmentData segment;
@@ -1922,7 +1922,7 @@ BOOL GCHeapSnapshot::AddSegments(const GCHeapDetails& details)
     // this loop will get information for all the heap segments in this heap. The outer loop iterates once
     // for the "normal" generation segments and once for the large object heap. The inner loop follows the chain
     // of segments rooted at AddrSegs[i]
-    for (unsigned int i = 0; i < sizeof(AddrSegs)/sizeof(AddrSegs[0]); ++i)
+    for (unsigned int i = 0; i < ARRAY_SIZE(AddrSegs); ++i)
     {
         if (AddrSegs[i] == NULL)
         {
@@ -2370,4 +2370,4 @@ DWORD_PTR PrintModuleHeapInfo(__out_ecount(count) DWORD_PTR *moduleList, int cou
         *outWasted += wasted;
 
     return toReturn;
-}
\ No newline at end of file
+}
index 8fa4062a6c9f76e04809cab859778b29883cb4e5..e0925c7c3484b8b8f5ae583720082c5e07224987 100644 (file)
@@ -348,7 +348,7 @@ DECLARE_API(HistRoot)
         {&rootstr.data, COSTRING},
     };
 
-    if (!GetCMDOption(args, NULL, 0, arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, NULL, 0, arg, ARRAY_SIZE(arg), &nArg))
         return Status;
 
     if (nArg != 1)
@@ -463,7 +463,7 @@ DECLARE_API(HistObjFind)
         {&objstr.data, COSTRING},
     };
 
-    if (!GetCMDOption(args, NULL, 0, arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, NULL, 0, arg, ARRAY_SIZE(arg), &nArg))
         return Status;
 
     if (nArg != 1)
@@ -542,7 +542,7 @@ DECLARE_API(HistObj)
         {&objstr.data, COSTRING},
     };
 
-    if (!GetCMDOption(args, NULL, 0, arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, NULL, 0, arg, ARRAY_SIZE(arg), &nArg))
         return Status;
 
     if (nArg != 1)
index aeaa6bfe938064857f0cca94861bc6c32c4eb250..a649bad82c69aa92240d83cf59da220ad0ad02a9 100644 (file)
@@ -220,7 +220,7 @@ void GCRootImpl::GetDependentHandleMap(std::unordered_map<TADDR, std::list<TADDR
 
     do
     {
-        hr = handles->Next(_countof(data), data, &fetched);
+        hr = handles->Next(ARRAY_SIZE(data), data, &fetched);
 
         if (FAILED(hr))
         {
@@ -240,7 +240,7 @@ void GCRootImpl::GetDependentHandleMap(std::unordered_map<TADDR, std::list<TADDR
                 map[obj].push_back(target);
             }
         }
-    } while (fetched == _countof(data));
+    } while (fetched == ARRAY_SIZE(data));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -791,7 +791,7 @@ int GCRootImpl::PrintRootsOnHandleTable(int gen)
     do
     {
         // Fetch more handles
-        hr = pEnum->Next(_countof(handles), handles, &fetched);
+        hr = pEnum->Next(ARRAY_SIZE(handles), handles, &fetched);
         if (FAILED(hr))
         {
             ExtOut("Failed to request more handles.\n");
@@ -833,7 +833,7 @@ int GCRootImpl::PrintRootsOnHandleTable(int gen)
             }
         }
     }
-    while (_countof(handles) == fetched);
+    while (ARRAY_SIZE(handles) == fetched);
 
     return total;
 }
@@ -1244,7 +1244,7 @@ UINT FindAllPinnedAndStrong(DWORD_PTR handlearray[], UINT arraySize)
 
     do
     {
-        hr = handles->Next(_countof(data), data, &fetched);
+        hr = handles->Next(ARRAY_SIZE(data), data, &fetched);
 
         if (FAILED(hr))
         {
@@ -1265,7 +1265,7 @@ UINT FindAllPinnedAndStrong(DWORD_PTR handlearray[], UINT arraySize)
                 handlearray[pos++] = (DWORD_PTR)data[i].Handle;
             }
         }
-    } while (fetched == _countof(data));
+    } while (fetched == ARRAY_SIZE(data));
 
     return pos;
 }
@@ -2190,14 +2190,14 @@ void HeapTraverser::TraceHandles()
 
     do
     {
-        hr = handles->Next(_countof(data), data, &fetched);
+        hr = handles->Next(ARRAY_SIZE(data), data, &fetched);
 
         if (FAILED(hr))
             break;
 
         for (unsigned int i = 0; i < fetched; ++i)
             PrintRoot(W("handle"), (size_t)data[i].Handle);
-    } while (fetched == _countof(data));
+    } while (fetched == ARRAY_SIZE(data));
 }
 
 /* static */ void HeapTraverser::GatherTypes(DWORD_PTR objAddr,size_t Size,
index 292ed4a8ab9616f5ef70ac8507f7cc9915f4c8f1..9dc1d5cc5c1e09eb621489337df9e85f98acf6ab 100644 (file)
@@ -382,7 +382,7 @@ void MDInfo::GetMethodName(mdTypeDef token, CQuickBytes *fullName)
     WCHAR szFunctionName[1024];
 
     hr = m_pImport->GetMethodProps(token, &memTypeDef, 
-                                   szFunctionName, _countof(szFunctionName), &nameLen, 
+                                   szFunctionName, ARRAY_SIZE(szFunctionName), &nameLen, 
                                    &flags, &pbSigBlob, &ulSigBlob, &ulCodeRVA, &ulImplFlags);
     if (FAILED (hr))
     {
@@ -393,12 +393,12 @@ void MDInfo::GetMethodName(mdTypeDef token, CQuickBytes *fullName)
     m_szName[0] = L'\0';
     if (memTypeDef != mdTypeDefNil)
     {
-        hr = NameForTypeDef_s (memTypeDef, m_pImport, m_szName, _countof(m_szName));
+        hr = NameForTypeDef_s (memTypeDef, m_pImport, m_szName, ARRAY_SIZE(m_szName));
         if (SUCCEEDED (hr)) {
-            wcscat_s (m_szName, _countof(m_szName), W("."));
+            wcscat_s (m_szName, ARRAY_SIZE(m_szName), W("."));
         }
     }
-    wcscat_s (m_szName, _countof(m_szName), szFunctionName);
+    wcscat_s (m_szName, ARRAY_SIZE(m_szName), szFunctionName);
 
     LONG lSigBlobRemaining;
     hr = GetFullNameForMD(pbSigBlob, ulSigBlob, &lSigBlobRemaining);
index df9fb2c70ded83f837263546e93aa6f037f57ed9..36ccdb82fd1dbb59fe9696ee519eac71ef9404ef 100644 (file)
@@ -311,12 +311,6 @@ LPCSTR Runtime::GetDacFilePath()
                 m_dacFilePath = _strdup(dacModulePath.c_str());
             }
         }
-
-        if (m_dacFilePath == nullptr)
-        {
-            // Attempt to only load the DAC/DBI modules
-            LoadRuntimeModules();
-        }
     }
     return m_dacFilePath;
 }
@@ -342,12 +336,6 @@ LPCSTR Runtime::GetDbiFilePath()
                 m_dbiFilePath = _strdup(dbiModulePath.c_str());
             }
         }
-
-        if (m_dbiFilePath == nullptr)
-        {
-            // Attempt to only load the DAC/DBI modules
-            LoadRuntimeModules();
-        }
     }
     return m_dbiFilePath;
 }
@@ -646,12 +634,6 @@ HRESULT Runtime::GetEEVersion(VS_FIXEDFILEINFO* pFileInfo, char* fileVersionBuff
     _ASSERTE(pFileInfo);
     _ASSERTE(g_ExtSymbols2 != nullptr);
 
-#ifdef FEATURE_PAL
-    // Load the symbols for runtime. On Linux we are looking for the "sccsid" 
-    // global so "libcoreclr.so/.dylib" symbols need to be loaded.
-    LoadNativeSymbols(true);
-#endif
-
     HRESULT hr = g_ExtSymbols2->GetModuleVersionInformation(
         m_index, 0, "\\", pFileInfo, sizeof(VS_FIXEDFILEINFO), NULL);
 
@@ -697,53 +679,3 @@ void Runtime::DisplayStatus()
         ExtOut("    DBI file path: %s\n", m_dbiFilePath);
     }
 }
-
-/**********************************************************************\
- * Attempt to download the runtime modules (runtime, DAC and DBI)
-\**********************************************************************/
-void Runtime::LoadRuntimeModules()
-{
-    ISymbolService* symbolService = GetSymbolService();
-    if (symbolService != nullptr)
-    {
-        if (m_runtimeInfo != nullptr)
-        {
-            symbolService->LoadNativeSymbolsFromIndex(
-                SymbolFileCallback,
-                this,
-                GetRuntimeConfiguration(),
-                GetRuntimeDllName(),
-                true,                                   // special keys (runtime, DAC and DBI)
-                m_runtimeInfo->RuntimeModuleIndex[0],   // size of module index
-                &m_runtimeInfo->RuntimeModuleIndex[1]); // beginning of index 
-        }
-        else
-        {
-            symbolService->LoadNativeSymbols(
-                SymbolFileCallback,
-                this,
-                GetRuntimeConfiguration(),
-                m_name,
-                m_address,
-                (int)m_size);
-        }
-    }
-}
-
-/**********************************************************************\
- * Called by LoadRuntimeModules to set the DAC and DBI file paths
-\**********************************************************************/
-void Runtime::SymbolFileCallback(const char* moduleFileName, const char* symbolFilePath)
-{
-    if (strcmp(moduleFileName, GetRuntimeDllName()) == 0) {
-        return;
-    }
-    if (strcmp(moduleFileName, GetDacDllName()) == 0) {
-        SetDacFilePath(symbolFilePath);
-        return;
-    }
-    if (strcmp(moduleFileName, NET_DBI_DLL_NAME_A) == 0) {
-        SetDbiFilePath(symbolFilePath);
-        return;
-    }
-}
index 8afcbc4ddcf36151f1c0ca3b93035f32b4c73df5..ac4f43f7df02b667c944c00434dddd5922166b90 100644 (file)
@@ -130,15 +130,6 @@ private:
 
     virtual ~Runtime();
 
-    void LoadRuntimeModules();
-
-    void SymbolFileCallback(const char* moduleFileName, const char* symbolFilePath);
-
-    static void SymbolFileCallback(void* param, const char* moduleFileName, const char* symbolFilePath)
-    {
-        ((Runtime*)param)->SymbolFileCallback(moduleFileName, symbolFilePath);
-    }
-
     void SetDacFilePath(LPCSTR dacFilePath)
     { 
         if (m_dacFilePath == nullptr && dacFilePath != nullptr) {
index 9b5dc7f0d276700249b2e92da4820a61f634c2fa..20f365809c54d2bcc5fdfdb380e10091712beac1 100644 (file)
@@ -264,7 +264,7 @@ LPCSTR Target::GetTempDirectory()
             pid = ::GetCurrentProcessId();
         }
         char pidstr[128];
-        sprintf_s(pidstr, _countof(pidstr), "sos%d", pid);
+        sprintf_s(pidstr, ARRAY_SIZE(pidstr), "sos%d", pid);
         strcat_s(tmpPath, MAX_LONGPATH, pidstr);
         strcat_s(tmpPath, MAX_LONGPATH, DIRECTORY_SEPARATOR_STR_A);
 
index 368d9105696b4f35cdf202285c6e3e2e56a5253e..08c0adf419c0f70c28d84d45f9cafb008312625d 100644 (file)
@@ -182,7 +182,7 @@ void DisassembleToken(IMetaDataImport *i,
             hr = i->GetTypeDefProps(token, szName, 49, &cLen, NULL, NULL);
 
             if (FAILED(hr))
-                StringCchCopyW(szName, COUNTOF(szName), W("<unknown type def>"));
+                StringCchCopyW(szName, ARRAY_SIZE(szName), W("<unknown type def>"));
 
             printf("%S", szName);
         }
@@ -196,7 +196,7 @@ void DisassembleToken(IMetaDataImport *i,
             hr = i->GetTypeRefProps(token, NULL, szName, 49, &cLen);
 
             if (FAILED(hr))
-                StringCchCopyW(szName, COUNTOF(szName), W("<unknown type ref>"));
+                StringCchCopyW(szName, ARRAY_SIZE(szName), W("<unknown type ref>"));
 
             printf("%S", szName);
         }
@@ -213,13 +213,13 @@ void DisassembleToken(IMetaDataImport *i,
                                   NULL, NULL, NULL, NULL, NULL, NULL);
 
             if (FAILED(hr))
-                StringCchCopyW(szFieldName, COUNTOF(szFieldName), W("<unknown field def>"));
+                StringCchCopyW(szFieldName, ARRAY_SIZE(szFieldName), W("<unknown field def>"));
 
             hr = i->GetTypeDefProps(mdClass, szClassName, 49, &cLen,
                                     NULL, NULL);
 
             if (FAILED(hr))
-                StringCchCopyW(szClassName, COUNTOF(szClassName), W("<unknown type def>"));
+                StringCchCopyW(szClassName, ARRAY_SIZE(szClassName), W("<unknown type def>"));
 
             printf("%S::%S", szClassName, szFieldName);
         }
@@ -240,7 +240,7 @@ void DisassembleToken(IMetaDataImport *i,
             MethodSigArgPrettyPrinter methodPrettyPrinter(sig, cbSigBlob, i);
 
             if (FAILED(hr))
-                StringCchCopyW(szFieldName, COUNTOF(szFieldName), W("<unknown method def>"));
+                StringCchCopyW(szFieldName, ARRAY_SIZE(szFieldName), W("<unknown method def>"));
             else
                 methodPrettyPrinter.HandleReturnType();
 
@@ -248,7 +248,7 @@ void DisassembleToken(IMetaDataImport *i,
                                     NULL, NULL);
 
             if (FAILED(hr))
-                StringCchCopyW(szClassName, COUNTOF(szClassName), W("<unknown type def>"));
+                StringCchCopyW(szClassName, ARRAY_SIZE(szClassName), W("<unknown type def>"));
 
             printf("%S::%S", szClassName, szFieldName);
             methodPrettyPrinter.HandleArguments(); // Safe to call in all cases if HandleReturnType hasn't been called. Will do nothing.
@@ -286,7 +286,7 @@ void DisassembleToken(IMetaDataImport *i,
             {
                 if (FAILED(i->GetTypeRefProps(cr, NULL, szName, 50, &cLen)))
                 {
-                    StringCchCopyW(szName, COUNTOF(szName), W("<unknown type ref>"));
+                    StringCchCopyW(szName, ARRAY_SIZE(szName), W("<unknown type ref>"));
                 }
             }
             else if (TypeFromToken(cr) == mdtTypeDef)
@@ -294,7 +294,7 @@ void DisassembleToken(IMetaDataImport *i,
                 if (FAILED(i->GetTypeDefProps(cr, szName, 49, &cLen,
                     NULL, NULL)))
                 {
-                    StringCchCopyW(szName, COUNTOF(szName), W("<unknown type def>"));
+                    StringCchCopyW(szName, ARRAY_SIZE(szName), W("<unknown type def>"));
                 }
             }
             else if (TypeFromToken(cr) == mdtTypeSpec)
@@ -304,7 +304,7 @@ void DisassembleToken(IMetaDataImport *i,
                 PCCOR_SIGNATURE sig;
                 if (FAILED(i->GetTypeSpecFromToken(cr, &sig, &cSig)))
                 {
-                    StringCchCopyW(szName, COUNTOF(szName), W("<Invalid record>"));
+                    StringCchCopyW(szName, ARRAY_SIZE(szName), W("<Invalid record>"));
                 }
                 else
                 {
@@ -314,7 +314,7 @@ void DisassembleToken(IMetaDataImport *i,
             }
             else
             {
-                StringCchCopyW(szName, COUNTOF(szName), W("<unknown type token>"));
+                StringCchCopyW(szName, ARRAY_SIZE(szName), W("<unknown type token>"));
             }
 
             printf("%S::%S", szName, pMemberName);
@@ -708,7 +708,7 @@ static void insertStr(CQuickBytes *out, const char* str) {
 
 static void appendStrNum(CQuickBytes *out, int num) {
     char buff[16];  
-    sprintf_s(buff, COUNTOF(buff), "%d", num);   
+    sprintf_s(buff, ARRAY_SIZE(buff), "%d", num);   
     appendStr(out, buff);   
 }
 
@@ -944,7 +944,7 @@ PCCOR_SIGNATURE PrettyPrintType(
                 if(typ)
                 {
                     char sz[64];
-                    sprintf_s(sz,COUNTOF(sz),"/* UNKNOWN TYPE (0x%X)*/",typ);
+                    sprintf_s(sz,ARRAY_SIZE(sz),"/* UNKNOWN TYPE (0x%X)*/",typ);
                     appendStr(out, sz);
                 }
                 break;  
@@ -979,7 +979,7 @@ const char* PrettyPrintClass(
     if (!pIMD->IsValidToken(tk))
     {
         char str[1024];
-        sprintf_s(str,COUNTOF(str)," [ERROR: INVALID TOKEN 0x%8.8X] ",tk);
+        sprintf_s(str,ARRAY_SIZE(str)," [ERROR: INVALID TOKEN 0x%8.8X] ",tk);
         appendStr(out, str);
         return(asString(out));
     }
@@ -997,7 +997,7 @@ const char* PrettyPrintClass(
                     if (((formatFlags & FormatAssembly) && FAILED(pIMD->GetTypeRefProps(tk, &tkEncloser, nameComplete, MAX_TYPE_NAME_LEN, &unused))))
                     {
                         char str[1024];
-                        sprintf_s(str, COUNTOF(str), " [ERROR: Invalid TypeRef record 0x%8.8X] ", tk);
+                        sprintf_s(str, ARRAY_SIZE(str), " [ERROR: Invalid TypeRef record 0x%8.8X] ", tk);
                         appendStr(out, str);
                         return asString(out);
                     }
@@ -1010,7 +1010,7 @@ const char* PrettyPrintClass(
                     if (FAILED(pIMD->GetTypeDefProps(tk, nameComplete, MAX_TYPE_NAME_LEN, &unused, &typeDefFlags, &tkExtends)))
                     {
                         char str[1024];
-                        sprintf_s(str, COUNTOF(str), " [ERROR: Invalid TypeDef record 0x%8.8X] ", tk);
+                        sprintf_s(str, ARRAY_SIZE(str), " [ERROR: Invalid TypeDef record 0x%8.8X] ", tk);
                         appendStr(out, str);
                         return asString(out);
                     }
@@ -1115,7 +1115,7 @@ const char* PrettyPrintClass(
                 if (FAILED(pIMD->GetTypeSpecFromToken(tk, &sig, &cSig)))
                 {
                     char str[128];
-                    sprintf_s(str, COUNTOF(str), " [ERROR: Invalid token 0x%8.8X] ", tk);
+                    sprintf_s(str, ARRAY_SIZE(str), " [ERROR: Invalid token 0x%8.8X] ", tk);
                     appendStr(out, str);
                 }
                 else
@@ -1131,7 +1131,7 @@ const char* PrettyPrintClass(
         default:
             {
                 char str[128];
-                sprintf_s(str,COUNTOF(str)," [ERROR: INVALID TOKEN TYPE 0x%8.8X] ",tk);
+                sprintf_s(str,ARRAY_SIZE(str)," [ERROR: INVALID TOKEN TYPE 0x%8.8X] ",tk);
                 appendStr(out, str);
             }
     }
index 534ca7b9458cf310aa3767f167967bb18a0fac4e..a430fac743587ae27f233671afc3c5162e0591ea 100644 (file)
@@ -976,7 +976,7 @@ namespace sos
             else if (isString)
             {
                 WCHAR str[32];
-                obj.GetStringData(str, _countof(str));
+                obj.GetStringData(str, ARRAY_SIZE(str));
 
                 _snwprintf_s(buffer, size, _TRUNCATE, W("%s: \"%s\""), mt.GetName(), str);
             }
index 21752c9ab8e74182523920e09d32074d1639c6ce..98a71b678e4f61ba32019e2658ba8a5a371b7dc4 100644 (file)
@@ -46,7 +46,7 @@ namespace sos
     public:
         Exception(const char *format, va_list args)
         {
-            vsprintf_s(mMsg, _countof(mMsg), format, args);
+            vsprintf_s(mMsg, ARRAY_SIZE(mMsg), format, args);
 
             va_end(args);
         }
index 71a874376d087403c411ff5e909ed41d46e9eba4..1ddb33059ec18f63529e9990130997cfa1d1701e 100644 (file)
@@ -68,7 +68,7 @@ typedef enum
 }
 PPFormatFlags;
 
-char* asString(CQuickBytes *out);
+static char* asString(CQuickBytes *out);
 
 PCCOR_SIGNATURE PrettyPrintType(
     PCCOR_SIGNATURE typePtr,            // type to convert,     
@@ -98,4 +98,3 @@ void PrettyPrintClassFromToken(
     DWORD formatFlags = FormatCSharp);  // the format flags for the types
 
 #endif
-
index ffe74d4d7f073904d121f80e3f978c578a208fc8..96a3a0ada40098cce53f8b8fac7defab521b7abe 100644 (file)
@@ -26,15 +26,14 @@ Object Inspection                  Examining code and stacks
 DumpObj (do)                       Threads (clrthreads)
 DumpALC (dumpalc)                  ThreadState
 DumpArray (da)                     IP2MD
-DumpAsync                          U
-DumpDelegate                       DumpStack
-DumpStackObjects (dso)             EEStack
-DumpHeap                           ClrStack
-DumpVC                             GCInfo
-GCRoot                             EHInfo
-ObjSize                            BPMD (bpmd)
-FinalizeQueue                      COMState
-PrintException (pe)
+DumpDelegate                       U
+DumpStackObjects (dso)             DumpStack
+DumpHeap                           EEStack
+DumpVC                             ClrStack
+GCRoot                             GCInfo
+ObjSize                            EHInfo
+FinalizeQueue                      BPMD (bpmd)
+PrintException (pe)                COMState
 TraverseHeap
 
 Examining CLR data structures      Diagnostic Utilities
@@ -361,23 +360,6 @@ specified object was loaded.
 
 \\
 
-COMMAND: dumpasync.
-!DumpAsync [-addr <Object Address>]
-           [-mt <MethodTable address>]
-           [-type <partial type name>]
-           [-tasks]
-           [-completed]
-           [-fields]
-           [-stacks]
-           [-roots]
-
-!DumpAsync traverses the garbage collected heap, looking for objects representing
-async state machines as created when an async method's state is transferred to the
-heap.  This command recognizes async state machines defined as "async void", "async Task",
-"async Task<T>", "async ValueTask", and "async ValueTask<T>".  It also optionally supports
-any other tasks.
-\\
-
 COMMAND: dso.
 COMMAND: dumpstackobjects.
 !DumpStackObjects [-verify] [top stack [bottom stack]]
index a6f53770b5c6ec32bc1284f3d5723bbcfb5a15ae..e72ea0a77bef8ce053dfeee72e369516fd3b8ab8 100644 (file)
@@ -26,14 +26,13 @@ Object Inspection                  Examining code and stacks
 DumpObj (dumpobj)                  Threads (clrthreads)
 DumpALC (dumpalc)                  ThreadState
 DumpArray                          IP2MD (ip2md)
-DumpAsync (dumpasync)              u (clru)
-DumpDelegate (dumpdelegate)        DumpStack (dumpstack)
-DumpStackObjects (dso)             EEStack (eestack)
-DumpHeap (dumpheap)                ClrStack (clrstack)
-DumpVC                             GCInfo
-FinalizeQueue (finalizequeue)      EHInfo
-GCRoot (gcroot)                    bpmd (bpmd)
-PrintException (pe)
+DumpDelegate (dumpdelegate)        u (clru)
+DumpStackObjects (dso)             DumpStack (dumpstack)
+DumpHeap (dumpheap)                EEStack (eestack)
+DumpVC                             ClrStack (clrstack)
+FinalizeQueue (finalizequeue)      GCInfo
+GCRoot (gcroot)                    EHInfo
+PrintException (pe)                bpmd (bpmd)
                                    
 Examining CLR data structures      Diagnostic Utilities
 -----------------------------      -----------------------------
@@ -229,23 +228,6 @@ specified object was loaded.
 
 \\
 
-COMMAND: dumpasync.
-DumpAsync [-addr <Object Address>]
-          [-mt <MethodTable address>]
-          [-type <partial type name>]
-          [-tasks]
-          [-completed]
-          [-fields]
-          [-stacks]
-          [-roots]
-
-DumpAsync traverses the garbage collected heap, looking for objects representing
-async state machines as created when an async method's state is transferred to the
-heap.  This command recognizes async state machines defined as "async void", "async Task",
-"async Task<T>", "async ValueTask", and "async ValueTask<T>".  It also optionally supports
-any other tasks.
-\\
-
 COMMAND: dso.
 COMMAND: dumpstackobjects.
 DumpStackObjects [-verify] [top stack [bottom stack]]
index ffb3a170e1419b93db1912d7bee72dbb76204d0c..0cac8b81bcb1dd706d478bad327339d6479976bb 100644 (file)
@@ -92,8 +92,8 @@ const char *getFacilityName(DWORD_PTR lf)
         {
             if ( lf & 0x1 )
             {
-                strcat_s ( buff, _countof(buff), &(facilities[i].lfName[3]) );
-                strcat_s ( buff, _countof(buff), "`" );
+                strcat_s ( buff, ARRAY_SIZE(buff), &(facilities[i].lfName[3]) );
+                strcat_s ( buff, ARRAY_SIZE(buff), "`" );
             }
             lf >>= 1;
         }
@@ -121,7 +121,7 @@ void formatOutput(struct IDebugDataSpaces* memCallBack, ___in FILE* file, __inou
     
     int iArgCount = 0;
     
-    strcpy_s(formatCopy, _countof(formatCopy), format);
+    strcpy_s(formatCopy, ARRAY_SIZE(formatCopy), format);
     for(;;) 
     {
         char c = *ptr++;
@@ -178,7 +178,7 @@ void formatOutput(struct IDebugDataSpaces* memCallBack, ___in FILE* file, __inou
                                     static WCHAR wszNameBuffer[1024]; // should be large enough
                                     if (g_sos->GetMethodDescName(arg, 1024, wszNameBuffer, NULL) != S_OK)
                                     {
-                                        wcscpy_s(wszNameBuffer, _countof(wszNameBuffer), W("UNKNOWN METHODDESC"));
+                                        wcscpy_s(wszNameBuffer, ARRAY_SIZE(wszNameBuffer), W("UNKNOWN METHODDESC"));
                                     }
 
                                     wcscpy_s(buff, capacity_buff, wszNameBuffer);
@@ -513,7 +513,7 @@ HRESULT StressLog::Dump(ULONG64 outProcLog, const char* fileName, struct IDebugD
             TADDR taFmt = GetFormatAddr(inProcLog, latestMsg->formatOffset, bHasModuleTable);
             hr = memCallBack->ReadVirtual(TO_CDADDR(taFmt), format, 256, 0);
             if (hr != S_OK) 
-                strcpy_s(format, _countof(format), "Could not read address of format string");
+                strcpy_s(format, ARRAY_SIZE(format), "Could not read address of format string");
 
             double deltaTime = ((double) (latestMsg->timeStamp - inProcLog.startTimeStamp)) / inProcLog.tickFrequency;
             if (bDoGcHist)
index 03be99886f7c3af90cdaff92d296d2a846031a9d..0796420cebb09d0fe2f56ea65c2c63a1a98875c7 100644 (file)
@@ -234,7 +234,7 @@ DECLARE_API (MinidumpMode)
     };
 
     size_t nArg;
-    if (!GetCMDOption(args, NULL, 0, arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, NULL, 0, arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -286,7 +286,7 @@ DECLARE_API(IP2MD)
     };
     size_t nArg;
 
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -321,7 +321,7 @@ DECLARE_API(IP2MD)
     }
 
     if (symlines != 0 &&
-        SUCCEEDED(GetLineByOffset(TO_CDADDR(IP), &linenum, filename, _countof(filename))))
+        SUCCEEDED(GetLineByOffset(TO_CDADDR(IP), &linenum, filename, ARRAY_SIZE(filename))))
     {
         ExtOut("Source file:  %S @ %d\n", filename, linenum);
     }
@@ -465,7 +465,7 @@ DECLARE_API(DumpStack)
         {&DSFlag.end, COHEX}
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
         return Status;
 
     // symlines will be non-zero only if SYMOPT_LOAD_LINES was set in the symbol options
@@ -518,7 +518,7 @@ DECLARE_API (EEStack)
         {"/d", &dml, COBOOL, FALSE}
     };
 
-    if (!GetCMDOption(args, option, _countof(option), NULL, 0, NULL))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL))
     {
         return Status;
     }
@@ -703,7 +703,7 @@ DECLARE_API(DumpStackObjects)
     };
     size_t nArg;
 
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -738,7 +738,7 @@ DECLARE_API(DumpMD)
     };
     size_t nArg;
 
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -857,7 +857,7 @@ DECLARE_API(DumpIL)
     };
     size_t nArg;
 
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -1058,7 +1058,7 @@ DECLARE_API(DumpSig)
         {&moduleExpr.data, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(args, NULL, 0, arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, NULL, 0, arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -1106,7 +1106,7 @@ DECLARE_API(DumpSigElem)
         {&moduleExpr.data, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(args, NULL, 0, arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, NULL, 0, arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -1155,7 +1155,7 @@ DECLARE_API(DumpClass)
     };
 
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -1275,7 +1275,7 @@ DECLARE_API(DumpMT)
         {&dwStartAddr, COHEX}
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -1914,7 +1914,7 @@ DECLARE_API(DumpArray)
         {&flags.strObject, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -2130,7 +2130,7 @@ DECLARE_API(DumpObj)
         {&str_Object.data, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -2188,7 +2188,7 @@ DECLARE_API(DumpALC)
         {&str_Object.data, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -2241,7 +2241,7 @@ DECLARE_API(DumpDelegate)
             {&dwAddr, COHEX}
         };
         size_t nArg;
-        if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+        if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
         {
             return Status;
         }
@@ -2512,7 +2512,7 @@ BOOL IsAsyncException(CLRDATA_ADDRESS taObj, CLRDATA_ADDRESS mtObj)
                 xcode = EXCEPTION_COMPLUS;
                 goto Done;
             }
-            for (size_t idx = 0; idx < _countof(AsyncHResultValues); ++idx)
+            for (size_t idx = 0; idx < ARRAY_SIZE(AsyncHResultValues); ++idx)
             {
                 if (ehr == AsyncHResultValues[idx])
                 {
@@ -2533,7 +2533,7 @@ BOOL IsAsyncException(const DacpExceptionObjectData & excData)
         return TRUE;
 
     HRESULT ehr = excData.HResult;
-    for (size_t idx = 0; idx < _countof(AsyncHResultValues); ++idx)
+    for (size_t idx = 0; idx < ARRAY_SIZE(AsyncHResultValues); ++idx)
     {
         if (ehr == AsyncHResultValues[idx])
         {
@@ -2653,13 +2653,13 @@ size_t FormatGeneratedException (DWORD_PTR dataPtr,
                 // The unmodified IP is displayed (above by DumpMDInfoBuffer) which points after the exception in most
                 // cases. This means that the printed IP and the printed line number often will not map to one another
                 // and this is intentional.
-                SUCCEEDED(GetLineByOffset(TO_CDADDR(ste.ip), &linenum, filename, _countof(filename), !bAsync || i > 0)))
+                SUCCEEDED(GetLineByOffset(TO_CDADDR(ste.ip), &linenum, filename, ARRAY_SIZE(filename), !bAsync || i > 0)))
             {
-                swprintf_s(wszLineBuffer, _countof(wszLineBuffer), W("    %s [%s @ %d]\n"), so.String(), filename, linenum);
+                swprintf_s(wszLineBuffer, ARRAY_SIZE(wszLineBuffer), W("    %s [%s @ %d]\n"), so.String(), filename, linenum);
             }
             else
             {
-                swprintf_s(wszLineBuffer, _countof(wszLineBuffer), W("    %s\n"), so.String());
+                swprintf_s(wszLineBuffer, ARRAY_SIZE(wszLineBuffer), W("    %s\n"), so.String());
             }
 
             Length += _wcslen(wszLineBuffer);
@@ -2960,7 +2960,7 @@ DECLARE_API(PrintException)
         {&strObject, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -3126,7 +3126,7 @@ DECLARE_API(DumpVC)
         {&p_Object, COHEX},
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -3168,7 +3168,7 @@ DECLARE_API(DumpRCW)
         {&strObject, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -3296,7 +3296,7 @@ DECLARE_API(DumpCCW)
         {&strObject, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -3552,7 +3552,7 @@ DECLARE_API(DumpPermissionSet)
         {&p_Object, COHEX}
     };
     size_t nArg;
-    if (!GetCMDOption(args, NULL, 0, arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, NULL, 0, arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -3595,7 +3595,7 @@ DECLARE_API(EEHeap)
         {"/d", &dml, COBOOL, FALSE},
     };
 
-    if (!GetCMDOption(args, option, _countof(option), NULL, 0, NULL))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL))
     {
         return Status;
     }
@@ -3641,7 +3641,7 @@ DECLARE_API(EEHeap)
                 break;
 
             char domain[16];
-            sprintf_s(domain, _countof(domain), "Domain %d", n+1);
+            sprintf_s(domain, ARRAY_SIZE(domain), "Domain %d", n+1);
 
             IfFailRet(PrintDomainHeapInfo(domain, pArray[n], &allHeapSize, &wasted));
 
@@ -3819,7 +3819,7 @@ DECLARE_API(TraverseHeap)
         {&Filename.data, COSTRING},
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -3949,7 +3949,7 @@ DECLARE_API(DumpRuntimeTypes)
         {"/d", &dml, COBOOL, FALSE},
     };
 
-    if (!GetCMDOption(args, option, _countof(option), NULL, 0, NULL))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL))
         return Status;
 
     EnableDMLHolder dmlHolder(dml);
@@ -4038,7 +4038,7 @@ public:
         };
 
         size_t nArgs = 0;
-        if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArgs))
+        if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArgs))
             sos::Throw<sos::Exception>("Failed to parse command line arguments.");
 
         if (mStart == 0)
@@ -4171,7 +4171,7 @@ private:
         if (mVerify)
         {
             char buffer[1024];
-            if (!itr.Verify(buffer, _countof(buffer)))
+            if (!itr.Verify(buffer, ARRAY_SIZE(buffer)))
             {
                 ExtOut(buffer);
                 return false;
@@ -4327,7 +4327,7 @@ private:
 
                 // Don't bother calculating the size of the string, just read the full 64 characters of the buffer.  The null
                 // terminator we read will terminate the string.
-                HRESULT hr = g_ExtData->ReadVirtual(TO_CDADDR(addr+offset), tmp.str, sizeof(WCHAR)*(_countof(tmp.str)-1), &fetched);
+                HRESULT hr = g_ExtData->ReadVirtual(TO_CDADDR(addr+offset), tmp.str, sizeof(WCHAR)*(ARRAY_SIZE(tmp.str)-1), &fetched);
                 if (SUCCEEDED(hr))
                 {
                     // Ensure we null terminate the string.  Note that this will not overrun the buffer as we only
@@ -4458,609 +4458,6 @@ private:
     }
 };
 
-/**********************************************************************\
-* Routine Description:                                                 *
-*                                                                      *
-*    This function dumps async state machines on GC heap,              *
-*    displaying details about each async operation found.              *
-*    (May not work if GC is in progress.)                              *
-*                                                                      *
-\**********************************************************************/
-
-void ResolveContinuation(CLRDATA_ADDRESS* contAddr)
-{
-    // Ideally this continuation is itself an async method box.
-    sos::Object contObj = TO_TADDR(*contAddr);
-    if (GetObjFieldOffset(contObj.GetAddress(), contObj.GetMT(), W("StateMachine")) == 0)
-    {
-        // It was something else.
-
-        // If it's a standard task continuation, get its task field.
-        int offset;
-        if ((offset = GetObjFieldOffset(contObj.GetAddress(), contObj.GetMT(), W("m_task"))) != 0)
-        {
-            MOVE(*contAddr, contObj.GetAddress() + offset);
-            if (sos::IsObject(*contAddr, false))
-            {
-                contObj = TO_TADDR(*contAddr);
-            }
-        }
-        else
-        {
-            // If it's storing an action wrapper, try to follow to that action's target.
-            if ((offset = GetObjFieldOffset(contObj.GetAddress(), contObj.GetMT(), W("m_action"))) != 0)
-            {
-                MOVE(*contAddr, contObj.GetAddress() + offset);
-                if (sos::IsObject(*contAddr, false))
-                {
-                    contObj = TO_TADDR(*contAddr);
-                }
-            }
-
-            // If we now have an Action, try to follow through to the delegate's target.
-            if ((offset = GetObjFieldOffset(contObj.GetAddress(), contObj.GetMT(), W("_target"))) != 0)
-            {
-                MOVE(*contAddr, contObj.GetAddress() + offset);
-                if (sos::IsObject(*contAddr, false))
-                {
-                    contObj = TO_TADDR(*contAddr);
-
-                    // In some cases, the delegate's target might be a ContinuationWrapper, in which case we want to unwrap that as well.
-                    if (_wcsncmp(contObj.GetTypeName(), W("System.Runtime.CompilerServices.AsyncMethodBuilderCore+ContinuationWrapper"), 74) == 0 &&
-                       (offset = GetObjFieldOffset(contObj.GetAddress(), contObj.GetMT(), W("_continuation"))) != 0)
-                    {
-                        MOVE(*contAddr, contObj.GetAddress() + offset);
-                        if (sos::IsObject(*contAddr, false))
-                        {
-                            contObj = TO_TADDR(*contAddr);
-                            if ((offset = GetObjFieldOffset(contObj.GetAddress(), contObj.GetMT(), W("_target"))) != 0)
-                            {
-                                MOVE(*contAddr, contObj.GetAddress() + offset);
-                                if (sos::IsObject(*contAddr, false))
-                                {
-                                    contObj = TO_TADDR(*contAddr);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        // Use whatever object we ended with.
-        *contAddr = contObj.GetAddress();
-    }
-}
-
-bool TryGetContinuation(CLRDATA_ADDRESS addr, CLRDATA_ADDRESS mt, CLRDATA_ADDRESS* contAddr)
-{
-    // Get the continuation field from the task.
-    int offset = GetObjFieldOffset(addr, mt, W("m_continuationObject"));
-    if (offset != 0)
-    {
-        DWORD_PTR contObjPtr;
-        MOVE(contObjPtr, addr + offset);
-        if (sos::IsObject(contObjPtr, false))
-        {
-            *contAddr = TO_CDADDR(contObjPtr);
-            ResolveContinuation(contAddr);
-            return true;
-        }
-    }
-
-    return false;
-}
-
-struct AsyncRecord
-{
-    CLRDATA_ADDRESS Address;
-    CLRDATA_ADDRESS MT;
-    DWORD Size;
-    CLRDATA_ADDRESS StateMachineAddr;
-    CLRDATA_ADDRESS StateMachineMT;
-    BOOL FilteredByOptions;
-    BOOL IsStateMachine;
-    BOOL IsValueType;
-    BOOL IsTopLevel;
-    int TaskStateFlags;
-    int StateValue;
-    std::vector<CLRDATA_ADDRESS> Continuations;
-};
-
-bool AsyncRecordIsCompleted(AsyncRecord& ar)
-{
-    const int TASK_STATE_COMPLETED_MASK = 0x1600000;
-    return (ar.TaskStateFlags & TASK_STATE_COMPLETED_MASK) != 0;
-}
-
-const char* GetAsyncRecordStatusDescription(AsyncRecord& ar)
-{
-    const int TASK_STATE_RAN_TO_COMPLETION = 0x1000000;
-    const int TASK_STATE_FAULTED = 0x200000;
-    const int TASK_STATE_CANCELED = 0x400000;
-
-    if ((ar.TaskStateFlags & TASK_STATE_RAN_TO_COMPLETION) != 0) return "Success";
-    if ((ar.TaskStateFlags & TASK_STATE_FAULTED) != 0) return "Failed";
-    if ((ar.TaskStateFlags & TASK_STATE_CANCELED) != 0) return "Canceled";
-    return "Pending";
-}
-
-void ExtOutTaskDelegateMethod(sos::Object& obj)
-{
-    DacpFieldDescData actionField;
-    int offset = GetObjFieldOffset(obj.GetAddress(), obj.GetMT(), W("m_action"), TRUE, &actionField);
-    if (offset != 0)
-    {
-        CLRDATA_ADDRESS actionAddr;
-        MOVE(actionAddr, obj.GetAddress() + offset);
-        CLRDATA_ADDRESS actionMD;
-        if (actionAddr != NULL && TryGetMethodDescriptorForDelegate(actionAddr, &actionMD))
-        {
-            NameForMD_s((DWORD_PTR)actionMD, g_mdName, mdNameLen);
-            ExtOut("(%S) ", g_mdName);
-        }
-    }
-}
-
-void ExtOutTaskStateFlagsDescription(int stateFlags)
-{
-    if (stateFlags == 0) return;
-
-    ExtOut("State Flags: ");
-
-    // TaskCreationOptions.*
-    if ((stateFlags & 0x01) != 0) ExtOut("PreferFairness ");
-    if ((stateFlags & 0x02) != 0) ExtOut("LongRunning ");
-    if ((stateFlags & 0x04) != 0) ExtOut("AttachedToParent ");
-    if ((stateFlags & 0x08) != 0) ExtOut("DenyChildAttach ");
-    if ((stateFlags & 0x10) != 0) ExtOut("HideScheduler ");
-    if ((stateFlags & 0x40) != 0) ExtOut("RunContinuationsAsynchronously ");
-
-    // InternalTaskOptions.*
-    if ((stateFlags & 0x0200) != 0) ExtOut("ContinuationTask ");
-    if ((stateFlags & 0x0400) != 0) ExtOut("PromiseTask ");
-    if ((stateFlags & 0x1000) != 0) ExtOut("LazyCancellation ");
-    if ((stateFlags & 0x2000) != 0) ExtOut("QueuedByRuntime ");
-    if ((stateFlags & 0x4000) != 0) ExtOut("DoNotDispose ");
-
-    // TASK_STATE_*
-    if ((stateFlags & 0x10000) != 0) ExtOut("STARTED ");
-    if ((stateFlags & 0x20000) != 0) ExtOut("DELEGATE_INVOKED ");
-    if ((stateFlags & 0x40000) != 0) ExtOut("DISPOSED ");
-    if ((stateFlags & 0x80000) != 0) ExtOut("EXCEPTIONOBSERVEDBYPARENT ");
-    if ((stateFlags & 0x100000) != 0) ExtOut("CANCELLATIONACKNOWLEDGED ");
-    if ((stateFlags & 0x200000) != 0) ExtOut("FAULTED ");
-    if ((stateFlags & 0x400000) != 0) ExtOut("CANCELED ");
-    if ((stateFlags & 0x800000) != 0) ExtOut("WAITING_ON_CHILDREN ");
-    if ((stateFlags & 0x1000000) != 0) ExtOut("RAN_TO_COMPLETION ");
-    if ((stateFlags & 0x2000000) != 0) ExtOut("WAITINGFORACTIVATION ");
-    if ((stateFlags & 0x4000000) != 0) ExtOut("COMPLETION_RESERVED ");
-    if ((stateFlags & 0x8000000) != 0) ExtOut("THREAD_WAS_ABORTED ");
-    if ((stateFlags & 0x10000000) != 0) ExtOut("WAIT_COMPLETION_NOTIFICATION ");
-    if ((stateFlags & 0x20000000) != 0) ExtOut("EXECUTIONCONTEXT_IS_NULL ");
-    if ((stateFlags & 0x40000000) != 0) ExtOut("TASKSCHEDULED_WAS_FIRED ");
-
-    ExtOut("\n");
-}
-
-void ExtOutStateMachineFields(AsyncRecord& ar)
-{
-    DacpMethodTableData mtabledata;
-    DacpMethodTableFieldData vMethodTableFields;
-    if (mtabledata.Request(g_sos, ar.StateMachineMT) == S_OK &&
-        vMethodTableFields.Request(g_sos, ar.StateMachineMT) == S_OK &&
-        vMethodTableFields.wNumInstanceFields + vMethodTableFields.wNumStaticFields > 0)
-    {
-        DisplayFields(ar.StateMachineMT, &mtabledata, &vMethodTableFields, (DWORD_PTR)ar.StateMachineAddr, TRUE, ar.IsValueType);
-    }
-}
-
-void FindStateMachineTypes(DWORD_PTR* corelibModule, mdTypeDef* stateMachineBox, mdTypeDef* debugStateMachineBox, mdTypeDef* task)
-{
-    int numModule;
-    ArrayHolder<DWORD_PTR> moduleList = ModuleFromName(const_cast<LPSTR>("System.Private.CoreLib.dll"), &numModule);
-    if (moduleList != NULL && numModule == 1)
-    {
-        *corelibModule = moduleList[0];
-        GetInfoFromName(*corelibModule, "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1", stateMachineBox);
-        GetInfoFromName(*corelibModule, "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+DebugFinalizableAsyncStateMachineBox`1", debugStateMachineBox);
-        GetInfoFromName(*corelibModule, "System.Threading.Tasks.Task", task);
-    }
-    else
-    {
-        *corelibModule = 0;
-        *stateMachineBox = 0;
-        *debugStateMachineBox = 0;
-    }
-}
-
-DECLARE_API(DumpAsync)
-{
-    INIT_API();
-    MINIDUMP_NOT_SUPPORTED();
-    if (!g_snapshot.Build())
-    {
-        ExtOut("Unable to build snapshot of the garbage collector state\n");
-        return E_FAIL;
-    }
-
-    try
-    {
-        // Process command-line arguments.
-        size_t nArg = 0;
-        TADDR mt = NULL, addr = NULL;
-        ArrayHolder<char> ansiType = NULL;
-        ArrayHolder<WCHAR> type = NULL;
-        BOOL dml = FALSE, includeCompleted = FALSE, includeStacks = FALSE, includeRoots = FALSE, includeAllTasks = FALSE, dumpFields = FALSE;
-        CMDOption option[] =
-        {   // name, vptr, type, hasValue
-            { "-addr", &addr, COHEX, TRUE },                // dump only the async object at the specified address
-            { "-mt", &mt, COHEX, TRUE },                        // dump only async objects with a given MethodTable
-            { "-type", &ansiType, COSTRING, TRUE },             // dump only async objects that contain the specified type substring
-            { "-tasks", &includeAllTasks, COBOOL, FALSE },      // include all tasks that can be found on the heap, not just async methods
-            { "-completed", &includeCompleted, COBOOL, FALSE }, // include async objects that are in a completed state
-            { "-fields", &dumpFields, COBOOL, FALSE },          // show relevant fields of found async objects
-            { "-stacks", &includeStacks, COBOOL, FALSE },       // gather and output continuation/stack information
-            { "-roots", &includeRoots, COBOOL, FALSE },         // gather and output GC root information
-            { "/d", &dml, COBOOL, FALSE },                      // Debugger Markup Language
-        };
-        if (!GetCMDOption(args, option, _countof(option), NULL, 0, &nArg) || nArg != 0)
-        {
-            sos::Throw<sos::Exception>(
-                "Usage: DumpAsync [-addr ObjectAddr] [-mt MethodTableAddr] [-type TypeName] [-tasks] [-completed] [-fields] [-stacks] [-roots]\n"
-                "[-addr ObjectAddr]     => Only display the async object at the specified address.\n"
-                "[-mt MethodTableAddr]  => Only display top-level async objects with the specified method table address.\n"
-                "[-type TypeName]       => Only display top-level async objects whose type name includes the specified substring.\n"
-                "[-tasks]               => Include Task and Task-derived objects, in addition to any state machine objects found.\n"
-                "[-completed]           => Include async objects that represent completed operations but that are still on the heap.\n"
-                "[-fields]              => Show the fields of state machines.\n"
-                "[-stacks]              => Gather, output, and consolidate based on continuation chains / async stacks for discovered async objects.\n"
-                "[-roots]               => Perform a gcroot on each rendered async object.\n"
-                );
-        }
-        if (ansiType != NULL)
-        {
-            size_t ansiTypeLen = strlen(ansiType) + 1;
-            type = new WCHAR[ansiTypeLen];
-            MultiByteToWideChar(CP_ACP, 0, ansiType, -1, type, (int)ansiTypeLen);
-        }
-
-        EnableDMLHolder dmlHolder(dml);
-        BOOL hasTypeFilter = mt != NULL || ansiType != NULL || addr != NULL;
-
-        // Display a message if the heap isn't verified.
-        sos::GCHeap gcheap;
-        if (!gcheap.AreGCStructuresValid())
-        {
-            DisplayInvalidStructuresMessage();
-        }
-
-        // Find the state machine types
-        DWORD_PTR corelibModule;
-        mdTypeDef stateMachineBoxMd, debugStateMachineBoxMd, taskMd;
-        FindStateMachineTypes(&corelibModule, &stateMachineBoxMd, &debugStateMachineBoxMd, &taskMd);
-
-        // Walk each heap object looking for async state machine objects.  As we're targeting .NET Core 2.1+, all such objects
-        // will be Task or Task-derived types.
-        std::map<CLRDATA_ADDRESS, AsyncRecord> asyncRecords;
-        for (sos::ObjectIterator itr = gcheap.WalkHeap(); !IsInterrupt() && itr != NULL; ++itr)
-        {
-            // Skip objects too small to be state machines or tasks, avoiding some compiler-generated caching data structures.
-            if (itr->GetSize() <= 24)
-            {
-                continue;
-            }
-
-            // Match only async objects.
-            if (includeAllTasks)
-            {
-                // If the user has selected to include all tasks and not just async state machine boxes, we simply need to validate
-                // that this is Task or Task-derived, and if it's not, skip it.
-                if (!IsDerivedFrom(itr->GetMT(), corelibModule, taskMd))
-                {
-                    continue;
-                }
-            }
-            else
-            {
-                // Otherwise, we only care about AsyncStateMachineBox`1 as well as the DebugFinalizableAsyncStateMachineBox`1
-                // that's used when certain ETW events are set.
-                DacpMethodTableData mtdata;
-                if (mtdata.Request(g_sos, TO_TADDR(itr->GetMT())) != S_OK ||
-                    mtdata.Module != corelibModule ||
-                    (mtdata.cl != stateMachineBoxMd && mtdata.cl != debugStateMachineBoxMd))
-                {
-                    continue;
-                }
-            }
-
-            // Create an AsyncRecord to store the state for this instance.  We're likely going to keep the object at this point,
-            // though we may still discard/skip it with a few checks later; to do that, though, we'll need some of the info
-            // gathered here, so we construct the record to store the data.
-            AsyncRecord ar;
-            ar.Address = itr->GetAddress();
-            ar.MT = itr->GetMT();
-            ar.Size = (DWORD)itr->GetSize();
-            ar.StateMachineAddr = itr->GetAddress();
-            ar.StateMachineMT = itr->GetMT();
-            ar.IsValueType = false;
-            ar.IsTopLevel = true;
-            ar.IsStateMachine = false;
-            ar.TaskStateFlags = 0;
-            ar.StateValue = 0;
-            ar.FilteredByOptions = // we process all objects to support forming proper chains, but then only display ones that match the user's request
-                (mt == NULL || mt == itr->GetMT()) && // Match only MTs the user requested.
-                (type == NULL || _wcsstr(itr->GetTypeName(), type) != NULL) && // Match only type name substrings the user requested.
-                (addr == NULL || addr == itr->GetAddress()); // Match only the object at the specified address.
-
-            // Get the state flags for the task.  This is used to determine whether async objects are completed (and thus should
-            // be culled by default).  It avoids our needing to depend on interpreting the compiler's "<>1__state" field, and also lets
-            // us display state information for non-async state machine objects.
-            DacpFieldDescData stateFlagsField;
-            int offset = GetObjFieldOffset(ar.Address, ar.MT, W("m_stateFlags"), TRUE, &stateFlagsField);
-            if (offset != 0)
-            {
-                MOVE(ar.TaskStateFlags, ar.Address + offset);
-            }
-
-            // Get the async state machine object's StateMachine field.
-            DacpFieldDescData stateMachineField;
-            int stateMachineFieldOffset = GetObjFieldOffset(TO_CDADDR(itr->GetAddress()), itr->GetMT(), W("StateMachine"), TRUE, &stateMachineField);
-            if (stateMachineFieldOffset != 0)
-            {
-                ar.IsStateMachine = true;
-                ar.IsValueType = stateMachineField.Type == ELEMENT_TYPE_VALUETYPE;
-
-                // Get the address and method table of the state machine.  While it'll generally be a struct, it is valid for it to be a
-                // class (the C# compiler generates a class in debug builds to better support Edit-And-Continue), so we accommodate both.
-                DacpFieldDescData stateField;
-                int stateFieldOffset = -1;
-                if (ar.IsValueType)
-                {
-                    ar.StateMachineAddr = itr->GetAddress() + stateMachineFieldOffset;
-                    ar.StateMachineMT = stateMachineField.MTOfType;
-                    stateFieldOffset = GetValueFieldOffset(ar.StateMachineMT, W("<>1__state"), &stateField);
-                }
-                else
-                {
-                    MOVE(ar.StateMachineAddr, itr->GetAddress() + stateMachineFieldOffset);
-                    DacpObjectData objData;
-                    if (objData.Request(g_sos, ar.StateMachineAddr) == S_OK)
-                    {
-                        ar.StateMachineMT = objData.MethodTable; // update from Canon to actual type
-                        stateFieldOffset = GetObjFieldOffset(ar.StateMachineAddr, ar.StateMachineMT, W("<>1__state"), TRUE, &stateField);
-                    }
-                }
-
-                if (stateFieldOffset >= 0 && (ar.IsValueType || stateFieldOffset != 0))
-                {
-                    MOVE(ar.StateValue, ar.StateMachineAddr + stateFieldOffset);
-                }
-            }
-
-            // If we only want to include incomplete async objects, skip this one if it's completed.
-            if (!includeCompleted && AsyncRecordIsCompleted(ar))
-            {
-                continue;
-            }
-
-            // If the user has asked to include "async stacks" information, resolve any continuation
-            // that might be registered with it.  This could be a single continuation, or it could
-            // be a list of continuations in the case of the same task being awaited multiple times.
-            CLRDATA_ADDRESS nextAddr;
-            if (includeStacks && TryGetContinuation(itr->GetAddress(), itr->GetMT(), &nextAddr))
-            {
-                sos::Object contObj = TO_TADDR(nextAddr);
-                if (_wcsncmp(contObj.GetTypeName(), W("System.Collections.Generic.List`1"), 33) == 0)
-                {
-                    // The continuation is a List<object>.  Iterate through its internal object[]
-                    // looking for non-null objects, and adding each one as a continuation.
-                    int itemsOffset = GetObjFieldOffset(contObj.GetAddress(), contObj.GetMT(), W("_items"));
-                    if (itemsOffset != 0)
-                    {
-                        DWORD_PTR listItemsPtr;
-                        MOVE(listItemsPtr, contObj.GetAddress() + itemsOffset);
-                        if (sos::IsObject(listItemsPtr, false))
-                        {
-                            DacpObjectData objData;
-                            if (objData.Request(g_sos, TO_CDADDR(listItemsPtr)) == S_OK && objData.ObjectType == OBJ_ARRAY)
-                            {
-                                for (int i = 0; i < objData.dwNumComponents; i++)
-                                {
-                                    CLRDATA_ADDRESS elementPtr;
-                                    MOVE(elementPtr, TO_CDADDR(objData.ArrayDataPtr + (i * objData.dwComponentSize)));
-                                    if (elementPtr != NULL && sos::IsObject(elementPtr, false))
-                                    {
-                                        ResolveContinuation(&elementPtr);
-                                        ar.Continuations.push_back(elementPtr);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-                else
-                {
-                    ar.Continuations.push_back(contObj.GetAddress());
-                }
-            }
-
-            // We've gathered all of the needed information for this heap object.  Add it to our list of async records.
-            asyncRecords.insert(std::pair<CLRDATA_ADDRESS, AsyncRecord>(ar.Address, ar));
-        }
-
-        // As with DumpHeap, output a summary table about all of the objects we found.  In contrast, though, his is based on the filtered
-        // list of async records we gathered rather than everything on the heap.
-        if (addr == NULL) // no point in stats if we're only targeting a single object
-        {
-            HeapStat stats;
-            for (std::map<CLRDATA_ADDRESS, AsyncRecord>::iterator arIt = asyncRecords.begin(); arIt != asyncRecords.end(); ++arIt)
-            {
-                if (!hasTypeFilter || arIt->second.FilteredByOptions)
-                {
-                    stats.Add((DWORD_PTR)arIt->second.MT, (DWORD)arIt->second.Size);
-                }
-            }
-            stats.Sort();
-            stats.Print();
-        }
-
-        // If the user has asked for "async stacks" and if there's not MT/type name filter, look through all of our async records
-        // to find the "top-level" nodes that start rather than that are a part of a continuation chain.  When we then iterate through
-        // async records, we only print ones out that are still classified as top-level.  We don't do this if there's a type filter
-        // because in that case we consider those and only those objects to be top-level.
-        if (includeStacks && !hasTypeFilter)
-        {
-            size_t uniqueChains = asyncRecords.size();
-            for (std::map<CLRDATA_ADDRESS, AsyncRecord>::iterator arIt = asyncRecords.begin(); arIt != asyncRecords.end(); ++arIt)
-            {
-                for (std::vector<CLRDATA_ADDRESS>::iterator contIt = arIt->second.Continuations.begin(); contIt != arIt->second.Continuations.end(); ++contIt)
-                {
-                    std::map<CLRDATA_ADDRESS, AsyncRecord>::iterator found = asyncRecords.find(*contIt);
-                    if (found != asyncRecords.end())
-                    {
-                        if (found->second.IsTopLevel)
-                        {
-                            found->second.IsTopLevel = false;
-                            uniqueChains--;
-                        }
-                    }
-                }
-            }
-
-            ExtOut("In %d chains.\n", uniqueChains);
-        }
-
-        // Print out header for the main line of each result.
-        ExtOut("%" POINTERSIZE "s %" POINTERSIZE "s %8s ", "Address", "MT", "Size");
-        if (includeCompleted) ExtOut("%8s ", "Status");
-        ExtOut("%10s %s\n", "State", "Description");
-
-        // Output each top-level async record.
-        int counter = 0;
-        for (std::map<CLRDATA_ADDRESS, AsyncRecord>::iterator arIt = asyncRecords.begin(); arIt != asyncRecords.end(); ++arIt)
-        {
-            if (!arIt->second.IsTopLevel || (hasTypeFilter && !arIt->second.FilteredByOptions))
-            {
-                continue;
-            }
-
-            // Output the state machine's details as a single line.
-            sos::Object obj = TO_TADDR(arIt->second.Address);
-            if (arIt->second.IsStateMachine)
-            {
-                // This has a StateMachine.  Output its details.
-                sos::MethodTable mt = TO_TADDR(arIt->second.StateMachineMT);
-                DMLOut("%s %s %8d ", DMLAsync(obj.GetAddress()), DMLDumpHeapMT(obj.GetMT()), obj.GetSize());
-                if (includeCompleted) ExtOut("%8s ", GetAsyncRecordStatusDescription(arIt->second));
-                ExtOut("%10d %S\n", arIt->second.StateValue, mt.GetName());
-                if (dumpFields) ExtOutStateMachineFields(arIt->second);
-            }
-            else
-            {
-                // This does not have a StateMachine.  Output the details of the Task itself.
-                DMLOut("%s %s %8d ", DMLAsync(obj.GetAddress()), DMLDumpHeapMT(obj.GetMT()), obj.GetSize());
-                if (includeCompleted) ExtOut("%8s ", GetAsyncRecordStatusDescription(arIt->second));
-                ExtOut("[%08x] %S ", arIt->second.TaskStateFlags, obj.GetTypeName());
-                ExtOutTaskDelegateMethod(obj);
-                ExtOut("\n");
-                if (dumpFields) ExtOutTaskStateFlagsDescription(arIt->second.TaskStateFlags);
-            }
-
-            // If we gathered any continuations for this record, output the chains now.
-            if (includeStacks && arIt->second.Continuations.size() > 0)
-            {
-                ExtOut(includeAllTasks ? "Continuation chains:\n" : "Async \"stack\":\n");
-                std::vector<std::pair<int, CLRDATA_ADDRESS>> continuationChainToExplore;
-                continuationChainToExplore.push_back(std::pair<int, CLRDATA_ADDRESS>(1, obj.GetAddress()));
-
-                // Do a depth-first traversal of continuations, outputting each continuation found and then
-                // looking in our gathered objects list for its continuations.
-                std::set<CLRDATA_ADDRESS> seen;
-                while (continuationChainToExplore.size() > 0)
-                {
-                    // Pop the next continuation from the stack.
-                    std::pair<int, CLRDATA_ADDRESS> cur = continuationChainToExplore.back();
-                    continuationChainToExplore.pop_back();
-
-                    // Get the async record for this continuation.  It should be one we already know about.
-                    std::map<CLRDATA_ADDRESS, AsyncRecord>::iterator curAsyncRecord = asyncRecords.find(cur.second);
-                    if (curAsyncRecord == asyncRecords.end())
-                    {
-                        continue;
-                    }
-
-                    // Make sure to avoid cycles in the rare case where async records may refer to each other.
-                    if (seen.find(cur.second) != seen.end())
-                    {
-                        continue;
-                    }
-                    seen.insert(cur.second);
-
-                    // Iterate through all continuations from this object.
-                    for (std::vector<CLRDATA_ADDRESS>::iterator contIt = curAsyncRecord->second.Continuations.begin(); contIt != curAsyncRecord->second.Continuations.end(); ++contIt)
-                    {
-                        sos::Object cont = TO_TADDR(*contIt);
-
-                        // Print out the depth of the continuation with dots, then its address.
-                        for (int i = 0; i < cur.first; i++) ExtOut(".");
-                        DMLOut("%s ", DMLObject(cont.GetAddress()));
-
-                        // Print out the name of the method for this task's delegate if it has one (state machines won't, but others tasks may).
-                        ExtOutTaskDelegateMethod(cont);
-
-                        // Find the async record for this continuation, and output its name.  If it's a state machine,
-                        // also output its current state value so that a user can see at a glance its status.
-                        std::map<CLRDATA_ADDRESS, AsyncRecord>::iterator contAsyncRecord = asyncRecords.find(cont.GetAddress());
-                        if (contAsyncRecord != asyncRecords.end())
-                        {
-                            sos::MethodTable contMT = TO_TADDR(contAsyncRecord->second.StateMachineMT);
-                            if (contAsyncRecord->second.IsStateMachine) ExtOut("(%d) ", contAsyncRecord->second.StateValue);
-                            ExtOut("%S\n", contMT.GetName());
-                            if (contAsyncRecord->second.IsStateMachine && dumpFields) ExtOutStateMachineFields(contAsyncRecord->second);
-                        }
-                        else
-                        {
-                            ExtOut("%S\n", cont.GetTypeName());
-                        }
-
-                        // Add this continuation to the stack to explore.
-                        continuationChainToExplore.push_back(std::pair<int, CLRDATA_ADDRESS>(cur.first + 1, *contIt));
-                    }
-                }
-            }
-
-            // Finally, output gcroots, as they can serve as alternative/more detailed "async stacks", and also help to highlight
-            // state machines that aren't being kept alive.  However, they're more expensive to compute, so they're opt-in.
-            if (includeRoots)
-            {
-                ExtOut("GC roots:\n");
-                IncrementIndent();
-                GCRootImpl gcroot;
-                int numRoots = gcroot.PrintRootsForObject(obj.GetAddress(), FALSE, FALSE);
-                DecrementIndent();
-                if (numRoots == 0 && !AsyncRecordIsCompleted(arIt->second))
-                {
-                    ExtOut("Incomplete state machine or task with 0 roots.\n");
-                }
-            }
-
-            // If we're rendering more than one line per entry, output a separator to help distinguish the entries.
-            if (dumpFields || includeStacks || includeRoots)
-            {
-                ExtOut("--------------------------------------------------------------------------------\n");
-            }
-        }
-
-        return S_OK;
-    }
-    catch (const sos::Exception &e)
-    {
-        ExtOut("%s\n", e.what());
-        return E_FAIL;
-    }
-}
-
 /**********************************************************************\
 * Routine Description:                                                 *
 *                                                                      *
@@ -5115,7 +4512,7 @@ DECLARE_API(VerifyHeap)
 
         while (itr)
         {
-            if (itr.Verify(buffer, _countof(buffer)))
+            if (itr.Verify(buffer, ARRAY_SIZE(buffer)))
             {
                 ++itr;
             }
@@ -5330,7 +4727,7 @@ DECLARE_API(VerifyObj)
         {&taddrObj, COHEX}
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -5392,7 +4789,7 @@ DECLARE_API(ListNearObj)
         {&taddrArg, COHEX}
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg) || nArg != 1)
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg) || nArg != 1)
     {
         ExtOut("Usage: !ListNearObj <obj_address>\n");
         return Status;
@@ -5577,7 +4974,7 @@ DECLARE_API(GCHeapStat)
         {"/d",            &dml, COBOOL, FALSE}
     };
 
-    if (!GetCMDOption(args, option, _countof(option), NULL, 0, NULL))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL))
     {
         return Status;
     }
@@ -5791,7 +5188,7 @@ DECLARE_API(SyncBlk)
         {&nbAsked, COSIZE_T}
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -6070,7 +5467,7 @@ DECLARE_API(FinalizeQueue)
         {"-mt",       &taddrMT,   COHEX,  TRUE},
     };
 
-    if (!GetCMDOption(args, option, _countof(option), NULL, 0, NULL))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL))
     {
         return Status;
     }
@@ -6265,7 +5662,7 @@ DECLARE_API(DumpModule)
     };
 
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -6436,7 +5833,7 @@ DECLARE_API(DumpDomain)
     };
     size_t nArg;
 
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -6557,7 +5954,7 @@ DECLARE_API(DumpAssembly)
     };
     size_t nArg;
 
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -7087,7 +6484,7 @@ DECLARE_API(ThreadState)
     if (state)
     {
 
-        for (unsigned int i = 0; i < _countof(ThreadStates); ++i)
+        for (unsigned int i = 0; i < ARRAY_SIZE(ThreadStates); ++i)
             if (state & ThreadStates[i].State)
             {
                 ExtOut("    %s\n", ThreadStates[i].Name);
@@ -7119,7 +6516,7 @@ DECLARE_API(Threads)
         {"-managedexception", &bSwitchToManagedExceptionThread, COBOOL, FALSE},
         {"/d", &dml, COBOOL, FALSE},
     };
-    if (!GetCMDOption(args, option, _countof(option), NULL, 0, NULL))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL))
     {
         return Status;
     }
@@ -7293,13 +6690,13 @@ void IssueDebuggerBPCommand ( CLRDATA_ADDRESS addr )
         if (g_sos->GetMethodDescPtrFromIP(addr, &pMD) != S_OK
             || g_sos->GetMethodDescName(pMD, 1024, wszNameBuffer, NULL) != S_OK)
         {
-            wcscpy_s(wszNameBuffer, _countof(wszNameBuffer), W("UNKNOWN"));
+            wcscpy_s(wszNameBuffer, ARRAY_SIZE(wszNameBuffer), W("UNKNOWN"));
         }
 
 #ifndef FEATURE_PAL
-        sprintf_s(buffer, _countof(buffer), "bp %p", SOS_PTR(addr));
+        sprintf_s(buffer, ARRAY_SIZE(buffer), "bp %p", SOS_PTR(addr));
 #else
-        sprintf_s(buffer, _countof(buffer), "breakpoint set --address 0x%p", SOS_PTR(addr));
+        sprintf_s(buffer, ARRAY_SIZE(buffer), "breakpoint set --address 0x%p", SOS_PTR(addr));
 #endif
         ExtOut("Setting breakpoint: %s [%S]\n", buffer, wszNameBuffer);
         g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer, 0);
@@ -8059,9 +7456,9 @@ public:
             {
                 CHAR buffer[100];
 #ifndef FEATURE_PAL
-                sprintf_s(buffer, _countof(buffer), "bp /1 %p", SOS_PTR(startAddr+catcherNativeOffset));
+                sprintf_s(buffer, ARRAY_SIZE(buffer), "bp /1 %p", SOS_PTR(startAddr+catcherNativeOffset));
 #else
-                sprintf_s(buffer, _countof(buffer), "breakpoint set --one-shot --address 0x%p", SOS_PTR(startAddr+catcherNativeOffset));
+                sprintf_s(buffer, ARRAY_SIZE(buffer), "breakpoint set --one-shot --address 0x%p", SOS_PTR(startAddr+catcherNativeOffset));
 #endif
                 g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer, 0);
             }
@@ -8089,7 +7486,7 @@ BOOL CheckCLRNotificationEvent(DEBUG_LAST_EVENT_INFO_EXCEPTION* pdle)
 
     if (SUCCEEDED(Status = g_sos->QueryInterface(__uuidof(ISOSDacInterface4), (void**) &psos4)))
     {
-        int count = _countof(arguments);
+        int count = ARRAY_SIZE(arguments);
         int countNeeded = 0;
 
         Status = psos4->GetClrNotification(arguments, count, &countNeeded);
@@ -8280,7 +7677,7 @@ DECLARE_API(bpmd)
         {&Offset, COSIZE_T},
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -8477,7 +7874,7 @@ DECLARE_API(bpmd)
                             TypeName.data = new NOTHROW char[buffSize];
                             if (TypeName.data != NULL)
                             {
-                                int bytesWritten = WideCharToMultiByte(CP_ACP, 0, FunctionName, -1, TypeName.data, buffSize, NULL, NULL);
+                                INDEBUG(int bytesWritten =) WideCharToMultiByte(CP_ACP, 0, FunctionName, -1, TypeName.data, buffSize, NULL, NULL);
                                 _ASSERTE(bytesWritten == buffSize);
                             }
                         }
@@ -8566,7 +7963,7 @@ DECLARE_API(bpmd)
             ExtOut("This DynamicMethodDesc is not yet JITTED. Placing memory breakpoint at %p\n",
                 SOS_PTR(MethodDescData.AddressOfNativeCodeSlot));
 
-            sprintf_s(buffer, _countof(buffer),
+            sprintf_s(buffer, ARRAY_SIZE(buffer),
 #ifdef _TARGET_WIN64_
                 "ba w8"
 #else
@@ -8639,7 +8036,7 @@ DECLARE_API(ThreadPool)
         {"/d", &dml, COBOOL, FALSE},
     };
 
-    if (!GetCMDOption(args, option, _countof(option), NULL, 0, NULL))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL))
     {
         return E_FAIL;
     }
@@ -9101,7 +8498,6 @@ DECLARE_API(ThreadPool)
                         TO_CDADDR(vPortableTpHcLogArray.ArrayDataPtr + (index * sizeof(HillClimbingLogEntry)));
                     INT32 i32Value = 0;
                     float f32Value = 0;
-                    int fieldOffset = 0;
 
                     if (FAILED(Status = MOVE(i32Value, entryPtr + portableTpHcLogEntry_tickCountOffset)))
                     {
@@ -9206,7 +8602,7 @@ DECLARE_API(FindAppDomain)
     };
     size_t nArg;
 
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -9476,7 +8872,7 @@ DECLARE_API(EHInfo)
     };
 
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg) || (0 == nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg) || (0 == nArg))
     {
         return Status;
     }
@@ -9557,7 +8953,7 @@ DECLARE_API(GCInfo)
         {&taStartAddr, COHEX},
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg) || (0 == nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg) || (0 == nArg))
     {
         return Status;
     }
@@ -9864,7 +9260,7 @@ DECLARE_API(u)
     {   // vptr, type
         {&dwStartAddr, COHEX},
     };
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg) || (nArg < 1))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg) || (nArg < 1))
     {
         return Status;
     }
@@ -10399,7 +9795,7 @@ DECLARE_API(DumpLog)
         {&sFileName.data, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -10972,7 +10368,7 @@ DECLARE_API(SOSStatus)
             {"--reset", &bReset, COBOOL, FALSE},
             {"-r", &bReset, COBOOL, FALSE},
         };
-        if (!GetCMDOption(args, option, _countof(option), NULL, 0, NULL))
+        if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL))
         {
             return Status;
         }
@@ -10983,7 +10379,6 @@ DECLARE_API(SOSStatus)
             return S_OK;
         }
         Target::DisplayStatus();
-        DisplaySymbolStore();
     }
     return Status;
 }
@@ -11097,7 +10492,7 @@ DECLARE_API (ProcInfo)
                 end = _wcschr (pt, L'\0');
                 if (end == NULL) {
                     char format[20];
-                    sprintf_s (format,_countof (format), "%dS", &buffer[DT_OS_PAGE_SIZE/2] - pt);
+                    sprintf_s (format, ARRAY_SIZE(format), "%dS", &buffer[DT_OS_PAGE_SIZE/2] - pt);
                     ExtOut(format, pt);
                     break;
                 }
@@ -11297,7 +10692,7 @@ DECLARE_API(Token2EE)
     };
 
     size_t nArg;
-    if (!GetCMDOption(args,option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args,option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -11389,7 +10784,7 @@ DECLARE_API(Name2EE)
     };
     size_t nArg;
 
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -11510,7 +10905,7 @@ DECLARE_API(PathTo)
         {&root, COHEX},
         {&target, COHEX},
     };
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -11560,7 +10955,7 @@ DECLARE_API(GCRoot)
     {   // vptr, type
         {&obj, COHEX}
     };
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -11606,7 +11001,7 @@ DECLARE_API(GCWhere)
     {   // vptr, type
         {&taddrObj, COHEX}
     };
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -11735,7 +11130,7 @@ DECLARE_API(FindRoots)
     {   // vptr, type
         {&taObj, COHEX}
     };
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -11958,7 +11353,7 @@ public:
             {"/d", &mDML, COBOOL, FALSE},
         };
 
-        if (!GetCMDOption(args,option,_countof(option),NULL,0,NULL))
+        if (!GetCMDOption(args,option,ARRAY_SIZE(option),NULL,0,NULL))
             sos::Throw<sos::Exception>("Failed to parse command line arguments.");
 
         if (type != NULL)
@@ -12056,14 +11451,14 @@ private:
         HRESULT hr = S_OK;
         do
         {
-            if (FAILED(hr = handles->Next(_countof(data), data, &fetched)))
+            if (FAILED(hr = handles->Next(ARRAY_SIZE(data), data, &fetched)))
             {
                 ExtOut("Error %x while walking the handle table.\n", hr);
                 break;
             }
 
             WalkHandles(data, fetched);
-        } while (_countof(data) == fetched);
+        } while (ARRAY_SIZE(data) == fetched);
     }
 
     void WalkHandles(SOSHandleData data[], unsigned int count)
@@ -12342,7 +11737,7 @@ DECLARE_API(GetCodeTypeFlags)
         {&PReg.data, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(args, NULL, 0, arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, NULL, 0, arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -12358,7 +11753,7 @@ DECLARE_API(GetCodeTypeFlags)
         }
     }
 
-    sprintf_s(buffer,_countof (buffer),
+    sprintf_s(buffer, ARRAY_SIZE(buffer),
         "r$t%d=0",
         preg);
     Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer ,0);
@@ -12409,7 +11804,7 @@ DECLARE_API(GetCodeTypeFlags)
         codeType = 16;
     }
 
-    sprintf_s(buffer,_countof (buffer),
+    sprintf_s(buffer, ARRAY_SIZE(buffer),
         "r$t%d=%x",
         preg, codeType);
     Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer, 0);
@@ -12450,7 +11845,7 @@ DECLARE_API(StopOnException)
         {&PReg.data, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -12478,7 +11873,7 @@ DECLARE_API(StopOnException)
         }
     }
 
-    sprintf_s(buffer,_countof (buffer),
+    sprintf_s(buffer, ARRAY_SIZE(buffer),
         "r$t%d=0",
         preg);
     Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer, 0);
@@ -12490,7 +11885,7 @@ DECLARE_API(StopOnException)
 
     if (fCreate1 || fCreate2)
     {
-        sprintf_s(buffer,_countof (buffer),
+        sprintf_s(buffer, ARRAY_SIZE(buffer),
             "sxe %s \"!soe %s %s %d;.if(@$t%d==0) {g} .else {.echo '%s hit'}\" %x",
             fCreate1 ? "-c" : "-c2",
             fDerived ? "-derived" : "",
@@ -12544,7 +11939,7 @@ DECLARE_API(StopOnException)
             if ((_wcscmp(g_mdName,typeNameWide) == 0) ||
                 (fDerived && IsDerivedFrom(taMT, typeNameWide)))
             {
-                sprintf_s(buffer,_countof (buffer),
+                sprintf_s(buffer, ARRAY_SIZE(buffer),
                     "r$t%d=1",
                     preg);
                 Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer, 0);
@@ -12585,7 +11980,7 @@ DECLARE_API(ObjSize)
         {&str_Object.data, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -12642,7 +12037,7 @@ DECLARE_API(GCHandleLeaks)
         {"/d", &dml, COBOOL, FALSE},
     };
 
-    if (!GetCMDOption(args, option, _countof(option), NULL, 0, NULL))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL))
     {
         return Status;
     }
@@ -13549,7 +12944,6 @@ private:
             ExtOut("\nLOCALS:\n");
             for (ULONG i=0; i < cLocals; i++)
             {
-                ULONG paramNameLen = 0;
                 WCHAR paramName[mdNameLen] = W("\0");
 
                 ToRelease<ICorDebugValue> pValue;
@@ -13867,7 +13261,7 @@ public:
 
                 WCHAR wszModuleName[MAX_LONGPATH];
                 ULONG32 cchModuleNameActual;
-                IfFailRet(pModule->GetName(_countof(wszModuleName), &cchModuleNameActual, wszModuleName));
+                IfFailRet(pModule->GetName(ARRAY_SIZE(wszModuleName), &cchModuleNameActual, wszModuleName));
 
                 ToRelease<IUnknown> pMDUnknown;
                 ToRelease<IMetaDataImport> pMD;
@@ -13914,7 +13308,7 @@ WString BuildRegisterOutput(const SOSStackRefData &ref, bool printObj)
     if (ref.HasRegisterInformation)
     {
         WCHAR reg[32];
-        HRESULT hr = g_sos->GetRegisterName(ref.Register, _countof(reg), reg, NULL);
+        HRESULT hr = g_sos->GetRegisterName(ref.Register, ARRAY_SIZE(reg), reg, NULL);
         if (SUCCEEDED(hr))
             res = reg;
         else
@@ -13970,7 +13364,7 @@ void PrintRef(const SOSStackRefData &ref, TableOutput &out)
     if (ref.Object && (ref.Flags & SOSRefInterior) == 0)
     {
         WCHAR type[128];
-        sos::BuildTypeWithExtraInfo(TO_TADDR(ref.Object), _countof(type), type);
+        sos::BuildTypeWithExtraInfo(TO_TADDR(ref.Object), ARRAY_SIZE(type), type);
 
         res += WString(W(" - ")) + type;
     }
@@ -14263,7 +13657,7 @@ public:
         out.WriteColumn(0, frame->StackOffset);
         out.WriteColumn(1, NativePtr(ip));
 
-        HRESULT hr = g_ExtSymbols->GetNameByOffset(TO_CDADDR(ip), symbol, _countof(symbol), NULL, &displacement);
+        HRESULT hr = g_ExtSymbols->GetNameByOffset(TO_CDADDR(ip), symbol, ARRAY_SIZE(symbol), NULL, &displacement);
         if (SUCCEEDED(hr) && symbol[0] != '\0')
         {
             String frameOutput;
@@ -14278,7 +13672,7 @@ public:
             if (!bSuppressLines)
             {
                 ULONG line;
-                hr = g_ExtSymbols->GetLineByOffset(TO_CDADDR(ip), &line, filename, _countof(filename), NULL, NULL);
+                hr = g_ExtSymbols->GetLineByOffset(TO_CDADDR(ip), &line, filename, ARRAY_SIZE(filename), NULL, NULL);
                 if (SUCCEEDED(hr))
                 {
                     frameOutput += " at ";
@@ -14616,7 +14010,6 @@ WatchCmd g_watchCmd;
 DECLARE_API(Watch)
 {
     INIT_API_NOEE();
-    BOOL bExpression = FALSE;
     StringHolder addExpression;
     StringHolder aExpression;
     StringHolder saveName;
@@ -14648,7 +14041,7 @@ DECLARE_API(Watch)
     {   // vptr, type
         {&expression.data, COSTRING}
     };
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -14781,7 +14174,7 @@ DECLARE_API(ClrStack)
         {&cvariableName.data, COSTRING},
         {&frameToDumpVariablesFor, COSIZE_T},
     };
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -14922,7 +14315,7 @@ DECLARE_API(SaveModule)
         {&Location.data, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(args, NULL, 0, arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, NULL, 0, arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
@@ -15112,7 +14505,7 @@ DECLARE_API(dbgout)
         {"-off", &bOff, COBOOL, FALSE},
     };
 
-    if (!GetCMDOption(args, option, _countof(option), NULL, 0, NULL))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL))
     {
         return Status;
     }
@@ -15648,7 +15041,7 @@ BOOL FormatFromRemoteString(DWORD_PTR strObjPointer, __out_ecount(cchString) PWS
     UINT Length = 0;
     while(1)
     {
-        if (_wcsncmp(pwszPointer, PSZSEP, _countof(PSZSEP)-1) != 0)
+        if (_wcsncmp(pwszPointer, PSZSEP, ARRAY_SIZE(PSZSEP)-1) != 0)
         {
             delete [] pwszBuf;
             return bRet;
@@ -15671,7 +15064,7 @@ BOOL FormatFromRemoteString(DWORD_PTR strObjPointer, __out_ecount(cchString) PWS
         WCHAR wszLineBuffer[mdNameLen + 8 + sizeof(size_t)*2];
 
         // Note that we don't add a newline because we have this embedded in wszLineBuffer
-        swprintf_s(wszLineBuffer, _countof(wszLineBuffer), W("    %p %p %s"), SOS_PTR(-1), SOS_PTR(-1), pwszPointer);
+        swprintf_s(wszLineBuffer, ARRAY_SIZE(wszLineBuffer), W("    %p %p %s"), SOS_PTR(-1), SOS_PTR(-1), pwszPointer);
         Length += (UINT)_wcslen(wszLineBuffer);
 
         if (wszBuffer)
@@ -15885,7 +15278,7 @@ DECLARE_API(VerifyStackTrace)
         {"-ManagedExcepStack", &bVerifyManagedExcepStack, COBOOL, FALSE},
     };
 
-    if (!GetCMDOption(args, option, _countof(option), NULL,0,NULL))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL,0,NULL))
     {
         return Status;
     }
@@ -16091,7 +15484,7 @@ DECLARE_API(SaveState)
         {&filePath.data, COSTRING},
     };
     size_t nArg;
-    if (!GetCMDOption(args, NULL, 0, arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, NULL, 0, arg, ARRAY_SIZE(arg), &nArg))
     {
         return E_FAIL;
     }
@@ -16131,7 +15524,7 @@ DECLARE_API(SuppressJitOptimization)
         {&onOff.data, COSTRING},
     };
     size_t nArg;
-    if (!GetCMDOption(args, NULL, 0, arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, NULL, 0, arg, ARRAY_SIZE(arg), &nArg))
     {
         return E_FAIL;
     }
@@ -16468,7 +15861,7 @@ DECLARE_API(VerifyGMT)
         };
         size_t nArg;
 
-        if (!GetCMDOption(args, NULL, 0, arg, _countof(arg), &nArg))
+        if (!GetCMDOption(args, NULL, 0, arg, ARRAY_SIZE(arg), &nArg))
         {
             return Status;
         }
@@ -16551,7 +15944,7 @@ DECLARE_API(SetHostRuntime)
         {&hostRuntimeDirectory.data, COSTRING},
     };
     size_t narg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &narg))
+    if (!GetCMDOption(args, option, ARRAY_SIZE(option), arg, ARRAY_SIZE(arg), &narg))
     {
         return E_FAIL;
     }
@@ -16614,123 +16007,6 @@ exit:
 
 #endif // FEATURE_PAL
 
-//
-// Sets the symbol server path.
-//
-DECLARE_API(SetSymbolServer)
-{
-    INIT_API_EXT();
-
-    StringHolder symbolCache;
-    StringHolder searchDirectory;
-    StringHolder windowsSymbolPath;
-    StringHolder authToken;
-    size_t timeoutInMinutes = 0;
-    std::string resolvedSearchDirectory;
-    BOOL disable = FALSE;
-    BOOL loadNative = FALSE;
-    BOOL msdl = FALSE;
-    BOOL symweb = FALSE;
-    CMDOption option[] =
-    {   // name, vptr, type, hasValue
-        {"-disable", &disable, COBOOL, FALSE},
-        {"-cache", &symbolCache.data, COSTRING, TRUE},
-        {"-directory", &searchDirectory.data, COSTRING, TRUE},
-        {"-pat", &authToken.data, COSTRING, TRUE},
-        {"-timeout", &timeoutInMinutes, COSIZE_T, TRUE},
-        {"-ms", &msdl, COBOOL, FALSE},
-#ifdef FEATURE_PAL
-        {"-loadsymbols", &loadNative, COBOOL, FALSE},
-        {"-sympath", &windowsSymbolPath.data, COSTRING, TRUE},
-#else
-        {"-mi", &symweb, COBOOL, FALSE},
-#endif
-    };
-    StringHolder symbolServer;
-    CMDValue arg[] =
-    {
-        {&symbolServer.data, COSTRING},
-    };
-    size_t narg;
-    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &narg))
-    {
-        return E_FAIL;
-    }
-
-    if (msdl && symweb)
-    {
-        ExtErr("Cannot have both -ms and -mi options\n");
-        return E_FAIL;
-    }
-
-    if ((msdl || symweb) && symbolServer.data != nullptr)
-    {
-        ExtErr("Cannot have -ms or -mi option and a symbol server path\n");
-        return E_FAIL;
-    }
-
-    if (disable) {
-        DisableSymbolStore();
-    }
-
-    if (searchDirectory.data != nullptr) {
-        if (!GetAbsolutePath(searchDirectory.data, resolvedSearchDirectory))
-        {
-            ExtErr("Invalid runtime directory %s\n", resolvedSearchDirectory.c_str());
-            return E_FAIL;
-        }
-    }
-
-    if (msdl || symweb || symbolServer.data != nullptr || symbolCache.data != nullptr || !resolvedSearchDirectory.empty() || windowsSymbolPath.data != nullptr)
-    {
-        Status = InitializeSymbolStore(msdl, symweb, symbolServer.data, authToken.data, (int)timeoutInMinutes, symbolCache.data, (resolvedSearchDirectory.empty() ? nullptr : resolvedSearchDirectory.c_str()), windowsSymbolPath.data);
-        if (FAILED(Status))
-        {
-            return Status;
-        }
-        if (msdl)
-        {
-            ExtOut("Added Microsoft public symbol server\n");
-        }
-        if (symweb)
-        {
-            ExtOut("Added internal symweb symbol server\n");
-        }
-        if (symbolServer.data != nullptr)
-        {
-            ExtOut("Added symbol server: %s\n", symbolServer.data);
-        }
-        if (symbolCache.data != nullptr)
-        {
-            ExtOut("Added symbol cache path: %s\n", symbolCache.data);
-        }
-        if (!resolvedSearchDirectory.empty())
-        {
-            ExtOut("Added symbol directory path: %s\n", resolvedSearchDirectory.c_str());
-        }
-        if (windowsSymbolPath.data != nullptr)
-        {
-            ExtOut("Added Windows symbol path: %s\n", windowsSymbolPath.data);
-        }
-    }
-#ifdef FEATURE_PAL
-    else if (loadNative)
-    {
-        Status = LoadNativeSymbols();
-        if (FAILED(Status))
-        {
-            ExtErr("Symbol server not set\n");
-        }
-    }
-#endif
-    else
-    {
-        DisplaySymbolStore();
-    }
-
-    return Status;
-}
-
 //
 // Sets the runtime module path
 //
@@ -16755,7 +16031,7 @@ DECLARE_API(SetClrPath)
             {&runtimeModulePath.data, COSTRING},
         };
         size_t narg;
-        if (!GetCMDOption(args, nullptr, 0, arg, _countof(arg), &narg))
+        if (!GetCMDOption(args, nullptr, 0, arg, ARRAY_SIZE(arg), &narg))
         {
             return E_FAIL;
         }
@@ -16800,7 +16076,7 @@ DECLARE_API(runtimes)
             {"-netfx", &bNetFx, COBOOL, FALSE},
             {"-netcore", &bNetCore, COBOOL, FALSE},
         };
-        if (!GetCMDOption(args, option, _countof(option), NULL, 0, NULL))
+        if (!GetCMDOption(args, option, ARRAY_SIZE(option), NULL, 0, NULL))
         {
             return Status;
         }
@@ -16859,6 +16135,15 @@ HRESULT ExecuteCommand(PCSTR command, PCSTR args)
     return S_OK;
 }
 
+//
+// Sets the symbol server path.
+//
+DECLARE_API(SetSymbolServer)
+{
+    INIT_API_EXT();
+    return ExecuteCommand("setsymbolserver", args);
+}
+
 //
 // Dumps the managed assemblies
 //
@@ -16868,6 +16153,15 @@ DECLARE_API(clrmodules)
     return ExecuteCommand("clrmodules", args);
 }
 
+//
+// Dumps async stacks
+//
+DECLARE_API(DumpAsync)
+{
+    INIT_API_EXT();
+    return ExecuteCommand("dumpasync", args);
+}
+
 //
 // Enables and disables managed extension logging
 //
@@ -16910,8 +16204,8 @@ void PrintHelp (__in_z LPCSTR pszCmdName)
         }
 
         char lpFilename[MAX_LONGPATH + 12]; // + 12 to make enough room for strcat function.
-        strcpy_s(lpFilename, _countof(lpFilename), szSOSModulePath);
-        strcat_s(lpFilename, _countof(lpFilename), "sosdocsunix.txt");
+        strcpy_s(lpFilename, ARRAY_SIZE(lpFilename), szSOSModulePath);
+        strcat_s(lpFilename, ARRAY_SIZE(lpFilename), "sosdocsunix.txt");
 
         HANDLE hSosDocFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
         if (hSosDocFile == INVALID_HANDLE_VALUE) {
@@ -16938,7 +16232,7 @@ void PrintHelp (__in_z LPCSTR pszCmdName)
 
     // Find our line in the text file
     char searchString[MAX_LONGPATH];
-    sprintf_s(searchString, _countof(searchString), "COMMAND: %s.", pszCmdName);
+    sprintf_s(searchString, ARRAY_SIZE(searchString), "COMMAND: %s.", pszCmdName);
 
     LPSTR pStart = strstr(pText, searchString);
     LPSTR pEnd = NULL;
@@ -16998,7 +16292,7 @@ DECLARE_API(Help)
         {&commandName.data, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(args, NULL, 0, arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, NULL, 0, arg, ARRAY_SIZE(arg), &nArg))
     {
         return Status;
     }
index 35ed21e80d86bdb1ef94732caa46fc6db5a5d7a8..2cf0a237b7277a51011a5f88c56b4f43f4b61df1 100644 (file)
@@ -10,9 +10,7 @@
 #ifndef __strike_h__
 #define __strike_h__
 
-#ifndef _countof
-#define _countof(x) (sizeof(x)/sizeof(x[0]))
-#endif
+#include <minipal/utils.h>
 
 #if defined(_MSC_VER)
 #pragma warning(disable:4245)   // signed/unsigned mismatch
index da46121b853a5f70a9d8dff359511f22e91a50f0..e155bbb4b12aa3b78974d3b5a996ce06175d4979 100644 (file)
@@ -84,122 +84,6 @@ extern "C" void STDMETHODCALLTYPE SOSUninitializeByHost()
     OnUnloadTask::Run();
 }
 
-/**********************************************************************\
- * Setup and initialize the symbol server support.
-\**********************************************************************/
-HRESULT InitializeSymbolStore(
-    BOOL msdl,
-    BOOL symweb,
-    const char* symbolServer,
-    const char* authToken,
-    int timeoutInMinutes,
-    const char* cacheDirectory,
-    const char* searchDirectory,
-    const char* windowsSymbolPath)
-{
-    HRESULT Status = S_OK;
-    ISymbolService* symbolService = GetSymbolService();
-    if (symbolService == nullptr)
-    {
-        return E_NOINTERFACE;
-    }
-    if (!symbolService->InitializeSymbolStore(
-        msdl,
-        symweb,
-        symbolServer,
-        authToken,
-        timeoutInMinutes,
-        cacheDirectory,
-        searchDirectory))
-    {
-        ExtErr("Error initializing symbol server support\n");
-        return E_FAIL;
-    }
-    if (windowsSymbolPath != nullptr)
-    {
-        if (!symbolService->ParseSymbolPath(windowsSymbolPath))
-        {
-            ExtErr("Error parsing symbol path %s\n", windowsSymbolPath);
-            return E_FAIL;
-        }
-    }
-    return S_OK;
-}
-
-#ifdef FEATURE_PAL
-
-//
-// Symbol downloader callback
-//
-static void SymbolFileCallback(void* param, const char* moduleFileName, const char* symbolFilePath)
-{
-    if (strcmp(moduleFileName, GetRuntimeDllName(IRuntime::Core)) == 0) {
-        return;
-    }
-    if (strcmp(moduleFileName, NETCORE_DAC_DLL_NAME_A) == 0) {
-        return;
-    }
-    if (strcmp(moduleFileName, NET_DBI_DLL_NAME_A) == 0) {
-        return;
-    }
-    g_ExtServices2->AddModuleSymbol(param, symbolFilePath);
-}
-
-//
-// Enumerate native module callback
-//
-static void LoadNativeSymbolsCallback(void* param, const char* moduleFilePath, ULONG64 moduleAddress, int moduleSize)
-{
-    GetSymbolService()->LoadNativeSymbols(SymbolFileCallback, param, IRuntime::Core, moduleFilePath, moduleAddress, moduleSize);
-}
-
-/**********************************************************************\
- * Enumerate the native modules and attempt to download the symbols
- * for them. Depends on the lldb callback to enumerate modules. Not
- * necessary on dbgeng because it already downloads native symbols.
-\**********************************************************************/
-HRESULT LoadNativeSymbols(bool runtimeOnly)
-{
-    ISymbolService* symbolService = GetSymbolService();
-    if (symbolService != nullptr)
-    {
-        if (symbolService->IsSymbolStoreEnabled())
-        {
-            return g_ExtServices2->LoadNativeSymbols(runtimeOnly, LoadNativeSymbolsCallback);
-        }
-    }
-    return E_FAIL;
-}
-
-#endif
-
-/**********************************************************************\
- * Displays the symbol server and cache status.
-\**********************************************************************/
-void DisplaySymbolStore()
-{
-    ISymbolService* symbolService = GetSymbolService();
-    if (symbolService != nullptr)
-    {
-        symbolService->DisplaySymbolStore([] (const char* message) {
-            ExtOut(message);
-            ExtOut("\n");
-        });
-    }
-}
-
-/**********************************************************************\
- * Turns off the symbol server support.
-\**********************************************************************/
-void DisableSymbolStore()
-{
-    ISymbolService* symbolService = GetSymbolService();
-    if (symbolService != nullptr)
-    {
-        symbolService->DisableSymbolStore();
-    }
-}
-
 /**********************************************************************\
  * Returns the metadata from a local or downloaded assembly
 \**********************************************************************/
index 2d402d622d99694ea2dc47cfb4ccb4c425ea4b10..d388a6f0f4f53f9fd9243250ae1e4b9550db72b3 100644 (file)
@@ -8,23 +8,6 @@
 
 extern HMODULE g_hInstance;
 
-#ifdef FEATURE_PAL
-extern HRESULT LoadNativeSymbols(bool runtimeOnly = false);
-#endif
-
-extern HRESULT InitializeSymbolStore(
-    BOOL msdl,
-    BOOL symweb,
-    const char* symbolServer,
-    const char* authToken,
-    int timeoutInMinutes,
-    const char* cacheDirectory,
-    const char* searchDirectory,
-    const char* windowsSymbolPath);
-
-extern void DisplaySymbolStore();
-extern void DisableSymbolStore();
-
 extern HRESULT GetMetadataLocator(
     LPCWSTR imagePath,
     ULONG32 imageTimestamp,
index 0a70e39971837e6a462918dd72e8580b1611428f..fe69ec024fa2c5ce786479b8295d3a0b67af28c7 100644 (file)
@@ -111,7 +111,7 @@ DWORD_PTR GetValueFromExpression(___in __in_z const char *const instr)
     else if (hr == S_FALSE && dwAddr)
         return (DWORD_PTR)dwAddr;
 
-    strcpy_s (name, _countof(name), str);
+    strcpy_s (name, ARRAY_SIZE(name), str);
     char *ptr;
     if ((ptr = strstr (name, "__")) != NULL)
     {
@@ -866,7 +866,7 @@ const char * ElementTypeName(unsigned type)
         return "MVAR";
         break;
     default:
-        if ((type >= _countof(CorElementTypeName)) || (CorElementTypeName[type] == NULL))
+        if ((type >= ARRAY_SIZE(CorElementTypeName)) || (CorElementTypeName[type] == NULL))
         {
             return "";
         }
@@ -877,7 +877,7 @@ const char * ElementTypeName(unsigned type)
 
 const char * ElementTypeNamespace(unsigned type)
 {
-    if ((type >= _countof(CorElementTypeName)) || (CorElementTypeNamespace[type] == NULL))
+    if ((type >= ARRAY_SIZE(CorElementTypeName)) || (CorElementTypeNamespace[type] == NULL))
     {
         return "";
     }
@@ -1017,7 +1017,7 @@ void DisplayFields(CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodT
                 // If ET type from signature is different from fielddesc, then the signature one is more descriptive.
                 // For example, E_T_STRING in field desc will be E_T_CLASS. In minidump's case, we won't have
                 // the method table for it.
-                ComposeName_s(vFieldDesc.Type != vFieldDesc.sigType ? vFieldDesc.sigType : vFieldDesc.Type, ElementName, sizeof(ElementName)/sizeof(ElementName[0]));
+                ComposeName_s(vFieldDesc.Type != vFieldDesc.sigType ? vFieldDesc.sigType : vFieldDesc.Type, ElementName, ARRAY_SIZE(ElementName));
                 ExtOut("%20.20s ", ElementName);
             }
         }
@@ -3179,7 +3179,7 @@ void DumpMDInfoFromMethodDescData(DacpMethodDescData * pMethodDescData, DacpReJi
     BOOL bFailed = FALSE;
     if (g_sos->GetMethodDescName(pMethodDescData->MethodDescPtr, 1024, wszNameBuffer, NULL) != S_OK)
     {
-        wcscpy_s(wszNameBuffer, _countof(wszNameBuffer), W("UNKNOWN"));
+        wcscpy_s(wszNameBuffer, ARRAY_SIZE(wszNameBuffer), W("UNKNOWN"));
         bFailed = TRUE;
     }
 
@@ -3272,7 +3272,7 @@ void DumpMDInfo(DWORD_PTR dwMethodDescAddr, CLRDATA_ADDRESS dwRequestedIP /* = 0
         TO_CDADDR(dwMethodDescAddr),
         dwRequestedIP,
         &MethodDescData,
-        _countof(revertedRejitData),
+        ARRAY_SIZE(revertedRejitData),
         revertedRejitData,
         &cNeededRevertedRejitData) != S_OK)
     {
@@ -3593,7 +3593,7 @@ BOOL GetSOSVersion(VS_FIXEDFILEINFO *pFileInfo)
     _ASSERTE(pFileInfo);
 
     WCHAR wszFullPath[MAX_LONGPATH];
-    DWORD cchFullPath = GetModuleFileNameW(g_hInstance, wszFullPath, _countof(wszFullPath));
+    DWORD cchFullPath = GetModuleFileNameW(g_hInstance, wszFullPath, ARRAY_SIZE(wszFullPath));
 
     DWORD dwHandle = 0;
     DWORD infoSize = GetFileVersionInfoSizeW(wszFullPath, &dwHandle);
@@ -3744,7 +3744,7 @@ void StringObjectContent(size_t obj, BOOL fLiteral, const int length)
                 toRead = count;
 
             ULONG bytesRead;
-            wcsncpy_s(buffer,_countof(buffer),(LPWSTR) dwAddr, toRead);
+            wcsncpy_s(buffer,ARRAY_SIZE(buffer),(LPWSTR) dwAddr, toRead);
             bytesRead = toRead*sizeof(WCHAR);
             DWORD wcharsRead = bytesRead/2;
             buffer[wcharsRead] = L'\0';
@@ -4042,7 +4042,7 @@ BOOL GetCMDOption(const char *string, CMDOption *option, size_t nOption,
                 ExtOut ("Invalid option %s\n", ptr);
                 return FALSE;
             }
-            strncpy_s (buffer,_countof(buffer), ptr, end-ptr);
+            strncpy_s (buffer,ARRAY_SIZE(buffer), ptr, end-ptr);
 
             size_t n;
             for (n = 0; n < nOption; n ++)
@@ -4822,7 +4822,6 @@ const char * const DMLFormats[] =
     "<exec cmd=\"!DumpRCW /d %s\">%s</exec>",       // DML_RCWrapper
     "<exec cmd=\"!DumpCCW /d %s\">%s</exec>",       // DML_CCWrapper
     "<exec cmd=\"!ClrStack -i %S %d\">%S</exec>",   // DML_ManagedVar
-    "<exec cmd=\"!DumpAsync -addr %s -tasks -completed -fields -stacks -roots\">%s</exec>", // DML_Async
     "<exec cmd=\"!DumpIL /i %s\">%s</exec>",         // DML_IL
     "<exec cmd=\"!DumpRCW -cw /d %s\">%s</exec>",    // DML_ComWrapperRCW
     "<exec cmd=\"!DumpCCW -cw /d %s\">%s</exec>",    // DML_ComWrapperCCW
@@ -4861,10 +4860,10 @@ CachedString Output::BuildHexValue(CLRDATA_ADDRESS disp, CLRDATA_ADDRESS addr, F
         char hex2[POINTERSIZE_BYTES*2 + 1];
         char* d = hex1;
         char* a = hex1;
-        GetHex(addr, hex1, _countof(hex1), fill);
+        GetHex(addr, hex1, ARRAY_SIZE(hex1), fill);
         if (disp != addr)
         {
-            GetHex(disp, hex2, _countof(hex2), fill);
+            GetHex(disp, hex2, ARRAY_SIZE(hex2), fill);
             d = hex2;
         }
 
@@ -4890,7 +4889,7 @@ CachedString Output::BuildHexValueWithLength(CLRDATA_ADDRESS addr, size_t len, F
     if (IsDMLEnabled())
     {
         char hex[POINTERSIZE_BYTES*2 + 1];
-        GetHex(addr, hex, _countof(hex), fill);
+        GetHex(addr, hex, ARRAY_SIZE(hex), fill);
         sprintf_s(ret, ret.GetStrLen(), DMLFormats[type], hex, len, hex);
     }
     else
@@ -4919,13 +4918,13 @@ CachedString Output::BuildVCValue(CLRDATA_ADDRESS disp, CLRDATA_ADDRESS mt, CLRD
         char* d = hexaddr1;
         char* a = hexaddr1;
 
-        GetHex(addr, hexaddr1, _countof(hexaddr1), fill);
+        GetHex(addr, hexaddr1, ARRAY_SIZE(hexaddr1), fill);
         if (disp != addr)
         {
-            GetHex(disp, hexaddr2, _countof(hexaddr2), fill);
+            GetHex(disp, hexaddr2, ARRAY_SIZE(hexaddr2), fill);
             d = hexaddr2;
         }
-        GetHex(mt, hexmt, _countof(hexmt), fill);
+        GetHex(mt, hexmt, ARRAY_SIZE(hexmt), fill);
 
         sprintf_s(ret, ret.GetStrLen(), DMLFormats[type], hexmt, a, d);
     }
@@ -4989,7 +4988,7 @@ CachedString Output::BuildManagedVarValue(__in_z LPCWSTR expansionName, ULONG fr
 CachedString Output::BuildManagedVarValue(__in_z LPCWSTR expansionName, ULONG frame, int indexInArray, FormatType type)
 {
     WCHAR indexString[24];
-    swprintf_s(indexString, _countof(indexString), W("[%d]"), indexInArray);
+    swprintf_s(indexString, ARRAY_SIZE(indexString), W("[%d]"), indexInArray);
     return BuildManagedVarValue(expansionName, frame, indexString, type);
 }
 
@@ -5080,7 +5079,7 @@ GetLastMethodIlOffset(
     HRESULT Status;
     CLRDATA_IL_ADDRESS_MAP MapLocal[16];
     CLRDATA_IL_ADDRESS_MAP* Map = MapLocal;
-    ULONG32 MapCount = _countof(MapLocal);
+    ULONG32 MapCount = ARRAY_SIZE(MapLocal);
     ULONG32 MapNeeded;
     ULONG32 HighestOffset;
 
@@ -5343,7 +5342,7 @@ const char *TableOutput::GetWhitespace(int amount)
 
     if (count == 0)
     {
-        count = _countof(WhiteSpace);
+        count = ARRAY_SIZE(WhiteSpace);
         for (int i = 0; i < count-1; ++i)
             WhiteSpace[i] = ' ';
         WhiteSpace[count-1] = 0;
@@ -5613,7 +5612,7 @@ WString MethodNameFromIP(CLRDATA_ADDRESS ip, BOOL bSuppressLines, BOOL bAssembly
 
                 if (SUCCEEDED(g_ExtSymbols->GetModuleNames(Index, moduleBase, NULL, 0, NULL, szModuleName, MAX_LONGPATH, NULL, NULL, 0, NULL)))
                 {
-                    MultiByteToWideChar (CP_ACP, 0, szModuleName, MAX_LONGPATH, g_mdName, _countof(g_mdName));
+                    MultiByteToWideChar (CP_ACP, 0, szModuleName, MAX_LONGPATH, g_mdName, ARRAY_SIZE(g_mdName));
                     methodOutput += g_mdName;
                     methodOutput += W("!");
                 }
@@ -5701,7 +5700,7 @@ HRESULT InternalFrameManager::Init(ICorDebugThread3 * pThread3)
     _ASSERTE(pThread3 != NULL);
 
     return pThread3->GetActiveInternalFrames(
-        _countof(m_rgpInternalFrame2),
+        ARRAY_SIZE(m_rgpInternalFrame2),
         &m_cInternalFramesActual,
         &(m_rgpInternalFrame2[0]));
 }
index 2307c540c518bf72fc9c993612eb45dcc7a301ad..d301972795ea4a85a4f1fa85f5b161296df34094 100644 (file)
@@ -41,10 +41,6 @@ inline void RestoreSOToleranceState() {}
 #include "runtimeimpl.h"
 #include "symbols.h"
 
-#ifndef COUNTOF
-#define COUNTOF(a) (sizeof(a) / sizeof(*a))
-#endif
-
 typedef LPCSTR  LPCUTF8;
 typedef LPSTR   LPUTF8;
 
@@ -1025,8 +1021,8 @@ namespace Output
                 char buffer[64];
                 if (mFormat == Formats::Default || mFormat == Formats::Pointer)
                 {
-                    sprintf_s(buffer, _countof(buffer), "%p", (int *)(SIZE_T)mValue);
-                    ConvertToLower(buffer, _countof(buffer));
+                    sprintf_s(buffer, ARRAY_SIZE(buffer), "%p", (int *)(SIZE_T)mValue);
+                    ConvertToLower(buffer, ARRAY_SIZE(buffer));
                 }
                 else
                 {
@@ -1038,8 +1034,8 @@ namespace Output
                     else if (mFormat == Formats::Decimal)
                         format = "%d";
 
-                    sprintf_s(buffer, _countof(buffer), format, (__int32)mValue);
-                    ConvertToLower(buffer, _countof(buffer));
+                    sprintf_s(buffer, ARRAY_SIZE(buffer), format, (__int32)mValue);
+                    ConvertToLower(buffer, ARRAY_SIZE(buffer));
                 }
 
                 return buffer;
@@ -1095,7 +1091,7 @@ namespace Output
         static void BuildDMLCol(__out_ecount(len) char *result, int len, CLRDATA_ADDRESS value, Formats::Format format, Output::FormatType dmlType, bool leftAlign, int width)
         {
             char hex[64];
-            int count = GetHex(value, hex, _countof(hex), format != Formats::Hex);
+            int count = GetHex(value, hex, ARRAY_SIZE(hex), format != Formats::Hex);
             int i = 0;
 
             if (!leftAlign)
@@ -1534,7 +1530,7 @@ public:
 
         va_list list;
         va_start(list, fmt);
-        vsprintf_s(result, _countof(result), fmt, list);
+        vsprintf_s(result, ARRAY_SIZE(result), fmt, list);
         va_end(list);
 
         WriteColumn(col, result);
@@ -1546,7 +1542,7 @@ public:
 
         va_list list;
         va_start(list, fmt);
-        vswprintf_s(result, _countof(result), fmt, list);
+        vswprintf_s(result, ARRAY_SIZE(result), fmt, list);
         va_end(list);
 
         WriteColumn(col, result);
@@ -2890,7 +2886,7 @@ public:
     {
 #ifdef _DEBUG
         char buffer[1024];
-        sprintf_s(buffer, _countof(buffer), "Cache (%s): %d reads (%2.1f%% hits), %d misses (%2.1f%%), %d misaligned (%2.1f%%).\n",
+        sprintf_s(buffer, ARRAY_SIZE(buffer), "Cache (%s): %d reads (%2.1f%% hits), %d misses (%2.1f%%), %d misaligned (%2.1f%%).\n",
                                              func, mReads, 100*(mReads-mMisses)/(float)(mReads+mMisaligned), mMisses,
                                              100*mMisses/(float)(mReads+mMisaligned), mMisaligned, 100*mMisaligned/(float)(mReads+mMisaligned));
         OutputDebugStringA(buffer);
index 70e9210dbd94f9b92391016849fc0e4deaa0bd9b..aabc3c76895959fb72900f8abf7fdc9701ff648d 100644 (file)
@@ -52,7 +52,7 @@ Revision History:
 #define PRINTF_FORMAT_HEAD  "%-7s  %*s  %*s  %*s %*s  %*s\n"
 #define PRINTF_FORMAT       "%-7s %*sK %*sK %*sK %*s %*sK\n"
 
-#define CCH_ULONGLONG_COMMAS   _countof("18,446,744,073,709,551,616")
+#define CCH_ULONGLONG_COMMAS   ARRAY_SIZE("18,446,744,073,709,551,616")
 #define CCH_ULONGLONG_MINIMUM_COMMAS (CCH_ULONGLONG_COMMAS - 3)
 #define CCH_ULONGLONG_BLOCKCOUNT_COMMAS    sizeof("1,000,000")
 
@@ -144,20 +144,16 @@ PROTECT_MASK ProtectMasks[] =
         }
     };
 
-#define NUM_PROTECT_MASKS (sizeof(ProtectMasks) / sizeof(ProtectMasks[0]))
-
 //
 // Private functions.
 //
 
-
 PSTR
 ULongLongToString(
     IN ULONGLONG Value,
     __out_ecount (CCH_ULONGLONG_COMMAS) OUT PSTR Buffer
     )
 {
-
     PSTR p1;
     PSTR p2;
     CHAR ch;
@@ -407,7 +403,7 @@ VmProtectToString(
     Buffer[0] = '\0';
 
     for( i = 0, mask = &ProtectMasks[0] ;
-        (i < NUM_PROTECT_MASKS) && (Protect != 0) ;
+        (i < ARRAY_SIZE(ProtectMasks)) && (Protect != 0) ;
         i++, mask++ ) {
         if( mask->Bit & Protect ) {
             Protect &= ~mask->Bit;
@@ -461,7 +457,7 @@ VmStateToString(
         break;
 
     default:
-        sprintf_s(invalidStr,_countof(invalidStr), "%08lx", State );
+        sprintf_s(invalidStr,ARRAY_SIZE(invalidStr), "%08lx", State );
         result = invalidStr;
         break;
     }
@@ -500,7 +496,7 @@ VmTypeToString(
         break;
 
     default:
-        sprintf_s(invalidStr,_countof(invalidStr), "%08lx", Type );
+        sprintf_s(invalidStr,ARRAY_SIZE(invalidStr), "%08lx", Type );
         result = invalidStr;
         break;
     }
@@ -698,10 +694,10 @@ Return Value:
             SOS_PTR(memInfo.BaseAddress),
             SOS_PTR(((ULONG_PTR)memInfo.BaseAddress + memInfo.RegionSize - 1)),
             SOS_PTR(memInfo.RegionSize),
-            VmProtectToString( memInfo.AllocationProtect, aprotectStr, _countof(aprotectStr) ),
-            VmProtectToString( memInfo.Protect, protectStr, _countof(protectStr)  ),
-            VmStateToString( memInfo.State, stateStr, _countof(stateStr) ),
-            VmTypeToString( memInfo.Type, typeStr , _countof(typeStr))
+            VmProtectToString( memInfo.AllocationProtect, aprotectStr, ARRAY_SIZE(aprotectStr) ),
+            VmProtectToString( memInfo.Protect, protectStr, ARRAY_SIZE(protectStr)  ),
+            VmStateToString( memInfo.State, stateStr, ARRAY_SIZE(stateStr) ),
+            VmTypeToString( memInfo.Type, typeStr , ARRAY_SIZE(typeStr))
             );
 
         //
index 0a065fc23c2a2d98a4f58ffbeecf1d51285cd7b0..75784755806e1c29eb86d2bdca060f656deb6378 100644 (file)
@@ -5,5 +5,6 @@
 #define __CONFIG_H__
 
 #cmakedefine01 HAVE_DIRENT_D_TYPE
+#cmakedefine01 HAVE_GETAUXVAL
 
 #endif // __CONFIG_H__
index dd02088147f311e53a8d95fffe3591a69e6d4d41..1dd0b96127782d9011a3cfe93a607be82fc8403a 100644 (file)
@@ -1,5 +1,7 @@
 include(CheckStructHasMember)
+include(CheckIncludeFiles)
 
 check_struct_has_member ("struct dirent" d_type dirent.h HAVE_DIRENT_D_TYPE)
+check_include_files("sys/auxv.h;asm/hwcap.h" HAVE_AUXV_HWCAP_H)
 
 configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
index 11a28385d4673f0f96d8aed90d21c95bb97211a5..bd42a0b4927dc3f80dc69c931bd8bb11734d48ae 100644 (file)
 #include <string>
 #include <vector>
 
-#if defined(__APPLE__)
-#include <mach-o/dyld.h>
-#endif
-
-#if defined(__FreeBSD__)
-#include <sys/types.h>
-#include <sys/sysctl.h>
-#endif
-
 #include "palclr.h"
 #include "arrayholder.h"
 #include "coreclrhost.h"
 #include "extensions.h"
 
-#ifndef _countof
-#define _countof(x) (sizeof(x)/sizeof(x[0]))
-#endif
+#include <minipal/getexepath.h>
+#include <minipal/utils.h>
 
 #ifndef IfFailRet
 #define IfFailRet(EXPR) do { Status = (EXPR); if(FAILED(Status)) { return (Status); } } while (0)
@@ -138,11 +128,6 @@ namespace RuntimeHostingConstants
         "/usr/share/dotnet",
 #endif
     };
-#if defined(TARGET_LINUX)
-    constexpr char SymlinkEntrypointExecutable[] = "/proc/self/exe";
-#elif !defined(TARGET_OSX)
-    constexpr char SymlinkEntrypointExecutable[] = "/proc/curproc/exe";
-#endif
 #endif
 };
 
@@ -360,14 +345,14 @@ static bool FindDotNetVersion(const RuntimeVersion& runtimeVersion, std::string&
     FileFind find;
     if (find.Open(hostRuntimeDirectory.c_str()))
     {
-        int highestRevision = 0;
+        uint32_t highestRevision = 0;
         do
         {
             if (find.IsDirectory())
             {
-                int major = 0;
-                int minor = 0;
-                int revision = 0;
+                uint32_t major = 0;
+                uint32_t minor = 0;
+                uint32_t revision = 0;
                 if (sscanf(find.FileName(), "%d.%d.%d", &major, &minor, &revision) == 3)
                 {
                     if (major == runtimeVersion.Major && minor == runtimeVersion.Minor)
@@ -393,88 +378,7 @@ static bool FindDotNetVersion(const RuntimeVersion& runtimeVersion, std::string&
     return false;
 }
 
-#ifdef HOST_WINDOWS
-
-static bool GetEntrypointExecutableAbsolutePath(std::string& entrypointExecutable)
-{
-    ArrayHolder<char> hostPath = new char[MAX_LONGPATH+1];
-    if (::GetModuleFileNameA(NULL, hostPath, MAX_LONGPATH) == 0)
-    {
-        return false;
-    }
-    entrypointExecutable.clear();
-    entrypointExecutable.append(hostPath);
-    return true;
-}
-
-#else // HOST_WINDOWS
-
-static bool GetEntrypointExecutableAbsolutePath(std::string& entrypointExecutable)
-{
-    bool result = false;
-
-    entrypointExecutable.clear();
-
-    // Get path to the executable for the current process using
-    // platform specific means.
-#if defined(TARGET_OSX)
-    // On Mac, we ask the OS for the absolute path to the entrypoint executable
-    uint32_t lenActualPath = 0;
-    if (_NSGetExecutablePath(nullptr, &lenActualPath) == -1)
-    {
-        // OSX has placed the actual path length in lenActualPath,
-        // so re-attempt the operation
-        std::string resizedPath(lenActualPath, '\0');
-        char *pResizedPath = const_cast<char *>(resizedPath.c_str());
-        if (_NSGetExecutablePath(pResizedPath, &lenActualPath) == 0)
-        {
-            entrypointExecutable.assign(pResizedPath);
-            result = true;
-        }
-    }
-#elif defined (TARGET_FREEBSD)
-    static const int name[] = {
-        CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1
-    };
-    char path[PATH_MAX];
-    size_t len;
-
-    len = sizeof(path);
-    if (sysctl(name, 4, path, &len, nullptr, 0) == 0)
-    {
-        entrypointExecutable.assign(path);
-        result = true;
-    }
-    else
-    {
-        // ENOMEM
-        result = false;
-    }
-#elif defined(TARGET_NETBSD) && defined(KERN_PROC_PATHNAME)
-    static const int name[] = {
-        CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME,
-    };
-    char path[MAXPATHLEN];
-    size_t len;
-
-    len = sizeof(path);
-    if (sysctl(name, __arraycount(name), path, &len, NULL, 0) != -1)
-    {
-        entrypointExecutable.assign(path);
-        result = true;
-    }
-    else
-    {
-        result = false;
-    }
-#else
-    // On other OSs, return the symlink that will be resolved by GetAbsolutePath
-    // to fetch the entrypoint EXE absolute path, inclusive of filename.
-    result = GetAbsolutePath(RuntimeHostingConstants::SymlinkEntrypointExecutable, entrypointExecutable);
-#endif 
-
-    return result;
-}
+#ifdef HOST_UNIX
 
 static HRESULT ProbeInstallationMarkerFile(const char* const markerName, std::string &hostRuntimeDirectory)
 {
@@ -505,7 +409,7 @@ static HRESULT ProbeInstallationMarkerFile(const char* const markerName, std::st
     return hostRuntimeDirectory.empty() ? S_FALSE : S_OK;
 }
 
-#endif // HOST_WINDOWS
+#endif // HOST_UNIX
 
 static HRESULT ProbeInstallationDir(const char* const installPath, std::string& hostRuntimeDirectory)
 {
@@ -572,7 +476,7 @@ static HRESULT GetHostRuntime(std::string& coreClrPath, std::string& hostRuntime
         };
 
 #if defined(HOST_UNIX)
-        for (int i = 0; i < _countof(RuntimeHostingConstants::UnixInstallPaths); i++)
+        for (int i = 0; i < ARRAY_SIZE(RuntimeHostingConstants::UnixInstallPaths); i++)
         {
             strategyList.push_back({ ProbeInstallationDir, RuntimeHostingConstants::UnixInstallPaths[i] });
         }
@@ -729,8 +633,8 @@ static HRESULT InitializeNetCoreHost()
             "UseLatestBehaviorWhenTFMNotSpecified"
         };
 
-        std::string entryPointExecutablePath;
-        if (!GetEntrypointExecutableAbsolutePath(entryPointExecutablePath))
+        char* exePath = minipal_getexepath();
+        if (!exePath)
         {
             TraceError("Could not get full path to current executable");
             return E_FAIL;
@@ -738,9 +642,9 @@ static HRESULT InitializeNetCoreHost()
 
         void* hostHandle;
         unsigned int domainId;
-        hr = initializeCoreCLR(entryPointExecutablePath.c_str(), "sos",
-            sizeof(propertyKeys) / sizeof(propertyKeys[0]), propertyKeys, propertyValues, &hostHandle, &domainId);
+        hr = initializeCoreCLR(exePath, "sos", ARRAY_SIZE(propertyKeys), propertyKeys, propertyValues, &hostHandle, &domainId);
 
+        free(exePath);
         if (FAILED(hr))
         {
             TraceError("Error: Fail to initialize coreclr %08x\n", hr);
index 427d013dece72300659c24266201279f2616c3be..66f2aab5c474cc2201f8c74d001c77847b3d81fb 100644 (file)
@@ -145,6 +145,16 @@ public:
         PULONG64 offset) = 0;
 
     virtual ULONG STDMETHODCALLTYPE GetOutputWidth() = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE SupportsDml(PULONG supported) = 0;
+
+    virtual void STDMETHODCALLTYPE OutputDmlString(
+        ULONG mask,
+        PCSTR message) = 0;
+
+    virtual HRESULT STDMETHODCALLTYPE AddModuleSymbol(
+        void* param,
+        const char* symbolFileName) = 0;
 };
 
 #ifdef __cplusplus
index 9295f7db716ccf7d2fbee99246b9928f00cba5b1..614bd47c333dfdb37eb06aa8b586007ebe6c8f6c 100644 (file)
@@ -23,42 +23,9 @@ MIDL_INTERFACE("7EE88D46-F8B3-4645-AD3E-01FE7D4F70F1")
 ISymbolService : public IUnknown
 {
 public:
-    virtual bool STDMETHODCALLTYPE IsSymbolStoreEnabled() = 0;
-
-    virtual bool STDMETHODCALLTYPE InitializeSymbolStore(
-        bool msdl,
-        bool symweb,
-        const char* symbolServerPath,
-        const char* authToken,
-        int timeoutInMinutes,
-        const char* symbolCacehPath,
-        const char* symbolDirectoryPath) = 0;
-
     virtual bool STDMETHODCALLTYPE ParseSymbolPath(
         const char* windowsSymbolPath) = 0;
     
-    virtual void STDMETHODCALLTYPE DisplaySymbolStore(
-        WriteLineDelegate writeline) = 0;
-
-    virtual void STDMETHODCALLTYPE DisableSymbolStore() = 0;
-
-    virtual void STDMETHODCALLTYPE LoadNativeSymbols(
-        SymbolFileCallbackDelegate,
-        void*,
-        int, 
-        const char*,
-        ULONG64,
-        int) = 0;
-
-    virtual void STDMETHODCALLTYPE LoadNativeSymbolsFromIndex(
-        SymbolFileCallbackDelegate,
-        void*,
-        int,
-        const char*,
-        BOOL,
-        int,
-        const unsigned char* moduleIndex) = 0;
-
     virtual PVOID STDMETHODCALLTYPE LoadSymbolsForModule(
         LPCWSTR,
         BOOL,
index 6c24506a9d25ddc4c7796e3005980a5b84ecc007..c2785582897881f55889b807bd8da6cfac469d0b 100644 (file)
@@ -2349,6 +2349,21 @@ LLDBServices::GetOutputWidth()
     return m_debugger.GetTerminalWidth();
 }
 
+HRESULT
+LLDBServices::SupportsDml(PULONG supported)
+{
+    supported = 0;
+    return S_OK;
+}
+
+void
+LLDBServices::OutputDmlString(
+    ULONG mask,
+    PCSTR str)
+{
+    OutputString(mask, str);
+}
+
 //----------------------------------------------------------------------------
 // Helper functions
 //----------------------------------------------------------------------------
index a9717f9008f9ef5486eb9167b3f1fd5a8325b0ac..558f30d85631c101e8fff1073a7eda44fda72cbd 100644 (file)
@@ -398,6 +398,12 @@ public:
 
     ULONG STDMETHODCALLTYPE GetOutputWidth();
 
+    HRESULT STDMETHODCALLTYPE SupportsDml(PULONG supported);
+
+    void STDMETHODCALLTYPE OutputDmlString(
+        ULONG mask,
+        PCSTR str);
+
     //----------------------------------------------------------------------------
     // LLDBServices (internal)
     //----------------------------------------------------------------------------
index 7c278ad2e2e5746e71a74cfd9dcbd1e546222bd6..3517fca1097c22215f669624fee57db0f780b67d 100644 (file)
@@ -159,7 +159,7 @@ sosCommandInitialize(lldb::SBDebugger debugger)
     g_services->AddCommand("logging", new sosCommand("logging"), "Enable/disable internal SOS logging.");
     g_services->AddCommand("dumpalc", new sosCommand("DumpALC"), "Displays details about a collectible AssemblyLoadContext to which the specified object is loaded.");
     g_services->AddCommand("dumparray", new sosCommand("DumpArray"), "Displays details about a managed array.");
-    g_services->AddCommand("dumpasync", new sosCommand("DumpAsync"), "Displays info about async state machines on the garbage-collected heap.");
+    g_services->AddCommand("dumpasync", new sosCommand("DumpAsync"), "Displays information about async \"stacks\" on the garbage-collected heap.");
     g_services->AddCommand("dumpassembly", new sosCommand("DumpAssembly"), "Displays details about an assembly.");
     g_services->AddCommand("dumpclass", new sosCommand("DumpClass"), "Displays information about a EE class structure at the specified address.");
     g_services->AddCommand("dumpdelegate", new sosCommand("DumpDelegate"), "Displays information about a delegate.");
index b1790fda668ad93f87656722545f5a3c01e13c9a..a6a1f87157da109ae0ef4fef8d8dc4f2f562b94e 100644 (file)
@@ -476,7 +476,7 @@ namespace Microsoft.Diagnostics.Tools.Counters
                 using (DiagnosticsClientHolder holder = await builder.Build(ct, _processId, diagnosticPort, showChildIO: false, printLaunchCommand: false))
                 using (VirtualTerminalMode vTerm = VirtualTerminalMode.TryEnable())
                 {
-                    bool useAnsi = vTerm.IsEnabled && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+                    bool useAnsi = vTerm.IsEnabled;
                     if (holder == null)
                     {
                         return ReturnCode.Ok;
index 5ee820a96218e359964e6095cfcef3054b125d7f..a22567c55803df2fec082366b6aa4a06199247c4 100644 (file)
@@ -61,6 +61,7 @@ namespace Microsoft.Diagnostics.Tools.Counters.Exporters
         private int maxNameLength = 40; // Allow room for 40 character counter names by default.
 
         private int STATUS_ROW; // Row # of where we print the status of dotnet-counters
+        private int Top_Row;
         private bool paused = false;
         private bool initialized = false;
         private string _errorText = null;
@@ -93,7 +94,7 @@ namespace Microsoft.Diagnostics.Tools.Counters.Exporters
         {
             if (this.useAnsi) 
             {
-                Console.Write($"\u001b[{row + 1};{col + 1}H");
+                Console.Write($"\u001b[{row + 1 - Top_Row};{col + 1}H");
             }
             else 
             {
@@ -126,6 +127,7 @@ namespace Microsoft.Diagnostics.Tools.Counters.Exporters
             Clear();
             
             int row = Console.CursorTop;
+            Top_Row = row;
             Console.WriteLine("Press p to pause, r to resume, q to quit."); row++;
             Console.WriteLine($"    Status: {GetStatus()}");                STATUS_ROW = row++;
             if (_errorText != null)
index 0a1e7e8ae1972472ee176203e7d7437c09595e84..0e284c974c93c952827e4f048d0969e302a047a8 100644 (file)
@@ -102,7 +102,7 @@ namespace Microsoft.Diagnostics.Tools.Dump
                 _target.ServiceProvider.AddServiceFactory<SOSHost>(() => new SOSHost(_contextService.Services));
 
                 // Automatically enable symbol server support, default cache and search for symbols in the dump directory
-                _symbolService.AddSymbolServer(msdl: true, symweb: false, symbolServerPath: null, authToken: null, timeoutInMinutes: 0);
+                _symbolService.AddSymbolServer(msdl: true, symweb: false, retryCount: 3);
                 _symbolService.AddCachePath(_symbolService.DefaultSymbolCache);
                 _symbolService.AddDirectoryPath(Path.GetDirectoryName(dump_path.FullName));
 
index 1a1b4dcae8e5dc0a763f412003b2607e1c8adf54..f8eafe268927f643261456e1f124ee3689a2ce78 100644 (file)
@@ -38,7 +38,7 @@ namespace Microsoft.Diagnostics.Tools.Stack
         /// <returns></returns>
         private static async Task<int> Report(CancellationToken ct, IConsole console, int processId, string name, TimeSpan duration)
         {
-            string tempNetTraceFilename = Path.GetRandomFileName() + ".nettrace";
+            string tempNetTraceFilename = Path.Join(Path.GetTempPath(), Path.GetRandomFileName() + ".nettrace");
             string tempEtlxFilename = "";
 
             try
index 90e45e785684959d15b8b9b20bc75b9b73e28105..c980e6d183d30d2360b2fbc36d6c7d7cac563dc1 100644 (file)
@@ -166,7 +166,7 @@ namespace Microsoft.Diagnostics.Tools.Trace
 
                 using (DiagnosticsClientHolder holder = await builder.Build(ct, processId, diagnosticPort, showChildIO: showchildio, printLaunchCommand: true))
                 {
-                    string processMainModuleFileName = "";
+                    string processMainModuleFileName = $"Process{processId}";
 
                     // if builder returned null, it means we received ctrl+C while waiting for clients to connect. Exit gracefully.
                     if (holder == null)
@@ -193,23 +193,20 @@ namespace Microsoft.Diagnostics.Tools.Trace
                     {
                         // Reading the process MainModule filename can fail if the target process closes
                         // or isn't fully setup. Retry a few times to attempt to address the issue
-                        for (int attempts = 0; true; attempts++)
+                        for (int attempts = 0; attempts < 10; attempts++)
                         {
                             try
                             {
                                 processMainModuleFileName = process.MainModule.FileName;
                                 break;
                             }
+
                             catch
                             {
-                                if (attempts > 10)
-                                {
-                                    Console.Error.WriteLine("Unable to examine process.");
-                                    return ReturnCode.SessionCreationError;
-                                }
                                 Thread.Sleep(200);
                             }
                         }
+
                     }
 
                     if (String.Equals(output.Name, DefaultTraceName, StringComparison.OrdinalIgnoreCase))
@@ -245,6 +242,12 @@ namespace Microsoft.Diagnostics.Tools.Trace
                         catch (DiagnosticsClientException e)
                         {
                             Console.Error.WriteLine($"Unable to start a tracing session: {e.ToString()}");
+                            return ReturnCode.SessionCreationError;
+                        }
+                        catch (UnauthorizedAccessException e)
+                        {
+                            Console.Error.WriteLine($"dotnet-trace does not have permission to access the specified app: {e.GetType()}");
+                            return ReturnCode.SessionCreationError;
                         }
 
                         if (session == null)
index caa3d5d6d8a63ac0646e80769abd9bbc710a984f..ee8d184c70ad302023b186177e4143423ea0b758 100644 (file)
@@ -32,6 +32,10 @@ namespace Microsoft.Diagnostics.Tools.Trace.CommandLine
             Match match = nameRx.Match(name);
             string functionList = match.Groups[1].Value;
             string arguments = match.Groups[2].Value;
+            if (functionList == string.Empty && arguments == string.Empty)
+            {
+                return name;
+            }
             string[] usingStatement = functionList.Split(".");
             int length = usingStatement.Length;
 
@@ -113,6 +117,10 @@ namespace Microsoft.Diagnostics.Tools.Trace.CommandLine
                 CallTreeNodeBase node = nodesToReport[i];
                 string name = node.Name;
                 string formatName = FormatFunction(name);
+                if (formatName == "?!?")
+                {
+                    formatName = "Missing Symbol";
+                }
                 List<string> nameList = SplitInto(formatName, functionColumnWidth);
 
                 if(isVerbose)
@@ -128,7 +136,7 @@ namespace Microsoft.Diagnostics.Tools.Trace.CommandLine
                 {
                     string inclusiveMeasure = "";
                     string exclusiveMeasure = "";
-                    string number = new string(' ', maxDigit + 2); //+2 lines 130 and 137 account for '. '
+                    string number = new string(' ', maxDigit + 2); //+2 to account for '. '
 
                     if(j == 0)
                     {
index 0c418aecb178cb9a3e14b77af92361e3e1131e82..f50a14830e7fc71578097963b2adfb08d70bbf21 100644 (file)
@@ -98,7 +98,11 @@ struct ClrRuntimeInfo
     ClrRuntimeInfo()
     {
         ModuleHandle = NULL;
+#ifdef TARGET_UNIX
+        ContinueStartupEvent = NULL;
+#else
         ContinueStartupEvent = INVALID_HANDLE_VALUE;
+#endif
 
         EngineMetrics.cbSize = sizeof(EngineMetrics);
         EngineMetrics.dwDbiVersion = CorDebugLatestVersion;
@@ -106,11 +110,13 @@ struct ClrRuntimeInfo
     }
 };
 
+static
 HRESULT
 GetRuntime(
     DWORD debuggeePID,
     ClrRuntimeInfo& clrRuntimeInfo);
 
+static
 HRESULT
 GetTargetCLRMetrics(
     LPCWSTR wszModulePath,
@@ -118,10 +124,12 @@ GetTargetCLRMetrics(
     ClrInfo* pClrInfoOut = NULL,
     DWORD *pdwRVAContinueStartupEvent = NULL);
 
+static
 void
 AppendDbiDllName(
     SString & szFullDbiPath);
 
+static
 bool
 CheckDbiAndRuntimeVersion(
     SString & szFullDbiPath,
@@ -392,8 +400,10 @@ public:
     exit:
         if (FAILED(hr))
         {
-            _ASSERTE(pCordb == NULL);
-
+            if (pCordb != NULL)
+            {
+                pCordb->Release();
+            }
             // Invoke the callback on error
             m_callback(NULL, m_parameter, hr);
         }
@@ -498,19 +508,19 @@ public:
         // Don't need to wake up and wait for the worker thread if called on it
         if (m_threadId != GetCurrentThreadId())
         {
-            // Wait for work thread to exit
-            WaitForSingleObject(m_threadHandle, INFINITE);
+            // Wait for work thread to exit for 60 seconds
+            WaitForSingleObject(m_threadHandle, 60 * 1000);
         }
     }
 
     HRESULT InvokeStartupCallback(bool *pCoreClrExists)
     {
         ClrRuntimeInfo clrRuntimeInfo;
+        IUnknown *pCordb = NULL;
         HRESULT hr = S_OK;
 
         PAL_CPP_TRY
         {
-            IUnknown *pCordb = NULL;
 
             *pCoreClrExists = FALSE;
 
@@ -588,7 +598,10 @@ public:
                 SetEvent(clrRuntimeInfo.ContinueStartupEvent);
             }
         }
-
+        if (FAILED(hr) && (pCordb != NULL))
+        {
+            pCordb->Release();
+        }
         return hr;
     }
 
@@ -1868,7 +1881,6 @@ GetDbiFilenameNextToRuntime(
 // Return Value:
 //    true if the versions match
 //
-static
 bool
 CheckDbiAndRuntimeVersion(
     SString & szFullDbiPath,
index 964c69ac3c53b115eaecb20132399a91e2446497..40fa07a85624fe700f86a985a4b7dac2f235a678 100644 (file)
@@ -105,7 +105,7 @@ STDMETHODIMP CLRDebuggingImpl::OpenVirtualProcess(
     HMODULE hDbi = NULL;
     HMODULE hDac = NULL;
     ICorDebugDataTarget * pDt = NULL;
-    CLR_DEBUGGING_VERSION version;
+    CLR_DEBUGGING_VERSION version = {};
 
     // argument checking
     if ((ppProcess != NULL || pFlags != NULL) && pLibraryProvider == NULL)
@@ -667,7 +667,7 @@ HRESULT CLRDebuggingImpl::GetCLRInfo(ICorDebugDataTarget * pDataTarget,
             }
         }
 
-        CLR_DEBUG_RESOURCE debugResource;
+        CLR_DEBUG_RESOURCE debugResource = {};
         if (SUCCEEDED(hr) && debugResourceSize != sizeof(debugResource))
         {
             hr = CORDBG_E_NOT_CLR;
index 8f8399fc3fe3c20c9340ca0f6384e631ec11426d..f013850303b222cd1d2c86e58ea1c98cc5b275d5 100644 (file)
@@ -1,7 +1,7 @@
 <Project>
   <Import Project="$(MSBuildThisFileDirectory)..\..\Directory.Build.props"/>
   <PropertyGroup>
-    <IsShipping>false</IsShipping>
+    <IsShipping>true</IsShipping>
     <NoPackageAnalysis>true</NoPackageAnalysis>
     <PackageDescription>Internal implementation package not meant for direct consumption. Please do not reference directly.</PackageDescription>
   </PropertyGroup>
index 242bf65eb8aeef065d89dd1bbe94f9b6f215531b..984834b46c834b4fa046fc84563fcdec68f57d24 100644 (file)
@@ -64,14 +64,12 @@ HRESULT GetMachineAndResourceSectionRVA(ICorDebugDataTarget* pDataTarget,
 
     // after the signature is a 20 byte image file header
     // we need to parse this to figure out the target architecture
-    IMAGE_FILE_HEADER imageFileHeader;
+    IMAGE_FILE_HEADER imageFileHeader = {};
     if (SUCCEEDED(hr))
     {
         hr = ReadFromDataTarget(pDataTarget, moduleBaseAddress + peSigFilePointer + 4, (BYTE*)&imageFileHeader, IMAGE_SIZEOF_FILE_HEADER);
     }
 
-
-
     WORD optHeaderMagic = 0;
     DWORD peOptImageHeaderFilePointer = 0;
     if (SUCCEEDED(hr))
@@ -426,4 +424,4 @@ HRESULT ReadFromDataTarget(ICorDebugDataTarget* pDataTarget,
     }
 
     return hr;
-}
+}
\ No newline at end of file
index aed37ea30dfdc1d170e15db5c028efdabc033495..41c427e6357f563eef44c55c94a78c30fee8774c 100644 (file)
@@ -191,14 +191,10 @@ PORTABILITY_ASSERT("GcInfoDumper::ReportPointerRecord is not implemented on this
 
     };
 
-    const UINT nCONTEXTRegisters = sizeof(rgRegisters)/sizeof(rgRegisters[0]);
-
     UINT iFirstRegister;
     UINT iSPRegister;
-    UINT nRegisters;
 
     iFirstRegister = 0;
-    nRegisters = nCONTEXTRegisters;
 #ifdef TARGET_AMD64
     iSPRegister = (FIELD_OFFSET(CONTEXT, Rsp) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONGLONG);
 #elif defined(TARGET_ARM64)
@@ -218,7 +214,7 @@ PORTABILITY_ASSERT("GcInfoDumper::ReportPointerRecord is not implemented on this
     {
         SIZE_T *pReg = NULL;
 
-        for (UINT iReg = 0; iReg < nRegisters; iReg++)
+        for (UINT iReg = 0; iReg < ARRAY_SIZE(rgRegisters); iReg++)
         {
             UINT iEncodedReg = iFirstRegister + iReg;
 #ifdef TARGET_ARM
@@ -278,7 +274,7 @@ PORTABILITY_ASSERT("GcInfoDumper::ReportPointerRecord is not implemented on this
             }
 #endif
             {
-                _ASSERTE(iReg < nCONTEXTRegisters);
+                _ASSERTE(iReg < ARRAY_SIZE(rgRegisters));
 #ifdef TARGET_ARM
                 pReg = *(SIZE_T**)(pContext + rgRegisters[iReg].cbContextOffset);
                 if (iEncodedReg == 12)
index 868235fc3cfaa1521eb44e77443db8f45e1fc5ed..58fc79c3f8085c92da76e35f5f95bad35bd0ae46 100644 (file)
@@ -36,7 +36,7 @@ const char *        RegName(unsigned reg)
         "EDI"
     };
 
-    _ASSERTE(reg < (sizeof(regNames)/sizeof(regNames[0])));
+    _ASSERTE(reg < ARRAY_SIZE(regNames));
 
     return regNames[reg];
 }
@@ -51,7 +51,7 @@ const char *        CalleeSavedRegName(unsigned reg)
         "EBP"
     };
 
-    _ASSERTE(reg < (sizeof(regNames)/sizeof(regNames[0])));
+    _ASSERTE(reg < ARRAY_SIZE(regNames));
 
     return regNames[reg];
 }
diff --git a/src/shared/minipal/getexepath.h b/src/shared/minipal/getexepath.h
new file mode 100644 (file)
index 0000000..a5e12e0
--- /dev/null
@@ -0,0 +1,100 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef HAVE_MINIPAL_GETEXEPATH_H
+#define HAVE_MINIPAL_GETEXEPATH_H
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#if defined(__APPLE__)
+#include <mach-o/dyld.h>
+#elif defined(__FreeBSD__)
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#elif defined(_WIN32)
+#include <windows.h>
+#elif HAVE_GETAUXVAL
+#include <sys/auxv.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Returns the full path to the executable for the current process, resolving symbolic links.
+// The caller is responsible for releasing the buffer. Returns null on error.
+static inline char* minipal_getexepath(void)
+{
+#if defined(__APPLE__)
+    uint32_t path_length = 0;
+    if (_NSGetExecutablePath(NULL, &path_length) != -1)
+    {
+        errno = EINVAL;
+        return NULL;
+    }
+
+    char path_buf[path_length];
+    if (_NSGetExecutablePath(path_buf, &path_length) != 0)
+    {
+        errno = EINVAL;
+        return NULL;
+    }
+
+    return realpath(path_buf, NULL);
+#elif defined(__FreeBSD__)
+    static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+    char path[PATH_MAX];
+    size_t len = sizeof(path);
+    if (sysctl(name, 4, path, &len, NULL, 0) != 0)
+    {
+        return NULL;
+    }
+
+    return strdup(path);
+#elif defined(__sun)
+    const char* path = getexecname();
+    if (path == NULL)
+    {
+        return NULL;
+    }
+
+    return realpath(path, NULL);
+#elif defined(_WIN32)
+    char path[MAX_PATH];
+    if (GetModuleFileNameA(NULL, path, MAX_PATH) == 0)
+    {
+        return NULL;
+    }
+
+    return _strdup(path);
+#elif defined(TARGET_WASM)
+    // This is a packaging convention that our tooling should enforce.
+    return strdup("/managed");
+#else
+#if HAVE_GETAUXVAL && defined(AT_EXECFN)
+    const char* path = (const char *)(getauxval(AT_EXECFN));
+    if (path && !errno)
+    {
+        return realpath(path, NULL);
+    }
+#endif // HAVE_GETAUXVAL && defined(AT_EXECFN)
+#ifdef __linux__
+    const char* symlinkEntrypointExecutable = "/proc/self/exe";
+#else
+    const char* symlinkEntrypointExecutable = "/proc/curproc/exe";
+#endif
+
+    // Resolve the symlink to the executable from /proc
+    return realpath(symlinkEntrypointExecutable, NULL);
+#endif // defined(__APPLE__)
+}
+
+#ifdef __cplusplus
+}
+#endif // extern "C"
+
+#endif // HAVE_MINIPAL_GETEXEPATH_H
index f91bb693e76133f0d625e14b60f0e743bc97e270..6b2622455067ac87e0a7d3d6569cf27107a477ec 100644 (file)
@@ -145,6 +145,7 @@ function_name() to call the system's implementation
 /* Include our configuration information so it's always present when
    compiling PAL implementation files. */
 #include "config.h"
+#include <minipal/utils.h>
 
 #ifdef DEBUG
 #define _ENABLE_DEBUG_MESSAGES_ 1
index fbf9a3f4c1c95358439eb185afbb1419f544c4ff..7963931b86cacd65870c0a1a2f77c64738a85472 100644 (file)
@@ -163,7 +163,7 @@ LPCWSTR GetPalErrorString(DWORD code)
     ErrorString *stringEntry = (ErrorString *)bsearch(
         &searchEntry,
         palErrorStrings,
-        sizeof(palErrorStrings) / sizeof(palErrorStrings[0]),
+        ARRAY_SIZE(palErrorStrings),
         sizeof(ErrorString),
         CompareErrorStrings);
 
index 54b6296b5ca26494c6df7831d3d3de3d22f47009..dd3870c26b4e9146b1eb5931726b6cabcc1d1a3e 100644 (file)
@@ -220,10 +220,10 @@ static int __check_float_string(size_t nFloatStrUsed,
 #endif  /* _UNICODE */
 {
     _TCHAR floatstring[_CVTBUFSIZE + 1];
-    _TCHAR *pFloatStr=floatstring;
-    size_t nFloatStrUsed=0;
-    size_t nFloatStrSz=sizeof(floatstring)/sizeof(floatstring[0]);
-    int malloc_FloatStrFlag=0;
+    _TCHAR *pFloatStr = floatstring;
+    size_t nFloatStrUsed = 0;
+    size_t nFloatStrSz = ARRAY_SIZE(floatstring);
+    int malloc_FloatStrFlag = 0;
 
     unsigned long number;               /* temp hold-value                   */
 #if ALLOC_TABLE
index 1b1206d8ecba55d6c31f5513fe44e4eab46c1b77..e00e62f44badcf3d2162eb5665209d89ab893ca4 100644 (file)
@@ -33,13 +33,8 @@ SET_DEFAULT_DEBUG_CHANNEL(SYNC);
 
 using namespace CorUnix;
 
-static PalObjectTypeId sg_rgWaitObjectsIds[] =
-    {
-        otiProcess,
-        otiThread
-    };
-static CAllowedObjectTypes sg_aotWaitObject(sg_rgWaitObjectsIds,
-    sizeof(sg_rgWaitObjectsIds)/sizeof(sg_rgWaitObjectsIds[0]));
+static PalObjectTypeId sg_rgWaitObjectsIds[] = { otiProcess, otiThread };
+static CAllowedObjectTypes sg_aotWaitObject(sg_rgWaitObjectsIds, ARRAY_SIZE(sg_rgWaitObjectsIds));
 
 /*++
 Function:
index 80de0941b6cdeb66c3f60e1e1a3953c0f8530b22..79a1c03657998328e4fe90d649efa67c392b6388 100644 (file)
@@ -1441,11 +1441,8 @@ public:
         // Don't need to wait for the worker thread if unregister called on it
         if (m_threadId != (DWORD)THREADSilentGetCurrentThreadId())
         {
-            // Wait for work thread to exit
-            if (WaitForSingleObject(m_threadHandle, INFINITE) != WAIT_OBJECT_0)
-            {
-                ASSERT("WaitForSingleObject\n");
-            }
+            // Wait for work thread to exit for 60 seconds
+            WaitForSingleObject(m_threadHandle, 60 * 1000);
         }
     }
 
index d1372faf30381524595ada101f86f9ee64aed86c..bf23f23ba4cf815d5c8a3e291ef9c18f732b8698 100644 (file)
@@ -50,7 +50,7 @@ LoadLibraryExWrapper(
 
     HRESULT hr   = S_OK;
     HMODULE ret = NULL;
-    DWORD lastError;
+    DWORD lastError = 0;
 
     EX_TRY
     {
@@ -102,7 +102,7 @@ CreateFileWrapper(
     CONTRACTL_END;
 
     HRESULT hr = S_OK;
-    DWORD lastError;
+    DWORD lastError = 0;
     HANDLE ret = INVALID_HANDLE_VALUE;
 
     EX_TRY
@@ -150,7 +150,7 @@ GetFileAttributesWrapper(
 
     HRESULT hr = S_OK;
     DWORD  ret = INVALID_FILE_ATTRIBUTES;
-    DWORD lastError;
+    DWORD lastError = 0;
 
     EX_TRY
     {
@@ -194,7 +194,7 @@ GetFileAttributesExWrapper(
 
     HRESULT hr = S_OK;
     BOOL   ret = FALSE;
-    DWORD lastError;
+    DWORD lastError = 0;
 
     EX_TRY
     {
@@ -239,7 +239,7 @@ DeleteFileWrapper(
 
     HRESULT hr = S_OK;
     BOOL   ret = FALSE;
-    DWORD lastError;
+    DWORD lastError = 0;
 
     EX_TRY
     {
@@ -283,7 +283,7 @@ MoveFileExWrapper(
 
     HRESULT hr  = S_OK;
     BOOL    ret = FALSE;
-    DWORD lastError;
+    DWORD lastError = 0;
 
     EX_TRY
     {
@@ -334,7 +334,7 @@ SearchPathWrapper(
 
     HRESULT hr  = S_OK;
     DWORD    ret = 0;
-    DWORD lastError;
+    DWORD lastError = 0;
 
     EX_TRY
     {
@@ -424,7 +424,7 @@ GetModuleFileNameWrapper(
 
     HRESULT hr = S_OK;
     DWORD ret = 0;
-    DWORD lastError;
+    DWORD lastError = 0;
 
     EX_TRY
     {
@@ -482,7 +482,7 @@ UINT WINAPI GetTempFileNameWrapper(
 
     HRESULT hr = S_OK;
     UINT ret = 0;
-    DWORD lastError;
+    DWORD lastError = 0;
 
     EX_TRY
     {
@@ -526,7 +526,7 @@ DWORD WINAPI GetTempPathWrapper(
 
     HRESULT hr = S_OK;
     DWORD ret = 0;
-    DWORD lastError;
+    DWORD lastError = 0;
 
     EX_TRY
     {
@@ -567,7 +567,7 @@ DWORD WINAPI GetCurrentDirectoryWrapper(
 
     HRESULT hr = S_OK;
     DWORD ret = 0;
-    DWORD lastError;
+    DWORD lastError = 0;
 
     EX_TRY
     {
@@ -609,7 +609,7 @@ DWORD WINAPI GetEnvironmentVariableWrapper(
 
     HRESULT hr = S_OK;
     DWORD ret = 0;
-    DWORD lastError;
+    DWORD lastError = 0;
 
     EX_TRY
     {
@@ -677,7 +677,7 @@ CopyFileExWrapper(
 
     HRESULT hr  = S_OK;
     BOOL    ret = FALSE;
-    DWORD lastError;
+    DWORD lastError = 0;
 
     EX_TRY
     {
@@ -730,7 +730,7 @@ FindFirstFileExWrapper(
 
     HRESULT hr = S_OK;
     HANDLE ret = INVALID_HANDLE_VALUE;
-    DWORD lastError;
+    DWORD lastError = 0;
 
     EX_TRY
     {
@@ -937,6 +937,3 @@ BOOL LongFile::IsDirectorySeparator(WCHAR c)
 {
     return c == DirectorySeparatorChar || c == AltDirectorySeparatorChar;
 }
-
-
-
index 9ab6790efb3f60f21ab866419acfcbcfd546c064..1901d65315d202c6c6b13c1d745e0dc703519490 100644 (file)
@@ -83,7 +83,7 @@ static WCHAR MapChar(WCHAR wc, DWORD dwFlags)
 
     if (dwFlags == LCMAP_UPPERCASE)
     {
-        wTmp =
+        wTmp = (WCHAR)
 #ifdef SELF_NO_HOST
             toupper(wc);
 #else
@@ -93,7 +93,7 @@ static WCHAR MapChar(WCHAR wc, DWORD dwFlags)
     else
     {
         _ASSERTE(dwFlags == LCMAP_LOWERCASE);
-        wTmp =
+        wTmp = (WCHAR)
 #ifdef SELF_NO_HOST
             tolower(wc);
 #else
@@ -2779,4 +2779,4 @@ bool SString::DacGetUnicode(COUNT_T                                   cBufChars,
     return false;
 }
 
-#endif //DACCESS_COMPILE
+#endif //DACCESS_COMPILE
\ No newline at end of file
index 1eba03fe483c541317d5322293370acc51bd63bb..30a1881176d44e2f5782cc70418b0e57fe98d07d 100644 (file)
@@ -85,43 +85,60 @@ namespace Microsoft.Diagnostics
 
         public delegate void RuntimeStartupCallbackDelegate(ICorDebug cordbg, object parameter, HResult hresult);
 
-        public static HResult RegisterForRuntimeStartup(int pid, object parameter, out IntPtr unregisterToken, RuntimeStartupCallbackDelegate callback)
+        public static HResult RegisterForRuntimeStartup(int pid, object parameter, out (IntPtr, GCHandle) unregister, RuntimeStartupCallbackDelegate callback)
         {
-            IntPtr nativeCallback = RuntimeStartupCallback(parameter, callback, out IntPtr nativeParameter);
-            return _registerForRuntimeStartup((uint)pid, nativeCallback, nativeParameter, out unregisterToken);
+            IntPtr nativeCallback = RuntimeStartupCallback(parameter, callback, out GCHandle gchNativeCallback, out IntPtr nativeParameter);
+            HResult hr = _registerForRuntimeStartup((uint)pid, nativeCallback, nativeParameter, out IntPtr unregisterToken);
+            unregister = (unregisterToken, gchNativeCallback);
+            return hr;
         }
 
-        public static HResult RegisterForRuntimeStartupEx(int pid, string applicationGroupId, object parameter, out IntPtr unregisterToken, RuntimeStartupCallbackDelegate callback)
+        public static HResult RegisterForRuntimeStartupEx(int pid, string applicationGroupId, object parameter, out (IntPtr, GCHandle) unregister, RuntimeStartupCallbackDelegate callback)
         {
-            IntPtr nativeCallback = RuntimeStartupCallback(parameter, callback, out IntPtr nativeParameter);
-            return _registerForRuntimeStartupEx((uint)pid, applicationGroupId, nativeCallback, nativeParameter, out unregisterToken);
+            IntPtr nativeCallback = RuntimeStartupCallback(parameter, callback, out GCHandle nativeCallbackHandle, out IntPtr nativeParameter);
+            HResult hr = _registerForRuntimeStartupEx((uint)pid, applicationGroupId, nativeCallback, nativeParameter, out IntPtr unregisterToken);
+            unregister = (unregisterToken, nativeCallbackHandle);
+            return hr;
         }
 
-        public static HResult RegisterForRuntimeStartup3(int pid, string applicationGroupId, object parameter, IntPtr libraryProvider, out IntPtr unregisterToken, RuntimeStartupCallbackDelegate callback)
+        public static HResult RegisterForRuntimeStartup3(int pid, string applicationGroupId, object parameter, IntPtr libraryProvider, out (IntPtr, GCHandle) unregister, RuntimeStartupCallbackDelegate callback)
         {
             if (_registerForRuntimeStartup3 == default)
             {
                 throw new NotSupportedException("RegisterForRuntimeStartup3 not supported");
             }
-            IntPtr nativeCallback = RuntimeStartupCallback(parameter, callback, out IntPtr nativeParameter);
-            return _registerForRuntimeStartup3((uint)pid, applicationGroupId, libraryProvider, nativeCallback, nativeParameter, out unregisterToken);
+            IntPtr nativeCallback = RuntimeStartupCallback(parameter, callback, out GCHandle nativeCallbackHandle, out IntPtr nativeParameter);
+            HResult hr = _registerForRuntimeStartup3((uint)pid, applicationGroupId, libraryProvider, nativeCallback, nativeParameter, out IntPtr unregisterToken);
+            unregister = (unregisterToken, nativeCallbackHandle);
+            return hr;
         }
 
         private delegate void NativeRuntimeStartupCallbackDelegate(IntPtr cordbg, IntPtr parameter, HResult hresult);
 
-        private static IntPtr RuntimeStartupCallback(object parameter, RuntimeStartupCallbackDelegate callback, out IntPtr nativeParameter)
+        private static IntPtr RuntimeStartupCallback(object parameter, RuntimeStartupCallbackDelegate callback, out GCHandle nativeCallbackHandle, out IntPtr nativeParameter)
         {
             NativeRuntimeStartupCallbackDelegate native = (IntPtr cordbg, IntPtr param, HResult hresult) => {
                 GCHandle gch = GCHandle.FromIntPtr(param);
                 callback(ICorDebug.Create(cordbg), gch.Target, hresult);
                 gch.Free();
             };
+            // Need to keep native callback delegate alive until UnregisterForRuntimeStartup
+            nativeCallbackHandle = GCHandle.Alloc(native);
+
+            // Need to keep parameter alive until the callback is invoked
             GCHandle gchParameter = GCHandle.Alloc(parameter);
             nativeParameter = GCHandle.ToIntPtr(gchParameter);
+
+            // Return the function pointer for the native callback
             return Marshal.GetFunctionPointerForDelegate(native);
         }
 
-        public static HResult UnregisterForRuntimeStartup(IntPtr unregisterToken) =>  _unregisterForRuntimeStartup(unregisterToken);
+        public static HResult UnregisterForRuntimeStartup((IntPtr unregisterToken, GCHandle nativeCallbackHandle) unregister)
+        {
+            HResult hr = _unregisterForRuntimeStartup(unregister.unregisterToken);
+            unregister.nativeCallbackHandle.Free();
+            return hr;
+        }
 
         private const int HRESULT_ERROR_PARTIAL_COPY = unchecked((int)0x8007012b);
         private const int HRESULT_ERROR_BAD_LENGTH = unchecked((int)0x80070018);
index 9aed6ff30480ff5d4f4736b1f83f9468aa1f95cd..d66536a9ca5dad7f573bef8073c9714f8151d0aa 100644 (file)
@@ -12,6 +12,7 @@ using System.Collections.Immutable;
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
+using System.Runtime.InteropServices;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
@@ -347,15 +348,15 @@ namespace Microsoft.Diagnostics
                 Assert.True(await debuggeeInfo.WaitForDebuggee());
             }
             Trace.TraceInformation("CreateProcessForLaunch pid {0} DONE", processId);
-            return debuggeeInfo;
+            return debuggeeInfo; 
         }
 
         private static void TestRegisterForRuntimeStartup(DebuggeeInfo debuggeeInfo, int api)
         {
             TestConfiguration config = debuggeeInfo.TestConfiguration;
             AutoResetEvent wait = new AutoResetEvent(false);
+            (IntPtr, GCHandle) unregister = (IntPtr.Zero, default);
             string applicationGroupId =  null;
-            IntPtr unregisterToken = IntPtr.Zero;
             HResult result = HResult.S_OK;
             HResult callbackResult = HResult.S_OK;
             Exception callbackException = null;
@@ -386,14 +387,14 @@ namespace Microsoft.Diagnostics
             switch (api)
             {
                 case 1:
-                    result = DbgShimAPI.RegisterForRuntimeStartup(debuggeeInfo.ProcessId, parameter: IntPtr.Zero, out unregisterToken, callback);
+                    result = DbgShimAPI.RegisterForRuntimeStartup(debuggeeInfo.ProcessId, parameter: IntPtr.Zero, out unregister, callback);
                     break;
                 case 2:
-                    result = DbgShimAPI.RegisterForRuntimeStartupEx(debuggeeInfo.ProcessId, applicationGroupId, parameter: IntPtr.Zero, out unregisterToken, callback);
+                    result = DbgShimAPI.RegisterForRuntimeStartupEx(debuggeeInfo.ProcessId, applicationGroupId, parameter: IntPtr.Zero, out unregister, callback);
                     break;
                 case 3:
                     LibraryProviderWrapper libraryProvider = new(config.RuntimeModulePath(), config.DbiModulePath(), config.DacModulePath());
-                    result = DbgShimAPI.RegisterForRuntimeStartup3(debuggeeInfo.ProcessId, applicationGroupId, parameter: IntPtr.Zero, libraryProvider.ILibraryProvider, out unregisterToken, callback);
+                    result = DbgShimAPI.RegisterForRuntimeStartup3(debuggeeInfo.ProcessId, applicationGroupId, parameter: IntPtr.Zero, libraryProvider.ILibraryProvider, out unregister, callback);
                     break;
                 default:
                     throw new ArgumentException(nameof(api));
@@ -410,7 +411,7 @@ namespace Microsoft.Diagnostics
             Assert.True(wait.WaitOne());
             Trace.TraceInformation("RegisterForRuntimeStartup pid {0} after callback wait", debuggeeInfo.ProcessId);
             
-            AssertResult(DbgShimAPI.UnregisterForRuntimeStartup(unregisterToken));
+            AssertResult(DbgShimAPI.UnregisterForRuntimeStartup(unregister));
             Assert.Null(callbackException);
 
             switch (api)
index 63e8541a3e1013f645a84001c4df988279aaae8d..63929610cdbc2ba15fd11642d796d8bb05fd1182 100644 (file)
@@ -396,7 +396,7 @@ namespace SOS.Hosting
             {
                 if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                 {
-                    using Utilities.ELFModule elfModule = Utilities.OpenELFFile(filePath);
+                    using ELFModule elfModule = ELFModule.OpenFile(filePath);
                     if (elfModule is not null)
                     {
                         return elfModule.BuildID.ToImmutableArray();
@@ -405,7 +405,7 @@ namespace SOS.Hosting
                 }
                 else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                 {
-                    using Utilities.MachOModule machOModule = Utilities.OpenMachOFile(filePath);
+                    using MachOModule machOModule = MachOModule.OpenFile(filePath);
                     if (machOModule is not null)
                     {
                         return machOModule.Uuid.ToImmutableArray();
@@ -445,7 +445,7 @@ namespace SOS.Hosting
                 if (_symbolService is null)
                 {
                     _symbolService = new SymbolService(this);
-                    _symbolService.AddSymbolServer(msdl: true, symweb: false, symbolServerPath: null, authToken: null, timeoutInMinutes: 0);
+                    _symbolService.AddSymbolServer(msdl: true, symweb: false, timeoutInMinutes: 6, retryCount: 5);
                     _symbolService.AddCachePath(SymbolService.DefaultSymbolCache);
                 }
                 return _symbolService;
index 063a1c1ce41a90f4e3306f778ca09ceb4c1b46a4..020212c80da902c640e49a56ec90e401110a3a33 100644 (file)
@@ -2,7 +2,7 @@
 
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net5.0</TargetFramework>
+    <TargetFramework>net6.0</TargetFramework>
   </PropertyGroup>
 
   <ItemGroup>
index 34e867916db778d7fb65efbe774d010628df1abf..c8da1b00e6ccc0b652dc05caa262f4e6e5eaae32 100644 (file)
@@ -16,6 +16,7 @@ using Microsoft.Diagnostics.NETCore.Client;
 using Microsoft.Diagnostics.Tracing;
 
 using Process = System.Diagnostics.Process;
+using System.Runtime.Versioning;
 
 namespace Orchestrator
 {
@@ -191,6 +192,10 @@ namespace Orchestrator
             };
         }
 
+        [SupportedOSPlatformGuard("Windows")]
+        [SupportedOSPlatformGuard("Linux")]
+        static bool IsWindowsOrLinux => OperatingSystem.IsLinux() || OperatingSystem.IsWindows();
+
         static async Task<int> Orchestrate(
             IConsole console,
             CancellationToken ct,
@@ -254,7 +259,8 @@ namespace Orchestrator
                 eventWritingProc.Start();
 
                 Console.WriteLine($"Executing: {eventWritingProc.StartInfo.FileName} {eventWritingProc.StartInfo.Arguments}");
-                if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+
+                if (IsWindowsOrLinux)
                 {
                     // Set affinity and priority
                     ulong affinityMask = 0;
@@ -263,7 +269,6 @@ namespace Orchestrator
                         affinityMask |= ((ulong)1 << j);
                     }
                     eventWritingProc.ProcessorAffinity = (IntPtr)((ulong)eventWritingProc.ProcessorAffinity & affinityMask);
-                    eventWritingProc.PriorityClass = ProcessPriorityClass.RealTime; // Set the process priority to highest possible
                 }
 
                 // Start listening to the event.
index 1f797977b06d9eadb343f93d3924f99d3639e75c..24cd03482b30b4bd43d5c440a4025166e611b461 100644 (file)
@@ -2,7 +2,7 @@
 
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net5.0</TargetFramework>
+    <TargetFramework>net6.0</TargetFramework>
   </PropertyGroup>
 
   <ItemGroup>
index 8ebf84ee3900883ebdaafc4a79803cd3e5ba92db..21e0f004084ad11a401c9910743f5a6f757c4b34 100644 (file)
@@ -3,9 +3,11 @@
 // See the LICENSE file in the project root for more information.
 
 using Microsoft.Diagnostics.DebugServices.Implementation;
+using Microsoft.SymbolStore.SymbolStores;
 using System;
 using System.Collections.Generic;
 using System.Runtime.InteropServices;
+using System.Text;
 using Xunit;
 
 namespace Microsoft.Diagnostics.DebugServices.UnitTests
@@ -105,12 +107,14 @@ namespace Microsoft.Diagnostics.DebugServices.UnitTests
 
         #endregion
     }
+
     public static class SymbolServiceExtensions
     {
-        public static string FormatSymbolStores(
-            this ISymbolService symbolService)
+        public static string FormatSymbolStores(this SymbolService symbolService)
         {
-            return symbolService.ToString().Replace(Environment.NewLine, " ").TrimEnd();
+            StringBuilder sb = new StringBuilder();
+            symbolService.ForEachSymbolStore<Microsoft.SymbolStore.SymbolStores.SymbolStore>((symbolStore) => sb.AppendLine(symbolStore.ToString()));
+            return sb.ToString().Replace(Environment.NewLine, " ").TrimEnd();
         }
     }
 }
index 253b57b42c8517a95db789139557b72ae3a5a7dd..e4df5ede61ea0f8302df5847c1def698e39934fd 100644 (file)
@@ -98,13 +98,17 @@ namespace Microsoft.Diagnostics.DebugServices.UnitTests
                     throw new DiagnosticsException($"Loading {sosPath} FAILED {hr:X8}");
                 }
 
+                // Set the HTTP symbol store timeout and retry count before the symbol path is added to the symbol service
+                HostServices.DefaultTimeout = 6;
+                HostServices.DefaultRetryCount = 5;
+
                 // Initialize the extension host
                 hr = HostServices.Initialize(sosPath);
                 if (hr != HResult.S_OK) {
                     throw new DiagnosticsException($"HostServices.Initialize({sosPath}) FAILED {hr:X8}");
                 }
 
-                var symbolService = Host.Services.GetService<ISymbolService>();
+                ISymbolService symbolService = Host.Services.GetService<ISymbolService>();
                 Trace.TraceInformation($"SymbolService: {symbolService}");
             }