最近在用 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.psm1
Start-PSBootstrap
或者直接:
Install-Dotnet
就可以完成安裝了。
如果只是這樣,就結束了,是不是過於順利了,就沒有這篇文章的必要了。
由於我安裝了 VS2022 preview 的版本,它順帶幫我安裝了 .net 6.0.400-preview.22330.6 的版本,而且還不讓解除安裝。因此我最新的版本始終是 6.0.400-preview,後續的編譯,它就死命安裝不了要的版本。也就是 6.0.203。
於是就只能從 dot.net 手動下載安裝了。
這種方式適用於不想安裝 VS,但需要詳細偵錯的同學。(不要問我為啥不用 VSC,看程式碼 VSC 確實不錯,但偵錯,還得 WinDbg 來)
這裡我們直接採用官方推薦的方式:
Import-Module ./build.psm1
Start-PSBuild
然後就出現下面的錯誤:
VERBOSE: In Find-DotNet
WARNING: 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.22330
Required 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-Dotnet
3. Start-PSBuild -Clean
可是我明明安裝了的呀:
- dotnet --list-sdks
6.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
其他就可以不管了。來,開始偵錯~