• windbg入门


    1.安装

    从微软官网msdn下载,搜索windbg,找到下载页面。下载下来的是一个在线安装工具,类似下载WOW的下载器。运行在线安装工具,会出一个向导,刚开始没仔细看,默认的是在线安装,居然要1.5个G左右的空间,下面还有一个选项,仔细一看不是在线安装,是下载文件到XXX路径,也不小,要700多M的空间,我一想居然这么大,对自己的英语水平没信心,果断取消。找了半天貌似就只有那个网页,确定是那个在线安装工具没错。再仔细看了msdn下载windbg工具的页面说明,原来是N个工具集成在一起的,下载的时候通过那个向导选择only windbg即可。原来如此,果断下载下来了,170多M。包括32位和64位的,还有个附带一个dotNetfx45(安装windbg之前必须先安装这个)

    image

    image

    安装选32位还是64位的呢?这个就要看自己的系统是多少位的,怎么看?在命令行下面输入systeminfo就可以查看了。

    2.安装完了之后,就像随便弄个exe文件,怎样调试呢?

    大概流程是,先用VS(我是用VS2012)随便弄个小程序,编译一下,注意需要生成PDB文件。然后把PDB文件拷贝到一个目录下面(例如e:mypdb)。再用windbg打开exe文件,来进行调试:

    image

    还需要打开PDB文件,

    image

    在打开之前先调出两个窗口吧,一个是command窗口(在打开exe文件时会自动弹出)。

    另外一个是Disassembly,叫反汇编窗口,显示汇编代码。

    打你打开exe文件时,两个窗口都会同步列出一堆信息。

    command窗口的:

    image

    Disassembly窗口的:

    image

    注意看,这两个窗口中,command窗口的最后一行:

    image

    与Disassembly窗口自动标注的一行地址是一样的。具体是什么意思我不懂,个人暂且理解为到这一行的时候程序暂时停止运行。可以看到调试器自动中断下来的位置并不是程序的入口点,这时由windbg实现造成的,暂时先不管,反正知道这样没有问题就是。借这个中断的机会可以对进程启动过程进行排错,或者进行一些准备工作,比如设定断点。

    上面是正常加载pdb文件的情况,之前我反反复复弄了N次,总是提示:

    image

    原来我的路径是这么写的:

    image

    我以为跟打开文件一样,直接精确到了文件。其实这里只是设置一个路径,我加上了文件名,这样windbg在找pdb文件时,把文件名也当作了路径,当然就加载不了pdb文件了。

    3.设置断点。

    使用bp命令可以设置断点。按书上讲的,在VS生成的release版本中带有map文件,打开map文件,看到了main函数的入口地址:

    image

    但是我在cmd窗口中,输入“bp 00401000”,然后输入g命令,继续运行程序,就报错了:

    image

    不知道什么原因,找了半天只找到了下面这个:

    image

    然后用x命令来查找main函数所在的地址。

    image

    根本就没用,没有任何结果,我输入了两遍,都是一样没有结果。也不报错。

    接着看书,还可以带通配符*,那就换通配符看看

    image

    果然有了,不过结果有几个,是哪个呢?为什么有这么多呢?这几个都表示什么呢?

    还有printf函数怎么变成了下面这形式:

    WindbgTest!_imp__printf = <no type information>

    3.用源文件调试。

    操作顺序:打开exe文件,配置源代码路径,再打开源代码文件。

    我刚开始没有打开exe文件,直接打开的源代码文件,点击设置断点符号,设置不了,提示如下:

    image

    4.设置环境变量

    先设置符号文件的环境变量。VS2012会自动生成PBD文件,这个PBD文件应该就是自己写的代码里面一些变量和函数的符号,还有window自己提供的一些微软公共符号在哪里呢?那就需要通过配置一下符号文件的环境变量,通过互联网下载到本地目录了。

    例如:"srv*e:MySymbols*http://msdl.microsoft.com/download/symbols"

    (e:MySymbols目录将被用来保存从符号文件服务器下载下来的符号文件;当然,你可以用

    任何有效的本地或网络路径)

    在你设置_NT_SYMBOL_PATH环境变量之后,就可以使用符号文件服务器了。

    5.打开日志文件

    就是把command窗口的一些消息保存到日志文件,便于朝看日志信息。

    使用三个命令:.logopen命令,.logappend命令,.logclose命令。

    或者在UI界面使用菜单:Edit—>Open/Close Log File

    6.设置workspace

    workspace是用来保存Windbg中工作环境的,例如自己习惯的窗口布局方式、符号路径、日志文件,异常处理的设置等等。

    如果打开调试目标之后,再保存workspace,下次打开调试目标时会自动打开上一次的workspace。如果不打开调试目标,调整Windbg的布局,日志等等设置信息之后,保存为workspace,那么这个workspace就是默认的workspace,下一次打开调试目标时,如果没有关联的workspace就使用这个默认的workspace。

    例如我保存的默认workspace:

    image

    7.重新弄个小程序,设置断点,设置成功了。

    代码:

    #include <stdio.h>
    void fun()
    {
        int a = 10;
        int b = 20;
        int c = 5;
        c= a+b;
        printf("%d",c);
    }
    int main()
    {
        fun();
        return 0;
    }

    按上面的步骤,配置好之后,在命令行窗口输入命令:bp WindbgTest2!fun,设置断点成功。再输入g命令继续运行,就运行到断点处,还弹出了源文件窗口。

    image

    注意,使用bp命令时,应写模块名。如上图中标红的位置,没有带模块名,设置断点时就报错。

    8.调试代码

    接下来和VS调试类似,使用Windbg工具栏上的按钮进行调试。

    调试命令:

    .lines        启用源码行信息
    bp main     设置初始断点到main函数处(以"main"函数为例)
    l+t           按源码行进行单步
    l-t           按汇编行进行单步
    l+s           命令窗口中显示源码行
    g             运行程序,直到断点处(以"main"函数为例)
    pr            执行一行源码,并将寄存器切换为不显示
    p             执行一行源码

    注意:用bp命令设置断点之后,打开源文件,会发现断点处标红了:

    image

    这里标红只是表示断点设置在此处,并不代表程序运行到此处了。应该再输入g命令,让程序走到断点处再进行调试,否者,你会发现单步执行时一直走的汇编代码,不会在源文件中执行一步。执行g命令之后,就会运行到断点处(如果执行一次g命令没有到达断点处,那就多执行几次,我执行了2次才到断点处)。如下图:

    image

    断点处是蓝色标记,然后按F11或者用调试命令就可以单步调试了。

    调试完后可以查看HelloLog文件,可以看出其中记录了调试过程中Command窗口的所有内容,这些内容比较详细,包括了各个时刻寄存器的内容。

    9.总结

    当然,对于上面如此简单的程序,完全没必要用Windbg。实际上,个人觉得,对于用户态程序,只要不牵涉到多线程,甚至一般复杂的多线程程序,都没有必要使用Windbg。

    但是对于偶发缺陷和复杂的多线程程序,Windbg是一种调试选择。Windbg基于命令行调试,具有灵活和强大的特点,至少以下的功能貌似VS还不能实现。

    a. Windbg具有Log文件:虽然VS下进行调试也会生成BuildLog.htm文件,但是根据其内容基本上只能判别出程序运行没运行这种很粗显的错误,用处不大,而Windbg的Log文件(如HelloLog)记录了到寄存器级别的信息,对于debug时分析程序错误还是很有帮助的。

    b. 通过Windbg的命令可以决定哪些信息写入Log文件:比如Windbg通过命令可以在断点处设置当变量满足某一条件时,将此时的callstack和任何你关心的信息写入Log文件。

    c. 通过Windbg通过命令可以实现程序运行多遍(调试偶发缺陷可能有用)。

  • 相关阅读:
    如何导出视图中的数据
    swift中的流程控制
    PostgreSQL导出sql脚本文件
    Java分享笔记:使用缓冲流复制文件
    Java分享笔记:FileOutputStream流的write方法
    Java分享笔记:FileInputStream流的 read()方法 和 read(byte[] b)方法
    Java分享笔记:File类中常用方法的介绍
    Java分享笔记:使用entrySet方法获取Map集合中的元素
    Java分享笔记:使用keySet方法获取Map集合中的元素
    Java分享笔记:Map集合(接口)的基本方法程序演示
  • 原文地址:https://www.cnblogs.com/VIPler/p/4275296.html
Copyright © 2020-2023  润新知