#fj.os.linux,fj.comp.lang.c,fj.unixにクロスポストしています。
#不適当でしたら御指摘下さい。
[Q] linux-2.2.xの元でlibtoolsを使って作成されたプログラムAをgdbでデバッ
グすることを考えます。なお、gdbでの検証が必要な場所は、dynamic
linkingされるライブラリの中(foo.c::x())にあることが判っています。
この場合、gdbよりfoo.c::x()にブレークポイントを定めようとしても、
dnynamic link libraryがロードされていない為、シンボルが見付から
ないと言われてしまいます。また、プログラムがデータドリブンなプログ
ラムなため、
・地道にstep実行すると日がくれてしまう。
・単体テストは通ってしまうが、結合するとバグるので
どうしても結合して検証したい
・人の書いた大きなプログラムなのでprintfによるデバッグが面倒
(Re-compileに時間がかかる。実際やってたがそろそろ飽きた)
などの理由により、どうしてもデバッガが使いたく思っています。
ここで、
[Q1] foo.c::x()で上手くブレークさせる方法はないでしょうか?
(load foo.soとかやったのですが、linuxシステムなのかエラーで弾
かれてしまいます)
なお、foo.cのエントリ内にてprintfで場所とgetpidの値を出力さ
せた後sleepさせ、gdb attachさせる以外にありますでしょうか?
このやり方の副作用として、呼ばれる回数が少々多い場所には使え
ないという問題があります。
[Q2] libtoolsを使って作成されたdnynamic link libraryを使った
プログラムのデバッグの方法などへのポインタはありますでしょう
か? なお、
[1] info libtools のDebugging executables章
以外でお願いします。
--
Takahide Nojima
Takahide Nojima <noj...@taito.co.jp> writes:
> [Q1] foo.c::x()で上手くブレークさせる方法はないでしょうか?
> (load foo.soとかやったのですが、linuxシステムなのかエラーで弾
> かれてしまいます)
>
> なお、foo.cのエントリ内にてprintfで場所とgetpidの値を出力さ
> せた後sleepさせ、gdb attachさせる以外にありますでしょうか?
> このやり方の副作用として、呼ばれる回数が少々多い場所には使え
> ないという問題があります。
これにて、static linkingという方法もあるのですが、事情によりdynamic
linkingの状態で行う方法についてお願いします。
--
Takahide Nojima
In article <tzzvggg...@nightmare.hm.taito.co.jp>,
Takahide Nojima <noj...@taito.co.jp> writes
> この場合、gdbよりfoo.c::x()にブレークポイントを定めようとしても、
> dnynamic link libraryがロードされていない為、シンボルが見付から
> ないと言われてしまいます。
source はあるんですよね。foo.c::x() のあるlibraryの中を呼び
出した後に、どこかを呼ぶようなコードを付けておいて、そのコー
ドで一旦、break します。そのあと、foo.c::x() を break します。
ここまでは、.gdbinit に記述しておきます。
あるいは、foo.c だけ、static にlinkしてしまうという手もあります。
> ・単体テストは通ってしまうが、結合するとバグるので
> どうしても結合して検証したい
> ・人の書いた大きなプログラムなのでprintfによるデバッグが面倒
> (Re-compileに時間がかかる。実際やってたがそろそろ飽きた)
このあたりは、困りますよね。gdb にdynamic link を呼び出すようなのを
付ければ良いのかな。
---
Shinji KONO @ Information Engineering, University of the Ryukyus,
PRESTO, Japan Science and Technology Corporation
河野真治 @ 琉球大学工学部情報工学科,
科学技術振興事業団さきがけ研究21(機能と構成)
<1961.10...@insigna.ie.u-ryukyu.ac.jp>の記事において
ko...@ie.u-ryukyu.ac.jpさんは書きました。
>> In article <tzzvggg...@nightmare.hm.taito.co.jp>,
>> Takahide Nojima <noj...@taito.co.jp> writes
>> > この場合、gdbよりfoo.c::x()にブレークポイントを定めようとしても、
>> > dnynamic link libraryがロードされていない為、シンボルが見付から
>> > ないと言われてしまいます。
>>
>> source はあるんですよね。foo.c::x() のあるlibraryの中を呼び
>> 出した後に、どこかを呼ぶようなコードを付けておいて、そのコー
>> ドで一旦、break します。そのあと、foo.c::x() を break します。
>> ここまでは、.gdbinit に記述しておきます。
プラットフォームによっても違うかもしれませんが、
まともにコンパイルしてあれば main にブレークポイントかけて実行するだけで、
実行時点で芋づる式にシンボルテーブルを読むはずです:
% uname -a
NetBSD aoi 1.5U NetBSD 1.5U (AOI) #2: Mon Apr 9 17:55:08 JST 2001 root@aoi:/usr/src/sys/arch/i386/compile/AOI i386
% cat a.c
int
main()
{
extern void foo(void);
foo();
return 0;
}
% cat b.c
void
foo()
{
extern void bar(void);
bar();
}
% cat c.c
#include <stdio.h>
static void
hoge()
{
printf("hello, world.\n");
}
void
bar()
{
hoge();
}
% gcc -g -c -fPIC a.c b.c c.c
% gcc -g -shared -o libbar.so -Wl,-soname,libbar.so c.o
% gcc -g -shared -o libfoo.so -Wl,-soname,libfoo.so b.o -Wl,-rpath,. -L. -lbar
% gcc -g a.o -L. -Wl,-rpath,. -lfoo
% gdb ./a.out
GNU gdb 4.17
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386--netbsd"...
(gdb) b c.c:hoge
No source file named c.c.
(gdb) b main
Breakpoint 1 at 0x80487ef: file a.c, line 5.
(gdb) r
Starting program: /usr/home/tshiozak/./a.out
Breakpoint 1, main () at a.c:5
5 foo();
(gdb) b c.c:hoge
Breakpoint 2 at 0x480fc2e3: file c.c, line 5.
(gdb) c
Continuing.
Breakpoint 2, hoge () at c.c:5
5 printf("hello, world.\n");
# NetBSD/i386 も 1.5 以降は ELF なので Linux とこの辺は大差ないはず。
しかしながら、さしつかえなければ
>> あるいは、foo.c だけ、static にlinkしてしまうという手もあります。
が確実かもしれませんね。
では。
--
Takuya SHIOZAKI / ASTEC Products, Inc.
早速の情報ありがとうございます。
ko...@ie.u-ryukyu.ac.jp (Shinji KONO) writes:
> In article <tzzvggg...@nightmare.hm.taito.co.jp>,
> Takahide Nojima <noj...@taito.co.jp> writes
> > この場合、gdbよりfoo.c::x()にブレークポイントを定めようとしても、
> > dnynamic link libraryがロードされていない為、シンボルが見付から
> > ないと言われてしまいます。
>
> source はあるんですよね。foo.c::x() のあるlibraryの中を呼び
> 出した後に、どこかを呼ぶようなコードを付けておいて、そのコー
> ドで一旦、break します。そのあと、foo.c::x() を break します。
> ここまでは、.gdbinit に記述しておきます。
ただ、少し問題があります。foo.c::x()が呼出す「どこか」をbar()とします。
ブレークを仕掛ける為にはbar()というのは少なくともgdbに既にロードされて
いる場所に置く必要があります。すると、foo.c::x()は最初にロードされる別
のモジュールのbar()に依存してしまい、foo.c::x()を利用する他のプログラ
ムも片っ端からbar()を実装する必要が出て来るような...
#もちろん、bar()を各プログラムのincludeに突込んでしまえばいいかもしれない
#のですが多くのソースを直すなど手がかかってしまいます。
自分としては、
・ユーザが何かコマンドを一発発行すると、予めダイナミックリンクライブ
ラリを吸い込んでリンクが完了してくれる。
ように出来ると嬉しく思います。
> あるいは、foo.c だけ、static にlinkしてしまうという手もあります。
すみません。どうも、dynamic linkすると出る問題(多分、自分の調べたいモ
ジュールの周辺がre-entrantに出来てない部分があるなど)により、static
linkでは問題が発生しないのです。涙。
> > ・単体テストは通ってしまうが、結合するとバグるので
> > どうしても結合して検証したい
> > ・人の書いた大きなプログラムなのでprintfによるデバッグが面倒
> > (Re-compileに時間がかかる。実際やってたがそろそろ飽きた)
>
> このあたりは、困りますよね。gdb にdynamic link を呼び出すようなのを
> 付ければ良いのかな。
info gdbによれば、HP-UXの上で動くgdbならload LIBRARY-FILEとかでライブ
ラリをプリロード出来るみたいです。でもなんとかlinux上でブレークポイン
トを仕掛けたいです。
みんなどうしてるのだろう?
#kaffeなんて、ダイナミックリンクライブラリの塊だし。
--
Takahide Nojima
<tzzn11s...@nightmare.hm.taito.co.jp>の記事において
noj...@taito.co.jpさんは書きました。
> ko...@ie.u-ryukyu.ac.jp (Shinji KONO) writes:
>
> > In article <tzzvggg...@nightmare.hm.taito.co.jp>,
> > Takahide Nojima <noj...@taito.co.jp> writes
> > > この場合、gdbよりfoo.c::x()にブレークポイントを定めようとしても、
> > > dnynamic link libraryがロードされていない為、シンボルが見付から
> > > ないと言われてしまいます。
> >
> > source はあるんですよね。foo.c::x() のあるlibraryの中を呼び
> > 出した後に、どこかを呼ぶようなコードを付けておいて、そのコー
> > ドで一旦、break します。そのあと、foo.c::x() を break します。
> > ここまでは、.gdbinit に記述しておきます。
>
> ただ、少し問題があります。foo.c::x()が呼出す「どこか」をbar()とします。
> ブレークを仕掛ける為にはbar()というのは少なくともgdbに既にロードされて
> いる場所に置く必要があります。すると、foo.c::x()は最初にロードされる別
> のモジュールのbar()に依存してしまい、foo.c::x()を利用する他のプログラ
> ムも片っ端からbar()を実装する必要が出て来るような...
ぬ?なんとなく分かるような、全然分からないような……
> すみません。どうも、dynamic linkすると出る問題(多分、自分の調べたいモ
> ジュールの周辺がre-entrantに出来てない部分があるなど)により、static
> linkでは問題が発生しないのです。涙。
dynamic link をするとは、dlopen とか使うって事でしょうか?
Linux 使いではないので、よくは分からんのですが、dlopen でしたら引
数に大抵 mode の項があって、そこに RTLD_NOW とか与えてやれば、そ
の時点でロードされるはずなので、そこに break を張れば良いのでは。
もし、dlopen ではなく、リンク時に共有ライブラリを指定するという場
合は、正当な手段は分かりませんが(なんかある様な気はする)、姑息な
手段として、main の頭辺りで、foo.c に入れたダミーの関数を一発呼ん
でみるとそのモジュール(foo.o)のシンボルは全部読み込まれたりせんだ
ろうか?
FreeBSD だと正当な手段として、環境変数 LD_BIND_NOW を作っておけば
なんとかなるんじゃなかろうか?でも、Linux は分かりませんです。(^^;
# man rtld ってあるのだろうか>Linux
--
成田 隆興 @ エー・アイ・ソフト株式会社 NB 推進部
E-mail tak...@aisoft.co.jp
『十分間で決断し、短い理由を添えよ。』
#フォローありがとうございます。
tak...@aisoft.co.jp (Narita Takaoki) writes:
> > ただ、少し問題があります。foo.c::x()が呼出す「どこか」をbar()とします。
> > ブレークを仕掛ける為にはbar()というのは少なくともgdbに既にロードされて
> > いる場所に置く必要があります。すると、foo.c::x()は最初にロードされる別
> > のモジュールのbar()に依存してしまい、foo.c::x()を利用する他のプログラ
> > ムも片っ端からbar()を実装する必要が出て来るような...
>
> ぬ?なんとなく分かるような、全然分からないような……
すみません。私の発言は忘れてください。あとで成田さんが仰った方法が良さ
そうなので使ってみます。
> dynamic link をするとは、dlopen とか使うって事でしょうか?
>
> Linux 使いではないので、よくは分からんのですが、dlopen でしたら引
> 数に大抵 mode の項があって、そこに RTLD_NOW とか与えてやれば、そ
> の時点でロードされるはずなので、そこに break を張れば良いのでは。
実際にはlibtoolのlibltdlとlibtoolのlink時オプション'-dlopen hoge.la'
でダイナミックリンクされています。
そのため、dlopenが呼ばれている場所は見事に隠蔽されており、RTLD_NOWに変
貌させることが困難になっています。もちろん、libtoolといえどもシェル
スクリプトなので、何とか解析して、dlopenの場所にRTLD_NOWするという方法
もないわけではないですが、もっと楽な方法はないかなぁと探しています。
> もし、dlopen ではなく、リンク時に共有ライブラリを指定するという場
> 合は、正当な手段は分かりませんが(なんかある様な気はする)、姑息な
> 手段として、main の頭辺りで、foo.c に入れたダミーの関数を一発呼ん
> でみるとそのモジュール(foo.o)のシンボルは全部読み込まれたりせんだ
> ろうか?
この方法は良さそうですね。こちらを採用してみます。
> FreeBSD だと正当な手段として、環境変数 LD_BIND_NOW を作っておけば
> なんとかなるんじゃなかろうか?でも、Linux は分かりませんです。(^^;
>
> # man rtld ってあるのだろうか>Linux
man rtldは無いですが、man dlopenには説明が出ています。しかし、
環境変数LD_BIND_NOWは載ってませんでした。
--
Takahide Nojima
#フォローありがとうございます。
tshi...@astec.co.jp (Shiozaki Takuya) writes:
> プラットフォームによっても違うかもしれませんが、
> まともにコンパイルしてあれば main にブレークポイントかけて実行するだけで、
> 実行時点で芋づる式にシンボルテーブルを読むはずです:
>
> % uname -a
> NetBSD aoi 1.5U NetBSD 1.5U (AOI) #2: Mon Apr 9 17:55:08 JST 2001 root@aoi:/usr/src/sys/arch/i386/compile/AOI i386
> % cat a.c
> int
> main()
> {
> extern void foo(void);
...中略...
> Breakpoint 2 at 0x480fc2e3: file c.c, line 5.
> (gdb) c
> Continuing.
>
> Breakpoint 2, hoge () at c.c:5
> 5 printf("hello, world.\n");
>
>
> # NetBSD/i386 も 1.5 以降は ELF なので Linux とこの辺は大差ないはず。
>
につきまして私のマシン(linxu-2.2.18+libc6)で行ってみたところ、塩崎氏
の仰るとおりの全く同様の動作をしました。
で、これは私の見た動作と違うので驚き、さらにデバッグしようとしている
プログラムを調べたところ、私のデバッグしようとしていたプログラムは、
・libtool gcc -module -export-symbole -export-dynamic
のオプション付きでコンパイルがなされ、
・libtool gcc -export-dynamic -o hoge -dlopen foo.la ...
となっており、libtoolのLTDLライブラリ経由のダイナミックリンク
がなされ
ていました。そのため、状況が異なってしまいました。私の勉強不足が原因で
折角お答え頂いたのに、はずしてしまい大変申し訳ないです。
しかし、libltdlなんて今日初めて知った...ソースコードにdlopenが全く
出てこないので、てっきり普通のdynamic linkだとばかり思い込んでました。
しかし、libltdlであっても未だにデバッグ出来無いことは変わってません...
--
Takahide Nojima
<tzzd72o...@nightmare.hm.taito.co.jp>の記事において
noj...@taito.co.jpさんは書きました。
>> しかし、libltdlであっても未だにデバッグ出来無いことは変わってません...
他の OS は知らないですが、Linux ならば環境変数 LD_PRELOAD を使えばでき
ませんか?
% cat a.c
#include <stdio.h>
#include <dlfcn.h>
int main()
{
printf ("hello, world.\n");
{
void *handle = dlopen ("libfoo.so", RTLD_LAZY);
void (*bar)(void) = dlsym (handle, "foo");
(*bar)();
dlclose(handle);
}
return (0);
}
% cat b.c
#include <stdio.h>
void foo()
{
printf ("hello in foo\n");
}
% gcc -g -c -fPIC b.c
% gcc -g -shared -o libfoo.so -Wl,-soname,libfoo.so b.o
% gcc -g a.c -L. -Wl,-rpath,. -ldl
% ./a.out
hello, world.
hello in foo
% env LD_PRELOAD=./libfoo.so gdb ./a.out
GNU gdb 19990928
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
(gdb) b main
Breakpoint 1 at 0x80484e7: file a.c, line 5.
(gdb) r
Starting program: /tmp/dd/./a.out
Breakpoint 1, main () at a.c:5
5 printf ("hello, world.\n");
(gdb) b foo
Breakpoint 2 at 0x40014793: file b.c, line 5.
(gdb) c
Continuing.
hello, world.
Breakpoint 2, foo () at b.c:5
5 printf ("hello in foo\n");
(gdb)
>> > FreeBSD だと正当な手段として、環境変数 LD_BIND_NOW を作っておけば
>> > なんとかなるんじゃなかろうか?でも、Linux は分かりませんです。(^^;
>> >
>> > # man rtld ってあるのだろうか>Linux
>>
>> man rtldは無いですが、man dlopenには説明が出ています。しかし、
>> 環境変数LD_BIND_NOWは載ってませんでした。
ld.so(8) に載ってますよ。
: LD_BIND_NOW
: If present, causes the dynamic linker to resolve
: all symbols at program startup instead of when they
: are first referenced.
--
野首 貴嗣
E-mail: kn...@daionet.gr.jp
kn...@namazu.org / kn...@debian.org
<9stc9r$auh$1...@daio.daionet.gr.jp>の記事において
kn...@daionet.gr.jpさんは書きました。
> >> > # man rtld ってあるのだろうか>Linux
>
> ld.so(8) に載ってますよ。
>
> : LD_BIND_NOW
> : If present, causes the dynamic linker to resolve
> : all symbols at program startup instead of when they
> : are first referenced.
FreeBSD4.4 の man rtld だと、
\begin{quote}
LD_BIND_NOW When set to a nonempty string, causes ld-elf.so.1 to
relocate all external function calls before starting
execution of the program. Normally, function calls are
bound lazily, at the first call of each function.
LD_BIND_NOW increases the start-up time of a program,
but it avoids run-time surprises caused by unexpectedly
undefined functions.
\end{quote}
ですので、FreeBSD の方は空文じゃ駄目な点が微妙に違う?
kn...@daionet.gr.jp (NOKUBI Takatsugu) writes:
> >> man rtldは無いですが、man dlopenには説明が出ています。しかし、
> >> 環境変数LD_BIND_NOWは載ってませんでした。
>
> ld.so(8) に載ってますよ。
>
> : LD_BIND_NOW
> : If present, causes the dynamic linker to resolve
> : all symbols at program startup instead of when they
> : are first referenced.
すみません。どうも私の環境のmanが古いらしく(slackware 7)、man ld.so
しても出てきませんでした。
参考になります。情報ありがとうございました。
#そろそろredhat/debianかなー
--
Takahide Nojima
おかげさまで解決出来ました。
Takahide Nojima <noj...@taito.co.jp> writes:
> [Q] linux-2.2.xの元でlibtoolsを使って作成されたプログラムAをgdbでデバッ
> グすることを考えます。なお、gdbでの検証が必要な場所は、dynamic
> linkingされるライブラリの中(foo.c::x())にあることが判っています。
>
> この場合、gdbよりfoo.c::x()にブレークポイントを定めようとしても、
> dnynamic link libraryがロードされていない為、シンボルが見付から
...中略...
> せた後sleepさせ、gdb attachさせる以外にありますでしょうか?
> このやり方の副作用として、呼ばれる回数が少々多い場所には使え
> ないという問題があります。
>
> [Q2] libtoolsを使って作成されたdnynamic link libraryを使った
> プログラムのデバッグの方法などへのポインタはありますでしょう
> か? なお、
>
> [1] info libtools のDebugging executables章
実はこの質問自体に問題がありました。申し訳ないです。皆様からの投稿を参考に
して、いろいろ試した結果解りました。
[真相]
・ デバッグしようとしていたプログラムが実は内部でlibltdlの
lt_dlopen,lt_dlopenext,lt_dlsymを明示的に呼出していた。
動作としてはデータに含まれているシンボルから、沢山ある必要な共有
ライブラリを自分でロードし、関数を呼出していた。
(私がlibltlの使用目的を100%勘違いしてました。
libltlを使い、libtool -module したモジュールを使ってもld.soがリ
ンクしてくれるという激しい勘違いを私がしてました。)
そのため、該当の共有ライブラリをロードさせるようなデータを入力しな
いかぎり、
・lt_dlopenにも飛んでいかないし、デバッグしたい部分は出てこないし、
ブレークさせるアドレスだって確定しなかった
のです。
これで、折角教えていただいたLD_PRELOADも、LD_BIND_NOW、-staticも私
がデバッグしているプログラムにきかない理由が解りました。
結局行ったデバッグ手法は次のとおりです。
[1] ロードされる共有ライブラリの中の関数で比較的呼び出し回数が少な
い場所に
fprintf(stderr,"%ld %s %d",__FILE__,__LINE__,getpid());
sleep(10);
を挿入。
[2] 表示させたら、gdb attach.
[3] ブレークかけて地道に実行。
御陰さまでデバッグも無事完了しました。結果、バグは
「あまりに恥ずかしい間違いだったので、ここでは言えない(;_;)」
ものです。すみません。
いずれにしろ、皆様有難うございました。非常に参考になりました。
--
Takahide Nojima