1

Windows 下如何调试 PowerShell - frendguo

 1 year ago
source link: https://www.cnblogs.com/frendguo/p/16485685.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Windows 下如何调试 PowerShell

最近在用 PowerShell 的时候,发现一些地方特别有意思。于是就萌生了看源代码的想法,单看肯定不过瘾,调试起来才有意思。于是就有了这个,记录下。

调试 PowerShell 主要分为两种方式:通过 VS 直接编译运行源代码和通过 WinDbg 来调试。

由于 PowerShell 跨平台的特性,由于我目前只有 Windows 的诉求,所以以下内容将围绕 Windows 来进行。其他平台可以参照官方文档,可以在这里看到:

PowerShell/docs/building at master · PowerShell/PowerShell

第一步自然就是去 github 把代码 clone 下来了。地址是:

https://github.com/PowerShell/PowerShell

截至到2022年7月16日,建议不要直接直接用 master 分支,根据文档介绍,master 分支为最新版本,并非稳定版本。也就是我们平常看到的 preview 的版本。而且,这里强烈建议不用是因为目前 preview 的版本已经切换到 .net 7 了,而 .net 7 的 sos 我没找到(如果知道怎么找到的小伙伴可以告诉我,感谢~)。所以我这里是采用最新的稳定版,也就是 7.2.5 版本的源代码进行。

第二步就是准备好编译环境。因为 PowerShell 全部是 C# 实现的,自然就是依赖 dotnet 环境的了。

官方给了我们一个非常好的脚本,非常便利,在源代码的根目录下执行:

Import-Module ./build.psm1Start-PSBootstrap

或者直接:

Install-Dotnet

就可以完成安装了。

如果只是这样,就结束了,是不是过于顺利了,就没有这篇文章的必要了。

由于我安装了 VS2022 preview 的版本,它顺带帮我安装了 .net 6.0.400-preview.22330.6 的版本,而且还不让卸载。因此我最新的版本始终是 6.0.400-preview,后续的编译,它就死命安装不了要的版本。也就是 6.0.203。

于是就只能从 dot.net 手动下载安装了。

方式一:通过 WinDbg 调试

这种方式适用于不想安装 VS,但需要详细调试的同学。(不要问我为啥不用 VSC,看代码 VSC 确实不错,但调试,还得 WinDbg 来)

这里我们直接采用官方推荐的方式:

Import-Module ./build.psm1Start-PSBuild

然后就出现下面的错误:

VERBOSE: In Find-DotNetWARNING: The 'dotnet' in the current path can't find SDK version 6.0.203, prepending C:\Users\frend\AppData\Local\Microsoft\dotnet to PATH.WARNING: The currently installed .NET Command Line Tools is not the required version. Installed version: 6.0.400-preview.22330Required version: 6.0.203 Fix steps: 1. Remove the installed version from: - on windows '$env:LOCALAPPDATA\Microsoft\dotnet' - on macOS and linux '$env:HOME/.dotnet'2. Run Start-PSBootstrap or Install-Dotnet3. Start-PSBuild -Clean

可是我明明安装了的呀:

- dotnet --list-sdks6.0.203 [C:\Program Files\dotnet\sdk]6.0.302 [C:\Program Files\dotnet\sdk]6.0.400-preview.22330.6 [C:\Program Files\dotnet\sdk]

于是,就去找了下对应的脚本。在 [ps code root]/build.psm1 文件中的 Start-PSBuild → Find-Dotnet → Get-LatestInstalledSDK

function Get-LatestInstalledSDK { Start-NativeExecution -sb { dotnet --list-sdks | Select-String -Pattern '\d*.\d*.\d*(-\w*\.\d*)?' | ForEach-Object { [System.Management.Automation.SemanticVersion]::new($_.matches.value) } | Sort-Object -Descending | Select-Object -First 1 } -IgnoreExitcode 2> $null}

好家伙,直接就是拿最新的作为我安装的版本,所以导致匹配不上,无法开始编译。由于我这里安装了 6.0.203 的,所以我就修改了下。根据我的安装情况,改成让他返回我想要让他返回的版本了(如下加粗版本)。这里需要根据自己实际情况修改!!!

dotnet --list-sdks | Select-String -Pattern '\d*.\d*.\d*(-\w*\.\d*)?' | ForEach-Object { [System.Management.Automation.SemanticVersion]::new($_.matches.value) } | Sort-Object -Descending | Select-Object -First **3 | Sort-Object | Select-Object -First 1**

于是我们重来一遍导入,编译。就能成功啦!

然后就能找到啦 ./src/powershell-win-core/bin/Debug/net6.0/win7-x64/publish/pwsh.exe

打开 WinDbg preview → Launch executable(advanced)

Executable 中填入上一步编译出来的地址,我的是这样的:C:\Users\frend\source\repos\dotnet\PowerShell\src\powershell-win-core\bin\Debug\net6.0\win7-x64\pwsh.exe

Arguments,填入你想调试的命令就好啦。我的是:ex bypass -nop -Command Invoke-webRequest www.baidu.com

其他就可以不管了。来,开始调试~

💡 这里再废话下,WinDbg 需要提前设置好 Default source path 和 Default symbols path 。

由于我们要调试的是托管代码,在启动点我们没办法打断点,得先等 sos 和 clr 加载好了之后才行。

这里我先打了一个clr上的断点:

bp coreclr!CallDescrWorkerInternal

待断点断到了,再加上 PowerShell 启动代码的断点。注意,托管代码需要用 sos 的 !bpmd 来打断点:

0:000> !bpmd pwsh Microsoft.PowerShell.ManagedPSEntry.MainAdding pending breakpoints...0:000> bd 00:000> gModLoad: 00007ff8`d7460000 00007ff8`d7478000 C:\WINDOWS\SYSTEM32\kernel.appcore.dllModLoad: 00000288`fa860000 00000288`fa884000 C:\Users\frend\source\repos\dotnet\PowerShell\src\powershell-win-core\bin\Debug\net6.0\win7-x64\pwsh.dllModLoad: 00000288`fa860000 00000288`fa884000 C:\Users\frend\source\repos\dotnet\PowerShell\src\powershell-win-core\bin\Debug\net6.0\win7-x64\pwsh.dll(45e4.6834): CLR notification exception - code e0444143 (first chance)ModLoad: 00000288`fa8a0000 00000288`fa8ae000 C:\Users\frend\source\repos\dotnet\PowerShell\src\powershell-win-core\bin\Debug\net6.0\win7-x64\System.Runtime.dll(45e4.6834): CLR notification exception - code e0444143 (first chance)ModLoad: 00000288`fa8b0000 00000288`fa90e000 C:\Users\frend\source\repos\dotnet\PowerShell\src\powershell-win-core\bin\Debug\net6.0\win7-x64\Microsoft.PowerShell.ConsoleHost.dll(45e4.6834): CLR notification exception - code e0444143 (first chance)(45e4.6834): CLR notification exception - code e0444143 (first chance)JITTED pwsh!Microsoft.PowerShell.ManagedPSEntry.Main(System.String[])Setting breakpoint: bp 00007FF7E6F82530 [Microsoft.PowerShell.ManagedPSEntry.Main(System.String[])]Breakpoint 1 hit*** WARNING: Unable to verify checksum for C:\Users\frend\source\repos\dotnet\PowerShell\src\powershell-win-core\bin\Debug\net6.0\win7-x64\pwsh.dllpwsh!Microsoft.PowerShell.ManagedPSEntry.Main:00007ff7`e6f82530 55 push rbp

然后,就可以命中断点了。

这里可能不会自动打开并且跳转到源代码中,再 t 几下,就会自动打开的。最终就会变成这样。

917989-20220717000610927-2017557081.png

于是,我们就可以开始顺利的调试了。

方式二:通过 VS 调试

这种方式相对就比较简单了,这里用 VS2022 来做演示。

记得一定要安装对应的 dotnet sdk。具体的版本可以在源代码根目录的 global.json 中查看。

直接在源代码中打开 PowerShell.sln 文件即可打开 PowerShell 项目。然后 build 一下,记得,Windows 下启动目录应该是:powershell-win-core

然后就可以配置调试的参数了:

在项目 powershell-win-core 上鼠标右击,选择属性 → 调试 → Open debug launch profiles UI

然后就是跟 WinDbg 调试类似的参数了。如下图:

917989-20220717000632505-174899592.png

然后,再你想观察的代码处打上断点,点击运行就好啦。

其实官方文档已经比较完善了。基本都比较简单。特别是通过 VS,简直方便的不要不要的。

对于基于 dotnet 的 PowerShell,肯定还会遇到 dotnet 上的问题,那怎么调试 dotnet 呢?

https://github.com/dotnet/runtime


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK