GDB modal tool learning notes - stepping and tracking function calls

Posted by Chrisinsd on Tue, 08 Mar 2022 18:54:01 +0100

brief introduction

When using the graphical ide for program development, the editing tool usually has its own debugging function, which can interrupt the point, execute the code step by step and view the real-time value of each variable at any time. However, when developing c and c + +, it is often carried out under linux system, and through vim or vi editor, without graphical interface, This is the use of GDB debugging tool. It provides most of the functions we need when debugging programs. This article is the author's learning notes on the use of GDB tools in the Book Linux C programming: one-stop learning.

1. Single step execution and trace function call

1.1 example program

First read the following code. The main function of this code is to realize the accumulation of numbers

#include <stdio.h>
int add_range(int low, int hight)
{
	int i, sum;
	for(i = low; i <= hight; i++)
	{
		sum += i;
	}
	return sum;
}

int main()
{
	int res1, res2;
	res1 = add_range(1, 10);
	res2 = add_range(1, 100);
	printf("res1 = %d, res2 = %d\n", res, res2);
	return 0;
	}

The following are the operation results given in the book

res1 = 55, res2 = 5105

However, interestingly, after the author runs it himself, he finds that the output result given by the author of the original book does not appear, and the author knows that it will not appear, because the variable sum is not initialized after it is defined. The result in the book may be the output result specially set by the author for gdb debugging, which does not hinder learning. The following is the output of the author's running program

zz@ubuntu:~/Project/gdb_study$ ./demo1
res1 = 21911, res2 = 26961
zz@ubuntu:~/Project/gdb_study$ ./demo1
res1 = 22009, res2 = 27059
zz@ubuntu:~/Project/gdb_study$ ./demo1
res1 = 22012, res2 = 27062
zz@ubuntu:~/Project/gdb_study$ ./demo1
res1 = 22051, res2 = 27101
zz@ubuntu:~/Project/gdb_study$ ./demo1
res1 = 22155, res2 = 27205
zz@ubuntu:~/Project/gdb_study$ ./demo1
res1 = 22001, res2 = 27051
zz@ubuntu:~/Project/gdb_study$ ./demo1
res1 = 22016, res2 = 27066

It can be seen that the result changes all the time, which is very consistent with the result that the variable is used without initialization. After we assign a value of 0 to sum, the program will run normally and output the result we want. Let's assume that we don't know what's wrong. After the program runs and outputs, we pretend to be confused. At this time, gdb should play.

1.2 common commands

Run the following command

gcc -g demo1.c -o demo1
gdb demo1

When compiling, adding the compiling option - g means adding the information of the source code into the executable file. For example, the first machine instruction in the executable file corresponds to the first line of the source code, but the whole source file is not embedded into the executable file. Therefore, gdb must be able to find the source file during debugging.

1.2.1 help

For help commands, you can view the category of commands or specify the specific description of a command
(gdb) help
List of classes of commands:

aliases -- Aliases of other commands.
breakpoints -- Making program stop at certain points.
data -- Examining data.
files -- Specifying and examining files.
internals -- Maintenance commands.
obscure -- Obscure features.
running -- Running the program.
stack -- Examining the stack.
status -- Status inquiries.
support -- Support facilities.
tracepoints -- Tracing of program execution without stopping the program.
user-defined -- User-defined commands.

Type "help" followed by a class name for a list of commands in that class.
Type "help all" for the list of all commands.
Type "help" followed by command name for full documentation.
Type "apropos word" to search for commands related to "word".
Type "apropos -v word" for full documentation of commands related to "word".
Command name abbreviations are allowed if unambiguous.

1.2.2 list (l)

List the contents of the source code, run the command once and display 10 lines. You need to continue browsing. Just press enter and execute the last command by default
(gdb) list
1       #include <stdio.h>
2
3       int add_range(int low, int hight)
4       {
5               int i, sum;
6               for(i = low; i <= hight; i++)
7               {
8                       sum += i;
9               }
10              return sum;
(gdb)
11      }
12
13      int main()
14      {
15              int res1, res2;
16              res1 = add_range(1, 10);
17              res2 = add_range(1, 100);
18              printf("res1 = %d, res2 = %d\n", res1, res2);
19              return 0;
20      }
(gdb)

1.2.3 quit

Exit command, push gdb Debugging environment

1.2.4 start

Program start command
(gdb) start
Temporary breakpoint 1 at 0x1176: file demo1.c, line 14.
Starting program: /home/zz/Project/gdb_study/demo1

Temporary breakpoint 1, main () at demo1.c:14
14      {

After running this command, you can find that it automatically jumps to the beginning of the main function and indicates the line number.

1.2.5 next(n)

Continue to execute the command and control the program to execute the next line
(gdb) next
16              res1 = add_range(1, 10);
(gdb)
17              res2 = add_range(1, 100);
(gdb)
18              printf("res1 = %d, res2 = %d\n", res1, res2);
(gdb)
res1 = 21900, res2 = 26950
19              return 0;
(gdb)
20      }
(gdb)

1.2.6 step(s)

Trace the function entered and executed

After calling the next command all the way, we found that we did not find any exceptions. Maybe the program error is not in the main function, but in the function called in the main function. But the next command is executed, the system will skip the function automatically. If you want to enter the function step by step, you will need the step command to track the program.

(gdb) start
Temporary breakpoint 2 at 0x555555555176: file demo1.c, line 14.
Starting program: /home/zz/Project/gdb_study/demo1

Temporary breakpoint 2, main () at demo1.c:14
14      {
(gdb) next
16              res1 = add_range(1, 10);
(gdb) step
add_range (low=21845, hight=1431654941) at demo1.c:4
4       {

From above, enter add_ After the range function, the formal parameters are given messy values, which is different from what we expected and what is said in the book. I won't explain it here, and the author will have some personal conjectures later.

1.2.7 backtrace(bt)

View stack frame of function call
(gdb) bt
#0  add_range (low=21845, hight=1431654941) at demo1.c:4
#1  0x0000555555555191 in main () at demo1.c:16

1.2.8 info(i)

View the value of the parameter
  1. Info localsview local parameters
  2. info arg view function parameters
(gdb) i locals
i = 1431654864
sum = 21845
(gdb) info locals
i = 1431654864
sum = 21845
(gdb) info arg
low = 21845
hight = 1431654941

It can be seen that the local parameters and formal parameters of the function are messy values. The author guesses that at this time, the function has just been pushed into the stack, the memory has just been allocated, the formal parameters and local parameters have been created, and the assignment of the actual parameters to the formal parameters has not been completed. We are going to take the next step.

(gdb) n
6               for(i = low; i <= hight; i++)
(gdb) info locals
i = 1431654864
sum = 21845
(gdb) info arg
low = 1
hight = 10
(gdb)

It can be seen that when the function is executed to the sixth line, the local parameter is garbled because it has not been initialized and has been assigned, but the formal parameter can be seen to be the correct value, indicating that the actual parameter has successfully assigned the formal parameter.

1.2.9 frame(f)

Function stack frame switching

At this point, the program is already in add_ In the range function, what should I do if I want to view the parameter information in the main function? Use the frame command to switch the frame of the function stack

(gdb) bt
#0  add_arrange (low=1, hight=10) at demo1.c:6
#1  0x0000555555555191 in main () at demo1.c:16
(gdb) frame 1
#1  0x0000555555555191 in main () at demo1.c:16
16              res1 = add_arrange(1, 10);
(gdb) i locals
res1 = 0
res2 = 0
(gdb) f 0
#0  add_arrange (low=1, hight=10) at demo1.c:6
6               for(i = low; i <= hight; i++)

As you can see, use the backtrace command to view the current function stack frame information, and use the frame function stack frame number command to switch to the specified function stack frame. At this time, use the info locals command to view the values of local parameters in the current main function. After viewing, use the frame command to switch to add_range function, you can see that it is still in the place where the previous function runs.

1.2.10 print§

Print the value of the variable
(gdb) print sum
$1 = 21845

Here, $1 means that gdb saves these intermediate results, and the number after $1 will increase automatically. You can replace the corresponding value with $1, $2, $3 and other numbers in the command.

1.2.11 set var

Set the variable to the specified value

At this time, we already know that the program error is caused by the reason that sum is not initialized. In order to verify our idea, we initialize sum manually to see whether the result is what we expect.

(gdb) set var sum=0
(gdb) print sum
$4 = 0

1.2.12 finish

Run continuously until the current function returns, and then stop and wait for the command
(gdb) finish
Run till exit from #0  add_arrange (low=1, hight=10) at demo1.c:6
0x0000555555555191 in main () at demo1.c:16
16              res1 = add_arrange(1, 10);
Value returned is $5 = 55

It can be seen that the function runs successfully to the end and the return value is 55, which shows that our idea is completely correct. The program error is due to the uninitialization of sum variable.

1.3 command summary

commanddescribe
backtrace(bt)View function calls and parameters at all levels
finishRun continuously until the current function returns, and then stop and wait for the command
frame(f)Select function stack frame
info(i)View current parameter information (locals: view local variable parameters; arg: View function parameter values; registers: view current register data)
list(l)List the source code, 10 lines at a time, with memory, and list it down after the last listing (add the line number after it, and list the code from this line number; add the function name after it: list the code of this function)
next(n)Execute the next statement
print§Print the value of the expression, through which you can modify the value of the variable or call the function
quit(q)Exit gdb debugging environment
set varModify the value of the variable
startStart executing the program, stay in front of the first line of the main function and wait for the command
step(s)Execute the next statement. If there is a function, enter the function