当前位置: 代码网 > it编程>编程语言>Asp.net > Net 高级调试之四:Windbg 动态调试

Net 高级调试之四:Windbg 动态调试

2024年05月16日 Asp.net 我要评论
一、简介 今天是《Net 高级调试》的第四篇文章。到今天为止,也有三篇文章了,对 Windbg 也有初步的认识了,当然,一个工具流畅、熟练的使用,对于我们调试 Net 程序是至关重要的。在前几篇文章的基础上,我们这篇文章主要介绍一些和使用 Windbg 有关的命令和操作。就我个人而言,第一次接触这个 ...
一、简介
    
今天是《net 高级调试》的第四篇文章。到今天为止,也有三篇文章了,对 windbg 也有初步的认识了,当然,一个工具流畅、熟练的使用,对于我们调试 net 程序是至关重要的。在前几篇文章的基础上,我们这篇文章主要介绍一些和使用 windbg 有关的命令和操作。就我个人而言,第一次接触这个东西,还是挺难的,以前从来没有用过 windbg,用的最多的就是 visual studio 的调试功能。不怕大家笑话,如何通过 windbg 加载一个 exe,我都不知道,更不要谈加载 dump 文件。我看第一遍视频的时候,也不知道说了个啥,命令的执行,调试的开始,都感觉是一头雾水,似懂非懂,自己一实操,总是得不到别人调试那样的结果,很是郁闷。怎么办呢?没办法,要想学会,除了努力那就是坚持。针对视频,放慢速度,一帧一帧的按着视频的操作,自己来一遍,速度虽然慢,但是有些操作开始有了感觉了,当整个视频系列看了一遍,所有操作都操作一遍,终于有些头绪了。还是那句老话,一遍不行,那就再来一遍,还不行,那就再来一遍,俗话说的好,书读千遍,其意自现,我这是第三遍。
     如果在没有说明的情况下,所有代码的测试环境都是 net framewok 4.8,但是,有时候为了查看源码,可能需要使用 net core 的项目,我会在项目章节里进行说明。好了,废话不多说,开始我们今天的调试工作。
    调试环境我需要进行说明,以防大家不清楚,具体情况我已经罗列出来。
          操作系统:windows professional 10
          调试工具:windbg preview(可以去microsoft store 去下载)
          开发工具:visual studio 2022
          net 版本:net framework 4.8
          coreclr源码:源码下载
二、相关知识
    
1、windbg 动态调试
          1.1、调试概况
              在任何一种调试中都有两个组件:调试器本身,调试目标。
              当调试器【windbg】附加进程【attach to process】时,调试器会给 目标程序 注入一个远程线程并用 int 3 中断程序,后续和 net 程序中的 debuggerrcthread 线程交互执行命令。int 3 指令之所以可以让进程中断,主要是来自于 cpu 硬件中断,当调试器发出了一个 int 3 的中断请求,cpu会到内核态执行3号例程,也就是执行【中断向量表】,内核执行中断的操作。
              actor------------》调试器(windbg)《------------》调试目标(net 程序,c++程序...)
              以上图例就是一个调试器的作用和所处的地位。

     2、程序的中断和恢复执行
          2.1、中断执行(让程序中断有4中方式)
              a、使用windbg 启动程序,在进程初始化函数中,如果发现有调试器附加在上面,就会执行 break 中断。 
                  说明一下:windbg 调试器刚开始的中断就是 int 3 中断,但是这个中断的时机很早,我们可以做一些初始化的工作,比如:加载sos.dll 等类似的工作。                
              b、附加进程,调试器会注入远程线程执行 int 3 中断程序。
                  这个挺简单的,我们双击程序,直接运行。然后通过 windbg 的【attach to process】附加进程,就可以进入调试器界面,这个时候,其实什么也不用做,调试器已经暂停了,这个暂停就是 int 3 中断。我们通过 windbg 的【break】命令也是 int 3 中断。当然,我们通过 c# debugger.break() 代码执行的也是 int 3 的中断。
              c、使用 bp 命令给程序下断点。
                  我们可以通过【u】命令查看方法的汇编代码,找到想要设断点的代码的地址,直接通过这个地址来下断点,当程序再次运行的时候,就会在这个断点处暂停。                 
              d、异常中断。
                   异常中断的流程是:当你的程序发生异常,会从用户态转到内核态,内核态检测到你的程序附加了调试器,内核态就会把这个请求转交给调试器,调试器也就能中断了,可以调试了。
          2.2、恢复执行
              可以使用 g 命令回复程序的执行。

     3、单步调试代码
          当我们调试程序的时候,最多的时候是使用 visual studio 的 f10、f11、f5这样的命令,在 windbg 中也有类似的命令可以使用。
        
  3.1、p 命令
              p(step):命令其实就是vs 中的 f10 快捷键,单步执行,遇到函数也是当成一条指令执行,不会进入函数体。
              
          3.2、t 命令
              
t(trace):命令其实就是 vs 的 f11 快捷键,它是一种进入函数的单步执行调试。
              
          3.3、pc 命令
              pc(step to next call)    就是一直运行直到遇到 call 为止,不会进入函数体,call 是一个函数调用,汇编指令。
              
          3.4、tc 命令
           
tc(trace to next call)    和 pc 不同的是,tc 会进入方法体,直到遇到 call 为止。

          3.5、pt 命令
              pt(step to next return)    遇到下一个 ret 为止。   
              
          3.6、tt 命令
              tt(trace to next return)    会进入函数体直到遇到 ret 为止。递归的意思。
              
    4、退出测试会话
          结束调试会话,有两个目的,看是否保留程序的执行。
          4.1、q(quit):结束调试会话+调试程序退出
              调试会话结束,应用程序也会退出。
          4.2、qd(quit and detach):结束调试会话+调试程序继续运行
              调试会话结束,应用程序保持运行态,不会退出。

三、调试过程
    
废话不多说,这一节是具体的调试操作的过程,又可以说是眼见为实的过程,在开始之前,我还是要啰嗦两句,这一节分为两个部分,第一部分是测试的源码部分,没有代码,当然就谈不上测试了,调试必须有载体。第二部分就是根据具体的代码来证实我们学到的知识,是具体的眼见为实。
    1、测试源码
        
1.1、example_4_1_1
 1 namespace example_4_1_1
 2 {
 3     internal class program
 4     {
 5         static void main(string[] args)
 6         {
 7             for (int i = 0; i < int.maxvalue; i++)
 8             {
 9                 console.writeline($"i={i}");
10                 thread.sleep(1000);
11             }
12             console.readline();
13         }
14     }
15 }
        1.2、example_4_1_2
 1 namespace example_4_1_2
 2 {
 3     internal class program
 4     {
 5         static void main(string[] args)
 6         {
 7             debugger.break();
 8 
 9             int a = 10;
10             int b = 12;
11 
12             var sum = a + b;
13 
14             console.writeline($"sum={sum}");
15 
16             console.readline();
17         }
18     }
19 }
        1.3、example_4_1_3
 1 namespace example_4_1_3
 2 {
 3     internal class program
 4     {
 5         static void main(string[] args)
 6         {
 7             run();
 8 
 9             console.readline();
10         }
11 
12         static void run()
13         {
14             console.writeline("请输入一个除数:");
15             var num = console.readline();
16             var result = 10 / convert.toint32(num);
17         }
18     }
19 }
        1.4、example_4_1_4
 1 namespace example_4_1_4
 2 {
 3     internal class program
 4     {
 5         static void main(string[] args)
 6         {
 7             sum1(10);
 8             debugger.break();
 9 
10             int i = 10;
11             int j = 20;
12 
13             var sum = sum1(i);
14             console.writeline($"sum={sum}");
15 
16             console.readline();
17         }
18 
19         private static int sum1(int a)
20         {
21             var i = a;
22             var j = 11;
23             int sum = sum2(i, j);
24 
25             return sum;
26         }
27 
28         private static int sum2(int a, int b)
29         {
30             var i = a;
31             var j = b;
32             var k = 13;
33 
34             var sum = sum3(i, j, k);
35             return sum;
36         }
37 
38         private static int sum3(int i, int j, int k)
39         {
40             return i + j + k;
41         }
42     }
43 }

    2、眼见为实
          2.1、windbg【attach to process】附加进程,通过 int 3 命令中断程序。
              测试代码:example_4_1_1
            程序很简单,直接运行 exe 程序,打开 windbg,点击菜单【attach to process】进入调试器界面。其实什么操作都不用做,我们就可以看到调试器的输出结果。特别强调,红色标注的就是 int 3中断。
1 modload: 6fa30000 6faba000   c:\windows\microsoft.net\framework\v4.0.30319\clrjit.dll
2 modload: 75f50000 75feb000   c:\windows\system32\oleaut32.dll
3 (5384.3250): break instruction exception - code 80000003 (first chance)
4 eax=00270000 ebx=00000000 ecx=7790cee0 edx=7790cee0 esi=7790cee0 edi=7790cee0
5 eip=778d3410 esp=04c2f92c ebp=04c2f958 iopl=0         nv up ei pl zr na pe nc
6 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
7 ntdll!dbgbreakpoint:
8 778d3410 cc              int     3

              当然,我们也可以通过【g】命令,继续运行程序,然后点击工具栏的【break】按钮,程序就进入中断,这里的结果和上面是一样的。

1 0:006> g
2 (5384.528c): break instruction exception - code 80000003 (first chance)
3 eax=00279000 ebx=00000000 ecx=7790cee0 edx=7790cee0 esi=7790cee0 edi=7790cee0
4 eip=778d3410 esp=04eaf960 ebp=04eaf98c iopl=0         nv up ei pl zr na pe nc
5 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
6 ntdll!dbgbreakpoint:
7 778d3410 cc              int     3

              当然,也可以通过【u】命令,查看 ntdll!dbgbreakpoint的汇编代码。          

1 0:008> u ntdll!dbgbreakpoint
2 ntdll!dbgbreakpoint:
3 778d3410 cc              int     3
4 778d3411 c3              ret(方法返回)

              我们也可以查看【disassembly】视图,截图如下:
              


            解释内核态:涉及到内核态的执行,我们也可以通过windbg 查看,重新在打开一个 windbg,点击【文件】----》【attach kernel】,选择【local】项,点击【ok】按钮,进入调试器界面。然后,我们可以输入【!idt】命令来查看。
 1 lkd> !idt
 2 
 3 dumping idt: fffff80069a91000
 4 
 5 00:    fffff80064b93100 nt!kidivideerrorfaultshadow
 6 01:    fffff80064b93180 nt!kidebugtraporfaultshadow    stack = 0xfffff80069a959d0
 7 02:    fffff80064b93240 nt!kinmiinterruptshadow    stack = 0xfffff80069a957d0
 8 03:    fffff80064b932c0 nt!kibreakpointtrapshadow
 9 04:    fffff80064b93340 nt!kioverflowtrapshadow
10 ..................

              红色标注的就是在内核态的中断函数,我们可以使用【u】命令,查看他的汇编代码。

 1 lkd> u nt!kibreakpointtrapshadow
 2 nt!kibreakpointtrapshadow:
 3 fffff800`64b932c0 f644240801      test    byte ptr [rsp+8],1
 4 fffff800`64b932c5 7467            je      nt!kibreakpointtrapshadow+0x6e (fffff800`64b9332e)
 5 fffff800`64b932c7 0f01f8          swapgs
 6 fffff800`64b932ca 0faee8          lfence
 7 fffff800`64b932cd 650fba24251890000001 bt  dword ptr gs:[9018h],1
 8 fffff800`64b932d7 720c            jb      nt!kibreakpointtrapshadow+0x25 (fffff800`64b932e5)
 9 fffff800`64b932d9 65488b242500900000 mov   rsp,qword ptr gs:[9000h]
10 fffff800`64b932e2 0f22dc          mov     cr3,rsp
            解释:,我们可以通过【~* k】命令,打印出所有线程栈,......表示省略,内容太多,没必要,显示重要的就可以了。
              
 1 0:008> ~*k
 2 
 3    0  id: 5384.4128 suspend: 1 teb: 0025e000 unfrozen
 4  # childebp retaddr      
 5 00 0057ee00 75942d3b     ntdll!ntdelayexecution+0xc
 6 ......
 7 
 8    1  id: 5384.22a4 suspend: 1 teb: 00261000 unfrozen
 9  # childebp retaddr      
10 00 0088fab8 778b0f30     ntdll!ntwaitforworkviaworkerfactory+0xc
11 ......
12 
13    2  id: 5384.3034 suspend: 1 teb: 00264000 unfrozen
14  # childebp retaddr      
15 00 00affb9c 778b0f30     ntdll!ntwaitforworkviaworkerfactory+0xc
16 .......
17 
18    3  id: 5384.35fc suspend: 1 teb: 00267000 unfrozen
19  # childebp retaddr      
20 00 00bff9f0 778b0f30     ntdll!ntwaitforworkviaworkerfactory+0xc
21 ......
22 
23    4  id: 5384.3c50 suspend: 1 teb: 0026a000 unfrozen
24  # childebp retaddr      
25 00 0258f804 75939623     ntdll!ntwaitformultipleobjects+0xc
26 01 0258f804 711567d7     kernelbase!waitformultipleobjectsex+0x103
27 02 0258f86c 711566ff     clr!debuggerrcthread::mainloop+0x99
28 03 0258f898 71156620     clr!debuggerrcthread::threadproc+0xd0
29 04 0258f8c4 7711f989     clr!debuggerrcthread::threadprocstatic+0xa3
30 05 0258f8d4 778c7084     kernel32!basethreadinitthunk+0x19
31 06 0258f930 778c7054     ntdll!__rtluserthreadstart+0x2f
32 07 0258f940 00000000     ntdll!_rtluserthreadstart+0x1b
33 
34    5  id: 5384.2050 suspend: 1 teb: 0026d000 unfrozen
35  # childebp retaddr      
36 00 0475fabc 75939623     ntdll!ntwaitformultipleobjects+0xc
37 ......
38 
39    6  id: 5384.2ce0 suspend: 1 teb: 00276000 unfrozen
40  # childebp retaddr      
41 00 04c2f84c 778b0f30     ntdll!ntwaitforworkviaworkerfactory+0xc
42 ......
43 
44    7  id: 5384.489c suspend: 1 teb: 00273000 unfrozen
45  # childebp retaddr      
46 ......
47 04 04d6ffb0 00000000     ntdll!_rtluserthreadstart+0x1b
48 
49 #  8  id: 5384.528c suspend: 1 teb: 00279000 unfrozen
50  # childebp retaddr      
51 00 04eaf98c 7790cf19     ntdll!dbgbreakpoint(int 3 中断)
52 01 04eaf98c 7711f989     ntdll!dbguiremotebreakin+0x39
53 02 04eaf99c 778c7084     kernel32!basethreadinitthunk+0x19
54 03 04eaf9f8 778c7054     ntdll!__rtluserthreadstart+0x2f
55 04 04eafa08 00000000     ntdll!_rtluserthreadstart+0x1b


          2.2、使用windbg 启动程序,在进程初始化函数中断进程。
              测试代码:example_4_1_2
            
我们编译项目,打开 windbg,点击【文件】----》【launch executable】附加程序,打开调试器的界面,程序已经处于中断状态。我们可以看到,如下输出:
 1 executable search path is: 
 2 modload: 00be0000 00be8000   example_4_1_2.exe
 3 modload: 77860000 77a02000   ntdll.dll
 4 modload: 717e0000 71832000   c:\windows\syswow64\mscoree.dll
 5 modload: 77100000 771f0000   c:\windows\syswow64\kernel32.dll
 6 modload: 75820000 75a33000   c:\windows\syswow64\kernelbase.dll
 7 modload: 5efe0000 5f07f000   c:\windows\syswow64\apphelp.dll
 8 (300c.20b8): break instruction exception - code 80000003 (first chance)
 9 eax=00000000 ebx=00000000 ecx=534d0000 edx=00000000 esi=77871f64 edi=7787252c
10 eip=77910de2 esp=00f7f824 ebp=00f7f850 iopl=0         nv up ei pl zr na pe nc
11 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
12 ntdll!ldrpdodebuggerbreak+0x2b:
13 77910de2 cc              int     3

              红色部分需要注意,然后我们使用【u】命令查看它的汇编代码。

 1 0:000> u ntdll!ldrpdodebuggerbreak+0x2b
 2 ntdll!ldrpdodebuggerbreak+0x2b:
 3 77910de2 cc              int     3
 4 77910de3 eb07            jmp     ntdll!ldrpdodebuggerbreak+0x35 (77910dec)
 5 77910de5 33c0            xor     eax,eax
 6 77910de7 40              inc     eax
 7 77910de8 c3              ret
 8 77910de9 8b65e8          mov     esp,dword ptr [ebp-18h]
 9 77910dec c745fcfeffffff  mov     dword ptr [ebp-4],0fffffffeh
10 77910df3 8b4df0          mov     ecx,dword ptr [ebp-10h]

              我们可以使用【k】命令,继续查看。

1 0:000> k
2  # childebp retaddr      
3 00 00f7f850 7790b2f8     ntdll!ldrpdodebuggerbreak+0x2b(int 3 中断)
4 01 00f7fab0 778ba3d1     ntdll!ldrpinitializeprocess+0x1c98(进程初始化的时候执行的 break中断,)
5 02 00f7fb08 778ba2c1     ntdll!_ldrpinitialize+0xba
6 03 00f7fb14 00000000     ntdll!ldrinitializethunk+0x11

               ntdll是一个网关函数dll,如果想使用内核的功能几必须通过 ntdll 里面的函数。ntdll!ldrpdodebuggerbreak 这个中断是在进程初始化之前进行的,是很早的一个时机,加载的东西也不多,只有【example_4_1_2.exentdll.dllmscoree.dllkernel32.dll...】,之所以这样,可以让我们设置一些或者说配置一些初始化的东西,比如:加载 sos等。

            
        
2.3、使用 bp 命令给程序下断点,可以让程序中断。
            
测试代码:example_4_1_2
            比如,我们在【int a = 10;】这样代码下断点,行数:12.
            

               我们编译项目,打开 windbg,点击【文件】----》【launch executable】附加程序,打开调试器的界面,程序已经处于中断状态。我们使用【g】命令,继续运行,然后我们使用【!clrstack】命令,查看线程栈。

1 0:000> !clrstack
2 os thread id: 0x3c54 (0)
3 child sp       ip call site
4 00d5ed38 7597f262 [helpermethodframe: 00d5ed38] system.diagnostics.debugger.breakinternal()
5 00d5edb4 7064f195 system.diagnostics.debugger.break() [f:\dd\ndp\clr\src\bcl\system\diagnostics\debugger.cs @ 91]
6 00d5eddc 02ba0886 example_4_1_2.program.main(system.string[]) [e:\visual studio 2022\...\example_4_1_2\program.cs @ 10]
7 00d5ef78 70faf036 [gcframe: 00d5ef78] 

                红色标注的是 main 方法的地址,然后执行【!u 02ba0886】命令,查看他的汇编代码。

1 0:000> !u 02ba0886
2 normal jit generated code
3 example_4_1_2.program.main(system.string[])
4 begin 02ba0848, size a3
5 
6 ......
7 
8 e:\visual studio 2022\...\example_4_1_2\program.cs @ 12:(这个行号就是c# 代码的行号)
9 02ba0887 c745f00a000000  mov     dword ptr [ebp-10h],0ah

                我们找到了代码的位置,就可以下断点了,使用【bp】命令。

0:000> bp 02ba0887

                【g】继续运行,就会到断点出暂停。

              

                效果如图。


        
2.4、触发异常,也可以让程序中断。
            
测试代码:example_4_1_3
              代码很简单,我简单说一些流程,我们首先将要测试的项目编译好,然后打开 windbg,通过【launch executable】附加应用程序,调试器会响应一个 int 3中断,我们通过【g】命令,继续运行程序。程序提示输入一个数字,我输入0,肯定就会异常了。
           效果如图:
           

              异常中断的代码是:014b08ea f77df4         idiv    eax, dword ptr [ebp-0ch],效果如图:
              
              我们使用【dp】命令,查看【ebp-0ch】代码的值。

1 0:000> dp ebp-0ch l1
2 012ff2fc  00000000

              我们可以使用【dp】命令,也可以使用【?】命令,查看一下eax 是什么,其实 eax就是十进制的10。

1 0:000> ? eax
2 evaluate expression: 10 = 0000000a

              代码【idiv】就是表示除法触发的异常。
              我们也可以使用【k】命令,查看调用栈,也能看出在哪里中断。

1 0:000> k
2  # childebp retaddr      
3 00 012ff308 014b086b     example_4_1_3!com+_entry_point <perf> (example_4_1_3+0x6308ea) [e:\...\example_4_1_3\program.cs @ 18] 
4 01 012ff318 7077f036     example_4_1_3!com+_entry_point <perf> (example_4_1_3+0x63086b) [e:\...\example_4_1_3\program.cs @ 9] 
5 ......
6 0f 012ffde4 77057054     ntdll!__rtluserthreadstart+0x2f
7 10 012ffdf4 00000000     ntdll!_rtluserthreadstart+0x1b

              红色部分就是中断的 c# 代码的行号。


          2.5、单步调试命令测试。
              测试代码:example_4_1_4
              说明一下,这些测试命令,不需要每个命令建立一个独立的测试项目,所以我这里就使用了一个项目做测试。为了更明确,每个命令单独测试。但是编译项目,通过windbg 加载项目就不详述了。都是通过 windbg的【launch executable】附加应用程序的,进入到的调试器后,通过【g】命令继续运行,会在 c# 【debugger.break()】代码出中断,我们通过【!clrstack】线程栈,找到 program 的 main 方法的地址,然后在这个地址上通过【bp】命令下断点,剩下就可以自由调试了。
1 0:000> !clrstack
2 os thread id: 0x35ec (0)
3 child sp       ip call site
4 00aff270 76e8f262 [helpermethodframe: 00aff270] system.diagnostics.debugger.breakinternal()
5 00aff2ec 6fe1f195 system.diagnostics.debugger.break() [f:\dd\ndp\clr\src\bcl\system\diagnostics\debugger.cs @ 91]
6 00aff314 00cc0895 example_4_1_4.program.main(system.string[]) [e:\visual studio\...\example_4_1_4\program.cs @ 11]
7 00aff4b4 7077f036 [gcframe: 00aff4b4] 

              在红色标注的地址上设置断点。

0:000> bp 00cc0895

              【g】继续运行。

              

              开始调试了。

              p命令:                  
 1 0:000> p
 2 eax=00000022 ebx=00aff3e4 ecx=0000000a edx=00000000 esi=02ab24bc edi=00aff330
 3 eip=00cc08b3 esp=00aff314 ebp=00aff348 iopl=0         nv up ei pl nz ac pe nc
 4 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216
 5 example_4_1_4!com+_entry_point <perf> (example_4_1_4+0x6408b3):
 6 00cc08b3 8945e8          mov     dword ptr [ebp-18h],eax ss:002b:00aff330=00000000
 7 0:000> p
 8 eax=00000022 ebx=00aff3e4 ecx=0000000a edx=00000000 esi=02ab24bc edi=00aff330
 9 eip=00cc08b6 esp=00aff314 ebp=00aff348 iopl=0         nv up ei pl nz ac pe nc
10 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216
11 example_4_1_4!com+_entry_point <perf> (example_4_1_4+0x6408b6):
12 00cc08b6 b9a8422a6f      mov     ecx,offset mscorlib_ni!getobjectdata+0x102 (6f2a42a8)
13 0:000> p
14 eax=00000022 ebx=00aff3e4 ecx=6f2a42a8 edx=00000000 esi=02ab24bc edi=00aff330
15 eip=00cc08bb esp=00aff314 ebp=00aff348 iopl=0         nv up ei pl nz ac pe nc
16 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216
17 example_4_1_4!com+_entry_point <perf> (example_4_1_4+0x6408bb):
18 00cc08bb e83428faff      call    00c630f4

              t命令:
 1 0:000> t
 2 eax=00000000 ebx=0053ee2c ecx=0000000a edx=00779910 esi=025224bc edi=0053ed70
 3 eip=023808a7 esp=0053ed54 ebp=0053ed88 iopl=0         nv up ei pl zr na pe nc
 4 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
 5 example_4_1_4!com+_entry_point <perf> (example_4_1_4+0x21e08a7):
 6 023808a7 ff156c4d3302    call    dword ptr ds:[2334d6ch] ds:002b:02334d6c=02380918
 7 0:000> t
 8 eax=00000000 ebx=0053ee2c ecx=0000000a edx=00779910 esi=025224bc edi=0053ed70
 9 eip=02380918 esp=0053ed50 ebp=0053ed88 iopl=0         nv up ei pl zr na pe nc
10 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
11 example_4_1_4!com+_entry_point <perf> (example_4_1_4+0x21e0918):
12 02380918 55              push    ebp

                  效果如图:
                  

                  执行【t】命令后,效果如图:
                  


              pc命令:                  
1 0:000> pc
2 eax=00000000 ebx=00bfee64 ecx=0000000a edx=00f69910 esi=02f124bc edi=00bfedb0
3 eip=014108a7 esp=00bfed94 ebp=00bfedc8 iopl=0         nv up ei pl zr na pe nc
4 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
5 example_4_1_4!com+_entry_point <perf> (example_4_1_4+0x9b08a7):
6 014108a7 ff156c4d1301    call    dword ptr ds:[1134d6ch] ds:002b:01134d6c=01410918

                  效果如图:
                  

                  运行后的效果,如图:
                  


              tc命令:               
1 0:000> tc
2 eax=00000000 ebx=010fee04 ecx=0000000a edx=013998f0 esi=031424bc edi=010fed50
3 eip=02f708a7 esp=010fed34 ebp=010fed68 iopl=0         nv up ei pl zr na pe nc
4 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
5 example_4_1_4!com+_entry_point <perf> (example_4_1_4+0x22608a7):
6 02f708a7 ff156c4d5e01    call    dword ptr ds:[15e4d6ch] ds:002b:015e4d6c=02f70918

                  第一次执行【tc】命令,效果如图:
                  

1 0:000> tc
2 eax=0000000a ebx=010fee04 ecx=0000000a edx=0000000b esi=031424bc edi=010fed50
3 eip=02f7095c esp=010fed14 ebp=010fed2c iopl=0         nv up ei pl zr na pe nc
4 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
5 example_4_1_4!com+_entry_point <perf> (example_4_1_4+0x226095c):
6 02f7095c ff15784d5e01    call    dword ptr ds:[15e4d78h] ds:002b:015e4d78=02f70990

                  第二次执行【tc】命令,效果如图:
                  

1 0:000> tc
2 eax=0000000b ebx=010fee04 ecx=0000000a edx=0000000b esi=031424bc edi=010fed50
3 eip=02f709e5 esp=010fece8 ebp=010fed0c iopl=0         nv up ei pl zr na pe nc
4 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
5 example_4_1_4!com+_entry_point <perf> (example_4_1_4+0x22609e5):
6 02f709e5 ff15844d5e01    call    dword ptr ds:[15e4d84h] ds:002b:015e4d84=02f70a18

                  第三次执行【tc】命令,效果如图:
                  


              pt命令:
                  初始状态,如图:
                  

                  执行了【pt】命令,遇到【ret】就暂停,也就是回到29行。

1 0:000> pt
2 eax=00000022 ebx=010ff29c ecx=0000000a edx=00000000 esi=030624bc edi=010ff1e0
3 eip=015f097a esp=010ff1c0 ebp=010ff1f8 iopl=0         nv up ei pl nz ac pe nc
4 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216
5 example_4_1_4!com+_entry_point <perf> (example_4_1_4+0x97097a):
6 015f097a c3              ret

                  效果如图:
                  


              tt命令:
                如果我们运行【tt】命令,第一暂停会到【sum3】方法的44行。
1 0:000> tt
2 eax=00000022 ebx=00aff158 ecx=0000000a edx=00000000 esi=02c924bc edi=00aff0a0
3 eip=00e00a4d esp=00aff034 ebp=00aff05c iopl=0         nv up ei pl nz ac pe nc
4 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216
5 example_4_1_4!com+_entry_point <perf> (example_4_1_4+0x730a4d):
6 00e00a4d c20400          ret     4

                  效果如图:
                                    

1 0:000> tt
2 eax=00000022 ebx=00aff158 ecx=0000000a edx=00000000 esi=02c924bc edi=00aff0a0
3 eip=00e00a03 esp=00aff060 ebp=00aff07c iopl=0         nv up ei pl nz ac pe nc
4 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216
5 example_4_1_4!com+_entry_point <perf> (example_4_1_4+0x730a03):
6 00e00a03 c3              ret

                  第二次执行【tt】命令,会在sum2方法的39行暂停,以此类推。
                  


        
2.6、退出调试会话
            
这里不需要更多的代码,也不用专门写一个测试程序了,所以就直接用 example_4_1_4 项目,很简单,就不作图例了。
              测试代码:example_4_1_4

              a、结束会话,并退出程序
                  使用【q】命令。

              b、结束会话,程序继续运行。
                 
使用【qd】命令。

四、总结
    
终于写完了,为什么说是终于,因为写这一篇文章,不是一天完成的,还要写文章,记录操作过程,作图例,所以时间就长了。今天介绍的是 windbg 动态调试的命令,我们要想让调试任务更容易,掌握这些调试技巧还是很有必要的。好了,不说了,不忘初心,继续努力,希望老天不要辜负努力的人。
(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com