Silniki DBI dynamicznie instrumentują procesy, monitorując i kontrolując wszystkie wykonywane instrukcje. Silnik DBI udostępnia API, które umożliwia pisanie zdefiniowanych przez użytkownika narzędzi DBI (często w formie biblioteki współdzielonej ładowanej przez silnik), które określają, który kod powinien zostać instrumentowany i w jaki sposób. Na przykład, narzędzie DBI pokazane po prawej stronie rysunku 9-4 implementuje (w pseudokodzie) prosty profiler, który zlicza liczbę wykonanych bloków podstawowych. W tym celu wykorzystuje API silnika DBI do instrumentacji ostatniej instrukcji każdego bloku podstawowego za pomocą wywołania zwrotnego do funkcji, która zwiększa licznik. Zanim silnik DBI uruchomi główny proces aplikacji (lub wznowi go, jeśli zostanie podłączony do istniejącego procesu), umożliwia zainicjowanie narzędzia DBI. Na rysunku 9-4 funkcja inicjalizacyjna narzędzia DBI rejestruje w silniku DBI funkcję o nazwie instrument_bb (1). Funkcja ta informuje silnik DBI, jak instrumentować każdy blok podstawowy; W tym przypadku dodaje wywołanie zwrotne do bb_callback po ostatniej instrukcji w bloku podstawowym. Następnie funkcja inicjalizacji informuje silnik DBI, że zakończył inicjalizację i jest gotowy do uruchomienia aplikacji (2). Silnik DBI nigdy nie uruchamia procesu aplikacji bezpośrednio, lecz uruchamia kod w pamięci podręcznej kodu, która zawiera cały zinstrumentowany kod. Początkowo pamięć podręczna kodu jest pusta, więc silnik DBI pobiera blok kodu z procesu (3) i instrumentuje ten kod (4) zgodnie z instrukcjami narzędzia DBI (5). Należy zauważyć, że silniki DBI niekoniecznie pobierają i instrumentują kod z podstawową granularnością bloku, co wyjaśnię szerzej w rozdziale 9.4. Jednak w tym przykładzie założę, że silnik instrumentuje kod z podstawową granularnością bloku, wywołując instrument_bb. Po instrumentacji kodu silnik DBI kompiluje go za pomocą kompilatora just-in-time (JIT) (6), który ponownie optymalizuje zinstrumentowany kod i zapisuje skompilowany kod w pamięci podręcznej kodu (7). Kompilator JIT przepisuje również instrukcje przepływu sterowania, aby zapewnić silnikowi DBI zachowanie kontroli, zapobiegając dalszemu wykonywaniu transferów sterowania w nieinstrumentowanym procesie aplikacji. Należy pamiętać, że w przeciwieństwie do większości kompilatorów, kompilator JIT w silniku DBI nie tłumaczy kodu na inny język; kompiluje z natywnego kodu maszynowego do natywnego kodu maszynowego. Instrumentacja i kompilacja JIT kodu jest konieczna tylko przy pierwszym uruchomieniu. Następnie kod jest przechowywany w pamięci podręcznej kodu i ponownie wykorzystywany. Zinstrumentowany i skompilowany kod JIT jest teraz wykonywany w pamięci podręcznej kodu, dopóki nie pojawi się instrukcja przepływu sterowania wymagająca pobrania nowego kodu lub wyszukania innego fragmentu kodu w pamięci podręcznej (8). Silniki DBI, takie jak Pin i DynamoRIO, zmniejszają narzut czasu wykonania poprzez przepisywanie instrukcji przepływu sterowania, gdy jest to możliwe, tak aby przeskakiwały one bezpośrednio do następnego bloku w pamięci podręcznej kodu bez pośrednictwa silnika DBI. Gdy nie jest to możliwe (na przykład w przypadku wywołań pośrednich), przepisane instrukcje zwracają sterowanie do silnika DBI, aby mógł on przygotować i uruchomić kolejny fragment kodu. Podczas gdy większość instrukcji działa natywnie w pamięci podręcznej kodu, silnik DBI może emulować niektóre instrukcje zamiast uruchamiać je bezpośrednio. Na przykład Pin robi to w przypadku wywołań systemowych, takich jak execve, które wymagają specjalnej obsługi przez silnik DBI. Zinstrumentowany kod zawiera wywołania zwrotne do funkcji w narzędziu DBI, które obserwują lub modyfikują zachowanie kodu (9). Na przykład na rysunku 9-4 funkcja instrument_bb narzędzia DBI dodaje wywołanie zwrotne na końcu każdego bloku podstawowego, który wywołuje funkcję bb_callback, zwiększającą licznik bloków podstawowych narzędzia DBI. Silnik DBI automatycznie zapisuje i przywraca stan rejestrów podczas przekazywania sterowania do lub z funkcji zwrotnej w narzędziu DBI. Teraz, gdy znasz już działanie silników DBI, omówmy Pin, silnik DBI, którego będę używać później



