![]() |
![]() |
Contents |
The left arrow above will return you to
the Home page
The left arrows below will return you to the Previous page
![]() |
![]() |
![]() |
Basic Debugging
If your program compiles, but doesn't work, you should compile it with the -Wall argument using gcc...i.e.
gcc -Wall test.cThis turns on all the compiler warnings, and, with any luck, may be enough to show you where you are going wrong. Make sure you fix every warning displayed, or at least understand why the warning is acceptable. In fact it is advisable to always compile your programs with the -Wall option to catch dubious programming practices.
If this doesn't turn on any lightbulbs, you can try in-program debugging by inserting printf statements through the code so that key information gets displayed as the program runs. To ensure that output actually gets displayed before a subsequent core dump, write your output to stderr which has unbufferred output. Also you may wish to use conditional compilation to turn this display on and off. e.g.
#define DEBUG ... #ifdef DEBUG fprintf(stderr,"Current command line buffer: %s\n", buffer); #endifInstead of #defineing DEBUG in your code, you can define it in the gcc command line:
Alternatively (or if you are still stuck) you can try using a debugger. A debugger allows you to "look inside" your program interactively as it runs. The debugger used with gcc on UNIX platforms is gdb - the GNU debugger. To use the debugger you must compile your code with the -g flag. i.e.gcc -Wall -D DEBUG source.c -o programgcc -g -Wall test.cgdb allows you to abbreviate commands (that is you only have to type p for print, b for break etc)
![]() |
![]() |
![]() |
Starting the Debugger
gdb a.out b main runThis runs the debugger on the executable a.out, sets a breakpoint at main and then starts the program executing. The program will stop at the start of your main program. You can now step through the program, examine the values of variables, set other breakpoints, etc
If you know which function is going wrong you can specify that function, rather than main as the first breakpoint at which to stop.
![]() |
![]() |
![]() |
Debugger Commands
- run [command line arguments]
- this sets the program running. It will run as normal until it hits a breakpoint or your program finishes (or crashes). You can put any normal command line arguments you would use with your program after the run command.
- step
- steps into the code - executes the next instruction; will step into a function.
- next
- steps over the code - stops at the next intruction in the current scope; i.e. function calls that appear within the line of code are executed without stopping.
- cont
- allows the program to continue running. It will run as normal until it hits a breakpoint or your program finishes (or crashes).
- prints the value of a variable. The following all work:
- p i
- prints the value of the variable i
- p (i + 1)
- prints the value of the variable i + 1 (i stays the same)
- p *a
- prints the value stored in the memory who's address is stored in a
- list
- lists your source code. You can say:
- l 23
- list code around line 23
- l io.c:23
- list code around line 23 of the file io.c
- l foo
- list code around the beginning of function foo
- l io.c:foo
- list code around the beginning of function foo in the file io.c
- break
- sets a breakpoint. You can say:
- b 23
- set a break point at line 23
- b foo
- set a break point at the function foo
- delete
- removes a specified breakpoint. You say:
- d 1
- removes breakpoint 1 - when you set a breakpoint the debugger tells you the breakpoint number or you can discover all current breakpoints using info break
- clear
- clear a breakpoint at specified line or function (see break above)
- info break
- lists all the break points you have set
- watch <expression>
- Set a watchpoint for an expression. A watchpoint stops execution of your program whenever the value of an expression changes:
- watch timer
- will stop the program whenever (and wherever) the variable timer is changed.
- bt
- prints a back trace, that is shows you which functions were called to get the program to the state it is now in. If you say bt full you also get the value of each function’s variables. You can also use the bt command to display the execution stack if a core dump/segmentatoion error occurs while you are running a program in the debugger.
- set variable i = 3
- sets the variable i to the value 3.
- help
- read the online help
- quit
- quit the debugger (and your program)
![]() |
![]() |
![]() |
Core Dumps
If your program core dumps you can use the debugger to see what went wrong. Use the command:
gdb a.out core
where a.out is a copy of your program compiled with -g and core is the core file. You can then use bt to see what routine you were in and from where it was called when the core dump occurred.
You can also use the bt command to display the execution stack if a core dump/segmentatoion error occurs while you are running a program in the debugger.
![]() |
![]() |
![]() |
Conclusion
There is much, much more you can do with the debugger that isn’t covered here. There are also graphical interfaces to the debugger.
![]() |
![]() |
![]() |
Further References
- Debugging with GDB - The much more extensive official manual.
- GDB Quick Reference Card (pdf
![]() | ![]() | ![]() |
For use only by students and instructors using the supplementary material available with the text book: "Operating Systems - Internals and Design Principles", William Stallings, Prentice Hall, 5th Edition, 2004. Not to be printed out or copied by any other persons or used for any other purpose without written permission of the author(s).
©