Running the program under GDB

After preparing the executable file that contains the debugging information and symbols, let's run GDB to read all the symbols from the file and debug it. Run the following command to start the debugging process:

gdb rangen_boost_gdb

Our output will be as follows:

C:CPP>gdb rangen_boost_gdb
GNU gdb (GDB) 7.8.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-w64-mingw32".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from rangen_boost_gdb...done.
(gdb)_

We got the same output as the previous GDB output, except for the last line before (gdb). This line tells us that GDB has successfully read all the debugging symbols and is ready to initiate the debugging process. In this step, we can also specify the arguments, if our program needs any. Since our program does not need to specify any argument, we can ignore it for now.

Starting the debugging process

To start the debugging process, we can call either the run or start command. The former will start our program under GDB, while the latter will behave similarly but will execute the code line-by-line. The difference is that if we have not yet set the breakpoint, the program will run as usual if we call the run command, whereas the debugger will automatically set the breakpoint in the main block of code, stopping the program if it reaches that point, if we start with the start command.

For now, let's use the start command for the debugging process. Just type start in the GDB prompt, and the console will append the following output:

(gdb) start
Temporary breakpoint 1 at 0x401506: file rangen_boost.cpp, line 10.
Starting program: C:CPP
angen_boost_gdb.exe
[New Thread 10856.0x213c]

Temporary breakpoint 1, main () at rangen_boost.cpp:10
10              std::cout << "Select number among 0 to 10: ";

The debugging process is started. From the output, we can find that one breakpoint is created automatically inside the main block which is in line 10. When there is no breakpoint, the debugger will choose the first statement inside the main block. That is why we get line 10 as our automatic breakpoint.

The continuing and stepping debugging process

After we successfully start our program under GDB, the next step is to continue and step. We can use one of the following commands to continue and step the debugging process:

  • continue: This command will resume the execution of the program until our program completes normally. If it finds a breakpoint, the execution will stop at the line where the breakpoint is set.
  • step: This command will execute just one more step of our program. The step might mean either one line of source code or one machine instruction. If it finds the invocation of function, it will come into the function and run one more step inside the function.
  • next: This command behaves similar to the step command, but it only continues to the next line in the current stack frame. In other words, if the next command finds the invocation of a function, it will not come into the function.

For now, let's use the next command. Type the next command in the GDB prompt just after we call the start command. We should get the following output:

(gdb) next
Select number among 0 to 10: 11         std::cin >> guessNumber;

The GDB executes the 10th line and then continues to the 11th line. We will call the next command again to continue the debugging process. However, if we just press the Enter key, the GDB will execute our previous command. This is why we now just need to press the Enter key, which will give us a blinking cursor. Now, we have to input the number that we guessed to be stored in the guessNumber variable. I will input the number 4, but you may enter your favorite number. Press the Enter key again to continue debugging as many times as needed to exit the program normally. The following output will be appended:

(gdb)
4
12              if(guessNumber < 0 || guessNumber > 10)
(gdb)
17              boost::random::mt19937 rng;
(gdb)
19              boost::random::uniform_int_distribution<> ten(0,10);
(gdb)
20              int randomNumber = ten(rng);
(gdb)
22              if(guessNumber == randomNumber)
(gdb)
28                      std::cout << "Sorry, I'm thinking about number " << randomNumber << "
";
(gdb)
Sorry, I'm thinking about number 8
30              return 0;
(gdb)
31      }(gdb)
0x00000000004013b5 in __tmainCRTStartup ()
(gdb)
Single stepping until exit from function __tmainCRTStartup, which has no line number information.
[Inferior 1 (process 11804) exited normally]

As we can see in the preceding output, after we enter the number guessed, the program executes the if statement to ensure that the number we entered is not out of range. If our guessing number is valid, the program continues to generate a random number. Our guessing number is then compared with a random number generated by our program. The program will give a different output irrespective of the two numbers being same or not. Unfortunately, my guessing number is different than the random number. You might obtain a different output if you are able to guess the number correctly.

Printing the source code

Sometimes, we may want to examine our source file while we run the debugging process. Since the debugging information and symbol are recorded in our program, GDB can print the source code even if it is an executable file. To print the source code, we can type list (or the l command for the shortcut) in the GDB prompt. By default, GDB will print ten lines at every invocation of the command. However, we can change this setting using the set listsize command. Also, to know the number of lines that will be displayed by the list command, we can invoke the show listsize command. Let's see the following command line output:

(gdb) show listsize
Number of source lines gdb will list by default is 10.
(gdb) set listsize 20
(gdb) show listsize
Number of source lines gdb will list by default is 20.
(gdb)_

We increase the number of lines to be displayed using the list command. Now, every time the list command is invoked, the output will display twenty lines of source code.

The following are several forms of the list command, which are the most common:

  • list: This command will show the source code for as many lines as the list size defines. If we call it again, it will display the remaining lines as many as the list size defines.
  • list [linenumber]: This command will display the lines centered on linenumber. The command list 10 will display line 5 to line 14 since line 10 is at the center.
  • list [functionname]: This command will display lines centered on the beginning of the functionname variable. The command list main will display the int main(void) function at the center of list.
  • list [first,last]: This command will display lines from first to last. The command list 15,16 will display line 15 and line 16 only.
  • list [,last]: This command will display lines ending with the last. The command list ,5 will display line 1 to line 5.
  • list [first,]: This command will display all the lines starting with the specified line as the first. The command list 5, will display line 5 to the rest of line if the number of the lines is more than the specified line number. Otherwise, it will display as many lines as the list size setting.
  • list +: This command will display all the lines following the lines last displayed.
  • list -: This command will display all the lines preceding the lines last displayed.

Setting and deleting the breakpoint

If we suspect that a line makes an error, we can set a breakpoint in that line so that the debugger stops the debugging process at that line. To set a breakpoint, we can call the break [linenumber] command. Consider that we want to stop at line 20, which contains the following code:

int randomNumber = ten(rng);

Here, we will have to call the break 20 command just after we load our program under GDB to set a breakpoint at line 20. The following output console illustrates this:

(gdb) break 20
Breakpoint 1 at 0x401574: file rangen_boost.cpp, line 20.
(gdb) run
Starting program: C:CPP
angen_boost_gdb.exe
[New Thread 1428.0x13f4]
Select number among 0 to 10: 2

Breakpoint 1, main () at rangen_boost.cpp:20
20              int randomNumber = ten(rng);
(gdb) next
22              if(guessNumber == randomNumber)
(gdb)
28                      std::cout << "Sorry, I'm thinking about number " << randomNumber << "
";
(gdb)
Sorry, I'm thinking about number 8
30              return 0;
(gdb)
31      }(gdb)
0x00000000004013b5 in __tmainCRTStartup ()
(gdb)
Single stepping until exit from function __tmainCRTStartup,
which has no line number information.
[Inferior 1 (process 1428) exited normally]
(gdb)_

In the preceding output console, just after our program is loaded under GDB, we call the break 20 command. The debugger then sets a new breakpoint at line 20. Instead of calling the start command as we previously did, we call the run command to execute the program and let it stop when it finds a breakpoint. After we enter our guessing number, 2 for example, the debugger stops at line 20, the line at which we expected it to stop. Then, we call the next command to continue the debugger and press the Enter key several times until the program exits.

If we want to delete a breakpoint, simply use the delete N command, in which N is the order in which all the breakpoints are set. If we do not memorize all the locations of the breakpoints that we set, we can call the info break command to get a list of all breakpoints. We can also use the delete command (without N), which will delete all breakpoints.

Printing a variable value

We were already able to stop at our desired line. We can also discover the value of the variable that we use in our program. We can call the print [variablename] command to print the value of any variable. Using the previous breakpoint, we will print the value of the variable randomNumber. Just after the debugger hits the breakpoint in line 20, we will call the print randomNumber command. Then, we call the next command and print the randomNumber variable again. Look at the following illustration of the command invocation:

(gdb) break 20
Breakpoint 1 at 0x401574: file rangen_boost.cpp, line 20.
(gdb) run
Starting program: C:CPP
angen_boost_gdb.exe
[New Thread 5436.0x1b04]
Select number among 0 to 10: 3

Breakpoint 1, main () at rangen_boost.cpp:20
20              int randomNumber = ten(rng);
(gdb) print randomNumber
$1 = 0
(gdb) next
22              if(guessNumber == randomNumber)
(gdb) print randomNumber
$2 = 8
(gdb)_

As we can see in the preceding output, the following line is where the breakpoint is set:

int randomNumber = ten(rng);

Before the line is executed, we peek the value of randomNumber variable. The value of the variable is 0. Then, we call the next command to instruct debugger to execute the line. After that, we peek at the value of the variable again, and this time it is 8. Of course, in this experiment, you might get the different value rather than 8.

Modifying a variable value

We will cheat our program by modifying the value of one of the variables. The value of a variable can be reassigned using the set var [variablename]=[newvalue] command. To ensure the type of the variable that we want to modify, we can call the whatis [variablename] command to get the required type of variable.

Now, let's change the value of the randomNumber variable after the program assigns a random number to the variable. We will restart the debugging process, delete all the breakpoints we set already, set a new breakpoint at line 22, and continue the debugging process by typing the continue command until the debugger hits the breakpoint in line 22. On this condition, we can reassign the value of the randomNumber variable to be exactly the same as the value of the guessNumber variable. Now, call the continue command again. After this, we will be congratulated for guessing the correct number.

For more details, let's take a look at the following output console, which will illustrate the preceding step:

(gdb) start
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Temporary breakpoint 2 at 0x401506: file rangen_boost.cpp, line 10.
Starting program: C:CPP
angen_boost_gdb.exe
[New Thread 6392.0x1030]

Temporary breakpoint 2, main () at rangen_boost.cpp:10
10              std::cout << "Select number among 0 to 10: ";
(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000401574 in main()
                                                   at rangen_boost.cpp:20
(gdb) delete 1
(gdb) info break
No breakpoints or watchpoints.
(gdb) break 22
Breakpoint 3 at 0x40158d: file rangen_boost.cpp, line 22.
(gdb) continue
Continuing.
Select number among 0 to 10: 5

Breakpoint 3, main () at rangen_boost.cpp:22
22              if(guessNumber == randomNumber)
(gdb) whatis randomNumber
type = int
(gdb) print randomNumber
$3 = 8
(gdb) set var randomNumber=5
(gdb) print randomNumber
$4 = 5
(gdb) continue
Continuing.
Congratulation, 5 is your lucky number.
[Inferior 1 (process 6392) exited normally]
(gdb)_

As we can see in the preceding output, when we call the start command, the debugger asks us to stop the previous debugging process since it is still running. Just type the Y key and press the Enter key to answer the query. We can list all the available breakpoints using the info break command and then delete the desired breakpoint based on the order we get from the info break command. We call the continue command to resume the debugging process, and when the debugger hits the breakpoint, we reassign the randomNumber variable with the value of the guessNumber variable. We continue the debugging process and successfully modify the value of the randomNumber variable at runtime since we are congratulated by the program.

If we have many variables in the program, instead of printing all of the variables one-by-one, we can print the values of all the variables using the info locals command.

Calling the command prompt

I occasionally call the Windows shell command inside the GDB prompt, such as the cls command to clear the screen, the dir command to list the content of the active directory, and even the compiling command. If you also want to execute the Windows shell command, the GDB command that you can use is shell [Windows shell command]. It actually just adds the shell command before the Windows shell command and argument when needed. Let's see the following console output to understand executing the Windows shell command inside the GDB prompt. Let's take a look at the following output:

C:CPP>gdb
GNU gdb (GDB) 7.8.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-w64-mingw32".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) shell dir rangen_boost* /w
 Volume in drive C is SYSTEM
 Volume Serial Number is 8EA6-1DBE

 Directory of C:CPP

rangen_boost.cpp       rangen_boost.exe       rangen_boost_gdb.exe
               3 File(s)        190,379 bytes
               0 Dir(s)  141,683,314,688 bytes free
(gdb) shell g++ -Wall -ansi -I ../boost_1_58_0 rangen_boost.cpp -o rangen_boost_gdb_2 -g
(gdb) shell dir rangen_boost* /w
 Volume in drive C is SYSTEM
 Volume Serial Number is 8EA6-1DBE

 Directory of C:CPP

rangen_boost.cpp         rangen_boost.exe         rangen_boost_gdb.exe
rangen_boost_gdb_2.exe
               4 File(s)        259,866 bytes
               0 Dir(s)  141,683,249,152 bytes free

In the preceding console output, we invoke the dir command to list all files that begin with the rangen_boost name within the active directory. Then, we invoke the compiling command to produce the rangen_boost_gdb_2.exe executable file in the active directory. Then, we call the dir command again to ensure that the rangen_boost_gdb_2.exe executable file has been successfully created.

Tip

You can use the apropos shell command to get more information about shell command in GDB.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset