Lab 7 -- debugging

There are a lot of things that can go wrong in programming, and assembly language is no different. This lab is about common problems, and using a debugger to help.

Part 1

First, we will look at a few possible problems that you might run into. Download the code at several_errors.asm. Try to assemble it with the command nasm -f elf64 several_errors.asm, then edit it to correct the errors noted by the assembler.

  1. Trying to define integer values, the next two lines generate an assembly error: "error: comma, colon or end of line expected".
    
        int1 dd 10
        int2 dd 5
    
    The code looks OK, and is even correct with some assemblers. But the assembler that we use, NASM, gives an error. The following is the solution.
    
        int1: dd 10
        int2: dd 5
    
  2. The next problem is like a syntax error. The assembler says "error: parser: instruction expected".
    
        move rax, 0
    
    The problem is that "move" is not a mnemonic. Obviously, the programmer means "mov" here, but that is not obvious to the assembler.
  3. The next line causes an assembly error: "error: invalid combination of opcode and operands".
    
        mov   rsi, ebx         ; Value to print
    
    The problem is that rsi is 64 bits, while ebx is 32. The solution is to use this line instead:
    
        mov   rsi, rbx         ; Value to print
    
  4. The next line gives the assembler error: "error: symbol `newline' undefined"
    
        mov  rdi, newline
    
    This happens because "newline" has no meaning to the assembler, and it is therefore expecting "newline" to be defined somewhere, such as the data section. The solution is simple, to add the following line in section .data. Once it is defined, the error goes away.
    
        newline: dq 10
    
    This is just like using a variable without declaring and initializing it first.

In the above, you should have altered the "several_errors.asm" program to fix all of the errors noted by the assembler. Make sure to show the new version of the program, and that it assembles and links. Now we will look at how you might debug the final error that occurs at run-time.

Part 2

The "gdb" program is the GNU debugger. You can run it from the command line by typing

 
    gdb several_errors 
From the "(gdb)" prompt, you can type "quit" to exit the program. Another good command to know is "help", such as "help running". This provides documentation on commands related to running a program in the debugger.

Type the following commands at the "(gdb)" prompt, pressing return between them.


    set disassembly-flavor intel
    disassemble main
The first command informs the debugger of what type of code to show. If you forget it, it will show code that looks familiar, but different. The default is "att" style code, from AT&T, and yes: it means American Telephone and Telegraph Company, the telephone/telecommunications company that may be your internet provider. For example, instead of "mov eax,0x0", you would see "mov $0x0,%eax". The second one shows the assembly language for the "main" function. Notice that the output is different from the source file. This is because it is showing a disassembly: it says what commands are there, but it bases this on the executable program instead of the original source code.

We will set a breakpoint. This is a place where the execution will stop, allowing us to inspect the state of the computer. Enter the command


    break main
to set a break-point at the main label. You could set more break-points, based on any other defined labels. Let's see what break-points are set with the following command.

    info breakpoints

Now run the program.


    run 
You should see something like this in the output. (You do not type this; this is something that the computer says in the response.)

    Breakpoint 1, 0x0000000000400580 in main ()
Now you can step through the code by entering the command

    nexti
This executes the next instruction. You can repeat "nexti" to step through as many instructions as you want. From here, you could enter "continue" to keep going until the next break-point. Or "step" to keep going until it reaches the main function's exit.

The problem with entering "nexti" again and again is that you will lose track of what it is doing. Enter the following command to show the instructions that will execute with the "nexti" command.


    display/i $pc

You should inspect the contents of the registers. This is done with the following command.


    info registers
If you just want the contents of one register, you can specify it/ Try this:

    info registers rax
Likewise, you can inspect the stack with

    info stack
Inspect the variables with the following command.
 
    info variables
Finally, inspect the flags with the following command.
 
    info registers eflags
The gdb program will respond with a hexadecimal value of the eflags register, along with a list of flags that are set.

Part 3

Now that you know about the gdb program, use it to debug the segmentation fault error. Walk us through the program, along with the information that you discover with gdb, explaining it. Talk about how what each instruction does, and how you can observe its effect.

Questions

Remember to use "quit" to quit the gdb program.

In this lab, we have learned:

gdb commands that were discussed are:
gdb commandeffect
break mainset a break-point at main
continuerun until the next break-point
disassemble maindisassemble the code starting at main
display/i $pcshow the next instruction
helpget help information
help runningget help information about running the program
info breakpointsshow the set break-points
info registersshow contents of the registers
info registers eflagsshow contents of the eflags register (flags)
info registers raxshow contents of the rax register
info stackshow contents of the stack
info variablesshow information about variable locations
nextistep through the next instruction
runbegin running the program
quitquit gdb
set disassembly-flavor intelswitch the instruction format
stepkeep going until the exit of the main function