Debugging C++ Programs Using GDB in Command Line

Last year, I had a colleague who debugged C++ programs very impressively from the command line, which made me quite envious. I planned to write an article introducing how to use gdb for debugging in the command line, but I procrastinated for a long time. This time, I can’t delay any longer.

Installing GCC and GDB on Ubuntu (WSL)

Since we are using the command line, we should definitely try it on WSL first. After all, it’s just a single command:

sudo apt install gcc

However, there were issues with the installation of gcc:

Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
 libasan8 : Depends: gcc-14-base (= 14.2.0-4ubuntu2~24.04) but 14.2.0-4ubuntu2 is to be installed
 libatomic1 : Depends: gcc-14-base (= 14.2.0-4ubuntu2~24.04) but 14.2.0-4ubuntu2 is to be installed
 libcc1-0 : Depends: gcc-14-base (= 14.2.0-4ubuntu2~24.04) but 14.2.0-4ubuntu2 is to be installed
 libhwasan0 : Depends: gcc-14-base (= 14.2.0-4ubuntu2~24.04) but 14.2.0-4ubuntu2 is to be installed
 libitm1 : Depends: gcc-14-base (= 14.2.0-4ubuntu2~24.04) but 14.2.0-4ubuntu2 is to be installed
 liblsan0 : Depends: gcc-14-base (= 14.2.0-4ubuntu2~24.04) but 14.2.0-4ubuntu2 is to be installed
 libquadmath0 : Depends: gcc-14-base (= 14.2.0-4ubuntu2~24.04) but 14.2.0-4ubuntu2 is to be installed
 libtsan2 : Depends: gcc-14-base (= 14.2.0-4ubuntu2~24.04) but 14.2.0-4ubuntu2 is to be installed
 libubsan1 : Depends: gcc-14-base (= 14.2.0-4ubuntu2~24.04) but 14.2.0-4ubuntu2 is to be installed
E: Unable to correct problems, you have held broken packages.

My system is Ubuntu 24.04 under WSL2, and I replaced the software source with Tsinghua’s Tuna source. I have tried many ways to solve this problem, including: installing other versions of gcc:

sudo apt install gcc-13

gcc-13 is available in the current software source, which can be checked with the following command:

apt-cache policy gcc-13
gcc-13:
  Installed: (none)
  Candidate: 13.3.0-6ubuntu2~24.04
  Version table:
     13.3.0-6ubuntu2~24.04 500
        500 https://mirrors.tuna.tsinghua.edu.cn/ubuntu noble-updates/main amd64 Packages
        500 https://mirrors.tuna.tsinghua.edu.cn/ubuntu noble-security/main amd64 Packages
        500 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages
        500 http://security.ubuntu.com/ubuntu noble-security/main amd64 Packages
     13.2.0-23ubuntu4 500
        500 https://mirrors.tuna.tsinghua.edu.cn/ubuntu noble/main amd64 Packages
        500 http://archive.ubuntu.com/ubuntu noble/main amd64 Packages

Or some common methods, such as updating all local software:

sudo apt upgrade

Performing cleanup and auto-clean:

sudo apt clean
sudo apt autoclean

Fixing dependencies:

sudo apt --fix-broken install
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
0 upgraded, 0 newly installed, 0 to remove and 180 not upgraded.

Anyway, this problem was not resolved by the time I finished writing this article, so I decided to set it up on Windows instead. The gnu purists probably couldn’t wait to build from source at this point, but I prefer the convenience of installation on Windows.

Installing GCC and GDB on Windows

To be precise, I installed MingW-w64; this set of tools is unique to Linux, and Windows usage is merely a simulation of Linux.

I had installed gcc once when I built my computer in 2023, and I downloaded it from this site:

https://files.1f0.de/mingw/

I don’t even remember which tutorial I followed to download it; the compressed package did not include gdb, so if I insisted on using this version of gcc, I would have to compile it from source. Considering that I don’t have any large C++ projects on my computer, I decided to reinstall it.

The official MingW-w64 website includes some pre-built toolchains, so there’s no need to build it yourself:

https://www.mingw-w64.org/downloads/#mingw-w64-buildsDebugging C++ Programs Using GDB in Command LineYou can directly download the compressed package from GitHub; there is no need to download the official installer (although that installer merely downloads and unzips the selected compressed package, and you have to set the environment variables yourself).https://github.com/niXman/mingw-builds-binaries/releases

You might not be able to access the above link, feel free to ask me for the compressed package.

After a lot of hassle, I finally completed the installation:Debugging C++ Programs Using GDB in Command Line

Using GDB to Debug C++ Programs in Command Line

Taking a program I previously wrote to test the double equals operator as an example:

#include <iostream>

using namespace std;

struct S
{
public:
    S(int num) : num(num) {};
    bool operator==(S s)
    {
        return this->num == s.num;
    }

private:
    int num;
};

int main()
{
    S s1{1};
    S s2{1};
    cout << (s1 == s2) << endl;
}

Execute the following command to compile the C++ program in debug mode:

g++ -g -o test testOP.cpp

Use gdb to debug the program:

gdb .\test.exe

If your terminal cannot use the backspace key to delete when entering commands in gdb (especially when using the built-in terminal of VS Code), it may be that the terminal has not unlocked the edit mode. You can unlock it using the following command:

set editing off

Viewing Code

<span>l line_number</span> displays 10 lines of code starting from this line

(gdb) l 1
1       #include &lt;iostream&gt;
2
3       using namespace std;
4
5       struct S
6       {
7       public:
8           S(int num) : num(num) {};
9           bool operator==(S s)
10          {

Entering<span>l 0</span> has the same effect. l is an abbreviation for list; gdb has many uses where single words are abbreviated to a letter. If you are unsure, feel free to use it; when an abbreviation is ambiguous, gdb will ask you.

For example, if I enter<span>d b</span>, gdb won’t know what my b refers to.

(gdb) d b
Ambiguous delete command "b": bookmark, breakpoints.

gdb automatically remembers commands and will repeat the command when you press enter without any input. In some cases, it will intelligently modify the command. For example, as long as you keep hitting enter, gdb will continuously update the parameters of the<span>list</span> command, displaying the complete code:

(gdb) l 1
1       #include &lt;iostream&gt;
2
3       using namespace std;
4
5       struct S
6       {
7       public:
8           S(int num) : num(num) {};
9           bool operator==(S s)
10          {
(gdb)
11              return this-&gt;num == s.num;
12          }
13
14      private:
15          int num;
16      };
17
18      int main()
19      {
20          S s1{1};
(gdb)
21          S s2{1};
22          cout &lt;&lt; (s1 == s2) &lt;&lt; endl;
23      }
(gdb)
End of the file was already reached, use "list ." to list the current location again

Breakpoints

<span>b line_number</span> sets a breakpoint at that line; b is an abbreviation for breakpoint

(gdb) b 20
Breakpoint 2 at 0x7ff70ac6145d: file testOP.cpp, line 20.

<span>b source_file:function_name</span> sets a breakpoint at the first line of that function

(gdb) b testOP.cpp:operator==
Breakpoint 3 at 0x7ff70ac62a3b: file testOP.cpp, line 11.

<span>info b</span> displays information about breakpoints

(gdb) info b
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x00007ff70ac6145d in main() at testOP.cpp:20     
3       breakpoint     keep y   0x00007ff70ac62a3b in S::operator==(S) at testOP.cpp:11

<span>d breakpoint_number</span> deletes a breakpoint; d is an abbreviation for delete

(gdb) d 2
(gdb) info b
Num     Type           Disp Enb Address            What
3       breakpoint     keep y   0x00007ff70ac62a3b in S::operator==(S) at testOP.cpp:11

<span>d breakpoints</span> deletes all breakpoints (breakpoints cannot be abbreviated)

(gdb) d breakpoints
Delete all breakpoints? (y or n) Y
(gdb) info b       
No breakpoints or watchpoints.

Debugging

<span>r</span> runs the program until the first breakpoint; r is an abbreviation for run

(gdb) b 21
Breakpoint 4 at 0x7ff70ac6146e: file testOP.cpp, line 21.
(gdb) r
Starting program: D:\Codes\leetcode\3133\test.exe 
[New Thread 27792.0x40c0]
[New Thread 27792.0x6c60]
[New Thread 27792.0x2d54]

Thread 1 hit Breakpoint 4, main () at testOP.cpp:21
21          S s2{1};

<span>n</span> runs the program line by line without entering functions (stepping into); n is an abbreviation for next

(gdb) r
Starting program: D:\Codes\leetcode\3133\test.exe 
[New Thread 5928.0x2170]
[New Thread 5928.0x6c68]
[New Thread 5928.0x6a3c]

Thread 1 hit Breakpoint 4, main () at testOP.cpp:21
21          S s2{1};
(gdb)
(gdb) n
22          cout &lt;&lt; (s1 == s2) &lt;&lt; endl;
(gdb)
1
23      }
(gdb)
0x00007ff70ac612ef in __tmainCRTStartup ()
(gdb)
Single stepping until exit from function __tmainCRTStartup,
which has no line number information.
[Thread 5928.0x2170 exited with code 0]
[Thread 5928.0x6c68 exited with code 0]
[Thread 5928.0x6a3c exited with code 0]
[Inferior 1 (process 5928) exited normally]

<span>s</span> runs the program statement by statement, entering functions; s is an abbreviation for step

(gdb) s
S::S (this=0x5ffec8, num=1) at testOP.cpp:8
8           S(int num) : num(num) {};
(gdb)
main () at testOP.cpp:22
22          cout &lt;&lt; (s1 == s2) &lt;&lt; endl;
(gdb)
S::operator== (this=0x5ffecc, s=...) at testOP.cpp:11
11              return this-&gt;num == s.num;
(gdb)
12          }
(gdb)
1
main () at testOP.cpp:23
23      }
(gdb)
0x00007ff70ac612ef in __tmainCRTStartup ()
(gdb)
Single stepping until exit from function __tmainCRTStartup,
which has no line number information.
[Thread 28652.0x6ed0 exited with code 0]
[Thread 28652.0x5db0 exited with code 0]
[Thread 28652.0x6eec exited with code 0]
[Inferior 1 (process 28652) exited normally]

Exiting GDB

<span>exit</span> exits the gdb command line

Leave a Comment