Поиск смещений локальных символов в общих библиотеках программно в OS X

Мне нужно найти смещение локального символа в общей библиотеке на OS X. Локальный символ как в неэкспортированном символе. Следовательно dyld("symbol_name") не будет работать.

Я могу однако использовать nm чтобы найти эти смещения, например

$ nm /System/Library/PrivateFrameworks/DesktopServicesPriv.framework/DesktopServicesPriv  | grep -e ChildSetLabel -e NodeVolumeEject
000000000006cccd T _NodeVolumeEject
000000000009dbd7 t __ChildSetLabel

Там мы видим экспортированный (T) условное обозначение NodeVolumeEject который смещен 0x6cccd Я могу легко показать, используя dyld("NodeVolumeEject"), dyld() покажет адрес в текущем адресном пространстве, но я доволен либо смещением в общей библиотеке, либо абсолютным адресом в адресном пространстве. Кроме того, есть местный (t) условное обозначение _ChildSetLabel который смещен (0x9dbd7) Я не могу раскрыть использование dyld(),

Я хотел бы иметь возможность сделать это разрешение программно (без gobjdump, nm, otoolили любая другая внешняя программа). Есть ли "легкий" способ добиться этого? Исходный код инструментов, упомянутых выше, содержит необходимый код, но мне интересно, нет ли чего-то более простого.

Домен: решение должно работать только на OS X 10.8 или лучше для двоичных файлов x86_64 MachO.

Пояснение: я был бы рад выяснить абсолютное смещение в текущем смещении (которое из-за ASLR) не является статичным, очевидно. Но я также счастлив выяснить смещение относительно начала этой библиотеки, которое остается статическим (до перекомпиляции). Часть от "адреса в библиотеке" до "адреса в адресном пространстве" довольно проста:

off_t sym_offset_child_set_label = ANSWER_TO_THIS_QUESTION("_ChildSetLabel");
Dl_info info;
void *abs_volume_eject = dlsym(RTLD_DEFAULT, "NodeVolumeEject");
void *abs_child_set_label = NULL;
if (dladdr(abs_volume_eject, &info)) {
    abs_child_set_label = (void *)((char *)info.dli_fbase + sym_offset_child_set_label);

    /* abs_child_set_label now points to the function in question */
}

Это до тех пор, пока _ChildSetLabel а также NodeVolumeEject находятся в той же общей библиотеке достаточно. Поэтому ASLR здесь не проблема.

1 ответ

Решение

Еще одна возможность (то, что я в конечном итоге использовал) является частным от Apple CoreSymbolication фреймворк:

void *resolve_private(const char *symbol_owner, const char *symbol_to_resolve)
{
    task_t targetTask;
    int err = task_for_pid(mach_task_self(), getpid(), &targetTask);
    if (err) {
        fprintf(stderr, "couldn't get my Mach task\n");
        return NULL;
    }

    CSSymbolicatorRef targetSymbolicator;

    targetSymbolicator = CSSymbolicatorCreateWithTaskFlagsAndNotification(targetTask,
                                                                              kCSSymbolicatorTrackDyldActivity,
                                                                          ^(uint32_t     notification_type, CSNotificationData data) {
                                                                          });
    if(CSIsNull(targetSymbolicator)) {
        fprintf("CSSymbolicatorCreateWithTaskFlagsAndNotification failed\n");
        return NULL;
    }

    __block CSSymbolOwnerRef symbolOwner = kCSNull;
    CSSymbolicatorForeachSymbolOwnerWithNameAtTime(targetSymbolicator,
                                                   symbol_owner,
                                                   kCSNow,
                                                   ^(CSSymbolOwnerRef owner) {
                                                       symbolOwner = owner;
                                                   });
    if (CSIsNull(symbolOwner)) {
        CSRelease(targetSymbolicator);
        fprintf("CSSymbolicatorForeachSymbolOwnerWithNameAtTime failed\n");
        return NULL;
    }

    __block uintptr_t p = (uintptr_t)NULL;
    CSSymbolOwnerForeachSymbol(symbolOwner, ^(CSSymbolRef symbol) {
        const char *symbol_name = CSSymbolGetMangledName(symbol);
        if (0 == strcmp(symbol_name, symbol_to_resolve)) {
            p = CSSymbolGetRange(symbol).location;
        }
    });

    CSRelease(targetSymbolicator);
    if ((uintptr_t)NULL == p) {
        fprintf("symbol not found\n");
        return NULL;
    } else {
        return (void *)p;
    }
}
Другие вопросы по тегам