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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With