Отладка ядра в Bochs с отладочными символами
Posted: Mon Sep 28, 2020 4:29 pm
Здравствуйте. В этой инструкции я расскажу как можно с удобством отлаживать ядро KolibriOS во встроенном отладчике эмулятора Bochs. Насколько мне известно, раньше для отладки ядра колибри применяли magic breakpoint'ы в bochs (xchg bx, bx) . Этот способ простой, но далеко не самый удобный, потому что каждый раз приходится менять код и пересобирать ядро, для того чтобы просто переставить брейкпоинт с одного места на другое. Я же покажу, как можно сгенерировать отладочные символы для всего ядра и как их использовать при отладке.
В отладчике Bochs'a есть замечательная возможность, можно загрузить отладочные символы из .map файла. Причем, данный формат крайне простой - это просто набор строк вида, например . Значит, создав такой файл и скормив его bochs'у, мы сможем, к примеру, ставить брейкпоинты, зная только имя функции, смотреть значения переменных, зная их имя - согласитесь, очень удобно.
Но как нам сформировать этот самый .map файл? Ведь в ядре тысячи переменных и функций, не будем же мы руками вбивать их и их адреса в файл?
Поэтому за нас это сделает софт.
Сперва, мы должны скомпилировать ядро Колибри с отладочными символами, да, fasm умеет их генерировать, у него свой формат .fas. Для этого возьмем build.bat и изменим строку на строку
Запустим, теперь у нас кроме kernel.mnt появится kernel.fas
Сам формат .fas досточно сложный, нам же потребуется лишь малая часть информации из него. Воспользуемся утилитой symbols, она поставляется вместе с самим fasm'ом (чтобы скомпилировать ее, зайдите в tools/win32 и выполните fasm symbols.asm symbols.exe). Данная утилита читает из .fas файла имена и адреса символов, а также место их объявления в исходнике. Теперь выполним
В получившемся файле kernel.txt мы увидим строки наподобие . Как видите, это не соответствует формату .map для отладчика bochs'a. Нужно написать конвертер.
Наконец, для конвертации в .map мы пишем скрипт на питоне fastxt2bochs_map.py следующего содержания:
Далее выполняем
После этого мы получаем файл kernel.txt.map - отладочные символы для bochs готовы!
Теперь расскажу как с ними, собственно, работать. Сначала приготовьте образ Колибри, скачайте самый свежий kolibri.img (это важно т.к если ваш образ колибри более старый (прошлогодний например), чем исходники ядра из которых вы получили символы на предыдущем шаге, то могут быть проблемы). Далее настраиваем конфигурацию машины (я просто прикреплю свой bochsrc.bxrc в конце).
Запускаем нашу машину в Bochs дебаггере (bochsdbg) . Видим такое приглашение ко вводу <bochs:1>
Далее выполняем следующие команды.
Загружаем наши отладочные символы:
Ставим брейкпоинт на какую-нибудь функцию, например:
Запустим выполнение кода до брейкпоинта:
.
Дойдя до брейкпоинта, bochs останавливает выполнение кода и снова дает возможность вводить нам команды.
Выведем, например, значения всех регистров, набрав команду:
Дизассемблируем, например, некоторое количество инструкций от начала нашей функции:
Можем смотреть значения переменных по имени, например читаем 4-байтовую:
Изучение всех команд отладчика Bochs выходит за рамки данного мануала, поэтому предлагаю еще почитать справку по ним http://bochs.sourceforge.net/doc/docboo ... ugger.html
P.S мой файл bochsrc.bxrc (пути только на свои подправьте ) :
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
В отладчике Bochs'a есть замечательная возможность, можно загрузить отладочные символы из .map файла. Причем, данный формат крайне простой - это просто набор строк вида
Code: Select all
16ичныйадрес имя
Code: Select all
0000000080023628 create_usb_thread
Но как нам сформировать этот самый .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
Сам формат .fas досточно сложный, нам же потребуется лишь малая часть информации из него. Воспользуемся утилитой symbols, она поставляется вместе с самим fasm'ом (чтобы скомпилировать ее, зайдите в tools/win32 и выполните fasm symbols.asm symbols.exe). Данная утилита читает из .fas файла имена и адреса символов, а также место их объявления в исходнике. Теперь выполним
Code: Select all
symbols kernel.fas kernel.txt
Code: Select all
tcp_output.options_done: 0x00000000800336B6, defined in network/tcp_output.inc[404]
Наконец, для конвертации в .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
Теперь расскажу как с ними, собственно, работать. Сначала приготовьте образ Колибри, скачайте самый свежий 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
Code: Select all
x /1wx "CURRENT_TASK"
P.S мой файл bochsrc.bxrc (пути только на свои подправьте ) :
Spoiler:
# configuration file generated by Bochsplugin_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