其他调试工具和调试多线程程序
转自 http://blog.csdn.net/todd911/article/details/36190953
下面是于线程相关的GDB命令用法汇总:
info threads:给出关于当前所有线程的信息。
thread 3:改成线程3.
break 88 thread 3 :当线程到达源代码88时停止执行。
break 88 thread 3 if i == 2 当线程3到达源代码行88行,并且变量i的值为2时停止执行。
对下面的多线程进行调试:
#include <stdio.h> #include <pthread.h> #include <string.h> #include <unistd.h> void* thr_fn(void* arg) { int i; for (i=0; i<5; i++) { printf("in thread%d,i=%d\n",*(int*)arg,i); sleep(1); } return (void*)0; } int main(void) { int ret; pthread_t tid1, tid2; int t1_para = 1; int t2_para = 2; ret = pthread_create(&tid1, NULL, thr_fn, (void*)&t1_para); if (ret != 0) { printf("thread1 pthread_create:%s\n",strerror(ret)); return 1; } ret = pthread_create(&tid2, NULL, thr_fn, (void*)&t2_para); if (ret != 0) { printf("thread1 pthread_create:%s\n",strerror(ret)); return 1; } pthread_join(tid1, NULL); pthread_join(tid2, NULL); return 0; }
调试结果:
(gdb) b main
Breakpoint 1 at 0x4006d9: file pthread.c, line 20.
(gdb) r
Starting program: /home/yanwenjie/ctest/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at pthread.c:20
warning: Source file is more recent than executable.
20 int t1_para = 1;
(gdb) n
21 int t2_para = 2;
(gdb)
23 ret = pthread_create(&tid1, NULL, thr_fn, (void*)&t1_para);
(gdb)
[New Thread 0x7ffff77fc700 (LWP 5366)]
in thread1,i=0
24 if (ret != 0) {
(gdb)
29 ret = pthread_create(&tid2, NULL, thr_fn, (void*)&t2_para);
(gdb)
[New Thread 0x7ffff6ffb700 (LWP 5367)]
in thread2,i=0
30 if (ret != 0) {
(gdb) info threads
Id Target Id Frame
3 Thread 0x7ffff6ffb700 (LWP 5367) "a.out" 0x00007ffff78bd08d in nanosleep
() from /lib/x86_64-linux-gnu/libc.so.6
2 Thread 0x7ffff77fc700 (LWP 5366) "a.out" 0x00007ffff78bd08d in nanosleep
() from /lib/x86_64-linux-gnu/libc.so.6
* 1 Thread 0x7ffff7fe3700 (LWP 5363) "a.out" main () at pthread.c:30
(gdb) break 10 thread 3 if i==3
Breakpoint 2 at 0x400699: file pthread.c, line 10.
(gdb) c
Continuing.
in thread2,i=1
in thread1,i=1
in thread1,i=2
in thread2,i=2
in thread1,i=3
[Switching to Thread 0x7ffff6ffb700 (LWP 5367)]
Breakpoint 2, thr_fn (arg=0x7fffffffe048) at pthread.c:10
10 printf("in thread%d,i=%d\n",*(int*)arg,i);
(gdb) p i
$1 = 3
(gdb) thread 2
[Switching to thread 2 (Thread 0x7ffff77fc700 (LWP 5366))]
#0 0x00007ffff78bd08d in nanosleep () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) n
Single stepping until exit from function nanosleep,
which has no line number information.
in thread2,i=3
0x00007ffff78bcf2c in sleep () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) break 10 thread 3
Note: breakpoint 2 (thread 3) also set at pc 0x400699.
Breakpoint 3 at 0x400699: file pthread.c, line 10.
(gdb) c
Continuing.
in thread1,i=4
[Switching to Thread 0x7ffff6ffb700 (LWP 5367)]
Breakpoint 3, thr_fn (arg=0x7fffffffe048) at pthread.c:10
10 printf("in thread%d,i=%d\n",*(int*)arg,i);
(gdb) p i
$2 = 4
(gdb) p arg
$3 = (void *) 0x7fffffffe048
(gdb) p *(int*)arg
$4 = 2
(gdb)
2.使用其他调试工具
1.splint //这个对代码检查功能更强大,但是出错和警告提示比较难看, //不太方便
splint是一个开源的静态代码检查工具,使用方法如下:
待检测的程序程序如下:
[cpp] view plaincopy
- #include <stdio.h>
- static void display(int i)
- {
- printf("i = %d\n",i);
- }
- int main(void)
- {
- int i,j;
- i = 1;
- i = i + 1;
- display(i);
- return 0;
- }
调试如下:
$ splint main.c
Splint 3.1.2 --- 03 May 2009
main.c: (in function main)
main.c:10:8: Variable j declared but not used //这个也要提示,,估计gcc 也可以的,只是没 //有设置开启
A variable is declared but never used. Use /*@unused@*/ in front of
declaration to suppress message. (Use -varuse to inhibit warning)
Finished checking --- 1 code warning
提示定义了一个变量j但是从来没有使用过。
将j定义去掉后,再进行检测:
$ splint main.c
Splint 3.1.2 --- 03 May 2009
Finished checking --- no warnings
splint有一大推flag可以使用,使用时标志前加’+‘或’-’,'+'标志开启这个标志,'-'表示关闭此标志。
下列语句用于检查程序中数据的越界问题。
splint +bounds main.c //这个不错
2.strace //这个不太好看
strace常用来跟踪进程执行时的系统调用和所接收的信号。
对上面的程序进行追踪测试:
$ strace ./a.out
execve("./a.out", ["./a.out"], [/* 50 vars */]) = 0
brk(0) = 0x1033000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f64fa550000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=77020, ...}) = 0
mmap(NULL, 77020, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f64fa53d000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200\30\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1815224, ...}) = 0
mmap(NULL, 3929304, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f64f9f70000
mprotect(0x7f64fa125000, 2097152, PROT_NONE) = 0
mmap(0x7f64fa325000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b5000) = 0x7f64fa325000
mmap(0x7f64fa32b000, 17624, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f64fa32b000
close(3) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f64fa53c000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f64fa53b000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f64fa53a000
arch_prctl(ARCH_SET_FS, 0x7f64fa53b700) = 0
mprotect(0x7f64fa325000, 16384, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ) = 0
mprotect(0x7f64fa552000, 4096, PROT_READ) = 0
munmap(0x7f64fa53d000, 77020) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f64fa54f000
write(1, "i = 2\n", 6i = 2
) = 6
exit_group(0) = ?
3.ltrace //这个也不懂怎么看
ltrace用来跟踪进程调用库函数的情况。
对上面的程序进行追踪测试:
$ ltrace ./a.out
__libc_start_main(0x400518, 1, 0x7ffff364a1a8, 0x400550, 0x4005e0 <unfinished ...>
printf("i = %d\n", 2i = 2
) = 6
+++ exited (status 0) +++