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

#ios #xcode #debug-symbols

#iOS #xcode #debug-символы

Вопрос:

У меня проблема с отладкой 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(amp;uncaughtExceptionHandler);
    // Normal launch stuff
}
 

Вот и все!

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

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

Комментарии:

1. Рад это слышать 🙂 Я считаю полезным записать журнал сбоев в файл и предложить пользователю отправить его при следующем запуске (только в режиме выпуска, чтобы не мешать отладке). Это позволяет мне получать отличные отчеты об ошибках… и пользователи знают, что их проблема решается 🙂

2. Похоже, это не работает — uncaughtExceptionHandler процедура никогда не вызывается.

3. Не могли бы вы уточнить, как его использовать? Похоже, у меня это не работает.

4. Довольно грустный xCode не отображает это для нас.

5. Очень признателен! Сбивает с толку тот факт, что Apple не внедряет такую элементарную функциональность в IDE.

Ответ №2:

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

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

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

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

(и т.д.)

Комментарии:

1. Пока это отлично работает для меня. Теперь отладчик останавливается на аварийной строке, нет необходимости в обратном отслеживании.

2. Это отлично работает и для меня. Большое вам спасибо, я сходил с ума без этой точки останова…

3. 1 за то, что это сработало. Это не дает вам такого приятного сообщения об ошибке, объясняющего причину исключения, но это только начало…

4. ты мой горячий друг @WiseOldDuck.

5. Это восстанавливает ожидаемое поведение для меня. ПРИМЕЧАНИЕ: Также не забудьте повторно добавить эту точку останова в новые проекты!

Ответ №3:

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

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

Вот и все!

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

Комментарии:

1. Определенно, это решение для меня.

2. Это было проблемой для меня. Мы с коллегой используем один и тот же проект Xcode, и я спросил его, есть ли у него проблема, и он не был. Разница заключалась в том, что его проект прерывался из-за исключений objective-c (objc_exception_throw)

3. Вы только что помогли найти неотслеживаемую ошибку. Большое вам спасибо. Я везде искал что-то подобное.

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

Ответ №4:

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

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

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

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

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

Ответ №5:

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

Ответ №6:

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

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

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

Редактировать:

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

Комментарии:

1. да, я попытался переключить компиляторы, однако проблема остается. но в любом случае спасибо 🙂

2. Он предложил переключать отладчики, а не компиляторы.

3. К вашему сведению: в данном случае это не имеет ничего общего с версией используемого вами компилятора или отладчика. Это изменение в выводе консоли из iOS.

4. Интересно, насколько сильно это влияет — я думаю, есть несколько проблем. Мне не удалось заставить отладчик остановиться на точке останова исключения. Переключение с GDB на LLDB решило проблему.

Ответ №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;
}
 

Комментарии:

1. Похоже, это не работает с раскадровками. 2012-06-04 20:34:52.211 Проблемы [1944:207] Делегат приложения должен реализовать свойство window, если он хочет использовать основной файл раскадровки. 2012-06-04 20:34:52.213 Проблемы [1944:207] Ожидается, что приложения будут иметь корневой контроллер представления в конце запуска приложения

Ответ №8:

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

image lookup -a 0x1234

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

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

Комментарии:

1. Спасибо, я действительно искал это. Удивительно, что нет ярлыка для отображения всего «стека вызовов первого броска» в виде стека вызовов, поскольку я предполагаю, что сценарий lldb на Python может быть легко написан.

Ответ №9:

Для меня сработало включение «Compile for Thumb» (конфигурация отладки).