私は次のことをしようとしています - pthreads ライブラリのラッパーを書き、各 API が呼び出されるたびに情報をログに記録します。記録したい情報の 1 つは、スタック トレースです。
以下は、そのままコンパイルして実行できる元のコードの最小限のスニペットです。
初期化 (ファイルlibmutex.c
):
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <dlfcn.h>
static int (*real_mutex_lock)(pthread_mutex_t *) __attribute__((__may_alias__));
static void *pthread_libhandle;
#ifdef _BIT64
#define PTHREAD_PATH "/lib64/libpthread.so.0"
#else
#define PTHREAD_PATH "/lib/libpthread.so.0"
#endif
static inline void load_real_function(char* function_name, void** real_func) {
char* msg;
*(void**) (real_func) = dlsym(pthread_libhandle, function_name);
msg = dlerror();
if (msg != NULL)
printf("init: real_%s load error %s\n", function_name, msg);
}
void __attribute__((constructor)) my_init(void) {
printf("init: trying to dlopen '%s'\n", PTHREAD_PATH);
pthread_libhandle = dlopen(PTHREAD_PATH, RTLD_LAZY);
if (pthread_libhandle == NULL) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
load_real_function("pthread_mutex_lock", (void**) &real_mutex_lock);
}
ラッパーとバックトレースの呼び出し。メソッドから可能な限り切り刻んだので、たとえば、元の pthread_mutex_lock を決して呼び出さないことはわかっています。
void my_backtrace(void) {
#define SIZE 100
void *buffer[SIZE];
int nptrs;
nptrs = backtrace(buffer, SIZE);
printf("backtrace() returned %d addresses\n", nptrs);
}
int pthread_mutex_lock(pthread_mutex_t *mutex) {
printf("In pthread_mutex_lock\n"); fflush(stdout);
my_backtrace();
return 0;
}
これをテストするには、次のバイナリ (ファイルtst_mutex.c
)を使用します。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int main (int argc, char *argv[]) {
pthread_mutex_t x;
printf("Before mutex\n"); fflush(stdout);
pthread_mutex_lock(&x);
printf("after mutex\n");fflush(stdout);
return 0;
}
これがすべてコンパイルされる方法です:
rm -f *.o *.so tst_mutex
cc -Wall -D_BIT64 -c -m64 -fPIC libmutex.c
cc -m64 -o libmutex.so -shared -fPIC -ldl -lpthread libmutex.o
cc -Wall -m64 tst_mutex.c -o tst_mutex
そして走る
LD_PRELOAD=$(pwd)/libmutex.so ./tst_mutex
これは、Linux x86 ではセグメンテーション違反でクラッシュします。Linux PPC では、すべてが問題なく動作します。GCC コンパイラ、GLIBC ライブラリ、および Linux ディストリビューションのいくつかのバージョンを試しましたが、すべて失敗しました。
出力は
init: trying to dlopen '/lib64/libpthread.so.0'
Before mutex
In pthread_mutex_lock
In pthread_mutex_lock
In pthread_mutex_lock
...
...
./run.sh: line 1: 25023 Segmentation fault LD_PRELOAD=$(pwd)/libmutex.so ./tst_mutex
ここに再帰があることを示唆しています。ソース コードを確認しましたbacktrace()
-ロック メカニズムへの呼び出しはありません。スタック フレームのリンクされたリストを簡単に確認するだけです。また、objdump を使用してライブラリ コードをチェックしましたが、異常なことは何も明らかになりませんでした。
ここで何が起きてるの?解決策/回避策はありますか?
ああ、そしておそらく最も重要なこと。これは pthread_mutex_lock 関数でのみ発生します!! 他のオーバーライドされた pthread_* 関数からのスタックの出力は問題なく動作します...