dl_iterate_phdr等效于Mac

时间:2012-04-04 10:08:14

标签: c macos

我想迭代所有加载的共享库并获取它们的基地址和文件名。这基本上是Linux上的dl_iterate_phdr

但我想为Mac做同样的事情。

2 个答案:

答案 0 :(得分:3)

刚刚完成:

输入是指向某些静态内容(例如函数)的任何指针,目标是查找库及其部分。

我在ptr_is_in_exe函数中实现了此here

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;
}

答案 1 :(得分:2)

dyld(3)手册页(似乎不再在线)中记录的功能似乎提供了类似的功能。

以下是该内容:

  

NAME

 _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 <mach-o/dyld.h>

 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);
     

说明

     

这些例程提供了对dyld的额外反省   由dlopen()dladdr()

提供      

_dyld_image_count()返回映射的当前图像数   通过dyld。请注意,使用此计数来迭代所有图像不是   线程安全,因为另一个线程可能是添加或删除图像   在迭代期间。

     

_dyld_get_image_header()返回一个指向the mach标题的指针   由image_index索引的图像。如果image_index超出范围,则为NULL   归还。

     

_dyld_get_image_vmaddr_slide()返回虚拟内存地址   由image_index索引的图像的幻灯片数量。如果image_index   超出范围归零。

     

_dyld_get_image_name()返回索引的图像的名称   image_index。 C-string继续由dyld拥有并且应该   没有删除。如果image_index超出范围,则返回NULL。

     

_dyld_register_func_for_add_image()注册指定的函数   添加新图像时要调用(捆绑或动态共享)   图书馆)到该计划。首次注册此功能时,它是   为当前属于该过程的每个图像调用一次。

     

_dyld_register_func_for_remove_image()注册指定的   删除图像时要调用的函数(包或动态)   来自流程的共享库。

     

NSVersionOfRunTimeLibrary()返回current_version数   由libraryName指定的当前加载的dylib。该   对于/path/libbar.3.dylib和,libraryName参数为“bar”   对于/path/Foo.framework/Versions/A/Foo,“Foo”。此函数返回   如果没有加载这样的库,则为-1。

     

NSVersionOfLinkTimeLibrary()返回当前的版本号   主要可执行文件在构建时链接。 libraryName   对于/path/libbar.3.dylib和“Foo”,参数将是“bar”   /path/Foo.framework/Versions/A/Foo。如果是,此函数返回-1   主可执行文件没有链接到指定的库。

     

_NSGetExecutablePath()将主要可执行文件的路径复制到   缓冲区bufbufsize参数最初应该是。{   缓冲区的大小。如果路径是,则此函数返回0   成功复制,和   * bufsize保持不变。如果缓冲区不够大,则返回-1,并将* bufsize设置为所需的大小。注意   _NSGetExecutablePath()将返回可执行文件的“路径”而不是a   可执行文件的“真实路径”。也就是说,路径可以是符号的   链接而不是真实的文件。使用深层目录总bufsize   需要的可能超过MAXPATHLEN