GDB(The GNU Project Debugger) is one of the most awesome softwares ever built for C programmers. I recently started to write some code in C, specifically trying out socket programming and some other stuff. I had a very basic problem about how to debug a variable (bytes) without using the printf. I have been using printf since always to debug softwares in C and Python, but lets see something new today.

First, lets see a very simple socket program:

To compile this program with debugging symbols(-g) that gdb can use, try:

1$ gcc -o server -g server.c

Then you can run your program:

1$ ./server 2000

You can then also test that your server works using telnet:

1$ telnet localhost 2000
2Trying 127.0.0.1...
3Connected to localhost.
4Escape character is '^]'.
5hi
6I got your message

Great Work! Now, my next problem was trying to close the connection with the client if it sent an “exit”. Not a problem, I just compared the read buffer against the string “exit” and expected it to work.

1n = strcmp(buffer, "exit");
2if (n == 0)
3	break;

But, unfortunately this did not work for some reason I could not reason about. So, lets see how we can debug this using gdb. First of all you run your program using gdb after compiling with debug symbols( option -g):

1$ gdb ./server
2...
3...
4Reading symbols from server...done.
5(gdb)

Great, now you can start introducing breakpoints in your program like this:

1(gdb) break server.c:78
2Breakpoint 1 at 0x400d00: file server.c, line 78.

This added a breakpoint at the line 78 in your program. Remember, this is your source code and not the compiled program. You can’t make sense out of your compiled program anyway.

So, what exactly is a breakpoint? It is simply a marker that you set where you want the execution of your program to halt, so that you can analyse the state and variables instead of priting all of them one by one in the source code.Now lets see how that exactly works:

1(gdb) run 3000
2Starting program: <path_to>/server 3003

Now when the execution reaches line 78, we should see a gdb prompt and program execution should pause.

1$ telnet localhost 3000
2Trying 127.0.0.1...
3Connected to localhost.
4Escape character is '^]'.
5hi
6I got your message

Wait, what happened? Why did the program not hault? A quick google search led me to the conclusion that gdb monitors the main parent process by default, even if you execute a fork() system call. This means, that the breakpoint should be introduced in the child process as the main parent process never runs the line 78 we introduced break point on. Lets now change that and again run the server and try connecting from a client.

 1$ gdb ./server
 2....
 3....
 4Reading symbols from server...done.
 5(gdb) set follow-fork-mode child
 6(gdb) break server.c:78
 7(gdb) run 3000
 8Starting program: /home/maxking/Documents/socket-prog/server 3000
 9[New process 8940]
10
11Breakpoint 1, dostuff (newsockfd=4) at server.c:78
1278					n = strcmp(strtok(buffer, "\r\n"), exit);
13(gdb)print buffer
14$1 = "yo\r\n", '\000' <repeats 251 times>

Awesome! Now, I guess you already know why “exit” string does not match with buffer, because the client(telnet) added “\r\n” at the end of the message.

We can easily remove that using strtok() method to strip them off:

1n = strcmp(strtok(buffer, "\r\n"), exit);
2if (n == 0)
3	break;

And, if you run this, you’d know that it does work! GDB is actually much more useful than just printing stuff. Here is a great tutorial that you can refer to learn more about how to use the advanced features of gdb.