-
Alexander Schoch authoredAlexander Schoch authored
\begin{center} {\Large \textbf{Debugging on Linux}} \end{center}
Print Debugging
\begin{center} Most often, debugging is done via print... \linebreak
...But that scales poorly \end{center}
GDB
\begin{center} A Debugger (such as GDB) can help here \end{center}
GDB
What is GDB?
GDB is a tool to inspect your program while it is running. It allows:
- to stop program execution at any point
- step through the program
- print the value of variables
- modify variables
Usage
Before running a program in GDB, it needs to be compiled with debug symbol.
- Available compiler flags flags are
-g
,-g3
,-ggdb3
-
-ggdb3
gives the most debug information
The program can then be run under gdb: gdb ./a.out
An Example...
#include<stdio.h>
#include<stdbool.h>
#include<tgmath.h>
bool is_prime(int number) { /* snip */ }
int
main(int argc, char** argv) {
int number;
scanf("%d", &number);
if (is_prime(number))
printf("%d: prime\n", number);
else
printf("%d: not prime\n", number);
return 0;
}
An Example...
$ gcc -ggdb3 simple.c -lm
$ gdb ./a.out
GNU gdb (GDB) 8.3.1
Copyright (C) 2019 Free Software Foundation, Inc.
...snip...
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...
(gdb)
The Start Command
- start
- starts program execution and stops it at the beginning of main
(gdb) start
Temporary breakpoint 1 at 0x11c7: file simple.c, line 16.
Starting program: /home/dcm/misc/debugging-on-linux/code/gdb-examples/a.out
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffdf18) at simple.c:16
16 main(int argc, char** argv) {
(gdb)
The Step Command
- step
- executes the next line. If there's a function, it will step into it.
(gdb) start
Temporary breakpoint 1 at 0x11c7: file simple.c, line 16.
Starting program: /home/dcm/misc/debugging-on-linux/code/gdb-examples/a.out
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffdf18) at simple.c:16
16 main(int argc, char** argv) {
(gdb) step
18 scanf("%d", &number);
(gdb)
The Next Command
- next
- executes the next line. If there's a function, DO NOT step into it.
(gdb) start
Temporary breakpoint 1 at 0x11c7: file simple.c, line 16.
Starting program: /home/dcm/misc/debugging-on-linux/code/gdb-examples/a.out
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffdf18) at simple.c:16
16 main(int argc, char** argv) {
(gdb) step
18 scanf("%d", &number);
(gdb) next
1234567
19 if (is_prime(number))
(gdb)
The Print Command
- prints the contents of variables. It also allows calling functions.
(gdb) step
18 scanf("%d", &number);
(gdb) next
1234567
19 if (is_prime(number))
(gdb) print number
$1 = 1234567
(gdb) print is_prime(number)
$2 = false
(gdb)
The List Command
- list
- lists the 10 lines of source code surrounding the current one
(gdb) next
1234567
19 if (is_prime(number))
(gdb) list
14
15 int
16 main(int argc, char** argv) {
17 int number;
18 scanf("%d", &number);
19 if (is_prime(number))
20 printf("%d: prime\n", number);
21 else
22 printf("%d: not prime\n", number);
23 return 0;
(gdb)
The Break Command
- break
- adds a break point, which will stop program execution when reached
(gdb) list
14
15 int
16 main(int argc, char** argv) {
17 int number;
18 scanf("%d", &number);
19 if (is_prime(number))
20 printf("%d: prime\n", number);
21 else
22 printf("%d: not prime\n", number);
23 return 0;
(gdb) break 22
Breakpoint 2 at 0x555555555214: file simple.c, line 22.
(gdb)
The Continue Command
- continue
- continues program execution until either a breakpoint is hit or the programs exits
(gdb) break 22
Breakpoint 2 at 0x555555555214: file simple.c, line 22.
(gdb) continue
Continuing.
Breakpoint 2, main (argc=1, argv=0x7fffffffdf08) at simple.c:22
22 printf("%d: not prime\n", number);
(gdb)
The Quit Command
- quit
- quits GDB, terminating the program
(gdb) continue
Continuing.
Breakpoint 2, main (argc=1, argv=0x7fffffffdf08) at simple.c:22
22 printf("%d: not prime\n", number);
(gdb) quit
A debugging session is active.
Inferior 1 [process 7431] will be killed.
Quit anyway? (y or n) y
$
Text User Interface
GDB can also be run with a TUI: gdb -tui ./a.out
Text User Interface
\begin{center} \includegraphics[width=0.75\textwidth]{img/gdb-tui.png} \end{center}
Valgrind
Quick Warning
The following is slide code and output, therefore all source code and program output is heavily shortend.
Valgrind
- Collection of usefull debugging tools
- Memcheck
- Helgrind
- Works on any executable
- Doesn't require recompilation
- Output gets more readable with debug symbols!
How to use Valgrind?
- (optionally) Recompile the program with debug symbols
- Choose a tool
- Run the program under valgrind:
valgrind --tool=$TOOL ./a.out
Memcheck
Memcheck
- finds common memory errors
- Use after free
- Use of uninitialised values
- Memory leaks
- ...and many more
- Usage:
valgrind [--leak-check=full] ./a.out
Use After Free
- Use After Free
- Usage of a pointer after it has been
free()
'd
Use After Free
#include<stdlib.h>
int
main(int argc, char **argv) {
int *ip;
ip = malloc(sizeof(int));
free(ip);
*ip = 3;
return 0;
}
Use After Free
==4474== Memcheck, a memory error detector
..snip..
==4474== Invalid write of size 4
==4474== at 0x109176: main (uaf.c:8)
==4474== Address 0x4a86040 is 0 bytes inside a block of size 4 free'd
==4474== at 0x48399AB: free (vg_replace_malloc.c:540)
==4474== by 0x109171: main (uaf.c:7)
==4474== Block was alloc'd at
==4474== at 0x483877F: malloc (vg_replace_malloc.c:309)
==4474== by 0x109161: main (uaf.c:6)
==4474==
..snip..
Uninitialized Values
- Unitialized Values
- Use of a variable or memory before it has been initialized
Uninitialized Values
#include<stdio.h>
int
main(int argc, char **argv) {
int i;
if (i)
printf("Hui\n");
else
printf("Pfui\n");
return 0;
}
Uninitialized Values
==7096== Memcheck, a memory error detector
..snip..
==7096== Conditional jump or move depends on uninitialised value(s)
==7096== at 0x10914C: main (ui.c:6)
==7096==
Pfui
==7096==
..snip..
Memory Leaks
- Memory Leak
- A piece of memory is
malloc()
'd, but neverfree()
'd
Memory Leaks
#include<stdlib.h>
int
main(int argc, char **argv) {
int *p;
p = malloc(sizeof(int));
return 0;
}
Memory Leaks
==7219== Memcheck, a memory error detector
..snip..
==7219== HEAP SUMMARY:
==7219== in use at exit: 4 bytes in 1 blocks
==7219== total heap usage: 1 allocs, 0 frees, 4 bytes allocated
==7219==
==7219== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==7219== at 0x483877F: malloc (vg_replace_malloc.c:309)
==7219== by 0x109151: main (ms.c:6)
==7219==
==7219== LEAK SUMMARY:
==7219== definitely lost: 4 bytes in 1 blocks
==7219== indirectly lost: 0 bytes in 0 blocks
==7219== possibly lost: 0 bytes in 0 blocks
==7219== still reachable: 0 bytes in 0 blocks
==7219== suppressed: 0 bytes in 0 blocks
..snip..
Helgrind
Helgrind
- finds common threading problems
- Potential lock order inversions
- Race conditions
- Has problems with lock-free data structures/algorithms
- Usage:
valgrind --tool=helgrind ./a.out
Race Condition
- Race Condition
- Several Threads try to modify the same variable at the same time yielding unexpected results