#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
}
Вот и все!
Если это не сработает, то есть только две возможные причины:
- Что-то перезаписывает ваш
NSSetUncaughtExceptionHandler
вызов (для всего вашего приложения может быть только один обработчик). Например, некоторые сторонние библиотеки устанавливают свой собственный UncaughtExceptionHandler. Итак, попробуйте установить его в КОНЦЕ вашейdidFinishLaunchingWithOptions
функции (или выборочно отключить сторонние библиотеки). Или, что еще лучше, установите символическую точку остановаNSSetUncaughtExceptionHandler
, чтобы быстро увидеть, кто ее вызывает. Что вы можете сделать, так это изменить свой текущий, а не добавлять другой. - На самом деле вы не сталкиваетесь с исключением (например,
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» (конфигурация отладки).