воскресенье, 20 февраля 2011 г.

Высокопроизводительный трейсер


Совершенно очевидно, что если говорить о высокопроизводительном трейсере, то вариант с Debugging API сразу отпадает, т.к. использует высокоуровневую модель сверху и LPC сообщения снизу.

Отладка посредством порта ислючений также не подходит под определение "высокопроизводительно", т.к. в основе лежит все тот же механизм LPC.

Т.е. вариант один - спускаться в ядро, на самый низкий уровень.

Путей реализации ring0 трейсера тоже несколько, один из них это перехват 1го прерывания и установка в обработчике TF флага, также можно установить свою KiDebugRoutine и так далее, вариантов масса.

Однако замена в IDT хендлера 1го прерывания плоха тем, что нужно самостоятельно строить трап фрейм, а это время.

KiDebugRoutine также плох тем, что задействован дисперчер исключений, сначала ядерный, затем пользовательский, а путь обработки исключения тернист и долог.

Поэтому мне видится оптимальным вариант вобще без задействования ядерного, а стало быть и юзермодного дисперчеров исключений, а также без замены хендлера в IDT, идея в том, чтобы перехватить сам код обработчика int 1, встроив свою ф-цию, которая будет вызывать ф-цию с реализацией логики трейсера, а после этого передавать управление не на ядерный диспетчер исключений, а сразу на код выхода из ISR (Kei386EoiHelper). В пользовательскую ф-цию передается указатель на трап фрейм, таким образом на руках будет вся нужная трейсеру информация, а на выходе из пользовательской ф-ции устанавливается трейс флаг.

Таким образом, такой способ реализации дает возможность избежать тяжеловесного кода по разруливанию ядром трассировочного исключения, и переключения контекста r0->r3 при передаче управления на юзермодный диспетчер исключений(KiUserExceptionDispatcher).

Никаких сложностей и проблем с поиском места для патча, и ф-ции Kei386EoiHelper нет.

Саму логику также предпочтительнее реализовывать в ядре(для того, чтобы избежать ненужных переключений r0-r3), все что нужно сделать в юзермоде, это передать установки для трейсера в ядро, и запустить приложение с введенным трейс флагом(хотя последнее можно делать и из нотификатора в ядре).

Что же касается темы выхода из трассировки, то это отдельная тема, о ней как-нибудь в другой раз.

Варианты использования трейсера наверно объяснять не нужно. Ниже пара картинок, первая это entry point нодов из блокнота, вторая тоже самое, но пропущенная через трейсер, цветом показана интенсивность попадания управления на данный нод(красный, как наверно понятно, взялся изза цикла). Одинокий нод справа - кусок от реализации высокоуровнего seh'a( хендлер из scopetable если точнее).



1 комментарий:

  1. О, я сейчас тоже тему трейсинга активно исследую. Правда, ядерный трассировщик с перехватом прерываний писать ещё не решился - это достаточно большой wokflow, а рабочее решение мне нужно чем быстрее, тем лучше (ограничился PIN Toolkit-ом в итоге).
    Собственно, в связи с вышеозвученным - не мог бы ты привести какие-то данные, касающиеся производительности твоего трейсера в сравнительных тестах?

    ОтветитьУдалить