How to Get Started With GNU Debugger on Linux: A Crash Course

Pratik MPratik M
5 min read

Debugging is an essential skill for any programmer or software developer. Knowing how to efficiently debug code allows you to quickly identify and fix issues in your programs.

The GNU Debugger (GDB) is a powerful, open-source debugging tool available on Linux and other Unix-based systems. It allows you to interactively debug programs written in languages like C, C++, Rust, Go, and more by controlling program execution and inspecting variable values.

In this comprehensive guide, you'll learn how to use GDB to debug programs on Linux by walking through various examples.

Installing GDB on Linux

GDB comes pre-installed on most Linux distributions. To verify if you already have it, run:

gdb --version

If not installed, use your distribution's package manager to install it.

For Debian/Ubuntu:

sudo apt install gdb

For RHEL/CentOS:

sudo yum install gdb

For Arch Linux:

sudo pacman -S gdb

Preparing a Sample Program

To learn GDB, you need a program to debug. Here's a simple "guess the number" game in C:

#include <stdio.h>
#include <stdlib.h>

int main() {
  int secretNum = 5; 
  int guess;

  printf("Guess the secret number (1-10): ");
  scanf("%d", &guess);

  if(guess == secretNum) {
    printf("You guessed correctly!");   
  } else {
    printf("Sorry, try again.");
  }

  return 0;
}

Save the above as guess.c and compile it into a binary with debug symbols:

gcc -g guess.c -o guess

The -g flag includes debugging information in the compiled program. This allows GDB to map code to source lines.

Starting GDB

To debug the guess program with GDB, run:

gdb guess

This will start GDB in interactive mode. You'll see the (gdb) prompt waiting for your commands.

To directly execute the program inside GDB, use the run command:

(gdb) run

This will start the program execution. Provide input when prompted and the program will run normally. Use Ctrl + C to halt execution and return to the GDB prompt.

Alternatively, you can directly load and run the program by:

gdb guess --args ./guess

Setting Breakpoints

A breakpoint stops execution at a specific line or function and returns control to GDB. This allows you to inspect the program state at that point.

To set a breakpoint at the main() function, type:

(gdb) break main

You can also set a breakpoint on a specific line number:

(gdb) break 8

This will break line 8 of the source code.

Run info breakpoints to see the currently set breakpoints.

When the program hits a breakpoint, execution will pause and you'll be able to inspect variables, execute code line-by-line, etc.

Stepping Through Code

Once stopped at a breakpoint, you can step through code one line at a time using:

  • step - Step to the next line of code

  • next - Step over the current line

  • finish - Finish execution of the current function

For example, on hitting the breakpoint at main():

(gdb) step
9      int secretNum = 5;

(gdb) print secretNum 
$1 = 5

(gdb) next
10    int guess;

(gdb) finish
Run till exit from #0  main () at guess.c:10
0x0000555555555167 in __libc_start_main (main=0x00005555555550d9 <main>, argc=1, argv=0x7fffffffe518, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, 
stack_end=0x7fffffffe508) at ../csu/libc-start.c:342
342    ../csu/libc-start.c: No such file or directory.

This allows you to walk through the program flow and observe the changes in state.

Viewing Variables

To inspect a variable value in GDB, use the print command:

(gdb) print guess
$1 = 4

You can also view all variables in the current scope:

(gdb) info locals
secretNum = 5
guess = 4

Examining the Stack

The stack contains valuable debugging information like parameter values, return addresses, and local variables of function calls.

To examine the stack trace, use:

(gdb) backtrace 
#0  main () at guess.c:14
#1  0x00007ffff7a0530a in __libc_start_main (main=0x5555555550d9 <main>, argc=1, argv=0x7fffffffe518, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe508) at ../csu/libc-start.c:342
#2  0x00005555555550a8 in _start ()

This shows the sequence of function calls currently active. You can combine it with other commands like frame and info locals to inspect a particular stack frame.

Debugging Core Dumps

When a program crashes unexpectedly, it can generate a core dump file containing the program state at the time of the crash.

Examine core dumps in GDB using:

gdb program_name core_file

This will load the program and core dump. You can then inspect variables, stack trace etc. to uncover the cause of the crash.

Debugging Multi-threaded Apps

To debug multi-threaded applications, first list the threads:

(gdb) info threads 
  Id   Target Id         Frame 
  2    Thread 0x7ffff7fc7700 (LWP 8189) "mythread" pthread_join (threadid=140737354072576, thread_return=0x7fffffffd4c0) at pthread_join.c:90
  1    Thread 0x7ffff7fc5700 (LWP 8188) "mythread" 0x00007ffff7a07aa1 in __GI___pthread_timedjoin_ex (threadid=140737354072576, thread_return=0x7fffffffd4c0, abstime=0x0, clockid=<optimized out>) at pthread_join_common.c:89
  * 1    Thread 0x7ffff7dd9700 (LWP 8187) "guess" 0x0000555555555193 in main () at guess.c:19

This shows the active threads in the program.

You can switch context to a specific thread using:

(gdb) thread 2
[Switching to thread 2 (Thread 0x7ffff7fc7700 (LWP 8189))]
#0  pthread_join (threadid=140737354072576, thread_return=0x7fffffffd4c0) at pthread_join.c:90
90      return SYSCALL_NOERROR;

Now you can inspect this thread's stack, variables etc. independently.

Summary

GDB is a powerful tool that should be in every developer's debugging toolkit. Its interactive nature, combined with commands like breakpoints, stepping, and inspection of variables and stack traces make it invaluable for understanding program execution flows and identifying issues.

Some key topics we covered:

  • Installing and starting GDB

  • Setting breakpoints

  • Stepping through code line-by-line

  • Printing variables and examining stack traces

  • Debugging core dumps and multi-threaded programs

This was just a short overview of GDB's capabilities. For more advanced use and customization of GDB, refer to the official GDB documentation.

Happy debugging!

4
Subscribe to my newsletter

Read articles from Pratik M directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Pratik M
Pratik M

As an experienced Linux user and no-code app developer, I enjoy using the latest tools to create efficient and innovative small apps. Although coding is my hobby, I still love using AI tools and no-code platforms.