Отладка Objective-C ARC retain

в 9:54, , рубрики: clang, gcc, iOS, objective-c, отладка, разработка под iOS, метки: , , ,

Иногда возникают ситуации, когда стандартных средств отладки недостаточно.

Например, в iOS 4.1 была возможность использовать valgrind в симуляторе. А в Lion x86_64 и iOS 5 valgrind работать уже перестал.
Это связано с 64-битной архитектурой и изменениями в симуляторе (в valgrind есть ряд
недоработок).

С переходом на ARC метод отладки retain исчез:

- (id) retain
{
// Break here to see who is retaining me.
return [super retain];
}

В моем случае выходом из этой ситуации стал хак компилятора clang.

Конфигурация:
Платформа: Lion x64_86
Xcode: 4.2.1 4D502
clang: 318.0.58 i686

1. Узнаем версию компилятора

$ clang --version
Apple clang version 3.1 (tags/Apple/clang-318.0.58) (based on LLVM 3.1svn)
...

2. Загружаем и извлекаем нашу версию clang с Apple Open Source

http://opensource.apple.com/tarballs/
clang/

Именно вайшей версии может не быть, в таком случае скачивайте максимально
приближенную, лучше которая новее.

$ tar xzvf clang-318.0.45.tar.gz

3. Патчим clang

Заменяем стандартный вызов objc_retain на свой objc_retain1.

clang-318.0.45/src/tools/clang/lib/CodeGen/CGObjC.cpp:1554
>
"objc_retain1");

4. Собираем clang

make RC_ProjectSourceVersion=1 RC_OS=macos RC_ARCHS=i686
TARGETS=i686
SRCROOT=`pwd` OBJROOT=`pwd`/build/obj
DSTROOT=`pwd`/build/dst SYMROOT=`pwd`/build/sym

Сборка завершится ошибкой связанной с правами.

chown: src/apple-gcc/1/clang-318.0.45/build/obj/stage1-install-x86_64/lib/c++: Operation not
permitted
make[4]: *** [do-installhdrs] Error 1
...
make[1]: *** [install] Error 1

Ничего страшного что install не прошел — главное бинарники и они получены.

build/obj/stage1-install-x86_64/bin/clang

Скрипты от Apple уникальны, возможно это можно решить указанием верных параметров,
возможно нет (например, для сборки gcc пришлось патчить build_gcc чтобы отключить
инсталляцию после сборки).

Внимание! Если собирать gcc или llvm-gcc методом указанным в README.TXT, то по умолчанию произойдет make install и ваши оригиналы будут перезаписаны.
Поэтому перед любыми действиями необходимо сделать резервную копию /
Developer/Platforms/iPhoneSimulator.platform/Developer/usr/.
Clang это не касается, поскольку он имеет иную конфигурацию сборки (проверено на
версии clang-318.0.45).

5. Устанавливаем clang

Сохраняем оригинал и делаем symlink на новый (только symlink, иначе будет ошибка из-за
различий в Developer/usr и stage1-install-x86_64/).

$ cd /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin
$ mv clang clang.orig
$ ln -s clang-318.0.45/build/obj/stage1-install-x86_64/bin/clang

Готово. Для полноценной работы понадобится 2 версии clang. Немодифицированная (без
патча п.3) — чтобы собрать большую часть файлов которые не нуждаются в отладке. И
модифицированная — для тех файлов в которых будем отлаживать ARC retain. Выбрать
версию для сборки в Xcode прийдется вручную

# Модифицированная версия
$ ln -s clang-318.0.45/build/obj/stage1-install-x86_64/bin/clang
# Немодифицированная версия, сохранил после билда в clang.new
$ ln -s clang-318.0.45/build/obj/stage1-install-x86_64/bin/clang.new clang

С компилятором все ясно, теперь дело за проектом.

В любой файл проекта добавляем свою функцию objc_retain1, у меня получилась такая
(печатает backtrace):

id objc_retain(id o);
void *objc_retain1(void *o)
{
static void *b[10];

static int z = 10;
static int n;
static char **c;
n = backtrace(b, z);
c = backtrace_symbols(b, n);
NSLog(@"objc_retain(%p):", o);
for (int i = 0; i < n; i++)
{
NSLog(@"%s", c[i]);
}
return (__bridge void *)objc_retain((__bridge id)o);

}

В этой функции можно поставить breakpoint и ловить мелких похитителей объектов.

Далее собираем проект при помощи немодифицированного компилятора чтобы не ловить
retain всех объектов (не забыв сделать cleanup, чтобы убрать файлы оригинального
компилятора).
Заменяем компилятор на модифицированный, сохраняем нужный файл, собираем и
отлаживаемся в симуляторе.

Файл CGObjC.cpp содержит иные функции ARC, которые можно также перехватить
(заодно изучив внутренний мир ARC).
Ссылка с подробностями ARC:
http://clang.llvm.org/
docs/AutomaticReferenceCounting.html

* Для разных версий SDK пути могут отличаться

Автор: infoe

* - обязательные к заполнению поля