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()将主可执行文件的路径复制到缓冲区bufbufsize参数最初应该是缓冲区的大小。 如果路径成功复制,则此函数返回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; }