C에서 함수의 포인터에서 함수 이름을 얻는 방법?
-
20-08-2019 - |
문제
기능 이름을 얻는 방법 기능의 포인터 C에서?
편집 : 실제 사례는 Linux 커널 모듈을 작성하고 있으며 커널 기능을 호출합니다. 이러한 기능 중 일부는 포인터이며 커널 소스에서 해당 함수의 코드를 검사하고 싶습니다. 그러나 나는 그것이 어떤 기능을 가리키고 있는지 모른다. 시스템이 실패 할 때 (커널 공황) 화면에서 기능 이름이있는 현재 콜 스택을 인쇄하기 때문에 수행 할 수 있다고 생각했습니다. 하지만 내가 틀린 것 같아요 ... 나야?
해결책
추가 지원 없이는 직접 불가능합니다.
당신은 할 수 있습니다 :
프로그램 매핑 함수 포인터에서 테이블을 이름으로 유지합니다.
실행 파일의 심볼 테이블이있는 경우 검사하십시오.
그러나 후자는 어렵고 휴대 할 수 없습니다. 이 방법은 운영 체제의 이진 형식 (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에 대한 경험이 있으며 작동 할 것으로 기대합니다. 이것은 심지어 교차 계획을 작동시키기 위해 구현 될 수도 있습니다.
다른 사람이 이미 디버그 기호로 컴파일한다고 언급 한 다음, 디버거가하는 일과 비슷한 실행중인 애플리케이션에서이를 분석하는 방법을 찾을 수 있습니다. 그러나 이것은 절대적으로 독점적이며 휴대용이 아닙니다.
사용
kallsyms_lookup_name()
주소를 찾으려면kallsyms_lookup
.가리키는 기능 포인터를 사용하십시오
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#과 같은 반사 가능 언어를 사용해야합니다.