2013-09-08 9 views
2

Я проанализировал адреса, имена файлов и номера строк из файла dSYM для приложения iOS. У меня в основном есть таблица, которая сопоставляет адрес с именем файла и номером строки, что очень полезно для отладки.dSYM Address Lookup

Чтобы получить actual lookup address, я использую адрес трассировки стека из отчета о сбое и использую формулу, указанную в этом ответе: https://stackoverflow.com/a/13576028/2758234. Так что-то вроде этого.

(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 символизировать отчет о сбоях.

Почему это происходит?

ответ

3

Для вопроса № 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 (который может появиться в отчете аварии).

Вы также можете выполнить отличную команду «сбросить свою внутреннюю таблицу строк» ​​в lldb с помощью target modules dump line-table. Например, я составил привет-мир Mac приложения:

(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 вызывает другую функцию, последняя инструкция функции может быть вызовом - без функции epilogue - потому что она знает, что она никогда не получит контроль снова. Довольно редко. Но в этом случае симпатичная символика даст вам указатель на первую инструкцию следующей функции в памяти. Debuggers et al используют трюк, в котором они вычитают 1 из обратного адреса при поиске символа/исходного кода, чтобы обойти эту проблему, но это не то, что обычно бывает в случайных символиках. И вы должны быть осторожны, чтобы не выполнять трюк decr-pc в текущей исполняемой функции (фрейм 0), потому что функция, возможно, только что начала выполнять, и вы не хотите делать резервную копию компьютера в предыдущей функции и неправильно отображаете ,