在 gdb 中的 pthread 线程本地存储上设置观察点
set watchpoint on pthread's thread-local storage in gdb
是否可以使用 GDB 在 pthread 的线程本地存储上设置观察点?我有一个运行的程序:
struct stored_type *res = pthread_getspecific(tls_key);
...在几千次之后调用它 returns 0 而不是有效指针。我真的很想弄清楚是什么将该值设置为 0。我尝试在 pthread_setspecific
和 pthread_delete_key
上设置断点(我唯一能想到的会合理地导致密钥更改值) 并且这些断点没有被击中,所以我认为发生了某种超限。
我正在使用 Linux x86_64 和 glibc 2.23。
... the only things I could think of that would reasonably cause the key to change value
pthread_getspecific
到 return 最可能的原因 NULL
:
- 您实际上是在一个新线程中执行,其中
pthread_setspecific
尚未被调用,
- 您正在调用
pthread_getspecific
,而当前线程正在被销毁(即 pthread_exit
在堆栈中的某处),
- 您正在信号处理程序中调用
pthread_getspecific
(pthread_*
函数中的 none 是异步信号安全的)。
假设上述 none 个原因在您的情况下是正确的,继续演出。
首先我们需要一个测试用例来演示。
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
pthread_key_t key;
void *thrfn(void *p) {
int rc = pthread_setspecific(key, &p);
assert(rc == 0);
sleep(60);
rc = pthread_setspecific(key, (void*)0x112233);
assert(rc == 0);
return p;
}
int main()
{
pthread_t thr;
int rc = pthread_key_create(&key, NULL);
assert(rc == 0);
rc = pthread_create(&thr, NULL, thrfn, NULL);
assert(rc == 0);
sleep(90);
return 0;
}
gcc -g -pthread t.c
gdb -q ./a.out
(gdb) start
现在,拥有使用调试信息编译的 GLIBC 非常有帮助。大多数发行版都提供了一个 libc-dbg
或类似的包来提供它。查看pthread_setspecificsource,可以看到在线程描述符(self
)里面有一个specific_1stblock
数组,其中space为第一个[=25] =] == 32 个键槽是预先分配的(32 个不同的键通常绰绰有余)。
我们传递的值将存储在 self->specific_1stblock[key].data
中,这正是您要设置观察点的位置。
在我们的示例程序中,key == 0
(因为这是第一个键)。把它们放在一起:
Starting program: /tmp/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Temporary breakpoint 1, main () at t.c:21
21 int rc = pthread_key_create(&key, NULL);
(gdb) b pthread_setspecific
Breakpoint 2 at 0x7ffff7bc9460: file pthread_setspecific.c, line 28.
(gdb) c
Continuing.
[New Thread 0x7ffff77f6700 (LWP 58683)]
[Switching to Thread 0x7ffff77f6700 (LWP 58683)]
Breakpoint 2, __GI___pthread_setspecific (key=0, value=0x7ffff77f5ef8) at pthread_setspecific.c:28
28 pthread_setspecific.c: No such file or directory.
(gdb) n
35 in pthread_setspecific.c
(gdb) n
28 in pthread_setspecific.c
(gdb) p self
= (struct pthread *) 0x7ffff77f6700
(gdb) watch -l self.specific_1stblock[key].data
Hardware watchpoint 3: -location self.specific_1stblock[key].data
(gdb) c
Continuing.
Hardware watchpoint 3: -location self.specific_1stblock[key].data
Old value = (void *) 0x0
New value = (void *) 0x7ffff77f5ef8
__GI___pthread_setspecific (key=<optimized out>, value=0x7ffff77f5ef8) at pthread_setspecific.c:89
89 in pthread_setspecific.c
请注意,新值正是我们传递给 pthread_setspecific
的值。
(gdb) c
Continuing.
Breakpoint 2, __GI___pthread_setspecific (key=0, value=0x112233) at pthread_setspecific.c:28
28 in pthread_setspecific.c
(gdb) c
Continuing.
Hardware watchpoint 3: -location self.specific_1stblock[key].data
Old value = (void *) 0x7ffff77f5ef8
New value = (void *) 0x112233
__GI___pthread_setspecific (key=<optimized out>, value=0x112233) at pthread_setspecific.c:89
89 in pthread_setspecific.c
这是我们的第二次 pthread_setspecific
通话
(gdb) c
Continuing.
Hardware watchpoint 3: -location self.specific_1stblock[key].data
Old value = (void *) 0x112233
New value = (void *) 0x0
__nptl_deallocate_tsd () at pthread_create.c:152
152 pthread_create.c: No such file or directory.
这是线程销毁,它会释放线程描述符本身。
(gdb) c
Continuing.
[Thread 0x7ffff77f6700 (LWP 58683) exited]
[Inferior 1 (process 58677) exited normally]
是否可以使用 GDB 在 pthread 的线程本地存储上设置观察点?我有一个运行的程序:
struct stored_type *res = pthread_getspecific(tls_key);
...在几千次之后调用它 returns 0 而不是有效指针。我真的很想弄清楚是什么将该值设置为 0。我尝试在 pthread_setspecific
和 pthread_delete_key
上设置断点(我唯一能想到的会合理地导致密钥更改值) 并且这些断点没有被击中,所以我认为发生了某种超限。
我正在使用 Linux x86_64 和 glibc 2.23。
... the only things I could think of that would reasonably cause the key to change value
pthread_getspecific
到 return 最可能的原因 NULL
:
- 您实际上是在一个新线程中执行,其中
pthread_setspecific
尚未被调用, - 您正在调用
pthread_getspecific
,而当前线程正在被销毁(即pthread_exit
在堆栈中的某处), - 您正在信号处理程序中调用
pthread_getspecific
(pthread_*
函数中的 none 是异步信号安全的)。
假设上述 none 个原因在您的情况下是正确的,继续演出。
首先我们需要一个测试用例来演示。
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
pthread_key_t key;
void *thrfn(void *p) {
int rc = pthread_setspecific(key, &p);
assert(rc == 0);
sleep(60);
rc = pthread_setspecific(key, (void*)0x112233);
assert(rc == 0);
return p;
}
int main()
{
pthread_t thr;
int rc = pthread_key_create(&key, NULL);
assert(rc == 0);
rc = pthread_create(&thr, NULL, thrfn, NULL);
assert(rc == 0);
sleep(90);
return 0;
}
gcc -g -pthread t.c
gdb -q ./a.out
(gdb) start
现在,拥有使用调试信息编译的 GLIBC 非常有帮助。大多数发行版都提供了一个 libc-dbg
或类似的包来提供它。查看pthread_setspecificsource,可以看到在线程描述符(self
)里面有一个specific_1stblock
数组,其中space为第一个[=25] =] == 32 个键槽是预先分配的(32 个不同的键通常绰绰有余)。
我们传递的值将存储在 self->specific_1stblock[key].data
中,这正是您要设置观察点的位置。
在我们的示例程序中,key == 0
(因为这是第一个键)。把它们放在一起:
Starting program: /tmp/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Temporary breakpoint 1, main () at t.c:21
21 int rc = pthread_key_create(&key, NULL);
(gdb) b pthread_setspecific
Breakpoint 2 at 0x7ffff7bc9460: file pthread_setspecific.c, line 28.
(gdb) c
Continuing.
[New Thread 0x7ffff77f6700 (LWP 58683)]
[Switching to Thread 0x7ffff77f6700 (LWP 58683)]
Breakpoint 2, __GI___pthread_setspecific (key=0, value=0x7ffff77f5ef8) at pthread_setspecific.c:28
28 pthread_setspecific.c: No such file or directory.
(gdb) n
35 in pthread_setspecific.c
(gdb) n
28 in pthread_setspecific.c
(gdb) p self
= (struct pthread *) 0x7ffff77f6700
(gdb) watch -l self.specific_1stblock[key].data
Hardware watchpoint 3: -location self.specific_1stblock[key].data
(gdb) c
Continuing.
Hardware watchpoint 3: -location self.specific_1stblock[key].data
Old value = (void *) 0x0
New value = (void *) 0x7ffff77f5ef8
__GI___pthread_setspecific (key=<optimized out>, value=0x7ffff77f5ef8) at pthread_setspecific.c:89
89 in pthread_setspecific.c
请注意,新值正是我们传递给 pthread_setspecific
的值。
(gdb) c
Continuing.
Breakpoint 2, __GI___pthread_setspecific (key=0, value=0x112233) at pthread_setspecific.c:28
28 in pthread_setspecific.c
(gdb) c
Continuing.
Hardware watchpoint 3: -location self.specific_1stblock[key].data
Old value = (void *) 0x7ffff77f5ef8
New value = (void *) 0x112233
__GI___pthread_setspecific (key=<optimized out>, value=0x112233) at pthread_setspecific.c:89
89 in pthread_setspecific.c
这是我们的第二次 pthread_setspecific
通话
(gdb) c
Continuing.
Hardware watchpoint 3: -location self.specific_1stblock[key].data
Old value = (void *) 0x112233
New value = (void *) 0x0
__nptl_deallocate_tsd () at pthread_create.c:152
152 pthread_create.c: No such file or directory.
这是线程销毁,它会释放线程描述符本身。
(gdb) c
Continuing.
[Thread 0x7ffff77f6700 (LWP 58683) exited]
[Inferior 1 (process 58677) exited normally]