Я сейчас решил с нуля писать свой отладчик, который писал год назад. Решил сделать его локальным, для удаленной отладки меня сейчас устравиает и kd/windbg (com-port), visual softice (ethernet) Проект : http://code.google.com/p/ngdbg/ Технология вывода: (Другое опишу позже) Выводить своё изображение можно : 1) прямым выводом в фреймбуффер. На некоторых видеокартах изображение идет подряд - пиксель за пикселем, строчка за строчкой в фреймбуффере. На некоторых - новые строчки могут выравниваться по границе страницы или же вообще фреймбуффер может иметь блочную структуру. 2) манипуляциями с win32k и драйвером дисплея. Если ты почитаешь MSDN, то найдешь там функции Eng** от win32k graphics engine. Увидишь, что есть много функции рисования на виртуальных "поверхностях" (surface objects, struct _SURFOBJ*). Например, EngLineTo. Они производят построение изображения. Поверхность можно создать через EngCreateBitmap. Можно даже загрузить с диска готовое изображение bmp. и сделать из него поверхность. Проблема в том, что этими функциями ты можешь создать виртуальное изображение на виртуальной поверхности (типа hdc в юзермоде), но тебе в конце концов потребуется перенести свое изображение на поверхность физического дисплея. Этим занимается функция видеодрайвера DrvCopyBits. Как найти ее - писать здесь и сейчас я сомневаюсь, что следует, поскольку хоть один человечек (PROFi, привеееет ) скидывал мне год назад технологию вывода свою, которую я если честно год назад нифига не понял, поскольку по этой теме нифига не знал, а сейчас все проделал самостоятельно и просто ради интереса вспомнил про тот случай. Та технология хоть и не имеет ничего общего с поиском DrvCopyBits, который я затеял сейчас, но некоторые люди все равно могут усмотреть аналогию и обвинить меня в плагиате. Ну да ладно, все равно отладчик я планирую делать OpenSource и в принципе исходнеы коды доступны и сейчас в http://code.google.com/p/ngdbg/source/browse/trunk/. Задача заключается в следующем: видеодрайвер реализует функции, которые отвечают за физическое рисование и копирование бит на физическую поверхность дисплея, производя необходимые преобразования в случае нелинейности фреймбуффера и в конце концов делает memmove, поэтому нам нужен указатель на его DrvCopyBits, так же нам нужен SURFOBJ* физической поверхности. С выводом графики в Windows связаны два драйвера: 1) драйвер минипорта видео, который является стандартным драйвером, драйвером видеопорта его делает лишь импорт из videoprt.sys и вызов VideoPortInitialize 2) драйвер дисплея .dll, который на самом деле никакой не dll, а самый настоящий драйвер режима ядра, но не обычный - его загружает подсистема win32 в момент загрузки системы или в рантайме при установке нового видеоадаптера и он может импортировать только из win32k.sys. Драйвер минипорта ничем не примечателен - он отвечает за фактическую работу с аппаратной частью - собственно видеокартой, а драйвер дисплея представляет некоторый интерес - он предоставляет подсистеме win32 функции, в которых заложена логика того, как работать с фреймбуффером, который можно получить от драйвера минипорта запросом IOCTL_VIDEO_MAP_VIDEO_MEMORY. Далеко не на всех видеокартах фреймбуффер содержит подряд пиксели экрана, например у меня на ноутбуке фреймбуффер содержит scan-lines (так Windows называет горизонтальную линию пикселей), выровненные на границу страницы. То есть если разрешение стоит 1280x800, то каждая новая строчка начинается не со смещения nLine * 1280 * sizeof(PIXEL), а со смещения ALIGN_UP (nLine*1280*sizeof(PIXEL), PAGE_SIZE). На других видеокартах могут быть свои причуды. Всем этим управляет драйвер дисплея, фунция DrvCopyBits которого как раз копирует пиксели с win32-поверхности (SURFOBJ) на поверхность экрана, производя, при необходимости, нужные преобразования (как минимум, нужно преобразовать обратный порядок бит, который используется в Windows и в bmp файлах в прямой порядок на экране). Поэтому для корректного вывода нам потребуется две вещи - адрес DrvCopyBits драйвера дисплея и указатель на поверхность экрана SURFOBJ*. Драйвер основного дисплея загружается при старте системы, инициализация win32 подсистемы csrss.exe вызывает функцию win32k!NtUserInitialize, которая делает NtUserChangeDisplaySettings, а она вызывает win32k!ldevLoadDriver: fa0f2980 bf8ba311 vmx_fb!DrvEnableDriver+0x11 fa0f29ac bf8ba3c6 win32k!ldevLoadDriver+0x71 fa0f29c4 bf8bd52d win32k!ldevGetDriverModes+0x1b fa0f29f4 bf8b8cde win32k!DrvBuildDevmodeList+0xa4 fa0f2a7c bf8b3221 win32k!DrvProbeAndCaptureDevmode+0x408 fa0f2bf4 bf8b9423 win32k!DrvCreateMDEV+0x42d fa0f2ce8 bf8b624e win32k!DrvChangeDisplaySettings+0x2e5 fa0f2d28 bf8b61bc win32k!InitVideo+0x3e fa0f2d48 bf8b71fe win32k!UserInitialize+0x14d fa0f2d50 8053c808 win32k!NtUserInitialize+0x87 fa0f2d50 7c90eb94 nt!KiFastCallEntry+0xf8 0015fd80 75b3a68e ntdll!KiFastSystemCallRet 0015fdb0 75b13472 winsrv!NtUserInitialize+0xc 0015fe20 75b1301b CSRSRV!CsrLoadServerDll+0x1a0 0015ff74 75b130f3 CSRSRV!CsrParseServerCommandLine+0x2d6 0015ff88 4a68115d CSRSRV!CsrServerInitialization+0x95 0015ffa8 4a6818d7 csrss!main+0x4f 0015fff4 00000000 csrss!NtProcessStartup+0x1d2 (не спрашивайте откуда у меня символы для дллек вмвари, это на самом деле мой собственный mirror-драйвер, которым я подменил оригинальный в вмваре и все запросы он транслировал в оригинальный - мне так легче было изучить как работает драйвер дисплоея) Этот стек вызовов показан с VMWare, где драйвер дисплея - vmx_fb.dll. Точка входа драйвера дисплея называется DrvEnableDriver, она имеет следующий прототип: BOOLEAN NTAPI DrvEnableDriver( ULONG iEngineVersion, ULONG cj, PDRVENABLEDATA pded ); Эта функция производит много полезных вещей, но на выходе она обязана записать в PDRVENABLEDATA массив Callback'ов драйвера (для примера как работает драйвер дисплея - посмотри \WINDDK\2600.1106\src\video\displays\mirror\disp\enable.c и другие файлы из этой директории). Нам нужен этот массив каллбеков. Я сделал следующим образом (см. http://code.google.com/p/ngdbg/source/browse/trunk/ngvid.cpp и функцию REINITIALIZE_ADAPTER()): я подгружаю себе копию видеодрайвера функцией EngLoadImage (как мне удается использовать Eng* в обычном драйвере с такой легкостью - другой вопрос это тоже можно найти в сорцах, у меня используется фишка с ложным импортом и его динамической подменой) и просто вызываю ее ентри. Она не производит никаких действий по инициализации видеокарты, поскольку драйвер дисплея обычно подгружается несколько раз. Поэтому я могу смело ее вызвать и получить себе массив каллбеков. После этого драйвер выгружается. Я ищу в массиве каллбеков DrvCopyBits, считаю её RVA относительно базы копии видеодрайвера. После этого я добавляю VA загруженного нормального видеодрайвера и получаю реальный адрес DrvCopyBits. Первая часть задачи решена. Начинаем решать вторую часть - чтобы получить SURFOBJ* поверности экрана, я ставлю сплайсинговый хук на DrvCopyBits. Не думаю, что юзеры во время загрузки моего драйвера будут интенсивно водить мышкой, поэтому вряд ли функция будет вызываться часто. DrvCopyBits имеет такой прототип: BOOLEAN NTAPI DrvCopyBits( OUT _SURFOBJ *psoDst, IN _SURFOBJ *psoSrc, IN VOID *pco, IN VOID *pxlo, IN VOID *prclDst, IN VOID *pptlSrc ); Нас интересует значение psoDst - функция обычно занимается копированием НА поверхность экрана. Поэтому в обработчике хука мы делаем некоторые проверки на psoDst (я делаю проверки на размер поверхности - если она больше или равна, чем 640х480, очевидно это главная поверхность) и записываю себе её как главную поверхность. После этого хук снимается. Задача решена. Теперь для вывода нужно создать себе поверхность через EngCreateBitmap, рисовать там через Eng*** функции, а потом скопировать изображение на первичную главную поверхность экрана через DrvCopyBits. Как это все происходит можно посмотреть в http://code.google.com/p/ngdbg/source/browse/trunk/worker.cpp - там содержатся функции, отвечающие за интерфейсную часть отладчика (в отличие от http://code.google.com/p/ngdbg/source/browse/trunk/gui.cpp, где содержится небольшой набор GDI-аналогов для вывода текста на экран и других шалостей с собственным форматом шрифтов). Достаточно посмотреть на функцию DisplayBuffers или WR_ENTER_DEBUGGER (нет, не все функции у меня называются заглавными буквами - только две, уже не помню почему ).
там кстати копирайты есть CADT точно указан http://code.google.com/p/ngdbg/source/browse/trunk/Disasm.h
Spasibo. Posmotrel, davolno interesno. Ja tozhe dlia sebia sdelal kmd, no on otlichaetsia tem shto bolshe softice napominaet (hooki na interaptah, i vivod priamo na pci framebuffer (do novih geforce on lineinij i rabotaet nadezhno s naimenshimi izmenenijami v sisteme). A vot naschet video draiverov i otkaza zagruzki kogda importiruetsa shto to ne iz win32k.sys, est' prostoe reshenie (nu kaneshno krome ioctl na miniport) - mozhno sdelat' obiknovenij driver, eksportirovat' iz nevo nuzhnie funkciji, togda ego zagruzhat' s EngLoadImage, naiti adresa s EngFindImageProcAddress i vipolnat' ih (analog loadlibrary, getprocaddress v usermode). Izvinite za translit, ja sam litovec i na ruskoi klaviature pol dnia bi pechatal
Nerka Если есть проблемы с русскоязычной клавиатурой, то используй транслитератор (например, http://www.translit.ru/ ).
Nerka Насчет драйверов была такая идея. Все равно не потребовалась, т.к. драйвера минипорта я отбросил из своего решения.
Great, я вот еще думал про вывод прямо через crt порта, но мне показалось довольно большая возня копаться в crt регистрах, зная то что стандарты такие как vesa например неиспользуетса и черт знает как потом все это востоновить чтобы nvidia не ругалась и смогла дальше работать. Во всяком случае именно с выводом самые трудные проблемы. Другие части у меня практически без изменений работают под windows, linux и т.д. на х86 (имея в виду что перехваты на прерываниях). Я еще до конца не пересмотрел все соурсы, но у меня сразу же вопрос... например при сингл степ отпускаем вывод до следующей инструкции.. Если ты все выводишь через GDI, как ты справляешься со всеми изменениями которые проходит во время вывода? Ведь черт знает что в это время драивер делает. Или ты уверен что в DrvBitBlt (или DrvCopyBits) будет простое memcpy которое ничего ни меняет и это можно утоить?