一、简介
    今天是《Net 高级调试》的第五篇文章。今天这篇文章开始介绍如何在托管方法和非托管方法设置断点,我们要想调试程序,必须掌握调试的一些命令,动态调试的命令,我们在上一篇文章已经讲过了。光有命令也是不行的,要让这些调试命令有用,必须可以在方法上设置断点,然后,再使用调试命令,才能完成我们的调试任务。当然了,第一次看视频或者看书,是很迷糊的,不知道如何操作,还是那句老话,一遍不行,那就再来一遍,还不行,那就再来一遍,俗话说的好,书读千遍,其意自现,我这是第三遍。
     如果在没有说明的情况下,所有代码的测试环境都是 Net Framewok 4.8,但是,有时候为了查看源码,可能需要使用 Net Core 的项目,我会在项目章节里进行说明。好了,废话不多说,开始我们今天的调试工作。
    调试环境我需要进行说明,以防大家不清楚,具体情况我已经罗列出来。
          操作系统:Windows Professional 10
          调试工具:Windbg Preview(可以去Microsoft Store 去下载)
          开发工具:Visual Studio 2022
          Net 版本:Net Framework 4.8
          CoreCLR源码:源码下载

二、基础知识
    
    1、非托管函数下断点
        其实对非托管函数下断点是十分方便的,因为C/C++函数在编译之后就成了【机器代码】了,函数名就进入了【符号表】,比如我们可以非常方便的 notepad 的 SaveFile 函数下断点。

        操作步骤如下:
            a、打开 notepad 。
            b、使用  x notepad!SaveFile 下断点。
            c、在 notepad 上保存一下文件,就会触发断点。
        
    2、托管函数下断点
        
        2.1、简介
            托管函数下断点是很难的,因为你要下断点的方法的机器码在内存中可能还没有生成,也就是 JIT 从来就没有对该方法进行编译过,所以在还没有生成的代码上下断点就比较麻烦。虽然比较麻烦,并不代表不能实现,我们还是有三种方法可以对托管函数下断点的。

        2.2、托管函数下断点的三种方式

            1)、在编译后的函数上下断点
                这是最简单的一种方式,既然方法已经编译完成,肯定就已经生成了机器代码,那在编译后的函数上下断点就容易很多了,和非托管的是一样的。

            2)、在未编译的函数上下断点
                a、使用 !bpmd assembly.exe(模块包含后缀名) namespace.ClassName.MethodName
                b、使用 sosex 扩展的 mbm 下断点(只能在 Net framework 下使用,Net Core 是不支持的)

            3)、对泛型方法下断点
                如果我们想对泛型类型的方法下断点,最首要的任务就是找到泛型类型的名称和方法的名称,找到之后,我们就可以下断点了。找泛型类型的名称和方法的名称有两种办法,第一种是通过命令,第二种是我们可以使用 ILSpy 找到。

三、调试过程
    废话不多说,这一节是具体的调试操作的过程,又可以说是眼见为实的过程,在开始之前,我还是要啰嗦两句,这一节分为两个部分,第一部分是测试的源码部分,没有代码,当然就谈不上测试了,调试必须有载体。第二部分就是根据具体的代码来证实我们学到的知识,是具体的眼见为实。

    1、测试源码        
        1.1、Example_5_1_1

 1 namespace Example_5_1_1
2 {
3 internal class Program
4 {
5 static void Main(string[] args)
6 {
7 var sum = Sum(10, 20);
8
9 Debugger.Break();
10
11 sum = Sum(100, 200);
12
13 Console.WriteLine($"sum={sum}");
14 }
15
16 private static int Sum(int a, int b)
17 {
18 var sum = a + b;
19
20 return sum;
21 }
22 }
23 }

     
        1.2、Example_5_1_2

 1 namespace Example_5_1_2
2 {
3 internal class Program
4 {
5 static void Main(string[] args)
6 {
7 Console.WriteLine("请查看:未编译形态的 Sum 方法");
8 Debugger.Break();
9
10 var sum = Sum(10,20);
11 Console.WriteLine("请查看:已经编译形态的 Sum 方法");
12 Debugger.Break();
13
14 sum = Sum(100, 200);
15
16 Console.WriteLine($"sum={sum}");
17 }
18
19 private static int Sum(int a, int b)
20 {
21 var sum = a + b;
22
23 return sum;
24 }
25 }
26 }

        1.3、Example_5_1_3

 1 namespace Example_5_1_3
2 {
3 internal class Program
4 {
5 static void Main(string[] args)
6 {
7 Debugger.Break();
8
9 var mylist = new MyList<int>();
10
11 mylist.Add(10);
12
13 Console.ReadLine();
14 }
15 }
16
17 public class MyList<T>
18 {
19 public T[] arr = new T[10];
20
21 public void Add(T t)
22 {
23 arr[0] = t;
24 }
25 }
26 }

    2、眼见为实
        
        2.1、在非托管函数 Notepad 的 SaveFile 方法上下断点。
            测试程序:Notepad
            操作流程:我们先要打开 notepad,然后再打开 windbg,点击【文件】菜单,然后通过【attach to process】附加进程,最后点击【Attach】按钮完成附加进程的操作。现在 notepad 是不能操作的,因为断点断住了,所以我们执行【g】命令,运行一下。然后我们点击工具栏【break】按钮,中断,然后就可以调试了。
            我们使用【x】命令查找一下 notepad 的 SaveFile 方法。

1 0:002> x notepad!*SaveFile*
2 00007ff6`e46be780 notepad!SaveFile (bool __cdecl SaveFile(struct HWND__ *,class wil::unique_any_t<class wil::details::unique_storage<struct wil::details::resource_policy<unsigned short *,void (__cdecl*)(void *),&void __cdecl CoTaskMemFree(void *),struct wistd::integral_constant<unsigned __int64,0>,unsigned short *,unsigned short *,0,std::nullptr_t> > > &,bool,unsigned short const *))
3 00007ff6`e46d508c notepad!_imp_load_GetSaveFileNameW (__imp_load_GetSaveFileNameW)
4 00007ff6`e46e50b0 notepad!_imp_GetSaveFileNameW = <no type information>

            使用【bp】命令对 notepad!SaveFile 函数下断点。下断点后,继续运行,使用【g】命令。

1 0:002> bp notepad!SaveFile
2 0:002> g

            此时,我们可以操作 notepad,随便输入一些内容,然后点击【保存】,就可以被断点断住。

1 .......
2 Breakpoint 0 hit
3 notepad!SaveFile:
4 00007ff6`e46be780 488bc4 mov rax,rsp

            我们可以使用【k】命令显示调用栈也能说明问题。

 1 0:000> k
2 # Child-SP RetAddr Call Site
3 00 00000002`1a1dec58 00007ff6`e46b9336 notepad!SaveFile
4 01 00000002`1a1dec60 00007ff6`e46badf4 notepad!NPCommand+0x2d2
5 02 00000002`1a1df240 00007ff8`23e0e338 notepad!NPWndProc+0x844
6 03 00000002`1a1df570 00007ff8`23e0dd79 USER32!UserCallWinProcCheckWow+0x2f8
7 04 00000002`1a1df700 00007ff6`e46bb30c USER32!DispatchMessageWorker+0x249
8 05 00000002`1a1df780 00007ff6`e46d3b66 notepad!wWinMain+0x29c
9 06 00000002`1a1df830 00007ff8`23b86fd4 notepad!__scrt_common_main_seh+0x106
10 07 00000002`1a1df870 00007ff8`25bbcec1 KERNEL32!BaseThreadInitThunk+0x14
11 08 00000002`1a1df8a0 00000000`00000000 ntdll!RtlUserThreadStart+0x21

            截图效果:
              

        2.2、在已经编译的托管函数上下断点。
            测试程序:Example_5_1_1
            我们使用 Windbg Preview 调试器,通过【launch executable】菜单加载【Example_5_1_1.exe】项目,通过【g】命令,运行程序,调试器运行代【Debugger.Break()】次会暂停执行。当然,我们可以使用【cls】命令清理一下调试器显示的过多信息,自己来决定,我是会清理的。我们将在【sum = Sum(100, 200);】这行下断点。
            当调试器暂停的时候,说明有一部分代码已经执行了。【var sum = Sum(10, 20);】就是这行代码已经被执行,也可以说是被 JIT 编译了。我们如何查看 Sum 方法被编译的代码呢?可以使用【!name2ee】命令。

1 0:000> !name2ee Example_5_1_1!Example_5_1_1.Program.Sum
2 Module: 00fc4044
3 Assembly: Example_5_1_1.exe
4 Token: 06000002
5 MethodDesc: 00fc4d64
6 Name: Example_5_1_1.Program.Sum(Int32, Int32)
7 JITTED Code Address: 01010908

            红色标注表示代码已经编译,我们也可以使用【!u】命令查看这个代码的汇编代码,汇编代码很多,所以折叠。

 1 0:000> !u 01010908
2 Normal JIT generated code
3 Example_5_1_1.Program.Sum(Int32, Int32)
4 Begin 01010908, size 3e
5
6 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_5_1_1\Program.cs @ 20:
7 >>> 01010908 55 push ebp
8 01010909 8bec mov ebp,esp
9 0101090b 83ec10 sub esp,10h
10 0101090e 894dfc mov dword ptr [ebp-4],ecx
11 01010911 8955f8 mov dword ptr [ebp-8],edx
12 01010914 833df042fc0000 cmp dword ptr ds:[0FC42F0h],0
13 0101091b 7405 je 01010922
14 0101091d e85ef40670 call clr!JIT_DbgIsJustMyCode (7107fd80)
15 01010922 33d2 xor edx,edx
16 01010924 8955f0 mov dword ptr [ebp-10h],edx
17 01010927 33d2 xor edx,edx
18 01010929 8955f4 mov dword ptr [ebp-0Ch],edx
19 0101092c 90 nop
20
21 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_5_1_1\Program.cs @ 21:
22 0101092d 8b45fc mov eax,dword ptr [ebp-4]
23 01010930 0345f8 add eax,dword ptr [ebp-8]
24 01010933 8945f4 mov dword ptr [ebp-0Ch],eax
25
26 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_5_1_1\Program.cs @ 23:
27 01010936 8b45f4 mov eax,dword ptr [ebp-0Ch]
28 01010939 8945f0 mov dword ptr [ebp-10h],eax
29 0101093c 90 nop
30 0101093d eb00 jmp 0101093f
31
32 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_5_1_1\Program.cs @ 24:
33 0101093f 8b45f0 mov eax,dword ptr [ebp-10h]
34 01010942 8be5 mov esp,ebp
35 01010944 5d pop ebp
36 01010945 c3 ret

            

            我们使用【bp】命令在地址【01010908】地址处下断点,【g】继续运行,就会在 Sum 方法的第一行断住。

0:000> bp 01010908

            继续运行后,            

1 0:000> g
2 Breakpoint 0 hit
3 eax=00000000 ebx=00aff108 ecx=00000064 edx=000000c8 esi=02b524bc edi=00aff058
4 eip=01010908 esp=00aff03c ebp=00aff068 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 Example_5_1_1!COM+_Entry_Point <PERF> (Example_5_1_1+0x920908):
7 01010908 55 push ebp

            效果截图:
              

            
        2.3、在未编译的托管函数上下断点。
            测试程序:Example_5_1_2
            我们使用 Windbg Preview 调试器,通过【launch executable】菜单加载【Example_5_1_2.exe】项目,通过【g】命令,运行程序,调试器运行代【Debugger.Break()】次会暂停执行,此行代码在12。当然,我们可以使用【cls】命令清理一下调试器显示的过多信息,自己来决定,我是会清理的。这次我们的任务依然是在 Sum 方法上下断点。
            先来一个截图吧,效果更明显:
            
              我们还是先使用【!name2ee】命令查找一下 Sum 方法。

1 0:000> !name2ee Example_5_1_2!Example_5_1_2.Program.Sum
2 Module: 00f34044
3 Assembly: Example_5_1_2.exe
4 Token: 06000002
5 MethodDesc: 00f34d64
6 Name: Example_5_1_2.Program.Sum(Int32, Int32)
7 Not JITTED yet. Use !bpmd -md 00f34d64 to break on run.

              红色标注说明,我们的代码还没有被JIT编译。我们听从他的建议,使用【!bpmd -md】下断点。

1 0:000> !bpmd -md 00f34d64
2 MethodDesc = 00f34d64
3 Adding pending breakpoints...

              我们可以使用【g】命令,继续运行,果然在断点处暂停。我这里是可以的,但是视频说是不可以的。

 1 0:000> g
2 (bb0.3798): CLR notification exception - code e0444143 (first chance)
3 JITTED Example_5_1_2!Example_5_1_2.Program.Sum(Int32, Int32)
4 Setting breakpoint: bp 00F8094C [Example_5_1_2.Program.Sum(Int32, Int32)]
5 Breakpoint: JIT notification received for method Example_5_1_2.Program.Sum(Int32, Int32) in AppDomain 0100da40.
6 Breakpoint 0 hit
7 eax=00f80928 ebx=009ef098 ecx=0000000a edx=00000000 esi=02c224bc edi=009eefe8
8 eip=00f8094c esp=009eefb8 ebp=009eefc8 iopl=0 nv up ei pl zr na pe nc
9 cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
10 Example_5_1_2!COM+_Entry_Point <PERF> (Example_5_1_2+0x73094c):
11 00f8094c 90 nop

             截图效果:
              

            1)、使用 !bpmd moduleName namespace.ClassName.MethodName
                这个实现的原理是借助 JIT 的编译完成通知事件,在事件中判断当前编译的是否是我们下断点的方法,如果是就转成 bp 命令下断点,从输出的信息也可以看得出来。
                【!bpmd】命令格式一下两种都对:!bpmd Example_5_1_2.exe Example_5_1_2.Program.Sum 或者 !bpmd Example_5_1_2 Example_5_1_2.Program.Sum

1 0:000> !bpmd Example_5_1_2 Example_5_1_2.Program.Sum
2 Found 1 methods in module 011a4044...
3 MethodDesc = 011a4d64
4 Adding pending breakpoints...

                断点设置成功,【g】继续运行,成功在断点处暂停。

 1 0:000> g
2 (14c4.1b60): CLR notification exception - code e0444143 (first chance)(表示 JIT 已经编译好了,CLR 给 Windbg 发出一个异常通知)
3 JITTED Example_5_1_2!Example_5_1_2.Program.Sum(Int32, Int32)
4 Setting breakpoint: bp 02DD094C [Example_5_1_2.Program.Sum(Int32, Int32)](Windbg 拿到编译后的机器码地址,重新设置断点)
5 Breakpoint: JIT notification received for method Example_5_1_2.Program.Sum(Int32, Int32) in AppDomain 011f0fe8.
6 Breakpoint 0 hit
7 eax=02dd0928 ebx=00efedd8 ecx=0000000a edx=00000000 esi=02f124bc edi=00efed28
8 eip=02dd094c esp=00efecf8 ebp=00efed08 iopl=0 nv up ei pl zr na pe nc
9 cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
10 Example_5_1_2!COM+_Entry_Point <PERF> (Example_5_1_2+0x22d094c):
11 02dd094c 90 nop

                截图效果:
                

            2)、使用 sosex 扩展的 mbm 下断点(只能在 Net framework 下使用,Net Core 是不支持的)
                mbm 是非托管命令 bm 的托管版本,对方法名下断点,还支持模糊匹配。
                

1 0:000> !mbm Example_5_1_2!Example_5_1_2.Program.Sum

                设置断点后,我们可以继续运行,执行【g】命令。

1 0:000> g
2 Breakpoint: JIT notification received for method Example_5_1_2.Program.Sum(Int32, Int32) in AppDomain 00a61010.
3 Breakpoint set at Example_5_1_2.Program.Sum(Int32, Int32) in AppDomain 00a61010.
4 Breakpoint 5 hit
5 eax=00a20928 ebx=008ff050 ecx=0000000a edx=00000000 esi=029d24bc edi=008fef98
6 eip=00a2094c esp=008fef68 ebp=008fef78 iopl=0 nv up ei pl zr na pe nc
7 cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
8 Example_5_1_2!COM+_Entry_Point <PERF> (Example_5_1_2+0x5a094c):
9 00a2094c 90 nop

                成功断住,效果如图:

                
                【mbm】命令很强大,也可以支持模糊查找。这个操作是另外一个过程,需要重新运行调试程序。

1 0:000> !mbm Example_5_1_2!*Sum

                成功在断点出暂停。

1 0:000> g
2 Breakpoint: JIT notification received for method Example_5_1_2.Program.Sum(Int32, Int32) in AppDomain 01720fb8.
3 Breakpoint set at Example_5_1_2.Program.Sum(Int32, Int32) in AppDomain 01720fb8.
4 Breakpoint 1 hit
5 eax=031c0928 ebx=0137f378 ecx=0000000a edx=00000000 esi=033d24bc edi=0137f2c8
6 eip=031c094c esp=0137f298 ebp=0137f2a8 iopl=0 nv up ei pl zr na pe nc
7 cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
8 Example_5_1_2!COM+_Entry_Point <PERF> (Example_5_1_2+0x21e094c):
9 031c094c 90 nop

              
        2.4、在泛型方法上下断点。
            测试程序:Example_5_1_3
            我们使用 Windbg Preview 调试器,通过【launch executable】菜单加载【Example_5_1_3.exe】项目,通过【g】命令,运行程序,调试器运行代【Debugger.Break();】次会暂停执行。当然,我们可以使用【cls】命令清理一下调试器显示的过多信息,自己来决定,我是会清理的。
            这次的任务是,我们要在泛型类型 MyList<T> 的 Add() 方法上下断点。
            我们想要在泛型类型的方法上下断点,首要的任务是找到泛型类型的名称和方法的名称,这是关键。
            效果如图:
            

            a、我们通过 Windbg 和 SOS 的命令找到类型的名称。
                编译程序集后,泛型类型一定在这个程序集的模块中。然后我们再在这个模块中打印出所有的类型,就可以找到这个类型了。
                我们现在这个程序集中查找模块信息,我们可以使用【!dumpdomain】命令。

 1 0:000> !dumpdomain
2 --------------------------------------
3 System Domain: 7141caf8
4 ....
5 --------------------------------------
6 Shared Domain: 7141c7a8
7 ......
8
9 --------------------------------------
10 Domain 1: 00a2da30
11 ......
12
13 Assembly: 00a87ea8 [E:\Visual Studio 2022\Source\Projects\......\Example_5_1_3\bin\Debug\Example_5_1_3.exe]
14 ClassLoader: 00a873a8
15 SecurityDescriptor: 00a872a0
16 Module Name
17 01004044(模块地址) E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_5_1_3\bin\Debug\Example_5_1_3.exe

              我们找到了模块,就可以将模块中所有的类型输出出来,可以使用【!dumpmodule -mt 】命令。

 1 0:000> !dumpmodule -mt 01004044
2 Name: E:\Visual Studio 2022\Source\Projects\...\Example_5_1_3\bin\Debug\Example_5_1_3.exe
3 Attributes: PEFile
4 Assembly: 00a87ea8
5 LoaderHeap: 00000000
6 TypeDefToMethodTableMap: 01000038
7 TypeRefToMethodTableMap: 01000048
8 MethodDefToDescMap: 01000094
9 FieldDefToDescMap: 010000a8
10 MemberRefToDescMap: 00000000
11 FileReferencesMap: 010000b8
12 AssemblyReferencesMap: 010000bc
13 MetaData start address: 006220a8 (1680 bytes)
14
15 Types defined in this module
16
17 MT TypeDef Name
18 ------------------------------------------------------------------------------
19 01004d6c 0x02000002 Example_5_1_3.Program
20 01004de8 0x02000003 Example_5_1_3.MyList`1
21
22 Types referenced in this module
23
24 MT TypeRef Name
25 ------------------------------------------------------------------------------
26 6f802734 0x02000010 System.Object
27 6f847540 0x02000011 System.Diagnostics.Debugger
28 6f808af0 0x02000012 System.Console

              红色标注的就是我们要查找泛型类型真实的名称。有了类型,我们继续可以使用【!dumpmt -md ...】命令,输出它所有方法。

 1 0:000> !dumpmt -md 01004de8
2 EEClass: 01001334
3 Module: 01004044
4 Name: Example_5_1_3.MyList`1
5 mdToken: 02000003
6 File: E:\Visual Studio 2022\Source\Projects\......\Example_5_1_3\bin\Debug\Example_5_1_3.exe
7 BaseSize: 0xc
8 ComponentSize: 0x0
9 Slots in VTable: 6
10 Number of IFaces in IFaceMap: 0
11 --------------------------------------
12 MethodDesc Table
13 Entry MethodDe JIT Name
14 6fbf97b8 6f7fc838 PreJIT System.Object.ToString()
15 6fbf96a0 6f938978 PreJIT System.Object.Equals(System.Object)
16 6fc021f0 6f938998 PreJIT System.Object.GetHashCode()
17 6fbb4f2c 6f9389a0 PreJIT System.Object.Finalize()
18 02840458 01004dd4 NONE Example_5_1_3.MyList`1..ctor()
19 02840450 01004dcc NONE Example_5_1_3.MyList`1.Add(!0)

              红色标记就是我们要查找的 Add 方法,有了方法的地址,我们就可以使用【bpmd】命令为其下断点了。

1 0:000> !bpmd Example_5_1_3 Example_5_1_3.MyList`1.Add
2 Found 1 methods in module 01004044...
3 MethodDesc = 01004dcc
4 Adding pending breakpoints...

              断点设置成功后,我们使用【g】命令,程序继续运行,就可以在断点处暂停。

 1 0:000> g
2 (3ab4.2920): CLR notification exception - code e0444143 (first chance)
3 JITTED Example_5_1_3!Example_5_1_3.MyList`1[[System.Int32, mscorlib]].Add(Int32)
4 Setting breakpoint: bp 02840942 [Example_5_1_3.MyList`1[[System.Int32, mscorlib]].Add(Int32)]
5 Breakpoint: JIT notification received for method Example_5_1_3.MyList`1[[System.Int32, mscorlib]].Add(Int32) in AppDomain 00a2da30.
6 Breakpoint 0 hit
7 eax=02840928 ebx=007bee20 ecx=029f26b0 edx=0000000a esi=00000000 edi=007bed90
8 eip=02840942 esp=007bed58 ebp=007bed60 iopl=0 nv up ei pl zr na pe nc
9 cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
10 Example_5_1_3!COM+_Entry_Point <PERF> (Example_5_1_3+0x2220942):
11 02840942 90 nop

              断点效果如图:
              

            b、我们可以使用 ILSpy 来查找泛型类型的名称和方法的名称。
              效果如图:
              

                上面就是类型的名称,我继续查找方法的名称,也很简单。
              效果如图:

          

              有了这些信息,我们就可以使用 Windbg 为程序设置断点了,操作过程和 a 的过程一样,就不多说了。

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

Net 高级调试之五:如何在托管函数上设置断点的更多相关文章

  1. Lua中如何实现类似gdb的断点调试—07支持通过函数名称添加断点

    我们之前已经支持了通过函数来添加断点,并且已经支持了行号的检查和自动修正.但是通过函数来添加断点有一些限制,如果在当前的位置无法访问目标函数,那我们就无法对其添加断点. 于是,本篇我们将扩展断点设置的 ...

  2. Linux高级编程--04.GDB调试程序(设置断点)

    调试已运行的程序 在UNIX下用ps查看正在运行的程序的PID(进程ID),然后用gdb PID格式挂接正在运行的程序. 先用gdb 关联上源代码,并进行gdb,在gdb中用attach命令来挂接进程 ...

  3. ###Android 断点调试和高级调试###

    转自:http://www.2cto.com/kf/201506/408358.html 有人说Android 的调试是最坑的,那我只能说是你不会用而已,我可以说Android Studio的调试是我 ...

  4. Linux高级调试与优化——gdb调试命令

    番外 2019年7月26日至27日,公司邀请<软件调试>和<格蠹汇编——软件调试案例集锦>两本书的作者张银奎老师进行<Linux高级调试与优化>培训,有幸聆听张老师 ...

  5. Visual Studio高级调试技巧

    1. 设置软件断点,运行到目标位置启动调试器 方法①:使用汇编指令(注:x64 c++不支持嵌入汇编) _asm 方法②:编译器提供的方法 __debugbreak(); 方法③:使用windows ...

  6. [Android Studio 权威教程]断点调试和高级调试

    好了开始写一个简单的调试程序,我们先来一个for循环 ? 1 2 3 4 5 6 7 8 <code class="language-java hljs ">for ( ...

  7. GDB高级调试

    一.多线程调试 多线程调试可能是问得最多的.其实,重要就是下面几个命令: info thread 查看当前进程的线程. thread <ID> 切换调试的线程为指定ID的线程. break ...

  8. python高级(六)——用一等函数实现设计模式

    本文主要内容 经典的“策略”模式 python高级——目录 文中代码均放在github上:https://github.com/ampeeg/cnblogs/tree/master/python高级 ...

  9. Android Stuido中断点调试和高级调试

    写一个简单的调试程序 import android.os.Bundle; import android.support.v7.app.AppCompatActivity; public class M ...

  10. .NET高级调试系列-Windbg调试入门篇

    Windbg是.NET高级调试领域中不可或缺的一个工具和利器,也是日常我们分析解决问题的必备.准备近期写2篇精华文章,集中给大家分享一下如果通过Windbg进行.NET高级调试. 今天我们来一篇入门的 ...

随机推荐

  1. 2023CCPC大学生程序设计竞赛-nhr

    新生菜菜第一次参加这种大型比赛,还是有点紧张的,CCPC我们队就A了三题,铜牌.第一道,以为是签到,然后就交给clk了,我和crf看下一道过的题比较多的,然后感觉是一个滑动窗口,另一道题是纯数学公式. ...

  2. MIT 6.5840 Raft Implementation(2A, Leader Election)

    Raft实现思路+细节 2A 任务分解 总体来说,2A中主要的任务就是选出领导人,在选出领导人的时候,我们要遵循下图. 在2A中,由于并没有出现日志复制,所以我们只需要考察两者的任期是否相等,以及接收 ...

  3. Linux 上 KVM 虚拟机网络问题

    通过控制台连接虚拟机,ping自己的ip,ping宿主机的ip,ping同网段的ip 1. 自己的ip也不通,先检查网络配置 2. 宿主机的ip不通,就要确认下虚拟机网卡的类型 对于macvlan网卡 ...

  4. vlunhub笔记(二)earth

    (一)信息收集 开始扫描目标机ip,目标机ip:192.168.241.135 arp-scan -l 直接访问目标  ip 192.168.241.135   发现400报错 只能先去考虑扫一下信息 ...

  5. Cilium系列-10-启用 IPv6 BIG TCP和启用巨帧

    系列文章 Cilium 系列文章 前言 将 Kubernetes 的 CNI 从其他组件切换为 Cilium, 已经可以有效地提升网络的性能. 但是通过对 Cilium 不同模式的切换/功能的启用, ...

  6. 【pandas小技巧】--反转行列顺序

    反转pandas DataFrame的行列顺序是一种非常实用的操作.在实际应用中,当我们需要对数据进行排列或者排序时,通常会使用到Pandas的行列反转功能.这个过程可以帮助我们更好地理解数据集,发现 ...

  7. 青少年CTF平台 Web签到

    题目说明 Web一星简单题,Web签到. 直接启动环境,等待30秒左右访问题目链接. 做题过程 进入后,题目好像没有告诉我们什么有用的信息, F12,看遍了题目源码,也没有发现flag,正当我怀疑这个 ...

  8. 【Azure K8S | AKS】在不丢失文件/不影响POD运行的情况下增加PVC的大小

    问题描述 在前两篇文章中,创建了Disk + PV + PVC + POD 方案后,并且进入POD中增加文件. [Azure K8S | AKS]在AKS集群中创建 PVC(PersistentVol ...

  9. CF992E Nastya and King-Shamans 题解

    传送门 分析 由于满足 \(a_i\ge0\),所以 \(s_i\) 单调不减. 当我们找到一个 \(i\) 时,不管 \(i\) 是否满足,下一个可能的一定大于等于 \(a_i+s_{i-1}\). ...

  10. 十年磨一剑的华为云GES,高明在哪

    本文分享自华为云社区<华为云GES:十年磨一剑,打造业界一流的云原生分布式图数据库>,作者:GES图引擎服务小图 . 1.浅谈云原生图数据库 图数据库(graph database)是一个 ...