For debugging purposes, I wanted to find out from which thread the pthread was created, so We investigated how to get tid and how to get tid of child thread created by pthread_create. Basically, it is assumed that LD_PRELOAD is used by the following method.
Replace printf later with LD_PRELOAD --Qiita
It seems that gettid can only be used via syscall on Linux. Do as follows.
#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
pid_t gettid(void) {
return syscall(SYS_gettid);
}
It would be easier if you could get the tid of the child thread directly from pthread_t, but basically it seems that you can't get it directly (it seems possible to get the tid by force if you get the definition from glibc's struct pthread). (Not used this time), wrapping pthread_create
, replacing the thread call target, and getting the tid withgettid ()
written above.
Hook mounting example
extern "C" {
struct pthread_args {
void* (*f)(void*);
void* args;
};
void* thread_wrap(void* args) {
//Output tid
printf("%s : tid => %d\n", __func__, gettid());
//Call the original function from the saved structure
auto p = (struct pthread_args*)args;
auto ret = p->f(p->args);
delete p;
return ret;
}
void* thread_excute(void* args) {
printf("%s : tid => %d\n", __func__, gettid());
return NULL;
}
// pthread_Wrap create
int pthread_create(pthread_t *__newthread, const pthread_attr_t *__attr,
void *(*__start_routine) (void *), void *__arg) {
using pthread_create_t =
int (*)(pthread_t *, const pthread_attr_t *, void *(*) (void *), void *);
static thread_local pthread_create_t real_pthread_create = nullptr;
if (!real_pthread_create) {
// create cache
real_pthread_create
= reinterpret_cast<pthread_create_t>(dlsym(RTLD_NEXT, __func__));
assert(real_pthread_create);
}
//Save the original function pointer and arguments to the structure once
struct pthread_args* p = new(std::nothrow) struct pthread_args();
p->f = __start_routine;
p->args = __arg;
//Call the replacement function and pass the save structure as an argument
auto ret = real_pthread_create(__newthread, __attr, &thread_wrap, (void*)p);
return ret;
}
} // extern "C"
tid_test.cpp
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <new>
// hook
extern "C" {
pid_t gettid(void) {
return syscall(SYS_gettid);
}
struct pthread_args {
void* (*f)(void*);
void* args;
};
void* thread_wrap(void* args) {
printf("%s : tid => %d\n", __func__, gettid());
auto p = (struct pthread_args*)args;
auto ret = p->f(p->args);
delete p;
return ret;
}
void* thread_excute(void* args) {
printf("%s : tid => %d\n", __func__, gettid());
return NULL;
}
int pthread_create(pthread_t *__newthread, const pthread_attr_t *__attr,
void *(*__start_routine) (void *), void *__arg) {
using pthread_create_t =
int (*)(pthread_t *, const pthread_attr_t *, void *(*) (void *), void *);
static thread_local pthread_create_t real_pthread_create = nullptr;
if (!real_pthread_create) {
// create cache
real_pthread_create
= reinterpret_cast<pthread_create_t>(dlsym(RTLD_NEXT, __func__));
assert(real_pthread_create);
}
Dl_info info;
dladdr(__builtin_return_address(0), &info);
printf("%s : __builtin_return_address => %p\n", __func__, __builtin_return_address(0));
printf("%s : Dl_info.dli_fname => %s\n", __func__, info.dli_fname);
printf("%s : Dl_info.dli_fbase => %p\n", __func__, info.dli_fbase);
printf("%s : Dl_info.dli_sname => %s\n", __func__, info.dli_sname);
printf("%s : Dl_info.dli_saddr => %p\n", __func__, info.dli_saddr);
printf("%s : tid => %d\n", __func__, gettid());
struct pthread_args* p = new(std::nothrow) struct pthread_args();
p->f = __start_routine;
p->args = __arg;
auto ret = real_pthread_create(__newthread, __attr, &thread_wrap, (void*)p);
return ret;
}
}
// main
int main(int argc, char const* argv[])
{
pthread_t thread_handler_;
puts("begin : pthread_create");
pthread_create(&thread_handler_, NULL, &thread_excute, NULL);
puts("end : pthread_create");
pthread_join(thread_handler_, NULL);
return 0;
}
Build and output results
$ g++ -std=c++11 tid_test.cpp -ldl -pthread -rdynamic
$ ./a.out
begin : pthread_create
pthread_create : __builtin_return_address => 0x400f40
pthread_create : Dl_info.dli_fname => ./a.out
pthread_create : Dl_info.dli_fbase => 0x400000
pthread_create : Dl_info.dli_sname => main
pthread_create : Dl_info.dli_saddr => 0x400f0c
pthread_create : tid => 4303
end : pthread_create
thread_wrap : tid => 4304
thread_excute : tid => 4304
Now we have the parent and child tid.
Replace printf later with LD_PRELOAD --Qiita Call the original function from the function replaced by LD_PRELOAD --Qiita [Linux] [C / C ++] How to get the return address value of a function and the function name of the caller --Qiita
Recommended Posts