Debugging C with gdb
Preface
This post was originally posted in my old blog raphaelpour.de on 06.02.2018. This is probably my most personally used blog post. Once in a while I
need to investigate a coredump that got collected by systemd-coredump
. Although the post covers only the tip of the debugging iceberg, it’s at least the tip from where you can start walking down.
Introduction
As long as the gcc tells you whats wrong (including the -Wall
flag) you can at least barely locate the source of the error. What about Segmentation Faults which are hard to detect during compilation time? The GNU Debugger (short gdb) may give you a clue!
Gdb is a command line debugger for investigating binaries. Especially when the binary was compiled with debug information, the debugger can tell us a bit more about its state.
Starting over with segmentation faults
For example look at the following code which provokes a segmentation faults by writing to unallocated memory.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void getLyrics(char* lyricBuffer){
char *segFaultLyrics = "SegFault, SegFault! Whatcha gonna do? Whatcha gonna do when I come for you?";
memcpy(lyricBuffer, segFaultLyrics, strlen(segFaultLyrics));
}
int main()
{
char* lyrics = NULL;
getLyrics(lyrics);
printf("%s\n",lyrics);
}
Let’s compile it with gcc and see what happens on execute.
$ gcc -Wall debugme1.c -o debugme1
$ ./debugme1
Segmentation fault (core dumped)
Gcc didn’t complain anything, even with the -Wall
flag.
In order to start over with the gdb, we have to compile our program with debug information. This can be achieved by adding the -g
flag to the gcc parameter list.
$gcc -Wall debugme1.c -g -o debugme1
$gdb debugme1
Reading symbols from debugme1...done.
(gdb) r
Starting program: ~/debugme/debugme1
Program received signal SIGSEGV, Segmentation fault.
__memcpy_avx_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S:100
100 ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S: No such file or directory.
As you can see, the gdb tells you which library-function causes the error. What we can’t see is the location of this faulty library-function call in our source code. The No such file or directory error can be ignored with the assumption that our call of this function is wrong and not the original source1.
This can be accomplished with the gdb command bt
(short for back-trace).
(gdb) bt
#0 __memcpy_avx_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S:100
#1 0x000000000040060c in getLyrics (lyricBuffer=0x0) at debugme1.c:8
#2 0x000000000040062b in main () at debugme1.c:14
The back trace will print the last call stack where the faulty function is on the top. In our example we have to look at the function getLyrics
in line 8 which will be the memcpy call.
## Division by zero
Imagine you worked out a fancy formula which solve a certain problem. Especially when you use fractions you have to take care of the range of the input values. The following code will implement a formula which doesn’t care about the input value. The compiler doesn’t either.
#include <stdio.h>
#include <stdlib.h>
int magicFormula(int a, int b)
{
return a/b;
}
int main()
{
int n = magicFormula(1,0);
printf("%d\n",n);
}
This will cause a floating point exception. This isn’t directly a divison-by-zero bug. If you would change the datatype from into float , this operation would be result inf for infinity. But a float with the value inf can’t be casted into an integer. However, we will ask the gdb if he can help us out again.
$gdb debugme2
Reading symbols from debugme2...done.
(gdb) r
Starting program: ~/debugme/debugme2
Program received signal SIGFPE, Arithmetic exception.
0x0000000000400534 in magicFormula (a=1, b=0) at debugme2.c:6
6 return a/b;
In order to see more than the faulty line, we can use the gdb-command l
to list. This will maybe give us the context and a hint why the method magicFormula failed with a=1
and b=0
(gdb) l
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int magicFormula(int a, int b)
5 {
6 return a/b;
7 }
8
9 int main()
10 {
Tips ‘n’ Tricks
- your application
foo
needs argumentsbar
andbbar
? Try this:gdb --args foo bar bbar
- more debug information with the gcc flag
-g3
- there is a console-based gui included in gdb which can be opened with
gdb -tui
strip <binary>
will remove all debug information which the gcc has included into your binary- generate gdb-friendly debug information with gcc flag
-ggdb
- if you think the memcpy is wrong and want to debug it, take a look at this SO Post.