Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding frameworks being linked to a project in Xcode

I saw this question: How can I programatically get the list of frameworks and libraries included in an ios project? here, which tries to answer similar question. However, I've two questions on this

  1. The answer in above link (or see code below) - does it provide all frameworks or "only" frameworks that are linked to the project.

    for (NSBundle *framework in [NSBundle allFrameworks]) 
        NSLog(@"%@",framework.bundlePath.lastPathComponent);
    
  2. if I see a framework appearing in above code, how can I find its usage in my code. I see many frameworks being referred to in above code, but I'm not able to figure out where exactly are they used. As per my knowledge, few of them are not used - is there a proper way to find this out.

Update 1: I made a simple new app with absolutely no code in it. Then, I executed the for loop above and found that, it also presented me with all the frameworks - which means, the code above simply prints all the frameworks and not the one that I am essentially be using in my app. But, does it mean that all frameworks that are printed are linked to the app?

like image 523
prabodhprakash Avatar asked Oct 30 '22 02:10

prabodhprakash


1 Answers

The dynamic loader dyld(3) provides this information. This code will print all loaded frameworks and shared libraries as well:

#include <stdio.h>
#include <dlfcn.h>
#include <mach-o/dyld.h>

int main() {
    uint32_t c = _dyld_image_count();

    for(uint32_t i = 0; i < c; ++i) {
        printf("%d: %s\n", i, _dyld_get_image_name(i));
    }
    return 0;
}

EDIT: allFrameworks lists only frameworks which are linked to your app, and which contain at least one Objective-C class (see https://developer.apple.com/documentation/foundation/nsbundle/1408056-allframeworks).

Searching for referrers is should be very difficult in general. If you are just looking for a single function, you can add a static implementation of the function and call the loaded variant from it. This technique is used for overwriting __cxa_throw for instance, but it should also work for other functions:

static cxa_throw_t sCxa_throw = 0;

extern "C" void __cxa_throw(void *inException, void *inPvtinfo, void (*inDestination)(void *)) {
    if (sCxa_throw == NULL) {
        sCxa_throw = (cxa_throw_t)dlsym(RTLD_NEXT, "__cxa_throw");
    }
    sCxa_throw(inException, inPvtinfo, inDestination);
}

The variable sCXA_throw contains the reference to the dynamic version of this function while the loader uses the static version. Inside of this function you can determine the callers with unwinding the stack with libunwind.

like image 148
clemens Avatar answered Nov 15 '22 06:11

clemens