(prepared by Takashi Okumura, aka taka)
Professional programmers use debuggers, instead, for debugging. It is extremely useful, once becomes familiar, and provides way to trace flows, inspect variables, and locate points of failure at runtime.
However, the heart of debugging is the interactive inspection of flows and variables. Since they need mouse operations everytime, you may have frustration.
For those of you who have experience with graphical debuggers, you may continue using them. The same idea in the lecture applies to most of them.
If you run the program on gdb, you can stop and locate the point of execution by just sending a break signal any time. Then you can trace or inspect. It's much more efficient.
Now you should have been enlightened enough.
%cc -g -o filename filename.c ... %gcc -g filename.cIf you use makefile, put the -g option into appropriate line of your Makefile.
Now, to start off gdb, type gdb filename at the command line. A few messages are printed, and then you are left at the (gdb) prompt:
%gdb filename %gdb GNU gdb 4.18 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-unknown-freebsd". (gdb) _Or, you may use filecommand to read an executable at prompt:
%gdb filename [messages] (gdb) file filename (gdb) _
Used to set a breakpoint at the line or function. In the case of the line, execution is stopped before any code on the line is executed. In the case of function_name, execution stops when the function is called.
Start execution of the program. If breakpoints are set, execution stops when the breakpoint is reached. Otherwise, the program runs to completion. gdb prints a message stating the status of the program on termination.
Continue execution from where it stopped.
Execute the next or next n source line(s). This command steps into functions. Argument N means do this N times.
Same as step, but the command passes functions, treating them as if they were single statements. Argument N means do this N times.
Execute until the program reaches a source line greater than the current. If your program enters a for loop and you grow weary of typing next, you can use the command to exit the loop.
Execute until current function return.
Deletes all breakpoints.
Deletes any breakpoints set on the line or at the entry of function.
Print 10 lines centered at sourceline, or starting from the beginning of function. list print 10 more lines, whereas list - prints 10 lines before the last printing.
Print the value of expression. The contents of variables in the program can be viewed through this command.
Print the value of variable i.
Print the contents of memory pointed by p, where p is a pointer variable.
Check all the members of a structure, assuming x is a structure.
Check the members of a structure.
Check a member of a structure, assuming p is a pointer to a structure.
Print the i'th element of array.
Print all the element of array, assuming array is an array.
Print value of expression each time the program stops.
Cancel some expressions to be displayed when program stops.
Print a backtrace of all the active functions on the execution stack. This is very useful in determining the location of execution, and order in which functions call each other.
Select and print a stack frame.
Select and print a stack frame (function) that called this one.
Select and print a stack frame called by this one.
Display the set of commands available in gdb. The last two display the usage, and information about command categories, and commands.
Kill execution of the program being run. Typically used to prepare to re-start the program from the beginning.
Exit gdb.
Typing of return will repeat the previous command. You can use this method to quickly step through the program with next or step. Or, you may want to use this to quickly browse your program with list command.
%nachos ... segmentation fault %
%gdb nachosgdb will show you the location of the error. (It stops execution automatically, and prints error messages)(gdb) run ... segmentation fault at line xxx of yyy.cc. (gdb)
(gdb) list 19 { 20 int sum = 0; 21 int i; 22 23 for(i = 0;;i++) 24 sum += *ptrs[i]; 25 } 26 27 28 void PrintArray() (gdb) print i $1 = 23424592334Use list command, and check the lines around the point of failure. You may use print command to check the value of variables.
If you could find the cause, just fix it, compile the source code, and run it again. Otherwise, proceed to next step.
Set breakpoints at the beginning of P() and V() and use the C-x space command to set breakpoint before and after the call to SWITCH() in Scheduler::Run().
Now run the program using run. Let it continue until it gets top the first call to P(). Use where to observe the stack. We are in foo():
(gdb) where #0 Semaphore::P (this=0x29768) at ../threads/synch.cc:67 #1 0x154c0 in foo (unused=0) at ../threads/threadtest.cc:11Continue execution until you reach the SWITCH() call. We are still in foo():
(gdb) where #0 Scheduler::Run (this=0x29250, nextThread=0x29700) at ../threads/scheduler.cc:116 #1 0x14d7c in Thread::Sleep (this=0x296a0) at ../threads/thread.cc:225 #2 0x134cc in Semaphore::P (this=0x29768) at ../threads/synch.cc:71 #3 0x154c0 in foo (unused=0) at ../threads/threadtest.cc:11Now let execution continue. It stops at a call to V(). Now we are in the bar() thread, as the stack shows:
(gdb) where #0 Semaphore::V (this=0x29768) at ../threads/synch.cc:91 #1 0x15520 in bar (unused=0) at ../threads/threadtest.cc:20Continue again and we stop at P(), still in the bar() thread. Continue one more time and bar() is about to switch back to foo().
(gdb) where #0 Scheduler::Run (this=0x29250, nextThread=0x296a0) at ../threads/scheduler.cc:116 #1 0x14d7c in Thread::Sleep (this=0x29700) at ../threads/thread.cc:225 #2 0x134cc in Semaphore::P (this=0x29780) at ../threads/synch.cc:71 #3 0x15530 in bar (unused=0) at ../threads/threadtest.cc:21Continue one more time and observe that we stop right after the switch. It appears as though SWITCH() has returned normally. But observe the stack:
(gdb) where #0 Scheduler::Run (this=0x29250, nextThread=0x29700) at ../threads/scheduler.cc:118 #1 0x14d7c in Thread::Sleep (this=0x296a0) at ../threads/thread.cc:225 #2 0x134cc in Semaphore::P (this=0x29768) at ../threads/synch.cc:71 #3 0x154c0 in foo (unused=0) at ../threads/threadtest.cc:11We are now back in the foo() thread!
The gdb manual. You can find this everywhere on the net.
A practical guide.
Illustrates the major commands.
The nachos example above is taken from the document.
DDD (GUI interface to gdb) manual page at gnu.org.