X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=doc%2Fdebug.texi;h=961888f297be48973b9af5d56ff28af3fcef23f1;hb=c0cd5f5c14152621ad5226d90d5ab1a2f48d5d9e;hp=8867c2c4080f9b271311ad73899329860e49ae33;hpb=ceb10f0de9a40570bbfb702d50f19bdc2bf62171;p=pintos-anon diff --git a/doc/debug.texi b/doc/debug.texi index 8867c2c..961888f 100644 --- a/doc/debug.texi +++ b/doc/debug.texi @@ -11,6 +11,7 @@ introduces you to a few of them. * UNUSED NO_RETURN NO_INLINE PRINTF_FORMAT:: * Backtraces:: * i386-elf-gdb:: +* Debugging by Infinite Loop:: * Modifying Bochs:: * Debugging Tips:: @end menu @@ -131,7 +132,7 @@ we've supplied a wrapper for it simply called @command{backtrace}. Give it the name of your @file{kernel.o} as the first argument and the hexadecimal numbers composing the backtrace (including the @samp{0x} prefixes) as the remaining arguments. It outputs the function name -and source file line numbers that correspond to each address. +and source file line numbers that correspond to each address. If the translated form of a backtrace is garbled, or doesn't make sense (e.g.@: function A is listed above function B, but B doesn't @@ -141,13 +142,121 @@ Alternatively, it could be that the @file{kernel.o} you passed to @command{backtrace} does not correspond to the kernel that produced the backtrace. +@menu +* Backtrace Example:: +@end menu + +@node Backtrace Example +@subsection Example + +Here's an example. Suppose that Pintos printed out this following call +stack, which is taken from an actual Pintos submission for the file +system project: + +@example +Call stack: 0xc0106eff 0xc01102fb 0xc010dc22 0xc010cf67 0xc0102319 +0xc010325a 0x804812c 0x8048a96 0x8048ac8. +@end example + +You would then invoke the @command{backtrace} utility like shown below, +cutting and pasting the backtrace information into the command line. +This assumes that @file{kernel.o} is in the current directory. You +would of course enter all of the following on a single shell command +line: + +@example +backtrace kernel.o 0xc0106eff 0xc01102fb 0xc010dc22 0xc010cf67 0xc0102319 +0xc010325a 0x804812c 0x8048a96 0x8048ac8 +@end example + +The backtrace output would then look something like this: + +@example +0xc0106eff: debug_panic (../../lib/debug.c:86) +0xc01102fb: file_seek (../../filesys/file.c:405) +0xc010dc22: seek (../../userprog/syscall.c:744) +0xc010cf67: syscall_handler (../../userprog/syscall.c:444) +0xc0102319: intr_handler (../../threads/interrupt.c:334) +0xc010325a: ?? (threads/intr-stubs.S:1554) +0x804812c: ?? (??:0) +0x8048a96: ?? (??:0) +0x8048ac8: ?? (??:0) +@end example + +(You will probably not get the same results if you run the command above +on your own kernel binary, because the source code you compiled from is +different from the source code that emitted the panic message.) + +The first line in the backtrace refers to @func{debug_panic}, the +function that implements kernel panics. Because backtraces commonly +result from kernel panics, @func{debug_panic} will often be the first +function shown in a backtrace. + +The second line shows @func{file_seek} to be the function that panicked, +in this case as the result of an assertion failure. In the source code +tree used for this example, line 405 of @file{filesys/file.c} is the +assertion + +@example +ASSERT (file_ofs >= 0); +@end example + +@noindent +Thus, @func{file_seek} panicked because it passed a negative file offset +argument. + +The third line indicates that @func{seek} called @func{file_seek}, +presumably without validating the offset argument. In this submission, +@func{seek} implements the @code{seek} system call. + +The fourth line shows that @func{syscall_handler}, the system call +handler, invoked @func{seek}. + +The fifth and sixth lines are the interrupt handler entry path. + +The remaining lines are for addresses below @code{PHYS_BASE}. This +means that they refer to addresses in the user program, not in the +kernel. If you know what user program was running when the kernel +panicked, you can re-run @command{backtrace} on the user program, like +so: (typing the command on a single line, of course): + +@example +backtrace grow-too-big 0xc0106eff 0xc01102fb 0xc010dc22 0xc010cf67 +0xc0102319 0xc010325a 0x804812c 0x8048a96 0x8048ac8 +@end example + +The results look like this: + +@example +0xc0106eff: ?? (??:0) +0xc01102fb: ?? (??:0) +0xc010dc22: ?? (??:0) +0xc010cf67: ?? (??:0) +0xc0102319: ?? (??:0) +0xc010325a: ?? (??:0) +0x804812c: test_main (/home/blp/cs140/pintos/grading/filesys/grow-too-big.c:20) +0x8048a96: main (/home/blp/cs140/pintos/grading/filesys/fsmain.c:10) +0x8048ac8: _start (../../src/lib/user/entry.c:9) +@end example + +Here's an extra tip for anyone who read this far: @command{backtrace} +is smart enough to strip the @code{Call stack:} header and @samp{.} +trailer from the command line if you include them. This can save you +a little bit of trouble in cutting and pasting. Thus, the following +command prints the same output as the first one we used: + +@example +backtrace kernel.o Call stack: 0xc0106eff 0xc01102fb 0xc010dc22 +0xc010cf67 0xc0102319 0xc010325a 0x804812c 0x8048a96 0x8048ac8. +@end example + @node i386-elf-gdb @section @command{i386-elf-gdb} You can run the Pintos kernel under the supervision of the @command{i386-elf-gdb} debugger.@footnote{If you're using an 80@var{x}86 system for development, it's probably just called -@command{addr2line}.} There are two steps in the process. First, +@command{gdb}.} There are two steps in the process. First, start Pintos with the @option{--gdb} option, e.g.@: @command{pintos --gdb run}. Second, in a second terminal, invoke @command{gdb} on @file{kernel.o}: @@ -201,14 +310,6 @@ address. (Use a @samp{0x} prefix to specify an address in hex.) @end table -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 @@ -283,17 +384,18 @@ above, a good place to start adding @func{printf}s is @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 +The page allocator in @file{threads/palloc.c} and the block allocator in +@file{threads/malloc.c} both clear all the bytes in pages and blocks 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}. +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 or +block. + +An assertion failure on the expression @code{sec_no < d->capacity} +indicates that Pintos tried to access a file through an inode that has +been closed and freed. Freeing an inode clears its starting sector +number to @t{0xcccccccc}, which is not a valid sector number for disks +smaller than about 1.6 TB.