Book Image

C++ System Programming Cookbook

By : Onorato Vaticone
Book Image

C++ System Programming Cookbook

By: Onorato Vaticone

Overview of this book

C++ is the preferred language for system programming due to its efficient low-level computation, data abstraction, and object-oriented features. System programming is about designing and writing computer programs that interact closely with the underlying operating system and allow computer hardware to interface with the programmer and the user. The C++ System Programming Cookbook will serve as a reference for developers who want to have ready-to-use solutions for the essential aspects of system programming using the latest C++ standards wherever possible. This C++ book starts out by giving you an overview of system programming and refreshing your C++ knowledge. Moving ahead, you will learn how to deal with threads and processes, before going on to discover recipes for how to manage memory. The concluding chapters will then help you understand how processes communicate and how to interact with the console (console I/O). Finally, you will learn how to deal with time interfaces, signals, and CPU scheduling. By the end of the book, you will become adept at developing robust systems applications using C++.
Table of Contents (13 chapters)

Using GDB to debug a program

Debugging is the process of identifying and removing errors from software systems. The GNU/Linux operating system has a standard de facto tool (that is, not part of any standard, but used by almost anybody in the Linux world) called GDB. The GDB version installed on this book's Docker is version 8.2.91. Of course, there are graphical tools that can use GDB under the hood, but GDB on Linux is the way to go for its reliability, simplicity, and speed. In this recipe, we will debug the software we've written in the previous recipe.

How to do it...

In order to use some of the GDB commands, we need to modify the previous program and add some variables in it:

  1. Open a shell and modify the hello.cpp file by typing in the following code:
 #include <iostream>
int main()
{
int x = 10;
x += 2;
std::cout << "Hello World! x = " << x << std::endl;
return 0;
}

This is a very simple program: take a variable, add 2 to it, and print the result.

  1. Let's make sure that the program is compiled by typing the following command:
root@bffd758254f8:~/Chapter1# make
g++ -c hello.cpp
g++ -o hello hello.o
  1. Now that we have the executable, we will debug it. From the command line, type gdb hello:
root@bffd758254f8:~/Chapter1# gdb hello
GNU gdb (Ubuntu 8.2.91.20190405-0ubuntu3) 8.2.91.20190405-git
Copyright (C) 2019 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-linux-gnu".
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 hello...
(No debugging symbols found in hello)
(gdb)
  1. As you can see, the last line says (No debugging symbols found in hello). GDB doesn't have to debug symbols to debug the program, so we have to communicate to the compiler that the debug symbols are to be included during the compilation. We have to quit the current session; to do this, type q (Enter]. Then, edit the makefile, and add the -g option to the g++ compiler section (the hello.o target):
CC = g++
all: hello
hello: hello.o
${CC} -o hello hello.o
hello.o: hello.cpp
$(CC) -c -g hello.cpp
clean:
rm hello.o hello
  1. Let's run it again, but, first, we have to rebuild the application with the make command:
root@bcec6ff72b3c:/BOOK/chapter1# gdb hello
GNU gdb (Ubuntu 8.2.91.20190405-0ubuntu3) 8.2.91.20190405-git
Copyright (C) 2019 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-linux-gnu".
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 hello...
(No debugging symbols found in hello)
(gdb)

We're ready to debug it. A debug session typically includes setting breakpoints, watching the content of variables, setting watchpoints, and many others. The next section will show the most common debug commands.

How it works...

In the previous section, we have seen the steps necessary to create a program and a makefile. In this section, we'll learn how to debug the Hello World! program we developed.

Let's start by visualizing the code we're going to debug. We do this by running the l command (short for list):

(gdb) l
1 #include <iostream>
2 int main()
3 {
4 int x = 10;
5 x += 2;
6 std::cout << "Hello World! x = " << x << std::endl;
7 return 0;
8 }

We have to set a breakpoint. To set a breakpoint, we run the b 5 command. This sets a breakpoint to the code line number 5 in the current module:

(gdb) b 5
Breakpoint 1 at 0x1169: file hello.cpp, line 5.
(gdb)

It's time to run the program now. To run a program, we type the r command. This runs the hello program we started with GDB:

(gdb) r
Starting program: /root/Chapter1/hello

Once started, GDB will automatically stop at any breakpoint hit by the process flow. In this case, the process runs, and then stops at line 5 of the hello.cpp file:

Breakpoint 1, main () at hello.cpp:5
5 x += 2;

To proceed step by step, we run the n command (that is, step over) on GDB. This executes the current visualized line of code. A similar command is s (step into). If the current command is a function, it steps into the function:

(gdb) n
6 std::cout << "Hello World! x = " << x << std::endl;
the 'n' command (short for next) execute one line. Now we may want to check the content of the variable x after the increment:

If we need to know the content of a variable, we run the p command (short for print), which prints the content of a variable. In this case, as expected, x = 12 gets printed:

(gdb) p x
$1 = 12

Now, let's run the program until the end (or until the next breakpoint, if set). This is done with the c command (short for continue):

(gdb) c 
Continuing.
Hello World! x = 12
[Inferior 1 (process 101) exited normally]
(gdb)

GDB really acts as an interpreter by letting the programmer step the program line by line. This helps the developer to troubleshoot problems, see the content of variables at runtime, change the status of variables, and more.

There's more...

GDB has a lot of very useful commands. In the following chapters, GDB will be explored more. There are four more commands to show here:

  1. s: Short for step. If called on a method, it steps into it.
  2. bt: Short for backtrace. Prints the call stack.
  3. q: Short for quit. Use to exit GDB.
  4. d: Short for delete. It removes a breakpoint. For example, d 1 removes the first breakpoint set.
The main page of the GNU GDB Project can be found here: https://www.gnu.org/software/gdbMore detailed information can be found on the man dbg man pages and online. You can also refer to Using GDB: A Guide to the GNU Source-Level Debugger, by Richard M. Stallman and Roland H. Pesch.