如何获取 C#程序 内核态线程栈

这篇具有很好参考价值的文章主要介绍了如何获取 C#程序 内核态线程栈。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一:背景

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 文件就属于内核态,配置如下:

如何获取 C#程序 内核态线程栈

但这里有一个问题,操作系统不可能无缘无故的蓝屏,那怎么办呢?微软想了一个办法,人为的造蓝屏,所以提供了一个叫 notmyfault.exe 的工具, MSDN网址:https://learn.microsoft.com/en-us/sysinternals/downloads/notmyfault

有了这些前置基础,接下来就可以操练一下,双击 notmyfault.exe 工具,崩溃原因选择默认的 High IRQL fault,最后点击 Crash 按钮,稍等片刻电脑就会蓝屏。截图如下:

如何获取 C#程序 内核态线程栈

我这里用的是一台物理的 迷你主机 测试,再次远程连接后,在 C:\Windows 下会生成一个 MEMORY.dmp 文件,截图如下:

如何获取 C#程序 内核态线程栈

拿到 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 参数即可,截图如下:

如何获取 C#程序 内核态线程栈

接下来使用 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.

如何获取 C#程序 内核态线程栈

从卦中看,当前生成了两个 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,总有一些千奇百怪的问题,太难了,这里总结一下给后来人少踩坑吧。文章来源地址https://www.toymoban.com/news/detail-472083.html

如何获取 C#程序 内核态线程栈

到了这里,关于如何获取 C#程序 内核态线程栈的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C#获取当前程序所在路径的各种方法

    结果:X:xxxxxxxxx.exe(.exe文件所在的目录+.exe文件名) 结果:X:xxxxxxxxx.exe(.exe文件所在的目录+.exe文件名) 结果:X:xxxxxxxxx.exe(.exe文件所在的目录+.exe文件名) 结果:X:xxxxxx(.exe文件所在的目录) 结果:X:xxxxxx(.exe文件所在的目录) 结果:X:xxxxxx(.exe文件所在的

    2024年02月11日
    浏览(49)
  • C# 微信小程序获取群id

    有个需求,需要限制小程序的抽奖只能在某个群内,需要知道谁在群里面,但是微信并没有提供谁在群里面的方法,不过提供了获取群id的方法,这样加上限制分享就能保证群里的参加,即时分享出去了,判断来源的时候也不是来自于群了,就不允许用户参与。 wx.login wx.get

    2024年01月16日
    浏览(40)
  • C#如何获取当前主机的IP地址

    Dns 类提供了一组用于域名系统 (DNS) 操作的静态方法。 我们可以使用Dns.GetHostName()方法来获取本地计算机的主机名, 这是一个静态方法。该方法调用操作系统的网络栈,以获取计算机的主机名。主机名是一个用来标识网络上的设备的名称。在网络中,每个设备都有一个唯一的

    2024年02月12日
    浏览(38)
  • C#自定义异常就这么简单

    C#是一种强类型语言,可以捕获和处理各种异常,从而帮助我们发现程序中出现的错误。在程序开发过程中,如果需要找到特定的错误情况并处理,这时就需要创建自定义异常。本文将介绍如何在C#中创建和使用自定义异常。 1、什么是异常? 异常是指在程序执行期间发生的错

    2024年02月03日
    浏览(48)
  • C#如何获取当前主机的局域网IP

    Dns 类提供了一组用于域名系统 (DNS) 操作的静态方法。 我们可以使用Dns.GetHostName()方法来获取本地计算机的主机名, 这是一个静态方法。该方法调用操作系统的网络栈,以获取计算机的主机名。主机名是一个用来标识网络上的设备的名称。在网络中,每个设备都有一个唯一的

    2024年02月06日
    浏览(44)
  • 微信小程序~如何设置页面的背景色

    众所周知,微信小程序每个页面由.json,.scss,.ts,.wxml这四个文件组成。 有的小伙伴会发现,需要给页面加背景色的时候,只需在此页面的.scss文件中写个page{background-color: #f8f8f8;}就能生效,却不知其所以然。 这是因为 微信小程序的每个页面,都有一个page根标签 ,见“调试

    2024年04月10日
    浏览(50)
  • 【Linux C】Linux如何执行一个程序(程序存储空间、系统调用、内核调用)

    本节说的空间主要是指内存空间,即程序如何分配和使用内存。 可执行程序,而不是源代码。 C语言程序的存储空间包括以下几个主要部分: 代码段(Text Segment): 也称 正文段 , 代码段是存储C程序的机器代码的区域。它包含了程序的指令集,这些指令由编译器生成,并且

    2024年02月08日
    浏览(49)
  • 微信小程序 背景图片如何占满整个屏幕

    1. 在页面的wxss文件中,设置背景图片的样式: 2. 在页面的json文件中,设置背景图片的样式:

    2024年02月14日
    浏览(98)
  • Spark重温笔记(三):Spark在企业中为什么能这么强?——持久化、Checkpoint机制、共享变量与内核调度原理全攻略“

    前言:今天是温习 Spark 的第 3 天啦!主要梳理了 Spark 核心数据结构:RDD(弹性分布式数据集),包括RDD持久化,checkpoint机制,spark两种共享变量以及spark内核调度原理,希望对大家有帮助! Tips:\\\"分享是快乐的源泉💧,在我的博客里,不仅有知识的海洋🌊,还有满满的正能量

    2024年04月09日
    浏览(46)
  • 如何在小程序中设置导航栏文字颜色和背景颜色

    不同商家有不同的颜色风格,例如有些做设计的公司,主要是黑色风格;有些卖珠宝的商家,主要是金色风格;他们的小程序,也需要进行同样的风格设定。下面具体介绍怎么在小程序中进行整个风格设定。 1. 在小程序管理员后台-基本设置页面,可以看到导航栏文字颜色和

    2024年02月04日
    浏览(99)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包