dl_iterate_phdr等效于Mac
我想迭代所有加载的共享库并获取它们的基地址和文件名。 这基本上是Linux上的dl_iterate_phdr
。
但我想为Mac做同样的事情。
dyld(3)手册页(似乎不再在线)中记录的function似乎提供了类似的function。
这是内容:
名称
_dyld_image_count, _dyld_get_image_header, _dyld_get_image_vmaddr_slide, _dyld_get_image_name, _dyld_register_func_for_add_image, _dyld_register_func_for_remove_image, NSVersionOfRunTimeLibrary, NSVersionOfLinkTimeLibrary _NSGetExecutablePath
概要
#include
uint32_t _dyld_image_count(void); const struct mach_header* _dyld_get_image_header(uint32_t image_index); intptr_t _dyld_get_image_vmaddr_slide(uint32_t image_index); const char* _dyld_get_image_name(uint32_t image_index); void _dyld_register_func_for_add_image(void (*func)(const struct mach_header* mh, intptr_t vmaddr_slide)); void _dyld_register_func_for_remove_image(void (*func)(const struct mach_header* mh, intptr_t vmaddr_slide)); int32_t NSVersionOfRunTimeLibrary(const char* libraryName); int32_t NSVersionOfLinkTimeLibrary(const char* libraryName); int _NSGetExecutablePath(char* buf, uint32_t* bufsize); 描述
这些例程提供了超出
dlopen()
和dladdr()
提供的dyld的额外内省
_dyld_image_count()
返回dyld映射的当前图像数。 请注意,使用此计数迭代所有图像不是线程安全的,因为另一个线程可能在迭代期间添加或删除图像。
_dyld_get_image_header()
返回指向由image_index索引的图像的mach头的指针。 如果image_index
超出范围,则返回NULL。
_dyld_get_image_vmaddr_slide()
返回由image_index
索引的图像的image_index
内存地址幻灯片数量。 如果image_index
超出范围,则返回零。
_dyld_get_image_name()
返回由image_index
索引的图像的名称。 C字符串继续由dyld拥有,不应删除。 如果image_index
超出范围,则返回NULL。
_dyld_register_func_for_add_image()
在向程序添加新映像(包或动态共享库)时注册要调用的指定函数。 首次注册此function时,对于当前属于该过程的每个图像,将调用一次该function。
_dyld_register_func_for_remove_image()
注册从进程中删除图像(包或动态共享库)时要调用的指定函数。
NSVersionOfRunTimeLibrary()
返回由libraryName指定的当前加载的dylib的current_version编号。 libraryName参数对于/path/libbar.3.dylib是“bar”,对于/path/Foo.framework/Versions/A/Foo是“Foo”。 如果没有加载这样的库,则此函数返回-1。
NSVersionOfLinkTimeLibrary()
返回主可执行文件在构建时链接的current_version编号。 libraryName参数对于/path/libbar.3.dylib是“bar”,对于/path/Foo.framework/Versions/A/Foo是“Foo”。 如果主可执行文件未链接到指定的库,则此函数返回-1。
_NSGetExecutablePath()
将主可执行文件的路径复制到缓冲区buf
。bufsize
参数最初应该是缓冲区的大小。 如果路径成功复制,则此函数返回0,并且*bufsize
保持不变。 如果缓冲区不够大,则返回-1,并且*bufsize
设置为所需的大小。 请注意,_NSGetExecutablePath()
将返回可执行文件的“路径”,而不是可执行文件的“实际路径”。 也就是说,路径可以是符号链接而不是真实文件。 对于深度目录,所需的总bufsize可能超过MAXPATHLEN
。
刚完成:
输入是指向某些静态内容(例如函数)的任何指针,目标是查找库及其部分。
我在ptr_is_in_exe
函数中实现了这个:
static bool ptr_is_in_exe(const void *ptr, const struct mach_header *& header, intptr_t& offset, uintptr_t& vmaddr, std::string& image_name) { uint32_t i, count = _dyld_image_count(); for (i = 0; i < count; i++) { header = _dyld_get_image_header(i); offset = _dyld_get_image_vmaddr_slide(i); uint32_t j = 0; struct load_command* cmd = (struct load_command*)((char *)header + sizeof(struct mach_header)); if(header->magic == MH_MAGIC_64) cmd = (struct load_command*)((char *)header + sizeof(struct mach_header_64)); while (j < header->ncmds) { if (cmd->cmd == LC_SEGMENT) { struct segment_command* seg = (struct segment_command*)cmd; if (((intptr_t)ptr >= (seg->vmaddr + offset)) && ((intptr_t)ptr < (seg->vmaddr + offset + seg->vmsize))) { vmaddr = seg->vmaddr; image_name = _dyld_get_image_name(i); return true; } } if (cmd->cmd == LC_SEGMENT_64) { struct segment_command_64* seg = (struct segment_command_64*)cmd; if (((uintptr_t)ptr >= (seg->vmaddr + offset)) && ((uintptr_t)ptr < (seg->vmaddr + offset + seg->vmsize))) { vmaddr = seg->vmaddr; image_name = _dyld_get_image_name(i); return true; } } j++; cmd = (struct load_command*)((char*)cmd + cmd->cmdsize); } } return false; }