お元気ですか? あいにく風邪気味の、サイオス 那賀です。
最近の RPM ベースの Linux ディストリビューションであれば、バイナリ RPM と共に、debuginfo パッケージが提供されているのが普通だと思います。この debuginfo パッケージをインストールすることで、従来であればバイナリパッケージ作成の際に strip で落とされてしまっていたデバッグ情報やソース情報を別パッケージとして利用することができるようになるため、本体パッケージを肥大化させることなく、本体パッケージのバイナリそのものを用いて、ソースレベルでのデバッグを行うことができます (GDB の分離デバッグ情報についての詳細は「Separate Debug Files - Debugging with GDB」あたりを、RPM のビルド中の処理については /usr/lib/rpm/find-debuginfo.sh の debugedit のあたりを参照してください)。
しかし現在の提供形態だと、いくつか問題があります。
- バイナリは "-g -O2" でコンパイルされているので、最適化がかかっており、デバッグがしづらい
- 自前でパラメータを変えてビルドしたら、既存の debuginfo は使用できない
- 最新のバイナリのアップデートは公開されているのに、対応する debuginfo が出ていないことがある (特に CentOS)
- debuginfo パッケージは大きいので、SRPM ファイルともども、ミラーから削除されがちで入手できなかったりする (特に CentOS)
そこで、自前でパッケージをビルドして、debuginfo を活用する方法をご紹介します。以下は、おそらく RHEL4~ の系列では動きますが、それ以外はよく知りません。合わせて以前の記事も参考にしてください → 「SIOS OSS Tech: ソースの入手と再ビルド ~ CentOS / Scientific Linux 編」。
まずは、redhat-rpm-config パッケージをインストールします。debuginfo パッケージ生成関連のマクロはこのパッケージに含まれているため、これをインストールしておかないと、RPM パッケージのビルドはできますが、debuginfo パッケージが生成されません。
[root@centos4 ~]# yum install redhat-rpm-config
次にビルドです。"rpmbuild --rebuild <SRPM ファイル>" なり "rpmbuild -ba <SPEC ファイル>" なり (渋いところでは、"rpmbuild -ta <tar.gz ファイル>" なり) でビルドをするところですが、ここで、デバッグ用のオプションを指定することができます。デフォルトは "-g -O2" になっていると思いますが、特にこの "-O2" のおかげでかなり最適化がされてしまい、ソースレベルでのデバッグがしづらくなります。これを "-O0" にして最適化を切ると同時に、"-pg", "-g3" で、付加的なデバッグ情報も付けておきます。
注意: 最適化オプションやコンパイル環境の変更によって、調査するはずだった不具合が解消してしまうことも、よくあります。困ります
以下は、CentOS 4 での例です。ソースの入手からビルド~ソースレベル・デバッグまでを見てみます。
[root@centos4 ~]# wget http://ftp.redhat.com/pub/redhat/linux/enterprise/4/en/os/i386/SRPMS/bash-3.0-19.2.src.rpm (中略) [root@centos4 ~]# rpmbuild --rebuild \ --define="optflags -pg -g3 -O0" bash-3.0-19.2.src.rpm (中略) Wrote: /usr/src/redhat/RPMS/i386/bash-3.0-19.2.i386.rpm Wrote: /usr/src/redhat/RPMS/i386/bash-debuginfo-3.0-19.2.i386.rpm (中略) [root@centos4 ~]# rpm -Uvh --force \ /usr/src/redhat/RPMS/i386/bash-3.0-19.2.i386.rpm \ /usr/src/redhat/RPMS/i386/bash-debuginfo-3.0-19.2.i386.rpm (中略) [root@centos4 ~]# bash -c "while true; do sleep 1; done" & [1] 32108 [root@centos4 ~]# gdb -p 32108 (中略) Attaching to process 32108 Reading symbols from /bin/bash...Reading symbols from /usr/lib/debug/bin/bash.debug...done. Using host libthread_db library "/lib/tls/libthread_db.so.1". done. Reading symbols from /lib/libtermcap.so.2...done. Loaded symbols for /lib/libtermcap.so.2 Reading symbols from /lib/libdl.so.2...done. Loaded symbols for /lib/libdl.so.2 Reading symbols from /lib/tls/libc.so.6...done. Loaded symbols for /lib/tls/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 0x0027f7a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2 (gdb) bt #0 0x0027f7a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2 #1 0x00324533 in __waitpid_nocancel () from /lib/tls/libc.so.6 #2 0x0807d03f in waitchld (wpid=32134, block=1) at jobs.c:2497 #3 0x0807be1d in wait_for (pid=32134) at jobs.c:1904 #4 0x0806b901 in execute_command_internal (command=0x9c73280, asynchronous=0, pipe_in=-1, pipe_out=-1, fds_to_close=0x9c73378) at execute_cmd.c:704 #5 0x0806b279 in execute_command (command=0x9c73280) at execute_cmd.c:351 #6 0x0806e2db in execute_while_or_until (while_command=0x9c732d0, type=0) at execute_cmd.c:2327 #7 0x0806e1ef in execute_while_command (while_command=0x9c732d0) at execute_cmd.c:2273 #8 0x0806ba79 in execute_command_internal (command=0x9c732e0, asynchronous=0, pipe_in=-1, pipe_out=-1, fds_to_close=0x9c732f8) at execute_cmd.c:764 #9 0x080a7187 in parse_and_execute (string=0x9c72d00 "while true; do sleep 1; done", from_file=0x80d9392 "-c", flags=4) at evalstring.c:267 #10 0x0805cb6f in run_one_command (command=0xbff9bc18 "while true; do sleep 1; done") at shell.c:1269 #11 0x0805bd7a in main (argc=3, argv=0xbff378e4, env=0xbff378f4) at shell.c:653 (gdb) frame 11 #11 0x0805bd7a in main (argc=3, argv=0xbff378e4, env=0xbff378f4) at shell.c:653 653 run_one_command (command_execution_string); (gdb) l 648 if (debugging_mode) 649 start_debugger (); 650 651 #if defined (ONESHOT) 652 executing = 1; 653 run_one_command (command_execution_string); 654 exit_shell (last_command_exit_value); 655 #else /* ONESHOT */ 656 with_input_from_string (command_execution_string, "-c"); 657 goto read_and_execute; (gdb) p command_execution_string $1 = 0xbff9bc18 "while true; do sleep 1; done"
ソースもシンボルも見えています。良いようですね。
では。
話は逸れますが、上記で、上書きでインストールをする際に "rpm" コマンドに "-U" と "--force" を組み合わせています。"--force" は依存を壊しませんので、それほど問題ではありません。一方、"--nodeps" はいけません。RPM の本質は依存関係の解決だと思いますので、それを破壊する "--nodeps" は悪です。"--nodeps" を付けなければならない状況に陥ったら、開発者 or 管理者として負けだと思ってください。
0 コメント:
コメントを投稿