Page 1 of 1

Отладка ядра в Bochs с отладочными символами

Posted: Mon Sep 28, 2020 4:29 pm
by rgimad
Здравствуйте. В этой инструкции я расскажу как можно с удобством отлаживать ядро KolibriOS во встроенном отладчике эмулятора Bochs. Насколько мне известно, раньше для отладки ядра колибри применяли magic breakpoint'ы в bochs (xchg bx, bx) . Этот способ простой, но далеко не самый удобный, потому что каждый раз приходится менять код и пересобирать ядро, для того чтобы просто переставить брейкпоинт с одного места на другое. Я же покажу, как можно сгенерировать отладочные символы для всего ядра и как их использовать при отладке.

В отладчике Bochs'a есть замечательная возможность, можно загрузить отладочные символы из .map файла. Причем, данный формат крайне простой - это просто набор строк вида

Code: Select all

16ичныйадрес имя
, например

Code: Select all

0000000080023628 create_usb_thread
. Значит, создав такой файл и скормив его bochs'у, мы сможем, к примеру, ставить брейкпоинты, зная только имя функции, смотреть значения переменных, зная их имя - согласитесь, очень удобно.

Но как нам сформировать этот самый .map файл? Ведь в ядре тысячи переменных и функций, не будем же мы руками вбивать их и их адреса в файл?
Поэтому за нас это сделает софт.

Сперва, мы должны скомпилировать ядро Колибри с отладочными символами, да, fasm умеет их генерировать, у него свой формат .fas. Для этого возьмем build.bat и изменим строку

Code: Select all

fasm -m 65536 kernel.asm kernel.mnt
на строку

Code: Select all

fasm -m 65536 kernel.asm -s kernel.fas kernel.mnt
Запустим, теперь у нас кроме kernel.mnt появится kernel.fas

Сам формат .fas досточно сложный, нам же потребуется лишь малая часть информации из него. Воспользуемся утилитой symbols, она поставляется вместе с самим fasm'ом (чтобы скомпилировать ее, зайдите в tools/win32 и выполните fasm symbols.asm symbols.exe). Данная утилита читает из .fas файла имена и адреса символов, а также место их объявления в исходнике. Теперь выполним

Code: Select all

symbols kernel.fas kernel.txt
В получившемся файле kernel.txt мы увидим строки наподобие

Code: Select all

tcp_output.options_done: 0x00000000800336B6, defined in network/tcp_output.inc[404]
. Как видите, это не соответствует формату .map для отладчика bochs'a. Нужно написать конвертер.

Наконец, для конвертации в .map мы пишем скрипт на питоне fastxt2bochs_map.py следующего содержания:

Code: Select all

import re
import sys
if len(sys.argv) < 2 or sys.argv[1].strip() == '':
    print('error: no input file\nusage: {:s} <file>'.format(sys.argv[0]))
    exit(-1)
inp_path = sys.argv[1].strip()
out_path = inp_path + '.map'
inp = open(inp_path,'r')
inp_text = inp.read()
inp.close()
regex1 = re.compile(r"[\S]+\:\s0x[\da-fA-F]*")
res = re.findall(regex1, inp_text)
#print(res)
out = open(out_path, 'w')
for ln in res:
    splt = ln.split()
    sym_addr = int(splt[1],16)
    sym_name = splt[0][:-1]
    out.write('{:016x} {:s}\n'.format(sym_addr, sym_name))
out.close()

Далее выполняем

Code: Select all

fastxt2bochs_map.py kernel.txt
После этого мы получаем файл kernel.txt.map - отладочные символы для bochs готовы!

Теперь расскажу как с ними, собственно, работать. Сначала приготовьте образ Колибри, скачайте самый свежий kolibri.img (это важно т.к если ваш образ колибри более старый (прошлогодний например), чем исходники ядра из которых вы получили символы на предыдущем шаге, то могут быть проблемы). Далее настраиваем конфигурацию машины (я просто прикреплю свой bochsrc.bxrc в конце).

Запускаем нашу машину в Bochs дебаггере (bochsdbg) . Видим такое приглашение ко вводу <bochs:1>
Далее выполняем следующие команды.
Загружаем наши отладочные символы:

Code: Select all

ldsym "kernel.txt.map"
Ставим брейкпоинт на какую-нибудь функцию, например:

Code: Select all

lb "high_code"
Запустим выполнение кода до брейкпоинта:

Code: Select all

cont
.
Дойдя до брейкпоинта, bochs останавливает выполнение кода и снова дает возможность вводить нам команды.
Выведем, например, значения всех регистров, набрав команду:

Code: Select all

r
Дизассемблируем, например, некоторое количество инструкций от начала нашей функции:

Code: Select all

u "high_code" "high_code"+50
Можем смотреть значения переменных по имени, например читаем 4-байтовую:

Code: Select all

x /1wx "CURRENT_TASK"
Изучение всех команд отладчика Bochs выходит за рамки данного мануала, поэтому предлагаю еще почитать справку по ним http://bochs.sourceforge.net/doc/docboo ... ugger.html

P.S мой файл bochsrc.bxrc (пути только на свои подправьте ) :
Spoiler:# configuration file generated by Bochs
plugin_ctrl: unmapped=true, biosdev=true, speaker=true, extfpuirq=true, parallel=true, serial=true, gameport=true
config_interface: win32config
display_library: win32
memory: host=128, guest=128
romimage: file="D:\ProgramFiles\Bochs-2.6.11/BIOS-bochs-latest", address=0x00000000, options=none
vgaromimage: file="D:\ProgramFiles\Bochs-2.6.11/VGABIOS-lgpl-latest"
boot: floppy
floppy_bootsig_check: disabled=0
floppya: type=1_44, 1_44="D:\Documents\ПРОГРАММНЫЕ ПРОЕКТЫ И ЗАДАЧИ\KolibriOS_projects\Kolibri_kernel\trunk\kolibri.img", status=inserted, write_protected=0
# no floppyb
ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=none
ata0-slave: type=none
ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata1-master: type=none
ata1-slave: type=none
ata2: enabled=false
ata3: enabled=false
optromimage1: file=none
optromimage2: file=none
optromimage3: file=none
optromimage4: file=none
optramimage1: file=none
optramimage2: file=none
optramimage3: file=none
optramimage4: file=none
pci: enabled=1, chipset=i440fx
vga: extension=vbe, update_freq=60, realtime=1
cpu: count=1, ips=8000000, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
cpuid: level=6, stepping=3, model=3, family=6, vendor_string="GenuineIntel", brand_string=" Intel(R) Pentium(R) 4 CPU "
cpuid: mmx=true, apic=xapic, simd=sse2, sse4a=false, misaligned_sse=false, sep=true
cpuid: movbe=false, adx=false, aes=false, sha=false, xsave=false, xsaveopt=false, x86_64=true
cpuid: 1g_pages=false, pcid=false, fsgsbase=false, smep=false, smap=false, mwait=true
cpuid: vmx=1
print_timestamps: enabled=0
port_e9_hack: enabled=0
private_colormap: enabled=0
clock: sync=none, time0=local, rtc_sync=1
# no cmosimage
log: -
logprefix: %t%e%d
debug: action=ignore
info: action=report
error: action=report
panic: action=ask
keyboard: type=mf, serial_delay=200, paste_delay=100000, user_shortcut=none
mouse: type=ps2, enabled=false, toggle=ctrl+f10
sound: waveoutdrv=win, waveout=none, waveindrv=win, wavein=none, midioutdrv=win, midiout=none
speaker: enabled=true, mode=sound
parport1: enabled=true, file=none
parport2: enabled=false
com1: enabled=true, mode=null
com2: enabled=false
com3: enabled=false
com4: enabled=false