Unofficial guide to MTDBG

From KolibriOS wiki
Revision as of 11:35, 11 July 2016 by Nisargshah95 (talk | contribs) (→‎bpm: changed 'bpm w' to 'bpmw')
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search


This is an unofficial guide, targetted at the beginner. The official documentation is called 'mtdbg.txt' and can be found in DOCPACK program in KolibriOS.


MTDBG is the application-level debugger for KolibriOS.
It can make your life easier on many occasions. Whether you are still learning assembly and just want to see what's going on, or you are trying to fix that bug that nobody else has the guts for.


Mtdbg overview.png

Loading your application

There are several ways to load your application into the debugger.
You could simply click 'MTDBG' icon on the KolibriOS desktop and use the 'load' command from there.
Another option is to load it from FASM (in KolibriOS) with 'debug' button.
The third option is to load directly from tinypad by pressing f10 or choosing "run > run in debugger" from the menu while your source code is opened in tinypad.

Loading symbols

The debugger works with binary code. It views the unassembled code to the developer, but this code has much less information then the original assembly code.
All information such as labels, comments etc. were lost during assembly process.
When working on a binary, this information cannot be recovered.
When you have the original source code however, it can be useful to load this information into the debugger so it displays the original label names additional to the hexadecimal addresses.

In FASM on KolibriOS, select the 'generate debug information' check-box before assembling your code.
FASM will now create a *.dbg file in the same folder as the binary, which should be automatically loaded by MTDBG when loading the binary.

MTDBG versions 0.34 and newer also have support to load symbols from a .map file that can be generated by GCC.



Using breakpoints

Single stepping can be really fun when you have nothing else to do, but most developers probably want to spend their time usefully.
Therefore, you can request the debugger to halt the execution of the program when a given instruction is about to be run.
Lets assume we have our symbols loaded, and we are interested in what happens after the label 'red'.
(Offcourse you can also enter addresses in hexadecimal, when no symbols are loaded, or the instruction of interest has no label)
While the program is suspended (default state after loading a program), type 'bp red' to set the breakpoint.
You will see the label highlighted in blue in the disassembly view.


Now you can run the program (eg by using the command 'g') and the program will suspend when the subroutine of interest is reached.


loading files into the debugger


Load the program you want to debug.
eg. 'load /rd/1/example'


Load the debug symbols.
These symbols can be generated with FASM on KolibriOS by selecting the 'generate debug symbols' option before compiling the code.

The debug symbols have .dbg extension.
If the symbols exist in the same directory, and with the same filename as the binary, they will be loaded automatically.
eg. 'load-symbols /rd/1/example.dbg

controlling the view


Dump data at a given addres.
Parameter can be direct hex address, register or label.
eg. 'd esi'


Unassemble code at a given addres.
Parameter can be direct hex address, register or label.
eg. 'u redraw'

Stepping and running


Single step. Execute the following instruction and then halt.


Go on. (Resume execution of program)
Execution will terminate when a breakpoint is reached, the application exits or when there occurs a fault (divide by 0, page fault, ..)

reading/manipulating the registers


Calculate the value of an expression (and print the value to the debugger).
eg. '? eax - ebx'


Change the value of a register to a given expression.
eg. 'r eax 1234'
eg. 'r eax edx'



Set a (regular) breakpoint.
The debugger will suspend the debugged process whenever such a point is reached.
eg. 'bp redraw'
eg. 'bp 1234'


Set a data breakpoint.
The debugger will suspend the debugged process when the data at the given address is being accessed.

You must give the size of the data type (b = byte, w = word, d = dword) and the type of access on which you want to break (r = read/write [default], w = write only)
eg. 'bpmw 1234'


Clear a breakpoint (remove it completely).
eg. 'bc 0'


Disable a breakpoint (but remember the address in list).
eg. 'bd 1'


Enable a previously disabled breakpoint.
eg. 'be 0'


List all active breakpoints.


Some of the previously listed commands accept so called expressions as an input.
Expressions can include:

  • Hexadecimal constants.
  • Names of general-purpose registers.
  • +, -, *, / arithmetic symbols (with standard priorities) and brackets.
  • labels from symbol file.

some examples:
ax+2*bh*(eip+ a73)

User breakpoints

Another way of inserting breakpoints into the program you want to debug, is by putting them inside the binary.
This can be done with a hex editor, your assembler, or even your compiler.
MTDBG will recognize all "int 3" instructions as so called user breakpoints. So all you need to do is place "int 3" assembly code at the place where you'd like the program to halt for inspection. (Or you can try to be hardcore and just use 0xCC hexadecimal code.)