À des fins de débogage, il y avait un cas où je voulais savoir à partir de quel thread le pthread a été créé. Nous avons étudié comment obtenir tid et comment obtenir tid du thread enfant créé par pthread_create. Fondamentalement, on suppose que LD_PRELOAD est utilisé par la méthode suivante.
Remplacez printf plus tard par LD_PRELOAD --Qiita
Il semble que gettid ne peut être utilisé que via syscall sous Linux. Faites comme suit.
#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
pid_t gettid(void) {
return syscall(SYS_gettid);
}
Ce serait plus facile si vous pouviez obtenir la tid du thread enfant directement à partir de pthread_t, mais en gros, il semble que vous ne puissiez pas l'obtenir directement (il semble possible d'obtenir la tid par la force si vous obtenez la définition de la structure pthread de la glibc). (Non utilisé cette fois), encapsulation de pthread_create
, remplacement de la cible d'appel du thread, et obtention du tid avec gettid ()
écrit ci-dessus.
Exemple de montage de crochet
extern "C" {
struct pthread_args {
void* (*f)(void*);
void* args;
};
void* thread_wrap(void* args) {
//Tid de sortie
printf("%s : tid => %d\n", __func__, gettid());
//Appeler la fonction d'origine à partir de la structure enregistrée
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_Envelopper créer
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);
}
//Enregistrer le pointeur de la fonction d'origine et les arguments dans la structure une fois
struct pthread_args* p = new(std::nothrow) struct pthread_args();
p->f = __start_routine;
p->args = __arg;
//Appelez la fonction de remplacement et passez la structure de sauvegarde comme 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;
}
Construire et produire des résultats
$ 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
Maintenant, nous avons le tid pour le parent et l'enfant.
Remplacez printf plus tard par LD_PRELOAD --Qiita Appelez la fonction d'origine à partir de la fonction remplacée par LD_PRELOAD --Qiita [Linux] [C / C ++] Comment obtenir la valeur d'adresse de retour d'une fonction et le nom de fonction de l'appelant --Qiita
Recommended Posts