Skip to main content

GNU Debugger(GDB)

GNU Debugger (GDB) is a debugging tool which helps in debugging c/c++ programs on Linux platform. Suppose you are writing a program and you want to trace the control flow of functions, then GDB is the answer.Though it's functionality is not only limited to this , you can also use GDB to add breakpoints ,to know that how the value of a variable is changing at run time, to trace the system calls ,library functions etc. Do not get confused because of so many new terms. Each term has been explained below.

Consider a scenario of you visiting your friend's house.You got ready, took your car and you are on the road. Generally it takes an hour to reach at your friend's. But today there is a police check post blocking the road. The police officers are searching each and every vehicle to solve a robbery case just happened in the city.They do not want the thief to leave the city. So they stopped you also, then checked your identification, searched your vehicle and then cleared you.

GDB works in the same way. Here a program is running. But there is a bug somewhere in that program, so at some point it will be stopped and checked that whether it is running correctly or not.

These points at which you want to define a 'police check post' are called 'breakpoints'. Breakpoints are a way of telling a program that you have to stop at a this given line number.

Why GDB?

Suppose you wrote a C program :
Now if you observe carefully,you can see that there is a bug at line 10. The comparison of 'count' variable with an integer value 5 is actually an assignment operation(count=5) instead it should be (count == 5). Because of this, the statement 'in loop' will not be printed.
To trace bugs like these ,you may want to trace the working of the program.
GDB helps you in observing this program at run time. You can stop the program at any step and check the values of all variables . Its like watching a movie in slow motion.. :-)

Compile a program which will support GDB :
To debug any program using GDB, you have to compile the program with -g option in gcc. This is done to tell the compiler to produce the output file which can be understood by the debugger. It's like everyone has been told that while driving they must have the vehicle papers with them so that they can be verified on the police check post. In a similar way, a compiler is told to produce a program which must include debugging symbol information so that they can be debugged later.
GNU Debugger can not debug a program if they have not been compiled with -g option in gcc.

command-prompt:~$ gcc -g -o programname programname.c
This will produce the executable file with debugging symbols.

Run a program using GDB
In the previous step, the program has been compiled and an executable file has been created. Next step is to run this program using GDB. The syntax to do this is :
command-prompt:~$ gdb programname
This command will start gdb for this program. After this,  run the program:
GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
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 "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/systemgenes/programname...done.
(gdb)
(gdb) run
Starting program: /home/systemgenes/programname
In main
In next function, count=5
Program exited normally.
(gdb) 
This command will start the execution of program and when the program completes ,it will exit. Now you may wonder that where is the part of 'debugging'. You don't even get a chance to see that where the bug is ?
This is because you did not stop the program. You let it complete, so it completed. To stop the program, you need to put 'police check post' i.e 'breakpoints'.
Note : Keep the bug in your mind, the printf statement 'in loop' at line 14 is not getting printed even one time though it should get printed 4 times.

Breakpoints
Breakpoints can be added for a line or a function. That is you can stop the program during execution at any given line number or a function name. But remember you should set breakpoints before running the program. First set the breakpoints, then run the program. After that the program will stop at the set breakpoints.

(gdb) break 6
Breakpoint 1 at 0x8048425: file programname.c, line 6.
(gdb) break nextFunc
Breakpoint 2 at 0x8048457: file programname.c, line 22.
Set the first breakpoint at main function if you want to trace the execution from beginning. Its a good practice to do this.
(gdb) break main
Breakpoint 3 at 0x8048423: file programname.c, line 3.
As the program will stop at these breakpoints , so you need to continue the execution to proceed further.

(gdb) continue

To delete a breakpoint , we can use clear command.
(gdb) break 6
Breakpoint 1 at 0x804841d: file programname.c, line 6.
(gdb) clear 6
Deleted breakpoint 1
To delete all breakpoints,use delete command.
(gdb) delete
Delete all breakpoints? (y or n) y

Watchpoints
You can think this term as if it is sibling of breakpoint. :-)
Breakpoints are used for a specific line or specific function where as Watchpoints are used for variables.That means if you want to check at a line or a function,then breakpoints are used, and if you want to keep track of a variable, then watchpoints are used. During the execution of a program, whenever a variable(which has been set for watchpoint) is read or write, the program will stop and you can watch the value of that variable at that instant.The general syntax of  watch is:

watch variable-name

(gdb) watch count
Watchpoint 1: count
(gdb) run
Starting program: /home/systemgenes/programname
In main
Hardware watchpoint 1: count
Old value = 0
New value = 1
main () at programname.c:10
10        if(count=5)
(gdb) c
Continuing.
Hardware watchpoint 1: count
Old value = 1
New value = 5
main () at programname.c:16
16      nextFunc(count);
Note : Due to some optimization techniques used by compilers, sometimes it might not be possible to set watchpoint for a variable(e.g if a variable is declared locally as in this case). You may get a message like this :
No symbol "foo" in current context.
See more details : GDB watchpoint-Program Variables

In those cases, set watchpoint during execution of the program i.e stop at particular line using breakpoint, then set watchpoint for that local variable.
Now, from the analysis of above debugging process , we found that the value of count is changing directly from 1 to 5 though it should have increased by 1. Bingo, we found the bug.

Some Basic Commands of GDB:

info
info command is used to get debugging information about the program which is being executed. For e.g. , to get a list of breakpoints and watchpoints set for a process.

(gdb) info break
Num   Type        Disp Enb Address    What
1     breakpoint  keep y   0x0804841d in main at programname.c:6
2     breakpoint  keep y   0x0804845a in nextFunc at programname.c:22
3     watchpoint  keep y              count 

continue
continue command is used to continue the execution of a process. Suppose a program is running and it stops at some point because of a breakpoint or watchpoint, then to continue the execution of the process, this command is used.
(gdb) continue
or
(gdb) c

backtrace
backtrace command shows a list of all the functions which are active. As whenever a function is called, it keeps track of its parent function. It does that by using stack. So using backtrace command simply means to read the stack.
(gdb) backtrace
#0  nextFunc (c=5) at programname.c:22
#1  0x0804844d in main () at programname.c:16

step and next
step and next commands are used to trace the execution of the process line by line. I found these as the most useful commands.The syntax is 'step' or 's' and 'next' or 'n'. First you need to stop the execution of the program ,say using breakpoint, then use these command to trace the execution line by line.
(gdb) break 6
Breakpoint 1 at 0x804841d: file programname.c, line 6.
(gdb) run
Starting program: /home/shubham/programname
Breakpoint 1, main () at programname.c:6
6       printf("In main\n");
(gdb) s
In main
9         count++;
(gdb) s
10        if(count=5)
(gdb) s
16      nextFunc(count);
(gdb) s
nextFunc (c=5) at programname.c:22
22      printf("In next function, count=%d\n",c);
If there is a function call, then step command steps into that function. Though if we want to skip that function, we use next command. It simply jumps to next line which is present after the function call.
-----
Your suggestions are welcome :-)

Comments

Popular posts from this blog

error: invalid application of ‘sizeof’ to incomplete type ‘struct ’

list.c:47:39: error: invalid application of ‘sizeof’ to incomplete type ‘struct Litsnode’ So, I was trying to run a program based on linked list and this is what I got. This is a very silly problem. I am mentioning it here just to help those who got frustrated like me :-\ Let me show you the line where this error occurred : 46   struct Listnode * newnode; 47   newnode = (struct Listnode *) malloc(sizeof(struct Litsnode)); Now, View it properly. Check the name(spelling) of the structure mentioned to sizeof : " struct Li ts node ". Though the defined name of the structure was : " struct Listnode " That's it.  This happens all the time that we may type something wrong. The important thing is to identify it. :-) Feel free to give any suggestions :)

Expandable Arrays in C : behind the code

Arrays. They are beautiful. In C, we always try to work through restrictions arrays have i.e the size of the array must be statically defined. We always want a dynamic array whose size can be decided at run-time. There are ways which we use widely for e.g by using pointers and then dynamically allocating memory to it using malloc or calloc. But depending on the situation, we might require more efficient and organizable ways. I will explain the concept with a series of examples as in how simple arrays evolved to the tricky expandable ones. The classic way is to use pointers This snippet will allocate a memory block of size = array_size(integer array). Though this is not what I wanted to explain because this way is too clumsy. Imagine if you need 10 dynamic arrays in your program, you have to write these four lines each time and you have to keep track of all the 10 sizes. A better way is to use structures: We can simply create a structure containing two elements: array_size and...

ssh: Could not resolve hostname git: No address associated with hostname

I came across this error when I needed to clone a git repo. I tried few times but I couldn't get it working. There were few suggestions on the internet, but none resolved my issue. So, lets get to the point, this issue may occur due to following reasons: 1. If you are using proxy to access git and it is not properly configured/proxy is not allowing you access git due to permission issues. More here: git-clone-no-address-associated-with-name getting-git-to-work-with-a-proxy-server 2. This happens due to a silly mistake. [I do make silly mistakes sometimes] Are you actually using git clone for cloning? I used this - ssh git@github.com:neovim/neovim.git instead of git clone git@github.com:neovim/neovim.git ----- Hope this have resolved your issue :-) Happy Coding.