errno
実際には、C標準では、変更可能な左辺値に展開されるマクロである必要があります。最も単純なケースでは、宣言された変数の名前に展開できますがerrno
、異なるスレッドに対して個別のオブジェクトを必要とする実装の場合、通常は次のように定義されます。
#define errno (*__errno_location ())
gdb
通常、関数呼び出しを評価できます。たとえば、私のシステムでは:
(gdb) p __errno_location()
$1 = -134383968
(gdb) p errno
Cannot find thread-local variables on this target
最初に出力される値は、によって返されるポインタ値の下位32ビットです__errno_location()
。その動作を説明するのに十分なgdbはわかりませんが、関数呼び出しを実行できることを示しています。
回避策として、ソースコードを変更して、アドレスerrno
またはその値をgdbが表示できる変数に保存することができます。
(gdb) l
1 #include <errno.h>
2 #include <stdio.h>
3 int main(void) {
4 errno = 42; /* arbitrary value */
5 const int *errno_ptr = &errno;
6 int errno_value = errno;
7 printf("%d %d %d\n", errno, errno_value, *errno_ptr);
8 }
(gdb) b 8
Breakpoint 1 at 0x4005b6: file c.c, line 8.
(gdb) r
Starting program: /home/kst/c
42 42 42
Breakpoint 1, main () at c.c:8
8 }
(gdb) p errno
Cannot find thread-local variables on this target
(gdb) p errno_value
$1 = 42
(gdb) p *errno_ptr
$2 = 42
この*errno_ptr
アプローチには、マルチスレッドプログラムをデバッグしている場合を除いて、一度だけ割り当てる必要があるという利点があります。その場合、の値は、&errno
評価するスレッドによって異なります。
これはおそらく、のバグ、または少なくとも欠落している機能ですgdb
。
更新KevinCoxのコメントは、回避策を示唆しています。
print *((int*(*)())__errno_location)()
そして、gcc6.2とgdb7.11では、print errno
実際に機能します。
(gdb) l
1 #include <errno.h>
2 int main(void) {
3 errno = 42;
4 return 0;
5 }
(gdb) b 4
Breakpoint 1 at 0x6bf: file c.c, line 4.
(gdb) r
Starting program: /home/kst/c
Breakpoint 1, main () at c.c:4
4 return 0;
(gdb) p errno
$1 = 42
(gdb)