Поиск адреса dSYM
Я проанализировал адреса, имена файлов и номера строк из файла dSYM для приложения для iOS. У меня в основном есть таблица, которая отображает адрес на имя файла и номер строки, что очень полезно для отладки.
Чтобы получить actual lookup address
Я использую адрес трассировки стека из отчета о сбое и использую формулу, указанную в этом ответе: /questions/30822325/otchetyi-o-sboyah-ios-atos-ne-rabotaet-dolzhnyim-obrazom/30822348#30822348. Ну как то так.
(actual lookup address)
= (stack trace address) + (virtual memory slide) - (image load address)
Я использую этот адрес и ищу его на своем столе. Полученное мной имя файла является правильным, но номер строки всегда указывает на конец вызванной функции или метода, а не на фактическую строку, вызвавшую следующую функцию в трассировке стека.
Я где-то читал, не могу вспомнить, где, что адреса кадров должны быть помечены, потому что они выровнены, чтобы удвоить размер системного указателя. Таким образом, для 32-битных систем размер указателя составляет 4 байта, поэтому мы удалим теги, используя 8 байтов, используя следующую формулу:
(de-tagged address) = (tagged address) & ~(sizeof(uintptr_t)*2 - 1)
где uintptr_t
тип данных, используемый для указателей в Objective-C.
После этого поиск вроде работает, но мне нужно что-то вроде поиска ближайшего адреса, который меньше или равен адресу без метки.
Вопрос № 1:
Почему я должен снять метку с адреса стекового фрейма? Почему в трассировке стека адреса не указывают на правильное место?
Вопрос № 2:
Иногда в отчете о сбое, кажется, отсутствует кадр. Например, если function1()
звонки function2()
какие звонки function3()
какие звонки function4()
в моей трассировке стека я увижу что-то вроде:
0 Exception
1 function4()
2 function3()
4 function1()
И адрес трассировки стека для function3()
(кадр 2, выше) даже не указывает на правильный номер строки (но это правильный файл), даже после удаления тегов. Я вижу это, даже когда позволяю Xcode символизировать отчет о сбое.
Почему это происходит?
1 ответ
Для вопроса № 1 адреса в отчете о сбое iOS имеют три компонента, которые учитываются: исходный адрес загрузки вашего приложения, случайное значение слайда, которое было добавлено к этому адресу при запуске приложения, и смещение в пределах двоичный файл. В конце отчета о сбое должна быть строка, показывающая фактический адрес загрузки вашего двоичного файла.
Чтобы вычислить слайд, вам нужно взять фактический адрес загрузки из отчета о сбое и вычесть исходный адрес загрузки. Это говорит о случайном значении слайда, которое было применено к данному конкретному запуску приложения.
Я не уверен, как вы получили свою таблицу - проблема может лежать там. Вы можете перепроверить, используя lldb. Вы можете загрузить свое приложение в lldb и сказать lldb, что оно должно быть загружено по адресу 0x140000 (это будет фактический адрес загрузки из вашего отчета о сбое, не беспокойтесь о слайдах и оригинальных адресах загрузки)
% xcrun lldb
(lldb) target create -d -a armv7 /path/to/myapp.app
(lldb) target modules load -f myapp __TEXT 0x140000
Теперь в lldb загружен ваш двоичный файл по фактическому адресу загрузки в этом отчете о сбое. Вы можете делать все обычные запросы в lldb, такие как
(lldb) image lookup -v -a 0x144100
сделать подробный поиск по адресу 0x144100 (который может появиться в вашем отчете о сбое).
Вы также можете сделать изящную команду "dump your table line table" в lldb с помощью target modules dump line-table
, Например, я скомпилировал приложение Mac для hello-world:
(lldb) tar mod dump line-table a.c
Line table for /tmp/a.c in `a.out
0x0000000100000f20: /tmp/a.c:3
0x0000000100000f2f: /tmp/a.c:4:5
0x0000000100000f39: /tmp/a.c:5:1
0x0000000100000f44: /tmp/a.c:5:1
(lldb)
Я могу изменить адрес загрузки моего бинарного файла и попробовать сбросить таблицу строк еще раз:
(lldb) tar mod load -f a.out __TEXT 0x200000000
section '__TEXT' loaded at 0x200000000
(lldb) tar mod dump line-table a.c
Line table for /tmp/a.c in `a.out
0x0000000200000f20: /tmp/a.c:3
0x0000000200000f2f: /tmp/a.c:4:5
0x0000000200000f39: /tmp/a.c:5:1
0x0000000200000f44: /tmp/a.c:5:1
(lldb)
Я не уверен, что понимаю, что вы делаете с удалением тегов адресов. Адреса в стеке вызовов являются адресами возврата этих функций, а не инструкциями вызова, поэтому они могут указывать на строку, следующую за фактической строкой источника вызова / отправки метода, но обычно это легко понять, когда вы смотрите на источник код. Если все ваши поиски указывают на конец методов, я думаю, что у вашей схемы поиска может быть проблема.
Что касается вопроса № 2, то раскрутка кадра № 1 может быть немного сложной, если кадр № 0 (текущий выполняемый кадр) является конечной функцией, которая не устанавливает кадр стека или находится в процессе установки. до кадра стека. В этих случаях кадр № 1 может быть пропущен. Но как только вы пройдете кадр № 1, особенно на руке, раскрутка не должна пропустить ни одного кадра.
Существует одна очень морщинка, когда функция помечена noreturn
вызывает другую функцию, последней инструкцией функции может быть вызов - без эпилога функции - потому что он знает, что никогда не получит контроль снова. Довольно необычно. Но в этом случае простая символика даст вам указатель на первую инструкцию следующей функции в памяти. Отладчики и др. Используют хитрость, при которой они вычитают 1 из адреса возврата, когда выполняют поиск строки символа / источника, чтобы обойти эту проблему, но это не то, о чем обычно нужно беспокоиться случайным символикам. И вы должны быть осторожны, чтобы не выполнять трюк decr-pc для выполняемой в данный момент функции (кадр 0), потому что функция, возможно, только что начала выполняться, и вы не хотите выполнять резервное копирование ПК в предыдущую функцию и неправильно обозначать символы,