Debugging your program using Valgrind gdbserver and GDB

一个在valgrind中运行的程序不是直接在CPU上执行。反之,它是运行在一个由valgrind提供的仿真CPU上。这就是当程序运行在valgrind中是,debugger不能不能调试的原因。

本小节描述GDB如何能够与algrind gdbserver交互,用来支持一个在valgrind环境下调试。使用这种方法,gdb可以提供与valgrind的core或者tool交互的功能,包含在Memcheck下增加leak search和Massif快照。

3.2.1. Quick Start: debugging in 3 steps

最简单的方法是用--vgdb-error=0来运行valgrind。然后按照on-screen上的指示(提供详细的指令来启动gdb,并且连接到你的程序)。如果你想用memcheck来debug一个程序,像这样运行程序。

valgrind --vgdb=yes --vgdb-error=0 prog
在另一个shell,运行gdb

gdb prog

然后输入下列命令

(gdb) target remote | vgdb

现在,你可以调试你的程序来,例如插入一个断点,然后使用gdb continue命令。

对于algrind gdbserver的基本使用,这个快速开始的方法已经足够了。下面的章节将会描述algrind和gdb联合使用提供的更高级的功能。注意,命令行参数 --vgdb=yes可以忽略,因为这是默认值。

root@ubuntu:~# valgrind  --vgdb-error=0 ls

==25403== Memcheck, a memory error detector

==25403== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.

==25403== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info

==25403== Command: ls

==25403==

==25403== (action at startup) vgdb me ...
==25403==
==25403== TO DEBUG THIS PROCESS USING GDB: start GDB like this

==25403==   /path/to/gdb ls
==25403== and then give GDB the following command
==25403==   target remote | /usr/local/lib/valgrind/../../bin/vgdb --pid=25403
==25403== --pid is optional if only one valgrind process is running

==25403==
eglibc-2.15  eglibc_2.15-0ubuntu10.4.diff.gz  eglibc_2.15-0ubuntu10.4.dsc  eglibc_2.15.orig.tar.gz  perl  valgrind-3.9.0
==25403==
==25403== HEAP SUMMARY:
==25403==     in use at exit: 13,540 bytes in 12 blocks
==25403==   total heap usage: 48 allocs, 36 frees, 48,823 bytes allocated
==25403==
==25403== LEAK SUMMARY:
==25403==    definitely lost: 0 bytes in 0 blocks
==25403==    indirectly lost: 0 bytes in 0 blocks
==25403==      possibly lost: 0 bytes in 0 blocks
==25403==    still reachable: 13,540 bytes in 12 blocks
==25403==         suppressed: 0 bytes in 0 blocks
==25403== Rerun with --leak-check=full to see details of leaked memory
==25403==
==25403== For counts of detected and suppressed errors, rerun with: -v
==25403== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)


3.2.2. Valgrind gdbserver overall organisation

GNU GDB debugger通常用在调试运行在同一机器上的进程。在这种模式下,GDB使用system calls来控制和查询被调试的程序。这样工作很好,但是他仅允许gdb调试运行在同一机器上的进程。
GDB同样也能调试运行在不同机器上的进程。为了达到这个目的,GDB定义了一个协议(也就是一组请求/应答packets)用来实现获得内存/寄存器的值,设置断点等。
gdbserver就是实现了这种"GDB remote debug"协议。为了调试一个不再本地运行的进程,gdbserver(有时也叫GDB stub)必须运行在remote机器上。
valgrind core提供了一个built-in gdbserver实现,通过--vgdb=yes或--vgdb=full来激活。这个gdbserver允许远程调试一个运行在valgring仿真CPU上的进程。
gdb向Valgrind built-in的gdbserver发送查询packets(例如"get register contents")。gdbserver执行查询(例如,它获得仿真CPU的寄存器值),然后返回给GDB。
GDB可以使用各种通道来(TCP/IP,串口等)和gdbserver通信。在valgrind侧,通信是通过一个pipe和一个叫vgdb的helper程序实现的,vgdb的功能类似中介。如果没有GDB
正在被使用,vgdb也可以用来通过shell命令行来发送monitor命令到gdbserver。

3.2.3. Connecting GDB to a Valgrind gdbserver

为了debug一个运行在valgrind中的prog,必须确保通过--vgdb=yes或--vgdb=full来激活valgrind gdbserver。一个辅助的命令行选项,--vgdb-error=number,可以用来告诉gdbserver在到达某个指定的数目的error时把它激活。0告诉gdbserver在startup时就激活,这样你可以在process开始运行之前插入断点。例如

valgrind --tool=memcheck --vgdb=yes --vgdb-error=0 ./prog

valgrind gdbserver在startup时就被激活,并且表明等待一个gdb连接

==2418== Memcheck, a memory error detector
==2418== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==2418== Using Valgrind-3.7.0.SVN and LibVEX; rerun with -h for copyright info
==2418== Command: ./prog
==2418== 
==2418== (action at startup) vgdb me ... 
然后GDB(在另一个shell中)就可以连接Valgrind gdbserver了。前提,GDB必须以prog开始运行

gdb ./prog
然后告诉GDB你想调试一个remote目标
(gdb) target remote | vgdb
gdb然后打开一个vgdb中转应用来和valgrind built-in的gdbserver通信
(gdb) target remote | vgdb
Remote debugging using | vgdb
relaying data between gdb and process 2418
Reading symbols from /lib/ld-linux.so.2...done.
Reading symbols from /usr/lib/debug/lib/ld-2.11.2.so.debug...done.
Loaded symbols for /lib/ld-linux.so.2
[Switching to Thread 2418]
0x001f2850 in _start () from /lib/ld-linux.so.2
(gdb)
注意vgdb是valgrind自带的,不用额外安装
如果vgdb检测到有多个valgrind gdbserver等待连接,它将列出这些servers和他们的PIDS,然后退出。然后你可以重新使用GDB "target"命令,但是要指明你要调试的进程的PID。
(gdb) target remote | vgdb
Remote debugging using | vgdb
no --pid= arg given and multiple valgrind pids found:
use --pid=2479 for valgrind --tool=memcheck --vgdb=yes --vgdb-error=0 ./prog 
use --pid=2481 for valgrind --tool=memcheck --vgdb=yes --vgdb-error=0 ./prog 
use --pid=2483 for valgrind --vgdb=yes --vgdb-error=0 ./another_prog 
Remote communication error: Resource temporarily unavailable.
(gdb) target remote | vgdb --pid=2479
Remote debugging using | vgdb --pid=2479
relaying data between gdb and process 2479
Reading symbols from /lib/ld-linux.so.2...done.
Reading symbols from /usr/lib/debug/lib/ld-2.11.2.so.debug...done.
Loaded symbols for /lib/ld-linux.so.2
[Switching to Thread 2479]
0x001f2850 in _start () from /lib/ld-linux.so.2
(gdb)


一旦GDB连接到valgrind gdbserver,它就和本地调试没有差别了:
×设置/删除断点
×查看/修改变量和寄存器
×配置信号处理函数(printing, ignoring)
×控制执行(continue,step,next,stepi等)
×通过Ctrl-C来中断程序
等等,参照GDB手册来了解GDB详细功能

3.2.4. Connecting to an Android gdbserver

当为android开发应用是,通常会用一个dev环境(这个环境安装了Andriod NDK)来编译你的应用。用一个Andriod目标系统或模拟器来运行程序。在这个setup中,Valgrind和vgdb将会安装到Andriod系统中。而GDB将会在dev环境中运行。GDB将会通过Andriod NDK'abd forward'连接到Andriod系统中正在运行的vgdb。
例如:在Andriod系统中,执行下面命令
valgrind --vgdb-error=0 --vgdb=yes prog
# and then in another shell, run:
vgdb --port=1234
在dev环境中,执行下面命令
adb forward tcp:1234 tcp:1234
gdb prog
(gdb) target remote :1234
GDB将会用一个本地tcp/ip连接来连接到Andriod abd forwarder。Adb将会在host system和Andriod target system之间建立一个中转连接。一定要确保GDB包含在Andriod NDK system中(通常,arm-linux-androideabi-gdb),因为host中的gdb有可能无法debugAndroid arm application。注意本地端口nr(gdb使用)不必一定等于vgdb使用的端口号:abd可以在不用的端口号之间转发 tcp/ip。
在当前release版本中,gdb server默认不支持Android,这是由于在建立一个合适的文件夹用来让valgrind创建用于通信目的FIFOs(命名管道)时会出问题。然而你仍然可以试着使用gdb sever,但是你需要明确使用"--vgdb=yes"或"--vgdb=full"来enable它。
除此之外,你需要指定一个临时文件夹,它必须(a)valgrind有写的权限,(b)支持FIFOs。这就是主要难点。通常/sdcard满足条件(a),但是不满足(b),这是由于它是一个VFAT文件系统,VFAT文件系统不支持管道。有可能的话,你可以试试 /data/local, /data/local/Inst(如果你把valgrind安装到这里),或者/data/data/name.of.my.app,如果你正在运行某个特定的应用,并且它有属于自己的支持那种格式的文件夹。最后的可能是最有希望成功的。
你可以通过1)-width-tmpdir=编译时的option或者2)当运行valgrind时设定环境变量TMPDIR(在Android设备上,不是在Android NDK开发机)指定临时文件夹.另一个办法是用--vgdb-prefix= valgrind命令行option来指定一个用于FIFOs的文件夹。
我们希望在临时文件夹处理上会有一个更好的方案。难点在于,不像标准Unixes,不存在一个临时文件夹可以在所有设备/场景下都能可靠的工作。

3.2.5. Monitor command handling by the Valgrind gdbserver

valgrind gdbserver通过monitor commands提供基于valgrind-specific的额外功能。这些monitor commands可以通过GDB命令行发送,或者通过shell,或者更由client程序使用VALGRIND_MONITOR_COMMAND请求。查看valgrind monitor commands(http://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.valgrind-monitor-commands)来获得独立于选择的algrind tool的valgrind core monitor命令列表。
下列的tools提供tool-specific monitor commands
  • Memcheck Monitor Commands

  • Callgrind Monitor Commands

  • Massif Monitor Commands

一个tool-specific monitor command的例子是memcheck monitor command:leak_check full reachable any。它要求一个完整的内存分配报告。使用gdb命令来获得这个报告:

(gdb) monitor leak_check full reachable any

GDB把leak_check命令发送到valgrind gdbserver。如果它识别出这个字符串是一个valgrind core monitor command,valgrind gdbserver将会执行monitor命令。如果没有识别出这个命令,它就假设这个字符串是tool-specific,将会交给tool执行。例如:

(gdb) monitor leak_check full reachable any
==2418== 100 bytes in 1 blocks are still reachable in loss record 1 of 1
==2418==    at 0x4006E9E: malloc (vg_replace_malloc.c:236)
==2418==    by 0x804884F: main (prog.c:88)
==2418== 
==2418== LEAK SUMMARY:
==2418==    definitely lost: 0 bytes in 0 blocks
==2418==    indirectly lost: 0 bytes in 0 blocks
==2418==      possibly lost: 0 bytes in 0 blocks
==2418==    still reachable: 100 bytes in 1 blocks
==2418==         suppressed: 0 bytes in 0 blocks
==2418== 
(gdb) 
除了GDB命令,valgrind gdbserver也会接受缩写的monitor命令和参数,只要这些缩写不产生歧义。例如上面的leak_check命令可以写为:

(gdb) mo l f r a
mo被GDB识别为monitor的缩写。所以GDB发送字符串l f r a给valgrind gdbserver。字符串中的缩写对于valgrind gdbserver没有歧义。所以结果与之前的一致。如果缩写有歧义,valgrind gdbserver将会列出匹配的命令(参数)列表:

(gdb) mo v. n
v. can match v.set v.info v.wait v.kill v.translate v.do
(gdb) mo v.i n
n_errs_found 0 n_errs_shown 0 (vgdb-error 0)
(gdb)
除了从GDB发送monitor命令,你也可以从shell命令行发送命令。例如下面命令行,在shell中,将会在进程3415中执行同样的leak search。

vgdb --pid=3145 leak_check full reachable any
vgdb --pid=3145 l f r a

注意在一个单独的vgdb命令后,valgrind gdbserver会自动继续程序的执行。有gdb发送的monitor commands不会导致程序的继续执行:程序有gdb命令控制,例如continue/next。


3.2.6. Valgrind gdbserver thread information

valgrind的gdbserver通过valgrind-specific提供的信息使gdb的"info threads"命令的结果更丰富。操作系统的线程号后跟随valgrind的内部index,以及valgrind线程调度状态“
(gdb) info threads
  4 Thread 6239 (tid 4 VgTs_Yielding)  0x001f2832 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
* 3 Thread 6238 (tid 3 VgTs_Runnable)  make_error (s=0x8048b76 "called from London") at prog.c:20
  2 Thread 6237 (tid 2 VgTs_WaitSys)  0x001f2832 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
  1 Thread 6234 (tid 1 VgTs_Yielding)  main (argc=1, argv=0xbedcc274) at prog.c:105
(gdb) 

3.2.7. Examining and modifying Valgrind shadow registers


当指定--vgdb-shadow-register=y选项时,valgrind gdbserver将会运行gdb查看/修改valgrind的shadow registers。要求gdb7.1或更高版本。对于x86和amd64,要求gdb7.2或更高版本。

对于每个CPU寄存器,valgrind core维护两组shadow register。这些shadow registers可以通过给定gdb一个后缀s1/s2来获得相应的第一/第二组shadow register。例如,x86寄存器eax和它的两个shadows可以用下面的命令获得。

(gdb) p $eax
$1 = 0
(gdb) p $eaxs1
$2 = 0
(gdb) p $eaxs2
$3 = 0
(gdb) 

float shadow registers在gdb中有unsigned int值代替float值,由于使用这些shadow value来做bit的memcheck。

Intel/amd64 AVX寄存器ymm0~ymm15同样也有他们的shadow registers。然而,gdb把这些shadow alues表示成两个half寄存器。例如。ymm9的half registers是xmm9s1(第一组低位),ymm9hs1是(第一组高位),xmm9s2(第二组低位),ymm9hs2(第二组高位)。

注意half registers的命名规则:低位部分以x开始,高位部分以y开始并且以h+shadow后缀结束。

AVX shadow registers以这种特殊的形式出现的原因是gdb独立分别ymm registers的低位/高位部分。GDB不知道shadow half registers必须以联合的方式显示。


3.2.8. Limitations of the Valgrind gdbserver

使用valgrind gdbserver来debug程序和本地debug类似。valgrind的gdbserver实现非常完整,并且他也提供了gdb的大部分调试功能。但是也有些限制和特点:

×Precision of "stop-at" commands
GDB命令例如"step", "next", "stepi",断点和监视点(watchpoint),将会停止程序的执行。在使用--vgdb=yes时,进程也许不会停在指定的地方。相反,它会继续执行当前的basic block(基本阻塞),并且会停在跟在这个basic block之后的basic block中。这是因为valgrind gdbserver必须注入一个block来允许停在一个指定的指令上。目前,不支持注入正在执行的block这项功能。所以,如果gdb要求的动作(例如单步/插入断点)隐含修改当前block的要求,gdb的动作也许不会准确执行。
当正在被执行的block还没被debug修改指令时,这个限制就发挥作用了。他通常发生在gdbsever由于tool报告一个错误或一个watchpoit而被激活时。如果gdbserver block(阻塞)激活并且后面跟随一个断点,或者一个断点在block执行前已经插入,那么该block已经修改为可以debug了。
如果使用--vgdb=full,那么gdb "stop-at"命令将会准确执行。其负面作用就是每个指令都修改为附带一个额外的gdbserver helper函数调用,将会产生很大的负载(对于memcheck是+500%)相对于--vgdb=no。--vgdb=yes产生的负载可以忽略。


×寄存器和标志位

当一个gdbserver由于错误而停止,或者由于断点或单步,由于valgrind core做的优化,导致寄存器和标志位不能总是同步更新。默认值--vex-iropt-register-updates=unwindregs-at-mem-access确保寄存器需要做stack trace(典型PC/SP/FP)更新(例如异常点)。使用下面的值来禁止一些优化将会增加寄存器/标志位的准确性(但是也会影响性能,用memcheck为例)。

  • --vex-iropt-register-updates=allregs-at-mem-access (+10%) 保证每次访问内存时标志位和寄存器都更新过。
    • --vex-iropt-register-updates=allregs-at-each-insn (+25%) 保证执行每条指令时标志位和寄存器都更新
    • 注意--vgdb=full(+500%)自动激活--vex-iropt-register-updates=allregs-at-each-insn.

    • ×valgrind gdbserver支持的硬件断点
    • valgrind可以模拟硬件断点,如果选择的工具支持。目前为止,只有memcheck tool支持模拟硬件断点。由memcheck提供的硬件断点比gdb的watchpoit更快,gdb的watch point是通过gdb在每条指令后检查监视zone来实现的。硬件断点模拟器同时支持读watchpoint。相比较真正的hardware watchpoint,memcheck模拟的watchpoint也有一些限制。但是模拟器提供的断点数目和长度没有限制。

通常,真正的硬件断点的数量是有限制的。例如,x86架构最多支持4个hardware watchpoint。每个watchpoint监视1,2,4,8字节。valgrind gdbserver没有模拟断点的数目限制。同时不限制监视zone的长度。使用gdb7.4或以后的版本可以获得valgrind gdbserver模拟硬件断点的完整的灵活性。更早的版本不支持gdbserver watchpoint不限制长度的功能。
memcheck通过把监视的zone标记为不可寻址来实现硬件断点。当一个硬件断点被删除,该区域又变为可寻址&已定义。硬件断点的"模拟可寻址但是未定义内存zone"这种模式可以工作的很好,但是有一个不希望的副作用--当watchpoint删除后,该zone又变成已定义。
写断点也许不会在在如被监视的区域的那条指令上停止程序执行,除非指定--vgdb=full。读指令总之会在读的指令上停止执行。
最好避免在还未可寻址的内存上使用硬件watchpoint:在这种情况下,gdb将会退化到及其慢的software watchpoint上。同时,如果你在两个gdb session间不退出gdb,如果监视区域不可寻址,在程序开始时,前一个session的硬件断点会被当作software watchpoint插入。

×多次断点
一些指令(例如x86,"rep movsb")被valgrind转换成一个循环。如果在这些指令上下断点,断点将会执行多次。

×在valgrind gdbserver上执行函数
gdb允许user在被调试的进程内调用函数。这些函数在gdb术语中叫做"inferior calls"。一个典型的例子就是执行一个把复杂数据结构转换成可读格式的函数。要使用这种inferior call,使用gdb的print命令后面跟着要调用的函数以及参数。例如,下面的gdb命令调用print函数来获得被调试的进程id。
(gdb) p printf("process being debugged has pid %d\n", getpid())
$5 = 36
(gdb) 
注:运行结果不是在gdb中显示,而是在gdbserver中显示。
valgrind gdbserver支持inferior calls。但一个inferior call运行时,valgrind tool将会正常报告错误。如果你不希望这些错误阻止inferior call的执行,可以在调用函数之前使用v.set vgdb-error来设置一个很大的数,然后当函数执行完成后,再把它设回原来的数值。
要执行inferior calls,gdb改变程序计数器(pc),然后继续程序的执行。在一个多线程的程序中,所有线程继续执行,而不仅仅是注入inferior call的那个线程。如果其他的另一个线程报告一个错误或者遇到断点,inferior call的值将会废弃。
inferior是gdb的有效工具,但应该小心使用。例如如果被调试的程序在printf函数内部停止,通过强制使用inferior call来递归调用printf函数将会出问题。valgrind tool也许对inferior call又增加一层复杂性,例如在inferior call时报告错误或者由于注入指令执行完成。

×连接到或者中断一个阻塞在系统调用中的valgrind进程
连接到或者中断一个阻塞在系统调用中的valgrind进程要求使用ptrace系统call。也许由于安全原因,这个system call被禁止了。
当运行程序,valgrind的scheduler周期检查是否有需要gdbserver处理的工作。不幸的是,这种检查只在至少有一个线程runnable时才进行。如果所有的线程都被system call阻塞注了,那么检查就不会进行,并且valgrind sheduler不会唤醒gdbserver。这种情况下,vdgb reply应用将会"强制"唤醒gdbserver,不通过valgrind sheduler的介入。
这种强制唤醒valgrind gdbserver由vgdb使用ptrace system call来实现。在一个实现恰当的内核中,ptrace call由vgdb处理,不会影响运行在valgrind上的程序。如果影响了,vgdb的--max-invoke-ms=0参数将会禁止使用ptrace call。禁止在vgdb中使用ptrace call的后果就是如果一个valgrind进程阻塞在一个system call中,将不会由gdb唤醒或中断直到他执行了足够的basic blocks后由valgrind scheduler的基本检查来使其生效。
当在vgdb中禁止ptrace后,你可以增加valgrind gdbserver到命令的相应,或通过给--vgdb-poll一个较低的值来中断。如果你的程序大部分时间都阻塞在system call中,给--vgdb-poll一个较低的值将会让gdbserver更快唤醒。由valgrind scheduler实现gdbserver的polling非常有效,所以增加polling频率不会产生明显的性能下降。
当在vgdb中禁止ptrace,valgrind gdbserver处理一个由gdb发送的packet将会花费更长的时间。在这种情况下,gdb也许会遇到协议timeout。为了避免这种情况,可以通过gdb命令"set remotetimeout"增加timeout。
Ubuntu 10.10和以后的版本将会限制的调用ptrace的进程的子进程的ptrace范围。由于valgrind进程不是vgdb的子进程,这种限制会导致ptrace call失败。为了避免这种情况,valgrind自动允许属于同一个userid的所有进程都可以ptrace一个valgrind进程,通过使用PR_SET_PTRACER。

×改变寄存器值

只有当线程的状态时runnable或者yielding时,valgrind gdbserver才会改变线程的寄存器的值。在其他状态(例如WaitSys),不会改变寄存器的值。除了其他不谈,这意味着当一个线程处于system call中时,inferior call不会执行,因为valgrind gdbserver不实现重新开始system call。


3.2.9. vgdb command line options

Usage: vgdb [OPTION]... [[-c] COMMAND]...

vgdb("Valgrind to GDB")是一个小程序,被用作一个valgrind和gdb/shell中转站。所以它有两种模式:
作为一个独立的应用,它被用作shell命令行,用来发向一个运行在valgrind中的进程送监视命令。对于这种用法,vgdb option后面必须跟随要发送的监视命令。如果要发送多于一个命令,用-c option分割他们。
结合gdb "target remote |"命令使用,他被用作gdb和valgrind gdbserver之间的中转application。对于这种用法,只能附带option,不能给它命令。

vgdb 接收下面命令:

--pid=<number>
指定vgdb要连接的进程的pid。当与多于一个可以被连接的valgrind gdbserver时,这个option很有用。如果没有给出--pid这个参数并且有多个gdbserver在运行时,vgdb将会列出这些进程,退出。
--vgdb-prefix
如果你想改变用于valgrind gdbserver和gdb之间通信的默认的FIFOs前缀,必须在valgrind和vgdb中同时给出。
--wait=<number>
告诉vgdb在指定时间内搜寻可用的valgrind gdbserver。这个使先启动vgdb进程,后启动希望与vgdb进程沟通的valgrind gdbserver进程成为可能。这个option与--vgdb-prefix结合使用,用于与一个特定的进程通信。同时,如果你想在gdb "target remote"中用--wait参数是,你必须给GDB remotetimeout设定一个比--wait参数更大的值。参考--max-invoke-ms
--max-invoke-ms=<number>
给定毫秒数,经过给定时间后,vgdb会强迫唤醒valgrind中的gdbserver。默认的时间是100ms。0禁止唤醒。强制唤醒用于当vgdb连到valgrind gdbserver,以及valgrind进程都阻塞于一个system call时。
如果你指定了一个较大的值,你需要增加GDB "remotetimeout"值,默认值为2s。你要确保超时时间大于--max-invoke-ms值。例如,--max-invoke-ms=5000,下面的gdb命令就比较合适:
    (gdb) set remotetimeout 6

--cmd-time-out=<number>
告诉一个单独的vgdb如果在指定时间内它连接的valgrind gdbserver没有处理该命令时,它就退出。默认从不超时。
--port=<portnr>
告诉vgdb使用tcp/ip并且在nr端口监听gdb,而不是使用一个pipe与gdb通信。使用tcp/ip使在一台机器上的gdb可以调试另一台机器上的valgrind进程。例如:
# On the target computer, start your program under valgrind using
valgrind --vgdb-error=0 prog
# and then in another shell, run:
vgdb --port=1234
在另一台机器上gdb,执行:
gdb prog
(gdb) target remote targetip:1234
targetip是目标ip或hostname
-c
用于在独立模式中给一个vgdb命令多个命令时,用-c分割命令
vgdb v.set log_output -c leak_check any
-l
告诉独立模式的vgdb报告正在运行在valgrind gdbserver进程列表,退出。
-D
告诉独立模式的vgdb显示valgrind gdbserver使用共享内存的情况。vgdb在显示完共享内存状态后退出。
-d
告诉vgdb输出debug信息。用多个-d args来详细显示信息。如果给中转vgdb一个-d,最好将stderr重定向到一个文件,以避免gdb和vgdb调试信息的交叉。

3.2.10. Valgrind monitor commands

monitor命令可以从命令行使用独立模式的vgdb发送,或者从gdb使用monitor命令发送。也可以被客户端程序创建,使用VALGRIND_MONITOR_COMMAND客户端请求。
help [debug] instructs Valgrind's gdbserver to give the list of all monitor commands of the Valgrind core and of the tool. The optional "debug" argument tells to also give help for the monitor commands aimed at Valgrind internals debugging.

  • v.info all_errors shows all errors found so far.

  • v.info last_error shows the last error found.

  • v.info n_errs_found [msg] 用于显示到目前为止发现的错误,到目前为止显示nr个错了,并且当前的--vgdb-error参数。option msg(一个或多个words)是附加的。典型的,它用于在几个执行的测试程序中,在一个进程的输出文件中插入marker。用于将algrind产生的错误报告关联到产生这些错误的测试中。

  • v.info open_fds shows the list of open file descriptors and details related to the file descriptor. This only works if --track-fds=yes was given at Valgrind startup.

  • v.set {gdb_output | log_output | mixed_output} allows redirection of the Valgrind output (e.g. the errors detected by the tool). The default setting is mixed_output.

    With mixed_output, the Valgrind output goes to the Valgrind log (typically stderr) while the output of the interactive GDB monitor commands (e.g. v.info last_error) is displayed by GDB.

    With gdb_output, both the Valgrind output and the interactive GDB monitor commands output are displayed by GDB.

    With log_output, both the Valgrind output and the interactive GDB monitor commands output go to the Valgrind log.

  • v.wait [ms (default 0)] instructs Valgrind gdbserver to sleep "ms" milli-seconds and then continue. When sent from a standalone vgdb, if this is the last command, the Valgrind process will continue the execution of the guest process. The typical usage of this is to use vgdb to send a "no-op" command to a Valgrind gdbserver so as to continue the execution of the guest process.

  • v.kill requests the gdbserver to kill the process. This can be used from a standalone vgdb to properly kill a Valgrind process which is currently expecting a vgdb connection.

  • v.set vgdb-error <errornr> dynamically changes the value of the --vgdb-error argument. A typical usage of this is to start with --vgdb-error=0 on the command line, then set a few breakpoints, set the vgdb-error value to a huge value and continue execution.

下面的命令用于调查在有错误/bug的情况下valgrind的行为或gdbserver

  • v.do expensive_sanity_check_general executes various sanity checks. In particular, the sanity of the Valgrind heap is verified. This can be useful if you suspect that your program and/or Valgrind has a bug corrupting Valgrind data structure. It can also be used when a Valgrind tool reports a client error to the connected GDB, in order to verify the sanity of Valgrind before continuing the execution.

  • v.info gdbserver_status shows the gdbserver status. In case of problems (e.g. of communications), this shows the values of some relevant Valgrind gdbserver internal variables. Note that the variables related to breakpoints and watchpoints (e.g. the number of breakpoint addresses and the number of watchpoints) will be zero, as GDB by default removes all watchpoints and breakpoints when execution stops, and re-inserts them when resuming the execution of the debugged process. You can change this GDB behaviour by using the GDB command set breakpoint always-inserted on.


  • v.info memory [aspacemgr] shows the statistics of Valgrind's internal heap management. If option --profile-heap=yes was given, detailed statistics will be output. With the optional argument aspacemgr. the segment list maintained by valgrind address space manager will be output. Note that this list of segments is always output on the Valgrind log.

(gdb) monitor v.info memory aspacemgr

--27375-- core    :  8388608/ 8388608  max/curr mmap'd, 0/0 unsplit/split sb unmmap'd,    147696/  128216 max/curr,       14664/   7423296 totalloc-blocks/bytes,       15142 searches 4 rzB
--27375-- dinfo   : 17973248/13873152  max/curr mmap'd, 4/2 unsplit/split sb unmmap'd,  16277440/11823864 max/curr,      114215/  40973672 totalloc-blocks/bytes,      114523 searches 4 rzB
--27375-- client  :        0/       0  max/curr mmap'd, 0/0 unsplit/split sb unmmap'd,         0/       0 max/curr,           0/         0 totalloc-blocks/bytes,           0 searches 20 rzB
--27375-- demangle:        0/       0  max/curr mmap'd, 0/0 unsplit/split sb unmmap'd,         0/       0 max/curr,           0/         0 totalloc-blocks/bytes,           0 searches 4 rzB
--27375-- ttaux   :    65536/   65536  max/curr mmap'd, 0/0 unsplit/split sb unmmap'd,     39312/   27792 max/curr,         265/     71208 totalloc-blocks/bytes,         265 searches 4 rzB


在gdbserver中显示更多log信息:

--27375:0:aspacem  >>>
--27375:0:aspacem  <<< SHOW_SEGMENTS: gdbserver v.info memory aspacemgr (65 segments, 12 segnames)
--27375:0:aspacem  ( 0) /usr/local/lib/valgrind/memcheck-x86-linux
--27375:0:aspacem  ( 1) /usr/bin/perl
--27375:0:aspacem  ( 2) /lib/i386-linux-gnu/ld-2.15.so

……
--27375:0:aspacem   63: ANON 00bffdf000-00bfffffff  135168 rw---
--27375:0:aspacem   64: RSVN 00c0000000-00ffffffff   1024m ----- SmFixed
--27375:0:aspacem  >>>




  • v.info exectxt shows informations about the "executable contexts" (i.e. the stack traces) recorded by Valgrind. For some programs, Valgrind can record a very high number of such stack traces, causing a high memory usage. This monitor command shows all the recorded stack traces, followed by some statistics. This can be used to analyse the reason for having a big number of stack traces. Typically, you will use this command if v.info memory has shown significant memory usage by the "exectxt" arena.

  • v.info scheduler shows the state and stack trace for all threads, as known by Valgrind. This allows to compare the stack traces produced by the Valgrind unwinder with the stack traces produced by GDB+Valgrind gdbserver. Pay attention that GDB and Valgrind scheduler status have their own thread numbering scheme. To make the link between the GDB thread number and the corresponding Valgrind scheduler thread number, use the GDB command info threads. The output of this command shows the GDB thread number and the valgrind 'tid'. The 'tid' is the thread number output by v.info scheduler. When using the callgrind tool, the callgrind monitor command status outputs internal callgrind information about the stack/call graph it maintains.

(gdb) monitor  v.info scheduler
sched status:
  running_tid=1
Thread 1: status = VgTs_Runnable
==27375==    at 0x40011C0: ??? (in /lib/i386-linux-gnu/ld-2.15.so)

  • v.set debuglog <intvalue> sets the Valgrind debug log level to <intvalue>. This allows to dynamically change the log level of Valgrind e.g. when a problem is detected.

  • v.translate <address> [<traceflags>] shows the translation of the block containing address with the given trace flags. The traceflags value bit patterns have similar meaning to Valgrind's --trace-flags option. It can be given in hexadecimal (e.g. 0x20) or decimal (e.g. 32) or in binary 1s and 0s bit (e.g. 0b00100000). The default value of the traceflags is 0b00100000, corresponding to "show after instrumentation". The output of this command always goes to the Valgrind log.The additional bit flag 0b100000000 (bit 8) has no equivalent in the --trace-flags option. It enables tracing of the gdbserver specific instrumentation. Note that this bit 8 can only enable the addition of gdbserver instrumentation in the trace. Setting it to 0 will not disable the tracing of the gdbserver instrumentation if it is active for some other reason, for example because there is a breakpoint at this address or because gdbserver is in single stepping mode.








你可能感兴趣的:(Debugging your program using Valgrind gdbserver and GDB)