Debugging C Programs Using gdb YASH PAL, 1 January 202428 May 2024 The debugger is the program that you use to figure out why your program isn’t behaving the way you think it should. The purpose of a debugger is to allow you to see what is going on inside your program while it runs. A debugger can be a handy tool. Many programmers use basic intuition when debugging a program. They rely on doing things like inserting cout or printf statements to help them see what values of variables are, and what point of a program has been reached at a certain time. The problem with this approach is that once your program is fixed, you have to go back and remove those cout and printf statements. A hidden ‘gotcha’ to this approach is that the very act of removing or inserting these cout and printf statements may actually introduce new bugs. The gdb debugger, like all debuggers, has tons of features. The GNU Debugger (gdb) is the debugger most Linux programmers use. You can use gdb to step through your code, set breakpoints, and examine the value of local variables. Here are some of the useful actions that gdb can perform: Start your program and step through it line by line Make your program stop on specified conditions Show the values of variables used by your program Examine the contents of any frame on the call stack Set breakpoints that will stop your program when it reaches a certain point. Then you can step through part of the execution using step and next, and type continues to resume regular execution. To learn C program debugging, let us create the following C program that calculates and prints the factorial of a number. However, this C program contains some errors in it for our debugging purpose. $ vim factorial.c #include <stdio.h> int main() { int i, num, j; printf("Enter the number:"); scanf("%d", &num); for(i = 1 ; i < num ; i ++) j = j * i; printf ("The factorial of %d is %d\n",num, j); } $ cc factorial.c$ ./a.out Output Enter the number: 3 The factorial of 3 is 12548672 Let us debug it while reviewing the most useful commands in gdb. Step 1. Compile the C program with the debugging option -gCompile your C program with -g option. This allows the compiler to collect the debugging information.$ cc -g factorial.cNote: The above command creates a out file which will be used for debugging as shown below. Step 2. Launch gdbLaunch the C debugger (gdb) as shown below.$ gbd a.out Step 3. Set up a break point inside C programSyntax:break line_numberOther formats: break [file_name]:line_number break [file_name]:func_name Places break points in the C program, where you suspect errors. While executing the program, the debugger will stop at the breakpoint and gives you the prompt to debug. So before starting up the program, let us place the following break point in our program.break 10Breakpoint 1 at 0x804846f: file factorial.c, line 10. Step 4. Execute the C program in the gdb debuggerrun [args] You can start running the program using the run command in the gdb debugger. You can also give command line arguments to the program via run args. The example program we used here does not require any command line arguments so let us give a run, and start the program execution.runStarting program: /home/sathiyamoorthy/Debugging/c/a.out Once you executed the C program, it would execute until the first break point, and give you the prompt for debugging.Breakpoint 1, main () at factorial.c: 1010 j=j*t; You can use various gdb commands to debug the C program as explained in the sections below. Step 5. Printing the variable values inside gdb debugger.Syntax: print {variable}Examples:print iprint jprint num(gdb) p i$1 = 1(gdb) p j$2 = 3042592(gdb) p num$3 = 3(gdb) As you see above, in the factorial.e, we have not initialized the variable j. So, it gets garbage value resulting in big numbers as factorial values. Fix this issue by initializing variable j with 1, compiling the C program, and executing it again. Even after this fix, there seems to be some problem in the factorial.c program, as it still gives the wrong factorial value. So, place the breakpoint in the 10th line, and continue as explained in the next section. Step 6. Continue, stepping over and in – gdb commandsThere are three kinds of gdb operations you can choose when the program stops at a breakpoint. They are continuing until the next breakpoint, stepping in, or stepping over the next program lines. c or continue: Debugger will continue executing until the next break point. n or next: Debugger will execute the next line as a single instruction. s or step: Same as next, but does not treat the function as a single instruction, instead goes into the function and executes it line by line. By continuing or stepping through you could have found that the issue is because we have not used the <= in the ‘for loop’ condition checking. So changing that from < to <= will solve the issue. gdb Command ShortcutsUse the following shortcuts for most of the frequent gdb operations. l – list: Pretty straightforward, this option permits you to list the source code of your program, either by the function name or by line number. For example, once the program is loaded, doing a ‘list main,100’ at the gdb prompt, will list 100 lines of your source code, starting at the main function. Doing a ‘list 10,100’ will list 100 lines, starting at line 10. p – print: The ‘print’ command is used to examine the contents of a variable. For example, if you were in the Crashed function above, you could do a ‘print p’ to show the contents of the ‘p’ pointer in that function. c – continue s – step: The ‘step’ command is similar to ‘next’, except that it will not step over a function if it is the next statement. Instead, it will enter the function, and suspend the program at the first line of that function. ENTER: pressing enter key would execute the previously executed command again. run: Use the ‘run’ command at the gdb prompt, to start your program running. You would probably want to set breakpoints before doing a run. Once run, your program will be suspended when it hits a breakpoint. Computer Science Tutorials Linux computer scienceLinux