性能分析之代码调试-动态修改内存变量值(C/C++)

听闻少年二字,当与平庸相斥。这篇文章主要讲述性能分析之代码调试-动态修改内存变量值(C/C++)相关的知识,希望能为你提供帮助。
前文提到了分析的思路是从OS级别到代码的级别。但是到了代码级别之后呢,可能还需要动态调试代码,之前写了java的应用的代码动态调试工具。请参见《??性能工具之Java调试工具JDB??》。并且之前在群里也有说要写关于如何修改内存变量值的。所以这里也就写一下。
        后续写系列文章的思路也是将我工作中遇得到的性能分析思路一一写出来。


        这次我们来写GDB这个工具。来看看官方如何定义这个工具的:

GDB, the GNU Project debugger, allows you to see what is going on `inside\' another program while it executes -- or what another program was doing at the moment it crashed.
GDB can do four main kinds of things (plus other things in support of these) to help you catch bugs in the act:
  • Start your program, specifying anything that might affect its behavior.
  • Make your program stop on specified conditions.
  • Examine what has happened, when your program has stopped.
  • Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another.
The program being debugged can be written in Ada, C, C++, Objective-C, Pascal (and many other languages). Those programs might be executing on the same machine as GDB (native) or on another machine (remote). GDB can run on most popular UNIX and Microsoft Windows variants.
        就是说可以让你查看另一个程序在运行的时候“里面”都有些啥。
  1. 可以改变程序的行为;
  2. 可以停在特定的地方;
  3. 可以定位程序停止时发生了什么事;
  4. 可以动态修改一些东西;
        并且它还能支持多种语言的调试,还能远程调试。


        因为本文不是GDB工具的说明书,所以没打算把每个命令都讲一遍,只扣题修改内存变量。


        起点这么高,还是要落地。我就随便写了几行C的代码,简单到无基础的也可以玩。
性能分析之代码调试-动态修改内存变量值(C/C++)

文章图片

        编译它:gcc -g test.c -o test。
        我们可以用gdb调用,也可以选择用cgdb调用。cgdb就是用来替代gdb -tui的,也就是加了点源代码显示的色彩啥的。看一下截图比对就知道了。
性能分析之代码调试-动态修改内存变量值(C/C++)

文章图片
                左边是gdb -tui,右边是cgdb。麻烦点的就是cgdb还得另装一下。其他没有什么不同。
        下面我们来调试下。运行一次没有加断点的。结果如下:
性能分析之代码调试-动态修改内存变量值(C/C++)

文章图片

        因为要调试,所以得先知道要调试什么。我这小段代码就一个循环,所以我把断点设置在第7行循环里(GDB断点有多种方式:可以指定行、函数、文件名+行数、class+function、内存地址等,还可以加if else的语法之类的),以便一会修改内存变量。过程如下:
(gdb) b 7   #设置断点在第7行
Breakpoint 2 at 0x400541: file test.c, line 7.
(gdb) run   #运行程序,命中断点
Starting program: /root/GDB/Sample6/./test


Breakpoint 2, main () at test.c:7
(gdb) info locals   #查看变量值
i = 1
(gdb) set var i=4        #修改变量值
(gdb) clear 7                #删掉断点,因为不删掉每次循环都会命中
Deleted breakpoint 2
(gdb) info breakpoints        #确认下断点已经删了
No breakpoints or watchpoints.
(gdb) c                #接着执行程序
i= : 4
i= : 5
i= : 6
i= : 7
i= : 8
i= : 9
i= : 10
Continuing.
[Inferior 1 (process 22528) exited with code 012]
(gdb) 
        从上面的结果来看i值的打印没有2、3的值了,被跳过了。
     
        GDB不仅可以调起来程序,也可以直接attach到已经启动的程序中,所以不用担心程序不是自己启动的。只要有权限收拾它,怎么都能收拾它。
        可能有人会说,我根本不知道要调试什么,怎么办呢?见到这样的问题我只能说:你还年轻,以后日子还长,总会知道滴。(潜台词就是:要好好学习我之前写的思路。)


        之所以在性能分析的系列中写这样的文章,是为了说明在性能分析中,这样的思路也是在必要的时候要有的。
        前面我一直说有问题要定位到代码或SQL或参数的层面。有时候即使我们把堆栈拿出来了,还会涉及到扯皮的事情,比如环境不一样导致的问题现象不同。所以如果有能力的话,我们就再往下走一层,就是把实际的运行数据拿出来,这样就没有什么可争辩的了。
        我曾经在一个项目中就是出现了问题之后,结果开发的环境不能重现,但是生产的环境肯定有。当时让一个小伙跟了这个问题两个星期,也没把问题和对应的开发工程师说明白。我就教了他这个手段。分分钟地让开发明白哪做错了。


        在性能分析的项目中,什么都有可能遇得到。我带团队的要求,就是在性能分析中要干得过项目中遇得到的所有技术人员,就是吵架也要有确凿的证据。(如果确实干不过人家的话,那就好好跟人家学。能屈能伸不才是大丈夫嘛。)


    希望现在做性能分析的人能掌握越来越多的技能。
【性能分析之代码调试-动态修改内存变量值(C/C++)】

    推荐阅读