Add some grading test programs.
[pintos-anon] / doc / debug.texi
index 9b0cd5a8e819852cc4e7e5d1c1e27310488b1932..7e372ca0a248d7483aa7e6b5de5142b14161fbee 100644 (file)
@@ -1,4 +1,4 @@
-@node Debugging Tools, , Project Documentation, Top
+@node Debugging Tools, Development Tools, Project Documentation, Top
 @appendix Debugging Tools
 
 Many tools lie at your disposal for debugging Pintos.  This appendix
@@ -8,29 +8,32 @@ introduces you to a few of them.
 * printf::                      
 * ASSERT::                      
 * DEBUG::                       
+* UNUSED NO_RETURN NO_INLINE PRINTF_FORMAT::  
 * Backtraces::                  
 * i386-elf-gdb::                
+* Debugging by Infinite Loop::  
 * Modifying Bochs::             
+* Debugging Tips::              
 @end menu
 
 @node printf
-@section @code{printf()}
+@section @code{@code{printf()}}
 
-Don't underestimate the value of @code{printf()}.  The way
-@code{printf()} is implemented in Pintos, you can call it from
+Don't underestimate the value of @func{printf}.  The way
+@func{printf} is implemented in Pintos, you can call it from
 practically anywhere in the kernel, whether it's in a kernel thread or
 an interrupt handler, almost regardless of what locks are held.
 
-@code{printf()} isn't useful just because it can print data members.
+@func{printf} isn't useful just because it can print data members.
 It can also help figure out when and where something goes wrong, even
 when the kernel crashes or panics without a useful error message.  The
-strategy is to sprinkle calls to @code{print()} with different strings
+strategy is to sprinkle calls to @func{print} with different strings
 (e.g.@: @code{"1\n"}, @code{"2\n"}, @dots{}) throughout the pieces of
 code you suspect are failing.  If you don't even see @code{1} printed,
 then something bad happened before that point, if you see @code{1}
 but not @code{2}, then something bad happened between those two
 points, and so on.  Based on what you learn, you can then insert more
-@code{printf()} calls in the new, smaller region of code you suspect.
+@func{printf} calls in the new, smaller region of code you suspect.
 Eventually you can narrow the problem down to a single statement.
 
 @node ASSERT
@@ -38,7 +41,7 @@ Eventually you can narrow the problem down to a single statement.
 
 Assertions are useful because they can catch problems early, before
 they'd otherwise be notices.  Pintos provides a macro for assertions
-named @code{ASSERT}, defined in @code{<debug.h>}, that you can use for
+named @code{ASSERT}, defined in @file{<debug.h>}, that you can use for
 this purpose.  Ideally, each function should begin with a set of
 assertions that check its arguments for validity.  (Initializers for
 functions' local variables are evaluated before assertions are
@@ -53,9 +56,9 @@ backtraces below for more information.
 @node DEBUG
 @section @code{DEBUG}
 
-The @code{DEBUG} macro, also defined in @code{<debug.h>}, is a sort of
-conditional @code{printf()}.  It takes as its arguments the name of a
-``message class'' and a @code{printf()}-like format string and
+The @code{DEBUG} macro, also defined in @file{<debug.h>}, is a sort of
+conditional @func{printf}.  It takes as its arguments the name of a
+``message class'' and a @func{printf}-like format string and
 arguments.  The message class is used to filter the messages that are
 actually displayed.  You select the messages to display on the Pintos
 command line using the @option{-d} option.  This allows you to easily
@@ -75,13 +78,46 @@ a command line like this:
 pintos run -d thread
 @end example
 
+@node UNUSED NO_RETURN NO_INLINE PRINTF_FORMAT
+@section UNUSED, NO_RETURN, NO_INLINE, and PRINTF_FORMAT
+
+These macros defined in @file{<debug.h>} tell the compiler special
+attributes of a function or function parameter.  Their expansions are
+GCC-specific.
+
+@defmac UNUSED
+Appended to a function parameter to tell the compiler that the
+parameter might not be used within the function.  It suppresses the
+warning that would otherwise appear.
+@end defmac
+
+@defmac NO_RETURN
+Appended to a function prototype to tell the compiler that the
+function never returns.  It allows the compiler to fine-tune its
+warnings and its code generation.
+@end defmac
+
+@defmac NO_INLINE
+Appended to a function prototype to tell the compiler to never emit
+the function in-line.  Occasionally useful to improve the quality of
+backtraces (see below).
+@end defmac
+
+@defmac PRINTF_FORMAT (@var{format}, @var{first})
+Appended to a function prototype to tell the compiler that the
+function takes a @func{printf}-like format string as its
+@var{format}th argument and that the corresponding value arguments
+start at the @var{first}th argument.  This lets the compiler tell you
+if you pass the wrong argument types.
+@end defmac
+
 @node Backtraces
 @section Backtraces
 
 When the kernel panics, it prints a ``backtrace,'' that is, a summary
 of how your program got where it is, as a list of addresses inside the
 functions that were running at the time of the panic.  You can also
-insert a call to @code{debug_backtrace()}, prototyped in
+insert a call to @func{debug_backtrace}, prototyped in
 @file{<debug.h>}, at any point in your code.
 
 The addresses in a backtrace are listed as raw hexadecimal numbers,
@@ -130,7 +166,7 @@ commands.  If you issue the @samp{c} command, the Bochs BIOS will take
 control, load Pintos, and then Pintos will run in the usual way.  You
 can pause the process at any point with @key{Ctrl+C}.  If you want
 @command{gdb} to stop when Pintos starts running, set a breakpoint on
-@code{main()} with the command @code{break main} before @samp{c}.
+@func{main} with the command @code{break main} before @samp{c}.
 
 You can read the @command{gdb} manual by typing @code{info gdb} at a
 terminal command prompt, or you can view it in Emacs with the command
@@ -166,7 +202,15 @@ address.
 (Use a @samp{0x} prefix to specify an address in hex.)
 @end table
 
-If you notice unexplainable behavior while using @command{gdb}, there
+You might notice that @command{gdb} tends to show code being executed
+in an order different from the order in the source.  That is, the
+current statement jumps around seemingly randomly.  This is due to
+GCC's optimizer, which does tend to reorder code.  If it bothers you,
+you can turn off optimization by editing
+@file{pintos/src/Make.config}, removing @option{-O3} from the
+@code{CFLAGS} definition.
+
+If you notice other strange behavior while using @command{gdb}, there
 are three possibilities.  The first is that there is a bug in your
 modified Pintos.  The second is that there is a bug in Bochs's
 interface to @command{gdb} or in @command{gdb} itself.  The third is
@@ -174,6 +218,38 @@ that there is a bug in the original Pintos code.  The first and second
 are quite likely, and you should seriously consider both.  We hope
 that the third is less likely, but it is also possible.
 
+@node Debugging by Infinite Loop
+@section Debugging by Infinite Loop
+
+If you get yourself into a situation where the machine reboots in a
+loop, you've probably hit a ``triple fault.''  In such a situation you
+might not be able to use @func{printf} for debugging, because the
+reboots might be happening even before everything needed for
+@func{printf} is initialized.  In such a situation, you might want to
+try what I call ``debugging by infinite loop.''
+
+What you do is pick a place in the Pintos code, insert the statement
+@code{for (;;);} there, and recompile and run.  There are two likely
+possibilities:
+
+@itemize @bullet
+@item
+The machine hangs without rebooting.  If this happens, you know that
+the infinite loop is running.  That means that whatever caused the
+problem must be @emph{after} the place you inserted the infinite loop.
+Now move the infinite loop later in the code sequence.
+
+@item
+The machine reboots in a loop.  If this happens, you know that the
+machine didn't make it to the infinite loop.  Thus, whatever caused the
+reboot must be @emph{before} the place you inserted the infinite loop.
+Now move the infinite loop earlier in the code sequence.
+@end itemize
+
+If you move around the infinite loop in a ``binary search'' fashion, you
+can use this technique to pin down the exact spot that everything goes
+wrong.  It should only take a few minutes at most.
+
 @node Modifying Bochs
 @section Modifying Bochs
 
@@ -202,5 +278,23 @@ put it in your @env{PATH}, and make sure that it is earlier than
 Of course, to get any good out of this you'll have to actually modify
 Bochs.  Instructions for doing this are firmly out of the scope of
 this document.  However, if you want to debug page faults as suggested
-above, a good place to start adding @code{printf()}s is
-@code{BX_CPU_C::dtranslate_linear()} in @file{cpu/paging.cc}.
+above, a good place to start adding @func{printf}s is
+@func{BX_CPU_C::dtranslate_linear} in @file{cpu/paging.cc}.
+
+@node Debugging Tips
+@section Tips
+
+The page allocator in @file{threads/palloc.c} clears all the bytes in
+pages to @t{0xcc} when they are freed.  Thus, if you see an attempt to
+dereference a pointer like @t{0xcccccccc}, or some other reference to
+@t{0xcc}, there's a good chance you're trying to reuse a page that's
+already been freed.  Also, byte @t{0xcc} is the CPU opcode for
+``invoke interrupt 3,'' so if you see an error like @code{Interrupt
+0x03 (#BP Breakpoint Exception)}, Pintos tried to execute code in a
+freed page.
+
+Similarly, the block allocator in @file{threads/malloc.c} clears all
+the bytes in freed blocks to @t{0xcd}.  The two bytes @t{0xcdcd} are
+a CPU opcode for ``invoke interrupt @t{0xcd},'' so @code{Interrupt
+0xcd (unknown)} is a good sign that you tried to execute code in a
+block freed with @func{free}.