2009-07-29 21 views
5

Il mio programma:Perché DTrace mi dà errori di indirizzo non valido a volte ma non sempre?

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

qualche uscita:

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 

Perché gli errori? Sembra essere il nome della classe (questo è l'unico %s, e non ottengo alcun errore se lo rimuovo), ma perché pensa che i nomi di alcune classi siano puntatori non validi?

C'è un modo per ottenere i messaggi di errore per dirmi che in realtà la linea del mio programma di DTrace causato un problema?

C'è un modo per chiamare object_getClassName invece di fare questa danza struttura-ispezione?

Per quello che vale, il programma che sto tracciando funziona bene-non è che si infrangono, quindi non credo che le classi in realtà sono rotti.

risposta

0

Questa è la mia ipotesi migliore basata sulle informazioni fornite.

DTrace è stato volutamente progettato in modo tale da rendere gli script di DTrace come deterministico possibile. Questo è il motivo per cui non ci sono istruzioni if, loop, subroutine (diverse dalle pseudo-subroutine fornite dallo stesso DTrace), ecc. Questo perché il codice nel tuo script DTrace è in esecuzione in modalità kernel, non come user-land come parte del processo (i) viene tracciato. In generale, l'informazione a cui DTrace ha accesso è "di sola lettura" (come la maggior parte delle generalizzazioni, questo non è strettamente vero), essendo in grado di manipolare bit nei programmi, o nel kernel, con qualcosa di potente come DTrace può causare cose da fare molto, molto male, molto molto rapidamente.

Dollari per ciambelle, il problema che stai avendo è perché la pagina che i punti di puntatore a non è mappata per nucleo dal sistema VM. DTrace può esaminare solo le informazioni per la memoria che si trova nel core, non può duplicare per ottenere il caricamento del sistema VM nella pagina.

Probabilmente si può contribuire ad alleviare il problema se si ha un'idea di cosa "dovrebbe" essere la classe e si costringe le pagine a mappare al centro facendo un mucchio di istruzioni fittizie NSLog() che fanno riferimento al necessario le lezioni in un momento pratico all'inizio del programma.

+0

Ho pensato a questa notte scorsa. Il design di DTrace mantiene al minimo la quantità di "codice" che viene eseguita nel kernel e il più "sicuro" possibile. La risoluzione dei nomi dei simboli avviene al di fuori del kernel. Il kernel registra solo l'indirizzo nel buffer, un programma esterno si traduce in qualcosa di leggibile dopo il fatto. L'idea era: perché non aggiungere la risoluzione del nome della classe ObjC a una di quelle attività "al di fuori del kernel"? Potrebbe valere un po 'di indagine per vedere se è fattibile, e poi un bug report RFE ad Apple. – johne

2

Non l'ho interamente rintracciato. È possibile che DTrace stia cercando di risolvere alcuni simboli Objective-C. Sebbene DTrace sia una struttura di tracciamento dinamica, non si adatta bene a Objective-C caricando dinamicamente le cose in fase di runtime. Quando Objective-C carica nuove classi, ecc. DTrace deve risolvere questo problema e ci vuole un po 'di tempo, specialmente quando la tua app si sta appena avviando. Anche se viene caricato qualcosa, e la tua app objc sta ancora caricando nuove classi sul runtime objc, il suo possibile DTrace potrebbe essere rovinato e stampare i metodi nell'ordine sbagliato (se ti interessa vedere in esecuzione i metodi di ordinazione corretti) , stampa risultati di temporizzazione errati, ecc.

5

Colin è abbastanza vicino per correggere.

See:

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

Più probabile che no, è necessario impostare la variabile di ambiente DYLD_SHARED_REGION a avoid. dtrace funziona davvero solo contro la memoria mappata che è effettivamente residente nella memoria fisica.

È possibile capire cosa manca utilizzando lo strumento da riga di comando vmmap.

Fare un vmmap PID sull'applicazione dopo aver generato i precedenti messaggi di errore. Osservando l'output, vedere in quale area si trovano gli indirizzi come 0x90206b98. Dato questo indirizzo, è probabile che in un pezzo di memoria condiviso non scrivibile che probabilmente non è residente e, quindi, dtrace non può leggere da esso.

3

Questo errore si verifica quando copyin/copyinstr viene utilizzato su una pagina che non ha ancora alcun difetto. Una soluzione comune consiste nel consentire alla funzione di utilizzare i dati in questione e quindi copiare [str] in una clausola ::: return. Ad esempio:

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