2009-07-29 6 views
5

Mój program:Dlaczego DTrace czasami podaje mi błędy nieprawidłowych adresów, ale nie zawsze?

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

Niektóre wyjściowe:

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 

dlaczego błędy? Wygląda na to, że jest to nazwa klasy (to jedyna %s, i nie otrzymam żadnych błędów, jeśli ją usunę), ale dlaczego sądzi, że niektóre nazwy klas są nieprawidłowymi wskaźnikami?

Czy istnieje sposób, aby komunikaty o błędach rzeczywiście mi powiedzieć, która linia mojego programu DTrace spowodowało problem?

Czy istnieje sposób na wywołanie object_getClassName zamiast wykonywania tego tańca inspekcyjnego?

Co jest warte, że program, który śledzę, działa dobrze - nie ulega awarii, więc nie wierzę, że zajęcia są naprawdę zepsute.

Odpowiedz

0

To jest moje najlepsze przypuszczenie na podstawie dostarczonych informacji.

DTrace został celowo zaprojektowany w taki sposób, aby skrypty DTrace były jak najbardziej deterministyczne. Dlatego nie ma żadnych instrukcji, pętli, podprogramów (innych niż pseudo-podprogramy dostarczone przez samą DTrace), itp. Dzieje się tak dlatego, że kod w twoim skrypcie DTrace działa w trybie jądra, a nie jako użytkownik-ziemia jako część proces (y) są śledzone. Ogólnie rzecz biorąc, informacja, do której ma dostęp DTrace, jest "tylko do odczytu" (jak większość uogólnień, nie jest to ściśle prawdą), ponieważ jest w stanie łączyć bity w programach lub jądrze, z czymś tak potężnym, jak DTrace może powodować problemy bardzo, bardzo źle, bardzo bardzo szybko.

Dolarów do pączków, problem polega na tym, że strona, na którą wskazuje wskaźnik, nie jest zmapowana do rdzenia przez system VM. DTrace może sprawdzać tylko informacje dotyczące pamięci, która jest w rdzeniu - nie może podwójnie uszkodzić, aby system VM mógł zostać załadowany na stronę.

Prawdopodobnie możesz pomóc w złagodzeniu problemu, jeśli masz pojęcie o tym, jakie zajęcia powinny "być" i zmusić strony do zmapowania do rdzenia, wykonując kilka fałszywych instrukcji NSLog(), które odnoszą się do potrzebnych zajęcia w dogodnym punkcie na początku uruchamiania programów.

+0

Myślałem o tej ostatniej nocy. Projekt DTrace utrzymuje minimalną ilość "kodu" uruchamianego w jądrze i jest "bezpieczna", jak to tylko możliwe. Rozpoznawanie nazw symboli odbywa się poza jądrem. Jądro rejestruje tylko adres w buforze, a program zewnętrzny przekłada się na coś czytelnego po fakcie. Pomysł polegał na tym, dlaczego nie należy dodawać rozwiązywania nazw klas ObjC do działań "poza kernelem"? Może warto byłoby przeprowadzić dochodzenie, aby sprawdzić, czy jest to wykonalne, a następnie raport o błędach RFE dla Apple. – johne

2

Nie całkiem to wyśledłem. Możliwe, że DTrace próbuje rozwiązać niektóre symbole Celu-C. Mimo że DTrace jest obiektem dynamicznego śledzenia, nie jest on zgodny z Objective-C dynamicznie ładującym rzeczy w czasie wykonywania. Kiedy Objective-C wczytuje nowe klasy, itp. DTrace musi to rozwiązać i zajmuje trochę czasu, szczególnie gdy twoja aplikacja dopiero się uruchamia. Nawet jeśli ładuje się rzeczy, a twoja aplikacja obstawia wciąż ładuje nowe klasy do środowiska wykonawczego objc, to możliwe, że DTrace może zostać wkręcony i wydrukować metody w złej kolejności (jeśli zależy Ci na zobaczeniu, w jaki sposób są wykonywane prawidłowe metody zamówień) , wydrukuj nieprawidłowe wyniki pomiaru czasu itp.

5

Colin jest dość blisko prawidłowy.

Patrz:

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

Bardziej prawdopodobne niż nie, trzeba ustawić zmienną środowiskową do avoidDYLD_SHARED_REGION. dtrace działa tylko przeciwko zmapowanej pamięci, która faktycznie znajduje się w pamięci fizycznej.

Można dowiedzieć się, czego brakuje, korzystając z narzędzia wiersza poleceń vmmap.

Wykonaj vmmap PID w swojej aplikacji po wygenerowaniu powyższych komunikatów o błędach. Patrząc na dane wyjściowe, zobacz, do jakiego regionu wchodzą adresy takie jak: 0x90206b98. Biorąc pod uwagę ten adres, najprawdopodobniej w nieopisywalnym fragmencie pamięci, który prawdopodobnie nie jest rezydentem, dtrace nie może z niego odczytać.

3

Ten błąd występuje, gdy copyin/copyinstr jest używany na stronie, która nie jest jeszcze błędna. Typowym sposobem obejścia tego problemu jest zezwolenie danej funkcji na użycie danych, a następnie skopiowanie [str] w klauzuli return ::: return. Na przykład:

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); 
} 
Powiązane problemy