2009-07-29 4 views
5

Mein Programm:Warum gibt DTrace manchmal ungültige Adressfehler, aber nicht immer?

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

Einige Ausgabe:

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 

Warum die Fehler? Es scheint der Klassenname zu sein (das ist der einzige %s, und ich bekomme keine Fehler, wenn ich ihn entferne), aber warum denkt er, dass die Namen einiger Klassen ungültige Zeiger sind?

Gibt es eine Möglichkeit, die Fehlermeldungen zu erhalten, um mir tatsächlich zu sagen, welche Zeile meines DTrace-Programms ein Problem verursachte?

Gibt es eine Möglichkeit, object_getClassName aufzurufen, anstatt diesen Struktur-Inspektions-Tanz zu machen?

Für was es wert ist, funktioniert das Programm, das ich suche, gut - es stürzt nicht ab, also glaube ich nicht, dass die Klassen wirklich gebrochen sind.

Antwort

0

Dies ist meine beste Schätzung basierend auf den bereitgestellten Informationen.

DTrace wurde gezielt so entworfen, dass DTrace-Skripte so deterministisch wie möglich sind. Deshalb gibt es keine if Anweisungen, Schleifen, Subroutinen (anders als die von DTrace selbst bereitgestellten Pseudo-Subroutinen) usw. Dies liegt daran, dass der Code in Ihrem DTrace-Skript im Kernel-Modus ausgeführt wird, nicht im Benutzerland als Teil des Prozess (e), die verfolgt werden. Im Allgemeinen hat die Information, auf die DTrace Zugriff hat, "schreibgeschützt" (wie die meisten Verallgemeinerungen, dies ist nicht streng zutreffend), kann Bits in Programmen oder dem Kernel mit etwas so Leistungsfähigem wie DTrace zum Laufen bringen sehr, sehr falsch, sehr, sehr schnell.

Dollars zu Donuts, das Problem, das Sie haben, liegt daran, dass die Seite, auf die der Zeiger zeigt, vom VM-System nicht dem Core zugeordnet ist. DTrace kann nur Informationen für Speicher untersuchen, der sich im Kern befindet - es kann nicht doppelt fehlerhaft sein, um das VM-System zum Laden auf der Seite zu veranlassen.

Sie können wahrscheinlich helfen, das Problem zu lösen, wenn Sie eine Vorstellung davon haben, was die Klassen "sein sollten" und die Seiten in den Kern zu mappen, indem Sie eine Reihe von NSLog() -Anweisungen ausführen, die auf die benötigten verweisen Klassen an einem geeigneten Punkt früh in Ihren Programmen starten.

+0

Ich hatte einen Gedanken über diese letzte Nacht. Das Design von DTrace hält die Menge an "Code", die im Kernel ausgeführt wird, auf ein Minimum und so sicher wie möglich. Auflösung des Symbolnamens geschieht außerhalb des Kernels. Der Kernel protokolliert nur die Adresse im Puffer, ein externes Programm wird später in etwas lesbares übersetzt. Die Idee war- warum nicht ObjC Klassennamen Auflösung zu einer dieser "außerhalb des Kernels" Aktivitäten hinzufügen? Es könnte ein bisschen Nachforschung wert sein, um zu sehen, ob es machbar ist, und dann ein RFE-Fehlerbericht an Apple. – johne

2

Ich habe das selbst nicht vollständig aufgespürt. Es ist möglich, dass DTrace versucht, einige Objective-C-Symbole aufzulösen. Obwohl DTrace eine dynamische Ablaufverfolgungsfunktion ist, passt es nicht gut zu Objective-C, das zur Laufzeit dynamisch geladen wird. Wenn Objective-C neue Klassen lädt, usw. muss DTrace dies lösen und es braucht etwas Zeit, besonders wenn Ihre App gerade gestartet wird. Auch wenn es Dinge lädt, und Ihre Objc-App immer noch neue Klassen auf die Objc-Laufzeit lädt, könnte ihr DTrace Fehler machen und die Methoden in der falschen Reihenfolge ausgeben (wenn Sie sich darum kümmern, dass die richtigen Order-Methoden ausgeführt werden) , falsche Timing - Ergebnisse usw.

5

Colin ist ziemlich nahe zu korrigieren.

See:

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

Wahrscheinlicher als nicht, müssen Sie die DYLD_SHARED_REGION Umgebungsvariable avoid einzustellen. Dtrace funktioniert nur wirklich gegen den zugeordneten Speicher, der sich tatsächlich im physischen Speicher befindet.

Sie können herausfinden, was fehlt, indem Sie das Befehlszeilenprogramm vmmap verwenden.

Führen Sie in Ihrer Anwendung eine vmmap PID aus, nachdem die obigen Fehlermeldungen generiert wurden. Betrachten Sie die Ausgabe, sehen Sie, in welche Region die Adressen wie 0x90206b98 fallen. Wenn diese Adresse gegeben ist, ist sie wahrscheinlich in einem nicht schreibbaren gemeinsamen Teil des Speichers, der wahrscheinlich nicht resident ist und daher von dtrace nicht gelesen werden kann.

3

Dieser Fehler tritt auf, wenn copyin/copeinstr auf einer Seite verwendet wird, die noch nicht fehlerhaft ist. Eine häufige Problemumgehung besteht darin, die Funktion die fraglichen Daten verwenden zu lassen und dann in einer ::: return -Klausel copin [str] zu kopieren. Zum Beispiel:

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