Linux gdb Command with Practical Examples

LinuxLinuxBeginner
Practice Now

Introduction

In this lab, we will introduce the GNU Debugger (gdb) and explore its usage for debugging C programs. gdb is a powerful tool that allows you to inspect the state of a running program, set breakpoints, and step through the code to identify and fix issues. We will start by ensuring that gdb is installed on our Ubuntu 22.04 Docker container, then create a simple C program with a runtime error and use gdb to debug it. Finally, we will demonstrate how to debug a multithreaded C program using gdb.

Linux Commands Cheat Sheet


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL linux(("`Linux`")) -.-> linux/BasicSystemCommandsGroup(["`Basic System Commands`"]) linux/BasicSystemCommandsGroup -.-> linux/printf("`Text Formatting`") subgraph Lab Skills linux/printf -.-> lab-422698{{"`Linux gdb Command with Practical Examples`"}} end

Introduction to gdb and Its Usage

In this step, we will introduce the GNU Debugger (gdb) and explore its usage for debugging C programs. gdb is a powerful tool that allows you to inspect the state of a running program, set breakpoints, and step through the code to identify and fix issues.

First, let's ensure that gdb is installed in our Ubuntu 22.04 Docker container:

sudo apt-get update
sudo apt-get install -y gdb

Example output:

Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  libasan6 libubsan1 python3-gdb
Suggested packages:
  gdb-multiarch
The following NEW packages will be installed:
  gdb libasan6 libubsan1 python3-gdb
0 upgraded, 4 newly installed, 0 to remove and 0 not upgraded.
Need to get 3,470 kB of archives.
After this operation, 13.5 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y

Now, let's create a simple C program to debug. Create a file named example.c in the ~/project directory with the following content:

#include <stdio.h>

int main() {
    int a = 5;
    int b = 0;
    int c = a / b;
    printf("The result is: %d\n", c);
    return 0;
}

This program will intentionally divide by zero, causing a runtime error.

To debug this program using gdb, follow these steps:

  1. Compile the program with the -g flag to include debugging symbols:
gcc -g -o example example.c
  1. Start the gdb debugger and load the compiled program:
gdb ./example
  1. In the gdb prompt, set a breakpoint at the main function:
(gdb) break main
Breakpoint 1 at 0x11a6: file example.c, line 4.
  1. Run the program:
(gdb) run
Starting program: /home/labex/project/example
  1. When the program hits the breakpoint, you can inspect variables, step through the code, and debug the issue:
Breakpoint 1, main () at example.c:4
4       int a = 5;
(gdb) print a
$1 = 5
(gdb) next
5       int b = 0;
(gdb) print b
$2 = 0
(gdb) next
6       int c = a / b;

As you can see, when the program attempts to divide by zero, it will trigger a runtime error that can be caught and debugged using gdb.

Debugging a Simple C Program with gdb

In this step, we will use gdb to debug a simple C program that has a runtime error.

First, let's create a new C file named simple.c in the ~/project directory with the following content:

#include <stdio.h>

int main() {
    int x = 10;
    int y = 0;
    int z = x / y;
    printf("The result is: %d\n", z);
    return 0;
}

This program will intentionally divide by zero, causing a runtime error.

Now, let's compile the program with the -g flag to include debugging symbols:

gcc -g -o simple simple.c

Next, start the gdb debugger and load the compiled program:

gdb ./simple

In the gdb prompt, set a breakpoint at the main function:

(gdb) break main
Breakpoint 1 at 0x11a6: file simple.c, line 4.

Now, run the program:

(gdb) run
Starting program: /home/labex/project/simple

When the program hits the breakpoint, you can inspect variables, step through the code, and debug the issue:

Breakpoint 1, main () at simple.c:4
4       int x = 10;
(gdb) print x
$1 = 10
(gdb) next
5       int y = 0;
(gdb) print y
$2 = 0
(gdb) next
6       int z = x / y;

As you can see, when the program attempts to divide by zero, it will trigger a runtime error that can be caught and debugged using gdb.

Debugging a Multithreaded C Program with gdb

In this step, we will use gdb to debug a multithreaded C program that has a race condition.

First, let's create a new C file named multithreaded.c in the ~/project directory with the following content:

#include <stdio.h>
#include <pthread.h>

int shared_variable = 0;

void* thread_function(void* arg) {
    for (int i = 0; i < 1000000; i++) {
        shared_variable++;
    }
    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    pthread_create(&thread1, NULL, thread_function, NULL);
    pthread_create(&thread2, NULL, thread_function, NULL);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    printf("Final value of shared_variable: %d\n", shared_variable);
    return 0;
}

This program creates two threads that both increment a shared variable 1,000,000 times. Due to a race condition, the final value of the shared variable may not be the expected 2,000,000.

Now, let's compile the program with the -g flag to include debugging symbols:

gcc -g -o multithreaded multithreaded.c -lpthread

Next, start the gdb debugger and load the compiled program:

gdb ./multithreaded

In the gdb prompt, set a breakpoint at the beginning of the thread_function:

(gdb) break thread_function
Breakpoint 1 at 0x11b6: file multithreaded.c, line 7.

Now, run the program:

(gdb) run
Starting program: /home/labex/project/multithreaded

When the program hits the breakpoint, you can inspect variables, step through the code, and debug the race condition:

Breakpoint 1, thread_function (arg=0x0) at multithreaded.c:7
7       for (int i = 0; i < 1000000; i++) {
(gdb) print shared_variable
$1 = 0
(gdb) step
8           shared_variable++;
(gdb) print shared_variable
$2 = 1

By stepping through the code and inspecting the shared variable, you can observe the race condition and identify the issue in the multithreaded program.

Summary

In this lab, we introduced the GNU Debugger (gdb) and explored its usage for debugging C programs. We first ensured that gdb was installed on the Ubuntu 22.04 Docker container, then created a simple C program with a runtime error to debug. We compiled the program with the -g flag to include debugging symbols, started the gdb debugger, set a breakpoint at the main function, and ran the program. Once the program hit the breakpoint, we were able to inspect variables, step through the code, and debug the issue.

The lab covered the basics of using gdb to debug a simple C program, as well as debugging a multithreaded C program. By following the step-by-step instructions, learners gained practical experience in using this powerful debugging tool.

Linux Commands Cheat Sheet

Other Linux Tutorials you may like