Basics of using the WinDbg debugger. GDB: closer to the body Resuming execution, step-by-step debugging

G.D.B. refers to “smart” debugger programs, that is, those that “understand” the code and are able to execute it line by line, change the values ​​of variables, set breakpoints and stopping conditions... In a word, do everything so that the developer can check the correct operation of his program .

G.D.B. built into many UNIX-like systems and can debug several programming languages. Xi is among them.

To call G.D.B. enter the command in the terminal

Gdb [name of the program you want to debug]

To exit from G.D.B.: enter the command

Quit or C–d

Other important GDB commands

run [arguments command line programs] Run the program for execution. break [line number/function name] Set a program breakpoint at a specific line or function. next Go to next line without going inside the functions.

step Go to next line.

If there is a function call on the line, go inside it.

list Print a fragment of program code (several lines around

that place

, where the point is currently set) print [ variable] Display the value of the variable on the screen.

info locals Print the current values ​​of all local variables inside a loop, function, etc.

display [variable] Display the value of a variable at each debugging step.

help Show a list of all GDB commands.

Let's look at how to work with GDB using the caesar.c program, which you most likely wrote last week. We will test it on our own version, so your results may differ slightly depending on the implementation.

So, go to the pset2 folder (we think you already remember how to do this) in the “cs50 Virtual Laboratory” or CS50 IDE. Enter the command:

Gdb. /caesar

The caesar program has one function, main. Let's set the program's breakpoint at the main function:

The first time next is called, the key variable is set to "0". Why is this so if we entered the number 3? The point is that the command has not yet been executed. When you enter next a few more times, the program prompts you to enter text.

By executing the next command again, we will go inside the loop with a condition.

Today you will take another step in business
studying Linux systems. I'll tell you about the main ones
techniques for working with gdb. Having mastered them, you will be able to understand how any program works and write your own exploits.

You've probably all heard about such a thing as a debugger; gdb is a debugger. GDB-GNU
Debugger. This is a kind of SoftICE for Windows (for those who don’t know, it’s the most popular and, in my opinion, generally the best debugger), only under
Linux systems. The fact is that there are not many documents on the network that demonstrate the operation of this thing, and at one time I mastered it myself. So,
The document will describe the basic gdb commands. All this will be shown with an example. And as an example, I decided to take the unnecessary program yes. For those who don’t know, this program simply prints the ‘y’ character ad infinitum. To begin with, I decided to teach it to print not this character, but the string ‘XAKEP’, at least it will be more fun.

Well, now everything is in order. The debugger itself starts like this:

But you can enter various parameters, for us this will be the path to the program under study:

# gdb /usr/bin/yes

You can examine core files, to do this you need to enter the following:

# gdb /usr/bin/yes core

You may also need a command to view the contents of the registers:

(gdb) info registers

or like this (short version)

Now let's look at how to make interceptions. Exist
breakpoints, interception points and watchpoints. More specifically, I'd like to talk about breakpoints. They can be installed on:

(gdb) break function - Stop before entering a function
(gdb) break *adress - Stop before executing the address instruction.

After the settings, you can view all the points, use the command:

(gdb) info break

And then you can delete these points:

(gdb) clear breakpoint - where break is the name of the breakpoint
(e.g. function or address)

A very necessary thing is the ability to automatically display different values ​​while executing a program. There is a display command for this:

(gdb) display/format value , where format is the display format, and value is the expression itself that needs to be displayed.

The following commands are provided to work with the display:

(gdb) info display - displays information about displays
(gdb) delete num - where num – delete elements with index
num

This was a short reference to the commands to get the basic idea.
Next, I would like to demonstrate this and a little more with an example. And remember - here I have given only a very small part of all the capabilities of gdb, in fact it has hundreds of times more, so read and learn.
As I promised, we take the unnecessary yes program. The path on your machine may not coincide with mine, it all depends on the operating system you are using, if anything, use the search (command
find).

# gdb /usr/bin/yes

Once launched it says a welcome message.

GNU gdb 19991004




There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux"...
(no debugging symbols found)...

Since yes outputs an infinite number of symbols, it would be better for us not to see them in the debugger, but the output
programs can be directed to another console. Open a new terminal, type who is i and you will get the console name. Should come out
something like that:

Now we just tie it to it.

(gdb) tty /dev/pts/1

Now we set a breakpoint on the puts() function, and to make it clearer, here is a man help about the function (man command
puts)

#include
int puts(const char *s);
puts() writes the string s and a trailing newline to std
out.

As you can see, the function sends the string s to the output stream. That's what we need. We'll stop there for now.

(gdb) break puts
Breakpoint 1 at 0x8048698

And we launch the program itself to wait until gdb stops its execution at the function call.

(gdb)r
Starting program: /usr/bin/yes
Breakpoint 1 at 0x4006d585: file ioputs.c, line 32.

Breakpoint 1, 0x4006d585 in _IO_puts (str=0x8048e59 "y") at ioputs.c:32
32 ioputs.c: No such file or directory.
1: x/i $eip 0x4006d585<_IO_puts+21>: mov 0x8(%ebp),%esi

Oh, a miracle happened, the breakpoint worked. What we see - and we see nothing more than a function parameter, or rather the address at which it lies. What do you need now?
do? That's right, correct the data at this address. At the same time, we will overwrite a couple more symbols with our own.

(gdb) set (char)0x8048e59="X"
(gdb) set (char)0x8048e5a="A"
(gdb) set (char)0x8048e5b="K"
(gdb) set (char)0x8048e5c="E"
(gdb) set (char)0x8048e5d="P"

Well, now let's look at our creation. What lies in memory:

(gdb) x/3sw 0x8048e59
0x8048e59<_IO_stdin_used+437>: "XAKEP\004\b"
0x8048e61<_IO_stdin_used+445>: ""
0x8048e62<_IO_stdin_used+446>: ""

Now let's remove our breakpoint:

(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x4006d585 in _IO_puts at ioputs.c:32
breakpoint already hit 1 time
(gdb) clear puts
Deleted breakpoint 1

And let’s continue execution to enjoy the result:

That's all. Let's go out.

(gdb)q
The program is running. Exit anyway? (y or n)y

This is where the practice ends, study the rest yourself and remember that the main thing in this life is LEARNING.
Here are some more examples of work:

Attaching to a running process:

//launch gdb
hack@exploit:~ > gdb
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details.
This GDB was configured as "i386-suse-linux".
(gdb) attach "pid"
(gdb) 1127 // attach example

Search in memory:

(gdb) x/d or x "address" show decimal
(gdb) x/100s "address" show next 100 decimals
(gdb) x 0x0804846c show decimal at 0x0804846c
(gdb) x/s "address" show strings at address
(gdb) x/105 0x0804846c show 105 strings at 0x0804846c
(gdb) x/x "address" show hexadecimal address
(gdb) x/10x 0x0804846c show 10 addresses at 0x0804846c
(gdb) x/b 0x0804846c show byte at 0x0804846c
(gdb) x/10b 0x0804846c-10 show byte at 0x0804846c-10
(gdb) x/10b 0x0804846c+20 show byte at 0x0804846c+20
(gdb) x/20i 0x0804846c show 20 assembler instructions at address

List of all sections in the executable file:

(gdb) maintenance info sections // or
(gdb) mai i s

Executable file:
`/home/hack/homepage/challenge/buf/basic", file type
elf32-i386.
0x080480f4->0x08048107 at 0x000000f4: .interp ALLOC

0x08048108->0x08048128 at 0x00000108: .note.ABI-tag
ALLOC LOAD READONLY DATA HAS_CONTENTS
0x08048128->0x08048158 at 0x00000128: .hash ALLOC
LOAD READONLY DATA HAS_CONTENTS
0x08048158->0x080481c8 at 0x00000158: .dynsym ALLOC
LOAD READONLY DATA HAS_CONTENTS
0x080481c8->0x08048242 at 0x000001c8: .dynstr ALLOC
LOAD READONLY DATA HAS_CONTENTS
0x08048242->0x08048250 at 0x00000242: .gnu.version
ALLOC LOAD READONLY DATA
HAS_CONTENTS

Breaking point to the address:

(gdb) disassemble main
Dump of assembler code for function main:
0x8048400

: push %ebp
0x8048401 : mov %esp,%ebp
0x8048403 : sub $0x408,%esp
0x8048409 : add $0xfffffff8,%esp
0x804840c : mov 0xc(%ebp),%eax
0x804840f : add $0x4,%eax
0x8048412 : mov (%eax),%edx
0x8048414 : push %edx
0x8048415 : lea 0xfffffc00(%ebp),%eax
...

(gdb) break *0x8048414 // example
Breakpoint 1 at 0x8048414
(gdb) break main // example
Breakpoint 2 at 0x8048409
(gdb)

The purpose of debugging a program is to eliminate errors in its code. To do this, you will most likely have to examine the state of the variables in lead time, as well as the execution process itself (for example, tracking conditional jumps). Here the debugger is our first assistant. Of course, C has quite a lot of debugging options without directly stopping the program: from simple printf(3) to special systems network logging and syslog. In assembler, such methods are also applicable, but you may need to monitor the state of the registers, image ( dump ) random access memory and other things that are much more convenient to do in an interactive debugger. In general, if you write in assembly language, then you are unlikely to do without a debugger.

You can start debugging by identifying a breakpoint if you already know approximately what part of the code you need to examine. This method is used most often: we set a breakpoint, run the program and go through its execution step by step, simultaneously observing the necessary variables and registers. You can also simply run the program under a debugger and catch the moment when it crashes due to a segmentation fault - this way you can find out which instruction is trying to access memory, take a closer look at the variable causing the error, and so on. Now you can examine this code again, go through it step by step, setting a breakpoint a little before the moment of failure.

Let's start with something simple. Let's take the Hello world program and compile it with debugging information using the -g compiler switch:

$ gcc -g hello.s -o hello $

Launch gdb:

$ gdb ./hello GNU gdb 6.4.90-debian Copyright (C) 2006 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i486-linux-gnu"...Using host libthread_db library "/lib/tls/libthread_db.so.1". (gdb)

GDB has started, loaded the program under study, displayed a prompt (gdb) and is waiting for commands. We want to go through the program "step by step" (single-step mode). To do this, you need to specify the command at which the program should stop. You can specify a subroutine - then the stop will be carried out before the execution of the instructions of this subroutine begins. You can also specify the file name and line number.

(gdb) b main Breakpoint 1 at 0x8048324: file hello.s, line 17. (gdb)

b is short for break. All commands in GDB can be abbreviated as long as this does not create ambiguity. We launch the program with the run command. The same command is used to restart a previously running program.

(gdb) r Starting program: /tmp/hello Breakpoint 1, main () at hello.s:17 17 movl $4, %eax /* put system call number write = 4 Current language: auto; currently asm (gdb)

GDB has stopped the program and is waiting for commands. You see the command in your program that will be executed next, the name of the function that is currently executing, the file name, and the line number. For step-by-step execution, we have two commands: step (abbreviated s) and next (abbreviated n). The step command executes the program by entering the bodies of subroutines. The next command steps only the instructions of the current subroutine.

(gdb) n 20 movl $1, %ebx /* first parameter goes to register %ebx */ (gdb)

So, the instruction on line 17 is executed, and we expect the number 4 to be in the %eax register. To print various expressions on the screen, we use the print command (abbreviated p ). Unlike assembler commands, GDB uses the $ sign instead of % when writing registers. Let's see what's in the %eax register:

(gdb) p $eax $1 = 4 (gdb)

Indeed 4! GDB numbers all output expressions. Now we see the first expression ($1), which is equal to 4. Now this expression can be accessed by name. You can also make simple calculations:

(gdb) p $1 $2 = 4 (gdb) p $1 + 10 $3 = 14 (gdb) p 0x10 + 0x1f $4 = 47 (gdb)

While we were playing with the print command, we had already forgotten which instruction was executed next. The info line command displays information about the specified line of code. Without arguments, prints information about the current line.

(gdb) info line Line 20 of "hello.s" starts at address 0x8048329 and ends at 0x804832e . (gdb)

The list command (abbreviated l ) displays the source code of your program. You can pass it as arguments:

  • line_number- line number in the current file;
  • file:line_number- line number in specified file;
  • function_name- function name, if there is no ambiguity;
  • file:function_name- name of the function in the specified file;
  • *address- the address in memory where the required instruction is located.

If you pass one argument, the list command will output 10 lines source code around this place. By passing two arguments, you specify the start line and the end line of the listing.

(gdb) l main 12 outside of this file */ 13 .type main, @function /* main - function (not data) */ 14 15 16 main: 17 movl $4, %eax /* put system call number 18 write = 4 in register %eax */ 19 20 movl $1, %ebx /* place the first parameter in register 21 %ebx; file descriptor number 22 stdout = 1 */ (gdb) l *$eip 0x8048329 is at hello.s:20. 15 16 main: 17 movl $4, %eax /* place the system call number 18 write = 4 in the register %eax */ 19 20 movl $1, %ebx /* place the first parameter in register 21 %ebx; file descriptor number 22 stdout = 1 */ 23 movl $hello_str, %ecx /* place the second parameter in register 24 %ecx; pointer to a string */ (gdb) l 20, 25 20 movl $1, %ebx /* place the first parameter in register 21 %ebx; file descriptor number 22 stdout = 1 */ 23 movl $hello_str, %ecx /* place the second parameter in register 24 %ecx; pointer to string */ 25 (gdb)

Remember this command: list *$eip . With its help, you can always view the source code around the instruction currently being executed. Let's run our program further:

(gdb) n 23 movl $hello_str, %ecx /* place the second parameter in the %ecx register (gdb) n 26 movl $hello_str_length, %edx /* place the third parameter in the %edx register (gdb)

Isn't it tedious to press n every time? If you just press Enter, GDB will repeat the last command:

(gdb) 29 int $0x80 /* call interrupt 0x80 */ (gdb) Hello, world! 31 movl $1, %eax /* system call number exit = 1 */ (gdb)

Another handy command worth knowing about is info registers. Of course, it can be shortened to i r . You can pass it a parameter - a list of registers that need to be printed. For example, when execution occurs in protected mode, we are unlikely to be interested in the values ​​of segment registers.

(gdb) info registers eax 0xe 14 ecx 0x804955c 134518108 edx 0xe 14 ebx 0x1 1 esp 0xbfabb55c 0xbfabb55c ebp 0xbfabb5a8 0xbfabb5a8 esi 0x0 0 edi 0xb7f6bcc0 - 1208566592 eip 0x804833a 0x804833a eflags 0x246 [ PF ZF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51 (gdb) info registers eax ecx edx ebx esp ebp esi edi eip eflags eax 0xe 14 ecx 0x804955c 134518108 edx 0xe 14 ebx 0x1 1 esp 0xbfabb55c 0xbfabb55c ebp 0xbfabb5a8 0xbfabb5a8 esi 0x0 0 edi 0xb7f6bcc0 -1208566592 eip 0x804833a 0x804833a eflags 0x246 [PF ZF IF] (gdb)

So, in addition to registers, we also have

GNU Debugger is a portable debugger for the GNU project that runs on many UNIX-like systems and can debug many programming languages, including C, C++, Ada and Fortran. GNU Debugger - free software, distributed under the GNU General Public License.

GNU Debugger was originally written by Richard Stallman in 1988. The DBX debugger, supplied with the BSD distribution, was used as a basis. From 1990 to 1993 The project was supported by John Gilmore during his time at Cygnus Solutions. Development is currently being coordinated by the GDB Steering Committee appointed by the Free Software Foundation.

Technical details of GNU Debugger

  • Peculiarities

GNU Debugger offers extensive tools for monitoring and controlling execution computer programs. The user can change internal program variables and even call functions independently of the program's normal behavior. GNU Debugger can debug executable files in a.out, COFF format (including executable Windows files), ECOFF, XCOFF, ELF, SOM, use debug information in stabs, COFF, ECOFF, DWARF, DWARF2 formats. The DWARF2 format provides the greatest debugging capabilities.

GNU Debugger is actively developed. For example, version 7.0 added support for “reversible debugging,” which allows you to rewind the execution process to see what happened. Also in version 7.0, support for scripting in .

Other debugging tools have been created to work with GNU Debugger, such as memory leak detectors.

  • Multiplatform and embedded system support

GNU Debugger can be compiled to support applications for multiple target platforms and switch between them during a debugging session. Processors supported by GNU Debugger (2003): Alpha, ARM, H8/300, System/370, System/390, x86 and x86-64, IA-64 (Itanium), Motorola 68000, MIPS, PA-RISC, PowerPC, SuperH , SPARC, VAX, A29K, ARC, AVR, CRIS, D10V, D30V, FR-30, FR-V, Intel i960, M32R, 68HC11, Motorola 88000, MCORE, MN10200, MN10300, NS32K, Stormy16, V850 and Z8000. (Newer releases will probably not support some of them.) Target platforms on which GNU Debugger cannot run, particularly embedded systems, can be supported using the built-in simulator (ARM, AVR processors), or applications for them can be compiled with special routines that provide remote debugging under GNU Debugger running on the developer's computer. The input file for debugging is usually not a binary file being flashed, but a file in one of the formats that supports debugging information, primarily ELF, from which subsequently using special utilities is extracted binary code for firmware.

  • Remote debugging

In remote debugging, GNU Debugger runs on one machine and the program being debugged runs on another. Communication is carried out using a special protocol via a serial port or TCP/IP. The protocol for interacting with the debugger is specific to GNU Debugger, but the source code for the necessary routines is included in the debugger archive. Alternatively, the target platform can run the GNU Debugger gdbserver program, which uses the same protocol, and performs low-level functions such as setting breakpoints and accessing registers and memory.

The same mode is used to interact with the built-in Linux kernel debugger KGDB. With its help, a developer can debug the kernel like a regular program: set breakpoints, step through code, and view variables. The built-in debugger requires two machines connected via Ethernet or serial cable, one running GNU Debugger and the other running the kernel being debugged.

  • User interface

In accordance with the ideology of the leading developers of the Free Software Foundation, GNU Debugger, instead of its own graphical user interface provides the ability to connect to external IDEs that control graphical shells or use a standard console text interface. To interface with external programs, you can use a text string language (as was done in the first versions of the DDD shell), the gdb/mi text control language, or an interface for the .

Interfaces such as DDD, cgdb, GDBtk/Insight and “GUD mode” were created in . IDEs that can interact with GNU Debugger include:

Errors, unfortunately, occur in any program, no matter how professional its developer may be. Therefore, whether you like it or not, you will still have to use the debugger. Life will force you. And the more time you spend now learning how to use it, the more time it will save you in the future.

We'll look at the GDB debugger that comes with the GNU software package.

In order to use it, you must first compile the program so that its binary file contains debugging information. This information includes, in particular, a description of the correspondence between the addresses of the executable code and the lines in the source code.

This compilation is achieved by adding the -g flag to the compile command. For example, if we were building the kalkul program without using a Makefile, we would issue the following command:

g++ main.cpp problem.cpp -o kalkul -g

If we use the make command, then we need to set the CFLAGS=-g option. Then all compilation commands contained in the Make file will automatically receive the -g flag.

Let's take the program we created from the files main.cpp, problem.cpp and problem.h (we called this project directory kalkulcpp back then). Our Makefile has already been created. Let's use it.

Let's clear the package from the results of the previous build.

Let's build the program again, but with debugging information included.

Let's launch the GDB debugger by loading our debugging program into it. (If you remember, our executable program was located in the src directory.)

gdb ./src/kalkul

To run a program inside the debugger, use the run command.

To view the source code, use the list command.

If you give this command without parameters, then it is the first nine lines of the source code of the main file (that is, the one that contains the main function). To view the file further, you need to type list again. To view specific lines, you need to specify two parameters: which line to start viewing from, and which line to end from.

To view other project files, you need to specify the name before the line numbers the desired file and separate it from the line numbers with a colon.

list problem.cpp:20,29

Let's put a breakpoint on line number 21. A breakpoint is a mark indicating that the program should stop when it reaches this point.

list problem.cpp:20,27

You can see where you have set breakpoints using the info breakpoints command.

info breakpoints

(If you wish, you can specify the name of the function instead of the line number, then the program will stop before entering the function.)

Let's launch the program.

Let's enter the first number 5 and the mathematical operation sign “+”. The program will reach a breakpoint and stop, displaying the line where this breakpoint is located.

We are, of course, interested in knowing exactly where we stopped and what the program has already managed to accomplish. We issue the backtrace command.

The debugger gives us the following information:

#0 CProblem::Calculate (this=0x804b008) at problem.cpp:21

#1 0x08048e00 in CProblem::Solve (this=0x804b008) at problem.cpp:93

#2 0x08048efc in main () at main.cpp:15

This means that we are inside a running Calculate function, which is a member function of the CProblem class. It was called from the Solve function of the same class, and that, in turn, from the main function. Thus, the backtrace command shows the entire stack of called functions from the beginning of the program to the current location.

Let's see what the value of the Numeral variable is at this stage.

And we are immediately given the number 5, which we entered into the program. (The value we entered from the keyboard was assigned to this particular variable.)

If we use the display command instead of print, the value of this variable will be shown every time the program stops, without special instructions.

Let's add another breakpoint on line 25 of the problem.cpp file.

break problem.cpp:25

Let's continue executing the program.

The Continue command continues program execution from the current address. If we typed run, the program would start from the beginning. Since line 24 contains the command cin >> SecondNumeral, we will have to enter the second term. Let's enter, for example, the number 2. After this, the program will stop again at line 25 (our second breakpoint).

Let's see what the values ​​of our Numeral, SecondNumeral and Operation variables are. If you remember, these are the variables we declared in the CProblem class.

print SecondNumeral

We get 5, “+”, 2. That’s how it should be. But let’s now “change our minds” and better assign the SecondNumeral variable the value 4. The GDB debugger allows you to change the value of any variable directly during program execution.

set SecondNumeral=4

If we don’t believe that its value has changed, we can check it.

print SecondNumeral

Now we expect the result to be 9. Let's run the program to completion.

The result is really 9.

Let's now remove our breakpoints. We seem to have created two such points. But this can be checked.

info breakpoints

Let's delete them.

There shouldn't be a single breakpoint left for us. Let's check.

info breakpoints

There really isn't one left.

Now let's go through the entire program step by step (fortunately, it's small).

Let's set a breakpoint on the tenth line of the main file.

break main.cpp:10

Let's launch the program

Having reached the tenth line, she will stop. Now we go through it, stopping at each line, using the step command.

So as not to type every times s-t-e-p, you can simply enter the letter s. As soon as the program reaches the Problem->SetValues() command, it immediately goes to the problem.cpp file, where the definition of the member function CProblem::SetValues() is located and passes the code of this function. The same thing happens when it gets to the Problem->Solve() call.

So that when calling a function, the program does not enter it, but continues to be executed only at the current stack level, instead of step, the command next or simply n is given.

In this way, you can view how the entire program or any section of the program is executed. At any step you can check the value of any variable. To stop going through the program step by step and run it to the end, you need to give the continue command.

Let's give a short list of the most common GDB debugger commands. For more detailed information you, of course, can always refer to the built-in description of the program (info gdb) or the user manual (man gdb).

backtrace- displays the entire path to the current breakpoint, that is, the names of all functions, starting from main(); in other words, displays the entire stack of functions;

break- sets a breakpoint; the parameter can be a line number or a function name;

clear- removes all breakpoints at the current stack level (that is, in the current function);

continue- continues program execution from the current point to the end;

delete- removes a breakpoint or control expression;

display- adds an expression to the list of expressions, the values ​​of which are displayed every time the program is stopped;

finish- executes the program until exiting the current function; displays the return value, if any;

info breakpoints- displays a list of all available breakpoints;

info watchpoints- displays a list of all available control expressions;

list- displays the source code; the name of the source code file is passed as a parameter, then, separated by a colon, the number of the starting and ending lines;

next- step-by-step execution of the program, but, unlike the step command, does not execute step-by-step functions;

print- displays the value of an expression (the expression is passed as a parameter);

run- launches the program for execution;

set- sets a new value for a variable

step- step-by-step execution of the program;

watch- sets a control expression, the program will stop as soon as the value of the control expression changes;

Dmitry Panteleichev (dimanix2006 at rambler dot ru) - Introduction to the gdb debugger