Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the path of a library from its handle (macOS / iOS)?

I have a handle to a dynamic library (from using dlopen()). Regardless of why, I don't have access to what the path supplied to dlopen() was, but need the path for another function. Thus, I need to be able to acquire the path to the library using its handle.

I've tried using dladdr(), as I have in other parts of my app, but on macOS / iOS you aren't able to use it to find the path of a library using the handle to the library it only works with a handle to a symbol in the library. I could try adding a "locator symbol" to the library, and accomplish things this way, but I'd prefer not to.

I also tried dlinfo() with RTLD_DI_LINKMAP, but this is apparently not available on macOS / iOS.

like image 426
Tom Metzger Avatar asked Jan 21 '26 23:01

Tom Metzger


1 Answers

I'm surprised at how little information there is out there for this. Many of the solutions out there were not available on macOS / iOS. Others still, were only about getting the path of the current executable, and had nothing to do with the handle.

After a TON of searching, I finally came across some resources saying to iterate through all the loaded images using _dyld_image_count() and _dyld_get_image_name(). I initially decided against this, as it just didn't seem like an unreasonably slow way of doing things.

Eventually, I decided to go with iterating over all the loaded images, as it was the only actual solution I had come across. I googled for examples, and couldn't find any tutorials on the topic. However, I did come across an open source C++ library that implemented the functionality (found here).

I translated it to normal C, and got rid of some excess things (such as stripping the handle). During the testing process, I noticed that the library I wanted was always last in the list (my best guess is that it stores them in the order they were loaded, and since mine isn't a system library, it will be one of the last ones loaded). This guaranteed a slow performance (in reference to the computer - to a human it'd still be nearly instantaneous). So, I did a clever optimization that started the search at the end of the list, rather than the beginning.

This is the final code for my solution:

// NOT a thread safe way of doing things
NSString *pathFromHandle(void* handle)
{
    // Since we know the image we want will always be near the end of the list, start there and go backwards
    for (int i = ((int)_dyld_image_count() - 1); i >= 0; i--)
    {
        const char* image_name = _dyld_get_image_name(i);
        
        // Why dlopen doesn't effect _dyld stuff: if an image is already loaded, it returns the existing handle.
        void* probe_handle = dlopen(image_name, RTLD_LAZY);
        dlclose(probe_handle);
        
        if (handle == probe_handle)
        {
            return [NSString stringWithUTF8String:image_name];
        }
    }
    
    
    return NULL;
}

It's important to note that this solution is not thread safe, as _dyld_image_count() and _dyld_get_image_name() are inherently not thread safe. This means that any other thread could load / unload an image and have a negative impact on our search.

Additionally, the resource I used questioned why dlopen didn't have an effect on _dyld_image_count(). This is because if an image is already loaded, dlopen does not load a new instance of the image, but rather returns the existing handle for it.

like image 180
Tom Metzger Avatar answered Jan 25 '26 05:01

Tom Metzger



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!