如何用gdb调试idea erlang 调试运行期

如何用gdb调试erlang运行期(高级)_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
如何用gdb调试erlang运行期(高级)
阅读已结束,下载文档到电脑
想免费下载更多文档?
定制HR最喜欢的简历
你可能喜欢1928人阅读
linux(37)
原创文章,欢迎转载。转载请注明:转载自淘宝核心系统团队博客,谢谢!
原文链接地址:
下面介绍我调试时经常遇到的三种问题,如果大家也有类似的问题交流一下解决方法:
情景1:在不中止程序服务的情况下,怎么调试正在运行时的程序
情景2:需要同时看几个变量的值或者批量查看多个core文件的堆栈信息怎么办
情景3:遇到需要查看、队列、链表、树、堆等数据结构里的变量怎么办
1. 情景1:在不中止程序服务的情况下,怎么调试正在运行时的程序
我们在生产环境或者测试环境,会遇到一些异常,我们需要知道程序中的变量或者内存的值来确定程序运行状态
之前听过@淘宝褚霸讲过用systemstap可以实现这种功能,但systamstap写起来复杂一些,
还有时候在低内核版本的操作系统上用stap之后,程序或者操作系统都有可能死掉。
看过多隆调试程序时用pstack(修改了pstack代码,用gdb实现的,详见/archives/873)查看和修改一个正在
执行程序的全局变量,感觉很神奇,尝试用gdb实现这种功能:
保存下面代码到文件runstack.sh
&Usage: `basename $0 .sh` &process-id& cmd&
&For exampl: `basename $0 .sh` 1000 bt&
/proc/$1; then
&Process $1 not found.&
GDB=${GDB:-/usr/bin/gdb}
result=`$GDB
-nx /proc/$1/exe
$1 &&EOF 2&&1
&$result& | egrep
&^\(gdb\)& | egrep -B
&^\(gdb\)&
用于测试runstack.sh调试的c代码
typedef struct slist {
&&&&struct slist *
&&&&char&&&&&&&& data[4096];
slist input_list = {NULL, {'\0'}};
int count = 0;
static void stdin_read (int fd)
&&&&char buf[4096];
&&&&memset(buf, 0, 4096);
&&&&fprintf(stderr,
&please input string:&);
&&&&while (ret = read(fd, buf, 4096)) {
&&&&&&&&slist *node = calloc(1, sizeof(slist));
&&&&&&&&memcpy(node-&data, buf, ret);
&&&&&&&&node-&next = input_list.
&&&&&&&&input_list.next =
&&&&&&&&count ++;
&&&&&&&&if (memcmp(buf,
&quit&, 4) == 0) {
&&&&&&&&&&&&fprintf(stdout,
&input quit:\n&);
&&&&&&&&&&&&
&&&&&&&&fprintf(stderr,
&ret: %d, there is %d strings, current is %s\nplease input string:&, ret, count, buf);
int main()
&&&&fprintf(stderr,
&main run!\n&);
&&&&stdin_read(STDIN_FILENO);
&&&&slist *
&&&&slist *list = input_list.
&&&&while (list) {
&&&&&&&&fprintf(stderr,
&%s\n&, list-&data);
&&&&&&&&nlist = list-&
&&&&&&&&free(list);
&&&&&&&&list =
&&&&return 0;
编译c代码:gcc -g -o read_input read_input.c
执行./read_input 我们开始使用runstack.sh来调试
使用方法:sh ./runstack.sh pid “command”
来试验一下:
[shihao@xxx]$ ps aux |grep read_input|grep -v grep
pts/4 S+ 09:41 0:00 ./read_input
10933是一个read_input程序的进程号
1)打印代码
sudo sh ./runstack.sh 10933 “list main”
(gdb) 35 fprintf(stderr, “ret: %d, there is %d strings, current is %s\nplease input string:”, ret, count, buf);
39 int main()
41 fprintf(stderr, “main run!\n”);
43 stdin_read(STDIN_FILENO);
(gdb) quit
2)显示程序全局变量值
./runstack.sh 10933 “p count”
(gdb) $1 = 1
(gdb) quit
3)修改变量值
执行下面命令前
[shihao@tfs036097 gdb]$ runstack.sh 11190 “set count=100″
结果: (gdb) (gdb) quit
我们可以用上面命令看我们修改成功没有
[shihao@tfs036097 gdb]$ runstack.sh 11190 “p count”
(gdb) $1 = 100
(gdb) quit
全局变量count变成100了。
注:1)有一些程序经过操作系统优化过,直接用上面的方法可能有找不到符号表的情况
result=`$GDB
-nx /proc/$1/exe
$1 &&EOF 2&&1
可以把上面的代码改成下面的试试,如果不行可能是其他原因
BIN=`readlink
/proc/$1/exe`
result=`$GDB
$1 &&EOF 2&&1
2)需要有查看和修改运行的进程的权限
2. 情景2:需要同时看几个变量的值或者批量查看多个core文件的信息怎么办
1)多个变量的情景
我们同时看一下count和input_list里面的值和堆栈信息,我们可以写一个script.gdb
$ cat script.gdb
p input_list
执行 runstack.sh 10933 “source script.gdb”
(gdb) $1 = {next = 0x597c020, data = ” }
#0 0xec5f00 in __read_nocancel () from /lib64/libc.so.6
#1 0x07c7 in stdin_read (fd=0) at read_input.c:23
#2 0×0803 in main () at read_input.c:43
#1 0x07c7 in stdin_read (fd=0) at read_input.c:23
23 while (ret = read(fd, buf, 4096)) {
$3 = “12345\n”, ”
(gdb) quit
这样就可以同时做多个操作
2)批处理查看core的情况
有的时候会出现很多core文件,我们想知道哪些core文件是因为相同的原因,哪些是不相同的,看一个两个的时候还比较轻松
$ ls core.*
core.12281 core.12282 core.12283 core.12284 core.12286 core.12287 core.12288 core.12311 core.12313 core.12314
像上面有很多core文件,一个一个用gdb去执行bt去看core在哪里有点麻烦,我们想有把所有的core文件的堆栈和变量信息打印出来
我对runstack稍作修改就可以实现我们的需求,我们起名叫corestack.sh
&Usage: `basename $0 .sh` program core cmd&
&For example: `basename $0 .sh` ./main core.1111 bt&
&&&&exit 1
&Process $1 not found.&
&&&&exit 1
GDB=${GDB:-/usr/bin/gdb}
result=`$GDB
$2 &&EOF 2&&1
&$result& | egrep
&^\(gdb\)& | egrep -B
&^\(gdb\)&
我们可以这样执行:
./corestack.sh ./read_input core.12281 “bt”
执行结果:
(gdb) #0 0xe30265 in raise (sig=)
at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0xe31d10 in abort () at abort.c:88
#2 0xe296e6 in __assert_fail (assertion=,
file=, line=,
function=) at assert.c:78
#3 0x08ba in main () at read_input.c:55
(gdb) quit
查看多个core文件堆栈信息的准备工作差不多了,我们写个脚本就可以把所有的core文件堆栈打印出来了
执行以下:for i in `ls core.*`;do ./corestack.sh ./read_input $i “bt”; done
(gdb) #0 0xe30265 in raise (sig=)
at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0xe31d10 in abort () at abort.c:88
#2 0xe296e6 in __assert_fail (assertion=,
file=, line=,
function=) at assert.c:78
#3 0x08ba in main () at read_input.c:55
(gdb) quit
(gdb) #0 0xe30265 in raise (sig=)
at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0xe31d10 in abort () at abort.c:88
#2 0xe296e6 in __assert_fail (assertion=,
file=, line=,
function=) at assert.c:78
#3 0x08ba in main () at read_input.c:55
(gdb) quit
ok, 我们看到了所有core文件的堆栈。
3. 情景3:遇到需要查看、队列、链表、树、堆等数据结构里的变量怎么办?
下面介绍链表怎么处理,对其他数据结构感兴趣的同学可以自己尝试编写一些gdb脚本(麻烦@周哲士豪一下我,我也学习学习),
希望我们可以实现一个gdb调试工具箱
gdb是支持编写的脚本的 http://sourceware.org/gdb/onlinedocs/gdb/Command-Files.html
我们写个plist.gdb,用while循环来遍历链表
$ cat plist.gdb
$list=&input_list
while($list)
&&&&p *$list
$list=$list-&next
我们执行一下:runstack.sh 13434 “source plist.gdb”
(gdb) $1 = {next = 0x3d61040, data = ” }
$2 = {next = 0x3d60030, data = “123456\n”, ” }
$3 = {next = 0x3d5f020, data = “12345\n”, ” }
$4 = {next = 0x3d5e010, data = “1234\n”, ” }
$5 = {next = 0×0, data = “123\n”, ” }
(gdb) quit
实际上我们可以把plist写成自定义函数,执行gdb的时候会在当前目下查找.gdbinit文件加载到gdb:
$ cat .gdbinit
define plist
$list=$arg0
&&&&while($list)
&&&&&&&&p *$list
&&&&&&&&set
$list=$list-&next
这样就可以用plist命令遍历list的值
$ runstack.sh 13434 “plist &input_list”
(gdb) $1 = {next = 0x3d61040, data = ” }
$2 = {next = 0x3d60030, data = “123456\n”, ” }
$3 = {next = 0x3d5f020, data = “12345\n”, ” }
$4 = {next = 0x3d5e010, data = “1234\n”, ” }
$5 = {next = 0×0, data = “123\n”, ” }
(gdb) quit
参考资料:
霸爷的博客:/archives/873
gdb从脚本加载命令:/?p=380
gdb官方文档:http://sourceware.org/gdb/onlinedocs/gdb/Command-Files.html
gdb回退: http://sourceware.org/gdb/news/reversible.html
gdb stl调试脚本:/TUTORIALS/src/dbinit_stl_views-1.03.txt
gdb 高级调试方法:http://blog.csdn.net/wwwsq/article/details/7086151
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:225819次
积分:3026
积分:3026
排名:第11636名
原创:73篇
转载:38篇
评论:12条
(1)(1)(1)(2)(1)(1)(2)(1)(2)(1)(3)(11)(1)(13)(9)(4)(9)(19)(2)(6)(4)(9)(8)&&&echo&Usage:
`basename $0 .sh` &process-id& cmd&
&&&echo&For
exampl: `basename $0 .sh` 1000 bt&
test ! -r/proc/$1;
&&&echo&Process
$1 not found.&
GDB=${GDB:-/usr/bin/gdb}
result=`$GDB--quiet-nx/proc/$1/exe$1&&EOF
echo&$result&|
egrep -A1000-e&^\(gdb\)&|
egrep -B1000-e&^\(gdb\)&
用于测试runstack.sh调试的c代码
struct slist {
&&&&struct
&&&&char&&&&&&&&
data[4096];
input_list = {NULL, {'\0'}};
count = 0;
void stdin_read (int fd)
buf[4096];
&&&&memset(buf,
&&&&fprintf(stderr,&please
input string:&);
(ret = read(fd, buf, 4096)) {
&&&&&&&&slist
*node = calloc(1, sizeof(slist));
&&&&&&&&memcpy(node-&data,
buf, ret);
&&&&&&&&node-&next
= input_list.
&&&&&&&&input_list.next
&&&&&&&&count
++;
&&&&&&&&if
(memcmp(buf, &quit&,
4) == 0) {
&&&&&&&&&&&&fprintf(stdout,&input
quit:\n&);
&&&&&&&&&&&&
&&&&&&&&fprintf(stderr,&ret:
%d, there is %d strings, current is %s\nplease input string:&,
ret, count, buf);
&&&&fprintf(stderr,&main
&&&&stdin_read(STDIN_FILENO);
*list = input_list.
&&&&&&&&fprintf(stderr,&%s\n&,
list-&data);
&&&&&&&&nlist
&&&&&&&&free(list);
&&&&&&&&list
&&&&return
编译c代码:gcc -g -o read_input read_input.c
执行./read_input 我们开始使用runstack.sh来调试
使用方法:sh ./runstack.sh pid “command”
来试验一下:
[shihao@xxx]$ ps aux |grep read_input|grep -v grep
pts/4 S+ 09:41 0:00 ./read_input
10933是一个read_input程序的进程号
1)打印代码
sudo sh ./runstack.sh 10933 “list main”
(gdb) 35 fprintf(stderr, “ret: %d, there is %d strings, current is %s\nplease input string:”, ret, count, buf);
39 int main()
41 fprintf(stderr, “main run!\n”);
43 stdin_read(STDIN_FILENO);
(gdb) quit
2)显示程序全局变量值
./runstack.sh 10933 “p count”
(gdb) $1 = 1
(gdb) quit
3)修改变量值
执行下面命令前
[shihao@tfs036097 gdb]$ runstack.sh 11190 “set count=100″
结果: (gdb) (gdb) quit
我们可以用上面命令看我们修改成功没有
[shihao@tfs036097 gdb]$ runstack.sh 11190 “p count”
(gdb) $1 = 100
(gdb) quit
全局变量count变成100了。
注:1)有一些程序经过操作系统优化过,直接用上面的方法可能有找不到符号表的情况
result=`$GDB--quiet-nx/proc/$1/exe$1&&EOF
可以把上面的代码改成下面的试试,如果不行可能是其他原因
BIN=`readlink-f/proc/$1/exe`
result=`$GDB--quiet-nx$BIN
&&EOF 2&&1
2)需要有查看和修改运行的进程的权限
2. 情景2:需要同时看几个变量的值或者批量查看多个core文件的信息怎么办
1)多个变量的情景
我们同时看一下count和input_list里面的值和堆栈信息,我们可以写一个script.gdb
$ cat script.gdb
input_list
执行 runstack.sh 10933 “source script.gdb”
(gdb) $1 = {next = 0x597c020, data = ” }
#0 0xec5f00 in __read_nocancel () from /lib64/libc.so.6
#1 0x07c7 in stdin_read (fd=0) at read_input.c:23
#2 0×0803 in main () at read_input.c:43
#1 0x07c7 in stdin_read (fd=0) at read_input.c:23
23 while (ret = read(fd, buf, 4096)) {
$3 = “12345\n”, ”
(gdb) quit
这样就可以同时做多个操作
2)批处理查看core的情况
有的时候会出现很多core文件,我们想知道哪些core文件是因为相同的原因,哪些是不相同的,看一个两个的时候还比较轻松
$ ls core.*
core.12281 core.12282 core.12283 core.12284 core.12286 core.12287 core.12288 core.12311 core.12313 core.12314
像上面有很多core文件,一个一个用gdb去执行bt去看core在哪里有点麻烦,我们想有把所有的core文件的堆栈和变量信息打印出来
我对runstack稍作修改就可以实现我们的需求,我们起名叫corestack.sh
&&&&echo&Usage:
`basename $0 .sh` program core cmd&
&&&&echo&For
example: `basename $0 .sh` ./main core.1111 bt&
test ! -r$1;
&&&&echo&Process
$1 not found.&
GDB=${GDB:-/usr/bin/gdb}
result=`$GDB--quiet-nx$1
&&EOF 2&&1
echo&$result&|
egrep -A1000-e&^\(gdb\)&|
egrep -B1000-e&^\(gdb\)&
我们可以这样执行:
./corestack.sh ./read_input core.12281 “bt”
执行结果:
(gdb) #0 0xe30265 in raise (sig=)
at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0xe31d10 in abort () at abort.c:88
#2 0xe296e6 in __assert_fail (assertion=,
file=, line=,
function=) at assert.c:78
#3 0x08ba in main () at read_input.c:55
(gdb) quit
查看多个core文件堆栈信息的准备工作差不多了,我们写个脚本就可以把所有的core文件堆栈打印出来了
执行以下:for i in `ls core.*`;do ./corestack.sh ./read_input $i “bt”; done
(gdb) #0 0xe30265 in raise (sig=)
at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0xe31d10 in abort () at abort.c:88
#2 0xe296e6 in __assert_fail (assertion=,
file=, line=,
function=) at assert.c:78
#3 0x08ba in main () at read_input.c:55
(gdb) quit
(gdb) #0 0xe30265 in raise (sig=)
at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0xe31d10 in abort () at abort.c:88
#2 0xe296e6 in __assert_fail (assertion=,
file=, line=,
function=) at assert.c:78
#3 0x08ba in main () at read_input.c:55
(gdb) quit
ok, 我们看到了所有core文件的堆栈。
3. 情景3:遇到需要查看、队列、链表、树、堆等数据结构里的变量怎么办?
下面介绍链表怎么处理,对其他数据结构感兴趣的同学可以自己尝试编写一些gdb脚本(麻烦@周哲士豪一下我,我也学习学习),
希望我们可以实现一个gdb调试工具箱
gdb是支持编写的脚本的 http://sourceware.org/gdb/onlinedocs/gdb/Command-Files.html
我们写个plist.gdb,用while循环来遍历链表
$ cat plist.gdb
set$list=&input_list
while($list)
&&&&set$list=$list-&next
我们执行一下:runstack.sh 13434 “source plist.gdb”
(gdb) $1 = {next = 0x3d61040, data = ” }
$2 = {next = 0x3d60030, data = “123456\n”, ” }
$3 = {next = 0x3d5f020, data = “12345\n”, ” }
$4 = {next = 0x3d5e010, data = “1234\n”, ” }
$5 = {next = 0×0, data = “123\n”, ” }
(gdb) quit
实际上我们可以把plist写成自定义函数,执行gdb的时候会在当前目下查找.gdbinit文件加载到gdb:
$ cat .gdbinit
&&&&set$list=$arg0
&&&&while($list)
&&&&&&&&set$list=$list-&next
这样就可以用plist命令遍历list的值
$ runstack.sh 13434 “plist &input_list”
(gdb) $1 = {next = 0x3d61040, data = ” }
$2 = {next = 0x3d60030, data = “123456\n”, ” }
$3 = {next = 0x3d5f020, data = “12345\n”, ” }
$4 = {next = 0x3d5e010, data = “1234\n”, ” }
$5 = {next = 0×0, data = “123\n”, ” }
(gdb) quit
参考资料:
霸爷的博客:/archives/873
gdb从脚本加载命令:/?p=380
gdb官方文档:http://sourceware.org/gdb/onlinedocs/gdb/Command-Files.html
This entry was posted by&&on 日 at 12:32, and is filed under&.
Follow any responses to this post through&. You can&&or&&from your own site.
11 comments
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:356901次
积分:4554
积分:4554
排名:第6518名
原创:28篇
转载:437篇
(12)(18)(21)(24)(4)(30)(27)(17)(4)(31)(151)(76)(8)(44)& 如何用gdb调试erlang运行期(高级)
如何用gdb调试erlang运行期(高级)
原创文章,转载请注明: 转载自
本文链接地址:
前些天在erlang的源码里面闲逛的时候发现了 bin目录下的cerl,一看原来是个调试的高级货。
我之前写过一篇文章/blog/113852 如何调试erlang 但是这是土八路的方法, cerl才是现代化工业。
# This is a script to start Erlang/OTP for debugging. PATH is set to
# include this script so if slave nodes are started they will use this
# script as well.
cerl [ OPTIONS ] [ ARGS ]
The OPTIONS are
-rootdir $MYROOTDIR
Run an installed emulator built from this source
Run debug compiled emulator
Run the debug compiled emulator in emacs and gdb.
You have to start beam in gdb using “run”.
Run the debug compiled emulator in emacs and gdb and set break.
The session is started, i.e. “run” is already don for you.
FIXME currently disabled
Run emulator compiled for purify
Run emulator compiled for quantify
Run emulator compiled for purecov
Run emulator compiled for gcov
Run emulator compiled for valgrind
-lcnt Run emulator compiled for lock counting
Unset the DISPLAY variable to disable us of X Windows
要使用cerl 我们最好准备个调试版本的erlang。R13B 修正了些编译错误,可以编译出debug版本的系统:./configure && make TYPE=debug && make
这样就生成了个beam.debug的运行期。
我们要调试的时候 就可以在otp的binx目录下运行
cerl -debug -gdb -break main
这时候cerl自动会加载 emacs 启动 gud,
整个过程都是自动的。但是这个脚本有点小问题, gud模型下没有把源码和当前对应的调试对应起来。可以通过以下方式修正:
yu-fengdemacbook-2:bin yufeng$ diff cerl cerl2
exec $EMACS --eval &(progn (gdb \&gdb $EMU\&) $gdbcmd)&
exec $EMACS --eval &(progn (gdb \&gdb --annotate=3
$EMU\&) $gdbcmd)&
具体的操作和界面可以参照这篇文章:
/printing-of-Eterm%27s-from-gdb-td.html
在调试的时候 我们会希望查看 eterm的值,但是由于eterm的格式非常复杂, gdb的print什么的无法满足我们的需求。 otp开发团队于是开发出了一套方法来减轻我们的负担:
erts/etc/unix/etp-commands 这是gdb的脚本 包含了几十个etp方法,而且文档非常详细。
2. 源码里面的 pp, ps等函数, 这些函数是专门为gdb调试开发的。 可以用gdb的 call pp(xxx)来调用。
有了这些工具 调试和研究erts变成了一件很快乐的事情!
Post Footer automatically generated by
for wordpress.
Related posts:
Categories:
Comments are closed.
buy me a coffee.
阿里核心系统数据库组招募高手!
招聘信息:
Recent Posts}

我要回帖

更多关于 gdb 调试已运行的程序 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信