I was testing the new DM6446 SPI support I had added to u-boot when I got a data abort.
U-Boot > sspi 0 32 abcd
data abort
pc : [<810a3674>] lr : [<810a3638>]
sp : 8104fe3c ip : 00000d39 fp : 00000001
r10: 00000002 r9 : 00000000 r8 : 8104ffdc
r7 : 000f4240 r6 : 00000000 r5 : 00000000 r4 : 810602b8
r3 : 00000001 r2 : 01c66800 r1 : 00000019 r0 : 810602b8
Flags: NzCv IRQs off FIQs off Mode SVC_32
Resetting CPU …
Egads, what should I do with that information? Actually, it is really rather easy to figure out what line of source code caused the problem. Here are the steps I used.
First, look in u-boot.map where you found the u-boot.bin that you loaded into your target hardware. Search for the library with the address closest (but lower) to the address shown in the dump for the pc (program counter) register – 0×810a3674 in my case. Note that the PC was incremented by 4, so the address of interest is at 0×810a3670
from u-boot.map:
.text 0×810a3428 0×25c drivers/spi/libspi.a
This is the collection of object files in an archive (the .a file) from the drivers/spi directory.
Since the PC address when the data abort occurred is 0×810a3670, and libspi.a starts 0×810a3428, the problem occurred 0×248 offset inside libspi.a.
Second, use objdump to see what is 0×248 bytes from the start of the libspi.a.
arm-linux-gnueabi-objdump -dS drivers/spi/libspi.a
which produces, in part
static inline void spi_out32(u32 addr, u32 data)
{
__raw_writel(data,addr);
244: e5832000 str r2, [r3]
/* Take SPI module out of reset */
spi_set_bits(SPI_GCR0, 1);
/* Take SPI module out of reset */
spi_set_bits(SPI_GCR0, 1);
return &spi_bus->slave;
}
248: e8bd84f0 pop {r4, r5, r6, r7, sl, pc}
the source code objdump added to the assembly listing isn’t exactly right (because I have compiler optimization enabled), but you can see the problem is near the return from the spi_setup_slave() function that caused the data abort.
Hmm, turns out it was one instruction before – at offset 0×244 – there is more instruction pipelining that I realized, the causing the value of PC to be incremented for two instructions before the data abort occurred.
In look at the inline function
static inline void spi_set_bits(u32 addr, u32 bits)
{
u32 v = spi_in32(addr);
v |= bits;
spi_out32(v, addr);
}
I see I have the arguments backwards in the spi_out32 call. Changing the line to:
spi_out32(addr,v );
fixed the problem.
I hope this simple example shows how with the aid of a symbol (map) file and using objdump, you can use the PC address where the problem occurred to quickly locate the line of offending code.
Uncategorized