Thursday, August 4, 2011

Set Breakpoints in arm-elf-gdb

Breakpoints allow you to run your program up to a desired point.

Set Breakpoint

In arm-elf-gdb, to set a breakpoint use the break command, which can be abbreviated to just b, followed by a label, address, or line number in the .s file. 
Examples
break _start
b main
b 0x8004
b 17 (set breakpoint at line 17 of the original assembly file)
Check Breakpoints


To find all breakpoints, type info breakpoint. Again, abbreviations can be used to execute the equivalent i b

Run Until Breakpoint is Reached


The command continue will run the program until the next breakpoint. c will perform the same function.

Further Debugging in arm-elf-gdb

Here are a few quick words on using GDB, with particular reference to ARM files.

Inspect Registers
To have a look at a particular register, use the command print $[register_name]
For example,
print $r0
print $r1
print $pc
print can be abbreviated to p
p $r0
p $r1
p $pc

Change Register Values
Use the command print $[register_name] = [value]
For example,
print $r0 = 10
print $r1 = 0x20
print $pc = _start
Again, the abbreviation p can be used in place of print

Formatting Output
Format can be specified by using /[symbol] after the print command. Possible symbols are:
a for address
x for hexadecimal
d for signed decimal
u for unsigned decimal
o for octal
t for binary ('two')
c for character
f for floating point
For example
print/a $pcprint/x $r0p/c $r1p/t $cpsr 
(Use the last command to check the NZCV and interrupt flags)

Wednesday, August 3, 2011

Online Assembler and Checker for UNSW ELEC2142

Update: Sept 21, 2011

I think all students are finished with this, so I am taking it down. If it's a problem, email me!

Tuesday, August 2, 2011

Debugging ARM files with DDD (Simulation)

DDD is a graphical front-end to a variety of debuggers, including arm-elf-gdb.


Installation
In Ubuntu, install by running sudo apt-get install ddd 
For OS X, you can try your luck over here.
Usage
With the GNU ARM tools installed, in the terminal run ddd --debugger arm-elf-gdb &
Click File -> Open Program. Select your ELF file (that was assembled with --gdwarf2).
In the GDB console (the bottom pane), type
(gdb) target sim 
(gdb) load
(gdb) start 
You can view the registers by clicking Source -> Registers.
You can now step through the program, set breakpoints, and perform most other functions that GDB is capable of.


Debugging ARM files with arm-elf-insight (Simulation)

Insight is a graphical user interface for gdb, available for use in Cygwin on Windows. Installation is fairly straight-forward.

Usage

Open Cygwin.
  1. Assemble and link a .s file, ensuring the '--gdwarf2' option is used.
  2. Run arm-elf-insight.exe
  3. Click File -> Open, and select the ELF file.
  4. Click Run -> Run, or click the running man icon.
  5. Select 'Simulator' as the Target, and click OK.





  6. Click 'Yes'.
  7. For embedded systems debugging, it is good to open both the registers and memory windows under the View menu.
  8. Step through the program, observing changes in the registers and memory contents. If using flash-v1.s, pay attention to the memory changes at 0x10000000.

Monday, August 1, 2011

Installing GNU ARM Toolchain (Windows)

To install the GNU ARM toolchain in Windows, you will need Cygwin, a tool that lets you use a lot of Unix stuff.

Installing Cygwin
To install, download and run setup.exe. You won't need to select any packages yet, unless you are a UNSW ELEC2142 student. In this case, install the following packages:
make (under 'Devel')
expect (under 'Interpreters')
(If you have already installed Cygwin without these packages, just run setup.exe again.)
Installing the GNU ARM Toolchain

Download the latest Windows toolchain from http://gnuarm.com/. At time of writing, that means grabbing this file.

Run this file, and accept all defaults.

If you launch Cygwin, and type arm-elf- and then hit 'Tab' twice, you should see a list of 24 executable files.

That's all, folks!

Debugging ARM files with arm-elf-gdb (Simulation)

First off, ensure you have downloaded the GNU ARM Toolchain, including the debugger (arm-elf-gdb). The following works beautifully in Ubuntu 10.04 (Lucid), and will work similarly under Cygwin.

We need an ARM assembly file. Here is one right here: flash-v1.s. (Note that the comments are preceded by @ symbols, not semicolons).

Create an executable file by following this post.


Life@Phi:$ make flash-v1.elf

arm-elf-as --gdwarf2 -mcpu=arm7tdmi -o flash-v1.o flash-v1.s
arm-elf-ld -o flash-v1.elf flash-v1.o
rm flash-v1.o


Open the ELF file with the debugger.

Life@Phi:$ arm-elf-gdb flash-v1.elf 
GNU gdb 6.8
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-elf"...
(gdb) 
GDB can be used to step through programs loaded on microcontrollers (via JTAG, etc), but here we will only look at simulating hardware. To do this, we need to initiate the simulator:

(gdb) target sim 
Connected to the simulator.
Now we 'load' our ELF file in to our simulator.
(gdb) load

Loading section .text, size 0x1c vma 0x8000
Start address 0x8000

Notice that the start address corresponds to the _start variable set in flash-v1.s.
There are hundreds of commands available in GDB. This is by no means the only (or best) way to debug programs, but here we go. Right now the code is loaded in our simulator, and we need to start running it. start will run the program until it reaches the beginning of the main function. (Alternatively, run will run to program until it finds a breakpoint).
(gdb) start

Breakpoint 1 at 0x8004: file flash-v1.s, line 62.
Starting program: /your/directory/flash-v1.elf 
main () at flash-v1.s:62
62    mov r4, #LED_port       @ Load the address of the LED port
Current language:  auto; currently asm

All that extra information in there is due to the -gdwarf2 debugging flag used during assembly. Without this information, it can be extremely difficult to debug and follow along.
The instruction 'mov r4, #LED_port' is the next instruction to be executed (i.e. it has not been executed yet).

Now for a little bit of information gathering. Let's inspect the values at the registers:

(gdb) info registers 
r0             0x0 0
r1             0x0 0
r2             0x0 0
r3             0x0 0
r4             0x0 0
r5             0x0 0
r6             0x0 0
r7             0x0 0
r8             0x0 0
r9             0x0 0
r10            0x0 0
r11            0x0 0
r12            0x0 0
sp             0x800 0x800
lr             0x0 0
pc             0x8004 0x8004

fps            0x0 0
cpsr           0x13 19
Let's execute ONE instruction of our program.

(gdb) step
main_loop () at flash-v1.s:70
70    mov r5, #Value1         @ Load the value Value1 into R5

It is important to remember this will execute the previously listed instruction, 'mov r4, #LED_port', not the currently displayed instruction. We verify this by inspecting the registers again.


(gdb) info registers 
r0             0x0 0
r1             0x0 0
r2             0x0 0
r3             0x0 0
r4             0x10000000 268435456
r5             0x0 0
r6             0x0 0
r7             0x0 0
r8             0x0 0
r9             0x0 0
r10            0x0 0
r11            0x0 0
r12            0x0 0
sp             0x800 0x800
lr             0x0 0
pc             0x8008 0x8008
fps            0x0 0
cpsr           0x13 19


We can also examine (x) specific parts of memory.
(gdb) x 0x10000000
0x10000000: 0x00000000
(gdb) step
71    strb    r5, [r4]        @ and store this value (a byte) to
(gdb) step
76    mov r5, #Value2         @ Load the value Value2 into R5
(gdb) x 0x10000000
0x10000000: 0x000000ff

Notice how the value at 0x10000000 changes from 0x00 to 0xFF.

In summary, here are some of the important commands for gdb:
target [object/process, e.g. sim]
load
start
info registers
step
x [addr]
and I didn't mention it, but the invaluable help.

Creating ARM Executable and Linkable Format Files

With the GNU ARM Toolchain installed, enter the following two lines in the terminal.


arm-elf-as --gdwarf2 -mcpu=arm7tdmi -o FILENAME.o FILENAME.s 
arm-elf-ld -o FILENAME.elf FILENAME.o


Where FILENAME.s is the name of your ARM assembly code file.

A few quick notes: the parameter 'gdwarf2' is used to maintain debugging information inside the file. It will come in handy when using arm-elf-gdb. The mcpu parameter tells the assembler what architecture the file is to be targeted towards.

Alternatively, copy the following code (EDIT: and replace the three indents on lines 21, 24, and 28 with tabs!), and save it as 'makefile' in the same directory as the .s file. Anytime you need to create an ELF file using filename.s, simply type 'make filename.elf'.

Download makefile

#
# Makefile for ARM Projects
# Author: S Hodgson
# Date: July 2011
#
# Usage: make filename.elf
#   i.e. if helloworld.s is the ARM assembly code,
#        execute 'make helloworld.elf'
#

# Linker and Assembler
LD      = arm-elf-ld
AS      = arm-elf-as

# Flags
DBGFLAG = --gdwarf2
ARCH    = -mcpu=arm7tdmi

# Create Files
%.elf : %.o
    $(LD) -o $@ $^

%.o : %.s
    $(AS) $(DBGFLAG) $(ARCH) -o $@ $^

# Clean - Warning: Removes ALL object and elf files
clean:
    rm -rf *.o *.elf



Edit: As Patrick pointed out, the indentation MUST be tabs, not spaces...