середу, 25 травня 2011 р.

Засоби зневадження в bochs

Вирішив окремо винести частину нульового уроку захищеного режиму, присвячену засобам зневадження (відлагодження) bochs - так-званому internal debugger.

Нагадаю, bochs -- емулятор x86-сумісних процесорів та деякої типової апаратури "IBM-PC-сумісних" машин. Підтримує процесори від 386 і далі. Реалізовано підтримку x86-64, MMX, SSE аж до SSE4.2, AES, тощо. Детальніше див. документацію та приклад конфігурування bochsrc-sample.txt. З апаратури підтримуються доволі просунутий BIOS, VGA адаптер та VESA режими аж до 2560x1600x32bpp, гнучкі та жорсткі диски, CD-ROM, клавіатуру-мишку-звукову-мережеву-карти, паралельні та послідовні порти, частково USB, тощо. Частина пристроїв виключно віртуальна, в ролі інших можна використовувати фізичні пристрої host-машини.

Не всі пристрої присутні на кожній з host-архітектур, на яких bochs працює.

Скачати цю всю радість можна тут: http://sourceforge.net/projects/bochs/files/bochs/2.4.6/. Представлено Win32, Win64, Linux 32/64 бінарні дистрибутиви та джерельні тексти.

Особисто я був вражений внутрішнім "дебагером", тому вирішив главу про нього винести в окремий пост.

Нічого такого, чого немає в документації, цей пост не містить, і може краще читати безпосередньо її. Також bochs підтримує взаємодію з GDB, ця можливість тут не розглядається.

Вiдладка з використанням bochsdbg

Iснує вiдлагоджувальний варiант bochs — bochsdbg (bochsdbg.exe пiд Windows).
Вiн дозволяє слiдкувати за роботою процесора вiртуальної машини. Зразу пiсля запуску вiн входить у режим вiдлагодження i щоб розпочати завантаження вiртуальної машини, слiд дати команду continue (c). Зупинити вiртуальну машину та перейти до вiдлагодження можна, натиснувши в консолi вiдладника Ctrl-C.
Деякi команди режиму вiдлагодження:
  • c, cont, continue — продовжити виконання.
  • s, step [count] — виконати count iнструкцiй, по замовчуванню — 1.
  • q, quit, exit — завершити роботу bochsdbg
  • r, reg, regs, registers — вивести регiстри процесора загального використання.
  • fpu; mmx; sse — вивести регiстри вiдповiдних розширень архiтектури.
  • sreg — вивести сегментнi регiстри.
  • creg — вивести регiстри керування.
  • info cpu — вивести всi регiстри.
  • info eflags — вивести розшифровку eflags.
  • trace on; trace off — вмикає/вимикає вивiд кожної виконаної команди.
  • print-stack [num words] — надрукувати num words 16-бiтних слiв з вершини стеку. (Може бути ненадiйним в захищеному режимi якщо базова адреса сегмента стеку не нуль)
  • modebp — зупинка при переключеннi режимiв.
  • show mode — показує переключення режиму процесора.
  • show int — показує виникнення переривань
  • show call — показує виклики пiдпрограм.
  • show ret — показує виконання iret.
  • show off — вимкнути вивiд символьної iнформацiї.
  • show dbg-all — ввiмкнути всi show.
  • show dbg-none — вимкнути всi show
Цей список далеко не повний! Зокрема є серiя команд по роботi з точками зупинки, манiпуляцiй з пам’яттю та регiстрами, дизасемблюванням, i т.д. Див. роздiл ”Using Bochs internal debugger” документацiї.

Особливо зручною для нас є команда modebp, яка дозволяє зупинитися якраз пiсля того, як наша програма перейшла в захищений режим. Слiд, однак мати на увазi, що драйвери типу himem самi часто можуть переходити в захищений режим i назад, тому ”наш” перехiд може бути далеко не першим. Натрапивши на такi переходи просто даємо команду continue.

”Офiцiйнi” збiрки bochs версiй 2.4.x для Win32 мiстять графiчний iнтерфейс конфiгурування та зневадження (вiдлагодження). Доволi зручний. Вмикається опцiєю:
config_interface: win32config
та
display_library: win32, options="gui_debug"
вiдповiдно. Якщо у конкретнiй збiрцi вiн не пiдтримується, про це буде повiдомлено якось так: ”config_interface ’win32config’ not available” або ”Unknown win32 option ’gui_debug’ ”.

Виглядає він ось так: (зверніть увагу на внутрішній стан PIC що розгорнуто праворуч, він буде корисний для розуміння деякого матеріалу 5-го уроку, ще не викладеного):
та цілком вартує окремого дослідження. Щоб заінтригувати, приклад відображення GDT уроку номер 6 (ще не викладеного):

”Магічна точка зупинки”

Якщо дозволити в конфiгурацiї, то bochsdbg, зустрiвши команду XCHG BX, BX зупинятиме емуляцiю та переходитиме у режим вiдлагодження. Ця команда нiяк не змiнює стану програми, лише обмiнюючи регiстр BX сам з собою, тому ї ї можна вставляти в тих мiсцях програми, в яких ми хочемо зупинитися для аналiзу або покрокового виконання. Вмикається магічна точка зупинки наступною директивою:
magic_break: enabled=1

Вiртуальний пристрiй вiдлагодження

Вiртуальний пристрiй вiдлагодження — iнтерфейс вводу-виводу зневаджувача (вiдладника) bochs дозволяє безпосередньо з програми керувати зневадженням (вiдлагодженням). Реалiзується цей iнтерфейс за допомогою двох (емульованих) портiв воду-виводу — 0x8A00 i 0x8A01. На реальних машинах данi порти зазвичай не використовуються. 0x8A00 — командний, 0x8A01 — регiстр даних для монiторингу пам’ятi. Вивiд-вивiд в них повинен здiйснюватися цілими 2-байтовими словами.

Підтримуються наступні команди:
  • 0x8A00 — активує пристрiй. До цiєї команди будь-який вивiд у цей порт iгнорується.
  • 0x8A01 — вибрати регiстр 0. Початкова адреса монiторингу пам’ятi.
  • 0x8A02 — вибрати регiстр 1. Кiнцева адреса монiторингу пам’ятi (не включається в область монiторингу).
  • 0x8A80 — вмикає монiторинг областi, вказаної пiсля команд 0x8A01 i 0x8A02 та очищає обидва регiстри.
  • 0x8AE0 — активує вiдладник. (Те ж, що i Ctrl-C в консолi bochsdbg, але по бажанню програми. Наприклад перед переходом в захищений режим, щоб покроковим виконанням виявити де помилка.)
  • 0x8AE2 — припинити автоматичне покрокове виконання у вiдладнику.
  • 0x8AE3 — розпочати автоматичне покрокове виконання.
  • 0x8AE4 — заборонити автоматичне вiдслiдковування регiстрiв.
  • 0x8AE5 — дозволити автоматичне вiдслiдковування регiстрiв. Виводить вмiст всiх регiстрiв пiсля виконання кожної команди. (Спочатку необхiдно ввiмкнути покрокове виконання командою 0x8AE3).
  • 0x8AFF — вимкнути пристрiй.
Читання з цього порту повертатиме 0x8A00 якщо пристрiй ввімкнено та 0 якщо нi.
Порт даних 0x8A01 доступний тiльки на запис. Зсуває вiдповiдний регiстр, вибраний командою 0x8A0X на 16 бiт лiворуч та додає до нього значення, що було записане в порт. Наприклад:
  • Регiстр 0 = 0x01234567 
  • В порт 0x8A01 виводимо 0xABCD
  • Регiстр 0 = 0x4567ABCD
З чого видно що для передачi лiнiйної адреси пам’ятi для монiторингу слiд виконувати в два етапи, спочатку пересилається старших два байти, потiм молодших. Приклад ввiмкнення монiторингу дiлянки пам’ятi 0xB8000-0xB8FA0, яка вiдповiдає першiй сторiнцi текстової вiдеопам’ятi:

mov     dx,0x8A00h ; Активуємо пристрій
mov     ax,dx
out     dx,ax

mov     ax,0x8A01h ; Вибираємо регістр 0
out     dx,ax
mov     ax,0xBh    ; Старше слово 0xB000h
mov     dx,0x8A01h ; в порт даних
out     dx,ax

mov     ax,0x8000h ; Молодше слово 0xB000h
out     dx,ax

mov     ax,0x8A01h ; Вибираємо регістр 0
mov     dx,0x8A00h ; через порт команд
out     dx,ax
mov     ax,0xBh    ; Старше слово 0xB8FA0
mov     dx,0x8A01h ; в порт даних
out     dx,ax

mov     ax,0x8FA0h ; Молодше слово 0xB000h
out     dx,ax

mov     ax,0x8A80  ; Вмикаємо моніторинг.
mov     dx,0x8A00h
out     dx,ax

mov     ax,0x8AE0  ; Переходимо у відладник
out     dx,ax

PORT_E9_HACK

Порт 0xE9 на типових IBM-PC не задiяно, однак bochs, щоб полегшити вiдлагодження програм, особливо на раннiх стадiях — завантаження BIOS чи операцiйної системи, показуватиме в своїй консолi все що було виведено в цей порт.
Читання з цього порту повертатиме 0xE9, показуючи що дана функцiя доступна.
Активується ця корисна можливiсть директивою конфiгурацiї port_e9_hack:
port_e9_hack: enabled=1


Символи 
 bochsdbg вмiє завантажувати iнформацiю про символи в програмi (debugging symbols). Формат файлу з символами надзвичайно простий – послiдовнi стрiчки такого вигляду:
<address> <name>
Завантажити їх можна двома способами. Перший — з конфiгурацiйного файлу:
debug_symbols: file=mysymbols.sym
або
debug_symbols: file=mysymbols.sym, offset=0x1000
при цьому символи завантажуватимуться в глобальний контекст, offset вказує зсув для адрес.
Другий — командою ldsym вiдладника:
ldsym [global] filename [offset]

 де global вказує завантажувати символи в глобальному контекстi, iнакше вони будуть завантаженi в поточному, offset так само задає зсув.

Ось і все. Вийшло трохи довго, але розбивати на частини лінь. 
Див. також "Уроки захищеного режиму x86"

Немає коментарів:

Дописати коментар