Debugging Tips and Tools
This page is designed to provide some tips and tools for debugging your lab assignments in CSE 351. As this course is more about concepts than programming, it is always recommended to first verify your understanding of the material being assessed first. However, since we are examining many concepts beneath the software layer (and therefore abstracted away from the programmer), it is very important to make use the debugging tools to examine what's actually going on in your program.
Debugging Tips
Code Walkthrough
Walking through your program's code is a good way to compare your expectations against the reality of the code execution. Finding where the two diverge from each other can provide the scope in which a bug in your code or a conceptual misunderstanding may exist. Here are some things to keep in mind:
- Take your time! Making sure you understand why your code leads to the erroneous behavior will often illuminate the bug or misunderstanding and is a much more efficient debugging strategy than just trying a bunch of different things randomly.
- Make use of the at your
disposal, as they are often the only way to truly see the reality
of the code execution.
- As 351 deals heavily with your computer's memory, you will often need to examine pieces of memory (e.g., registers, the stack) using GDB and not just variable values.
Test Frequently
Debugging is difficult when you do not know where the bug is in your code! Most of the labs in 351 are comprised of multiple functions or parts that should be tackled one-by-one:
- You should test (usually just re-compiling and running the provided test suite) after attempting/completing each one of these parts so you can isolate/restrict the source of the bugs.
- The test suites will often test all of the parts in one go. You should ignore scores and error messages about the parts that you haven't attempted yet.
Collaboration
We encourage collaboration in this course! Oftentimes, bugs can be easily overlooked individually, so collaboration allows more perspectives, ideas, and just another pair of eyes when writing code or trying to understand the problem! Here are some ideas to consider:
- Discuss with your partner: Review the for policies and tips to work with one another.
- Go to : Office hours are a wonderful place to work with other students that may be working on a similar problem, and it is facilitated by the staff, who have experience with the material from before.
- Post on the : The discussion board is a place for student discussion of course material in an asynchronous (and possibly anonymized) manner.
Debugging Tools
printf
Debugging
Debugging with printf
can be a good starting point for
better understanding the state and execution of your program.
Here are some places where it might be useful:
- Printing out the current state of the program (e.g., local variables or parameters) at a particular point of interest or to assess the changes over time. Note that this is entirely possible with as well, though.
- Printing a message to mark the execution (i.e., was this code reached?) of different parts of the program to give you a better idea of how your program is operating.
printf
.
Parts of 351 can only be done through GDB.
GDB
GDB (Gnu DeBugger) is an immensely useful tool to help you debug your C and assembly programs:
- It lets you insert breakpoints into your programs so that you can stop execution and examine the contents of memory and registers.
- It supports single-stepping your program one line of source code or one line of assembly code at a time.
- It leads to much more productive debugging than just using
printf
statements.
Resources
- is a handy dandy guide to the most commonly used GDB commands. Useful to have open while using GDB (and going through the other resources here).
- is a video that shows you how to get started with GDB. This will be especially useful for Lab 2.
- is an optional walkthrough assignment to give you some hands-on experience with GDB.
- is a web page about formatting your memory output in GDB. This will be especially useful for Lab 3.
- by Norman Matloff at UC Davis has all the details you'll ever want about GDB.
Examples
Here are some code samples for playing with GDB along with some example commands you can try:
- and corresponding .
- and corresponding .
Text User Interface Mode
Text User Interface (TUI) mode of GDB can nicely show your code and the value of registers as you debug! Its use is entirely optional for 351, but we wanted you to be aware of it as it may help some of you. Here is the link for the full documentation of .
- Opening TUI Mode. Most TUI commands will automatically
start TUI mode, but you can also explicitly open GDB in TUI mode
using:
[attu]$ gdb -tui <filename>
- Layout Views. Of particular interest, you can bring up
the disassembly and registers view using:
(gdb) layout asm (gdb) layout regs
Note that you want to do them in that order so that the registers window is on top. Then as you execute instructions (
stepi
orsi
for assembly instructions), the assembly view will highlight the next instruction (not executed yet) and the registers view will highlight any changed registers. - Formatting Issues. Unfortunately, there are some
annoying formatting issues that sometimes pop up while using
TUI mode.
If things start to look weird, run the following command (or
press
Ctrl+L
) to set things straight:(gdb) refresh
Viewing Binary Files
In 351, we will deal with binary files, where the stored data uses the full range of possible character values. This is in contrast to text files, where the stored data are mostly restricted to the values that correspond to printable (e.g., ASCII or Unicode) characters. Different types of binary files serve different purposes, but the one thing they have in common is that they will look like garbage when opened in a text editor because non-printable characters will be represented in ways you wouldn't expect.
objdump
The primary types of binary files that we will examine are
object files and executables.
Both of these types of files are primarily used to hold
machine code, so we can use the utility
objdump
to interpret their contents in a textual
format.
Knowing the ins and outs of objdump
isn't a high
priority in 351, so, when applicable, you will generally be given
the exact commands to run in the assignments.
xxd
xxd
will print out the bytes of a file in hex format.
You don't need to know much about this utility and it is primarily
useful for Lab 3.
Here is an example usage.
The first command creates a file called test.bin
whose
contents are the ASCII characters hello world followed by
the bytes CA, FE, F0, and 0D
(the \x you see means that the byte is specified in hex).
The second command invokes xxd
on the binary file that
we just created.
[attu]$ echo -ne "hello world\xca\xfe\xf0\x0d" > test.bin [attu]$ xxd test.bin 00000000: 6865 6c6c 6f20 776f 726c 64ca fef0 0d hello world....
There are three blocks/columns of information in the single line of output shown above:
- The left-most block (the
00000000:
) represents the byte address/index of the left-most byte of the line (in hex). This can be helpful for finding your place in a longer file. - The middle block (
68
through0d
) shows the values (in hex) of the bytes themselves. Recall that one byte = two hex digits. The bytes have increasing address/index from left-to-right. - The last block is the ASCII decoding of the bytes (as a basic
text editor would interpret the bytes).
For instance, the first byte of the file,
0x68
, is the'h'
. The last four bytes show up as.
, which is howxxd
chooses to show non-printable ASCII characters. This can be a little bit confusing as there is a valid'.'
character (0x2e
) and these non-printable characters might display differently in a text editor.