How to ignore interrupts with arm gdb - c

I am trying to debug a program using arm-none-eabi-gdb and step through it. There is an interrupt, USB0_Handler, which I do not want to step into while stepping the program. To achieve this, I tried to use skip, but it didn't work, even if I try to skip the function or skip the entire file (containing the interrupt). I am using openocd to achieve the remote debugging on the tm4c123gh6pm.
I have reached a point where I don't know if I should define myself a gdb function or I am missing a point. Here is the output of my terminal :
(gdb) info skip
Num Type Enb What
1 function y USB0_Handler
(gdb) c
Continuing.
Breakpoint 2, relayTask () at ./relay.c:191
191 nextTime = rtcGetTimeIn(DEFAULT_REFRESH_RATE);
(gdb) n
USB0_Handler () at ./UsbConfig.c:326
326 {
(gdb) n
332 ui32Status = MAP_USBIntStatusControl(USB0_BASE);
(gdb) n
337 USBDeviceIntHandlerInternal(0, ui32Status);
(gdb) n
338 }
(gdb) n #returning at the top of USB0_Handler
326 {

When an interrupt is triggered while stepping, GDB usually stops because the step ended in a place it didn't expect.
Interrupt handlers are generally hard to deal with from a debugger point of view because they are executed in a new context: the stack frames are changed and unless GDB recognizes a particular pattern in the frame it won't be able to compute a complete stack trace (i.e. the interrupt handler frames + your regular program stack trace before the interrupt.)
The simplest way to get you out of the interrupt handler is to plant a breakpoint on the last line of the function, resume and continue stepping. Someone suggested to use the finish command but it may fail depending on again the quality of the stack trace.
Thanks to GDB scriptability (in python for instance) it may be possible to automate that by checking the PC and if PC is on the isr address in irq vector, fetch the return address, plant a temporary breakpoint and resume.

Related

gdb commands gdbstub to write to _Unwind_DebugHook memory location

I ported a gdbstub for an OS I'm working on which runs on x86_64. The host which is running gdb is connected to the target that has the stub and the OS over serial. I have an int3 instruction in the source code to force the OS to jump into the stub's code which it does. The problem is if I try to step to the next instruction using nexti the stub stops responding and the host keeps timing out.
Looking at the packets that the host is sending I see this:
Sending packet: $Me1dc20,1:cc#6c...Ack
Timed out.
Timed out.
Timed out.
Ignoring packet error, continuing...
which means that the host is telling the stub to write cc (which is the opcode for int3) to memory location 0xe1dc20. I looked into that memory location and found this:
(gdb) x/16i 0xe1dc20
0xe1dc20 <_Unwind_DebugHook>: retq
0xe1dc21: data16 nopw %cs:0x0(%rax,%rax,1)
0xe1dc2c: nopl 0x0(%rax)
This function is part of gcc's code here https://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-dw2.c but it is not used anywhere in the source file that I am debugging.
Now obviously it is causing me troubles so I disabled memory writing functionality in my stub so that it longer responds to memory writing commands $M and $X and when I did I was able to execute nexti and step in gdb without issues. The stub uses the RFLAGS.TF for flow control.
The question is why is gdb trying to set a breakpoint in a function that I am not using anywhere and how do I prevent it from doing so? I thought about adding an if statement in the stub to ignore writes to this memory location but is there a less intrusive way of doing it?
The _Unwind_DebugHook symbol exists as a place for GDB (or any other debugger) to place a breakpoint and so catch exceptions. GDB will look for this symbol (in the debug info), and it it exists, place a breakpoint there.
These breakpoints will always get inserted, even when doing something as simple as a stepi, just in case - you might be about to step to that address.
One problem I see with the remote trace is that GDB will be expecting an OK packet to indicate that the write succeeded, this is why you're seeing the timeout messages.

Breakpoint not working in gdb with QEMU simulating cortex-a8

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!
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.

Remote Debugging with GDB: Program dies after SIGILL, Illegal instruction

I am trying to debug code on an ARMv6-compatible processor rev 4.
I compiled the GDBserver with the --host=arm-openwrt-linux-gnueabi flag.
The gdb itself is compiled with
--host=x86_64-unknon-linux-gnu --target=arm-openwrt-linux-gnueabi --with-expat
If I now connect to the gdbserver in, my program is running in, I get the following error message:
(gdb) target remote 192.168.x.x:2345
Remote debugging using 192.168.x.x:2345
Cannot access memory at address 0x0
0xb6fdaec0 in ?? ()
(gdb) set sysroot /home/xxxxxx/Dokumente/lgn-sdk-v0.2/staging_dir/toolchain-arm_v6k_gcc-4.6-linaro_eglibc-2.15_eabi/
Reading symbols from /home/xxxxxx/Dokumente/lgn-sdk-v0.2/staging_dir/toolchain-arm_v6k_gcc-4.6-linaro_eglibc-2.15_eabi/lib/ld-linux.so.3...done.
Loaded symbols for /home/xxxxxxx/Dokumente/lgn-sdk-v0.2/staging_dir/toolchain-arm_v6k_gcc-4.6-linaro_eglibc-2.15_eabi/lib/ld-linux.so.3
(gdb) n
Single stepping until exit from function _start,
which has no line number information.
Program received signal SIGILL, Illegal instruction.
0xb6fe8d20 in _dl_debug_initialize () from /home/xxxxx/Dokumente/lgn-sdk-v0.2/staging_dir/toolchain-arm_v6k_gcc-4.6-linaro_eglibc-2.15_eabi/lib/ld-linux.so.3
(gdb)
Single stepping until exit from function _dl_debug_initialize,
which has no line number information.
Program terminated with signal SIGILL, Illegal instruction.
I don't have a complete answer, but I have a similar problem and work around it by:
connect via target remote
break main
continue
then, set sysroot
This lets me get past the crash. I'd certainly be interested in a better solution, though.

Program received signal SIGTRAP, Trace/breakpoint trap

I'm debugging a piece of (embedded) software. I've set a breakpoint on a function, and for some reason, once I've reached that breakpoint and continue I always come back to the function (which is an initialisation function which should only be called once). When I remove the breakpoint, and continue, GDB tells me:
Program received signal SIGTRAP, Trace/breakpoint trap.
Since I was working with breakpoints, I'm assuming I fell in a "breakpoint trap". What is a breakpoint trap?
Breakpoint trap just means the processor has hit a breakpoint. There are two possibilities for why this is happening. Most likely, your initialization code is being hit because your CPU is resetting and hitting the breakpoint again. The other possibility would be that the code where you set the breakpoint is actually run in places other than initialization. Sometimes with aggressive compiler optimization it can be hard to tell exactly which code your breakpoint maps to and which execution paths can get there.
The other possibility i can think of is:
1.Your process is running more than one thread.
For eg - 2 say x & y.
2.Thread y hits the break point but you have attached gdb to thread x.
This case is a Trace/breakpoint trap.
I got this problem running linux project in Visual studio 2015 and debugging remotely. My solution is project_properties -> Configuration properties -> Debugging -> Debugging mode and change the value from "gdbserver" to "gdb"
If you use V BAT as backup supply and your backup voltage drives lower than 1.65V then you get the same problem after conecting to a power supply.
In this case you have to disconnect all power supplies and reconnect with correct voltage level. Then the problem with debugging goes away.
I stucked with the same problem and in my
case the solution is to decrease SWDs frequency.
(I've got soldering staff between mcu and host, not so reliable)
I changed 4000k to 100k and problem gone.

why am i getting a SIGTRAP in gdb while debugging Ruby C extension?

I want to use rb_p() to aid in debugging a ruby C extension, but everytime i use it i get a SIGTRAP in gdb!
here's an example:
(gdb) p user_defaults
$3 = 137559900
(gdb) call rb_p(user_defaults)
{:fill=>true, :texture=>#}
(gdb) n
Program received signal SIGTRAP, Trace/breakpoint trap.
is_a_hash (try_hash=137560420) at utils.c:65
(gdb)
why does this happen? how can i stop it happening??
SIGTRAP is caused by a breakpoint exception, specifically by the int3 instruction on x86 (interrupt 3). Your code is probably executing an int3. Take a look where gdb is telling you -- at utils.c line 65 in the is_a_hash() function. If you don't have access to the source code, you can at least get the disassembly from gdb by typing
disas try_hash
at the gdb prompt.

Resources