gdbでgetopt()のoptind/optoptを参照したときに値が違うように見える
結構ハマったのでメモ。
#include <stdio.h> #include <getopt.h> char *short_opts = "ab:"; struct option long_opts[] = { {"test", no_argument, 0, 0}, {"add", required_argument, 0, 0}, {0, 0, 0, 0} }; int main(int argc, char *argv[]) { int c = 0; int longindex; while (1) { longindex = 0; c = getopt_long(argc, argv, short_opts, long_opts, &longindex); if (c == -1) { break; } fprintf(stdout, "%d(%x) %d(%x) %c(%x)\n", c, &c, optind, &optind, optopt, &optopt); } return 0; }
というソースがあり、getoptのextern変数optind, optoptの実際の値とgdbで参照した値が違うのに気がついた。
$ cc -g getopt.c $ ./a.out -a -b a --test --add A 97(4cc7b7ac) 2(600ae4) (600ae0) 98(4cc7b7ac) 4(600ae4) (600ae0) 0(4cc7b7ac) 5(600ae4) (600ae0) 0(4cc7b7ac) 7(600ae4) (600ae0) $ gdb a.out GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1) Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-redhat-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /home/kohchi/C/a.out...done. (gdb) b main Breakpoint 1 at 0x4005e4: file getopt.c, line 14. (gdb) run -a -b a --test --add A Starting program: /home/kohchi/C/a.out -a -b a --test --add A Breakpoint 1, main (argc=7, argv=0x7fffffffe1c8) at getopt.c:14 14 int c = 0; Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.132.el6_5.2.x86_64 (gdb) n 18 longindex = 0; (gdb) 19 c = getopt_long(argc, argv, short_opts, long_opts, &longindex); (gdb) 20 if (c == -1) { (gdb) 24 fprintf(stdout, "%d(%x) %d(%x) %c(%x)\n", (gdb) p c $1 = 97 (gdb) p optind $2 = 1 (gdb) p optopt $3 = 63 (gdb) n 97(ffffe0cc) 2(600ae4) (600ae0) ※あれ?optind=2 optopt=0になっている。 26 } (gdb)
で以下のページを参照したところ、シェアードライブラリの値と実行バイナリで使っているものが2つあるらしい。
コマンドを実行すると当然シェアードライブラリ中の値となるのだが、gdbで何も指定しないと実行バイナリのものを表示するらしい。
http://www.linuxquestions.org/questions/programming-9/gdb-does-not-print-right-value-908538/
なのでgdbでは以下のように"@@GLIBC_X.X.X"を指定するとシェアードライブラリの値を参照できるようだ。
$ gdb a.out GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1) Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-redhat-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /home/kohchi/C/a.out...done. (gdb) b main Breakpoint 1 at 0x4005e4: file getopt.c, line 14. (gdb) run -a -b a --test --add A Starting program: /home/kohchi/C/a.out -a -b a --test --add A Breakpoint 1, main (argc=7, argv=0x7fffffffe1c8) at getopt.c:14 14 int c = 0; Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.132.el6_5.2.x86_64 (gdb) n 18 longindex = 0; (gdb) 19 c = getopt_long(argc, argv, short_opts, long_opts, &longindex); (gdb) 20 if (c == -1) { (gdb) p c $1 = 97 (gdb) p /c c $2 = 97 'a' (gdb) n 24 fprintf(stdout, "%d(%x) %d(%x) %c(%x)\n", (gdb) l 19 c = getopt_long(argc, argv, short_opts, long_opts, &longindex); 20 if (c == -1) { 21 break; 22 } 23 24 fprintf(stdout, "%d(%x) %d(%x) %c(%x)\n", 25 c, &c, optind, &optind, optopt, &optopt); 26 } 27 return 0; 28 } (gdb) n 97(ffffe0cc) 2(600ae4) (600ae0) 26 } (gdb) p optind $3 = 1 ※2になっていないぞ (gdb) p &optind $4 = (int *) 0x38bfd8e114 ※参照先も違う (gdb) p optopt $5 = 63 ※0になっていないぞ (gdb) p &optopt $6 = (int *) 0x38bfd8e11c ※参照先も違う (gdb) p optind[tabを2回押す] optind optind@@GLIBC_2.2.5 (gdb) p 'optind@@GLIBC_2.2.5' $7 = 2 ※OK! (gdb) p &'optind@@GLIBC_2.2.5' $8 = (<data variable, no debug info> *) 0x600ae4 ※OK! (gdb) p optopt[tabを2回押す] optopt optopt@@GLIBC_2.2.5 (gdb) p 'optopt@@GLIBC_2.2.5' $9 = 0 ※OK! (gdb) p &'optopt@@GLIBC_2.2.5' $10 = (<data variable, no debug info> *) 0x600ae0 ※OK! (gdb) info var optind All variables matching regular expression "optind": Non-debugging symbols: 0x0000000000600ae4 optind@@GLIBC_2.2.5 (gdb) info var optopt All variables matching regular expression "optopt": Non-debugging symbols: 0x0000000000600ae0 optopt@@GLIBC_2.2.5 (gdb) n 18 longindex = 0; (gdb) quit A debugging session is active. Inferior 1 [process 8020] will be killed. Quit anyway? (y or n) y $