前言
需要在bash4.4源码工程上填点新功能,首先遇到了调试问题。
以前用gdb调试程序,调试和运行效果是一样的。
但是bash有点不同,如果直接用gdb带着编译好的bash起来,运行流程和系统直接调用bash的效果不同。
如果在bash代码中大量打印syslog日志(可能也不是大量,可能加的地方不对头,bash本来就是命令解释器,如果调用syslog也算是执行了命令),会影响bash的执行效果。日志加多了,更换bash重启后,正确的用户名/口令都登陆不成功,没法玩了。
只能加必要的逻辑代码,在虚拟机里面换掉bash后,重新启动.然后用gdb附加调试。调试的时候还有点小技巧。
实验
实验环境
vmware14 + debian7.5
修改Makefile
bash4.4 ./configure之后,产生的Makefile是有 -O2选项的,要去掉,要不单步调试时,看到的效果和没有优化的源码不一致。
e.g.
# PROFILE_FLAGS is either -pg,to generate profiling info for use
# with gprof,or nothing (the default).
PROFILE_FLAGS=
# CFLAGS = -g -O2 -Wno-parentheses -Wno-format-security
CFLAGS = -g -Wno-parentheses -Wno-format-security
# CFLAGS_FOR_BUILD = -g -O2 -Wno-parentheses -Wno-format-security
CFLAGS_FOR_BUILD = -g -Wno-parentheses -Wno-format-security
./configure之后,将虚拟机里里面的bash4.4目录拷贝回windows归档
bash工程中有一些子工程,搜索所有的Makefile,将-O2都去掉。
下次再编译以前,就不用./configure,直接将保存修改后的bash4.4源码目录拷贝到虚拟机里,编译即可。
为了确认替换后是自己何时改的程序,可以将bash –version 处理的函数 version.c::shell_version_string()改掉
编译工程
make clean
make all
替换系统的bash
[root@localhost bash-4.4]# whereis bash
bash: /usr/bin/bash /usr/bin/bash.bk /usr/share/man/man1/bash.1.gz /usr/share/info/bash.info.gz
[root@localhost bash-4.4]# mv /usr/bin/bash /usr/bin/bash.bk_2018_0610_1637
[root@localhost bash-4.4]# cp ./bash /usr/bin/
重启系统(必须的,因为系统已经启动了一份bash实例. 重启计算机后,系统才会启动我们替换后的bash)
<2018-0612-0057>
// 替换修改版bash时,必须make all 之后,用make install 来替换bash
// 然后用 /usr/local/lib/bash 替换/usr/bin/bash
// make install 后,替换的是usr/local/lib/bash
// 否则会出现重启后,无法登陆的情况
附加调试系统已经启动的bash
用putty或xshell连接debian7.5时,每一个ssh连接有一个bash伺候.
[root@localhost ~]# ps aux | grep bash
root 1032 0.2 0.1 117580 4524 tty1 Ss+ 02:22 0:00 -bash
root 1061 0.3 0.1 117584 4516 pts/0 Ss 02:22 0:00 -bash
root 1085 0.2 0.1 117584 4520 pts/1 Ss+ 02:23 0:00 -bash
root 1110 0.0 0.0 115816 2368 pts/0 S+ 02:23 0:00 grep --color=auto bash
tty1是系统启动时启动的.
我用xshell连接debian7.5时,开了2个ssh连接,对应为pts/0, pts/1
现在调试pts/0中的bash,gdb运行在pts/1中。
在pts/1那个连接中,进入编译好的bash4.4源码目录.。
[root@localhost ~]# cd /home/dev/bash-4.4/
可以看到pts/0的pid为1061
gdb -tui attach 1061
(gdb) break execute_simple_command
Breakpoint 1 at 0x43d949: file execute_cmd.c,line 4107.
c
在pts/0那个连接上,随便输入一个测试命令
rm -f /var/log/test.txt
可以看到pts/0已经卡住了,回到pts/1,看到代码已经断住了。
查看系统调用栈
(gdb) bt
#0 execute_simple_command (simple_command=0x2727a08,pipe_in=-1,pipe_out=-1,async=0,fds_to_close=0x2723868) at execute_cmd.c:4107
#1 0x0000000000437e53 in execute_command_internal (command=0x2724dc8,asynchronous=0,fds_to_close=0x2723868) at execute_cmd.c:826
#2 0x00000000004374b5 in execute_command (command=0x2724dc8) at execute_cmd.c:421
#3 0x0000000000422564 in reader_loop () at eval.c:180
#4 0x000000000042016a in main (argc=1,argv=0x7fffb1c591c8,env=0x7fffb1c591d8) at shell.c:807
现在可以进入正常的调试流程了:)