Für Debugging-Zwecke gab es einen Fall, in dem ich herausfinden wollte, aus welchem Thread der Pthread erstellt wurde. Wir haben untersucht, wie man tid bekommt und wie man tid von untergeordnetem Thread bekommt, der von pthread_create erstellt wurde. Grundsätzlich wird davon ausgegangen, dass LD_PRELOAD von der folgenden Methode verwendet wird.
Ersetzen Sie printf später durch LD_PRELOAD --Qiita
Es scheint, dass gettid nur über syscall unter Linux verwendet werden kann. Gehen Sie wie folgt vor.
#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
pid_t gettid(void) {
return syscall(SYS_gettid);
}
Es wäre einfacher, wenn ich die Nachricht des untergeordneten Threads direkt von pthread_t abrufen könnte, aber im Grunde scheint es, dass ich sie nicht direkt abrufen kann (es scheint möglich, die Nachricht mit Gewalt zu erhalten, wenn ich die Definition von glibcs Struktur pthread erhalte). (Diesmal nicht verwendet), "pthread_create" umbrechen, das Aufrufziel des Threads ersetzen und die tid mit "gettid ()" abrufen, wie oben geschrieben.
Beispiel für die Hakenmontage
extern "C" {
struct pthread_args {
void* (*f)(void*);
void* args;
};
void* thread_wrap(void* args) {
//Ausgabe tid
printf("%s : tid => %d\n", __func__, gettid());
//Rufen Sie die ursprüngliche Funktion aus der gespeicherten Struktur auf
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 erstellen
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);
}
//Speichern Sie den ursprünglichen Funktionszeiger und die Argumente einmal in der Struktur
struct pthread_args* p = new(std::nothrow) struct pthread_args();
p->f = __start_routine;
p->args = __arg;
//Rufen Sie die Ersetzungsfunktion auf und übergeben Sie die Sicherungsstruktur als 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;
}
Ergebnisse erstellen und ausgeben
$ 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
Jetzt haben wir die Nachricht für Eltern und Kind.
Ersetzen Sie printf später durch LD_PRELOAD --Qiita Rufen Sie die ursprüngliche Funktion von der durch LD_PRELOAD --Qiita ersetzten Funktion auf [Linux] [C / C ++] So ermitteln Sie den Wert der Rücksprungadresse einer Funktion und den Funktionsnamen des Aufrufers --Qiita
Thread ID-Volatile Note abrufen
Recommended Posts