Menlo Parkに戻ってCafe Borroneで ブランチを食べました。そこで「opaque typeをdebuggerで見たい時ってどうするのがいいんですかね?」という話がでたので、ちょっと試してみました。
libraryなどで、内部では具体的な型が定義されているけど、使う側にはgenericなpointer(void *)としてしか見せていない場合です。例えばこんなかんじ。
# library側 % cat a.h void* create_foo(); void set_foo(void* p, int i); % cat liba.c #include <stdlib.h> #include <string.h> #include "a.h" struct foo { int i; }; void* create_foo() { void *p = malloc(sizeof(struct foo)); memset(p, 0, sizeof(struct foo)); return p; } void set_foo(void* p, int i) { struct foo* fp = (struct foo*)p; fp->i = i; } % gcc -fPIC -o liba.o -c liba.c % gcc -shared -o liba.so liba.o -lc # libraryを使う側 % cat b.c #include <stdlib.h> #include "a.h" int main(int argc, char *argv[]) { void* p = craete_foo(); set_foo(p, argc); exit(0); } % gcc -g -o b.o -c b.c % gcc -g -o b b.o -L. -la % LD_LIBRARY_PATH=. gdb b ... (gdb) break main Breakpoint 1 at 0x400657: file b.c, line 6. (gdb) run Starting program: /tmp/g/b Breakpoint 1, main (argc=1, argv=0x7fffb44a6e08 "?\213J??\177") at b.c:6 6 void *p = create_foo(); (gdb) n 7 set_foo(p, argc); (gdb) print p $1 = (void *) 0x601010 (gdb) whatis p type = void * (gdb) whatis *p type = void (gdb) ptype p type = void * (gdb) ptype *p type = void (gdb) print *(struct foo*)p No struct type named foo. (gdb)というかんじで p の中身をみることができません。defaultでは
set opaque-type-resolution on
ですが、liba.so
のデバッグ情報がないのでどうしようもないのです。単純な場合なら examine でダンプしちゃうのが簡単ですね。
(gdb) x/dw p 0x601010 0(
/dw
でword(w)を10進(d)で表示)もし
liba.so
のデバッグ情報つきが手にはいれば次のようにロードしてやればよいでしょう。# デバッグ情報つき % gcc -fPIC -g -o liba.g.o -c liba.c % gcc -shared -g -o liba.g.so liba.g.o -lc ... (gdb) info share From To Syms Read Shared Object Library 0x00007f3ba9cd3a60 0x00007f3ba9ce9d44 Yes /lib64/ld-linux-x86-64.so.2 0x00007f3ba9ad2520 0x00007f3ba9ad2648 Yes ./liba.so 0x00007f3ba978de30 0x00007f3ba987ee88 Yes /lib/libc.so.6 (gdb) add-symbol-file liba.g.so 0x00007f3ba9ad2520 add symbol table from file "liba.g.so" at .text_addr = 0x7f3ba9ad2520 (y or n) y Reading symbols from /tmp/g/liba.g.so...done. (gdb) print *(struct foo*)p $2 = {i = 0} (gdb) s set_foo (p=0x601010, i=1) at a.c:18 18 struct foo *fp = (struct foo *)p; (gdb) s 19 fp->i = i; (gdb) s 20 } (gdb) s main (argc=1, argv=0x7fffb1ef1858 "?\033??\177") at b.c:8 8 exit(0); (gdb) print *p Attempt to dereference a generic pointer. (gdb) print *(struct foo*)p $4 = {i = 1}このように p のさしている先を struct foo として解釈できるようになります。またstep実行もできますね。
デバッグ情報つきライブラリがつくれない/入手できない、でもopaque typeの中をみたいという場合は、型情報を含むオブジェクトをつくってロードしてみるとよいかと
% cat atype.c struct foo { int i; }; struct foo *fooptr; % gcc -fPIC -g -o atype.o -c atype.c % gcc -shared -g -o atype.so atype.o -lc % LD_LIBRARY_PATH=. gdb b ... (gdb) break main Breakpoint 1 at 0x400657: file b.c, line 6. (gdb) run Starting program: /tmp/g/b Breakpoint 1, main (argc=1, argv=0x7fff8bd03668 "?;?\213?\177") at b.c:6 6 void *p = create_foo(); (gdb) n 7 set_foo(p, argc); (gdb) info share From To Syms Read Shared Object Library 0x00007fde83ae5a60 0x00007fde83afbd44 Yes /lib64/ld-linux-x86-64.so.2 0x00007fde838e4520 0x00007fde838e4648 Yes ./liba.so 0x00007fde8359fe30 0x00007fde83690e88 Yes /lib/libc.so.6 (gdb) add-symbol-file atype.so 0x00007fde838e4520 add symbol table from file "atype.so" at .text_addr = 0x7fde838e4520 (y or n) y Reading symbols from /tmp/g/atype.so...done. (gdb) print *(struct foo*)p $1 = {i = 0} (gdb) s 8 exit(0); (gdb) print *(struct foo*)p $2 = {i = 1} (gdb)この場合はstep実行はできせんがstruct fooとして見ることはできるようになりました。
static linkされている場合だとどうでしょう。
# static library % ar ruv liba.a liba.o ar: creating liba.a a - liba.o % gcc -g -o b.static b.o liba.a % gdb b.static ... (gdb) break main Breakpoint 1 at 0x400547: file b.c, line 6. (gdb) run Starting program: /tmp/g/b.static Breakpoint 1, main (argc=1, argv=0x7fffedb324a8 "?+???\177") at b.c:6 6 void *p = create_foo(); (gdb) n 7 set_foo(p, argc); (gdb) print p $1 = (void *) 0x601010 (gdb) whatis p type = void * (gdb) whatis *p type = void (gdb) ptype p type = void * (gdb) ptype *p type = void (gdb) print *(struct foo*)p No struct type named foo. (gdb) info share From To Syms Read Shared Object Library 0x00007f49e5914a60 0x00007f49e592ad44 Yes /lib64/ld-linux-x86-64.so.2 0x00007f49e55cfe30 0x00007f49e56c0e88 Yes /lib/libc.so.6 (gdb) add-symbol-file atype.so 0x800000000000 add symbol table from file "atype.so" at .text_addr = 0x800000000000 (y or n) y Reading symbols from /tmp/g/atype.so...done. (gdb) print *(struct foo*)p $2 = {i = 0} (gdb) n 8 exit(0); (gdb) print *(struct foo*)p $3 = {i = 1}というかんじで適当なアドレスにadd-symbol-fileで型情報付きオブジェクトをロードしてやればよさそうです。
なるほど、add-symbol-fileを使えばよかったんですね。gdbのマニュアルを見てこれが使えるかもとは思ったのですが、アドレスをどう指定するといいのかがよくわからなくて素通りしてしまってました。
ReplyDelete勉強になりました。ありがとうございます。