• Windows调试神器:WinDBG


    Q:WinDBG的Watch窗口中我想要查看长字符串,但是后面的内容都被省略为...了怎么办?

    A:如图,双击你要查看的内容,出现光标后,移动光标即可查看后面被省略的内容

    Q:WinDBG如何给程序设置命令行参数?

    A:如图,第一行是参数名(是我的一个用来测试的HTML文件名),第二行是参数所在的位置(也就是该HTML文件所在的目录)

    另外,第二行也代表程序运行时所在的目录。什么意思呢?

    下载demo

    比如说,在调试运行上面那个demo的时候,你把第一行留空(不给任何参数),但是第二行设置为c:myfolder

    你就会发现程序生成的文件在c:myfolder之下,这就好像你打开了cmd,切换到c:myfolder,然后再运行这个程序一样的效果

    ---------------------------------------------------------------------------------------

    最开始一直在撸JAVA,最近处于巩固基础和拓宽知识面的目的翻出了久违的C艹研究。习惯性的用IDE,要么CODEBLOCKS,要么VS.

    过了一段时间,最明显的感觉就是,IDE用多了很多细节不清楚,而这些细节往往是最关键的知识,关系到你能不能从根本上明白程序的本质或者完成一些顽固BUG的修复,而IDE往往会把这些东西给你屏蔽掉(出于方便和自动化的考虑),如果你不知道这些被屏蔽掉的细节,那么你往往在构建程序的时候经常看到IDE报一大堆ERROR的时候不知所措

    反正,我是终于明白了IDE不适合新手的原因。

    在UNIX或者类UNIX系统下有GNU MAKE+GCC+GDB作为命令行编译和调试的工具,个人喜欢称之为3G套装

    那么Windows下难道就只能依赖VS或者CODEBLOCKS+MinGW了么,况且CODEBLOCKS+MinGW本质上也就是3G套装。在Windows下开发一些东西的时候还是要MS自家的工具才吃得开

    经过前段时间的学习,大概学习了一些MS家的NMAKE以及CL还有LINK的基本用法,见这篇随笔

    今天上网搜了搜,发现了神器WinDBG,终于不用在需要DEBUG的时候打开笨重的VS了!新技能GET!MS套装GET!(=,='''逗比。。。)

    点此下载教学PPT(我从百度文库下载下来修改了一些微小的错误并上传到我的网盘)

    点此下载项目文件夹

    代码,main.cpp:

     1 #include <stdlib.h>
     2 #include <stdio.h>
     3 
     4 char *getcharBuffer();
     5 void changeto4p(char* buffer);
     6 
     7 int main()
     8 {
     9     system("pause");
    10     char *str = getcharBuffer();
    11     changeto4p(str);
    12     printf("%s",str);
    13     return 0;
    14 }
    15 
    16 char *getcharBuffer()
    17 {
    18     return "6969,3p3p";
    19 }
    20 
    21 void changeto4p(char* buffer)
    22 {
    23     while (*buffer) {
    24         if (*buffer == '3') {
    25             *buffer = '4';
    26         }
    27         ++buffer;
    28     }
    29 }

    显然,上面的代码在changeto4p中尝试修改read only的memory区域(25行),因此会发生Access violation error

    首先,如果要调试你的代码,那么你在编译的时候要给compiler还有linker加上debug选项,这样调试信息(symbol,line number等等)才会保留下来给DEBUGGER

    见Makefile:

     1 # compiler
     2 CC = cl
     3 # linker
     4 LINK = link
     5 # libraries
     6 LIB = 
    7
    # headers 8 HEADER_PATH = /I include 9 # options 10 EHSC = /EHsc 11 COMPILATION_ONLY = /c 12 C_OUT = /Fo: 13 L_OUT = /OUT: 14 # compiler & linker debug option, to disable debug, replace '/Zi' & '/DEBUG' with empty strings 15 C_DEBUG = /Zi 16 L_DEBUG = /DEBUG 17 # targets 18 bin est.exe: bin obj objmain.obj 19 $(LINK) $(L_DEBUG) $(OBJ_PATH) $(L_OUT)bin est.exe objmain.obj 20 21 objmain.obj: 22 $(CC) $(C_DEBUG) $(EHSC) $(HEADER_PATH) $(COMPILATION_ONLY) srcmain.cpp $(C_OUT)objmain.obj 23 24 # folders 25 26 obj: 27 mkdir obj 28 29 bin: 30 mkdir bin 31 32 # clean 33 # bin, obj folders and pdb files 34 35 .PHONY: clean 36 clean: 37 -rmdir /s /q bin 38 -rmdir /s /q obj 39 -del *.pdb

    我由于不是很会玩Makefile,所以DEBUG选项的添加或者删除都是通过手工修改Makefile实现的。见第14行。至于CL和LINK的各个选项的含义,在MSDN可以找到,就不赘述了。

    (说实话我觉得更好的办法是一个target叫release,另一个叫debug,需要debug的时候就输入nmake debug,所有的obj、exe、pdb文件都放到debugobj,debugin,debugpdb三个文件夹中,需要clean的时候就输入nmake clean,nmake就直接生成release版本的obj和bin文件夹,改天研究研究该怎么写这个Makefile)

    打开命令行,输入nmake生成了demovc120.pdb, demoin est.exe、demoin est.pdb

    这里的vc120.pdb test.pdb就是调试信息文件(Program Debug Database file),WinDBG用这些文件找到源代码的位置和行号还有符号的位置以及其他信息

    打开WinDBG

    第一步,选择File>Symbol File Path,设置pdb文件的位置为demoin,因为test.pdb在这个位置

    第二步,选择File>Source File Path,设置源代码文件的位置为demosrc,因为main.cpp在这个位置

    第三步,选择File>Open Executable,打开test.exe

    你会发现main.cpp也被打开了(WinDBG根据test.pdb找到了main.cpp的位置)

    第四步,打断点,快捷键为F9(命令为bp <代码所在行的二进制地址>),我选择给changeto4p这个函数打上一个断点

    第五步,开始调试,快捷键为F5(命令为g,也就是go的意思,你也可以选择按面板上的按钮,如下图,基本的功能有:Go, Restart, Stop debugging, Break, Step into, Step over, Step out, Run to cursor, Insert or remove breakpoint, Command, Watch, Locals, Registers, Memory window, Call stack, Disassembly, etc)说白了就是(继续运行,重新调试,停止调试,暂停,单步指令(跳入,跳过,跳出,运行到光标处),插入删除断点,命令窗口,变量观察窗口,局部变量观察窗口,寄存器观察窗口,主存观察窗口,调用栈,汇编代码窗口等等),你也可以从View选项中找到这些功能。

    对应的快捷键可以打开WinDBG去查看,我这里就不手打了,撸不动,简单说一下,F10是单步step over,F11是单步step into,跟VS里面一样

    第六步,运行到changeto4p的时候,打开Watch窗口,输入*buffer,你会发现如下图所示,这里的值是0n57 '9',什么意思呢?0n的意思是十进制(类似0x表示十六进制,0开头表示八进制),0n57 '9'的意思就是字符'9'的ASCII码是十进制的57,说白了就是*buffer的值是字符'9'。值得一提的是,这里Watch窗口的name列不仅可以写变量名,也可以写合法的c++表达式,反正指针操作、结构体操作是可以作为合法表达式写到name这一栏的,我估计简单的算术表达式也是可以的,可以试试看。

    另外:你可以选择View>Locals查看局部变量,直接就能看到buffer字符串的所有值,可以试试。

    对于WinDBG初步的学习就到这里。下面还会补充一些更进一步的例子。

     附上zthreaddemo_debug的调试界面截图,步骤跟上面一样哦,试试吧!(注意,就算你设置了Source file path,WinDBG也不会自动去帮你打开cpp文件,所以在开始调试之前把需要的cpp文件打开,然后打上断点!)

    我修改了Makefile从而编译的时候会保留调试信息,生成pdb文件(在Makefile中搜索L_DEBUG和C_DEBUG)

    点此下载zthreaddemo_debug项目文件夹

  • 相关阅读:
    HashMap:JDK7 与 JDK8 的实现
    es简单介绍及使用注意事项
    mongo学习使用记录2 spring data
    mongo学习使用记录1
    数据库三范式
    mysql数据库中实现内连接、左连接、右连接
    JDK7与JDK8中HashMap的实现
    字符串按照相似度排序
    Linux shell 脚本小记2
    ReentrantLock源码了解
  • 原文地址:https://www.cnblogs.com/qrlozte/p/4214316.html
Copyright © 2020-2023  润新知