Как регистрировать все методы, используемые в приложении iOS

Я занимаюсь разработкой iPad-приложения для клиента. Там уже проделана значительная работа, и я пытаюсь объединить все, что предназначено для запуска.

Одна из вещей, которые я хотел бы сделать, - это журнал, который вызывает вызовы при запуске приложения. Я видел пользовательский DTrace script, который предназначен для регистрации всех методов при запуске, но когда я запускаю его в Инструментах, я не получаю никаких результатов.

Каков наилучший способ регистрации методов?

Ответ 1

Вдохновленный tc ответом на аналогичный вопрос здесь, я собрал действие точки останова отладки, которое выведет имя класса и метода за каждый раз, когда objc_msgSend() будет запускается в вашем приложении. Это работает аналогично DTrace script, описанному в этом ответе.

Чтобы включить это действие точки останова, создайте новую символическую точку останова (в Xcode 4, перейдите к навигатору точки останова и создайте новую символическую точку останова, используя плюс в левом нижнем углу окна). Иметь символ objc_msgSend, автоматически настроить его после оценки действий и установить действие как команду отладчика, используя следующее:

printf "[%s %s]\n", (char *)object_getClassName(*(long*)($esp+4)),*(long *)($esp+8)

Ваша точка останова должна выглядеть примерно так:

Breakpoint action

При запуске с вашим приложением следует выводить сообщения, подобные этому:

[UIApplication sharedApplication]
[UIApplication _isClassic]
[NSCFString getCString:maxLength:encoding:]
[UIApplication class]
[SLSMoleculeAppDelegate isSubclassOfClass:]
[SLSMoleculeAppDelegate initialize]

Если вам интересно, куда я вытащил адреса памяти, прочитайте эту статью Phrack о внутренних функциях Objective-C. Адреса памяти, указанные выше, будут работать только против Simulator, поэтому вам может потребоваться настроить ее для работы с приложениями на устройствах iOS. Коллин предлагает следующую модификацию в его ответе, чтобы запустить это на устройстве:

printf "[%s %s]\n", (char *)object_getClassName($r0),$r1

Кроме того, я думаю, вы увидите, что выключение каждого метода, вызванного в вашем приложении, приведет к переполнению информации. Возможно, вы сможете использовать некоторые условия для фильтрации, но я не знаю, поможет ли это вам узнать, как выполняется ваш код.

Ответ 2

Если вы используете LLDB, вам нужно будет использовать следующие команды отладчика. Они были протестированы в Xcode 4.6.

Device:

expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($r0),$r1)

Simulator:

expr -- (void) printf("[%s %s]\n", (char *)object_getClassName(*(long*)($esp+4)), *(long *)($esp+8))

Ответ 3

Чтобы отследить код приложения под Xcode 6 на устройстве, мне пришлось использовать следующее выражение отладчика.

expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($arg1),$arg2)

Ответ 4

Подход Брэда Ларсона может быть адаптирован для работы на устройстве с помощью команды отладчика:

printf "[%s %s]\n", (char *)object_getClassName($r0),$r1

Более подробную информацию можно найти в Технической заметке здесь: technotes

Ответ 5

более поздние версии xcode, которые вы должны вызвать таким образом

expr -- (void)printf("[%s, %s]\n",(char *) object_getClassName(*(long*)($esp+4)), (char *) *(long *)($esp+8) )

Ответ 6

Если вы хотите ограничить вывод только сообщениями, отправленными на один класс, вы можете добавить условие, подобное этому

(int) strcmp ((char *) object_getClassName ($ r0), "NSString" ) == 0

Ответ 7

Для приложений iOS simulator, которые работают как процессы архитектуры arm/x86_64 на Mac

Создайте Symbolic Breakpoint с символом objc_msgSend и следующий Debugger Command

p (void)printf("[%s, %s]\n", (char*)object_getClassName($arg1), $arg2)

p является псевдонимом для expr --

Источник ТАК ответ

Ответ 8

Один разработчик научил меня добавлять те же самые два оператора журнала к каждому методу. Первая - первая, вторая - последняя. Я думаю, что у него есть script, который делает это автоматически для своих проектов, но результат:

NSLog(@"<<< Entering %s >>>", __PRETTY_FUNCTION__);
NSLog(@"<<< Leaving %s >>>", __PRETTY_FUNCTION__);

На консоли это выплюнет что-то вроде:

 <<< Entering -[MainListTableViewController viewDidLoad] >>>

Очень полезно отслеживать, что происходит.

Ответ 9

Если вы хотите регистрировать методы в Simulator на 64-битной версии, используйте следующую команду:

expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($rdi), (char *) $rsi)

Или, если это не работает, запишите его так:

введите описание изображения здесь

Основная идея - использовать $rdi для объекта (self) и $rsi для селектора.

Ответ 10

NSLog(@"%@", NSStringFromSelector(_cmd));

ИЛИ

NSLog(@"%s", __PRETTY_FUNCTION__);