bash源码的调试方法

前言

改了一版bash, 给同事用了好长时间,现在需要再加点东西,突然发现gdb附加后,不能正常调试输入的shell命令了。

在原版上试一下, 是能单步源码调试的。
那可能是改版的bash, 在处理用户输入命令之前,在处理过程中,又自己执行了shell命令去干其他活,建立了bash子进程引起不能有效调试的。

记录一下原版bash单步调试的过程。

实验

将bash-4.4.tar.gz上传到debian虚拟机中的实验目录。
解压

tar -xzvf ./bash-4.4.tar.gz
cd /home/dev/bash-4.4

设置configure为调试版

export CFLAGS='-DGCC_HASCLASSVISIBILITY -g -Wall -W'
./configure --enable-debug
看了 ./configure --help, 好像 --enable-debug 是个无效参数啊
主要还是依赖自己导出的CFLAGS中带的-g选项
make clean
将干净的目录回传到本地,用si建立工程进行代码走读。

如果为了标记这是实验的版本,可以改–version的实现,那样再运行bash时,就能确定是自己改过的版本。

/* Give version information about this shell. */
char *
shell_version_string ()
{
  const char* psz_my_ver = "ls_2019_0422_1354"; // @note 长度不要 >= 32

  static char tt[32 * 2] = { '\0' };

  if (tt[0] == '\0')
    {
      if (release_status)
#if HAVE_SNPRINTF
	snprintf (tt, sizeof (tt), "%s_%s.%d(%d)-%s", psz_my_ver, dist_version, patch_level, build_version, release_status);
#else
	sprintf (tt, "%s_%s.%d(%d)-%s", psz_my_ver, dist_version, patch_level, build_version, release_status);
#endif
      else
#if HAVE_SNPRINTF
	snprintf (tt, sizeof (tt), "%s_%s.%d(%d)", psz_my_ver, dist_version, patch_level, build_version);
#else
	sprintf (tt, "%s_%s.%d(%d)", psz_my_ver, dist_version, patch_level, build_version);
#endif
    }
  return tt;
}

make
这时,当前目录下,就生成好了新版的bash.

新bash的安装

make install
但是这样,在我现在的虚拟机debian8.8下是安装失败的,没拷贝到/bin中。
也有另外的可能,bash没有拷贝到当前系统的目录中替换掉原始bash, 而是拷贝到了其他目录.
这时,需要自己手工拷贝。
将make install结果定向到日志中,看到bash拷贝到了/usr/local/lib/下,而实际系统运行的bash是/bin/bash
installing example loadable builtins in /usr/local/lib/bash

用gdb附加另外的bash时,如果break main或已经存在的file:line时,提示不成功,说明有可能是bash不是我们编译出的版本。

用cmp命令验证一下。

cmp -l /bin/bash ./bash | gawk '{printf "%08X %02X %02X\n", $1, strtonum(0$2), strtonum(0$3)}'

如果bash被替换到了系统bash位置,cmp命令行执行后,结果是空的(没输出)。
如果当前编译出的bash和系统中的不一样,cmp命令行会输出那些字节不一样。
如果发现用make install 安装bash不成功,需要手工换一下bash.

mv /bin/bash /bin/bash.org.bk
cp ./bash /bin/

bash的调试

在开发目录的SecureCRT控制台中,输入tty, 先看看自己的tty号码。
然后用ps aux | grep bash 列出当前所有的bash.

再新开一个SecureCRT控制台, 用tty看看tty号码。
然后回到开发目录所在的控制台中,重新用ps aux | grep bash列出当前所有的bash.
新增的bash很容易看出来,那个bash的进程ID就在第2列。

拿到新开控制台窗口的bash进程ID后,就可以用gdb进行源码调试了。
在开发目录的控制台中,输入以下命令进行附加调试。

gdb -tui -p new_bash_pid
这时:
* 下断点,应该有效的。
* 在新bash控制台(被调试的bash), 按键是没有反应的。

下好断点后,按c继续跑起。
在被调试的bash控制台,输入预期的命令后,就会被开发目录所在的bash断住。
然后就可以用s, n 开始单步调试了。

2019_0423

用原版和修改版做了比对,知道修改版为啥编译不过了。
因为是在虚拟机或工控机里面编译的, 回传到本地之前(因为修改了bash源码),会先make clean.
bash的make clean, 并不会清除./support/man2html.o
当在不同计算机上编译后,归档时,导致man2html.o不是当前计算机编译出来的. 在架构不同的计算机上编译时,编译器编译时,不会更新man2html.o(也许是时间比当前的时间更旧), 而是会直接包含上用来编译。这样就导致编译不过。

写了一个编译bash的脚本,这样以后就不会忘了怎么才能正确编译bash工程
rebuild.sh

root@localhost:/home/dev/bash-4.4# vi ./rebuild.sh            

#! /bin/sh
export CFLAGS='-DGCC_HASCLASSVISIBILITY -g -Wall'
./configure --enable-debug
make clean
rm -f ./support/man2html.o
make
make install
mv /bin/bash /bin/bash.bk_$(date "+%Y%m%e_%H%M%S_%s")
cp ./bash /bin/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值