2013-04-24 5 views
3

다음을 시도합니다. pthreads 라이브러리의 래퍼를 작성하여 각 API를 호출 할 때마다 일부 정보를 기록합니다. 기록하고 싶은 정보는 스택 추적입니다.리눅스 x86에서 backtrace()를 호출 할 때 세그먼테이션 오류가 발생했습니다.

다음은 컴파일하고 그대로 실행할 수있는 원본 코드의 최소 코드입니다.

의 초기화 (파일 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이라는 함수를 호출하지 않는다는 것을 알고있다. 여기

#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; 
} 

이 컴파일되는 모든 방법은 다음과 같습니다 :
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을)이를 테스트하려면

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_ * 함수에서 스택을 인쇄하면 정상적으로 작동합니다 ...

+0

RTLD_NOW로 시도해 보셨나요? – stark

+0

문제는 pthreads 라이브러리를 여는 것이 아닙니다. –

+0

당신의 단계를 시도했지만'./tst_mutex : symbol lookup error : libmutex.so : undefined symbol : dlopen' 오류가납니다. 지금 문제를 해결하지는 않겠지 만 문제를 재현하기위한 단계에서 뭔가가 누락되었을 수 있습니다. –

답변

0

무한 재귀 (@Chris Dodd에 의해 언급 됨)로 인한 스택 오버플로입니다. backtrace() 함수는 pthread 라이브러리없이 컴파일 된 프로그램에서 호출되는 다른 시스템 호출을 실행합니다. pthread 함수가 프로그램에서 명시 적으로 호출되지 않더라도.

다음은 backtrace() 함수를 사용하고 pthread 함수를 사용하지 않는 간단한 프로그램입니다.

pthread에 링크하지 않고 컴파일하고 strace 유틸리티를 사용하여 프로그램 시스템 호출을 검사하십시오. 뮤텍스 관련 시스템 호출이 출력에 표시되지 않습니다.

$ gcc -o backtrace_no_thread backtrace.c 
$ strace -o backtrace_no_thread.out backtrace_no_thread 

아니오 동일한 코드를 pthread 라이브러리에 연결하여 컴파일하면 strace를 실행하고 출력을 살펴보십시오.

$ gcc -o backtrace_with_thread backtrace.c -lpthread 
$ strace -o backtrace_with_thread.out backtrace_with_thread 

이번에 출력에는 뮤텍스 관련 시스템 호출이 포함됩니다 (이름은 플랫폼에 따라 다를 수 있음). 다음은 X86 Linux 컴퓨터에서 얻은 strace 출력 파일의 일부입니다.

futex(0x3240553f80, FUTEX_WAKE_PRIVATE, 2147483647) = 0 
futex(0x324480d350, FUTEX_WAKE_PRIVATE, 2147483647) = 0 
관련 문제