How to debug KolibriOS kernel/ru: Difference between revisions
No edit summary |
m (fix typo) |
||
(One intermediate revision by the same user not shown) | |||
Line 1: | Line 1: | ||
Есть несколько способов отлаживать ядро KolibriOS. | |||
Отладка ядра в первую очередь связана с использованием различных эмуляторов | Отладка ядра в первую очередь связана с использованием различных эмуляторов. | ||
== Bochs == | == Bochs == | ||
Bochs - это полностью программный эмулятор процессора и периферии. Эмулирует только x86, на которой и работает Колибри. | Bochs - это полностью программный эмулятор процессора и периферии. Эмулирует только x86, на которой и работает Колибри. | ||
Чтобы добраться до нужного кода ядра в процессе отладки есть несколько способов. | Чтобы добраться до нужного кода ядра в процессе отладки есть несколько способов. | ||
1 | |||
=== 1 способ: === | |||
Ставим "magic breakpoint" в коде - xchg bx, bx | |||
и в конфиге bochs: magic_break: enabled=1 | и в конфиге bochs: magic_break: enabled=1 | ||
перекомпилируем, запускаем и в нужном месте эмулятор остановится. | перекомпилируем, запускаем и в нужном месте эмулятор остановится. | ||
=== 2 способ: === | |||
Первый способ простой, но далеко не самый удобный, потому что каждый раз приходится менять код и пересобирать ядро, для того чтобы просто переставить брейкпоинт с одного места на другое. Далее описана инструкция, как можно сгенерировать отладочные символы для всего ядра и как их использовать при отладке. | |||
В отладчике Bochs'a есть замечательная возможность, можно загрузить отладочные символы из .map файла. Причем, данный формат крайне простой - это просто набор строк вида '''16ичныйадрес имя''', например '''0000000080023628 create_usb_thread''' Значит, создав такой файл и скормив его bochs'у, мы сможем, к примеру, ставить брейкпоинты, зная только имя функции, смотреть значения переменных, зная их имя - согласитесь, очень удобно. | |||
Но как нам сформировать этот самый .map файл? Ведь в ядре тысячи переменных и функций, не будем же мы руками вбивать их и их адреса в файл? | |||
Поэтому за нас это сделает софт. | |||
Сперва, мы должны скомпилировать ядро Колибри с отладочными символами, да, fasm умеет их генерировать, у него свой формат .fas. Для этого возьмем build.bat и изменим строку '''fasm -m 65536 kernel.asm kernel.mnt''' на строку '''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 файла имена и адреса символов, а также место их объявления в исходнике. Теперь выполним '''symbols kernel.fas kernel.txt''' | |||
В получившемся файле kernel.txt мы увидим строки наподобие '''tcp_output.options_done: 0x00000000800336B6, defined in network/tcp_output.inc[404]''' . Как видите, это не соответствует формату .map для отладчика bochs'a. Нужно написать конвертер. | |||
Наконец, для конвертации в .map мы пишем скрипт на питоне fastxt2bochs_map.py следующего содержания: | |||
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() | |||
Далее выполняем '''fastxt2bochs_map.py kernel.txt''' | |||
После этого мы получаем файл kernel.txt.map - отладочные символы для bochs готовы! | |||
Теперь расскажу как с ними, собственно, работать. Сначала приготовьте образ Колибри, скачайте самый свежий kolibri.img (это важно т.к если ваш образ колибри более старый (прошлогодний например), чем исходники ядра из которых вы получили символы на предыдущем шаге, то могут быть проблемы). Далее настраиваем конфигурацию машины (я просто прикреплю свой bochsrc.bxrc в конце). | |||
Запускаем нашу машину в Bochs дебаггере (bochsdbg) . Видим такое приглашение ко вводу <bochs:1> | |||
Далее выполняем следующие команды. | |||
Загружаем наши отладочные символы: | |||
'''ldsym "kernel.txt.map"''' | |||
Ставим брейкпоинт на какую-нибудь функцию, например: | |||
'''lb "high_code"''' | |||
Запустим выполнение кода до брейкпоинта: | |||
'''cont''' | |||
Дойдя до брейкпоинта, bochs останавливает выполнение кода и снова дает возможность вводить нам команды. | |||
Выведем, например, значения всех регистров, набрав команду: | |||
'''r''' | |||
Дизассемблируем, например, некоторое количество инструкций от начала нашей функции: | |||
'''u "high_code" "high_code"+50''' | |||
Можем смотреть значения переменных по имени, например читаем 4-байтовую: | |||
'''x /1wx "CURRENT_TASK"''' | |||
Изучение всех команд отладчика Bochs выходит за рамки данного мануала, поэтому предлагаю еще почитать справку по ним http://bochs.sourceforge.net/doc/docbook/user/internal-debugger.html | |||
== Qemu == | == Qemu == |
Latest revision as of 15:31, 24 November 2020
Есть несколько способов отлаживать ядро KolibriOS. Отладка ядра в первую очередь связана с использованием различных эмуляторов.
Bochs
Bochs - это полностью программный эмулятор процессора и периферии. Эмулирует только x86, на которой и работает Колибри. Чтобы добраться до нужного кода ядра в процессе отладки есть несколько способов.
1 способ:
Ставим "magic breakpoint" в коде - xchg bx, bx и в конфиге bochs: magic_break: enabled=1 перекомпилируем, запускаем и в нужном месте эмулятор остановится.
2 способ:
Первый способ простой, но далеко не самый удобный, потому что каждый раз приходится менять код и пересобирать ядро, для того чтобы просто переставить брейкпоинт с одного места на другое. Далее описана инструкция, как можно сгенерировать отладочные символы для всего ядра и как их использовать при отладке.
В отладчике Bochs'a есть замечательная возможность, можно загрузить отладочные символы из .map файла. Причем, данный формат крайне простой - это просто набор строк вида 16ичныйадрес имя, например 0000000080023628 create_usb_thread Значит, создав такой файл и скормив его bochs'у, мы сможем, к примеру, ставить брейкпоинты, зная только имя функции, смотреть значения переменных, зная их имя - согласитесь, очень удобно.
Но как нам сформировать этот самый .map файл? Ведь в ядре тысячи переменных и функций, не будем же мы руками вбивать их и их адреса в файл? Поэтому за нас это сделает софт.
Сперва, мы должны скомпилировать ядро Колибри с отладочными символами, да, fasm умеет их генерировать, у него свой формат .fas. Для этого возьмем build.bat и изменим строку fasm -m 65536 kernel.asm kernel.mnt на строку 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 файла имена и адреса символов, а также место их объявления в исходнике. Теперь выполним symbols kernel.fas kernel.txt В получившемся файле kernel.txt мы увидим строки наподобие tcp_output.options_done: 0x00000000800336B6, defined in network/tcp_output.inc[404] . Как видите, это не соответствует формату .map для отладчика bochs'a. Нужно написать конвертер.
Наконец, для конвертации в .map мы пишем скрипт на питоне fastxt2bochs_map.py следующего содержания:
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()
Далее выполняем fastxt2bochs_map.py kernel.txt После этого мы получаем файл kernel.txt.map - отладочные символы для bochs готовы!
Теперь расскажу как с ними, собственно, работать. Сначала приготовьте образ Колибри, скачайте самый свежий kolibri.img (это важно т.к если ваш образ колибри более старый (прошлогодний например), чем исходники ядра из которых вы получили символы на предыдущем шаге, то могут быть проблемы). Далее настраиваем конфигурацию машины (я просто прикреплю свой bochsrc.bxrc в конце).
Запускаем нашу машину в Bochs дебаггере (bochsdbg) . Видим такое приглашение ко вводу <bochs:1> Далее выполняем следующие команды. Загружаем наши отладочные символы: ldsym "kernel.txt.map" Ставим брейкпоинт на какую-нибудь функцию, например: lb "high_code" Запустим выполнение кода до брейкпоинта: cont Дойдя до брейкпоинта, bochs останавливает выполнение кода и снова дает возможность вводить нам команды. Выведем, например, значения всех регистров, набрав команду: r Дизассемблируем, например, некоторое количество инструкций от начала нашей функции: u "high_code" "high_code"+50 Можем смотреть значения переменных по имени, например читаем 4-байтовую: x /1wx "CURRENT_TASK" Изучение всех команд отладчика Bochs выходит за рамки данного мануала, поэтому предлагаю еще почитать справку по ним http://bochs.sourceforge.net/doc/docbook/user/internal-debugger.html
Qemu
В Qemu есть встроенный отладчик - реализация gdb server. Соответственно для отладки нужен клиент - сам gdb, или реализации клиентов.