有關OutputDebugString的一點兒事實


我最近花了一些時間分析OutputDebugString方法。在我的另一個實驗中,我需要一個僅依賴於本機API的OutputDebugString版本。在實現它的過程中,我發現了一些關於OutputDebugString的有趣的事實,也許您也會感興趣。

OutputDebugString的工作原理

簡而言之,OutputDebugString嘗試將消息發送到附加到給定進程的調試器,如果沒有調試器偵聽,則嘗試將全局節映射到進程內存中並將調試消息保存在其中。我使用本機API實現OutputDebugStringA(ANSI版本)的示例如下:

void NTAPI RtlOutputDebugStringA(_In_opt_ LPCSTR OutputString) {
    if (OutputString) {
        EXCEPTION_RECORD exceptionRecord{ 0 };
 
        exceptionRecord.ExceptionCode = DBG_PRINTEXCEPTION_C;
        exceptionRecord.NumberParameters = 2;
        exceptionRecord.ExceptionInformation[0] = strlen(OutputString) + 1;
        exceptionRecord.ExceptionInformation[1] = reinterpret_cast<ULONG_PTR>(OutputString);
 
        __try {
            RtlRaiseException(&exceptionRecord);
        } __except (EXCEPTION_EXECUTE_HANDLER) {
            NotifyGlobalDebugOutputMonitor(OutputString);
        }
    }
}

RtlOutputDebugStringA(以及OutputDebugString)檢查調試器存在的方式非常有趣:它引發了一個異常。如果有一個調試器正在偵聽,它將吞了異常(異常代碼:0x40010006L表示ANSI消息,0x4001000A表示UNICODE消息),並且處理程序將永遠不會執行。我們都知道異常是昂貴的,我們應該只在特殊情況下使用它們。因此,對跟蹤的每個寫操作都拋出異常似乎不正確。稍后我將向您展示一些基准測試結果和解決此問題的簡單方法(我想您已經知道了)。但是關於NotifyGlobalDebugOutputMonitor方法的前幾句話。它使用一個全局映射部分、兩個事件對象和一個互斥對象來編寫調試消息。事件對象和互斥鎖保護該節防止並發使用。我不會過多地討論這個問題;如果你感興趣,可以看看張玉武關於代碼項目的優秀文章。您還可以在github上查看我的實現的源代碼(它只是一個POC,所以請不要在接近生產的地方使用它)。可以說,在系統中運行調試輸出監視器(如DebugView)也會對OutputDebugString性能產生負面影響,特別是當多個進程同時向調試輸出寫入數據時。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM