Отладка 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)

Спасибо.

Ответ 1

Ничего, что я пробовал, не исправит это (попробовал как компиляторы, так и отладчики и т.д.) После обновления 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
}

Что это!

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

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

Ответ 2

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

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

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

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

(и т.д.)

Ответ 3

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

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

Что все!

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

Ответ 4

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

(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, просто скопируйте адреса с выхода консоли и вставьте их в терминал.

Ответ 5

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

Ответ 6

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

Введите здесь отчет об ошибке.

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

EDIT:

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

Ответ 7

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

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;
}

Ответ 8

В приглашении консоли отладки Xcode введите:

image lookup -a 0x1234

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

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

Ответ 9

Для меня работала настройка "Компиляция для большого пальца" (настройка отладки).