KolibriOS Help [To main] [To the next point] [To the previous point]

Debugging Applications Guide

Introduction

mtdbg is a debugger for the KolibriOS. This documentation describes the capabilities of the debugger and how to work with it. For questions, please visit our forum (board.kolibrios.org).

General description

Mtdbg can only debug one program at a time. Let's call such a program loaded for debugging. If no program is loaded, the vast majority of debugging actions are not available.

mtdbg is controlled by the command line entered from the keyboard. The command line is displayed at the bottom of the debugger window. The standard input keys Backspace, Delete, Home, End, left / right arrows are processed.
Commands are not case sensitive. An arbitrary non-zero number of spaces is used as a separator.

The debugger can be terminated at any time with the "quit" command (no arguments). However, you can just click on the close button in the upper left corner of the window.

Running the debugger without command line parameters results in no program being loaded. Also, mtdbg can be run with the command line, in this case it will try to load the program with the name specified as the first command line argument and parameters specified as subsequent (if any).

If no program is loaded, you can load the program with the command load <full name of the executable file> [<arguments>].
For example:
load / rd / 1 / example
LOAD / rd / 1 / aclock w200 h200
LoaD / hd0 / 1 / menuetos / dosbox / dosbox

Everything after the first space after the name of the executable file is literally passed to the program as a command line.
The load command reports the result in a message window (just above the command line window). If the program was loaded, then this will appear the corresponding message; if not successful, the message will indicate the reason for the error. The most likely one is "file not found" if the filename is incorrect.

The debugger can load files with information about the names in the program (labels, global variables) - text files, each line of which has the form 0x <hex_address_value> <name> (lines that do not have this form are ignored). Such a file can be created manually or generated automatically when compiling the source by fasm.
Explicit loading is performed with the command load-symbols <full name of the symbol file>.
In addition, when executing the load command, the debugger checks for the existence of a file with the same name as the loaded binary and the extension .dbg (/rd/1/example.dbg for the first example above), and if there is one, loads it automatically (displaying the message "Symbols loaded" if everything is ok).

It may happen that the downloaded program is packed. The general principle of packaging programs is the following: first, the source file is packed (by some compression algorithm), then a small code is assigned, which receives control when the program starts, unpacks the source code in memory, and then transfers control to it. If the program is packed, then its "real" code is not visible and for debugging you must first go through the unpacker code. mtdbg detects most of the existing packers (mxp, mxp_lzo, mxp_nrv, mtappack) and in this case offers to automatically go to the "real" code. It is recommended to agree (press 'y' or Enter), but you can refuse.
In case of failure and in the case when the program is packed with something unknown, you can use the "unpack" command (no arguments). Call it only when you are sure that the program is packed and that control has not yet reached the main code! (Starting from Kolibri 0.6.5.0, this entire paragraph is no longer relevant, since applications can be packaged like any binaries with kpack and the unpacker code is in the kernel and unpacking is transparent for debugging.)

The loaded program can be nailed with the "terminate" command (no arguments). The detach command (with no arguments) is detached from the program, after which the program continues to execute normally, as if the debugger was not present. After both of these commands, the program ceases to be debuggable.

You can reload the program for debugging with the "reload" command (no arguments). If there is already a loaded program, then it is nailed and starts (from the very beginning) a new instance (with the same command line), in this case the command is similar to the commands terminate
load <last program name> <last program arguments>
Otherwise, the program that was debugged last (in the current session with mtdbg) (with the same command line) is loaded again, i.e. almost the same as load <last program name> <last program arguments>, but the reload command is shorter and more convenient in both cases; moreover, load considers that a new program is loaded, and transfers the data window (see below) to address zero, and reload saves the current address.

The "help" command is always available, which can be abbreviated to "h".
All teams are divided into groups:
help with no arguments displays a list of command groups.
help specifying a group displays a list of commands for that group with short comments.
help with a command specifies information about the specified command.
For example:
help
help control
h LoaD

The debugger window consists of the following items, listed from top to bottom:
- status bar. If there is a loaded program, it shows its name and state ("Running" / "Paused"), if not, it says "No program loaded".
- register window - shows the values ​​of general-purpose registers, eip register and flags register. The latter is written in two ways: the full hex value and the states of individual flags: CF, PF, AF, ZF, SF, DF, OF. If the flag is cleared, then a small letter is displayed; if set, capitalized.

Registers that have changed since the previous moment are highlighted in green.
- data window (dump window) - shows the contents of the loaded program memory
- code window (disassembler window) - shows the program code in the form of disassembled instructions
- message box
- command line window

In the dump window, you can view data starting from any address, for this there is the d <expression> command.
Command d without arguments scrolls down the dump window. The same applies to the code window and the u <expression> command or just u.
For example:
d esi - shows the data located at esi (for example, useful before executing the rep movsb instruction)
d esp - shows the stack
u eip - disassembles instructions starting with the current one

Expressions in mtdbg can include
- hexadecimal constants
- the names of all general purpose registers (8 32-bit, 8 16-bit and 8 8-bit) and eip register; 16- and 8-bit register values ​​are zero-expanded to 32 bits
- four arithmetic operations +, -, *, / (with standard precedence) and brackets
- [if there is information about symbols] names loaded from dbg file
All calculations are done modulo 2 ^ 32.
Examples of expressions:
eax
eip + 2
ecx-esi-1F
al + AH * bl
ax + 2 * bH * (eip + a73)
3 * esi * di / EAX
Command ? <expression> evaluates the value of the specified expression.

The values ​​of the registers of the loaded program can be changed with the r command, which has two absolutely equivalent forms:
r <case> <expression>
r <case> = <expression>
(in both cases, you can add spaces to your liking). As a register, you can specify any of the above - 24 general registers and eip.

Let's say the load command has successfully loaded a program for debugging. Immediately after loading, the program is suspended and does not run.
Pressing Ctrl + F7 (similar to the command line - the "s" command) takes one step in the loaded program, after which control returns to the debugger, which shows the new contents of registers and memory. The int 40h system call (as well as the sysenter and syscall instructions) counts as one step.
Pressing Ctrl + F8 (similar to the command line - the "p" command) also takes a step in the loaded program, but procedure calls, line operations with the rep / repz / repnz prefix, and loops are performed as one step.
Stepping instructions are used, as a rule, in separate sections of the program, when it is necessary, for example, to regularly monitor the values ​​of registers and / or some variables in memory.
The g <expression> command resumes the execution of the program and waits until control reaches eip = the corresponding address, and at this moment suspends the program. The "g" command with no arguments simply resumes program execution.

You can pause the program execution with the "stop" command (without arguments).

Usually it is required for the program to run normally, but when certain conditions are met, the program is suspended and the debugger takes control. The corresponding conditions are called breakpoints, breakpoint (s), in common parlance - breakpoints. The simplest type of breakpoints is to a specific address, i.e. abort execution on eip = <specified value>. These breakpoints are set with the bp <expression> command.

Comment. If there is only one such breakpoint, it is more convenient to use the "g" command with an argument instead.

Another type of breakpoints is by accessing a given area of ​​memory. There can be no more than four such breakpoints (since the hardware capabilities of x86 processors are used, where only 4 such breakpoints are allowed).
bpm <expression> - bryak to any access to the byte at the specified address
bpm w <expression> - bryak to write a byte at the specified address
bpmb, bpmw, bpmd <expression> - bryak to access, respectively, byte, word and doubleword at the specified address. bpm and bpmb are synonyms. When using bpmw, the bpmd address must be word-aligned (i.e. even) or double-word aligned (i.e., divisible by 4), respectively.
bpmb, bpmw, bpmd w <expression> - similarly for write break.

The list of set breakpoints can be viewed with the "bl" command, information about a specific breakpoint can be obtained with "bl <number>". Unnecessary breakpoints are removed with the "bc <number>" command, temporarily unnecessary ones can be disabled with the "bd <number>" command, when they are needed again, use the "be <number>" command.

Remarks.

When debugging your own programs, you can insert int3 instructions into the code (note that there is no space!). Such an instruction throws an exception on normal startup, which will lead to the termination of the process, but when working under the debugger, the debugger is simply activated (with the message "int3 command at xxx"). This allows you not to think about which addresses to use in the g and / or bp commands. You can also generate a file with information about symbols and load it, then not only there is no need to independently calculate the addresses for "g" and "bp", but also "u", "d", "?" will understand the indication of the label / variable name.
All output and all input is hexadecimal.
When the program is running, the register and data windows show information pertaining to the point before the resume; setting of register values ​​in this mode is not possible. However, the "d" command in this mode shows the information that was correct at the time the command was issued.
Written by diamond. Translated by Alex2003