GDB Debugger
Introduction of debugger:
A debugger is a program which can run the program. The only difference is that it can go inside of a program and it has the ability to run step by step in the program. Debugger sometimes referred to as symbolic debugger also.
GDB Debugger:
GDB is a debugger which is part of the Free Software Foundation's GNU operating system. Its original author is Richard M. Stallman. GDB can be used to debug C, C++, Objective-C, Fortran, Java and Assembly programs. There's partial support for Modula-2 and Pascal. It'll run on any architecture.
Compile source code:
In order to debug a file, first you need to compile the program. In case of gcc compiler you need -g option to compile the source code so that the output file is ready to debug with GDB. For example, if the source file is hello-world.c, the command for compilation will be:
gcc -g -o hello_world hello_world.c
This command will create the output/executable file named as hello_world. You have to debug the source file with this executable file.
Run GDB debugger:
In order to run the GDB debugger, the command is:
gdb hello_world
It will display the license agreement and the you will be able to see the GDB prompt (GDB). It means that you are under GDB debugger and you are all ready to start debugging your source program.
Listing of source file:
The list command, abbreviated by l will show you the the source program from the gdb command prompt. By default, GDB always displays 10 lines of the source code. First time list command will print the 10 lines of the source code centered on main(). Subsequent uses of list displays the next 10 lines of the source code.
List – works similar like list but in reverse order.
List followed by a line number will display 10 lines centered on that line number.
Other listing operations you'll find useful:
starting with some line number(gdb) list 5,
ending with some line number (gdb) list ,28
between two numbers: (gdb) list 21,25
by function name: (gdb) list f
functions in the other file: (gdb) list CentralDiff
by filename and line number: (gdb) list derivative.c:12
filename and function name: (gdb) list derivative.c:ForwardDiff
Listing by Memory Address:
If you know the memory location of any function then with that memory location alos you can use list command to display 10 lines of code.
Example: list *0x801234b
Change the default list size:
The below command will change the list size from default 1o to 20
set listsize 20
Running a program in GDB:
The run command is responsible to run the program. Run command without any argument will run the program without command line arguments. You can specify command line arguments in the below way:
(GDB) run one two three
It means argument #1 is one
argument #1 is two
argument #1 is three
Restarting a program in GDB:
There are several ways to do that:
Quit GDB and start again
Use the kill command to stopl the program and run command to restart it again.
Use the command run. It will ask you that the program is already running. So whether you really want to start from the beginning or not?
Some important commands:
We can use the command “back trace” (bt) to get the stack information of the running process. It will display the stack.
bt will display the stack. Each entry in the stack is aasociated with an integer number. So if there is any function call from the main function then there will be two entries in the stack. One for the main function and another for the new function call. Now when we are in the function body, we can move to the main function with the below command(considering main function has the frame number 1):
(gdb)frame 1
Breakpoints:
We can resume a running program in three different ways. Here are the three ways:
Breakpoint: It stops a program whenever a particular point in the program is reached.
Watchpoint: It stops a program whenever the value of a variable or expression changes.
Catchpoint: It stops a program whenever a particular event occurs.
A breakpoint stops a program at a particular point of the program. For example, it can stop the program when the execution is at the line number 10 or when the execution enters the function display() or when the execution is at the line number 20 of the source file other.c
There are four major ways to set up the breakpoint:
1. By Function name.
2. By Line number.
3. By filename and line number.
4. By address.
By function name:
We can assign the breakpoint by function name in the below fashion:
(GDB) break main.
The "break main" command sets a breakpoint at the top of main().
By line number:
We can assign the breakpoint by line number in the below fashion:
(GDB) break 10
It will create the breakpoint at the line number 10 and program execution will resume at line number 10. But one important point to remember is that internally the program execution is at the middle of line number 9 and 10. Line number 9 has been executed but line number 10 is not yet executed. It is waiting for the execution. If you give the command “next” then only the line number 10 will be executed.
By filename and line number:
A third way of setting breakpoints is with a filename and line number, separated with a colon. Let's set a breakpoint at line 10 of hello_world.c:
(gdb) break hello_world.c:10
Breakpoint 3 at 0x80483fd: file hello_world.c, line 10.
By address:
A fourth way of setting breakpoints is with a memory address within the process's VM space. First try to identify the address of the main function and then assign the breakoint at main with its own memory address.
(gdb) print main
$1 = {int (const char *)} 0x80483f4 <main>
(gdb) break *0x80483f4
Breakpoint 4 at 0x80483f4: file hello_world.c, line 7.
Breakpoint numbers:
Every breakpoint is given a particular integer number starting from 1. We can refer a breakpoint with its integer number also. We can see all our breakpoints with the command:
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x08048464 in main at main.c:6
breakpoint already hit 1 time
2 breakpoint keep y 0x0804846b in main at main.c:9
breakpoint already hit 1 time
3 breakpoint keep y 0x08048477 in main at main.c:12
The Num field gives the identifier. The type field gives the type of the breakpoints. The Disp field (disposition) describes what will happen to the breakpoint to the next time. Keep means nothing will happen. Allthough we can disable or delete a particular breakpoint.
Disable / Enable a particular breakpoint:
We can disbale a particular breakpoint in this way.
(gdb)disbale 2
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x08048464 in main at main.c:6
breakpoint already hit 1 time
2 breakpoint keep n 0x0804846b in main at main.c:9
breakpoint already hit 1 time
3 breakpoint keep y 0x08048477 in main at main.c:12
Now see the breakpoint 2 status is disabled.
We can again enable the breakpoint in the below way:
(gdb)enabale 2
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x08048464 in main at main.c:6
breakpoint already hit 1 time
2 breakpoint keep y 0x0804846b in main at main.c:9
breakpoint already hit 1 time
3 breakpoint keep y 0x08048477 in main at main.c:12
Delete the breakpoint(s):
If you want to remove the breakpoint by its location, use clear.
If you want to remove the breakpoint by its identifier, use delete.
(gdb) clear *0x80483f4
Deleted breakpoint 4
(gdb) clear fgets.c:10
Deleted breakpoint 3
(gdb) clear 9
Deleted breakpoint 2
(gdb) clear main
Deleted breakpoint 1
(gdb)
The delete command deletes breakpoints by identifier, as opposed to clear which removes breakpoints based on their location. In fact, delete n deletes the breakpoint with identifier n.
Resume a running program:
Here are the details:
1. Continue: We can resume the execution of a program by the command “continue”.
2. Next: Execute a single line in the program but treat function calls as a single line. This command is used to skip over function calls.
3. Step: Execute a single line in the program. If the current statement calls a function, the function is single stepped.
Inspecting a variable:
We can see the vale of a variable by the command “print'. For example, if we want to print the value of the variable I, then the command will be:
(gdb)print I
We can use the command “ptype” to see the type of the variable for example whether the variable is an interger or float or double etc. We can use ptype to look at the structure also.
Inspecting arrays and structures:
The below command will display the contents of an array:
(gdb) p myIntArray
$46 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
If you want to print 5 elements of myIntArray, starting at element 3:
(gdb) p myIntArray[3]@5
$49 = {3, 4, 5, 6, 7}
You can also print structures:
(gdb) p myStruct
$2 = {name = 0x40014978 "Miles Davis", EyeColour = 1}
Since it does not looks good. You can set pretty printing of structures by set print pretty:
(gdb) set print pretty
(gdb) p myStruct
$4 = {
name = 0x40014978 "Miles Davis",
EyeColour = 1
}
(gdb)
if you only want one of the elements of the structure, you can print it in the way
(gdb) print myStruct.name
$6 = 0x40014978 "Miles Davis"
Changing Variables:
We can change a variable in the below way:
set myvar = 10;
Finding out the current execution position:
The command is “where”
Debugging a running process:
In order to do that first we need to run the process as a background job. We can do that in this way:
$ ./print-the-number &
It will show the process number.
After that we can start gdb session with that process number in the below way(considering the process number is 17399):
$ gdb print-the-number 17399
Attaching to program: code/running_process/print-the-number, process 17399
0x410c64fb in nanosleep () from /lib/tls/libc.so.6
(gdb)
There is another way to attach a process with the gdb session. The command is “attach”.
$gdb
(gdb) attach 17399.
It will attach the process with this gdb session.
Now if we want we can use detach command to detach the process from the gdb session.
Note: One important point to remember here is that when we attach any running process with the gdb session the process pauses at that point. Again when we will detach or quit from the gdb session, the process will start executing from that position only.
Debugging an infinite loop example:
Consider the below program inf.c:
//inf.c //program to debug infinite loop #include<stdio.h> #include<ctype.h> int main(int argc, char *argv[]) { char c; c = fgetc(stdin); while(c!=EOF) { if(isalnum(c)) printf("%c",c); else c = fgetc(stdin); } return 1; }
Lets first compile the program:
$ gcc -W -Wall -g -o inf inf.c
Now run the progarm:
$./inf
Sudipta
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSS…………………
So it seems from the o/p that the problem is because of infinite loop. Now let us do the debug with GDB.
$gdb inf
(gdb) run
Starting program:/home/sudipta/inf
Sudipta
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSSSSSSSSSSSS^C
Program received signal SIGINT, Interrupt.
0xb80f7430 in __kernel_vsyscall ()
(gdb)bt
#0 0xb80f7430 in __kernel_vsyscall ()
#1 0xb8041393 in write () from /lib/tls/i686/cmov/libc.so.6
#2 0xb7fdab3c in _IO_file_write () from /lib/tls/i686/cmov/libc.so.6
#3 0xb7fdbcb7 in _IO_do_write () from /lib/tls/i686/cmov/libc.so.6
#4 0xb7fdb765 in _IO_file_overflow () from /lib/tls/i686/cmov/libc.so.6
#5 0xb7fde4e3 in __overflow () from /lib/tls/i686/cmov/libc.so.6
#6 0xb7fd3507 in putchar () from /lib/tls/i686/cmov/libc.so.6
#7 0x080484c0 in main () at inf.c:16
Now lets go to the main function and print the value of c
(gdb) frame 7
#7 0x080484c0 in main () at inf.c:16
16 printf("%c",c);
(gdb) p c
$1 = 83 'S'
Now do some next and we will get the below o/p:
(gdb) n
Single stepping until exit from function putchar,
which has no line number information.
main () at inf.c:13
13 while(c!=EOF)
(gdb) n
15 if(isalnum(c))
(gdb) n
16 printf("%c",c);
(gdb) n
13 while(c!=EOF)
(gdb) n
15 if(isalnum(c))
(gdb) n
16 printf("%c",c);
(gdb) n
13 while(c!=EOF)
(gdb) n
15 if(isalnum(c))
(gdb) n
16 printf("%c",c);
(gdb) n
13 while(c!=EOF)
From this it looks like that the lines 13-16 are repeating every time. And this is the reason of this infinite loop problem. So now we identified the problem of infinite loop.


LinkBack URL
About LinkBacks




Reply With Quote



Bookmarks
Algorithms and Data Structures
Java tutorials
Algorithms Forum