DTracing objc_msgSend не печатает имя класса получателя

Я использую dtrace для печати всех objc_msgSend в моем коде. Благодаря тому, что я сделал до сих пор, я вижу имя селектора, но не могу получить правильное имя класса.

Это мой сценарий dtrace:

#!/usr/sbin/dtrace -qs

pid$target::objc_msgSend:entry
{
self->isa = *(long *)copyin(arg0, 8);
printf("-[%s %s]\n",
copyinstr(*(long *)copyin(self->isa + 16, 8)),
copyinstr(arg1));
}

и я предполагаю, что Я бы объект-получатель имеет следующую структуру:

typedef struct objc_class {
struct objc_class *isa;
struct objc_class *super_class;
char *name;
...
}

В моей голове, чтобы достичь имени, указатель должен быть перемещен 2 * sizeof (objc_class *), что составляет 16, и мы получаем указатель имени размера 8. Поэтому я ожидал увидеть имя класса, но я получаю вместо этого напечатан мусор.

Есть идеи, что я делаю не так?

Моя система Mavericks x64.

1

Решение

После ковыряться Исходный код среды выполнения Obj-C для 64-битной архитектуры и файл «objc-private.h», это «формула» для получения имени класса из указателя класса:

#define RW_REALIZED (1<<31)
#define RW_FUTURE (1<<30)
#define CLASS_FAST_FLAG_MASK  3
#define TAG_MASK 1
#define TAG_SLOT_SHIFT 0
#define TAG_SLOT_MASK 0xf

extern "C" Class objc_debug_taggedpointer_classes[];  // Available in 10.9 for tagged pointers decoding

static const char* ClassNameFromInstance(id instance) {
char* ptr0 = (char*)instance;

char* ptr1;
if ((long)ptr0 & TAG_MASK) {
long slot = ((long)ptr0 >> TAG_SLOT_SHIFT) & TAG_SLOT_MASK;
ptr1 = (char*)objc_debug_taggedpointer_classes[slot];  // struct objc_class pointer
} else {
ptr1 = *(char**)ptr0;  // struct objc_class pointer i.e. instance ISA
}

char* ptr2 = *((char**)(((long)ptr1 + 32) & ~CLASS_FAST_FLAG_MASK));  // struct class_ro_t or struct class_rw_t pointer

uint32_t flags = *((uint32_t*)ptr2);  // struct class_ro_t or struct class_rw_t flags
char* ptr3;
if ((flags & RW_REALIZED) || (flags & RW_FUTURE)) {
ptr3 = *((char**)((long)ptr2 + 8));  // struct class_ro_t pointer from struct class_rw_t pointer
} else {
ptr3 = ptr2;  // struct class_ro_t pointer same as struct class_rw_t pointer
}

const char* name = *((char**)((long)ptr3 + 24));  // Name string pointer from struct class_ro_t pointer

return name;
}

Который в dtrace становится в этом примере скриптом, который регистрирует создание объектов Obj-C & разрушение:

#!/usr/bin/env dtrace -s
#pragma D option quiet

pid$target:libobjc.A.dylib:class_createInstance:entry
{
ptr1 = *(long*)copyin(arg0, 8);  /* arg0 is Class pointer */
ptr2 = *(long*)copyin((ptr1 + 32) & ~3, 8);
flags = *(int*)copyin(ptr2, 4);
ptr3 = (flags & (1 << 31)) || (flags & (1 << 30)) ? *(long*)copyin(ptr2 + 8, 8) : ptr2;
ptr4 = *(long*)copyin(ptr3 + 24, 8);
self->class = copyinstr(ptr4);
}

pid$target:libobjc.A.dylib:class_createInstance:return
{
printf("[+] %s = %p\n", self->class, arg1);  /* arg1 is instance pointer */
self->class = 0;
}

pid$target:libobjc.A.dylib:object_dispose:entry
/arg0 != 0/
{
ptr0 = *(long*)copyin(arg0, 8);  /* arg0 is instance pointer */
ptr1 = *(long*)copyin(ptr0, 8);  /* TODO: Handle tagged pointers */
ptr2 = *(long*)copyin((ptr1 + 32) & ~3, 8);
ptr3 = (flags & (1 << 31)) || (flags & (1 << 30)) ? *(long*)copyin(ptr2 + 8, 8) : ptr2;
ptr4 = *(long*)copyin(ptr3 + 24, 8);
class = copyinstr(ptr4);

printf("[-] %s = %p\n", class, arg0);
}

ВАЖНЫЙ Этот сценарий dtrace не обрабатывает помеченные указатели. Обязательно установите переменную среды «DYLD_SHARED_REGION = избежать» при использовании этого сценария, как описано Вот.

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]