Я использовал следующую арифметику, чтобы понять это:
slide
+ stack address
- load address
= symbol address
и
stack address
- это шестнадцатеричное значение, которое я получаю из отчета о сбое дампа стека (не файл .crash, а просто дамп стека).
и
slide
— это vmaddr команды LC_SEGMENT при запуске otool -arch armv7 -l APP_BINARY_PATH
. Мой обычно заканчивается 0x00001000.
и
load address
сложная штука. На самом деле это разница между самым нижним адресом стека основного потока и ПЕРВЫМ адресом той части моего двоичного файла, которая содержит символы при запуске 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/Contents/Resources/DWARF/MyApp (armv7)
----------------------------------------------------------------------
0x00000024: [0x00003af4 - 0x00003b4e) основной
0x00000098: [0x00003b50 - 0x00003d8c) -[приложение MyAppDelegate: didFinishLaunchingWithOptions:]
... остальная часть дампа
Сложнее всего было понять, что в одной из двух статических библиотек, которые я включил, были удалены символы, прежде чем они стали ссылкой на двоичный файл моего приложения! Это оставило ОГРОМНЫЙ разрыв адресов символов, поэтому я получил только две трети символов, которые мне нужны, в моем dSYM.
Убедитесь, что следующие флаги установлены в NO в вашем проекте xcode статических библиотек, чтобы при компоновке с ним вы могли вставлять символы в двоичный файл вашего приложения (который позже можно удалить): COPY_PHASE_STRIP
, DEAD_CODE_STRIPPING
и STRIP_INSTALLED_PRODUCT
.
Теперь вы можете спросить, что мне делать, если дамп стека не включает основную функцию, поскольку она не находится в основном потоке, поэтому я не могу получить адрес стека основной функции? На это я бы ответил, что понятия не имею! Просто скрестите пальцы и надейтесь, что вы сможете получить трассировку стека, включающую адрес символа, или использовать систему отчетов о сбоях, которая имитирует журналы сбоев Apple, например PLCrashReporter.
[РЕДАКТИРОВАТЬ 26 мая 2013 г.] -
Мое внимание было обращено на то, что load address
на самом деле является адресом двоичного файла mach-o. Хотя то, что я описал выше, часто может работать - это не совсем правильно. Это можно получить с помощью ОТЧЕТА О АВАРИИ, однако смысл этого ответа заключался в том, чтобы предоставить символы сбоя, когда у вас нет отчета о сбое. Лучший способ, которым я пришел к выяснению 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 от armv7.
Так что это может помочь в будущем. Я планирую использовать все, чему научился, и превратить это в простой аварийный инструмент — лучше, чем инструмент natos (вероятно, natos v2).
Я обновил natos для поддержки доставки load address
вручную: https://github.com/NSProgrammer/natos
person
NSProgrammer
schedule
17.09.2012