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

news2024/12/25 23:47:19

一:背景

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,总有一些千奇百怪的问题,太难了,这里总结一下给后来人少踩坑吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/612814.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

线程同步(一)

上篇文章讲述了什么是线程&#xff0c;以及在Linux系统下线程的相关操作 线程&#xff08;Linux系统实现&#xff09;_小梁今天敲代码了吗的博客-CSDN博客 本文将继续讲述线程的相关知识——线程同步 目录 1.线程同步的概念 2.线程不同步可能会发生什么 3.线程同步方式 …

机器学习——聚类算法详解

1.聚类问题 1&#xff09;聚类问题与核心概念 聚类算法做的事情&#xff0c;就是对无标签的数据&#xff0c;基于数据分布进行分群分组&#xff0c;使得相似的数据尽量落在同一个簇内。 我们先对比区分一下聚类和分类&#xff1a; 聚类是一种无监督学习&#xff0c;而分类是…

第十三届蓝桥杯C++B组j国赛

第十三届蓝桥杯C组 题目 2693: 蓝桥杯2022年第十三届决赛真题-卡牌 题目描述 这天&#xff0c;小明在整理他的卡牌。 他一共有 n 种卡牌&#xff0c;第 i 种卡牌上印有正整数数 i(i ∈ [1, n])&#xff0c;且第 i 种卡牌 现有 ai 张。 而如果有 n 张卡牌&#xff0c;其中…

硬件测试—温升测试之JinKo 多路温度测试仪使用说明

一、概述 1.1&#xff1a;测试概述 在硬件测试中&#xff0c;温升测试也是很重要的一项测试&#xff0c;产品各项器件在稳定的环境温度下满载工作的芯片温度&#xff0c;根据测试情况评估散热需求。 1.2&#xff1a;产品图片 1.3&#xff1a;使用设备 名称 厂家 型号 PC电脑…

Acer Aspire V3-572G电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件配置 硬件型号驱动情况 主板Acer Aspire V3-572G 处理器i7 5500U 2 Cores/4 Threads2,4Ghz已驱动 内存Any Samsung, Hynix or Kingston DDR3 8GB(4GBx2).已驱动 硬…

CSDN 每日一练用例数据缺失了怎么办?

CSDN 每日一练用例数据缺失了怎么办&#xff1f; 引子1、用例与结果不匹配2、阅读理解困难3、用例数据缺失 用例数据缺失&#xff0c;却有人 AC &#xff1f;神奇的 c28761 津津的储蓄计划70093 近视的小张 小结最后的吐槽 引子 老顾最近几个月经常在 CSDN 举办的周赛上浑水摸…

Tomcat 部署

一.Tomcat介绍 Servlet 是 Java Servlet 的简称&#xff0c;可以理解为是一个服务连接器&#xff0c;是用 Java 编写的服务器端程序&#xff0c;具有独立于平台和协议的特性&#xff0c; 简单的理解&#xff1a;servlet 就是一个中间件&#xff0c;包含了接口和方法&#xff0…

5.2.6 地址解析协议ARP

5.2.6 地址解析协议ARP 我们知道要想实现全球范围内主机之间的通信&#xff0c;必须要有两个统一&#xff0c;一个是地址&#xff0c;另一个是数据格式&#xff0c;我们使用IP地址来实现统一的地址&#xff0c;使用IP分组实现统一的数据格式&#xff0c;在前面局域网的学习中我…

【AIGC】13、GLIP | 首次将 object detection 重建为 phrase grounding 任务

文章目录 一、背景二、方法2.1 将 object detection 和 phrase grounding 进行统一2.2 Language-aware deep fusion2.3 使用语义丰富的数据来进行预训练 三、效果3.1 迁移到现有 Benchmarks3.2 在 COCO 上进行零样本和有监督的迁移3.3 在 LVIS 上进行零样本迁移学习3.4 在 Flic…

android 如何分析应用的内存(四)

android 如何分析应用的内存&#xff08;四&#xff09; 接上文 在介绍细节部分时&#xff0c;先介绍了各种工具的使用&#xff0c;而这些工具&#xff0c;大部分都用来调试&#xff0c;诸如&#xff1a;特定内存点&#xff0c;堆栈&#xff0c;寄存器&#xff0c;变量值等的…

MySQL安装流程 及 8.0与5.7区别

一、MySQL版本介绍 1、MySQL 8.0 窗口函数&#xff1a;MySQL 8.0版本支持窗口函数&#xff0c;这是数据分析工作中非常常用的一类函数。窗口函数可以让用户在单个查询中跨多个行检索数据&#xff0c;并在查询结果中对数据执行计算。隐藏索引&#xff1a;在MySQL 8.0版本中&am…

C++STL详解 string【C++】

文章目录 函数模板函数模板的原理函数模板的实例化模板参数的匹配原则 类模板类模板的定义格式类模板的实例化 string 函数模板 函数模板的原理 template <typename T> //模板参数 ——类型 void Swap(T& x1, T& x2) {T tmp x1;x1 x2;x2 tmp; } int main()…

牛客网语法刷题篇(C语言) — 输出格式化

&#x1f929;本文作者&#xff1a;大家好&#xff0c;我是paperjie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 &#x1f970;内容专栏&#xff1a;这里是《C语言—语法篇》专栏&#xff0c;笔者用重金(时间和精力)打造&#xff0c;基础知识一网打尽&#xff0c;…

解析Linux中断子系统之中断映射

中断是当前计算机系统的基础功能&#xff0c;也是系统响应外设事件的必备桥梁。不同的架构对中断控制器有不同的设计理念&#xff0c;本文针对ARM公司提供的通用中断控制器&#xff08;GIC,Generic Interrupt Controller&#xff09;介绍在linux系统中的硬件中断号与软件中断号…

SpringBootWeb登录认证

1. 登录功能 1.1 需求 在登录界面中&#xff0c;我们可以输入用户的用户名以及密码&#xff0c;然后点击 “登录” 按钮就要请求服务器&#xff0c;服务端判断用户输入的用户名或者密码是否正确。如果正确&#xff0c;则返回成功结果&#xff0c;前端跳转至系统首页面。 1.2 …

简单聊一聊数据库驱动

数据库驱动通常是数据库厂家提供的&#xff0c;他们按照jdbc协议对自家数据库封装了一套可对外调用的API。在应用程序和数据库之间起到了桥接的作用。它是一个软件组件&#xff0c;提供了与特定数据库系统进行通信的接口和功能。 1. 数据库驱动的作用&#xff1a; 连接数据库&…

AAOS 音频动态路由

文章目录 基本概念车载音频配置文件外部的配置音频区的方式车载音频服务配置路由流程框架中获取可用输出设备配置例子测试方法相关问题 基本概念 Android 管理来自 Android 应用的声音&#xff0c;同时控制这些应用&#xff0c;并根据其声音类型将声音路由到 HAL 中的输出设备…

FastAPi上传文件报错,There was an error parsing the body

问题描述 通过postman调用fastapi编写的文件接口报错&#xff0c;如下图&#xff1a; {"detail": "There was an error parsing the body" } 问题的解决过程 postman本身的问题 postman有个work directory的概念&#xff0c;所以再使用postman上传的文…

Git常用命令submodule

Git常用命令submodule 1、需求 当程序比较大参与开发人员较多时&#xff0c;代码管理就复杂起来。代码如果全员可见&#xff0c;可以创建 share 分支维护共用代 码&#xff0c;可以创建 core 分支维护核心算法代码&#xff0c;各进程分别占一个分支&#xff0c;定期同步 sha…

如何从 OpenAI 迁移到 Azure OpenAI(保姆级教程,包含如何兼容 JS 语言版 LangChain)

Azure OpenAI 和 OpenAI 一样&#xff0c;本质都是调用 api&#xff0c;Azure OpenAI 的使用会稍微复杂一点&#xff0c;但好处就是方便付费。 创建 Azure OpenAI 资源 首先&#xff0c;先登录 Azure 账号&#xff1a;https://azure.microsoft.com/zh-cn/ 接着创建 OpenAI 资…