Breakpoint not working in gdb with QEMU simulating cortex-a8

0

I am testing some simple code running in the ARM7TDMI, since I haven't found ARM7TDMI simulator on QEMU, I use Cortex-a8 instead (I am not sure if this will lead to bug, total newbie).
This is how I run QEMU:
qemu-system-arm -machine realview-pb-a8 -cpu cortex-a8 -nographic -monitor null -serial null -semihosting -kernel main.elf -gdb tcp::51234 -S

The code I want to test is quite simple, the function LoadContext() and SaveContext() is written in arm assembly for IAR IDE, and the IAR IDE is using ARM7TDMI as a core. I compiled this assembly file into an object file with IAR and link the code below with arm-none-eabi-gcc, will this cause unpredictable errors? (Just want to use gcc and QEMU instead of IAR...)

int main(void)
{

    Running = &taskA;
    Running->PC = task1;
    Running->SP = &(Running->StackSeg[STACK_SIZE-1]);

    LoadContext();
}

void task1(void)
{
    register int reg_var = 1;
    volatile int vol_var = 1;

    SaveContext();
    reg_var++;
    vol_var++;

    SaveContext();
    reg_var++;
    vol_var++;

    LoadContext();
}

So, when I have set a breakpoint in the gdb, it is not working, it will just go into an endless loop I think. I checked the initialization process, it is:

(gdb) 
0x000082f6 in __libc_init_array ()
(gdb) 
0x000080e2 in _start ()
(gdb) 
0x000080e4 in _start ()
(gdb) 
0x000080e6 in _start ()
(gdb) 
main () at src/context-demo.c:12
12  int main(void) {
(gdb) 
0x000081ea  12  int main(void) {
(gdb) 
0x00000008 in ?? ()
(gdb) 
0x0000000c in ?? ()
(gdb) 
0x00000010 in ?? ()
(gdb) 
0x00000014 in ?? ()
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x00000004 in ?? ()
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x00000004 in ?? ()
(gdb) 

Does anybody have any ideas about what happened here? Any help is appreciated, thanks!

c
gcc
arm
gdb
qemu
asked on Stack Overflow Jan 15, 2018 by Jiahao Cai

1 Answer

0

You'll find this much easier to debug if you tell gdb to tell you about the assembly instructions it is executing ("display /3i $pc" will print the next 3 instructions every time gdb stops), and do single step of individual instructions ("stepi").

Something is causing you to end up at a low address 0x8 unexpectedly, and you need to find out what that is. Either you're really jumping to 0x8, or you've taken an exception. Looking at execution at a per-machine instruction level will tell you which it is.

Some plausible possibilities here:

  • executable built to assume it has RAM where the realview-pb-a8 does not have RAM -- this often manifests as "writing to the stack (or global variables) silently does nothing and reading from the stack/globals returns 0", so if you have a function pointer in a global or you try to push a return address to the stack and then pop it you'll end up at 0
  • executable built to assume it's running under an OS that provides an SVC API -- in this case the code will execute an SVC instruction and your code will crash because there's nothing to handle it at the SVC exception vector
  • executable built for the wrong CPU type and executes an instruction that UNDEFs (this should result in execution going to address 0x4, the undef vector, but I have a feeling there's a qemu bug in its gdbstub that may mean that a step that executes an UNDEF insn will not stop until after executing the first insn at the UNDEF vector)
  • executable built to assume that the FPU is always enabled. When QEMU is executing a "bare metal" binary like this, the CPU is started in the state that hardware starts, which has the FPU disabled. So any instructions using the FPU will UNDEF unless the executable's startup code has explicitly turned on the FPU.

I've listed those in rough order of probability for your case, but in any case single stepping by machine instruction should identify what's going on.

answered on Stack Overflow Jan 16, 2018 by Peter Maydell

User contributions licensed under CC BY-SA 3.0