1 @node Debugging Tools, Development Tools, Project Documentation, Top
2 @appendix Debugging Tools
4 Many tools lie at your disposal for debugging Pintos. This appendix
5 introduces you to a few of them.
11 * UNUSED NO_RETURN NO_INLINE PRINTF_FORMAT::
14 * Debugging by Infinite Loop::
20 @section @code{@code{printf()}}
22 Don't underestimate the value of @func{printf}. The way
23 @func{printf} is implemented in Pintos, you can call it from
24 practically anywhere in the kernel, whether it's in a kernel thread or
25 an interrupt handler, almost regardless of what locks are held.
27 @func{printf} isn't useful just because it can print data members.
28 It can also help figure out when and where something goes wrong, even
29 when the kernel crashes or panics without a useful error message. The
30 strategy is to sprinkle calls to @func{print} with different strings
31 (e.g.@: @code{"1\n"}, @code{"2\n"}, @dots{}) throughout the pieces of
32 code you suspect are failing. If you don't even see @code{1} printed,
33 then something bad happened before that point, if you see @code{1}
34 but not @code{2}, then something bad happened between those two
35 points, and so on. Based on what you learn, you can then insert more
36 @func{printf} calls in the new, smaller region of code you suspect.
37 Eventually you can narrow the problem down to a single statement.
40 @section @code{ASSERT}
42 Assertions are useful because they can catch problems early, before
43 they'd otherwise be notices. Pintos provides a macro for assertions
44 named @code{ASSERT}, defined in @file{<debug.h>}, that you can use for
45 this purpose. Ideally, each function should begin with a set of
46 assertions that check its arguments for validity. (Initializers for
47 functions' local variables are evaluated before assertions are
48 checked, so be careful not to assume that an argument is valid in an
49 initializer.) You can also sprinkle assertions throughout the body of
50 functions in places where you suspect things are likely to go wrong.
52 When an assertion proves untrue, the kernel panics. The panic message
53 should help you to find the problem. See the description of
54 backtraces below for more information.
59 The @code{DEBUG} macro, also defined in @file{<debug.h>}, is a sort of
60 conditional @func{printf}. It takes as its arguments the name of a
61 ``message class'' and a @func{printf}-like format string and
62 arguments. The message class is used to filter the messages that are
63 actually displayed. You select the messages to display on the Pintos
64 command line using the @option{-d} option. This allows you to easily
65 turn different types of messages on and off while you debug, without
66 the need to recompile.
68 For example, suppose you want to output thread debugging messages. To
69 use a class named @code{thread}, you could invoke @code{DEBUG} like
72 DEBUG(thread, "thread id: %d\n", id);
75 and then to start Pintos with @code{thread} messages enable you'd use
76 a command line like this:
81 @node UNUSED NO_RETURN NO_INLINE PRINTF_FORMAT
82 @section UNUSED, NO_RETURN, NO_INLINE, and PRINTF_FORMAT
84 These macros defined in @file{<debug.h>} tell the compiler special
85 attributes of a function or function parameter. Their expansions are
89 Appended to a function parameter to tell the compiler that the
90 parameter might not be used within the function. It suppresses the
91 warning that would otherwise appear.
95 Appended to a function prototype to tell the compiler that the
96 function never returns. It allows the compiler to fine-tune its
97 warnings and its code generation.
101 Appended to a function prototype to tell the compiler to never emit
102 the function in-line. Occasionally useful to improve the quality of
103 backtraces (see below).
106 @defmac PRINTF_FORMAT (@var{format}, @var{first})
107 Appended to a function prototype to tell the compiler that the
108 function takes a @func{printf}-like format string as its
109 @var{format}th argument and that the corresponding value arguments
110 start at the @var{first}th argument. This lets the compiler tell you
111 if you pass the wrong argument types.
117 When the kernel panics, it prints a ``backtrace,'' that is, a summary
118 of how your program got where it is, as a list of addresses inside the
119 functions that were running at the time of the panic. You can also
120 insert a call to @func{debug_backtrace}, prototyped in
121 @file{<debug.h>}, at any point in your code.
123 The addresses in a backtrace are listed as raw hexadecimal numbers,
124 which are meaningless in themselves. You can translate them into
125 function names and source file line numbers using a tool called
126 @command{i386-elf-addr2line}.@footnote{If you're using an 80@var{x}86
127 system for development, it's probably just called
128 @command{addr2line}.}
130 The output format of @command{i386-elf-addr2line} is not ideal, so
131 we've supplied a wrapper for it simply called @command{backtrace}.
132 Give it the name of your @file{kernel.o} as the first argument and the
133 hexadecimal numbers composing the backtrace (including the @samp{0x}
134 prefixes) as the remaining arguments. It outputs the function name
135 and source file line numbers that correspond to each address.
137 If the translated form of a backtrace is garbled, or doesn't make
138 sense (e.g.@: function A is listed above function B, but B doesn't
139 call A), then it's a good sign that you're corrupting a kernel
140 thread's stack, because the backtrace is extracted from the stack.
141 Alternatively, it could be that the @file{kernel.o} you passed to
142 @command{backtrace} does not correspond to the kernel that produced
146 @section @command{i386-elf-gdb}
148 You can run the Pintos kernel under the supervision of the
149 @command{i386-elf-gdb} debugger.@footnote{If you're using an
150 80@var{x}86 system for development, it's probably just called
151 @command{addr2line}.} There are two steps in the process. First,
152 start Pintos with the @option{--gdb} option, e.g.@: @command{pintos
153 --gdb run}. Second, in a second terminal, invoke @command{gdb} on
156 i386-elf-gdb kernel.o
158 @noindent and issue the following @command{gdb} command:
160 target remote localhost:1234
163 At this point, @command{gdb} is connected to Bochs over a local
164 network connection. You can now issue any normal @command{gdb}
165 commands. If you issue the @samp{c} command, the Bochs BIOS will take
166 control, load Pintos, and then Pintos will run in the usual way. You
167 can pause the process at any point with @key{Ctrl+C}. If you want
168 @command{gdb} to stop when Pintos starts running, set a breakpoint on
169 @func{main} with the command @code{break main} before @samp{c}.
171 You can read the @command{gdb} manual by typing @code{info gdb} at a
172 terminal command prompt, or you can view it in Emacs with the command
173 @kbd{C-h i}. Here's a few commonly useful @command{gdb} commands:
177 Continue execution until the next breakpoint or until @key{Ctrl+C} is
180 @item break @var{function}
181 @itemx break @var{filename}:@var{linenum}
182 @itemx break *@var{address}
183 Sets a breakpoint at the given function, line number, or address.
184 (Use a @samp{0x} prefix to specify an address in hex.)
186 @item p @var{expression}
187 Evaluates the given C expression and prints its value.
188 If the expression contains a function call, the function will actually
189 be executed, so be careful.
191 @item l *@var{address}
192 Lists a few lines of code around the given address.
193 (Use a @samp{0x} prefix to specify an address in hex.)
196 Prints a stack backtrace similar to that output by the
197 @command{backtrace} program described above.
199 @item p/a @var{address}
200 Prints the name of the function or variable that occupies the given
202 (Use a @samp{0x} prefix to specify an address in hex.)
205 You might notice that @command{gdb} tends to show code being executed
206 in an order different from the order in the source. That is, the
207 current statement jumps around seemingly randomly. This is due to
208 GCC's optimizer, which does tend to reorder code. If it bothers you,
209 you can turn off optimization by editing
210 @file{pintos/src/Make.config}, removing @option{-O3} from the
211 @code{CFLAGS} definition.
213 If you notice other strange behavior while using @command{gdb}, there
214 are three possibilities. The first is that there is a bug in your
215 modified Pintos. The second is that there is a bug in Bochs's
216 interface to @command{gdb} or in @command{gdb} itself. The third is
217 that there is a bug in the original Pintos code. The first and second
218 are quite likely, and you should seriously consider both. We hope
219 that the third is less likely, but it is also possible.
221 @node Debugging by Infinite Loop
222 @section Debugging by Infinite Loop
224 If you get yourself into a situation where the machine reboots in a
225 loop, you've probably hit a ``triple fault.'' In such a situation you
226 might not be able to use @func{printf} for debugging, because the
227 reboots might be happening even before everything needed for
228 @func{printf} is initialized. In such a situation, you might want to
229 try what I call ``debugging by infinite loop.''
231 What you do is pick a place in the Pintos code, insert the statement
232 @code{for (;;);} there, and recompile and run. There are two likely
237 The machine hangs without rebooting. If this happens, you know that
238 the infinite loop is running. That means that whatever caused the
239 problem must be @emph{after} the place you inserted the infinite loop.
240 Now move the infinite loop later in the code sequence.
243 The machine reboots in a loop. If this happens, you know that the
244 machine didn't make it to the infinite loop. Thus, whatever caused the
245 reboot must be @emph{before} the place you inserted the infinite loop.
246 Now move the infinite loop earlier in the code sequence.
249 If you move around the infinite loop in a ``binary search'' fashion, you
250 can use this technique to pin down the exact spot that everything goes
251 wrong. It should only take a few minutes at most.
253 @node Modifying Bochs
254 @section Modifying Bochs
256 An advanced debugging technique is to modify and recompile the
257 simulator. This proves useful when the simulated hardware has more
258 information than it makes available to the OS. For example, page
259 faults have a long list of potential causes, but the hardware does not
260 report to the OS exactly which one is the particular cause.
261 Furthermore, a bug in the kernel's handling of page faults can easily
262 lead to recursive faults, but a ``triple fault'' will cause the CPU to
263 reset itself, which is hardly conducive to debugging.
265 In a case like this, you might appreciate being able to make Bochs
266 print out more debug information, such as the exact type of fault that
267 occurred. It's not very hard. You start by retrieving the source
268 code for Bochs 2.1.1 from @uref{http://bochs.sourceforge.net} and
269 extracting it into a directory. Then read
270 @file{pintos/src/misc/bochs-2.1.1.patch} and apply the patches needed.
271 Then run @file{./configure}, supplying the options you want (some
272 suggestions are in the patch file). Finally, run @command{make}.
273 This will compile Bochs and eventually produce a new binary
274 @file{bochs}. To use your @file{bochs} binary with @command{pintos},
275 put it in your @env{PATH}, and make sure that it is earlier than
276 @file{/usr/class/cs140/i386/bochs}.
278 Of course, to get any good out of this you'll have to actually modify
279 Bochs. Instructions for doing this are firmly out of the scope of
280 this document. However, if you want to debug page faults as suggested
281 above, a good place to start adding @func{printf}s is
282 @func{BX_CPU_C::dtranslate_linear} in @file{cpu/paging.cc}.
287 The page allocator in @file{threads/palloc.c} clears all the bytes in
288 pages to @t{0xcc} when they are freed. Thus, if you see an attempt to
289 dereference a pointer like @t{0xcccccccc}, or some other reference to
290 @t{0xcc}, there's a good chance you're trying to reuse a page that's
291 already been freed. Also, byte @t{0xcc} is the CPU opcode for
292 ``invoke interrupt 3,'' so if you see an error like @code{Interrupt
293 0x03 (#BP Breakpoint Exception)}, Pintos tried to execute code in a
296 Similarly, the block allocator in @file{threads/malloc.c} clears all
297 the bytes in freed blocks to @t{0xcd}. The two bytes @t{0xcdcd} are
298 a CPU opcode for ``invoke interrupt @t{0xcd},'' so @code{Interrupt
299 0xcd (unknown)} is a good sign that you tried to execute code in a
300 block freed with @func{free}.