TrumanWong

gdb

Powerful program debugger

Supplementary instructions

gdb command is included in GNU's gcc development kit and is a powerful program debugger. Although there are many commands in GDB, we only need to master about ten of them to complete basic daily program debugging work.

grammar

gdb(options)(parameters)

Options

-cd: Set the working directory;
-q: Quiet mode, does not print introduction information and version information;
-d: Add file search path;
-x: Execute GDB instructions from the specified file;
-s: Set the symbol table file to be read.
Command Explanation Example
file Load the executable program file being debugged.
Because GDB is generally executed in the directory where the program being debugged is located, the text name does not need to include a path.
(gdb) file gdb-sample
r Short for Run, runs the program being debugged.
If no breakpoint has been set before, the entire program will be executed; if there is a breakpoint, the program will pause at the first available breakpoint.
(gdb) r
c Abbreviation of Continue, continue executing the debugged program until the next breakpoint or the end of the program. (gdb) c
b
b
b *
b * d [number]
b: Abbreviation of Breakpoint, set breakpoint. You can use "line number", "function name", "execution address" and other methods to specify the breakpoint location.
Adding the "*" symbol in front of the function name means setting the breakpoint at "the prolog code generated by the compiler". If you don't understand assembly, you can ignore this usage. d: Abbreviation for Delete breakpoint, delete a breakpoint with a specified number, or delete all breakpoints. Breakpoint numbers start from 1 and increase.
(gdb) b 8(gdb) b main
(gdb) b *main
(gdb) b *0x804835c (gdb) d
s, n s: Execute a line of source code, and if there is a function call in this line of code, enter the function;
n: Execute a line of source code, and the function calls in this line of code are also executed. s is equivalent to "Step Into" in other debuggers;
n is equivalent to "Step Over" in other debuggers. These two commands can only be used with source code debugging information (use the "-g" parameter when compiling with GCC).
(gdb) s
(gdb) n
si, ni The si command is similar to the s command, and the ni command is similar to the n command. The difference is that these two commands (si/ni) target assembly instructions, while s/n targets source code. (gdb) si
(gdb) ni
p Short for Print, displays the value of the specified variable (temporary variable or global variable). (gdb) p i
(gdb) p nGlobalVar
display ... undisplay display, set the data and format to be displayed after the program is interrupted.
For example, if you want to see the next assembly instruction to be executed every time the program is interrupted, you can use the command
"display /i $pc"
where $pc represents the current assembly instruction , /i means display in sixteen. This command is useful when you need to care about assembly code. undispaly, cancel the previous display settings, the number starts from 1 and increases.
(gdb) display /i $pc (gdb) undisplay 1
i The abbreviation of info, used to display various information, please refer to "help i" for details. (gdb) i r
q Abbreviation for Quit, exit the GDB debugging environment. (gdb) q
help [command name] GDB help command, providing explanations of various GDB commands.
If the "command name" parameter is specified, the detailed description of the command will be displayed; if no parameter is specified, all GDB commands will be displayed in categories for users to further browse and query.
(gdb) help

Parameters

File: Binary executable program.

Example

The following is an example of dgb debugging under Linux. First, a small program for the example, C language code:

#include <stdio.h>
int nGlobalVar = 0;

int tempFunction(int a, int b)
{
     printf("tempFunction is called, a = %d, b = %d /n", a, b);
     return (a + b);
}

int main()
{
     int n;
         n = 1;
         n++;
         n--;

         nGlobalVar += 100;
         nGlobalVar -= 12;

     printf("n = %d, nGlobalVar = %d /n", n, nGlobalVar);

         n = tempFunction(1, 2);
     printf("n = %d", n);

     return 0;
}

Please copy this code and save it to the file gdb-sample.c, then switch to the directory where this file is located, and compile it with GCC:

gcc gdb-sample.c -o gdb-sample -g

In the above command line, the -o parameter is used to specify the name of the compiled executable file gdb-sample, and the -g parameter is used to compile the source code information into the executable file. If the parameter -g is not used, it will cause inconvenience in subsequent GDB debugging. Of course, if we do not have the source code of the program, we naturally cannot use the -g parameter, and debugging/tracing can only be debugging/tracing at the assembly code level.

The following "gdb" command starts GDB and will first display the GDB description, regardless of it:

GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu".
(gdb)

The last line "(gdb)" above is the GDB internal command guide, waiting for the user to enter the GDB command.

Use the "file" command below to load the debugged program gdb-sample (gdb-sample here is the executable file output by the previous GCC compilation):

(gdb) file gdb-sample
Reading symbols from gdb-sample...done.

The last line above indicates that it has been loaded successfully.

The following uses the "r" command to execute (Run) the debugged file. Since no breakpoint has been set, it will be executed directly to the end of the program:

(gdb)r
Starting program: /home/liigo/temp/test_jmp/test_jmp/gdb-sample
n = 1, nGlobalVar = 88
tempFunction is called, a = 1, b = 2
n=3
Program exited normally.

Let's use the "b" command to set a breakpoint (Breakpoint) at the beginning of the main function:

(gdb) b main
Breakpoint 1 at 0x804835c: file gdb-sample.c, line 19.

The last line above prompts that the breakpoint has been set successfully and gives the breakpoint information: Set a breakpoint at line 19 of the source file gdb-sample.c; this is the first breakpoint of this program (serial number is 1) ;The code address at the breakpoint is 0x804835c (this value may only be valid during this debugging process). Looking back at the source code, the code in line 19 is "n = 1", which happens to be the first executable statement in the main function (the previous "int n;" is a variable definition statement, not an executable statement) .

Use the "r" command again to execute (Run) the debugged program:

(gdb) r
Starting program: /home/liigo/temp/gdb-sample

Breakpoint 1, main () at gdb-sample.c:19
19 n = 1;

The program interrupts at line 19 of gdb-sample.c, where the main function is the first executable statement.

The last line of information above is: The next source code to be executed is "n = 1;", which is line 19 in the source code file gdb-sample.c.

Use the "s" command (Step) below to execute the next line of code (ie, line 19 "n = 1;"):

(gdb)s
20n++;

The above information indicates that "n = 1;" has been executed, and the next code to be executed is "n++;" on line 20.

Now that "n = 1;" has been executed, that is, the variable n is assigned a value of 1, then we use the "p" command (Print) to see if the value of variable n is 1:

(gdb) p n
$1 = 1

Sure enough it was 1. ($1 roughly means this is the first time the "p" command has been used - executing "p n" again will show "$2 = 1" - this information should be of little use.)

Next, we set a breakpoint at line 26 and at the beginning of the tempFunction function (use the commands "b 26" and "b tempFunction" respectively):

(gdb) b 26
Breakpoint 2 at 0x804837b: file gdb-sample.c, line 26.
(gdb) btempFunction
Breakpoint 3 at 0x804832e: file gdb-sample.c, line 12.

Use the "c" command to continue (Continue) to execute the debugged program. The program will interrupt at the second breakpoint (line 26). At this time, the value of the global variable nGlobalVar should be 88; execute the "c" command again and the program will interrupt. At the third breakpoint (line 12, at the beginning of the tempFunction function), the values ​​of the two parameters a and b of the tempFunction function should be 1 and 2 respectively:

(gdb)c
Continuing.

Breakpoint 2, main () at gdb-sample.c:26
26 printf("n = %d, nGlobalVar = %d /n", n, nGlobalVar);
(gdb) p nGlobalVar
$2 = 88
(gdb)c
Continuing.
n = 1, nGlobalVar = 88

Breakpoint 3, tempFunction (a=1, b=2) at gdb-sample.c:12
12 printf("tempFunction is called, a = %d, b = %d /n", a, b);
(gdb) p a
$3 = 1
(gdb) p b
$4 = 2

The above feedback information is all within our expectations~~

Execute the "c" command (Continue) again, because there are no other breakpoints later, and the program will continue to execute until the end:

(gdb) c
Continuing.
tempFunction is called, a = 1, b = 2
n=3
Program exited normally.

Sometimes you need to see the assembly code generated by the compiler for assembly-level debugging or tracing. How to do this?

This requires the display command "display /i $pc" (this command has been explained in detail previously):

(gdb) display /i $pc
(gdb)

After that, when the program is interrupted, the assembly code can be displayed:

(gdb) r
Starting program: /home/liigo/temp/test_jmp/test_jmp/gdb-sample

Breakpoint 1, main () at gdb-sample.c:19
19 n = 1;
1: x/i $pc 0x804835c <main+16>: movl $0x1,0xfffffffc(%ebp)

I saw the assembly code. The assembly code corresponding to "n = 1;" is "movl $0x1,0xfffffffc(%ebp)".

And every time the program is interrupted in the future, the next assembly specification will be displayed (the "si" command is used to execute an assembly code - different from "s" which executes a line of C code):

(gdb)si
20n++;
1: x/i $pc 0x8048363 <main+23>: lea 0xfffffffc(%ebp),%eax
(gdb)si
0x08048366 20 n++;
1: x/i $pc 0x8048366 <main+26>: incl (%eax)
(gdb)si
21n--;
1: x/i $pc 0x8048368 <main+28>: lea 0xfffffffc(%ebp),%eax
(gdb)si
0x0804836b 21 n--;
1: x/i $pc 0x804836b <main+31>: decl (%eax)
(gdb)si
23 nGlobalVar += 100;
1: x/i $pc 0x804836d <main+33>: addl $0x64,0x80494fc

Next we try the command "b *".

For the sake of simplicity, it is necessary to first delete all current breakpoints (use the "d" command - Delete breakpoint):

(gdb)d
Delete all breakpoints? (y or n) y
(gdb)

When asked if you want to delete all breakpoints, enter "y" and press Enter.

The following uses the command "b *main" to set a breakpoint at the prolog code of the main function (prolog and epilog, respectively, represent the code inserted by the compiler at the beginning and end of each function):

(gdb) b *main
Breakpoint 4 at 0x804834c: file gdb-sample.c, line 17.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/liigo/temp/test_jmp/test_jmp/gdb-sample

Breakpoint 4, main () at gdb-sample.c:17
17 {
1: x/i $pc 0x804834c <main>: push %ebp
(gdb)si
0x0804834d 17 {
1: x/i $pc 0x804834d <main+1>: mov %esp,%ebp
(gdb)si
0x0804834f in main () at gdb-sample.c:17
17 {
1: x/i $pc 0x804834f <main+3>: sub $0x8,%esp
(gdb)si
0x08048352 17 {
1: x/i $pc 0x8048352 <main+6>: and $0xfffffff0,%esp
(gdb)si
0x08048355 17 {
1: x/i $pc 0x8048355 <main+9>: mov $0x0,%eax
(gdb)si
0x0804835a 17 {
1: x/i $pc 0x804835a <main+14>: sub %eax,%esp
(gdb)si
19 n = 1;
1: x/i $pc 0x804835c <main+16>: movl $0x1,0xfffffffc(%ebp)

At this time, you can use the "ir" command to display the current value in the register - "ir" is "Information Register":

(gdb) i r
eax 0xbffff6a4-1073744220
ecx 0x42015554 1107383636
edx 0x40016bc8 1073834952
ebx 0x42130a14 1108544020
esp 0xbffff6a0 0xbffff6a0
ebp 0xbffff6a8 0xbffff6a8
esi 0x40015360 1073828704
edi 0x80483f0 134513648
eip 0x8048366 0x8048366
eflags 0x386 902
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x33 51

Of course, you can also display any specified register value:

(gdb) i r eax
eax 0xbffff6a4-1073744220

The last command to be introduced is "q", which quits (Quit) the GDB debugging environment:

(gdb) q
The program is running. exit anyway? (y or n)

to add on

gdb tutorial: MOOC-Linux C Language Pointers and Memory-Chapter 3

If the source code is deleted, auxiliary information such as line numbers cannot be displayed.

gcc -g gdb.c -o gdb.out # -g supports gdb debugging; -o output, default is a.out

gdb gdb.out # Enter the gdb debugging environment
enter # Continue executing the previous command
l # List source code, default 10 lines, press l to continue

start # Start single-step debugging, the default is the first line of main()
p a # View the value of a variable
n # Continue to the next line
s # Enter sub-function
bt # View function stack
f 1 # Switch function stack

q Exit debugging

Code for testing

#include <stdio.h>

void change(int a, int b){
     int tmp=a;
     a=b; b=tmp;
}

void change2(int *a, int *b){
     int tmp=*a;
     *a=*b; *b=tmp;
}

int main(){
     int a=5,b=3;
     change(a,b);
     printf("change:\na=%d\nb=%d\n", a,b);
     change2(&a,&b);
     printf("change2:\na=%d\nb=%d\n", a,b);
}