IdeaMonk

thoughts, ideas, code and other things...

Saturday, August 15, 2009

GDB, Why didn't I use you all this time.... ?!

My first introduction to gdb was through "Hacking - The art of exploitation", a book on writing exploits and many other basics of network/application security by Jon Erickson. During those days, I neither ran linux on my machine, nor did I care to go deep into tools explained in the book. Installing Gentoo, which was used to write examples of the book was a painful experience. And I did not know of the wonderful offsprings of mother Debian like Ubuntu!
Anyways coming to the point, I seriously wonder why don't they teach gdb at our colleges. I just realised that just two weeks back we had network simulation lab, one boy said "Ma'am I got segmentaton fault! I'll do it next time..." and the teacher too, aware of the mysteries of segmentation fault, let him go. Forget mysteries, everyone in my college knows debugging as a painful task that involves putting printfs everywhere in your code. And, that's not all, it alone doesn't assure where the hell things went wrong, then you start printing the values too, its more of a guesswork! Now think about this - they wrote the linux kernel in C right ? did they debug their way to every new releases by putting a printf before every damn line ?! And before the release, did they spend sleepless nights just removing those printf patches left out here n there! Nopes, not at all.
Anyways lol, coming back to the point, let me show you some nice things about gdb, the GNU Debugger that I just found out right now reading 'Developing with Gnome'
Consider this code -
#include <stdio.h>

int total;

foo(){
// calls bar() 5 times
int i=5;
while (i--)
bar();
}

bar(){
// calls baz() 2 times
int i=2;
while (i--)
baz();
}

baz(){
total++;
}

int main (){
// just calls up other funcs that do something on total
total = 0;

foo();
bar();

printf ("%d\n",total);

return 0;
}
As you can see, it increments a global integer total 5X2 times using foo() and then 2 times more by a call to bar() in main(), final output being 12. Simple enough! I've just nested the functions to stress on the fact that bigger programs can be tough to debug.

ideamonk@sacea:~$ gcc segfault.c
ideamonk@sacea:~$ ./a.out
12
ideamonk@sacea:~$

Now I'll add some weird lines to the code and try to get a segmentation fault.
Let's modify foo() as this -
foo(){
// calles bar() 5 times
int i=5;

char c1='a',*c=&c1;
while (i--){
printf ("%c ", *c);
c+=0xdeadbeef;
*c++;
bar();
}
}

What it tried to do is, have a pointer to a character, shift that pointer in insanely far that it exceeds permissible addressing, and poof! get us a segmentation fault. Here it is -

ideamonk@sacea:~$ gcc segfault.c
ideamonk@sacea:~$ ./a.out
Segmentation fault
ideamonk@sacea:~$

That's it, all I get is a segmentation fault. Now someone right from my computer programming course would go about debugging this by putting printfs before every possible suspect lines :P. But with gdb, you can actually pinpoint the line where it broke, see the source and even find out which functions were called in what order, and even more, we also get to have a look at values of local variables. What more could've anyone wanted. Let me show you how gdb makes debugging easy as a pie -

// we'll ask gcc to turn debugging flags on and optimization flags off by a -g
ideamonk@sacea:~$ gcc -g segfault.c
ideamonk@sacea:~$ gdb a.out
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu"...
// lets run our code
(gdb) run
Starting program: /home/ideamonk/a.out

Program received signal SIGSEGV, Segmentation fault.
0x000000000040052d in foo () at segfault.c:12
12 printf ("%c ", *c);
// Look at that! there we have it, which line, what was there, we know all :)
// lets seek more
// list would give us codeblock where it occured
(gdb) list
7 int i=5;
8
9 char c1='a',*c=&c1;
10
11 while (i--){
12 printf ("%c ", *c);
13 c+=0xdeadbeef;
14 *c++;
15 bar();
16 }
// we'll take a look at local vars now
(gdb) info locals
i = 3
c1 = 97 'a'
c = 0x8000599580ff

// there you have it :) the pointer c went out of bounds as intended
// as I said we can look at the order of function calls, here it is
(gdb) backtrace
#0 0x000000000040052d in foo () at segfault.c:12
#1 0x00000000004005c4 in main () at segfault.c:34
(gdb) ^D


Now you exactly know what went wrong and where, get back to your editors and you know exactly which line number is the bug you need to squash.
Happy debugging and a Happy Independence day to one and all :)
on #linux-india one guy asked me this when I greeted with the usual "Happy Independence Day!" thingie -
"What are you happy about?", "Why so happy?"
It set me thinking, what for? I could come up with one answer, "I'm happy for the possibility of getting a free jalebi tomorrow.", for I realised that there isn't any answer to "Are we free?", I guess we're not, unless we abandon the common road on which everyone walks and take the road not taken. I would like to take it :)

Labels: , ,

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home