A Debugging Tool More Convenient Than GDB

CGDB isGDB‘s frontend, which allows debugging code in a graphical form within the terminal window (based onncurse), making it very convenient. Compared toGDB, it can significantly improve efficiency.

This article will share the most basic usage of CGDB. If you are hearing about it for the first time, I strongly recommend you to try it out; you will definitely love it!

Example Code with Bugs

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

typedef struct USER_DATA{
	char data[32];
	unsigned short data_len;
	unsigned int flag;
}__attribute((packed))__;

const unsigned char * g_data =  "hello";

/*
Function: Load a piece of data
Param 1: data[OUT]: Buffer where the data is loaded
Param 2: len [OUT]: Actual length of the loaded data
Return: 0-success, else-failure
*/
static int get_data(unsigned char *data, unsigned int *len)
{
	assert(data && len);
	memcpy((void *)data, (void *)g_data, strlen(g_data));
	*len = strlen(g_data);
	return 0;
}

int main(int argc, char *argv[])
{
    // Create struct variable
	struct USER_DATA user_data;
	user_data.flag = 0xA5;
	
	// Load data into struct variable
	if (0 == get_data(user_data.data, &user_data.data_len))
	{
		printf("get_data ok! \n");
		printf("data_len = %d, data = %s \n", user_data.data_len, user_data.data);
		printf("user_data.flag = 0x%x \n", user_data.flag);  // Expected value: 0xA5
	}
	else
	{
		printf("get_data failed! \n");
	}
	return 0;
}

Before compiling, take a look at the code. Can you spot the bug in it?

Of course, during compilation, the compiler gives a warning about the risk. Since the example code is simple, it is easy to spot.

However, in a project, if you don’t like to eliminate compilation Warning messages, this bug can be quite hidden.

Compile test code: gcc -g test.c -o test

Since you need to use GDB for debugging, don’t forget to add the -g option.

GDB Debugging Operations

$ gdb ./test
(gdb) r   // Run it directly at full speed
(gdb) r
Starting program: /home/captain/demos_2022/cgdb/test 
test start... 
get_data ok! 
data_len = 5, data = hello 
user_data.flag = 0x0 
[Inferior 1 (process 9933) exited normally]

Noticing that the value of user_data.flag is incorrect, I decided to set a breakpoint on the line before calling get_data, then start executing from the beginning:

View the line numbers:

(gdb) l main
18		*len = strlen(g_data);
19		return 0;
20	}
21	
22	int main(int argc, char *argv[])
23	{
24		struct USER_DATA user_data;
25		user_data.flag = 0xA5;
26		if (0 == get_data(user_data.data, &user_data.data_len))
27		{

Set a breakpoint at line 25:

(gdb) b 25
Breakpoint 1 at 0x400771: file test.c, line 25.

Start running:

(gdb) r
Starting program: /home/captain/demos_2022/cgdb/test 

Breakpoint 1, main (argc=1, argv=0x7fffffffdc58) at test.c:25
25		user_data.flag = 0xA5;

The execution stopped at the breakpoint, and the assignment statement has not yet been executed, so I execute it step by step:

(gdb) step
26		if (0 == get_data(user_data.data, &user_data.data_len))

At this point, print the value and address of the variable user_data.flag:

Since we will enter the called function later, this variable will become invisible, so we need to print it by address.

(gdb) print &user_data.flag
$1 = (unsigned int *) 0x7fffffffdb62
(gdb) print/x user_data.flag
$2 = 0xa5

At this point, the assignment is correct. Next, continue executing and enter the called function get_data():

(gdb) step
get_data (data=0x7fffffffdb40 "n\333\377\377\377\177", len=0x7fffffffdb60) at test.c:16
16		assert(data && len);

This function has a total of 4 lines of code. We execute it step by step and print the content of the user_data.flag variable each time.

Step to the next line memcpy, and check if the content at the address of user_data.flag is still: 0xa5:

(gdb) step
17		memcpy((void *)data, (void *)g_data, strlen(g_data));
(gdb) print/x *0x7fffffffdb62
$3 = 0xa5

Continue stepping (since we don’t need to follow the internals of memcpy and strlen, we use the next command) and print:

(gdb) next
18		*len = strlen(g_data);     // This line is about to be executed
(gdb) print/x *0x7fffffffdb62
$4 = 0xa5
(gdb) next
19		return 0;
(gdb) print/x *0x7fffffffdb62
$5 = 0x0

We’ve discovered the problem: after executing the statement *len = strlen(g_data), the content at the address of the variable user_data.flag has changed.

Upon careful inspection of the code, we can diagnose that the data type was used incorrectly.

Bug Fix: The last parameter of the get_data() function should correctly be a pointer of type unsigned short.

The problem is solved, but looking back at the gdb debugging process, it is still quite cumbersome: the debugging commands and code display are mixed together, requiring a lot of commands to type.

CGDB Debugging Operations

After starting CGDB, the terminal window is divided into two parts: the upper part is the code window, and the lower part is the debugging window.

A Debugging Tool More Convenient Than GDB

Press the ESC key to enter the code window, where you can scroll through the code up and down and perform a series of operations:

Spacebar: Set or cancel a breakpoint;

o: View the file where the code is located;

/ or ?: Search for strings in the code;

There are many convenient hotkeys:

-: Shrink the code window;

+: Expand the code window;

gg: Move the cursor to the top of the file;

GG: Move the cursor to the end of the file;

ctrl + b: Scroll up the code by one page;

ctrl + u: Scroll up the code by half a page;

ctrl + f: Scroll down the code by one page;

ctrl + d: Scroll down the code by half a page;

Press the i key to return to the debugging window, entering debugging mode, where the debugging commands are almost the same as GDB!

In other words: you can perform debugging operations while viewing the code in real time, greatly improving efficiency.

Let’s go through the debugging process of GDB again:

Press the ESC key to enter the code window. If the line number in front of the code is white, it indicates the current line.

Press the j key to move the highlighted current line down. When moving to line 25, as shown below:

A Debugging Tool More Convenient Than GDB

Press the spacebar to set a breakpoint on this line, and the line number turns red:

A Debugging Tool More Convenient Than GDB

And the debugging window prints a line of information:

(gdb) 
Breakpoint 1 at 0x400771: file test.c, line 25.

Press the i key to return to the debugging operation window, then enter the run command r, which will stop at line 25, as indicated by the green arrow below:

A Debugging Tool More Convenient Than GDB

Of course, the debugging window will also print relevant information:

(gdb) r
Starting program: /home/captain/demos_2022/cgdb/test 

Breakpoint 1, main (argc=1, argv=0x7fffffffdc58) at test.c:25

Step step to execute this assignment statement, and then print the value and address of user_data.flag:

(gdb) print/x user_data.flag
1: /x user_data.flag = 0xa5
(gdb) print &user_data.flag
2: &user_data.flag = (unsigned int *) 0x7fffffffdb62

At this point, the assignment statement executed correctly, and the printed value is also as expected.

Continue executing step commands to enter the get_data() function:

(gdb) step
get_data (data=0x7fffffffdb40 "n\333\377\377\377\177", len=0x7fffffffdb60) at test.c:16

At this point, the upper code window automatically enters the relevant code of get_data(), as shown below:

A Debugging Tool More Convenient Than GDB

Continue stepping, and before executing the assignment statement *len = strlen(g_data); print the content at the address of the variable user_data.flag:

(gdb) print/x *0x7fffffffdb62
$2 = 0xa5

Correct! Then execute the assignment statement, and print again:

(gdb) next
(gdb) print/x *0x7fffffffdb62
$3 = 0x0

We found the problem: after executing the statement *len = strlen(g_data), the content at the address of the variable user_data.flag has changed.

Summary:

The operation process of CGDB is quite smooth, although I wrote it in detail, but in actual use, it is truly smooth, just like chocolate!

—— End ——

Since you have read this far, if you find it good, please give a quick 【like】 and 【view】!

Reposted from WeChat public account: IOT Internet of Things Town

A Debugging Tool More Convenient Than GDB

A Debugging Tool More Convenient Than GDB

Leave a Comment