Я использовал следующую арифметику для иллюстрации это:
slide
+ stack address
- load address
= symbol address
и
stack address
является шестнадцатеричное значение я получаю от моего отчета об ошибке стека дампа (не .crash файл, просто стек дампа).
и
slide
является vmaddr из LC_SEGMENT ЦМД при запуске otool -arch armv7 -l APP_BINARY_PATH
. Шахта обычно заканчивается 0x00001000.
и
load address
является сложным кусок. На самом деле это разница между самым нижним адресом стека основного потока и адресом FIRST части моего двоичного файла, которая содержит символы при запуске dwarfdump --arch armv7 --all DSYM_BINARY_PATH
. Это просто символический адрес функции main
. Поэтому, если ваш самый нижний адрес сбоя - 0x8000, а символический адрес вашей основной функции - 0x2000, то ваш load address
равен 0x6000.
Теперь со всеми этими частями я могу вычислить адрес символа и поместить его в atos или dwarfdump: dwarfdump --lookup SYM_ADDR --arch armv7 APP_BINARY_PATH
.
Пример дампа (вы можете увидеть, что load address
был 0x00003af4):
----------------------------------------------------------------------
Файл: /Users/user/Desktop/MyApp.xcarchive/dSYMs/MyApp.app.dSYM/Содержание/Ресурсы/DWARF/MyApp (ARMv7)
----------------------------------------------------------------------
0x00000024: [0x00003af4 - 0x00003b4e) Главный
0x00000098: [0x00003b50 - 0x00003d8c) - [MyAppDelegate применения: didFinishLaunchingWithOptions:]
... остальная часть свалки
Самая трудная часть была понимая, что один из 2-х статических библиотек I» d включили, если бы их символы разделились, прежде чем ссылаться на двоичный файл моего приложения! Это оставило ОГРОМНЫЙ пробел в символьных адресах, поэтому я только закончил с двумя третями символов, которые мне нужны в моем dSYM.
Обязательно иметь следующие флаги, установленные для NO в вашем статическом проекте библиотеки Xcode, так что, когда вы ссылаетесь на него, вы можете тянуть в символах, чтобы ваше приложение бинарного (которые впоследствии могут быть удалены): COPY_PHASE_STRIP
, DEAD_CODE_STRIPPING
, и STRIP_INSTALLED_PRODUCT
.
Теперь вы можете спросить: «Что мне делать, если дамп стека не включает основную функцию, так как он не находится в основном потоке, так что я не могу получить адрес стека главной функции?». На это я бы ответил: «У меня нет подсказки!». Просто скрестите пальцы и надейтесь, что вы можете получить трассировку стека, которая включает в себя адрес символа, или использовать систему отчетов о сбоях, которая имитирует журналы сбоев Apple, такие как PLCrashReporter.
[EDIT 26 мая 2013] -
Это было доведено до моего сведения, что load address
действительно адрес маш-о двоичной системе. Хотя то, что я описал выше, часто может работать - на самом деле это неверно. Это можно получить с помощью CRASH REPORT, однако точкой этого ответа было предоставление символов сбоя, когда у вас нет отчета о сбоях. Лучший способ, которым я пришел к выяснению load address
, когда вы хотите его символизировать, - это убедиться, что я зарегистрировал load address
с stack addresses
.
Я лично создал систему для регистрации сбоев (не отчетов о сбоях) и отправки их в ведро S3, где я могу получить их позже для отладки. Когда я запускаю свое приложение, я кэширую slide
, load address
и main function address
для использования, если мое приложение падает, и я посылаю stack addresses
.
Примечание: функции dyld использовать #include <mach-o/dyld.h>
slide
= адрес, возвращаемый _dyld_get_image_vmaddr_slide(0)
load address
= адрес, возвращаемый _dyld_get_image_header(0)
main function address
= последний адрес [NSThread callStackReturnAddresses]
когда призвал главный нить
В аварийное время я схожу е войти [NSThread callStackReturnAddresses]
и [NSThread callStackSymbols]
, а также архитектуру, которую можно восстановить, имея этот метод:
- (NSString*) arch
{
NSString* arch =
#ifdef _ARM_ARCH_7
@"armv7";
#elif defined (_ARM_ARCH_6)
@"armv6";
#else
nil;
#endif
return arch;
}
Я пока не знаю, как провести различие между ARMv7 и armv7s хотя.
Так что это может помочь в будущем. Я планирую взять все, что я узнал, и превратить это в простой инструмент крушения - лучше, чем инструмент natos (возможно, natos v2).
Я обновил natos для поддержки снабжающих load address
вручную: https://github.com/NSProgrammer/natos
У меня тот же вопрос. У меня есть сообщение об аварии, которое предоставляет трассировку стека, но ни один из символов моего проекта, который попадает в стек, не найден в dSYM моего архива. UUIDs совпадают, но символы все выключены. Как это возможно и как я могу это решить? Является ли яблоко каким-то образом модифицировать двоичный файл перед тем, как отпустить его в хранилище приложений, таким образом развращая выравнивание с моим dSYM? – NSProgrammer
Вам нужно будет учитывать слайды двоичного и стартового адресов приложения. Вы не можете просто использовать адрес памяти из трассировки стека. Просто используйте скрипт symbolicatecrash из Xcode, который делает все, что вам нужно. – Kerni
Но если все, что у меня есть, являются символами (я должен был сказать, что дамп стека, а не трассировка), который чисто дает мне шестнадцатеричные значения, как мне взять «слайд»? – NSProgrammer