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

140

У меня проблема с отладкой 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)

Спасибо.

cekisakurek
источник

Ответы:

256

Ничто из того, что я пробовал, не исправило бы это (пробовал оба компилятора, оба отладчика и т. Д.). После обновления 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 ниже)
Зейн Клаас
источник
1
Рад это слышать :) Я считаю полезным записать журнал сбоев в файл и предложить пользователю отправить его при следующем запуске (только в режиме выпуска, чтобы не мешать отладке). Это позволяет мне получать отличные отчеты об ошибках ... и пользователи знают, что их проблема решается :)
Zane Claes
2
Кажется, это не работает - uncaughtExceptionHandlerпроцедура никогда не запускается.
Hot Licks
1
Не могли бы вы подробнее рассказать, как его использовать? Похоже, у меня это не работает.
Danut Pralea
1
Довольно печально, что xCode не показывает нам этого.
Authman Apatira
1
Очень признателен! Удивительно, что Apple не реализует такую ​​рудиментарную функциональность в IDE.
devios1 08
110

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

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

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

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

(так далее)

МудрыйСтарыйУтка
источник
3
У меня это пока работает отлично. Теперь отладчик останавливается на аварийной строке, нет необходимости в обратной трассировке.
Тим
1
У меня это тоже отлично работает. Большое вам спасибо, я сошел с ума без этой точки останова ...
Уильям Деннисс
+1 за это сработало. Это не дает вам такого приятного сообщения об ошибке, объясняющего причину исключения, но это начало ...
Нику Сурду,
ты мой HotD @WiseOldDuck.
Maverick,
Это восстанавливает для меня ожидаемое поведение. ПРИМЕЧАНИЕ: Также не забудьте повторно добавить эту точку останова в новых проектах!
MechEthan
46

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

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

Вот и все!

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

Педро
источник
Определенно это решение для меня.
bradgonesurfing
Это было проблемой для меня. У нас с коллегой один и тот же проект Xcode, и я спросил его, есть ли у него проблема, а у него нет. Разница была , что его проект разрывалось на Objective-C исключений (objc_exception_throw)
horseshoe7
Вы только что помогли найти неотслеживаемую ошибку. Огромное спасибо. Я везде искал что-то подобное.
rjgonzo
1
Это работает как шарм! Это именно то, что я искал, это лучше, чем добавление обработчика исключений, поскольку добавление точки останова может привести вас прямо к тому месту, где было выброшено исключение, обработчик исключений работает, но просто дает вам представление.
im8bit
21

Вот еще одно решение, не такое элегантное, как предыдущее, но если вы не добавляли точки останова или обработчики исключений, это может быть только один путь.
Когда приложение вылетает из строя и вы получаете необработанный стек вызовов первого вызова (в шестнадцатеричном формате), введите в консоль 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, просто скопируйте адреса из вывода консоли и вставьте их в терминал.

Александр
источник
9

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

MonsieurDart
источник
6

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

Отправьте отчет об ошибке здесь.

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

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

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

Logancautrell
источник
да, я пробовал переключать компиляторы, но проблема осталась. но все
равно
Он предложил переключать отладчики, а не компиляторы.
bames53
1
К вашему сведению: в данном случае это не имеет ничего общего с используемой вами версией компилятора или отладчика. Это изменение в выводе консоли iOS.
clarkcox3
Интересно, насколько разнится этот опыт - я думаю, что есть несколько проблем. Мне не удалось заставить отладчик останавливаться на точке останова исключения. Переход с GDB на LLDB решил проблему.
Мэтт
6

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

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;
}
Уилсон Лин
источник
Похоже, это не работает с раскадровками. 2012-06-04 20: 34: 52.211 Проблемы [1944: 207] Делегат приложения должен реализовать свойство окна, если он хочет использовать основной файл раскадровки. 2012-06-04 20: 34: 52.213 Проблемы [1944: 207] Ожидается, что приложения будут иметь корневой контроллер представления в конце запуска приложения
macasas 04
6

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

image lookup -a 0x1234

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

  Address: MyApp[0x00018eb0] (MyApp.__TEXT.__text + 91088)
  Summary: MyApp`-[MyViewController viewDidAppear:] + 192 at MyViewController.m:202
Мэтт Коннолли
источник
Спасибо, я действительно это искал. Удивительно, но нет никакого ярлыка для отображения всего «стека вызовов первого вызова» в виде стека вызовов, потому что я думаю, сценарий Python lldb можно легко написать.
Илья
1

У меня сработало включение «Компилировать для большого пальца» (конфигурация отладки).

Брэдвайзер86
источник