Отладка 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
Для меня работала настройка "Компиляция для большого пальца" (настройка отладки).