摘要:1.如果選擇.NET Framework,請確保不要使用與.NET Core不兼容的任何功能(例如AppDomain),否則您將無法在LLDB中運行擴展。最後,使用以下 LoadManaged 命令加載WinDbg擴展:。

在之前的 如何爲WinDbg編寫ClrMD擴展的CriteoLabs 文章中,我們介紹了在Windows上面寫插件。當遷移到Linux時,由於LLDB是Linux上.NET網絡核心的通用調試器,因此我決定編寫一個兼容層,以便能夠在新環境中加載擴展。

什麼是ClrMD插件

如何創建一個適用於WinDbg和LLDB的擴展?第一步仍然是創建一個新的類庫項目。無論是.NET Framework和.NET Standard都可以,但有些事情需要注意:

1.如果選擇.NET Framework,請確保不要使用與.NET Core不兼容的任何功能(例如AppDomain),否則您將無法在LLDB中運行擴展;
2.如果選擇.NET Standard,請記住發佈項目以將所有依賴項包含在一個文件夾中,因爲在編譯時默認情況下不會這樣做

創建項目後,添加 對ClrMDExports nuget 包的引用。它會自動將ClrMD和 UnmanagedExports.Repack 作爲依賴項。UnmanagedExports.Repack是UnmanagedExports的一個分支,它增加了與.NET Framework 4.7+和.NET Standard的兼容性,並支持PackageReference。

請注意,新的Init.cs文件將添加到您的項目中(如果您使用包引用,則不應該看到它)。 不要對此文件進行任何更改。 每次更新nuget包時都會被覆蓋。

Init文件負責導出WinDbg所需的DebugExtensionInitialize方法,並設置所有內容,只要依賴項與擴展位於相同的文件夾中,就可以正確加載它們。

下一步是添加自定義命令。您需要爲每個命令創建一個靜態方法,並使用以下簽名:

public static void HelloWorld(IntPtr client, [MarshalAs(UnmanagedType.LPStr)] string args)
{
}

然後使用UnmanagedExports附帶的DllExport屬性裝飾它。您可以使用 ExportName 屬性的參數來定義WinDbg / LLDB可見的命令名稱。請記住,名稱區分大小寫!

[DllExport("helloworld")]
public static void HelloWorld(IntPtr client, [MarshalAs(UnmanagedType.LPStr)] string args)
{
}

在該方法中,您應該只調用 DebuggingContext.Execute 由ClrMDExports提供的方法。它接受 clientargs 作爲參數的值,以及帶有 (ClrRuntime runtime, string args) 簽名的另一個靜態方法的委託。在靜態回調方法中,實現命令。

[DllExport("helloworld")]
public static void HelloWorld(IntPtr client, [MarshalAs(UnmanagedType.LPStr)] string args)
{
    DebuggingContext.Execute(client, args, HelloWorld);
}

private static void HelloWorld(ClrRuntime runtime, string args)
{
    Console.WriteLine("The first 10 types on the heap are: ");

    foreach (var type in runtime.Heap.EnumerateTypes().Take(10))
    {
        Console.WriteLine(type);
    }
}

爲方便起見,控制檯輸出會自動重定向到調試器。

您可以直接在WinDbg中加載和使用您的擴展:

在Linux上運行LLDB

由於擴展是爲WinDbg API編寫的,因此無法直接加載到LLDB中。相反,我編寫了一個進行翻譯 的插件

首先, 下載最新版本 的LLDB-LoadManaged元插件並將其解壓縮到一個文件夾中。

然後啓動LLDB並附加到目標:

./lldb -c dump.dmp

接下來,加載元插件:

plugin load ./loadmanaged/libloadmanaged.so

確保Mono.Cecil.dll和PluginInterop.dll文件與libloadmanaged.so位於同一文件夾中。

加載後,LLDB-LoadManaged將嘗試通過瀏覽調試目標中加載的模塊來定位CoreCLR。如果失敗(例如,因爲您在與目標不同的機器上運行lldb),您可以通過調用 SetClrPath 以下命令手動設置路徑:

SetClrPath /usr/local/share/dotnet/shared/Microsoft.NETCore.App/2.2.0/

最後,使用以下 LoadManaged 命令加載WinDbg擴展:

LoadManaged /home/k.gosse/TestExtension.dll

(該 LoadManaged 命令尚不支持相對路徑)

就是這樣!現在,您可以像在WinDbg中一樣調用擴展程序。

WinDbg的ClrMD擴展在Linux上的LLDB中完美運行

注意:libloadmanaged.so和libsosplugin.so都會根據自己的需要託管CLR。但是, .NET Core CLR不支持並排方案 。這意味着我們不能同時使用LoadManaged和SOS插件。這可以講是一個限制,它不太可能在.NET Core端修復。我們這裏有一種解決方法,可以通過LoadManaged加載並替換libsosplugin.so的SOS託管版本。

接下來的路

這雖然是LLDB-LoadManaged的早期版本。在接下來的幾周裏,我想改進錯誤處理並使CLR路徑檢測變得更加智能。還有一點,其實我們已經在Criteo上使用它,這麼來說它對於常見的用例應該足夠穩定。使用LLDB與獨立ClrMD應用程序的主要附加價值是可以附加到實時進程(Linux上的ClrMD尚不支持)。我也想知道基於ClrMD( https://github.com/dotnet/diagnostics/tree/master/src/Tools )的跨平臺REPL環境有一些知識,所以很高興看到這兩項工作如何匯合。

*參考來源 medium ,由周大濤編譯,轉載請註明來自FreeBuf.COM

相關文章