Почему backtrace не содержит символов Objective-C независимо от -rdynamic? - PullRequest
2 голосов
/ 15 сентября 2010

Обновление: Я работаю с GNU-runtime в Linux. Проблема возникает , а не в MacOS с Apple-runtime.

Обновление 2: Я скомпилировал среду исполнения GNU на MacOS и собрал с ней пример. Ошибка не возникает в MacOS с GNU-средой выполнения. Я бы сказал, что проблема в glibc (поскольку backtrace и backtrace_symbols являются расширениями glibc).

При печати трассировки в скомпилированном GCC-приложении Objective-C с использованием backtrace и backtrace_symbols я не получаю никаких символов Objective-C. Отображаются только имена файлов, адреса и символы C.

Я скомпилирован с -g и связан с -rdynamic.

Мое тестовое приложение:

void _printTrace()
{
    void *addr[1024];
    int aCount = backtrace(addr, 1024);
    char **frameStrings = backtrace_symbols(addr, aCount);
    for (int i = 0; i < aCount; i++) {
        printf("%s\n", frameStrings[i]);
    }
    free(frameStrings);
}

@interface TheObject
+ (void)_printTrace;
+ (void)printTrace;
@end

@implementation TheObject
+ (void)_printTrace
{
    _printTrace();
}

+ (void)printTrace
{
    [self _printTrace];
}
@end

void printTrace()
{
    [TheObject printTrace];
}

int main(int argc, char **argv)
{
    printTrace();
    return 0;
}

и вывод:

./test.bin(_printTrace+0x1f) [0x8048e05]
./test.bin() [0x8048e60]
./test.bin() [0x8048e8b]
./test.bin(printTrace+0x34) [0x8048ec5]
./test.bin(main+0xf) [0x8048eda]
/lib/libc.so.6(__libc_start_main+0xe5) [0xb7643bb5]
./test.bin() [0x8048b51]

Есть ли способ, чтобы символы Objective-C появлялись в этом обратном следе?

Ответы [ 3 ]

2 голосов
/ 18 октября 2010

dladdr() сообщает только о глобальных и слабых символах.Но все функциональные символы Objective C являются локальными:

$ readelf -s so_backtrace

Symbol table '.dynsym' contains 29 entries:
…

Symbol table '.symtab' contains 121 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
…
    49: 08048a01    13 FUNC    LOCAL  DEFAULT   14 _c_TheObject___printTrace
    50: 08048a0e    47 FUNC    LOCAL  DEFAULT   14 _c_TheObject__printTrace
…

Вы можете убедиться, что локальные символы никогда не возвращаются, посмотрев исходный код GNU libc самостоятельно.backtrace_symbols() определяется в sysdeps / generic / elf / backtracesyms.c.Он использует _dl_addr(), который определен в elf / dl-addr.c, для предоставления ему имен символов.Это в конечном итоге называет determine_info().Если это возможно, он использует хэш-таблицу GNU , которая не включает в себя локальные символы:

49       /* We look at all symbol table entries referenced by the hash
50          table.  */
…
60                   /* The hash table never references local symbols so
61                      we can omit that test here.  */

Если хеш-таблица GNU отсутствует, она возвращается кстандартная хеш-таблица.Это включает в себя все символы, но код determine_info() отфильтровывает все, кроме глобальных символов и слабых символов:

90         if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL
91              || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)

Чтобы символизировать адреса функций Objective C, вы должны выполнить поисксебя и не отфильтровывать символы локальных функций.Кроме того, вам придется разобрать символы функции Objective C, чтобы восстановить _c_TheObject___printTrace в +[TheObject _printTrace].

1 голос
/ 18 октября 2010

Реализация NSException GNUstep не использует backtrace, вместо этого она использует libbfd (дескриптор двоичного файла). Я думаю, что функция, которая действительно выполняет эту работу, называется static void find_address, которую вы можете просмотреть здесь . Используя этот тривиальный пример, я получаю следующие результаты.

#include <Foundation/Foundation.h>

@interface Test : NSObject {}
+ (void) test;
@end

@implementation Test
+ (void) test
{
    Class GSStackTrace = objc_getClass("GSStackTrace");

    id stack = [GSStackTrace currentStack];

    for (int i = 0; i < [stack frameCount]; i++)
    {
        NSLog (@"%@", [[stack frameAt:i] function]);
    }
}
@end

int main(int argc, char **argv)
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [Test test];

    [pool release];

    return 0;
}

Вывод (при компиляции с отладочными символами):

2010-10-18 14:14:46.188 a.out[29091] +[GSStackTrace currentStack]
2010-10-18 14:14:46.190 a.out[29091] +[Test test]
2010-10-18 14:14:46.190 a.out[29091] main
2010-10-18 14:14:46.190 a.out[29091] __libc_start_main

Возможно, вы сможете отделить GSStackTrace. Это & ldquo; private & rdquo; class (вот почему мне нужно использовать objc_getClass, вы также получите много нераспознанных предупреждений селектора), но, похоже, он содержит весь код, необходимый для чтения имен классов Objective-C.

Протестировано в Ubuntu 9.04 с GNUstep, настроенным на --enable-debug (так что GSFunctionInfo включен в сборку).

0 голосов
/ 30 сентября 2010

Полагаю, вам нужно будет запросить во время выполнения ObjC адреса, чтобы получить информацию о символах.Адреса, возвращаемые функцией backtrace (), вероятно, могут быть переданы, например, в object_getClass () для получения класса.Я не пробовал ничего из этого, но именно в этом случае я бы посмотрел дальше.

...