2009-07-29 1 views
5

Моя программа:Почему DTrace иногда приводит к ошибкам ввода-вывода, но не всегда?

typedef struct objc_class { 
    struct objc_class *isa; 
    struct objc_class *super_class; 
    char *name; 
    long version; 
    long info; 
    long instance_size; 
    void *ivars; 
    void *methodLists; 
    void *cache; 
    void *protocols; 
} *Class; 
struct objc_object { 
    Class isa; 
}; 

/* Code to extract the class name from arg0 based on a snippet by Bill Bumgarner: http://friday.com/bbum/2008/01/26/objective-c-printing-class-name-from-dtrace/ */ 

objc$target:NSObject:-init:entry { 
    printf("time: %llu\n", timestamp); 
    printf("arg0: %p\n", arg0); 
    obj = (struct objc_object *)copyin(arg0, sizeof(struct objc_object)); 
    printf("obj: %p\n", obj); 
    printf("obj->isa: %p\n", obj->isa); 
    isa = (Class)copyin((user_addr_t)obj->isa, sizeof(struct objc_class)); 
    printf("isa: %p\n", obj->isa); 
    classname = copyinstr((user_addr_t)(isa->name)); 
    printf("classname: %s\n", classname); 
} 

Некоторые выходные:

dtrace: script 'test.d' matched 1 probe 
dtrace: error on enabled probe ID 1 (ID 61630: objc5936:NSObject:-init:entry): invalid address (0x90206b98) in action #8 at DIF offset 28 
dtrace: error on enabled probe ID 1 (ID 61630: objc5936:NSObject:-init:entry): invalid address (0x90206b98) in action #8 at DIF offset 28 
dtrace: error on enabled probe ID 1 (ID 61630: objc5936:NSObject:-init:entry): invalid address (0x90206b98) in action #8 at DIF offset 28 
CPU  ID     FUNCTION:NAME 
    0 61630      -init:entry time: 28391086668386 
arg0: 1291ae10 
obj: 6f0a1158 
obj->isa: a023f360 
isa: a023f360 
classname: NSBitmapImageRep 

    1 61630      -init:entry time: 28391586872297 
arg0: 12943560 
obj: 6f4a1158 
obj->isa: 2fca0 
isa: 2fca0 
classname: GrowlApplicationTicket 

    1 61630      -init:entry time: 28391586897807 
arg0: 152060 
obj: 6f4a1280 
obj->isa: 2fe20 
isa: 2fe20 
classname: GrowlNotificationTicket 

    2 61630      -init:entry time: 28391079142905 
arg0: 129482d0 
obj: 700a1128 
obj->isa: a0014140 
isa: a0014140 
classname: NSDistributedObjectsStatistics 

    2 61630      -init:entry time: 28391079252640 
arg0: 147840 
obj: 700a1250 
obj->isa: a0014780 
isa: a0014780 
classname: NSDistantObjectTableEntry 

Почему ошибки? Кажется, это имя класса (это единственный %s, и я не получаю никаких ошибок, если я его удалю), но почему он считает, что имена некоторых классов являются недопустимыми указателями?

Есть ли способ получить сообщения об ошибках, чтобы на самом деле сказать, какая линия моей программы DTrace вызвала проблему?

Есть ли способ позвонить object_getClassName вместо того, чтобы делать это?

Для чего это стоит, программа, которую я отслеживаю, работает нормально - это не сбой, поэтому я не верю, что классы действительно сломаны.

ответ

0

Это мое лучшее предположение, основанное на предоставленной информации.

DTrace был специально разработан таким образом, чтобы сделать сценарии DTrace максимально детерминированными. Вот почему нет операторов if, циклов, подпрограмм (кроме псевдо-подпрограмм, предоставляемых самим DTrace) и т. Д. Это связано с тем, что код в вашем сценарии DTrace работает в режиме ядра, а не в пользовательской области как часть отслеживаются процессы (процессы). В общем, информация, которую DTrace имеет доступ к «только для чтения» (как и большинство обобщений, это не совсем верно), возможность бить биты в программах или ядре с чем-то таким же мощным, как DTrace, может привести к тому, очень, очень неправильно, очень быстро.

Доллары до пончиков, проблема, с которой вы сталкиваетесь, связана с тем, что страница, на которую указывает указатель, не привязана к ядру системой VM. DTrace может только просматривать информацию для памяти, которая находится в ядре, - она ​​не может удваивать ошибку, чтобы заставить систему VM загружаться на странице.

Возможно, вы можете помочь решить проблему, если у вас есть представление о том, какие классы должны «быть», и заставляя страницы отображаться в ядре, создавая кучу фиктивных операторов NSLog(), которые ссылаются на необходимые классы в какой-то удобной точке в начале ваших программ запускаются.

+0

У меня была мысль об этом прошлой ночью. Конструкция DTrace хранит количество «кода», которое запускается в ядре до минимума, и как можно безопаснее. Разрешение имени символа происходит за пределами ядра. Ядро регистрирует только адрес в буфере, внешняя программа преобразуется во что-то читаемое после факта. Идея была: почему бы не добавить разрешение имени класса ObjC в одну из этих действий «за пределами ядра»? Возможно, стоит немного расследовать, чтобы понять, возможно ли это, а затем отчет об ошибке RFE для Apple. – johne

2

Я не полностью отследил это. Возможно, DTrace пытается разрешить некоторые символы Objective-C. Хотя DTrace является объектом динамической трассировки, он не очень хорошо взаимодействует с Objective-C, динамически загружая вещи во время выполнения. Когда Objective-C загружает новые классы и т. Д. DTrace должен решить это, и это занимает немного времени, особенно когда ваше приложение только запускается. Даже если он загружается, и ваше приложение objc по-прежнему загружает новые классы во время выполнения objc, его возможный DTrace может быть запутан и напечатать методы в неправильном порядке (если вы хотите, чтобы в правильном порядке выполнялись методы заказа) , печатать неверные результаты синхронизации и т. д.

5

Колин довольно близко к правилу.

См:

http://www.friday.com/bbum/2008/01/03/objective-c-using-dtrace-to-trace-messages-to-nil/

Скорее всего, вам нужно установить переменную окружения DYLD_SHARED_REGIONavoid. dtrace действительно работает против сопоставленной памяти, которая фактически находится в физической памяти.

Вы можете выяснить, чего не хватает с помощью инструмента командной строки .

Сделайте vmmap PID на вашем приложении после создания вышеуказанных сообщений об отказах. Посмотрев на результат, посмотрите, в какой регион попадают такие адреса, как 0x90206b98. Учитывая этот адрес, это, скорее всего, несовместимый общий кусок памяти, который, вероятно, не является резидентным, и, следовательно, dtrace не может его прочитать.

3

Эта ошибка возникает, когда copyin/copyinstr используется на странице, которая еще не была обнаружена. Общим решением является функция, использующая данные, о которых идет речь, а затем copyin [str] в a ::: return. Например:

syscall::open:entry 
{ 
    self->filename = arg0; /* Hang on to the file name pointer. */ 
} 

syscall::open:return 
/self->filename/ 
{ 
    @files[copyinstr(self->filename)] = count(); 
    self->filename = 0; 
} 

END 
{ 
    trunc(@files, 5); 
} 
Смежные вопросы