2010-06-14 6 views
1

작은 디버그 유틸리티를 작성하려고했는데이 이름에 해당 함수/전역 변수 주소를 가져와야합니다. 이것은 내장 된 디버그 유틸리티입니다. 즉, 디버그 유틸리티가 디버깅 할 코드 내에서 실행되거나 실행 파일을 구문 분석 할 수 없습니다.이름에서 함수 주소를 얻으십시오 [.debug_info ??]

이제는 잘 알려진 방법이 있습니까? 내가 가진 계획 *이 섹션은

.DATA { (*. 데이터) __sym_start를 [내가 LD 스크립트에 다음과 같이 싸구려 속임수에 의해 할 계획] 메모리에로드 할 .debug_을 만드는 것입니다 =.; (디버그 _); __sym_end =.; }

지금 내가 필요한 정보를 얻기 위해 섹션을 구문 분석해야하지만, 이것이 가능하거나이 문제가 있는지 확실하지 않습니다. 이것은 모두 이론에 불과합니다. 그러나 그것은 또한 너무 많은 일처럼 보입니다 :-) 간단한 방법이 있습니다. 또는 누군가 내 계획이 효과가없는 이유를 사전에 말할 수 있다면 도움이 될 수도 있습니다.

미리 감사드립니다. 알렉스.

+0

당신이 말하는 플랫폼을 지정해야합니다. – nategoose

답변

0

당신은에 당신이 할 수 있어야 dlopen(3)dlsym(3) (리눅스 등)가있는 시스템에서 실행하는 경우 :

char thing_string[] = "thing_you_want_to_look_up"; 
void * handle = dlopen(NULL, RTLD_LAZY | RTLD_NOLOAD); 
    // you could do RTLD_NOW as well. shouldn't matter 
if (!handle) { 
    fprintf(stderr, "Dynamic linking on main module : %s\n", dlerror()); 
    exit(1); 
} 

void * addr = dlsym(handle, thing_string); 
fprintf(stderr, "%s is at %p\n", thing_string, addr); 

내가 다른 시스템이 작업을 수행하는 가장 좋은 방법을 모르는,이 아마 정적 변수 및 함수에는 작동하지 않습니다. C++ 심볼 이름은 그들과 함께 작업하는 데 관심이 있다면 엉망이됩니다.

공유 라이브러리에서이 기능을 확장하려면 /proc/self/maps에서 현재로드 된 라이브러리의 이름을 가져온 다음 라이브러리 파일 이름을 dlopen으로 전달하십시오. 그러나 라이브러리 이름이 변경되거나 삭제 된 경우 실패 할 수 있습니다.

다른 여러 가지 방법이 있습니다.

편집

/* name_addr.h */ 
struct name_addr { 
    const char * sym_name; 
    const void * sym_addr; 
}; 
typedef struct name_addr name_addr_t; 
void * sym_lookup(cost char * name); 
extern const name_addr_t name_addr_table; 
extern const unsigned name_addr_table_size; 

/* name_addr_table.c */ 
#include "name_addr.h" 

#define PREMEMBER(X) extern const void * X 
#define REMEMBER(X) { .sym_name = #X , .sym_addr = (void *) X } 

PREMEMBER(strcmp); 
PREMEMBER(printf); 
PREMEMBER(main); 
PREMEMBER(memcmp); 
PREMEMBER(bsearch); 
PREMEMBER(sym_lookup); 
/* ... */ 

const name_addr_t name_addr_table[] = 
{ 
     /* You could do a #include here that included the list, which would allow you 
     * to have an empty list by default without regenerating the entire file, as 
     * long as your compiler only warns about missing include targets. 
     */ 
    REMEMBER(strcmp), 
    REMEMBER(printf), 
    REMEMBER(main), 
    REMEMBER(memcmp), 
    REMEMBER(bsearch), 
    REMEMBER(sym_lookup); 
    /* ... */ 
}; 
const unsigned name_addr_table_size = sizeof(name_addr_table)/sizeof(name_addr_t); 

/* name_addr_code.c */ 
#include "name_addr.h" 
#include <string.h> 

void * sym_lookup(cost char * name) { 
    unsigned to_go = name_addr_table_size; 
    const name_addr_t *na = name_addr_table; 
    while(to_to) { 
     if (!strcmp(name, na->sym_name)) { 
      return na->sym_addr; 
     } 
     na++; 
     to_do--; 
    } 
    /* set errno here if you are using errno */ 
    return NULL; /* Or some other illegal value */ 
} 

dlopen을를 사용하지 않고 당신은 링커가 주소에서 작성 처리됩니다 이런 식으로 할 경우 너 모든 후. ng가 배치되었습니다. 테이블에 나열한 모든 심볼에 헤더 파일을 포함 시키면 테이블 파일을 컴파일 할 때 경고 메시지가 나타나지 않지만 모든 파일을 extern void *으로 설정하고 컴파일러에서 경고하도록하면 훨씬 쉽습니다. 그것들 모두 (이것은 가능할지라도 반드시 그런 것은 아니다).

기호를 반복해서 반복하지 않고 이진 검색을 사용할 수 있도록 기호를 정렬 할 수도 있습니다.

테이블에 sqrt에 대한 항목이 있지만 전화를 걸지 않은 것처럼 프로그램에서 다른 방법으로 참조되지 않는 멤버가있는 경우 링커에서 다음을 원한다는 점에 유의해야합니다.)를 사용하여 해당 기능을 이미지에 연결하십시오. 이것은 그것을 폭파시킬 수 있습니다.

또한 전역 최적화 기능을 사용하는 경우이 테이블을 사용하면 컴파일러에서 나열된 모든 함수가이 목록의 포인터를 통해 액세스 될 수 있으며 모든 콜 포인트.

정적 함수를이 목록에 넣는 것은 쉽지 않습니다. 테이블을 동적으로 변경하고 각 모듈의 함수에서 런타임에 수행하거나 테이블이있는 객체 파일에 새 섹션을 생성하여이 작업을 수행 할 수 있습니다. gcc :

#define SECTION_REMEMBER(X) \ 
    static const name_addr_t _name_addr##X = \ 
    {.sym_name= #X , .sym_addr = (void *) X } \ 
    __attribute__(section("sym_lookup_table")) 

그리고 각 파일 끝에 기억하고 싶은 모든 기호가있는 .c 파일의 끝에이 목록을 추가하십시오. 이것은 링커가 링커가이 멤버들로 무엇을해야 하는지를 알 수 있도록하지만, 그 멤버가 상주하는 섹션의 시작과 끝을 보면서리스트를 반복 할 수있다. (정확히 어떻게 해야할지 모르겠다. 이 일은 끝날 수 있지만 너무 어렵지는 않습니다.) 하지만 이렇게하면 정렬 된 목록이 더 어려워집니다. 또한, 문자열 리터럴의 주소로 .sym_name을 초기화하는 것이이 섹션에 문자열을 주입하는 결과를 가져 오지는 않을 것이라고 완전히 확신하지는 않지만, 그렇게 생각하지는 않습니다. 만약 그렇다면 이것은 일을 망칠 것입니다.

여전히 objdump를 사용하여 개체 파일 (아마도 elf)에 포함 된 기호 목록을 가져온 다음 관심있는 기호에 대해 필터링 한 다음 테이블 구성원이 나열한 테이블 파일을 다시 생성 할 수 있습니다.

+0

안녕하세요, 답변 해 주셔서 감사합니다. 그러나 나는 dlopen을 가지고 있지 않은 아주 작은 ukernel을 연구 중이다. dlopen()이 어떻게 작동하는지 궁금합니다. 어떻게 주소를 찾습니까? 감사합니다. 알렉스. – MGH

+0

그것은 연결 상징 표에서 그것을 본다. ELF 오브젝트 파일을 사용하는 경우 libelf 및 사용자 정의 코드를 사용하여 파일 섹션이로드 된 위치를 찾을 수 있습니다. 그러나 당신은 합리적인 답을주기 위해 어느 시스템이 실행되어야하는지에 대해 더 많은 정보를 제공해야 할 것입니다. 불합리한 대답은 각 함수 이름과 주소로 C 코드에서 실행되는 awk 또는 perl 스크립트와 같은 테이블을 만드는 것입니다 (스크립트의 출력은'struct {char * name; void * addr;}'당신의 프로그램에 추가 할 값 – nategoose

+0

안녕하세요, 저는 사실 debug_info + debug_abbrev + debug_pubnames를 데이터 세그먼트의 메모리로로드하고 그것을 파싱하여 내 정보를 얻으려는 계획을 시험해 보았습니다. 그것을 작동 시키려면 :-) 나는 실제 시스템에서 시도하기 전에 * linux *에서 이것을 실제로 시도했다. 요청하신 실제 시스템은 마이크로 커널이며, 작성하고자하는 코드는 마이크로 커널과 함께 제공됩니다 (내장 된 종류의 응용 프로그램이며 prog @ runtime을로드 할 수 없습니다). 커널 이미지는 elf 형식이므로이 스키마를 사용해 볼 수 있다고 생각합니다. 그러나 이것은 간단한 일을하기에는 너무 많은 코드라고 생각합니다 :-( – MGH

관련 문제