Отладка Xcode 4.2 не символизирует вызов стека

У меня проблема с отладкой Xcode 4.2 в симуляторе / устройстве iOS 5. Следующий код вылетает, как и ожидалось:

NSArray *arr=[NSArray array];
[arr objectAtIndex:100];

В iOS 4 я получаю полезную трассировку стека шестнадцатеричных чисел. Но в iOS 5 это просто дает мне:

*** First throw call stack:
(0x16b4052 0x1845d0a 0x16a0674 0x294c 0x6f89d6 0x6f98a6 0x708743 0x7091f8 0x7fcaa9 0x2257fa9 0x16881c5 0x15ed022 0x15eb90a 0x15eadb4 0x15eaccb 0x6f02a7 0x6faa93 0x2889 0x2805)

Благодарю.

9 ответов

Решение

Ничто из того, что я пробовал, не исправило бы это (пробовал оба компилятора, оба отладчика и т. Д.) После обновления XCode для обновления iOS 5, похоже, не работали никакие следы стека.

Однако я нашел эффективный обходной путь - создание собственного обработчика исключений (что также полезно по другим причинам). Сначала создайте функцию, которая будет обрабатывать ошибку и выводить ее на консоль (а также все, что вы хотите с ней сделать):

void uncaughtExceptionHandler(NSException *exception) {
    NSLog(@"CRASH: %@", exception);
    NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
    // Internal error reporting
}

Затем добавьте обработчик исключений в ваш делегат приложения:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{   
    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
    // Normal launch stuff
}

Это оно!

Если это не работает, то есть только две возможные причины:

  1. Что-то перезаписывает твой NSSetUncaughtExceptionHandler вызов (может быть только один обработчик для всего вашего приложения). Например, некоторые сторонние библиотеки устанавливают свои собственные uncaughtExceptionHandler. Итак, попробуйте установить его в конце вашего didFinishLaunchingWithOptions функция (или выборочное отключение сторонних библиотек). Или еще лучше, установите символическую точку останова на NSSetUncaughtExceptionHandler чтобы быстро увидеть, кто это звонит. То, что вы можете сделать, это изменить свой текущий, а не добавлять другой.
  2. Вы на самом деле не сталкиваетесь с исключением (например, EXC_BAD_ACCESS не исключение; благодарность за комментарии @Erik B, ниже)

Существует полезная опция добавления точки останова исключения (с помощью + в нижней части навигатора точек останова). Это будет нарушать любое исключение (или вы можете установить условия). Я не знаю, является ли этот выбор новым в 4.2 или я только наконец заметил это, пытаясь обойти проблему отсутствующих символов.

Как только вы достигнете этой точки останова, вы можете использовать Debug Navigator для навигации по стеку вызовов, проверки переменных и т. Д. Как обычно.

Если вы хотите использовать символьный стек вызовов, подходящий для копирования / вставки и т. П., Обратная трассировка gdb будет работать нормально:

(gdb) bt
#0  0x01f84cf0 in objc_exception_throw ()
#1  0x019efced in -[NSObject doesNotRecognizeSelector:] ()

(так далее)

В отладчике появилась новая функция. Вы можете установить точку останова всякий раз, когда выдается исключение, и сразу же останавливать выполнение, как это происходило в 4.0.

В "Навигаторе точек останова" добавьте "Точку останова исключений" и просто нажмите "Готово" во всплывающем окне параметров.

Это все!

PS: В некоторых случаях было бы лучше разбить только для исключений Objective-C.

Вот еще одно решение, не такое элегантное, как предыдущее, но если вы не добавили точки останова или обработчики исключений, это может быть только один путь.
Когда приложение падает, и вы получаете свой первый стек вызовов броска (в шестнадцатеричных числах), введите в консоль Xcode info line *hex (не забудьте звезду и 0x шестнадцатеричный спецификатор), например:

(gdb) info line *0x2658
Line 15 of "path/to/file/main.m" starts at address 0x25f2 <main+50>
and ends at 0x267e <main+190>.

Если вы используете lldb, вы можете набрать image lookup -a hex (без звезды в этой ситуации), и вы получите аналогичный вывод.

С помощью этого метода вы можете перейти от вершины стека броска (будет около 5-7 распространителей системных исключений) к вашей функции, которая вызвала сбой, и определить точный файл и строку кода.

Также, для аналогичного эффекта вы можете использовать утилиту atos в терминале, просто наберите:

atos -o path/to/AplicationBundle.app/Executable 0xAdress1 0xAdress2 0xAdress3 ...

и вы получите символическую трассировку стека (по крайней мере, для функций у вас есть символы отладки). Этот метод более предпочтителен, потому что у вас нет для каждого вызова адреса info lineПросто скопируйте адреса из консоли и вставьте их в терминал.

Вы можете добавить точку останова исключения (используя + в нижней части навигатора точек останова) и добавить действие bt к нему (нажмите кнопку "Добавить действие", выберите команду "Отладчик", введите "bt" в текстовое поле). Это отобразит трассировку стека, как только будет сгенерировано исключение.

Это распространенная проблема, не получая трассировки стека в 4.2. Вы можете попробовать переключиться между LLDB и GDB, чтобы увидеть, если вы получите лучшие результаты.

Подайте отчет об ошибке здесь.

http://developer.apple.com/bugreporter/

РЕДАКТИРОВАТЬ:

Я полагаю, что если вы вернетесь к LLVM GCC 4.2, вы этого не увидите. Вы можете потерять функции, которые вам нужны.

Используйте этот код в вашей основной функции:

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

    int retVal;
    @try {
        retVal = UIApplicationMain(argc, argv, nil, nil);
    }
    @catch (NSException *exception) {
        NSLog(@"CRASH: %@", exception);
        NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
    }
    @finally {
        [pool release];
    }
    return retVal;
}

В командной строке отладки Xcode введите:

image lookup -a 0x1234

И это покажет вам что-то вроде:

  Address: MyApp[0x00018eb0] (MyApp.__TEXT.__text + 91088)
  Summary: MyApp`-[MyViewController viewDidAppear:] + 192 at MyViewController.m:202

Повторное включение "Compile for Thumb" (отладочная конфигурация) мне помогло.

Другие вопросы по тегам