2014-03-06 5 views
1

dtrace를 사용하여 코드에서 모든 objc_msgSend를 인쇄하고 있습니다. 지금까지 내가 한 것을 사용하여 선택기의 이름을 볼 수 있지만 올바른 클래스 이름을 가져올 수 없습니다. DTracing 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)); 
} 

나는하여 ID 수신기 객체는 다음과 같은 구조체 인 것이 가정입니다 : 도달하기 위해, 내 머리에서

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

포인터를 옮겨야하는 이름 2 * sizeof (objc_class *)는 16을 만들고 크기 8의 포인터를 얻습니다. 따라서 클래스 이름을 볼 것으로 예상되었지만 대신 약간의 쓰레기가 인쇄됩니다.

내가 잘못하고있는 것에 대한 아이디어가 있습니까?

내 시스템은 Mavericks x64입니다.

+1

'struct objc_class'의 정의는 32 비트 Mac을 제외한 모든 곳에서 부정확합니다. –

+0

올바른 것을 알고 있습니까? – Vame

답변

3

Obj-C runtime source code for 64 bit architecture하고 "objc-private.h"파일 주위에 파고 후,이 클래스 포인터에서 클래스 이름을 얻을 수있는 "공식"입니다 :

의 DTrace이 예에서이된다
#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; 
} 

#!/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 스크립트 tagged pointers을 처리하지 않습니다를 Obj-C 로그 스크립트 작성을 & 파괴를 객체. here과 같이이 스크립트를 사용할 때는 "DYLD_SHARED_REGION = avoid"환경 변수를 설정하십시오.