문제

기능 이름을 얻는 방법 기능의 포인터 C에서?

편집 : 실제 사례는 Linux 커널 모듈을 작성하고 있으며 커널 기능을 호출합니다. 이러한 기능 중 일부는 포인터이며 커널 소스에서 해당 함수의 코드를 검사하고 싶습니다. 그러나 나는 그것이 어떤 기능을 가리키고 있는지 모른다. 시스템이 실패 할 때 (커널 공황) 화면에서 기능 이름이있는 현재 콜 스택을 인쇄하기 때문에 수행 할 수 있다고 생각했습니다. 하지만 내가 틀린 것 같아요 ... 나야?

도움이 되었습니까?

해결책

추가 지원 없이는 직접 불가능합니다.

당신은 할 수 있습니다 :

  1. 프로그램 매핑 함수 포인터에서 테이블을 이름으로 유지합니다.

  2. 실행 파일의 심볼 테이블이있는 경우 검사하십시오.

그러나 후자는 어렵고 휴대 할 수 없습니다. 이 방법은 운영 체제의 이진 형식 (ELF, A.out, .Exe 등) 및 링커가 수행 한 재배치에 따라 다릅니다.

편집 : 실제 사용 사례가 무엇인지 설명 했으므로 실제로 대답은 그렇게 어렵지 않습니다. 커널 기호 테이블은 사용할 수 있습니다 /proc/kallsyms, 그리고 액세스하기위한 API가 있습니다.

#include <linux/kallsyms.h>

const char *kallsyms_lookup(unsigned long addr, unsigned long *symbolsize,
                            unsigned long *ofset, char **modname, char *namebuf)

void print_symbol(const char *fmt, unsigned long addr)

간단한 디버그 목적으로 후자는 아마도 필요한 것을 정확하게 수행 할 것입니다. 주소를 가져 가고 형식화하고 printk, 또는 사용할 수 있습니다 printk 이랑 %pF 형식 지정자.

다른 팁

모두가 불가능하다고 말하는 이유에 놀랐습니다. 비 정적 기능은 Linux에서 가능합니다.

나는 이것을 달성하는 두 가지 이상을 알고 있습니다.

배경 인쇄를위한 GNU 기능이 있습니다. backtrace() 그리고 backtrace_symbols() (보다 man). 귀하의 경우에는 필요하지 않습니다 backtrace() 이미 기능 포인터가 있으므로 backtrace_symbols().

예 (작동 코드) :

#include <stdio.h>
#include <execinfo.h>

void foo(void) {
    printf("foo\n");
}

int main(int argc, char *argv[]) {
    void    *funptr = &foo;

    backtrace_symbols_fd(&funptr, 1, 1);

    return 0;
}

컴파일 gcc test.c -rdynamic

산출: ./a.out(foo+0x0)[0x8048634]

이진 이름, 기능 이름, 기능 시작 및 포인터 값에서 포인터 오프셋을 제공하여 구문 분석 할 수 있습니다.

또 다른 방법은 사용하는 것입니다 dladdr() (또 다른 확장), 나는 추측한다 print_backtrace() 용도 dladdr(). dladdr() 보고 Dl_info 기능 이름이있는 구조 dli_sname 필드. 나는 여기에 코드 예제를 제공하지 않지만 분명하다 - man dladdr 자세한 내용은.

NB! 두 가지 접근 방식 모두 기능이 아닌 기능이 필요합니다!

글쎄, 한 가지 더 방법이 있습니다 - 디버그 정보를 사용하여 사용하십시오. libdwarf 그러나 스트리핑되지 않은 바이너리가 필요하고 쉽지 않기 때문에 권장하지 않습니다.

Linux 커널에서는 직접 사용할 수 있습니다 "%pf" Printk의 형식!

void *func = &foo;
printk("func: %pF at address: %p\n", func, func);

다음은 Linux에서 저를 작동시킵니다.

  • Printf 사용 기능의 주소를 사용합니다 %p
  • 그런 다음하십시오 nm <program_path> | grep <address> (없이 0x 접두사)
  • 함수 이름을 보여 주어야합니다.

해당 기능이 동일한 프로그램에있는 경우에만 작동합니다 (동적으로 연결된 라이브러리 등이 아님).

로드 된 공유 라이브러리의로드 주소를 찾을 수 있다면 인쇄 번호에서 주소를 빼고 라이브러리에서 NM을 사용하여 기능 이름을 찾을 수 있습니다.

당신은 차별적으로 할 수 없지만 원하는 경우이 문제에 대한 다른 접근 방식을 구현할 수 있습니다. 당신은 당신이 원하는대로 설정할 수있는 설명 문자열뿐만 아니라 함수를 가리키는 대신 구조물 포인터를 만들 수 있습니다. 또한이 VARS가 Printet을 영원히 원하지 않기 때문에 디버깅 포스 빌티를 추가했습니다.

// Define it like this
typedef struct
{
  char        *dec_text;
  #ifdef _DEBUG_FUNC
  void        (*action)(char);
  #endif
} func_Struct;

// Initialize it like this
func_Struct func[3]= {
#ifdef _DEBUG_FUNC
{"my_Set(char input)",&my_Set}};
{"my_Get(char input)",&my_Get}};
{"my_Clr(char input)",&my_Clr}};
#else
{&my_Set}};
{&my_Get}};
{&my_Clr}};
#endif 

// And finally you can use it like this
func[0].action( 0x45 );
#ifdef _DEBUG_FUNC
printf("%s",func.dec_text);
#endif

지적 할 수있는 기능 목록이 너무 크지 않거나 이미 작은 기능 그룹을 의심하는 경우 주소를 인쇄하여 실행 중에 사용되는 주소와 비교할 수 있습니다. 전:

typedef void (*simpleFP)();
typedef struct functionMETA {
    simpleFP funcPtr;
    char * funcName;
} functionMETA;

void f1() {/*do something*/}
void f2() {/*do something*/}
void f3() {/*do something*/}

int main()
{
    void (*funPointer)() = f2; // you ignore this
    funPointer(); // this is all you see

    printf("f1 %p\n", f1);
    printf("f2 %p\n", f2);
    printf("f3 %p\n", f3);

    printf("%p\n", funPointer);

    // if you want to print the name
    struct functionMETA arrFuncPtrs[3] = {{f1, "f1"}, {f2, "f2"} , {f3, "f3"}};

    int i;
    for(i=0; i<3; i++) {
        if( funPointer == arrFuncPtrs[i].funcPtr )
            printf("function name: %s\n", arrFuncPtrs[i].funcName);
    }
}

산출:

f1 0x40051b
f2 0x400521
f3 0x400527
0x400521
function name: f2

이 접근법은 정적 기능에도 작동합니다.

일반적으로하는 방법은 없습니다.

해당 코드를 DLL/공유 라이브러리로 컴파일하는 경우 모든 진입 지점을 입대하고 가지고있는 포인터와 비교할 수 있어야합니다. 아직 시도하지는 않았지만 DLLS/Shared Libs에 대한 경험이 있으며 작동 할 것으로 기대합니다. 이것은 심지어 교차 계획을 작동시키기 위해 구현 될 수도 있습니다.

다른 사람이 이미 디버그 기호로 컴파일한다고 언급 한 다음, 디버거가하는 일과 비슷한 실행중인 애플리케이션에서이를 분석하는 방법을 찾을 수 있습니다. 그러나 이것은 절대적으로 독점적이며 휴대용이 아닙니다.

  1. 사용 kallsyms_lookup_name() 주소를 찾으려면 kallsyms_lookup.

  2. 가리키는 기능 포인터를 사용하십시오 kallsyms_lookup, 그것을 부르기 위해.

체크 아웃 시각적 누출 감지기 그들이 콜 스택 인쇄가 어떻게 작동하는지 확인합니다. 그러나 이것은 당신이 Windows를 사용하고 있다고 가정합니다.

질문이 무엇을 요구하는지가 아니라 여기서 답을 읽은 후에도 비슷한 문제에 대한이 해결책이 있습니다.

/**
* search methods */
static int starts(const char *str, const char *c);
static int fuzzy(const char *str, const char *c);

int (*search_method)(const char *, const char *);

/* asign the search_method and do other stuff */
[...]

printf("The search method is %s\n", search_method == starts ? "starts" : "fuzzy")

프로그램이 많이 필요한 경우 xmacro의 문자열과 함께 메소드 이름을 정의하고 사용 할 수 있습니다. #define X(name, str) ... #undef X 코드에서 함수 이름에서 해당 문자열을 가져옵니다.

당신은 할 수 없습니다. 함수 이름은 컴파일되고 연결될 때까지 함수에 첨부되지 않습니다. 그것은 이름이 아닌 그 시점에서 메모리 주소에 의한 것입니다.

당신은 반사 거울없이 어떻게 생겼는지 모를 것입니다. C#과 같은 반사 가능 언어를 사용해야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top