如何獲取 C#程式 內核態線程棧

来源:https://www.cnblogs.com/huangxincheng/archive/2023/06/05/17458487.html
-Advertisement-
Play Games

## 一:背景 ### 1. 講故事 在這麼多的案例分析中,往往會發現一些案例是卡死線上程的內核態棧上,但拿過來的dump都是用戶態模式下,所以無法看到內核態棧,這就比較麻煩,需要讓朋友通過其他方式生成一個藍屏的dump,這裡我們簡單彙總下。 ## 二:如何生成內核態dump ### 1. 案例代碼 ...


一:背景

1. 講故事

在這麼多的案例分析中,往往會發現一些案例是卡死線上程的內核態棧上,但拿過來的dump都是用戶態模式下,所以無法看到內核態棧,這就比較麻煩,需要讓朋友通過其他方式生成一個藍屏的dump,這裡我們簡單彙總下。

二:如何生成內核態dump

1. 案例代碼

為了方便演示,來一段簡單的測試代碼,目的就是觀察 Console.ReadLine 方法的內核態棧。


    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("hello world!");

            Console.ReadLine();
        }
    }

通過 任務管理器 或者 Process Explorer 預設抓取的dump都是 ntdll 之上的空間,可以用 k 來看一下。


0:000> k 3
 # Child-SP          RetAddr               Call Site
00 000000d6`7c9fe328 00007ffe`61405593     ntdll!NtReadFile+0x14
01 000000d6`7c9fe330 00007ffd`50724782     KERNELBASE!ReadFile+0x73
02 000000d6`7c9fe3b0 00007ffe`215bc742     0x00007ffd`50724782

問題來了,如果我要看下 ntdll!NtReadFile 函數對應在內核態中的 nt!NtReadFile 方法怎麼辦呢?只能抓內核態dump,抓內核態dump的方式有很多,這裡聊一下其中的兩種方式。

2. 使用 notmyfault 抓取

說到 藍屏 我相信有很多朋友都知道,簡而言之就是內核態代碼出bug導致系統崩潰,也有朋友知道通過增加一些配置可以在藍屏的時候自動生成 dump 文件,這種 dump 文件就屬於內核態,配置如下:

但這裡有一個問題,操作系統不可能無緣無故的藍屏,那怎麼辦呢?微軟想了一個辦法,人為的造藍屏,所以提供了一個叫 notmyfault.exe 的工具, MSDN網址:https://learn.microsoft.com/en-us/sysinternals/downloads/notmyfault

有了這些前置基礎,接下來就可以操練一下,雙擊 notmyfault.exe 工具,崩潰原因選擇預設的 High IRQL fault,最後點擊 Crash 按鈕,稍等片刻電腦就會藍屏。截圖如下:

我這裡用的是一臺物理的 迷你主機 測試,再次遠程連接後,在 C:\Windows 下會生成一個 MEMORY.dmp 文件,截圖如下:

拿到 dump 之後就可以用 windbg 中的 !process 之類的命令分析了,非常爽。


1: kd>  !process 0 2 ConsoleApp1.exe
PROCESS ffffdb05c1641080
    SessionId: 1  Cid: 1bc8    Peb: fd877dd000  ParentCid: 15ec
    DirBase: 1b9ef3000  ObjectTable: ffffa105fc3d5280  HandleCount: 161.
    Image: ConsoleApp1.exe

        THREAD ffffdb05bf3c7080  Cid 1bc8.0924  Teb: 000000fd877de000 Win32Thread: ffffdb05c00d0ad0 WAIT: (Executive) KernelMode Alertable
            ffffdb05c1902ef8  NotificationEvent

        THREAD ffffdb05c0fc6080  Cid 1bc8.07c8  Teb: 000000fd877e4000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable
            ffffdb05be642ae0  NotificationEvent

        THREAD ffffdb05be694080  Cid 1bc8.17dc  Teb: 000000fd877e6000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable
            ffffdb05be645860  SynchronizationEvent
            ffffdb05be646e60  SynchronizationEvent
            ffffdb05be645d60  SynchronizationEvent

        THREAD ffffdb05be7e2080  Cid 1bc8.1020  Teb: 000000fd877e8000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable
            ffffdb05b68b53a0  NotificationEvent
            ffffdb05be651de0  SynchronizationEvent

1: kd> .thread ffffdb05bf3c7080
Implicit thread is now ffffdb05`bf3c7080

1: kd> k
  *** Stack trace for last set context - .thread/.cxr resets it
 # Child-SP          RetAddr               Call Site
00 fffff50f`606ed570 fffff800`52c1c9c0     nt!KiSwapContext+0x76
01 fffff50f`606ed6b0 fffff800`52c1beef     nt!KiSwapThread+0x500
02 fffff50f`606ed760 fffff800`52c1b793     nt!KiCommitThreadWait+0x14f
03 fffff50f`606ed800 fffff800`52df04c4     nt!KeWaitForSingleObject+0x233
04 fffff50f`606ed8f0 fffff800`53010cdb     nt!IopWaitForSynchronousIoEvent+0x50
05 fffff50f`606ed930 fffff800`52fcc9e8     nt!IopSynchronousServiceTail+0x50b
06 fffff50f`606ed9d0 fffff800`52ff9ae8     nt!IopReadFile+0x7cc
07 fffff50f`606edac0 fffff800`52e0f3f5     nt!NtReadFile+0x8a8
08 fffff50f`606edbd0 00007ffa`2fb4d124     nt!KiSystemServiceCopyEnd+0x25
09 000000fd`8797e108 00000000`00000000     0x00007ffa`2fb4d124

從卦中看,主線程的內核態棧中的 nt!NtReadFile 函數果然給找到了。

2. 使用 procdump

如果僅僅是看線程的內核態棧,我發現有一個非常簡單的方式,就是在 procudump 中多加一個 mk 參數即可,截圖如下:

接下來使用 Terminal 執行 procdump,輸出如下:


PS C:\Users\Administrator\Desktop> procdump -ma -mk ConsoleApp -o D:\testdump

ProcDump v11.0 - Sysinternals process dump utility
Copyright (C) 2009-2022 Mark Russinovich and Andrew Richards
Sysinternals - www.sysinternals.com

[16:24:49] Dump 1 initiated: D:\testdump\ConsoleApp1.exe_230605_162449.dmp
[16:24:50] Dump 1 writing: Estimated dump file size is 57 MB.
[16:24:50] Dump 1 complete: 57 MB written in 0.1 seconds
[16:24:50] Dump 1 kernel: D:\testdump\ConsoleApp1.exe_230605_162449.Kernel.dmp
[16:24:50] Dump count reached.

從卦中看,當前生成了兩個 dmp 文件,一個是用戶態dump,一個是內核態dump,也能看到後者還不到 1M,和剛纔用 notmyfault 生成的 500M dump 所存儲的信息量相差甚遠,但對我目前的場景來說已經夠用了。

接下來打開 ConsoleApp1.exe_230605_162449.Kernel.dmp 文件,使用 !process 找到 ConsoleApp1.exe 的進程。


..................................................
For analysis of this file, run !analyze -v
nt!DbgkpLkmdSnapThreadInContext+0x95:
fffff804`5e688b51 488364242800    and     qword ptr [rsp+28h],0 ss:0018:ffffe10d`62386fd8=ffffe10d5b8fa810
0: kd> !process 0 2 ConsoleApp1.exe
Unable to read _LIST_ENTRY @ fffff8045ea1e080 
0: kd> .reload /user
Loading User Symbols
0: kd> !process 0 2 ConsoleApp1.exe
Unable to read _LIST_ENTRY @ fffff8045ea1e080 

從卦中看居然報錯了,那怎麼辦呢?辦法肯定是有辦法的,可以到用戶態dump中尋找進程ID即可。


0:000> ~
.  0  Id: 3adc.5920 Suspend: 0 Teb: 000000d6`7cb98000 Unfrozen
   1  Id: 3adc.2240 Suspend: 0 Teb: 000000d6`7cba0000 Unfrozen
   2  Id: 3adc.514 Suspend: 0 Teb: 000000d6`7cba2000 Unfrozen
   3  Id: 3adc.3c68 Suspend: 0 Teb: 000000d6`7cba4000 Unfrozen ".NET Finalizer"

拿到 3adc 進程號後再找下麵的主線程,觀察它的線程棧信息,輸出如下:


0: kd> .process 3adc
Implicit process is now 00000000`00003adc
0: kd> !process
PROCESS ffffcf8d5d5b0080
    SessionId: none  Cid: 3adc    Peb: d67cb97000  ParentCid: 4c80
    DirBase: 367d95000  ObjectTable: ffff8e81710bbb40  HandleCount: <Data Not Accessible>
    Image: ConsoleApp1.ex
    VadRoot ffffcf8d5b20fcb0 Vads 90 Clone 0 Private 1529. Modified 941. Locked 2.
    DeviceMap ffff8e8172645110
    Token                             ffff8e815e216060
    ReadMemory error: Cannot get nt!KeMaximumIncrement value.
fffff78000000000: Unable to get shared data
    ElapsedTime                       00:00:00.000
    UserTime                          00:00:00.000
    KernelTime                        00:00:00.000
    QuotaPoolUsage[PagedPool]         153768
    QuotaPoolUsage[NonPagedPool]      12648
    Working Set Sizes (now,min,max)  (14126, 50, 345) (56504KB, 200KB, 1380KB)
    PeakWorkingSetSize                14033
    VirtualSize                       2101882 Mb
    PeakVirtualSize                   2101888 Mb
    PageFaultCount                    15757
    MemoryPriority                    BACKGROUND
    BasePriority                      8
    CommitCharge                      1628
    Job                               ffffcf8d53a102c0

        THREAD ffffcf8d5ae14080  Cid 3adc.5920  Teb: 000000d67cb98000 Win32Thread: ffffcf8d54c3a3b0 RUNNING on processor 0
        THREAD ffffcf8d4f63e080  Cid 3adc.2240  Teb: 000000d67cba0000 Win32Thread: 0000000000000000 INVALID
        THREAD ffffcf8d69a32080  Cid 3adc.0514  Teb: 000000d67cba2000 Win32Thread: 0000000000000000 INVALID
        THREAD ffffcf8d55003580  Cid 3adc.3c68  Teb: 000000d67cba4000 Win32Thread: 0000000000000000 INVALID

0: kd> .thread ffffcf8d5ae14080
Implicit thread is now ffffcf8d`5ae14080

0: kd> k
  *** Stack trace for last set context - .thread/.cxr resets it
 # Child-SP          RetAddr               Call Site
00 ffffe10d`62386fb0 fffff804`5e688a7b     nt!DbgkpLkmdSnapThreadInContext+0x95
01 ffffe10d`623874f0 fffff804`5e01dcd0     nt!DbgkpLkmdSnapThreadApc+0x3b
02 ffffe10d`62387520 fffff804`5e01bb67     nt!KiDeliverApc+0x1b0
03 ffffe10d`623875d0 fffff804`5e01ad6f     nt!KiSwapThread+0x827
04 ffffe10d`62387680 fffff804`5e01a613     nt!KiCommitThreadWait+0x14f
05 ffffe10d`62387720 fffff804`5e439c68     nt!KeWaitForSingleObject+0x233
06 ffffe10d`62387810 fffff804`5e411fe9     nt!IopSynchronousServiceTail+0x238
07 ffffe10d`623878b0 fffff804`5e20d9f5     nt!NtReadFile+0x599
08 ffffe10d`62387990 00007ffe`6390d184     nt!KiSystemServiceCopyEnd+0x25
09 000000d6`7c9fe328 00000000`00000000     0x00007ffe`6390d184


怎麼樣,上面的 nt!NtReadFile+0x599 函數就是。

三:總結

有時候真的需要去抓內核態dump,總有一些千奇百怪的問題,太難了,這裡總結一下給後來人少踩坑吧。

圖片名稱
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • # 前言 生成器是Python的一種核心特性,允許我們在請求新元素時再生成這些元素,而不是在開始時就生成所有元素。它在處理大規模數據集、實現節省記憶體的演算法和構建複雜的迭代器模式等多種情況下都有著廣泛的應用。在本篇文章中,我們將從理論和實踐兩方面來探索Python生成器的深度用法。 ## 生成器的定義 ...
  • 在B站有許多坤坤的視頻,作為一名ikun,讓我們寫個爬蟲研究一下視頻的視頻的名字、鏈接、觀看次數、彈幕、發佈時間以及作者。我們用selenium來實現這個爬蟲,由於要獲取的數據比較多,我們寫幾個函數來實現這個爬蟲。 先倒入需要用到的庫,包括selenium, time ,BeautifulSoup ...
  • 鑒於公司內網安裝的python版本為python3.6.5,而此時又需要安裝第三方庫pytest,本來是想直接在Python官網PyPI直接搜對應可匹配跑python3.6.5版本的pytest進行下載然後傳到內網安裝即可,但是發現pytest依賴別的第三方庫,根據報錯裝了幾個依賴的第三方庫之後,發 ...
  • 基於java的座位預約系統,可以用於圖書館占位系統,圖書館座位預約系統,大學自習室占座系統,自習室座位預約系統,圖書館預約占座系統,自習室預約占座系統,座位預約系統等等; ...
  • 清醒點[toc] # Java虛擬線程 > 翻譯自 screencapture-pradeesh-kumar-medium-an-era-of-virtual-threads-java ```mermaid flowchart LR introduction-->a(why thread)-->b( ...
  • 基於java的倉庫管理系統設計與實現,可適用於出庫、入庫、庫存管理,基於java的出入庫管理,java出入庫管理系統,基於java的WMS倉庫管理系統,庫存物品管理系統。 ...
  • # 1、背景 在我們開發的過程中有這麼一種場景, `/projectA` 目錄是 `hadoopdeploy`用戶創建的,他對這個目錄有`wrx`許可權,同時這個目錄屬於`supergroup`,在這個組中的用戶也具有這個目錄的`wrx`許可權,對於其他人,不可訪問這個目錄。現在有這麼一個特殊的用戶`r ...
  • 有時候,我們為了方便,我們往往使用擴展函數的代碼方式創建很多GridView的操作功能,如在隨筆《在DevExpress中使用BandedGridView表格實現多行表頭的處理》中介紹過多行表頭的創建及綁定處理,在《基於DevExpress的GridControl實現的一些界面處理功能》也介紹了一些... ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...