From: Mike McLaughlin Date: Tue, 24 May 2022 01:14:08 +0000 (-0700) Subject: Merge main into release/stable (#3089) X-Git-Tag: accepted/tizen/unified/20221103.165810~26 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4859474f9e8e6b570b0ff011e71fb2964e5a5cc7;p=platform%2Fcore%2Fdotnet%2Fdiagnostics.git Merge main into release/stable (#3089) * 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] * 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] * 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 * 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] * 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 * Code review feedback Co-authored-by: Juan Hoyos * 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] Co-authored-by: Mike McLaughlin * 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 Co-authored-by: dotnet-maestro[bot] Co-authored-by: Stephen Toub Co-authored-by: Juan Sebastian Hoyos Ayala Co-authored-by: mikelle-rogers <45022607+mikelle-rogers@users.noreply.github.com> Co-authored-by: Dan Moseley Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com> Co-authored-by: John Salem Co-authored-by: Andrew Au Co-authored-by: Martin-Molinero --- diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..cc806a9ac --- /dev/null +++ b/.devcontainer/Dockerfile @@ -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 index 000000000..cba68c3e9 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -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" +} diff --git a/.gitignore b/.gitignore index 357502372..6c05f8d89 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/NuGet.config b/NuGet.config index 11d13157e..68ed20a98 100644 --- a/NuGet.config +++ b/NuGet.config @@ -7,10 +7,9 @@ - + - diff --git a/documentation/EventPipeFormat.md b/documentation/EventPipeFormat.md new file mode 100644 index 000000000..738b43600 --- /dev/null +++ b/documentation/EventPipeFormat.md @@ -0,0 +1 @@ +Please see the [EventPipeFormat documentation in Perfview](https://github.com/Microsoft/perfview/blob/master/src/TraceEvent/EventPipe/EventPipeFormat.md) diff --git a/documentation/building/official-build-instructions.md b/documentation/building/official-build-instructions.md index a21343b0f..42461707e 100644 --- a/documentation/building/official-build-instructions.md +++ b/documentation/building/official-build-instructions.md @@ -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: diff --git a/documentation/lldb/linux-instructions.md b/documentation/lldb/linux-instructions.md index efb15082a..b91043c5a 100644 --- a/documentation/lldb/linux-instructions.md +++ b/documentation/lldb/linux-instructions.md @@ -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 #### diff --git a/eng/Build-Native.cmd b/eng/Build-Native.cmd index d9d5b46f7..d72b33f39 100644 --- a/eng/Build-Native.cmd +++ b/eng/Build-Native.cmd @@ -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: diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6713e2ecf..07d6ba866 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,52 +1,52 @@ - + https://github.com/dotnet/symstore - aebde3c78a70fbbc067a059a98f27f7c4d0abbd5 + 073abc4f492cbc6795989e4a813b0d32017a8623 - + https://github.com/microsoft/clrmd - 5444e45c321f681bdd6b5fbfb4d2115de19c39a2 + a64d9ac11086f28fbd4b2b2337c19be7826fbfa9 - + https://github.com/microsoft/clrmd - 5444e45c321f681bdd6b5fbfb4d2115de19c39a2 + a64d9ac11086f28fbd4b2b2337c19be7826fbfa9 - + https://github.com/dotnet/source-build-reference-packages - e7f2964ac4a556d2ba99a185f52aa93dcbba4f7e + c71ce108eda9f657c9f58a613a1fe56b6b08235d - + https://github.com/dotnet/arcade - e0b311bcd81fc9e27bcf7715dcda62fa38dfa49a + 0403b0d07aff1b103256cfbe082c97a5c8846d20 - + https://github.com/dotnet/arcade - e0b311bcd81fc9e27bcf7715dcda62fa38dfa49a + 0403b0d07aff1b103256cfbe082c97a5c8846d20 - + https://github.com/dotnet/installer - f6e3766b7adfac2863e91ba6453912d24d0fbd9e + ee1b7085a6eb99c97851ed67fc3fd52b8bda3ba0 - + https://github.com/dotnet/aspnetcore - 14468ef10b172da67df3e452ade3d7e0f7e256ca + fac970ded3047f63328ff56f59a874bcabf18126 - + https://github.com/dotnet/aspnetcore - 14468ef10b172da67df3e452ade3d7e0f7e256ca + fac970ded3047f63328ff56f59a874bcabf18126 https://github.com/dotnet/runtime - 0bb27bd5aa461aea3d8a0ab58c6cb1369534f8f6 + a21b9a2dd4c31cf5bd37626562b7612faf21cee6 - + https://github.com/dotnet/runtime - 0bb27bd5aa461aea3d8a0ab58c6cb1369534f8f6 + a21b9a2dd4c31cf5bd37626562b7612faf21cee6 diff --git a/eng/Versions.props b/eng/Versions.props index 50833274d..08c1bc22e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -16,22 +16,22 @@ - 6.0.3 + 6.0.5 - 1.0.320401 + 1.0.326601 3.1.18 $(MicrosoftNETCoreApp31Version) 5.0.9 $(MicrosoftNETCoreApp50Version) - 6.0.5-servicing.22205.8 + 6.0.5-servicing.22213.11 6.0.5 - 6.0.5-servicing.22205.16 - 6.0.5 + 6.0.6-servicing.22262.8 + 6.0.6 - 6.0.104-servicing.22181.15 + 6.0.106-servicing.22263.13 @@ -44,8 +44,8 @@ 4.3.0 1.1.0 - 2.0.317902 - 2.0.317902 + 2.0.325901 + 2.0.325901 16.9.0-beta1.21055.5 2.0.64 2.1.1 @@ -58,7 +58,7 @@ 4.7.2 4.7.1 2.0.3 - 7.0.0-beta.22181.2 + 7.0.0-beta.22269.3 10.0.18362 12.0.2 diff --git a/eng/build.sh b/eng/build.sh index 61824484c..654ab0c0f 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -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 # diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh index e784c9c00..5a59dcff2 100644 --- a/eng/common/cross/build-rootfs.sh +++ b/eng/common/cross/build-rootfs.sh @@ -4,12 +4,13 @@ set -e usage() { - echo "Usage: $0 [BuildArch] [CodeName] [lldbx.y] [--skipunmount] --rootfsdir ]" + echo "Usage: $0 [BuildArch] [CodeName] [lldbx.y] [llvmx[.y]] [--skipunmount] --rootfsdir ]" 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 diff --git a/eng/common/dotnet-install.sh b/eng/common/dotnet-install.sh index 5c94e9863..abd045a32 100755 --- a/eng/common/dotnet-install.sh +++ b/eng/common/dotnet-install.sh @@ -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 ;; *) diff --git a/eng/common/init-tools-native.ps1 b/eng/common/init-tools-native.ps1 index db830c00a..24a5e65de 100644 --- a/eng/common/init-tools-native.ps1 +++ b/eng/common/init-tools-native.ps1 @@ -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 } diff --git a/eng/common/internal/Tools.csproj b/eng/common/internal/Tools.csproj index beb9c4648..7f5ce6d60 100644 --- a/eng/common/internal/Tools.csproj +++ b/eng/common/internal/Tools.csproj @@ -8,6 +8,9 @@ + + + diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1 index b1bca63ab..119a6c660 100644 --- a/eng/common/sdk-task.ps1 +++ b/eng/common/sdk-task.ps1 @@ -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 diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml index 9d1e3042d..3bcd243c4 100644 --- a/eng/common/templates/job/onelocbuild.yml +++ b/eng/common/templates/job/onelocbuild.yml @@ -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 }} diff --git a/eng/common/templates/job/publish-build-assets.yml b/eng/common/templates/job/publish-build-assets.yml index d91bf9147..1cbb6a0c5 100644 --- a/eng/common/templates/job/publish-build-assets.yml +++ b/eng/common/templates/job/publish-build-assets.yml @@ -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: diff --git a/eng/common/templates/job/source-index-stage1.yml b/eng/common/templates/job/source-index-stage1.yml index 4af724eb1..c2d51098d 100644 --- a/eng/common/templates/job/source-index-stage1.yml +++ b/eng/common/templates/job/source-index-stage1.yml @@ -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 }} diff --git a/eng/common/templates/jobs/jobs.yml b/eng/common/templates/jobs/jobs.yml index 554e71cfc..2cca53c2d 100644 --- a/eng/common/templates/jobs/jobs.yml +++ b/eng/common/templates/jobs/jobs.yml @@ -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 }} diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml index 2f176571f..5a9056f6b 100644 --- a/eng/common/templates/post-build/post-build.yml +++ b/eng/common/templates/post-build/post-build.yml @@ -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 diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index f1e1cb539..797f05292 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -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 } diff --git a/eng/native/configurecompiler.cmake b/eng/native/configurecompiler.cmake index b67594cb6..c3e757ccd 100644 --- a/eng/native/configurecompiler.cmake +++ b/eng/native/configurecompiler.cmake @@ -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($<$>>:TARGET_ANDROID>) elseif(CLR_CMAKE_TARGET_LINUX) add_compile_definitions($<$>>:TARGET_LINUX>) + if(CLR_CMAKE_TARGET_LINUX_MUSL) + add_compile_definitions($<$>>:TARGET_LINUX_MUSL>) + endif() elseif(CLR_CMAKE_TARGET_NETBSD) add_compile_definitions($<$>>:TARGET_NETBSD>) elseif(CLR_CMAKE_TARGET_SUNOS) add_compile_definitions($<$>>:TARGET_SUNOS>) + if(CLR_CMAKE_TARGET_OS_ILLUMOS) + add_compile_definitions($<$>>:TARGET_ILLUMOS>) + endif() endif() else(CLR_CMAKE_TARGET_UNIX) add_compile_definitions($<$>>: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($<$:/W$>,$,3>>>) + + # [[! Microsoft.Security.SystemsADM.10086 !]] - SDL required warnings + # set default warning level to 4 but allow targets to override it. + add_compile_options($<$:/W$>,$,4>>>) add_compile_options($<$:/WX>) # treat warnings as errors add_compile_options($<$:/Oi>) # enable intrinsics add_compile_options($<$:/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($<$:/wd4456>) # declaration of 'identifier' hides previous local declaration add_compile_options($<$:/wd4457>) # declaration of 'identifier' hides function parameter add_compile_options($<$:/wd4458>) # declaration of 'identifier' hides class member + add_compile_options($<$:/wd4702>) # unreachable code add_compile_options($<$:/wd4733>) # Inline asm assigning to 'FS:0' : handler not registered as safe handler add_compile_options($<$:/wd4838>) # conversion from 'type_1' to 'type_2' requires a narrowing conversion add_compile_options($<$:/wd4960>) # 'function' is too big to be profiled @@ -586,11 +604,30 @@ if (MSVC) # Treat Warnings as Errors: add_compile_options($<$:/we4007>) # 'main' : must be __cdecl. add_compile_options($<$:/we4013>) # 'function' undefined - assuming extern returning int. + add_compile_options($<$:/we4018>) # 'expression' : signed/unsigned mismatch + add_compile_options($<$:/we4055>) # 'conversion' : from data pointer 'type1' to function pointer 'type2' add_compile_options($<$:/we4102>) # "'%$S' : unreferenced label". + add_compile_options($<$:/we4146>) # unary minus operator applied to unsigned type, result still unsigned + add_compile_options($<$:/we4242>) # 'identifier' : conversion from 'type1' to 'type2', possible loss of data + add_compile_options($<$:/we4244>) # 'conversion' conversion from 'type1' to 'type2', possible loss of data + add_compile_options($<$:/we4267>) # 'var' : conversion from 'size_t' to 'type', possible loss of data + add_compile_options($<$:/we4302>) # 'conversion' : truncation from 'type 1' to 'type 2' + add_compile_options($<$:/we4308>) # negative integral constant converted to unsigned type + add_compile_options($<$:/we4509>) # nonstandard extension used: 'function' uses SEH and 'object' has destructor + add_compile_options($<$:/we4510>) # 'class' : default constructor could not be generated + add_compile_options($<$:/we4532>) # 'continue' : jump out of __finally/finally block has undefined behavior during termination handling + add_compile_options($<$:/we4533>) # initialization of 'variable' is skipped by 'instruction' add_compile_options($<$:/we4551>) # Function call missing argument list. - add_compile_options($<$:/we4700>) # Local used w/o being initialized. + add_compile_options($<$:/we4610>) # object 'class' can never be instantiated - user-defined constructor required + add_compile_options($<$:/we4611>) # interaction between 'function' and C++ object destruction is non-portable add_compile_options($<$:/we4640>) # 'instance' : construction of local static object is not thread-safe + add_compile_options($<$:/we4700>) # Local used w/o being initialized. + add_compile_options($<$:/we4701>) # Potentially uninitialized local variable 'name' used + add_compile_options($<$:/we4703>) # Potentially uninitialized local pointer variable 'name' used + add_compile_options($<$:/we4789>) # destination of memory copy is too small add_compile_options($<$:/we4806>) # Unsafe operation involving type 'bool'. + add_compile_options($<$:/we4995>) # 'function': name was marked as #pragma deprecated + add_compile_options($<$:/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($<$:/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 index 5fc499a8c..000000000 --- a/eng/set-cmake-path.ps1 +++ /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") -} diff --git a/global.json b/global.json index 0d4a3d4fd..37472ac52 100644 --- a/global.json +++ b/global.json @@ -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" } } diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/CommandService.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/CommandService.cs index 03e6a7640..bfb2bc572 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/CommandService.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/CommandService.cs @@ -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 /// 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(); - 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(); + } + 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 index 000000000..66f786f49 --- /dev/null +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/ElfModule.cs @@ -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 +{ + /// + /// Disposable ELFFile wrapper around the module file. + /// + public class ELFModule : ELFFile, IDisposable + { + private readonly Stream _stream; + + /// + /// Opens and returns an ELFFile instance from the local file path + /// + /// ELF file to open + /// ELFFile instance or null + 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 diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/ImageMappingMemoryService.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/ImageMappingMemoryService.cs index 2c9015129..c27f5d4df 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/ImageMappingMemoryService.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/ImageMappingMemoryService.cs @@ -169,11 +169,11 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation else { // Find or download the ELF image, if one. - Reader virtualAddressReader = module.Services.GetService()?.VirtualAddressReader; + Reader virtualAddressReader = module.Services.GetService()?.VirtualAddressReader; if (virtualAddressReader is null) { // Find or download the MachO image, if one. - virtualAddressReader = module.Services.GetService()?.VirtualAddressReader; + virtualAddressReader = module.Services.GetService()?.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 index 000000000..f530888eb --- /dev/null +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/MachOModule.cs @@ -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 +{ + /// + /// Disposable MachOFile wrapper around the module file. + /// + public class MachOModule : MachOFile, IDisposable + { + private readonly Stream _stream; + + /// + /// Opens and returns an MachOFile instance from the local file path + /// + /// MachO file to open + /// MachOFile instance or null + 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(); + } +} diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/Module.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/Module.cs index ec5c3f3a3..dde7210a4 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/Module.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/Module.cs @@ -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 _pdbFileInfos; protected ImmutableArray _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(() => GetPEInfo()); + ServiceProvider.AddService(this); - ServiceProvider.AddServiceFactory(() => Utilities.OpenPEReader(ModuleService.SymbolService.DownloadModule(this))); - if (target.OperatingSystem == OSPlatform.Linux) { - ServiceProvider.AddServiceFactory(() => Utilities.OpenELFFile(ModuleService.SymbolService.DownloadModule(this))); + ServiceProvider.AddServiceFactory(() => { + if (!IndexTimeStamp.HasValue || !IndexFileSize.HasValue) { + return null; + } + return Utilities.OpenPEReader(ModuleService.SymbolService.DownloadModuleFile(this)); + }); + + if (target.OperatingSystem == OSPlatform.Linux) + { + ServiceProvider.AddServiceFactory(() => { + if (BuildId.IsDefaultOrEmpty) { + return null; + } + return ELFModule.OpenFile(ModuleService.SymbolService.DownloadModuleFile(this)); + }); + ServiceProvider.AddServiceFactory(() => { + 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(() => Utilities.OpenMachOFile(ModuleService.SymbolService.DownloadModule(this))); + + if (target.OperatingSystem == OSPlatform.OSX) + { + ServiceProvider.AddServiceFactory(() => { + if (BuildId.IsDefaultOrEmpty) { + return null; + } + return MachOModule.OpenFile(ModuleService.SymbolService.DownloadModuleFile(this)); + }); + ServiceProvider.AddServiceFactory(() => { + Stream stream = ModuleService.MemoryService.CreateMemoryStream(); + var machoFile = new MachOFile(new StreamAddressSpace(stream), ImageBase, true); + return machoFile.IsValid() ? machoFile : null; + }); } + _onChangeEvent = target.Services.GetService()?.OnChangeEvent.Register(() => { - ServiceProvider.RemoveService(typeof(MachOFile)); - ServiceProvider.RemoveService(typeof(ELFFile)); + ServiceProvider.RemoveService(typeof(MachOModule)); + ServiceProvider.RemoveService(typeof(ELFModule)); ServiceProvider.RemoveService(typeof(PEReader)); }); - ServiceProvider.AddService(this); } public void Dispose() @@ -134,16 +166,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation } } - public IEnumerable PdbFileInfos - { - get - { - GetPEInfo(); - Debug.Assert(_pdbFileInfos is not null); - return _pdbFileInfos; - } - } - public virtual ImmutableArray BuildId { get @@ -164,9 +186,51 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation } } - public abstract VersionData VersionData { get; } + public IEnumerable 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(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(); + 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; diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/ModuleService.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/ModuleService.cs index 746ce1ecb..d58bf78cc 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/ModuleService.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/ModuleService.cs @@ -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 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 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 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 /// build id or null 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 /// /// Get the version string from a Linux or MacOS image /// - /// image base + /// module to get version string /// version string or null - 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(); + 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(); + 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; } diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/ModuleServiceFromDataReader.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/ModuleServiceFromDataReader.cs index 7fd2e230f..4624b94a2 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/ModuleServiceFromDataReader.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/ModuleServiceFromDataReader.cs @@ -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 diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/RuntimeService.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/RuntimeService.cs index a29d69484..8892e8bb3 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/RuntimeService.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/RuntimeService.cs @@ -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(); diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/SymbolService.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/SymbolService.cs index fad230562..97b82ac45 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/SymbolService.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/SymbolService.cs @@ -90,6 +90,21 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation } } + /// + /// The time out in minutes passed to the HTTP symbol store when not overridden in AddSymbolServer. + /// + public int DefaultTimeout { get; set; } = 4; + + /// + /// The retry count passed to the HTTP symbol store when not overridden in AddSymbolServer. + /// + public int DefaultRetryCount { get; set; } = 0; + + /// + /// Reset any HTTP symbol stores marked with a client failure + /// + public void Reset() => ForEachSymbolStore((httpSymbolStore) => httpSymbolStore.ResetClientFailure()); + /// /// Parses the Windows debugger symbol path (srv*, cache*, etc.). /// @@ -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 /// if true, use the public Microsoft server /// if true, use symweb internal server and protocol (file.ptr) /// symbol server url (optional) - /// - /// symbol server timeout in minutes (optional) + /// PAT for secure symbol server (optional) + /// symbol server timeout in minutes (optional uses if null) + /// number of retries (optional uses if null) /// if false, failure 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 /// /// module interface /// module path or null - 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; + } + + /// + /// Downloads the symbol file for module + /// + /// module interface + /// module path or null + 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 /// /// module instance + /// /// module path or null - 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 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 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 /// /// module instance + /// /// module path or null - 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 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. /// /// module instance + /// /// module path or null - 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 keys = generator.GetKeys(KeyTypeFlags.IdentityKey); + var generator = new MachOFileKeyGenerator(Tracer.Instance, machOModule, fileName); + IEnumerable 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((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; } + /// + /// Enumerates the symbol stores. + /// + /// type of symbol store or SymbolStore for all + /// called for each store found + public void ForEachSymbolStore(Action 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; + } + } + /// /// Quick fix for Path.GetFileName which incorrectly handles Windows-style paths on Linux /// diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/Utilities.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/Utilities.cs index 71acaf539..2646ea90c 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/Utilities.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/Utilities.cs @@ -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; } - /// - /// Disposable ELFFile wrapper - /// - 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(); - } - - /// - /// Opens and returns an ELFFile instance from the local file path - /// - /// ELF file to open - /// ELFFile instance or null - 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; - } - - /// - /// Disposable MachOFile wrapper - /// - 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(); - } - - /// - /// Opens and returns an MachOFile instance from the local file path - /// - /// MachO file to open - /// MachOFile instance or null - 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; - } - /// /// Attempt to open a file stream. /// diff --git a/src/Microsoft.Diagnostics.DebugServices/IConsoleService.cs b/src/Microsoft.Diagnostics.DebugServices/IConsoleService.cs index 726f0b919..0e8f46770 100644 --- a/src/Microsoft.Diagnostics.DebugServices/IConsoleService.cs +++ b/src/Microsoft.Diagnostics.DebugServices/IConsoleService.cs @@ -29,6 +29,12 @@ namespace Microsoft.Diagnostics.DebugServices /// void WriteError(string value); + /// Writes Debugger Markup Language (DML) markup text. + void WriteDml(string text); + + /// Gets whether is supported. + bool SupportsDml { get; } + /// /// Cancellation token for current command /// diff --git a/src/Microsoft.Diagnostics.DebugServices/IModule.cs b/src/Microsoft.Diagnostics.DebugServices/IModule.cs index 3f4746cd7..b40badf31 100644 --- a/src/Microsoft.Diagnostics.DebugServices/IModule.cs +++ b/src/Microsoft.Diagnostics.DebugServices/IModule.cs @@ -74,18 +74,29 @@ namespace Microsoft.Diagnostics.DebugServices bool? IsFileLayout { get; } /// - /// PDB information for Windows PE modules (managed or native). + /// Returns PDB information for Windows PE modules (managed or native). /// - IEnumerable PdbFileInfos { get; } + IEnumerable GetPdbFileInfos(); /// - /// Version information for Window PE modules (managed or native). + /// Returns the Linux or MacOS symbol file name. /// - VersionData VersionData { get; } + string GetSymbolFileName(); /// - /// This is the file version string containing the build version and commit id. + /// Returns the version information for the modules. /// - string VersionString { get; } + VersionData GetVersionData(); + + /// + /// Returns the file version string containing the build version and commit id. + /// + string GetVersionString(); + + /// + /// Loads or downloads the module's symbol file and registers it with the underlying host debugger. + /// + /// the symbol file name + string LoadSymbols(); } } diff --git a/src/Microsoft.Diagnostics.DebugServices/ISymbolService.cs b/src/Microsoft.Diagnostics.DebugServices/ISymbolService.cs index 4900510cc..db3360797 100644 --- a/src/Microsoft.Diagnostics.DebugServices/ISymbolService.cs +++ b/src/Microsoft.Diagnostics.DebugServices/ISymbolService.cs @@ -11,16 +11,6 @@ namespace Microsoft.Diagnostics.DebugServices { public interface ISymbolService { - /// - /// Symbol file reader instance - /// - public class SymbolFile : IDisposable - { - public virtual void Dispose() - { - } - } - /// /// Invoked when anything changes in the symbol service (adding servers, caches, or directories, clearing store, etc.) /// @@ -40,6 +30,21 @@ namespace Microsoft.Diagnostics.DebugServices /// string DefaultSymbolCache { get; set; } + /// + /// The time out in minutes passed to the HTTP symbol store when not overridden in AddSymbolServer. + /// + int DefaultTimeout { get; set; } + + /// + /// The retry count passed to the HTTP symbol store when not overridden in AddSymbolServer. + /// + int DefaultRetryCount { get; set; } + + /// + /// Reset any HTTP symbol stores marked with a client failure + /// + void Reset(); + /// /// Parses the Windows debugger symbol path (srv*, cache*, etc.). /// @@ -53,10 +58,11 @@ namespace Microsoft.Diagnostics.DebugServices /// if true, use the public Microsoft server /// if true, use symweb internal server and protocol (file.ptr) /// symbol server url (optional) - /// - /// symbol server timeout in minutes (optional) + /// PAT for secure symbol server (optional) + /// symbol server timeout in minutes (optional uses if null) + /// number of retries (optional uses if null) /// if false, failure - 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); /// /// Add cache path to symbol search path @@ -76,11 +82,18 @@ namespace Microsoft.Diagnostics.DebugServices void DisableSymbolStore(); /// - /// Downloads module file + /// Downloads the module file + /// + /// module interface + /// module path or null + string DownloadModuleFile(IModule module); + + /// + /// Downloads the symbol file for module /// /// module interface /// module path or null - string DownloadModule(IModule module); + string DownloadSymbolFile(IModule module); /// /// Download a file from the symbol stores/server. diff --git a/src/Microsoft.Diagnostics.DebugServices/MemoryServiceExtensions.cs b/src/Microsoft.Diagnostics.DebugServices/MemoryServiceExtensions.cs index 2674d567a..bf65e9d58 100644 --- a/src/Microsoft.Diagnostics.DebugServices/MemoryServiceExtensions.cs +++ b/src/Microsoft.Diagnostics.DebugServices/MemoryServiceExtensions.cs @@ -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); } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/ClrModulesCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/ClrModulesCommand.cs index 435e38402..35fabd1eb 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/ClrModulesCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/ClrModulesCommand.cs @@ -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 index 000000000..b5d2c5455 --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs @@ -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 + { + /// The name of the command. + private const string CommandName = "dumpasync"; + + /// Indent width. + private const int TabWidth = 2; + /// The command invocation syntax when used in Debugger Markup Language (DML) commands. + private const string DmlCommandInvoke = $"!{CommandName}"; + + /// The help text to render when asked for help. + private static readonly string s_detailedHelpText = + $"Usage: {CommandName} [--stats] [--coalesce] [--address ] [--methodtable ] [--type ] [--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"; + + /// Gets the runtime for the process. Set by the command framework. + public ClrRuntime? Runtime { get; set; } + + /// Gets whether to only show stacks that include the object with the specified address. + [Option(Name = "--address", Aliases = new string[] { "-addr" }, Help = "Only show stacks that include the object with the specified address.")] + public ulong? ObjectAddress { get; set; } + + /// Gets whether to only show stacks that include objects with the specified method table. + [Option(Name = "--methodtable", Aliases = new string[] { "-mt" }, Help = "Only show stacks that include objects with the specified method table.")] + public ulong? MethodTableAddress { get; set; } + + /// Gets whether to only show stacks that include objects whose type includes the specified name in its name. + [Option(Name = "--type", Help = "Only show stacks that include objects whose type includes the specified name in its name.")] + public string? NameSubstring { get; set; } + + /// Gets whether to include stacks that contain only non-state machine task objects. + [Option(Name = "--tasks", Aliases = new string[] { "-t" }, Help = "Include stacks that contain only non-state machine task objects.")] + public bool IncludeTasks { get; set; } + + /// Gets whether to include completed tasks in stacks. + [Option(Name = "--completed", Aliases = new string[] { "-c" }, Help = "Include completed tasks in stacks.")] + public bool IncludeCompleted { get; set; } + + /// Gets whether to show state machine fields for every async stack frame that has them. + [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; } + + /// Gets whether to summarize all async frames found rather than showing detailed stacks. + [Option(Name = "--stats", Help = "Summarize all async frames found rather than showing detailed stacks.")] + public bool Summarize { get; set; } + + /// Gets whether to coalesce stacks and portions of stacks that are the same. + [Option(Name = "--coalesce", Help = "Coalesce stacks and portions of stacks that are the same.")] + public bool CoalesceStacks { get; set; } + + /// Invokes the command. + 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 objects = CollectObjects(); + + // Render the data according to the options specified. + if (Summarize) + { + RenderStats(); + } + else if (CoalesceStacks) + { + RenderCoalescedStacks(); + } + else + { + RenderStacks(); + } + return; + + // Group frames and summarize how many of each occurred. + 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(); + foreach (KeyValuePair 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 entry in typeCounts.OrderByDescending(e => e.Value.Count)) + { + WriteMethodTable(entry.Value.Type.MethodTable, asyncObject: true); + WriteLine($" {entry.Value.Count,-8:N0} {entry.Key}"); + } + } + + // Group stacks at each frame in order to render a tree of coalesced stacks. + void RenderCoalescedStacks() + { + // Find all stacks to include. + var startingList = new List(); + foreach (KeyValuePair 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); + } + + // Renders the next level of frames for coalesced stacks. + void RenderLevel(List frames, int depth) + { + Console.CancellationToken.ThrowIfCancellationRequested(); + List nextLevel = new List(); + + // 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 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 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(""); + } + } + } + } + + // Render each stack of frames. + 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 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; + } + } + } + } + } + + // Writes out a frame for the specified awaiter field, if possible. + 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(""); + } + } + + // Determine whether the stack rooted in this object should be rendered. + 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(); + 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; + } + + // Outputs a line of information for each instance field on the object. + 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}"); + } + } + } + } + + // Gets a printable description for the specified object. + 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 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; + } + + // Determines whether the specified object is of interest to the user based on their criteria provided as command arguments. + 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; + } + + // Finds all of the relevant async-related objects on the heap. + Dictionary CollectObjects() + { + var found = new Dictionary(); + + // 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 entry in found) + { + foreach (ClrObject continuation in entry.Value.Continuations) + { + if (found.TryGetValue(continuation, out AsyncObject asyncContinuation)) + { + asyncContinuation.TopLevel = false; + } + } + } + + return found; + } + + // Adds the continuation into the list of continuations. + // + // If the continuation is actually a List{object}, enumerate the list to add + // each of the individual continuations to the continuations list. + // + void AddContinuation(ClrObject continuation, List 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); + } + } + + // Tries to get the object contents of a Task's continuations field + 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; + } + + // Analyzes a continuation object to try to follow to the actual continuation target. + 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; + } + + // Determines if a type is or is derived from Task. + 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; + } + } + + /// Writes out a header line. If DML is supported, this will be bolded. + private void WriteHeaderLine(string text) + { + if (Console.SupportsDml) + { + Console.WriteDml($"{text}{Environment.NewLine}"); + } + else + { + WriteLine(text); + } + } + + /// Writes out a method table address. If DML is supported, this will be linked. + /// The method table address. + /// + /// 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. + /// + 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($"{mt,16:x8}"); + break; + + case (true, true, 8): + Console.WriteDml($"{mt:x16}"); + break; + + case (true, false, 4): + Console.WriteDml($"{mt,16:x8}"); + break; + + case (true, false, 8): + Console.WriteDml($"{mt:x16}"); + break; + } + } + + /// Writes out an object address. If DML is supported, this will be linked. + /// The object address. + /// + /// 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. + /// + 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($"{addr,16:x8}"); + break; + + case (true, true, 8): + Console.WriteDml($"{addr:x16}"); + break; + + case (true, false, 4): + Console.WriteDml($"{addr,16:x8}"); + break; + + case (true, false, 8): + Console.WriteDml($"{addr:x16}"); + break; + } + } + + /// Writes out a value type address. If DML is supported, this will be linked. + /// The value type's address. + /// The value type's method table address. + 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($"{addr,16:x8}"); + break; + + case (true, 8): + Console.WriteDml($"{addr:x16}"); + break; + } + } + + /// Writes out a link that should open the source code for an address, if available. + /// If DML is not supported, this is a nop. + private void WriteCodeLink(ulong address) + { + if (address != 0 && address != ulong.MaxValue && + Console.SupportsDml) + { + Console.WriteDml($" @ {address:x}"); + } + } + + /// Gets whether the specified type is an AsyncStateMachineBox{T}. + 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; + } + + /// Tries to get the compiler-generated state machine instance from a state machine box. + private static bool TryGetStateMachine(ClrObject obj, out IAddressableTypedEntity? stateMachine) + { + // AsyncStateMachineBox 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; + } + + /// Extract from the specified field of the specified object something that can be ToString'd. + private static object GetDisplay(IAddressableTypedEntity obj, ClrInstanceField field) + { + if (field.Name is string fieldName) + { + switch (field.ElementType) + { + case ClrElementType.Boolean: + return obj.ReadField(fieldName) ? "true" : "false"; + + case ClrElementType.Char: + char c = obj.ReadField(fieldName); + return c >= 32 && c < 127 ? $"'{c}'" : $"'\\u{(int)c:X4}'"; + + case ClrElementType.Int8: + return obj.ReadField(fieldName); + + case ClrElementType.UInt8: + return obj.ReadField(fieldName); + + case ClrElementType.Int16: + return obj.ReadField(fieldName); + + case ClrElementType.UInt16: + return obj.ReadField(fieldName); + + case ClrElementType.Int32: + return obj.ReadField(fieldName); + + case ClrElementType.UInt32: + return obj.ReadField(fieldName); + + case ClrElementType.Int64: + return obj.ReadField(fieldName); + + case ClrElementType.UInt64: + return obj.ReadField(fieldName); + + case ClrElementType.Float: + return obj.ReadField(fieldName); + + case ClrElementType.Double: + return obj.ReadField(fieldName); + + case ClrElementType.String: + return $"\"{obj.ReadStringField(fieldName)}\""; + + case ClrElementType.Pointer: + case ClrElementType.NativeInt: + case ClrElementType.NativeUInt: + case ClrElementType.FunctionPointer: + return obj.ReadField(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)"; + } + + /// Tries to get a ClrMethod for the method wrapped by a delegate object. + 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(delegateObject.Address, interior: false).ToUInt64(); + if (methodPtr != 0) + { + method = runtime.GetMethodByInstructionPointer(methodPtr); + if (method is null) + { + methodPtr = methodPtrAuxField.Read(delegateObject.Address, interior: false).ToUInt64(); + if (methodPtr != 0) + { + method = runtime.GetMethodByInstructionPointer(methodPtr); + } + } + + return method is not null; + } + } + + method = null; + return false; + } + + /// Creates an indenting string. + /// The number of tabs. + private static string Tabs(int count) => new string(' ', count * TabWidth); + + /// Shortens a string to a maximum length by eliding part of the string with ... + 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; + } + + /// Tries to get the state flags from a task. + private static bool TryGetTaskStateFlags(ClrObject obj, out int flags) + { + if (obj.Type?.GetFieldByName("m_stateFlags") is ClrInstanceField field) + { + flags = field.Read(obj.Address, interior: false); + return true; + } + + flags = 0; + return false; + } + + /// Tries to read the specified value from the field of an entity. + private static bool TryRead(IAddressableTypedEntity entity, string fieldName, out T result) where T : unmanaged + { + if (entity.Type?.GetFieldByName(fieldName) is not null) + { + result = entity.ReadField(fieldName); + return true; + } + + result = default; + return false; + } + + /// Tries to read an object from a field of another object. + 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; + } + + /// Gets whether a task has completed, based on its state flags. + private static bool IsCompleted(int taskStateFlags) + { + const int TASK_STATE_COMPLETED_MASK = 0x1600000; + return (taskStateFlags & TASK_STATE_COMPLETED_MASK) != 0; + } + + /// Determines whether a span contains all zeros. + private static bool AllZero(ReadOnlySpan bytes) + { + for (int i = 0; i < bytes.Length; i++) + { + if (bytes[i] != 0) + { + return false; + } + } + + return true; + } + + /// Gets a string representing interesting aspects of the specified task state flags. + /// + /// 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. + /// + 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 " "; + } + + /// Gets detailed help for the command. + protected override string GetDetailedHelp() => s_detailedHelpText; + + /// Represents an async object to be used as a frame in an async "stack". + private sealed class AsyncObject + { + /// The actual object on the heap. + public ClrObject Object; + /// true if is an AsyncStateMachineBox. + public bool IsStateMachine; + /// A compiler-generated state machine extracted from the object, if one exists. + public IAddressableTypedEntity? StateMachine; + /// The state of the state machine, if the object contains a state machine. + public int AwaitState; + /// The 's Task state flags, if it's a task. + public int TaskStateFlags; + /// Whether this object meets the user-specified criteria for inclusion. + public bool IncludeInOutput; + /// true if this is a top-level instance that nothing else continues to. + /// This starts off as true and then is flipped to false when we find a continuation to this object. + public bool TopLevel = true; + /// The address of the native code for a method on the object (typically MoveNext for a state machine). + public ulong NativeCode; + /// This object's continuations. + public readonly List Continuations = new(); + } + } +} diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Host/ModulesCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Host/ModulesCommand.cs index 3db956e32..9a450ea1a 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/Host/ModulesCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Host/ModulesCommand.cs @@ -50,13 +50,13 @@ namespace Microsoft.Diagnostics.ExtensionCommands WriteLine(" IsFileLayout: {0}", module.IsFileLayout?.ToString() ?? ""); WriteLine(" IndexFileSize: {0}", module.IndexFileSize?.ToString("X8") ?? ""); WriteLine(" IndexTimeStamp: {0}", module.IndexTimeStamp?.ToString("X8") ?? ""); - WriteLine(" Version: {0}", module.VersionData?.ToString() ?? ""); - string versionString = module.VersionString; + WriteLine(" Version: {0}", module.GetVersionData()?.ToString() ?? ""); + 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(); + 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(); + 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 index 000000000..756b302c0 --- /dev/null +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Host/SetSymbolServerCommand.cs @@ -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()); + } + } + } +} diff --git a/src/Microsoft.Diagnostics.Repl/ConsoleService.cs b/src/Microsoft.Diagnostics.Repl/ConsoleService.cs index 1519125b3..fa4687bae 100644 --- a/src/Microsoft.Diagnostics.Repl/ConsoleService.cs +++ b/src/Microsoft.Diagnostics.Repl/ConsoleService.cs @@ -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 diff --git a/src/Microsoft.Diagnostics.TestHelpers/TestHost/TestDataWriter.cs b/src/Microsoft.Diagnostics.TestHelpers/TestHost/TestDataWriter.cs index 5e6b284aa..adc4c668f 100644 --- a/src/Microsoft.Diagnostics.TestHelpers/TestHost/TestDataWriter.cs +++ b/src/Microsoft.Diagnostics.TestHelpers/TestHost/TestDataWriter.cs @@ -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)) { diff --git a/src/Microsoft.Diagnostics.TestHelpers/TestHost/TestDump.cs b/src/Microsoft.Diagnostics.TestHelpers/TestHost/TestDump.cs index 33a64ddb8..2df8072ee 100644 --- a/src/Microsoft.Diagnostics.TestHelpers/TestHost/TestDump.cs +++ b/src/Microsoft.Diagnostics.TestHelpers/TestHost/TestDump.cs @@ -26,7 +26,7 @@ namespace Microsoft.Diagnostics.TestHelpers _serviceProvider.AddService(_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); } diff --git a/src/SOS/SOS.Extensions/ConsoleServiceFromDebuggerServices.cs b/src/SOS/SOS.Extensions/ConsoleServiceFromDebuggerServices.cs index 48096ee6d..927f21b8f 100644 --- a/src/SOS/SOS.Extensions/ConsoleServiceFromDebuggerServices.cs +++ b/src/SOS/SOS.Extensions/ConsoleServiceFromDebuggerServices.cs @@ -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(); diff --git a/src/SOS/SOS.Extensions/DebuggerServices.cs b/src/SOS/SOS.Extensions/DebuggerServices.cs index cbb62bf7c..eb8d85b19 100644 --- a/src/SOS/SOS.Extensions/DebuggerServices.cs +++ b/src/SOS/SOS.Extensions/DebuggerServices.cs @@ -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] GetSymbolByOffset; public readonly delegate* unmanaged[Stdcall] GetOffsetBySymbol; public readonly delegate* unmanaged[Stdcall] GetOutputWidth; + public readonly delegate* unmanaged[Stdcall] SupportsDml; + public readonly delegate* unmanaged[Stdcall] OutputDmlString; + public readonly delegate* unmanaged[Stdcall] AddModuleSymbol; } } } diff --git a/src/SOS/SOS.Extensions/HostServices.cs b/src/SOS/SOS.Extensions/HostServices.cs index 4a062b555..41b9947ac 100644 --- a/src/SOS/SOS.Extensions/HostServices.cs +++ b/src/SOS/SOS.Extensions/HostServices.cs @@ -61,6 +61,16 @@ namespace SOS.Extensions /// public static HostServices Instance { get; private set; } + /// + /// The time out in minutes passed to the HTTP symbol store + /// + public static int DefaultTimeout { get; set; } = 4; + + /// + /// The retry count passed to the HTTP symbol store + /// + public static int DefaultRetryCount { get; set; } = 0; + /// /// 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 }); diff --git a/src/SOS/SOS.Extensions/ModuleServiceFromDebuggerServices.cs b/src/SOS/SOS.Extensions/ModuleServiceFromDebuggerServices.cs index 74ee74b85..ef097f3f3 100644 --- a/src/SOS/SOS.Extensions/ModuleServiceFromDebuggerServices.cs +++ b/src/SOS/SOS.Extensions/ModuleServiceFromDebuggerServices.cs @@ -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(); 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) diff --git a/src/SOS/SOS.Hosting/Commands/SOSCommand.cs b/src/SOS/SOS.Hosting/Commands/SOSCommand.cs index 741c10510..d3eb44e12 100644 --- a/src/SOS/SOS.Hosting/Commands/SOSCommand.cs +++ b/src/SOS/SOS.Hosting/Commands/SOSCommand.cs @@ -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.")] diff --git a/src/SOS/SOS.Hosting/RuntimeWrapper.cs b/src/SOS/SOS.Hosting/RuntimeWrapper.cs index c10e74136..4cd6d655d 100644 --- a/src/SOS/SOS.Hosting/RuntimeWrapper.cs +++ b/src/SOS/SOS.Hosting/RuntimeWrapper.cs @@ -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 diff --git a/src/SOS/SOS.Hosting/SOSHost.cs b/src/SOS/SOS.Hosting/SOSHost.cs index 171cb364e..bc46c91bb 100644 --- a/src/SOS/SOS.Hosting/SOSHost.cs +++ b/src/SOS/SOS.Hosting/SOSHost.cs @@ -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; diff --git a/src/SOS/SOS.Hosting/SymbolServiceWrapper.cs b/src/SOS/SOS.Hosting/SymbolServiceWrapper.cs index b3316bbb4..ca1292ae1 100644 --- a/src/SOS/SOS.Hosting/SymbolServiceWrapper.cs +++ b/src/SOS/SOS.Hosting/SymbolServiceWrapper.cs @@ -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"); } - /// - /// 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. - /// - /// if true, use the public Microsoft server - /// if true, use symweb internal server and protocol (file.ptr) - /// symbol server url (optional) - /// symbol server timeout in minutes (optional) - /// symbol cache directory path (optional) - /// symbol directory path to search (optional) - /// if false, failure - 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; - } - /// /// Parse the Windows sympath format /// @@ -144,164 +96,10 @@ namespace SOS.Hosting if (string.IsNullOrWhiteSpace(symbolPath)) { return false; } + _symbolService.DisableSymbolStore(); return _symbolService.ParseSymbolPathFixDefault(symbolPath); } - /// - /// Displays the symbol server and cache configuration - /// - private void DisplaySymbolStore(IntPtr self, WriteLine writeLine) - { - writeLine(_symbolService.ToString()); - } - - /// - /// Load native symbols and modules (i.e. DAC, DBI). - /// - /// called back for each symbol file loaded - /// callback parameter - /// Target configuration: Windows, Linux or OSX - /// module path - /// module base address - /// module size - /// read memory callback delegate - 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 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); - } - } - } - - /// - /// Load native modules (i.e. DAC, DBI) from the runtime build id. - /// - /// called back for each symbol file loaded - /// callback parameter - /// Target configuration: Windows, Linux or OSX - /// module path - /// if true, returns the DBI/DAC keys, otherwise the identity key - /// build id size - /// pointer to build id - 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 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); - } - } - } - /// /// Get expression helper for native SOS. /// @@ -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); } diff --git a/src/SOS/SOS.UnitTests/Scripts/WebApp.script b/src/SOS/SOS.UnitTests/Scripts/WebApp.script index 38b619de9..f5e7e5eef 100644 --- a/src/SOS/SOS.UnitTests/Scripts/WebApp.script +++ b/src/SOS/SOS.UnitTests/Scripts/WebApp.script @@ -117,16 +117,24 @@ VERIFY:\s*\s+\s+\s+.* VERIFY:\s*Total\s+\s+objects\s+ !VERIFY:.*UNKNOWN.* -SOSCOMMAND:DumpAsync -VERIFY:\s*Statistics:\s+ -VERIFY:\s+MT\s+Count\s+TotalSize\s+Class Name\s+ -VERIFY:\s*\s+\s+\s+.* -VERIFY:\s*Total\s+\s+objects\s+ +SOSCOMMAND:DumpAsync --completed +VERIFY:\s*STACK \s* +VERIFY?:\s*<< Awaiting: \s+\s+.* >>\s+ +VERIFY:\s*\s+\s+\(()?\)\s+.* + +SOSCOMMAND:DumpAsync --stats +VERIFY:\s+MT\s+Count\s+Type\s+ +VERIFY:\s*\s+\s+.* +!VERIFY:.*UNKNOWN.* -SOSCOMMAND:DumpAsync -mt \s+MT\s+Count\s+TotalSize\s+Class Name\s+()\s+\s+\s+.* -VERIFY:\s*Statistics:\s+ -VERIFY:\s+MT\s+Count\s+TotalSize\s+Class Name\s+ -VERIFY:\s*\s+\s+\s+.* -VERIFY:\s*Total\s+\s+objects\s+ +SOSCOMMAND:DumpAsync --methodtable 0x\s+MT\s+Count\s+Type\s+()\s+\s+.* +VERIFY:\s*STACK \s* +VERIFY?:\s*<< Awaiting: \s+\s+.* >>\s+ +VERIFY:\s*\s+\s+\(()?\)\s+.* + +SOSCOMMAND:DumpMT --stats +!VERIFY:\s* is not a MethodTable -SOSCOMMAND:DumpAsync -mt -fields +SOSCOMMAND:DumpAsync --coalesce +VERIFY:\s*STACKS \s* +VERIFY:\s*\[\]\s+\s+\(()?\)\s+.* \ No newline at end of file diff --git a/src/SOS/Strike/ExpressionNode.cpp b/src/SOS/Strike/ExpressionNode.cpp index 850784346..bc260ae24 100644 --- a/src/SOS/Strike/ExpressionNode.cpp +++ b/src/SOS/Strike/ExpressionNode.cpp @@ -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 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 || diff --git a/src/SOS/Strike/dbgengservices.cpp b/src/SOS/Strike/dbgengservices.cpp index 96ddf0b7d..4fd5ad7bc 100644 --- a/src/SOS/Strike/dbgengservices.cpp +++ b/src/SOS/Strike/dbgengservices.cpp @@ -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()); diff --git a/src/SOS/Strike/dbgengservices.h b/src/SOS/Strike/dbgengservices.h index 8cd3e593d..18bd585ed 100644 --- a/src/SOS/Strike/dbgengservices.h +++ b/src/SOS/Strike/dbgengservices.h @@ -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 //---------------------------------------------------------------------------- diff --git a/src/SOS/Strike/disasm.cpp b/src/SOS/Strike/disasm.cpp index 1bfebed6e..434c1b69d 100644 --- a/src/SOS/Strike/disasm.cpp +++ b/src/SOS/Strike/disasm.cpp @@ -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); diff --git a/src/SOS/Strike/disasm.h b/src/SOS/Strike/disasm.h index d20cd8b2d..a43e2d3cf 100644 --- a/src/SOS/Strike/disasm.h +++ b/src/SOS/Strike/disasm.h @@ -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; diff --git a/src/SOS/Strike/disasmARM.cpp b/src/SOS/Strike/disasmARM.cpp index 795b568bc..2f9b8793c 100644 --- a/src/SOS/Strike/disasmARM.cpp +++ b/src/SOS/Strike/disasmARM.cpp @@ -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 diff --git a/src/SOS/Strike/disasmARM64.cpp b/src/SOS/Strike/disasmARM64.cpp index ba68dda69..31f5ccb87 100644 --- a/src/SOS/Strike/disasmARM64.cpp +++ b/src/SOS/Strike/disasmARM64.cpp @@ -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 diff --git a/src/SOS/Strike/disasmX86.cpp b/src/SOS/Strike/disasmX86.cpp index 166cc9ecf..7db5d264d 100644 --- a/src/SOS/Strike/disasmX86.cpp +++ b/src/SOS/Strike/disasmX86.cpp @@ -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 diff --git a/src/SOS/Strike/eeheap.cpp b/src/SOS/Strike/eeheap.cpp index 3fcec0382..2642d0a75 100644 --- a/src/SOS/Strike/eeheap.cpp +++ b/src/SOS/Strike/eeheap.cpp @@ -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 +} diff --git a/src/SOS/Strike/gchist.cpp b/src/SOS/Strike/gchist.cpp index 8fa4062a6..e0925c7c3 100644 --- a/src/SOS/Strike/gchist.cpp +++ b/src/SOS/Strike/gchist.cpp @@ -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) diff --git a/src/SOS/Strike/gcroot.cpp b/src/SOS/Strike/gcroot.cpp index aeaa6bfe9..a649bad82 100644 --- a/src/SOS/Strike/gcroot.cpp +++ b/src/SOS/Strike/gcroot.cpp @@ -220,7 +220,7 @@ void GCRootImpl::GetDependentHandleMap(std::unordered_mapNext(_countof(data), data, &fetched); + hr = handles->Next(ARRAY_SIZE(data), data, &fetched); if (FAILED(hr)) { @@ -240,7 +240,7 @@ void GCRootImpl::GetDependentHandleMap(std::unordered_mapNext(_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, diff --git a/src/SOS/Strike/metadata.cpp b/src/SOS/Strike/metadata.cpp index 292ed4a8a..9dc1d5cc5 100644 --- a/src/SOS/Strike/metadata.cpp +++ b/src/SOS/Strike/metadata.cpp @@ -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); diff --git a/src/SOS/Strike/platform/runtimeimpl.cpp b/src/SOS/Strike/platform/runtimeimpl.cpp index df9fb2c70..36ccdb82f 100644 --- a/src/SOS/Strike/platform/runtimeimpl.cpp +++ b/src/SOS/Strike/platform/runtimeimpl.cpp @@ -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; - } -} diff --git a/src/SOS/Strike/platform/runtimeimpl.h b/src/SOS/Strike/platform/runtimeimpl.h index 8afcbc4dd..ac4f43f7d 100644 --- a/src/SOS/Strike/platform/runtimeimpl.h +++ b/src/SOS/Strike/platform/runtimeimpl.h @@ -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) { diff --git a/src/SOS/Strike/platform/targetimpl.cpp b/src/SOS/Strike/platform/targetimpl.cpp index 9b5dc7f0d..20f365809 100644 --- a/src/SOS/Strike/platform/targetimpl.cpp +++ b/src/SOS/Strike/platform/targetimpl.cpp @@ -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); diff --git a/src/SOS/Strike/sildasm.cpp b/src/SOS/Strike/sildasm.cpp index 368d91056..08c0adf41 100644 --- a/src/SOS/Strike/sildasm.cpp +++ b/src/SOS/Strike/sildasm.cpp @@ -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("")); + StringCchCopyW(szName, ARRAY_SIZE(szName), W("")); 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("")); + StringCchCopyW(szName, ARRAY_SIZE(szName), W("")); 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("")); + StringCchCopyW(szFieldName, ARRAY_SIZE(szFieldName), W("")); hr = i->GetTypeDefProps(mdClass, szClassName, 49, &cLen, NULL, NULL); if (FAILED(hr)) - StringCchCopyW(szClassName, COUNTOF(szClassName), W("")); + StringCchCopyW(szClassName, ARRAY_SIZE(szClassName), W("")); 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("")); + StringCchCopyW(szFieldName, ARRAY_SIZE(szFieldName), W("")); else methodPrettyPrinter.HandleReturnType(); @@ -248,7 +248,7 @@ void DisassembleToken(IMetaDataImport *i, NULL, NULL); if (FAILED(hr)) - StringCchCopyW(szClassName, COUNTOF(szClassName), W("")); + StringCchCopyW(szClassName, ARRAY_SIZE(szClassName), W("")); 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("")); + StringCchCopyW(szName, ARRAY_SIZE(szName), W("")); } } 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("")); + StringCchCopyW(szName, ARRAY_SIZE(szName), W("")); } } 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("")); + StringCchCopyW(szName, ARRAY_SIZE(szName), W("")); } else { @@ -314,7 +314,7 @@ void DisassembleToken(IMetaDataImport *i, } else { - StringCchCopyW(szName, COUNTOF(szName), W("")); + StringCchCopyW(szName, ARRAY_SIZE(szName), W("")); } 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); } } diff --git a/src/SOS/Strike/sos.cpp b/src/SOS/Strike/sos.cpp index 534ca7b94..a430fac74 100644 --- a/src/SOS/Strike/sos.cpp +++ b/src/SOS/Strike/sos.cpp @@ -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); } diff --git a/src/SOS/Strike/sos.h b/src/SOS/Strike/sos.h index 21752c9ab..98a71b678 100644 --- a/src/SOS/Strike/sos.h +++ b/src/SOS/Strike/sos.h @@ -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); } diff --git a/src/SOS/Strike/sos_md.h b/src/SOS/Strike/sos_md.h index 71a874376..1ddb33059 100644 --- a/src/SOS/Strike/sos_md.h +++ b/src/SOS/Strike/sos_md.h @@ -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 - diff --git a/src/SOS/Strike/sosdocs.txt b/src/SOS/Strike/sosdocs.txt index ffe74d4d7..96a3a0ada 100644 --- a/src/SOS/Strike/sosdocs.txt +++ b/src/SOS/Strike/sosdocs.txt @@ -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 ] - [-mt ] - [-type ] - [-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", "async ValueTask", and "async ValueTask". It also optionally supports -any other tasks. -\\ - COMMAND: dso. COMMAND: dumpstackobjects. !DumpStackObjects [-verify] [top stack [bottom stack]] diff --git a/src/SOS/Strike/sosdocsunix.txt b/src/SOS/Strike/sosdocsunix.txt index a6f53770b..e72ea0a77 100644 --- a/src/SOS/Strike/sosdocsunix.txt +++ b/src/SOS/Strike/sosdocsunix.txt @@ -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 ] - [-mt ] - [-type ] - [-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", "async ValueTask", and "async ValueTask". It also optionally supports -any other tasks. -\\ - COMMAND: dso. COMMAND: dumpstackobjects. DumpStackObjects [-verify] [top stack [bottom stack]] diff --git a/src/SOS/Strike/stressLogDump.cpp b/src/SOS/Strike/stressLogDump.cpp index ffb3a170e..0cac8b81b 100644 --- a/src/SOS/Strike/stressLogDump.cpp +++ b/src/SOS/Strike/stressLogDump.cpp @@ -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) diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index 03be99886..0796420ce 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -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("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 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 moduleList = ModuleFromName(const_cast("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 ansiType = NULL; - ArrayHolder 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( - "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 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. 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(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::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::iterator arIt = asyncRecords.begin(); arIt != asyncRecords.end(); ++arIt) - { - for (std::vector::iterator contIt = arIt->second.Continuations.begin(); contIt != arIt->second.Continuations.end(); ++contIt) - { - std::map::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::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> continuationChainToExplore; - continuationChainToExplore.push_back(std::pair(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 seen; - while (continuationChainToExplore.size() > 0) - { - // Pop the next continuation from the stack. - std::pair cur = continuationChainToExplore.back(); - continuationChainToExplore.pop_back(); - - // Get the async record for this continuation. It should be one we already know about. - std::map::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::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::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(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 \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("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 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 pMDUnknown; ToRelease 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; } diff --git a/src/SOS/Strike/strike.h b/src/SOS/Strike/strike.h index 35ed21e80..2cf0a237b 100644 --- a/src/SOS/Strike/strike.h +++ b/src/SOS/Strike/strike.h @@ -10,9 +10,7 @@ #ifndef __strike_h__ #define __strike_h__ -#ifndef _countof -#define _countof(x) (sizeof(x)/sizeof(x[0])) -#endif +#include #if defined(_MSC_VER) #pragma warning(disable:4245) // signed/unsigned mismatch diff --git a/src/SOS/Strike/symbols.cpp b/src/SOS/Strike/symbols.cpp index da46121b8..e155bbb4b 100644 --- a/src/SOS/Strike/symbols.cpp +++ b/src/SOS/Strike/symbols.cpp @@ -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 \**********************************************************************/ diff --git a/src/SOS/Strike/symbols.h b/src/SOS/Strike/symbols.h index 2d402d622..d388a6f0f 100644 --- a/src/SOS/Strike/symbols.h +++ b/src/SOS/Strike/symbols.h @@ -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, diff --git a/src/SOS/Strike/util.cpp b/src/SOS/Strike/util.cpp index 0a70e3997..fe69ec024 100644 --- a/src/SOS/Strike/util.cpp +++ b/src/SOS/Strike/util.cpp @@ -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[] = "%s", // DML_RCWrapper "%s", // DML_CCWrapper "%S", // DML_ManagedVar - "%s", // DML_Async "%s", // DML_IL "%s", // DML_ComWrapperRCW "%s", // 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])); } diff --git a/src/SOS/Strike/util.h b/src/SOS/Strike/util.h index 2307c540c..d30197279 100644 --- a/src/SOS/Strike/util.h +++ b/src/SOS/Strike/util.h @@ -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); diff --git a/src/SOS/Strike/vm.cpp b/src/SOS/Strike/vm.cpp index 70e9210db..aabc3c768 100644 --- a/src/SOS/Strike/vm.cpp +++ b/src/SOS/Strike/vm.cpp @@ -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)) ); // diff --git a/src/SOS/extensions/config.h.in b/src/SOS/extensions/config.h.in index 0a065fc23..757847558 100644 --- a/src/SOS/extensions/config.h.in +++ b/src/SOS/extensions/config.h.in @@ -5,5 +5,6 @@ #define __CONFIG_H__ #cmakedefine01 HAVE_DIRENT_D_TYPE +#cmakedefine01 HAVE_GETAUXVAL #endif // __CONFIG_H__ diff --git a/src/SOS/extensions/configure.cmake b/src/SOS/extensions/configure.cmake index dd0208814..1dd0b9612 100644 --- a/src/SOS/extensions/configure.cmake +++ b/src/SOS/extensions/configure.cmake @@ -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) diff --git a/src/SOS/extensions/hostcoreclr.cpp b/src/SOS/extensions/hostcoreclr.cpp index 11a28385d..bd42a0b49 100644 --- a/src/SOS/extensions/hostcoreclr.cpp +++ b/src/SOS/extensions/hostcoreclr.cpp @@ -20,23 +20,13 @@ #include #include -#if defined(__APPLE__) -#include -#endif - -#if defined(__FreeBSD__) -#include -#include -#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 +#include #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 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(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); diff --git a/src/SOS/inc/debuggerservices.h b/src/SOS/inc/debuggerservices.h index 427d013de..66f2aab5c 100644 --- a/src/SOS/inc/debuggerservices.h +++ b/src/SOS/inc/debuggerservices.h @@ -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 diff --git a/src/SOS/inc/symbolservice.h b/src/SOS/inc/symbolservice.h index 9295f7db7..614bd47c3 100644 --- a/src/SOS/inc/symbolservice.h +++ b/src/SOS/inc/symbolservice.h @@ -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, diff --git a/src/SOS/lldbplugin/services.cpp b/src/SOS/lldbplugin/services.cpp index 6c24506a9..c27855828 100644 --- a/src/SOS/lldbplugin/services.cpp +++ b/src/SOS/lldbplugin/services.cpp @@ -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 //---------------------------------------------------------------------------- diff --git a/src/SOS/lldbplugin/services.h b/src/SOS/lldbplugin/services.h index a9717f900..558f30d85 100644 --- a/src/SOS/lldbplugin/services.h +++ b/src/SOS/lldbplugin/services.h @@ -398,6 +398,12 @@ public: ULONG STDMETHODCALLTYPE GetOutputWidth(); + HRESULT STDMETHODCALLTYPE SupportsDml(PULONG supported); + + void STDMETHODCALLTYPE OutputDmlString( + ULONG mask, + PCSTR str); + //---------------------------------------------------------------------------- // LLDBServices (internal) //---------------------------------------------------------------------------- diff --git a/src/SOS/lldbplugin/soscommand.cpp b/src/SOS/lldbplugin/soscommand.cpp index 7c278ad2e..3517fca10 100644 --- a/src/SOS/lldbplugin/soscommand.cpp +++ b/src/SOS/lldbplugin/soscommand.cpp @@ -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."); diff --git a/src/Tools/dotnet-counters/CounterMonitor.cs b/src/Tools/dotnet-counters/CounterMonitor.cs index b1790fda6..a6a1f8715 100644 --- a/src/Tools/dotnet-counters/CounterMonitor.cs +++ b/src/Tools/dotnet-counters/CounterMonitor.cs @@ -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; diff --git a/src/Tools/dotnet-counters/Exporters/ConsoleWriter.cs b/src/Tools/dotnet-counters/Exporters/ConsoleWriter.cs index 5ee820a96..a22567c55 100644 --- a/src/Tools/dotnet-counters/Exporters/ConsoleWriter.cs +++ b/src/Tools/dotnet-counters/Exporters/ConsoleWriter.cs @@ -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) diff --git a/src/Tools/dotnet-dump/Analyzer.cs b/src/Tools/dotnet-dump/Analyzer.cs index 0a1e7e8ae..0e284c974 100644 --- a/src/Tools/dotnet-dump/Analyzer.cs +++ b/src/Tools/dotnet-dump/Analyzer.cs @@ -102,7 +102,7 @@ namespace Microsoft.Diagnostics.Tools.Dump _target.ServiceProvider.AddServiceFactory(() => 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)); diff --git a/src/Tools/dotnet-stack/ReportCommand.cs b/src/Tools/dotnet-stack/ReportCommand.cs index 1a1b4dcae..f8eafe268 100644 --- a/src/Tools/dotnet-stack/ReportCommand.cs +++ b/src/Tools/dotnet-stack/ReportCommand.cs @@ -38,7 +38,7 @@ namespace Microsoft.Diagnostics.Tools.Stack /// private static async Task 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 diff --git a/src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs b/src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs index 90e45e785..c980e6d18 100644 --- a/src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs +++ b/src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs @@ -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) diff --git a/src/Tools/dotnet-trace/CommandLine/PrintReportHelper.cs b/src/Tools/dotnet-trace/CommandLine/PrintReportHelper.cs index caa3d5d6d..ee8d184c7 100644 --- a/src/Tools/dotnet-trace/CommandLine/PrintReportHelper.cs +++ b/src/Tools/dotnet-trace/CommandLine/PrintReportHelper.cs @@ -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 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) { diff --git a/src/dbgshim/dbgshim.cpp b/src/dbgshim/dbgshim.cpp index 0c418aecb..f50a14830 100644 --- a/src/dbgshim/dbgshim.cpp +++ b/src/dbgshim/dbgshim.cpp @@ -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, diff --git a/src/dbgshim/debugshim.cpp b/src/dbgshim/debugshim.cpp index 964c69ac3..40fa07a85 100644 --- a/src/dbgshim/debugshim.cpp +++ b/src/dbgshim/debugshim.cpp @@ -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; diff --git a/src/dbgshim/pkg/Directory.Build.props b/src/dbgshim/pkg/Directory.Build.props index 8f8399fc3..f01385030 100644 --- a/src/dbgshim/pkg/Directory.Build.props +++ b/src/dbgshim/pkg/Directory.Build.props @@ -1,7 +1,7 @@ - false + true true Internal implementation package not meant for direct consumption. Please do not reference directly. diff --git a/src/shared/dbgutil/dbgutil.cpp b/src/shared/dbgutil/dbgutil.cpp index 242bf65eb..984834b46 100644 --- a/src/shared/dbgutil/dbgutil.cpp +++ b/src/shared/dbgutil/dbgutil.cpp @@ -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 diff --git a/src/shared/gcdump/gcinfodumper.cpp b/src/shared/gcdump/gcinfodumper.cpp index aed37ea30..41c427e63 100644 --- a/src/shared/gcdump/gcinfodumper.cpp +++ b/src/shared/gcdump/gcinfodumper.cpp @@ -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) diff --git a/src/shared/gcdump/i386/gcdumpx86.cpp b/src/shared/gcdump/i386/gcdumpx86.cpp index 868235fc3..58fc79c3f 100644 --- a/src/shared/gcdump/i386/gcdumpx86.cpp +++ b/src/shared/gcdump/i386/gcdumpx86.cpp @@ -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 index 000000000..a5e12e08a --- /dev/null +++ b/src/shared/minipal/getexepath.h @@ -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 +#include +#include + +#if defined(__APPLE__) +#include +#elif defined(__FreeBSD__) +#include +#include +#include +#include +#elif defined(_WIN32) +#include +#elif HAVE_GETAUXVAL +#include +#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 diff --git a/src/shared/pal/src/include/pal/palinternal.h b/src/shared/pal/src/include/pal/palinternal.h index f91bb693e..6b2622455 100644 --- a/src/shared/pal/src/include/pal/palinternal.h +++ b/src/shared/pal/src/include/pal/palinternal.h @@ -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 #ifdef DEBUG #define _ENABLE_DEBUG_MESSAGES_ 1 diff --git a/src/shared/pal/src/misc/errorstrings.cpp b/src/shared/pal/src/misc/errorstrings.cpp index fbf9a3f4c..7963931b8 100644 --- a/src/shared/pal/src/misc/errorstrings.cpp +++ b/src/shared/pal/src/misc/errorstrings.cpp @@ -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); diff --git a/src/shared/pal/src/safecrt/input.inl b/src/shared/pal/src/safecrt/input.inl index 54b6296b5..dd3870c26 100644 --- a/src/shared/pal/src/safecrt/input.inl +++ b/src/shared/pal/src/safecrt/input.inl @@ -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 diff --git a/src/shared/pal/src/synchmgr/wait.cpp b/src/shared/pal/src/synchmgr/wait.cpp index 1b1206d8e..e00e62f44 100644 --- a/src/shared/pal/src/synchmgr/wait.cpp +++ b/src/shared/pal/src/synchmgr/wait.cpp @@ -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: diff --git a/src/shared/pal/src/thread/process.cpp b/src/shared/pal/src/thread/process.cpp index 80de0941b..79a1c0365 100644 --- a/src/shared/pal/src/thread/process.cpp +++ b/src/shared/pal/src/thread/process.cpp @@ -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); } } diff --git a/src/shared/utilcode/longfilepathwrappers.cpp b/src/shared/utilcode/longfilepathwrappers.cpp index d1372faf3..bf23f23ba 100644 --- a/src/shared/utilcode/longfilepathwrappers.cpp +++ b/src/shared/utilcode/longfilepathwrappers.cpp @@ -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; } - - - diff --git a/src/shared/utilcode/sstring.cpp b/src/shared/utilcode/sstring.cpp index 9ab6790ef..1901d6531 100644 --- a/src/shared/utilcode/sstring.cpp +++ b/src/shared/utilcode/sstring.cpp @@ -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 diff --git a/src/tests/DbgShim.UnitTests/DbgShimAPI.cs b/src/tests/DbgShim.UnitTests/DbgShimAPI.cs index 1eba03fe4..30a188117 100644 --- a/src/tests/DbgShim.UnitTests/DbgShimAPI.cs +++ b/src/tests/DbgShim.UnitTests/DbgShimAPI.cs @@ -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); diff --git a/src/tests/DbgShim.UnitTests/DbgShimTests.cs b/src/tests/DbgShim.UnitTests/DbgShimTests.cs index 9aed6ff30..d66536a9c 100644 --- a/src/tests/DbgShim.UnitTests/DbgShimTests.cs +++ b/src/tests/DbgShim.UnitTests/DbgShimTests.cs @@ -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) diff --git a/src/tests/DbgShim.UnitTests/LibraryProviderWrapper.cs b/src/tests/DbgShim.UnitTests/LibraryProviderWrapper.cs index 63e8541a3..63929610c 100644 --- a/src/tests/DbgShim.UnitTests/LibraryProviderWrapper.cs +++ b/src/tests/DbgShim.UnitTests/LibraryProviderWrapper.cs @@ -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; diff --git a/src/tests/EventPipeStress/Orchestrator/Orchestrator.csproj b/src/tests/EventPipeStress/Orchestrator/Orchestrator.csproj index 063a1c1ce..020212c80 100644 --- a/src/tests/EventPipeStress/Orchestrator/Orchestrator.csproj +++ b/src/tests/EventPipeStress/Orchestrator/Orchestrator.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6.0 diff --git a/src/tests/EventPipeStress/Orchestrator/Program.cs b/src/tests/EventPipeStress/Orchestrator/Program.cs index 34e867916..c8da1b00e 100644 --- a/src/tests/EventPipeStress/Orchestrator/Program.cs +++ b/src/tests/EventPipeStress/Orchestrator/Program.cs @@ -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 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. diff --git a/src/tests/EventPipeStress/Stress/Stress.csproj b/src/tests/EventPipeStress/Stress/Stress.csproj index 1f797977b..24cd03482 100644 --- a/src/tests/EventPipeStress/Stress/Stress.csproj +++ b/src/tests/EventPipeStress/Stress/Stress.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6.0 diff --git a/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/SymbolServiceTests.cs b/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/SymbolServiceTests.cs index 8ebf84ee3..21e0f0040 100644 --- a/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/SymbolServiceTests.cs +++ b/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/SymbolServiceTests.cs @@ -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((symbolStore) => sb.AppendLine(symbolStore.ToString())); + return sb.ToString().Replace(Environment.NewLine, " ").TrimEnd(); } } } diff --git a/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/TestDbgEng.cs b/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/TestDbgEng.cs index 253b57b42..e4df5ede6 100644 --- a/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/TestDbgEng.cs +++ b/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/TestDbgEng.cs @@ -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 symbolService = Host.Services.GetService(); Trace.TraceInformation($"SymbolService: {symbolService}"); }