Skip to content

Commit df919a1

Browse files
authored
Merge pull request #7 from cs-ieee-ist/gdb
Add GDB topic
2 parents 766d752 + b5ae94e commit df919a1

File tree

5 files changed

+439
-1
lines changed

5 files changed

+439
-1
lines changed

content/topics/gdb/assembly.md

+108
Original file line numberDiff line numberDiff line change
@@ -1 +1,109 @@
11
# GDB - Assembly
2+
3+
There are several occasions where you need to debug at the assembler level. It can be, for example, to understand how the compiler is generating your code and how that code is behaving.
4+
5+
## Machine Language related commands
6+
7+
Before we start going through an example, we need to introduce some Assembly related commands:
8+
9+
| Command | Short version | Description |
10+
| ------- | ------------- | ----------- |
11+
| info line | | Displays the start and end position of the compiled code for the current line |
12+
| info line number | | Display position in object code for a specified line |
13+
| disassemble *start_address* *end_address* | | Displays machine code for positions in object code specified, start and end memory values are optional |
14+
| stepi | si | step assembly instruction |
15+
| nexti | ni | next assembly instruction |
16+
| x *address* | | Examine the contents of memory |
17+
x/nfu *address* | | Examine the contents of memory with a specific format. n: number of display items to print (default is 1), f: specify the format for the output i - instr, s-string, x-hex, d-sdecimal, u-udecimal, o-octal, t-binary, a-addr, c-char ,f-float, u: specify the size of the data unit b-byte, h-halfword, w-word, g-giant (8 bytes)|
18+
19+
## Debug
20+
21+
**Program**
22+
23+
```c
24+
#include <stdio.h>
25+
26+
int main() {
27+
int a = 1;
28+
a = a + 2;
29+
printf("a: %d\n", a);
30+
return 0;
31+
}
32+
```
33+
34+
**Compile and open GDB**
35+
36+
```bash
37+
~ $ gcc -g hello.c
38+
~ $ gdb ./a.out
39+
```
40+
41+
**Start execution**
42+
43+
```bash
44+
(gdb) b main
45+
(gdb) r
46+
```
47+
48+
So far everything we have done is just the usual setup. Now we want to start analysing the machine code. You can find the Assembly code specific commands at the table above. To start let's display the start and end memory position of the current line.
49+
50+
```bash
51+
(gdb) info line
52+
Line 3 of "hello.c" starts at address 0x8001149 <main> and ends at 0x8001155 <main+12>.
53+
```
54+
55+
We can also display the compiled code that corresponds to the "main" function.
56+
57+
```bash
58+
(gdb) disassemble
59+
=> 0x0000000008001149 <+0>: endbr64
60+
0x000000000800114d <+4>: push %rbp
61+
0x000000000800114e <+5>: mov %rsp,%rbp
62+
0x0000000008001151 <+8>: sub $0x10,%rsp
63+
0x0000000008001155 <+12>: movl $0x1,-0x4(%rbp)
64+
0x000000000800115c <+19>: addl $0x2,-0x4(%rbp)
65+
0x0000000008001160 <+23>: mov -0x4(%rbp),%eax
66+
0x0000000008001163 <+26>: mov %eax,%esi
67+
0x0000000008001165 <+28>: lea 0xe98(%rip),%rdi # 0x8002004
68+
0x000000000800116c <+35>: mov $0x0,%eax
69+
0x0000000008001171 <+40>: callq 0x8001050 <printf@plt>
70+
0x0000000008001176 <+45>: mov $0x0,%eax
71+
0x000000000800117b <+50>: leaveq
72+
0x000000000800117c <+51>: retq
73+
```
74+
75+
Now we can follow the execution one instruction at a time using the "stepi" command.
76+
77+
```bash
78+
(gdb) stepi
79+
(gdb) disassemble
80+
0x0000000008001149 <+0>: endbr64
81+
=> 0x000000000800114d <+4>: push %rbp
82+
0x000000000800114e <+5>: mov %rsp,%rbp
83+
0x0000000008001151 <+8>: sub $0x10,%rsp
84+
0x0000000008001155 <+12>: movl $0x1,-0x4(%rbp)
85+
0x000000000800115c <+19>: addl $0x2,-0x4(%rbp)
86+
0x0000000008001160 <+23>: mov -0x4(%rbp),%eax
87+
0x0000000008001163 <+26>: mov %eax,%esi
88+
0x0000000008001165 <+28>: lea 0xe98(%rip),%rdi # 0x8002004
89+
0x000000000800116c <+35>: mov $0x0,%eax
90+
0x0000000008001171 <+40>: callq 0x8001050 <printf@plt>
91+
0x0000000008001176 <+45>: mov $0x0,%eax
92+
0x000000000800117b <+50>: leaveq
93+
0x000000000800117c <+51>: retq
94+
```
95+
96+
To finish we can set a new breakpoint at the line where we add plus 2 to the "a" variable and watch the value at the memory address change.
97+
98+
```bash
99+
(gdb) b 5
100+
(gdb) c
101+
(gdb) p &a
102+
$3 = (int *) 0x7ffffffedebc
103+
(gdb) x/1d 0x7ffffffedebc
104+
0x7ffffffedebc: 1
105+
(gdb) x/1d 0x7ffffffedebc
106+
0x7ffffffedebc: 3
107+
```
108+
109+

content/topics/gdb/commands.md

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# GDB - List of Commands
2+
3+
## Basic Commands
4+
5+
| Command | Short version | Description |
6+
| ------- | ------------- | ----------- |
7+
| run | r | The run command causes execution of the program to start from the beginning |
8+
| quit | q | Exit GDB debugger |
9+
| breakpoint *location* | b *location* | The breakpoint command sets a breakpoint in a certain location. (line, function, etc) |
10+
| print *expression* | p *expression* | This will print the value of the given expression. |
11+
| continue | c | Continues execution following a breakpoint, until the next breakpoint or the termination of the program. |
12+
| step | s | Executes a single line after a breakpoint. |
13+
| next | n | Executes a single line. If this line is a subprogram call, executes and returns from the call. |
14+
| list | l | Lists a few lines around the current source location. |
15+
| backtrace | bt | Displays a backtrace of the call chain. |
16+
17+
## Execution control
18+
19+
| Command | Short version | Description |
20+
| ------- | ------------- | ----------- |
21+
| run | r | Start program execution |
22+
| run *command-line-arguments* | r *command-line-arguments* | Start program execution |
23+
| run < *stdin-file* > *stdout-file* | r < *stdin-file* > *stdout-file* | Start program execution with IO redirection |
24+
| continue | c | Continues program execution until encounters a breakpoint |
25+
| kill | | Kills the current process |
26+
| quit | q | Exit GDB debugger |
27+
28+
## Breakpoint management
29+
30+
| Command | Description |
31+
| ------- | ----------- |
32+
| break function-name | Set a breakpoint at specified function |
33+
| break line-number | Set a breakpoint at specified line number |
34+
| break ClassName::functionName | Set a breakpoint at specified class function |
35+
| break +offset | Set a breakpoint specified number of lines forward from the current position |
36+
| break -offset | Set a breakpoint specified number of lines back from the current position |
37+
| break filename:function | Set a breakpoint at specified function inside a file |
38+
| break filename:line-number | Set a breakpoint at specified line number of a file |
39+
| break *address | Set a breakpoint at specified instruction address |
40+
| break line-number if condition | Set a breakpoint if the condition is met |
41+
| break line thread thread-number | Set a breakpoint in the thread specified by the line number |
42+
| tbreak | Set a temporary break (break once only) |
43+
| watch condition | Suspend execution when the condition is met |
44+
| clear | Delete breakpoints |
45+
| clear function | Delete all breakpoints in function |
46+
| clear *line-number* | Delete breakpoints at specified line number |
47+
| delete | Delete all breakpoints, watchpoints, or catchpoints |
48+
| delete *breakpoint-number* | Delete the breakpoint specified |
49+
| delete *breakpoint-number*-*breakpoint-number* | Delete the breakpoints inside the specified range. ex: delete 1-4 |
50+
| disable *breakpoint-number* | Disable the breakpoint specified |
51+
| disable *breakpoint-number*-*breakpoint-number* | Disable the breakpoints inside the specified range, ex: disable 1-4 |
52+
| enable *breakpoint-number* | Enable the breakpoint specified |
53+
| enable *breakpoint-number*-*breakpoint-number* | Enable the breakpoints inside the specified range, ex: enable 1-4
54+
55+
## Analyse stack
56+
57+
| Command | Short version | Description |
58+
| ------- | ------------- | ----------- |
59+
| backtrace | bt | Print stack backtrace |
60+
| backtrace full | | Print values of local variables |
61+
| frame | f | Show current stack frame
62+
| frame number | f number | Show the specified frame number |
63+
| up | | Move up a single frame |
64+
| down | | Move down a single frame |
65+
| up number | | Move up the specified number of frames in the stack |
66+
| down number | | Move down the specified number of frames in the stack |
67+
| info frame | | List address, language, address of arguments/local variables and which registers were saved in a frame.
68+
| info args | | Info arguments of the selected frame |
69+
| info locals | | Info arguments of the selected local variables |
70+
| info catch | | Info arguments of the selected exception handlers |

content/topics/gdb/core-files.md

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# GDB - Debug with core files
2+
3+
A Core Dump is a file containing a process's address space (memory) when the process terminates unexpectedly. This file is very useful for debugging, for example, segmentation faults.
4+
5+
## Generate a Core Dump file
6+
7+
Most systems by default have the core dump file generation disabled. We can check by running the following command:
8+
9+
```bash
10+
~ $ ulimit -c
11+
0
12+
```
13+
14+
To enable the creation we need to run the following commands:
15+
16+
```bash
17+
~ $ ulimit -c unlimited
18+
```
19+
20+
## The program
21+
22+
To examplify how you can use the Core Dump and the GDB to better debug your programs, we will use this very simple program:
23+
24+
```c
25+
int main() {
26+
char* s = 0;
27+
char c = s[0];
28+
return 0;
29+
}
30+
```
31+
32+
Now we can compile and run the program.
33+
34+
```bash
35+
~ $ gcc -g example.c
36+
~ $ ./a.out
37+
Segmentation fault (core dumped)
38+
```
39+
40+
Make sure that the Core Dump file was created, you can use the "ls" command.
41+
42+
## Debug
43+
44+
Now that we have the core file we can start the debug process.
45+
46+
### Open GDB
47+
48+
```bash
49+
~ $ gdb a.out core
50+
Core Dump was generated by `./a.out'.
51+
Program terminated with signal SIGSEGV, Segmentation fault.
52+
#0 0x0000563a5b9f160a in nullPtr () at hello.c:3
53+
3 char c = s[0];
54+
```
55+
56+
The first thing we are going to do is use the "backtrace" command. A program when running maintains a call stack that contains information about the functions that have been called so far. Each item in the stack is a call frame, and each frame contains both the information needed to return to its caller and the information needed to provide the local variables of the function. Backtrace is used to get a stack trace from the time when the SIGSEGV was raised. Each frame in the stack has a number, where 0 is the most recent call.
57+
58+
```bash
59+
(gdb) bt
60+
#0 0x0000563a5b9f160a in nullPtr () at hello.c:3
61+
#1 0x0000563a5b9f1621 in main () at hello.c:7
62+
```
63+
64+
This example is trivial, but in normal cases, this backtrace is essential and gives the programmer a good idea of what the problem might be.
65+
66+
In some cases it might be useful to use the "frame" command to gives us more information about each frame. For example the frame 0:
67+
68+
```bash
69+
(gdb) frame 0
70+
#0 0x0000563a5b9f160a in nullPtr () at hello.c:3
71+
3 char c = s[0];
72+
```
73+
74+
This information is the same given by the debugger when we started. This is because the operation "s[0]" is trying to access an invalid memory position (0x0), which is the problem with our program.
75+
76+

content/topics/gdb/gui.md

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# GDB - GUI
2+
3+
There are plenty of Front Ends you can use to debug your code. Here we will only talk about TUI which is built-in GDB. To see more options you can check out this [website](https://sourceware.org/gdb/wiki/GDB%20Front%20Ends).
4+
5+
## TUI
6+
7+
The GDB Text User Interface (TUI) is a terminal interface which can be used to show the source file, the assembly output, the program registers and GDB commands in separate text windows. The TUI mode is enabled by default when you invoke GDB as `gdb -tui`. You can also switch in and out of TUI mode using `tui enable` or the keyboard shortcuts `CTRL+x CTRL+a`.
8+
9+
TUI behaves the same way as the normal mode. Although it has some specific commands that can be useful
10+
11+
## TUI specific commands
12+
13+
| Command | Description |
14+
| ------- | ---------- |
15+
| layout next | Display the next layout. |
16+
|layout prev | Display the previous layout. |
17+
|layout src |Display the source window only. |
18+
|layout asm |Display the assembly window only. |
19+
|layout split |Display the source and assembly window. |
20+
|layout regs |Display the register window together with the source or assembly window. |
21+
|focus next, prev, src, asm, regs, split | Set the focus to the named window. This command allows changing the active window so that scrolling keys can be affected by another window. |
22+
|refresh |Refresh the screen. This is similar to using C-L key. |
23+
|update |Update the source window and the current execution point. |
24+
|winheight name +count | Increase the height of the window name by count lines. |
25+
| winheight name -count | Decrease the height of the window name by count lines. |
26+
27+
## Example
28+
29+
Hello World program:
30+
31+
```c
32+
#include <stdio.h>
33+
34+
int main() {
35+
int a = 0;
36+
a = 2;
37+
printf("%s\n", "Hello World");
38+
return 0;
39+
}
40+
```
41+
42+
Compile and run:
43+
44+
```bash
45+
~ $ gcc -g hello.c
46+
~ $ ./a.out
47+
Hello World
48+
```
49+
50+
Start GDB:
51+
52+
```bash
53+
~ $ gdb -tui ./a.out
54+
```
55+
56+
You will see that you have the same GDB layout with the prompt but now you also have a big rectangle at the top. This is where all the information will be shown, for example, the source code or the executable disassembled. To show the source code you can run the following command:
57+
58+
```bash
59+
(gdb) layout src
60+
```
61+
62+
Let's create a breakpoint at lines 4, 5 and 6:
63+
64+
```bash
65+
(gdb) b hello.c:4
66+
(gdb) b hello.c:5
67+
(gdb) b hello.c:6
68+
```
69+
70+
Now at the source code will appear b+ in lines 4, 5 and 6.
71+
72+
Run:
73+
74+
```bash
75+
(gdb) run
76+
(gdb) p a
77+
(gdb) c
78+
(gdb) p a
79+
(gdb) c
80+
```
81+
82+
Everything works as expected, and now we have a graphical interface that helps us making the debug more visual. Let's continue the execution:
83+
84+
```bash
85+
(gdb) layout next
86+
```
87+
88+
This will show the assembly code of our example from the current breakpoint. This can be a little bit overwhelming, but if you look carefully to the line after the current you will see that the program will call the "puts" function `callq 0x8001050 <puts@plt>x,1)`. Which makes sense since our current breakpoint is supposed to be the "printf" and if we run `layout src` we can confirm that.
89+

0 commit comments

Comments
 (0)