2009-07-29 15 views
5

Mi programa:¿Por qué DTrace me da errores de direcciones no válidas a veces pero no siempre?

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); 
} 

Algunos de salida:

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 

por qué los errores? Parece ser el nombre de clase (ese es el único %s, y no obtengo ningún error si lo elimino), pero ¿por qué cree que los nombres de algunas clases son punteros no válidos?

¿Hay alguna forma de que los mensajes de error me digan qué línea de mi programa DTrace causó un problema?

¿Hay alguna manera de llamar al object_getClassName en lugar de hacer este baile de inspección de estructura?

Por lo que vale, el programa que estoy rastreando funciona bien, no está fallando, por lo que no creo que las clases realmente estén rotas.

Respuesta

0

Esta es mi mejor estimación basada en la información proporcionada.

DTrace se diseñó a propósito de manera tal que las secuencias de comandos de DTrace sean lo más deterministas posible. Esta es la razón por la cual no hay if declaraciones, bucles, subrutinas (que no sean las pseudo subrutinas proporcionadas por DTrace), etc. Esto se debe a que el código en su script DTrace se ejecuta en modo kernel, no user-land como parte del proceso (s) siendo rastreado. En general, la información a la que DTrace tiene acceso es "de solo lectura" (como la mayoría de las generalizaciones, esto no es estrictamente cierto), es capaz de mezclar bits en programas, o kernel, con algo tan poderoso como DTrace puede hacer que las cosas vayan muy, muy mal, muy, muy rápido.

Dollars to donuts, el problema que tiene es que la página a la que apunta el puntero no está asignada al núcleo por el sistema VM. DTrace solo puede examinar la información de la memoria que está en el núcleo; no puede duplicar la falla para que el sistema VM se cargue en la página.

Probablemente pueda ayudar a aliviar el problema si tiene una idea de lo que "deberían" ser las clases y forzar el mapeo de las páginas al núcleo haciendo un montón de instrucciones ficticias NSLog() que hacen referencia a las necesidades clases en algún punto conveniente al principio de sus programas.

+0

Pensé en esto anoche. El diseño de DTrace mantiene la cantidad de 'código' que se ejecuta en el kernel a un mínimo y lo más 'seguro' posible. La resolución del nombre del símbolo ocurre fuera del kernel. El núcleo solo registra la dirección en el búfer, un programa externo se traduce en algo legible después del hecho. La idea era: ¿por qué no agregar la resolución del nombre de clase ObjC a una de esas actividades "fuera del kernel"? Podría valer la pena investigar un poco para ver si es factible, y luego un informe de fallas de RFE a Apple. – johne

2

No he rastreado todo esto yo mismo. Es posible que DTrace intente resolver algunos símbolos de Objective-C. Aunque DTrace es una instalación de seguimiento dinámico, no combina bien con Objective-C cargando elementos dinámicamente en el tiempo de ejecución. Cuando Objective-C carga nuevas clases, etc. DTrace tiene que resolver esto y lleva un poco de tiempo, especialmente cuando la aplicación está recién comenzando. Incluso si carga cosas, y su aplicación objc aún está cargando nuevas clases en el tiempo de ejecución objc, es posible que se estropee su posible DTrace e imprima métodos en el orden incorrecto (si le interesa ver los métodos de orden correctos en ejecución) , imprime resultados de sincronización incorrectos, etc.

5

Colin está muy cerca de ser correcto.

Ver:

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

Lo más probable es que no, tiene que establecer la variable de entorno para DYLD_SHARED_REGIONavoid. dtrace solo funciona realmente contra la memoria mapeada que reside realmente en la memoria física.

Puede averiguar lo que falta utilizando la herramienta de línea de comandos vmmap.

Realice un vmmap PID en su aplicación después de que se generen los mensajes de error anteriores. En cuanto a la salida, vea en qué región entran las direcciones como 0x90206b98. Dada esa dirección, es probable que en un trozo compartido de memoria no grabable que probablemente no sea residente y, por lo tanto, dtrace no pueda leer de ella.

3

Este error ocurre cuando copyin/copyinstr se usa en una página que aún no ha fallado. Una solución común es permitir que la función use los datos en cuestión, y luego copie [str] en una ::: cláusula return. Por ejemplo:

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); 
} 
Cuestiones relacionadas