返回顶部
首页 > 资讯 > 精选 >C#怎么实现windbg的时间旅行
  • 411
分享到

C#怎么实现windbg的时间旅行

2023-06-30 18:06:59 411人浏览 独家记忆
摘要

本篇内容主要讲解“C#怎么实现windbg的时间旅行”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#怎么实现windbg的时间旅行”吧!一:什么是时间旅行简而言之就是把程序的执行流拍成vlog

本篇内容主要讲解“C#怎么实现windbg的时间旅行”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#怎么实现windbg的时间旅行”吧!

一:什么是时间旅行

简而言之就是把程序的执行流拍成vlog,这样就可以对 vlog 快进或者倒退,还可以分享给别人做进一步的分析,是不是想都不敢想。

很开心的是 windbg preview 版本中已经实现了,叫做 时间旅行调试 TTD,相比传统的 静态分析 不知道好多少倍。

C#怎么实现windbg的时间旅行

为了能提起大家兴趣,我就举二个例子吧。

二:二个有趣的例子

1. 查看程序都触发了第几代垃圾回收

为了方便说明,我就用诱导GC手工触发,然后再观察都触发了哪一代的 GC ,参考代码如下:

        static void Main(string[] args)        {            List<string> list = new List<string>();            //1. 第一次触发GC            GC.Collect();            Console.WriteLine("触发full gc");            //2. 第二次触发GC            GC.Collect(0);            Console.WriteLine("触发 0 代 gc");            //3.第二次触发GC            GC.Collect(1);            Console.WriteLine("触发 1 代 gc");        }

接下来用 windbg 的 launch executeable (advanced) 来附加程序,勾选 Record,然后在弹框中将 vlog 保存到指定目录,最后点击 Record 就可以啦!

C#怎么实现windbg的时间旅行

运行完后,windbg 会自动加载我的 D:\test\ConsoleApp104.run 的 vlog 文件,因为 gc 触发的底层函数是coreclr!WKS::GCHeap::GarbageCollectGeneration ,所以我们用 bp给它下一个断点,运行多次 g 命令。

0:000> bp coreclr!WKS::GCHeap::GarbageCollectGenerationBp expression 'coreclr!WKS::GCHeap::GarbageCollectGeneration' could not be resolved, adding deferred bp0:000> gTime Travel Position: 3079F:63Eeax=00000001 ebx=00000002 ecx=00000002 edx=00000008 esi=00000002 edi=00000002eip=02fc4256 esp=0057f204 ebp=0057f214 iopl=0         nv up ei pl nz na po nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202coreclr!WKS::GCHeap::GarbageCollectGeneration:02fc4256 55              push    ebp0:000> gTime Travel Position: 34661:AFeax=00000001 ebx=00000002 ecx=00000000 edx=00000008 esi=00000000 edi=00000002eip=02fc4256 esp=0057f1f8 ebp=0057f208 iopl=0         nv up ei pl nz na po nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202coreclr!WKS::GCHeap::GarbageCollectGeneration:02fc4256 55              push    ebp0:000> gBreakpoint 0 hitTime Travel Position: 346A5:2CDeax=00000001 ebx=00000002 ecx=00000001 edx=00000008 esi=00000001 edi=00000002eip=02fc4256 esp=0057f1f8 ebp=0057f208 iopl=0         nv up ei pl nz na po nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202coreclr!WKS::GCHeap::GarbageCollectGeneration:02fc4256 55              push    ebp

从输出中可以很清楚的看到,命中了三次 GarbageCollectGeneration 回收,而且从上面的 ecx 寄存器看依次是 2,0,1,对应着 gc 的2代回收,0代回收, 1代回收, 这比只有一个静态的 dump 是不是有优势的多,要知道我这里的 ConsoleApp101.run 文件是可以分发给别人分析的哦。

2. 查看新生成的线程曾今都执行了什么代码

这个例子源自朋友遇到的一个问题,他的程序跑着跑着,发现 ThreadPool 中有400多待命的工作线程,线程栈大概如下:

0:011> k # ChildEBP RetAddr      00 0564fc6c 7531f0ca     ntdll!NtRemoveiocompletion+0xc01 0564fc6c 78480b69     KERNELBASE!GetQueuedCompletionStatus+0x2a02 0564fcb8 7847d92b     coreclr!CLRLifoSemaphore::WaitForSignal+0x29 [d:\a\_work\1\s\src\vm\synch.cpp @ 654] 03 0564fd08 7847cf04     coreclr!CLRLifoSemaphore::Wait+0x13b [d:\a\_work\1\s\src\vm\synch.cpp @ 897] 04 0564fdd4 783f2910     coreclr!ThreadpoolMgr::WorkerThreadStart+0x234 [d:\a\_work\1\s\src\vm\win32threadpool.cpp @ 2121] 05 0564ff70 7703fa29     coreclr!Thread::intermediateThreadProc+0x50 [d:\a\_work\1\s\src\vm\threads.cpp @ 2110] 06 0564ff80 772175f4     KERNEL32!BaseThreadInitThunk+0x1907 0564ffdc 772175c4     ntdll!__RtlUserThreadStart+0x2f08 0564ffec 00000000     ntdll!_RtlUserThreadStart+0x1b

因为给我的是 静态dump,所以我无法寻找 11号线程 曾今执行了什么托管代码,因为时间不能倒流,但现在有了 TTD,真的可以让时间倒流啦。。。太有意思了,哈哈,既然能倒流,那就一定有办法找到破绽。

为了方便讲解,写一个简单例子。

       static void Main(string[] args)        {            Task.Factory.StartNew(() =>            {                Console.WriteLine("我是 task 线程");            });            Console.ReadLine();        }

接下来我们一起探究下最后生成的 Thread WorkThread 曾今都执行了什么? 深挖思路大概是这样的。

先将进度条拉到底,然后用 !bpmd System_Private_CoreLib System.Threading.Tasks.Task.InnerInvoke 下一个断点,最后将时间倒流,看谁命中了这个 task。

0:000> gTTD: End of trace reached.(4f20.4d0c): Break instruction exception - code 80000003 (first/second chance not available)Time Travel Position: 36F51:0eax=00070053 ebx=00000000 ecx=8a60f857 edx=77237170 esi=7845e6c0 edi=00000000eip=771a7000 esp=0602fe90 ebp=0602ff70 iopl=0         nv up ei pl zr na pe nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246771a7000 ea09701a773300  jmp     0033:771A70090:009> !bpmd System_Private_CoreLib System.Threading.Tasks.Task.InnerInvokeMethodDesc = 06A29704Setting breakpoint: bp 05A915C7 [System.Threading.Tasks.Task.InnerInvoke()]Adding pending breakpoints...0:009> g-Breakpoint 1 hitTime Travel Position: 32DF4:ACeax=05a915c0 ebx=00000000 ecx=0349a864 edx=0349a864 esi=0349a864 edi=0349a7c8eip=05a915c7 esp=066afa14 ebp=066afa1c iopl=0         nv up ei pl zr na pe nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246System_Private_CoreLib!System.Threading.Tasks.Task.InnerInvoke()$##6002185+0x7:05a915c7 8b7e04          mov     edi,dWord ptr [esi+4] ds:002b:0349a868=0349a8000:008> !clrstack OS Thread Id: 0x44a8 (8)Child SP       IP Call Site066AFA14 05a915c7 System.Threading.Tasks.Task.InnerInvoke() [/_/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @ 2437]066AFA24 05a915bb System.Threading.Tasks.Task+c.<.cctor>b__274_0(System.Object) [/_/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @ 2427]066AFA2C 05a91567 System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) [/_/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs @ 289]066AFA5C 05a912d1 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread) [/_/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @ 2389]066AFABC 05a911d7 066AFACC 05a9118b System.Threading.Tasks.Task.ExecuteFromThreadPool(System.Threading.Thread) [/_/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @ 2312]066AFAD0 05a90e58 System.Threading.ThreadPoolWorkQueue.Dispatch() [/_/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs @ 663]066AFB1C 05a90c6f 066AFD10 784fa0ef [DebuggerU2MCatchHandlerFrame: 066afd10]

熟悉 Task 的朋友应该知道: System.Threading.Tasks.Task.InnerInvoke 的下一步就是执行我的回调函数,而此时 回调函数 还没有被 JIT 编译,这时候我们可以在 bp clrjit!CILJit::compileMethod 中去拦截 JIT 对此方法的编译,然后从 compileMethod 中提取 mt。

0:008> bp clrjit!CILJit::compileMethod0:008> gBreakpoint 1 hitTime Travel Position: 32E36:C18eax=7933ad50 ebx=066af5c8 ecx=792c8770 edx=066af5c8 esi=7932d164 edi=00cbbf90eip=792c8770 esp=066af3ec ebp=066af44c iopl=0         nv up ei pl zr na pe nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246clrjit!CILJit::compileMethod:792c8770 55              push    ebp0:008> kb # ChildEBP RetAddr      Args to Child              00 066af44c 78428db2     7933ad50 066af5c8 066af4f0 clrjit!CILJit::compileMethod [d:\a\_work\1\s\src\jit\ee_il_dll.cpp @ 294] ...0:008> dp 066af4f0 L1066af4f0  06a2ae040:008> !dumpmd 06a2ae04Method Name:          ConsoleApp1.dll!UnknownClass:                032fa0dcMethodTable:          06a2ae14mdToken:              06000005Module:               02c5d7d0IsJitted:             noCurrent CodeAddr:     ffffffffVersion History:  ILCodeVersion:      00000000  ReJIT ID:           0  IL Addr:            00000000     CodeAddr:           00000000  (MinOptJitted)     NativeCodeVersion:  00000000

很奇怪的是提取的 md 目前还不能显示完全名字,不过没关系,我们继续 g ,然后再重复执行一下命令。

0:009> gTTD: End of trace reached.(4f20.4d0c): Break instruction exception - code 80000003 (first/second chance not available)Time Travel Position: 36F51:0eax=00070053 ebx=00000000 ecx=8a60f857 edx=77237170 esi=7845e6c0 edi=00000000eip=771a7000 esp=0602fe90 ebp=0602ff70 iopl=0         nv up ei pl zr na pe nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246771a7000 ea09701a773300  jmp     0033:771A70090:009> !dumpmd 06a2ae04Method Name:          ConsoleApp1.Program+<>c.<Main>b__0_0()Class:                032fa0dcMethodTable:          06a2ae14mdToken:              06000005Module:               02c5d7d0IsJitted:             yesCurrent CodeAddr:     06133300Version History:  ILCodeVersion:      00000000  ReJIT ID:           0  IL Addr:            00000000     CodeAddr:           06133300  (MinOptJitted)     NativeCodeVersion:  00000000

当时间线结束的时候,我们终于看到了,原来 Task 执行的是 ConsoleApp1.Program+<>c.<Main>b__0_0() 方法,那这个方法逻辑是什么呢? 可以用 ILSpy 查看。

C#怎么实现windbg的时间旅行

总的来说,要复现还是挺考验基本功的。

到此,相信大家对“C#怎么实现windbg的时间旅行”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: C#怎么实现windbg的时间旅行

本文链接: https://lsjlt.com/news/330744.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C#怎么实现windbg的时间旅行
    本篇内容主要讲解“C#怎么实现windbg的时间旅行”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#怎么实现windbg的时间旅行”吧!一:什么是时间旅行简而言之就是把程序的执行流拍成vlog...
    99+
    2023-06-30
  • C#程序终极调试实现windbg的时间旅行
    目录一:什么是时间旅行二:二个有趣的例子1. 查看程序都触发了第几代垃圾回收2. 查看新生成的线程曾今都执行了什么代码一:什么是时间旅行 简而言之就是把程序的执行流拍成vlog,这样...
    99+
    2024-04-02
  • 时间旅行的艺术:用 PHP DateTime 扩展穿越时间
    PHP DateTime 扩展是一个用于处理日期和时间数据的扩展,它提供了丰富的功能,可以帮助开发者轻松地处理日期和时间相关的数据。该扩展还提供了时间旅行功能,允许开发者穿越到过去或未来并进行操作。 要使用 PHP DateTime 扩...
    99+
    2024-02-21
    PHP DateTime 时间旅行 日期 时间
  • mongodb怎么实现时间排行榜
    要实现时间排行榜,可以使用MongoDB的聚合管道和索引来完成。首先,你需要在文档中加入一个时间字段,例如`created_at`,...
    99+
    2023-09-01
    mongodb
  • 怎么用Python实现环球旅行
    这篇文章主要讲解了“怎么用Python实现环球旅行”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么用Python实现环球旅行”吧!1、.准备工作在开始编写脚本之前,需要做如下准备工作:一部...
    99+
    2023-06-16
  • C#怎么实现常见时间格式
    这篇文章主要介绍“C#怎么实现常见时间格式”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C#怎么实现常见时间格式”文章能帮助大家解决问题。 代码如下:string aa ...
    99+
    2023-06-30
  • C++ 函数如何实现最优执行时间?
    c++++ 函数最优执行时间优化的技巧:避免拷贝操作。使用内联函数。使用快速算法。优化数据结构。优化内存使用。 C++ 函数如何实现最优执行时间 优化函数执行时间是提高代码效率的关键。...
    99+
    2024-04-22
    c++ 算法设计
  • C#实现时间戳与标准时间的互转
    目录前言1.标准时间转时间戳的方法2.时间戳转为标准时间3.TimeZone.CurrentTimeZone.ToLocalTime()方法补充前言 C# 时间戳与 标准时间的转其实...
    99+
    2024-04-02
  • PHP DateTime 扩展的时间旅行者:穿越过去和未来的时间线
    要将 PHP DateTime 对象设置到过去,可以使用 modify() 方法。此方法接受一个字符串参数,指定要应用的修改。例如,要将日期对象回溯 10 天,可以使用以下代码: $date = new DateTime(); $date...
    99+
    2024-04-02
  • c#时间转字符串格式怎么实现
    在C#中,可以使用DateTime类的ToString方法来将时间转换为特定的字符串格式。以下是一些常见的时间转换示例: 将时间转...
    99+
    2024-03-02
    c#
  • java怎么实现时间时钟
    Java中可以使用`java.util.Date`类和`java.text.SimpleDateFormat`类来实现时间时钟。首先...
    99+
    2023-08-29
    java
  • 怎么实现在运行时生成C#的.NET类
    这篇文章主要介绍“怎么实现在运行时生成C#的.NET类”,在日常操作中,相信很多人在怎么实现在运行时生成C#的.NET类问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么实现在运行时生成C#的.NET类”的疑...
    99+
    2023-06-03
  • C++实现统计代码运行时间的示例详解
    目录纯标准库实现类似C#的实现总结本来想自己写的,一看github上面都有就不再重复造轮子了。github上的项目如下: StopWatch 纯标准库实现:使用std::chrono...
    99+
    2023-05-19
    C++统计代码运行时间 C++ 代码运行时间 C++统计时间
  • Java怎么实现生活旅行分享平台
    这篇“Java怎么实现生活旅行分享平台”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java怎么实现生活旅行分享平台”文章吧...
    99+
    2023-06-29
  • C语言怎么设置程序的运行时间
    在C语言中,可以使用time.h头文件中的clock()函数来获取程序的运行时间。clock()函数返回从程序启动起算的时钟周期数,...
    99+
    2023-08-31
    C语言
  • mysql毫秒时间戳转时间怎么实现
    在MySQL中,可以使用FROM_UNIXTIME()函数将毫秒时间戳转换为时间。需要注意的是,FROM_UNIXTIME()函数接...
    99+
    2024-05-14
    mysql
  • php怎么实现时间差
    php实现时间差的方法:1、通过strtotime函数将两个日期转换为时间戳;2、通过“$enddate-$startdate”公式将两个时间戳相减;3、将时间差“$diff_seconds”除以86400,并使用“floor()”函数向下...
    99+
    2023-05-14
    php
  • C#实现常见时间格式
    有时候我们要对时间进行格式化,达到不同的显示效果,本文为大家整理了C#中一些常见时间格式的实现方法。 string aa = DateTime.Now.ToShortDateStri...
    99+
    2024-04-02
  • Linux C/C++ timeout命令实现运行具有时间限制功能
    目录Linux C/C++ timeout命令实现运行具有时间限制如何使用timeout命令如何使用timeout命令的基本示例1.设置定时间后终止命令:2.发送正确的信号3.尝试使...
    99+
    2023-02-14
    Linux运行具有时间限制 C++ timeout命令
  • Unix时间和时间戳的命令行怎么写
    这篇文章主要介绍“Unix时间和时间戳的命令行怎么写”,在日常操作中,相信很多人在Unix时间和时间戳的命令行怎么写问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Unix时间和时间戳的命令行怎么写”的疑惑有所...
    99+
    2023-07-04
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作