作者:张华 发表于:2015-05-05
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明
( quqi99的博客_CSDN博客-OpenStack Networking,Linux Application,OpenStack Non-Networking领域博主 )
人啊,总要不断地与记忆作斗争。
1, 加-g参数编译可执行性文件, 如果没有-g,你将看不见程序的函数名、变量名,所代替的全是运行时的内存地址。
cc -g test.c -o test
静态检查程序错误,splint test.c
单元测试可使用CUnit, gcc -o test.o -I /usr/local/include/CUnit -L /usr/local/lib/ -g testcase.c -l cunit ./test.o
若是要调试master可以下载源码用./configure前加上CFLAGS="-Wall -O2 -g"即可编译。若是ubuntu repo里已经有的package,则直接安装dbg即可编译(没有dbg包时可次优选择dbgsym包)。
2, 启动gdb, gdb test
启动GDB的方法有以下几种:
a、gdb <program>
program也就是你的执行文件,一般在当然目录下。
b、gdb <program> core
用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。
如果产生coredump呢? 需要执ulimit -c unlimited才可以(缺省是coredump文件大小是0字节所以它不生成)。
并不是所有的异常都会生成coredump文件,附录1是一个运行异常时会产生coredump文件的例子。
运行后coredump文件产生在当前文件夹的core文件中。分析它: gdb ./test ./core, 如下显示了是哪一句出了错误:
(gdb) bt
#0 0x000000000040054d in core_dump () at test.c:5
#1 0x0000000000400585 in main () at test.c:10
c、gdb <program> <PID>
通过sudo gdb启动gdb后直接attach <PID>可以attach到正在运行的程序,当然程序得加-g参数编译的。
3, 一些常用gdb命令
l, 列出源代码
- break 16, 第16行设置断点
- b fn1 if a>b, 条件设置断点
- break func, 在函数的入口处设置断点
- delete/disable/enable/clear 16, 删除第16个断点
- delete breakpoints,清除所有断点
- info break, 查看断点
- r, 运行程序,到断点处处时会停止运行等待用户输入(run), 在gdb中正常结束的程序也可以用此命令重新运行
- n, 单步执行(next)
- s, 进入函数(step)
- c, 继续运行(continue), 到下一个断点处
- p <variable>, 打印变量的值
- set var i=1, 修改变量的值
- info registers, 查看寄存器
- bt, 查看函数堆栈
- call 函数(参数),调用程序中可见的函数,并传递“参数”,如:call gdb_test(55)
- display 表达式:在单步运行时将非常有用,它将在每次单步进行指令后,紧接着输出被设置的表达式及值。如: display a
- watch 表达式:设置一个监视点,一旦被监视的“表达式”的值改变,gdb将强行终止正在被调试的程序。如:watch a
- q, 退出
4, 使用GDB调试多进程程序, https://www.ibm.com/developerworks/cn/linux/l-cn-gdbmp/
5, 使用cgdb可以很方便的查看代码。
6, 性能分析, 比如哪个函数调用了多少次,被谁调用了, 平均每次调用花费多少时间等。这时候要用gprof,gprof是分析profile输出的。
要想执行时输出profile文件编译时要加-pg选项, gcc -o helloworld.o -pg -g helloworld.c
执行上面语句后会在当前目录下生成gmon.out文件, 然后用gprof去读取并显示出来,gprof -b -A -p -q helloworld.o gmon.out >prof_info.txt
7, gdb也可以调试go语言的程序,采用”go build -gcflags "-N -l" test.go“编译,再'gdb test"即可。可能相比于C会多出一个‘info goroutines’命令。
附录1, 产生coredump文件的例子
#include <stdio.h>
int core_dump() {
int i;
for (i = 5; i >= 0; i--) {
printf("(%d, %d)\n", i, 100 / i);
}
return 0;
}
int main() {
core_dump();
return 0;
}
附录2, 如何分析CoreDump文件
1, 安装dbgsym,注意安装的是librados2-dbg librbd1-dbg, 而不是librados2-dbgsym librbd1-dbgsym. (注意:有dbg内建包时优先安装dbg包,没有时才安装dbgsym非内建包,这点异常重要,否则会造成gdb调试时缺失符号表,这个网页有解释: https://wiki.ubuntu.com/DebuggingProgramCrash#Debug_Symbol_Packages)
echo "deb http://ddebs.ubuntu.com $(lsb_release -cs) main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/debuginfo_debs.list
echo "deb http://ddebs.ubuntu.com $(lsb_release -cs)-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/debuginfo_debs.list
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C8CAB6595FDFF622
sudo apt update
sudo apt-get install qemu-system-x86-dbgsym librados2-dbg librbd1-dbg
For example: /usr/lib/x86_64-linux-gnu/libstdc++.so.6 and the debugging version is at /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6
(gdb) set debug-file-directory /usr/lib/x86_64-linux-gnu/debug/
(gdb) directory /xxx/qemu/qemu-2.5+dfsg #sometimes directory doesn't take effect, so use the following line
(gdb) set substitute-path /build/qemu-e2kucK/qemu-2.5+dfsg /xxx/qemu/qemu-2.5+dfsg
(gdb) l
(gdb) info sharedlibrary
2, 解压 - apport-unpack _usr_bin_qemu-system-x86_64.64055.crash ./tmp/
3, 分析CoreDump (确保/usr/bin/qemu-system-x86_64与版本与之一致)
gdb /usr/bin/qemu-system-x86_64 ./tmp/CoreDump
4, 查看堆栈
(gdb) bt 1
#0 malloc_consolidate (av=av@entry=0x7fa810000020) at malloc.c:4175
5, 查看汇编,上面的malloc.c:4175可能由于编译器优化和源代码对不上,所以仍然需要通过编译代码一一比对
(gdb) p $rip
$5 = (void (*)()) 0x7fa84c275470 <malloc_consolidate+336>
(gdb) x/2gi $rip
0x7fa84c275320 <malloc_consolidate>: cmpq $0x0,0x3484d0(%rip) # 0x7fa84c5bd7f8 <global_max_fast>
0x7fa84c275328 <malloc_consolidate+8>: je 0x7fa84c275a8b <malloc_consolidate+1899>
6, 采用汇编理解出错代码,结合源代码辅助分析(因为编译器会优化代码,所以不能完全相信CoreDump中的行号)
注:UCA缺乏debug symbol,例如为trusty上的mitaka uca的qemu包构建debug symbol,因为都是ppa编译的其编译器版本及设置都差不多这样编译出的debug symbol还可以近似地去用。
1, PPA中有"Build debug symbols"的选项(https://launchpad.net/~zhhuabj/+archive/ubuntu/trusty-mitaka-sru/+edit),再在 "Add PPA dependency"里添加"~ubuntu-cloud-archive/+archive/ubuntu/mitaka-staging"
2, 进这个页面(https://launchpad.net/~ubuntu-cloud-archive/+archive/ubuntu/mitaka-staging),点击"View package details" -> "copy packages",在搜索框输入qemu并同时将其后的下拉列表从Published改为Superseded这样就可以选择客户所用的qemu版本。
# trusty doesn't support mitaka uca (sudo add-apt-repository cloud-archive:mitaka), but it supports mitaka-staging
sudo add-apt-repository ppa:ubuntu-cloud-archive/mitaka-staging
sudo add-apt-repository ppa:xxxx
sudo apt update
sudo apt install qemu-system-x86=1:2.5+dfsg-5ubuntu10.16~cloud0
# seems can't use 'apt-cache' to qeury dbgsym in PPA, so change to use wget
wget http://ppa.launchpad.net/xxx/sf177500/ubuntu/pool/main/q/qemu/qemu-system-x86-dbgsym_2.5+dfsg-5ubuntu10.16~cloud0_amd64.ddeb
sudo dpkg -i qemu-system-x86-dbgsym_2.5+dfsg-5ubuntu10.16~cloud0_amd64.ddeb
sudo apt install qemu-system-x86-dbgsym=1:2.5+dfsg-5ubuntu10.16~cloud0
gdb /usr/bin/qemu-system-x86_64 10Apr18-instance-000a2f60-qemu-system-x86_64.core.2003745
#GDB调试
sysctl kernel.core_pattern
sudo service apport start force_start=1 enabled=1
grep enabled /etc/default/apport
sudo killall -SIGSEGV ovs-vswitchd
sudo cat /var/log/apport.log
sudo apt install openvswitch-dbg cgdb
#cgdb $(which ovs-vswitchd) $(pidof ovs-vswitchd)
cgdb ovs-vswitchd /var/crash/_usr_lib_openvswitch-switch_ovs-vswitchd.0.crash
但是上面killall生成coredump的方法会让ovs停掉,下面的不会:
sudo apt install gdb openvswitch-dbg -y
sudo gcore `pidof ovs-vswitchd`
sudo gdb --core ./core.16524 /usr/sbin/ovs-vswitchd
sudo tail -f /var/log/openvswitch/ovs-vswitchd.log | awk '/blocked 1000 ms waiting for main to quiesce/ {system("sudo /usr/bin/gcore `pidof ovs-vswitchd`")}'
thread apply all bt
info proc mapping #query all sysbol tables
sudo /usr/bin/gdb --batch -p $(pidof ovs-vswitchd) --ex bt --ex quit"
更多的gdb 也可参考: set up ovn development env (by quqi99)_quqi99的博客-CSDN博客