0
votes

I'm having difficulties getting debugger and gdb to work as expected with a FIQ handler in Linux kernel. It can trigger fine to the driver code that sets up the condition for FIQ triggering, but not with FIQ.

I'm using ARM-USB-TINY-H debugger + imx233-SJTAG converter (the board doesn't have pins for parallel JTAG) from Olimex to debug i.mx233 board.

I'm compiling gdb 7.5.1 with buildroot, and openocd 0.6.1 comes from Ubuntu repository. I launch openocd:

# openocd -f olimex-arm-usb-tiny-h.cfg -f imx233.cfg

Open On-Chip Debugger 0.6.1 (2012-12-06-17:15)
....
Info : only one transport option; autoselect 'jtag'
trst_and_srst srst_pulls_trst srst_gates_jtag trst_push_pull srst_open_drain
adapter speed: 800 kHz
dcc downloads are enabled
fast memory access is enabled
Info : max TCK change to: 30000 kHz
Info : clock speed 789 kHz
Info : JTAG tap: imx23.cpu tap/device found: 0x079264f3 (mfg: 0x279, part: 0x7926, ver: 0x0)
Info : Embedded ICE version 6
Info : imx23.cpu: hardware has 2 breakpoint/watchpoint units

Starting gdb and setting up the breakpoint:

# arm-buildroot-linux-uclibcgnueabi-gdb vmlinux
....
target remote :3333
Remote debugging using :3333
0x00000000 in ?? ()
(gdb) monitor halt
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x600000d3 pc: 0xc0019024
MMU: enabled, D-Cache: enabled, I-Cache: disabled
(gdb) hbreak mydriver_userland_write
Hardware assisted breakpoint 1 at 0xc02da930: file drivers/misc/mydriver.c, line 309.
(gdb) c
Continuing.

Now at this point the gdb will happily trigger, when ever I send message from userland to the driver.

Breakpoint 1, mydriver_userland_write (filp=0xc2cb81c0, buf=0x19d8600 "1\n\235\001t", count=2, f_pos=0xc2cb3f88) at drivers/misc/mydriver.c:309
309                       size_t count, loff_t *f_pos) {

After processing the information from userland, I initialize the conditions for FIQ to trigger, and return. In gdb, I setup the breakpoint for FIQ. (line 60 is basically 4th assembler instruction after clearing the interrupt flag)

## Enable catching for FIQ vectors
(gdb) monitor arm9 vector_catch fiq
reset: don't catch
undef: don't catch
swi: don't catch
pabt: don't catch
dabt: don't catch
irq: don't catch
fiq: catch

## setup the breakpoint
(gdb) hbreak myfiq_handler.S:60
Hardware assisted breakpoint 1 at 0xc02db040: file     drivers/misc/myfiq_handler.S, line 60.
(gdb) c
Continuing.

Now after all is setup, I trigger the condition that results into FIQ processing, and this is where strange result happens:

Program received signal SIGTRAP, Trace/breakpoint trap.
0xffff001c in ?? ()

I can't do anything at this point really:

## Try to see call trace
(gdb) bt
#0  0xffff001c in ?? ()

## Try stepping
(gdb) step
Cannot find bounds of current function
(gdb) next
Cannot find bounds of current function

monitor reg shows register state like this http://paste.ubuntu.com/6113942/ If I look at the vmlinux map file, the PC points literylly last 4 lines of the file:

ffe5095d A __crc_groups_free
fff3672c A __crc_directly_mappable_cdev_bdi
ffffe9f5 A __crc_cfg80211_wext_giwfrag
     w __crc_softirq_work_list

If I use stepi command, the whole execution seems to hang.

I'm still learning how to use gdb, so I really have no clue where to look for the problem now.. any suggestions are welcome!

1

1 Answers

1
votes

The FIQ routine is copied to the tail end of the vector table. The layout of the ARM vector table is,

  1. Reset
  2. Undefined instruction
  3. Software interrupt (SWI)
  4. Pre-fetch abort
  5. Data Abort
  6. 4-byte hole
  7. IRQ (normal interrupt)
  8. FIQ (fast interrupt).

As well as the banked registers r8-r14, the FIQ mode hands execution directly to address 0x1c (plus table offset). All of the other exceptions will typically do a branch instruction. However, for the FIQ, there is no need to branch meaning that your assembler routine can execute directly.

See the routine set_fiq_handler() in Linux's fiq.c. Your GDB will be un-aware of this relocation and will place a break-point at the original address. As a caveat, the initial FIQ routine must be PC-relative or it will not execute. In GDB, you can use b 0xffff001c to set a break-point at the initial FIQ instruction.

Other exception and the vector table definition are in entry-armv.S near the bottom of the file as __vectors_start with the W(b) vector_fiq instruction, which will be over-written by your routine. See also vmlinux.lds.S which is the linker script for the kernel. You have a space of 0x1000-0x1c as the size of the FIQ routine.