exported symbol 被设置为空时怎么通过__builtin_return_address获得objective-c的方法名
时间: 2024-03-17 12:44:45 浏览: 14
当 exported symbol 被设置为空时,可以通过 `__builtin_return_address` 函数获取当前函数的返回地址,然后再通过 Objective-C 的运行时 API `sel_getName` 函数获取对应的方法名。
具体步骤如下:
1. 在代码中调用 `__builtin_return_address` 函数获取当前函数的返回地址,例如:
```c
void *retAddr = __builtin_return_address(0);
```
2. 调用 Objective-C 的运行时 API `sel_registerName` 函数将返回地址转换为对应的方法选择器,例如:
```c
SEL sel = (SEL)retAddr;
```
3. 调用 Objective-C 的运行时 API `sel_getName` 函数获取方法选择器对应的方法名,例如:
```c
const char *methodName = sel_getName(sel);
```
这样就可以通过 `__builtin_return_address` 和 Objective-C 的运行时 API `sel_getName` 函数获取到当前函数对应的方法名了。
相关问题
还有其他方法能 在exported symbol 被设置为空时怎么通过__builtin_return_address获得objective-c的方法名
除了使用 `__builtin_return_address` 和 Objective-C 的运行时 API `sel_getName` 函数外,还可以使用 `dladdr` 函数获取当前函数所在的动态链接库(或可执行文件)的信息,进而获取当前函数对应的符号名称,再通过 Objective-C 的运行时 API `NSSelectorFromString` 函数将符号名称转换为对应的方法选择器,最终获取方法名。
具体步骤如下:
1. 在代码中调用 `__builtin_return_address` 函数获取当前函数的返回地址,例如:
```c
void *retAddr = __builtin_return_address(0);
```
2. 调用 `dladdr` 函数获取返回地址所在的动态链接库(或可执行文件)的信息,例如:
```c
Dl_info info;
dladdr(retAddr, &info);
```
3. 通过 `info.dli_sname` 可以获取当前函数对应的符号名称,例如:
```c
const char *symbolName = info.dli_sname;
```
4. 将符号名称转换为对应的方法选择器,例如:
```c
SEL sel = NSSelectorFromString([NSString stringWithUTF8String:symbolName]);
```
5. 最后,通过 Objective-C 的运行时 API `sel_getName` 函数获取方法选择器对应的方法名,例如:
```c
const char *methodName = sel_getName(sel);
```
这样就可以通过 `__builtin_return_address` 和 `dladdr` 函数获取当前函数对应的方法名了。需要注意的是,使用 `dladdr` 函数获取符号名称可能存在一定的限制和不稳定性,具体需要根据使用场景进行评估。
Exported symbol为空时怎么获取函数名
如果一个函数没有导出符号,无法通过`dladdr`函数获取函数名。但是我们可以通过解析可执行文件的符号表获取函数名。
首先需要使用`dlopen`函数打开可执行文件,然后通过`dlsym`函数获取可执行文件中函数的地址。接着使用`nm`命令或`libbfd`库解析可执行文件的符号表,找到函数的名称。
以下是一个示例代码,可以获取可执行文件中所有函数的名称:
```c++
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <bfd.h>
#include <string.h>
#include <errno.h>
void print_function_name(void* addr) {
Dl_info info;
if (dladdr(addr, &info) && info.dli_sname) {
printf("%s\n", info.dli_sname);
return;
}
bfd* abfd;
bfd_init();
abfd = bfd_openr("/path/to/executable", 0);
if (!abfd) {
fprintf(stderr, "Failed to open executable: %s\n", strerror(errno));
return;
}
if (!bfd_check_format(abfd, bfd_object)) {
fprintf(stderr, "Invalid executable format\n");
bfd_close(abfd);
return;
}
long storage_needed = bfd_get_symtab_upper_bound(abfd);
if (storage_needed < 0) {
fprintf(stderr, "Failed to get symbol table size\n");
bfd_close(abfd);
return;
}
asymbol** symbol_table = (asymbol**)malloc(storage_needed);
long symbols_read = bfd_canonicalize_symtab(abfd, symbol_table);
if (symbols_read < 0) {
fprintf(stderr, "Failed to read symbol table\n");
bfd_close(abfd);
free(symbol_table);
return;
}
for (long i = 0; i < symbols_read; ++i) {
if (symbol_table[i]->flags & BSF_FUNCTION) {
bfd_vma value = symbol_table[i]->value;
if (value == (bfd_vma)addr) {
printf("%s\n", symbol_table[i]->name);
}
}
}
bfd_close(abfd);
free(symbol_table);
}
int main() {
// Call some functions
print_function_name((void*)&main);
print_function_name((void*)&printf);
print_function_name((void*)&print_function_name);
return 0;
}
```
需要注意的是,`libbfd`库是GNU binutils的一部分,需要安装binutils才能使用。另外,该库可能会影响程序性能,因为它需要解析可执行文件的符号表。