在pthread的gdb中的线程本地存储上设置watchpoint

时间:2016-11-29 18:29:57

标签: debugging gdb pthreads thread-local-storage

是否可以使用GDB在pthread的线程本地存储上设置观察点?我有一个运行的程序:

equals()

...并且在几千次调用之后它返回0而不是有效指针。我真的很想弄清楚将该值设置为0.我已尝试在struct stored_type *res = pthread_getspecific(tls_key); pthread_setspecific上设置断点(我能想到的唯一的事情是会合理地导致关键改变价值)并且这些断点没有被击中,所以我认为那里发生了某种超支。

我使用Linux x86_64和glibc 2.23。

1 个答案:

答案 0 :(得分:1)

  

......我能想到的唯一可以合理地导致关键改变价值的事情

pthread_getspecific返回NULL的最可能原因:

  • 你实际上正在一个新线程中执行,其中pthread_setspecific尚未被调用,
  • 你正在调用pthread_getspecific而当前线程正在被销毁(即pthread_exit在堆栈的某个地方),
  • 您在信号处理程序中调用pthread_getspecificpthread_*个函数都不是异步信号安全的。)

假设在你的情况下没有上述原因,那就是节目。

首先,我们需要一个测试用例来演示。

#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_setspecific source,您可以看到在线程描述符(self)内有一个specific_1stblock数组,其中第一个PTHREAD_KEY_2NDLEVEL_SIZE == 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
$1 = (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]