riscvarchive / riscv-binutils-gdb

RISC-V backports for binutils-gdb. Development is done upstream at the FSF.
GNU General Public License v2.0
148 stars 233 forks source link

What is the expected behavior upon hitting a EBREAK? #245

Closed sunny-lan closed 3 years ago

sunny-lan commented 3 years ago

If in my code I have

//...
asm("ebreak");
//...

Does GDB recognize this situation and try to increment PC to the next instruction upon step or resume?

jim-wilson commented 3 years ago

GDB maintains an internal list of breakpoints. When you set a breakpoint, we emit an ebreak instruction and add it to the list. When you remove a breakpoint, the original code is written back, and it is removed from the list.

If you insert your own ebreak instruction, then gdb will first catch the breakpoint trap, and then see that it isn't a gdb breakpoint, and then announce that you hit some unknown trap. At that point you will be stuck. If you can figure out how to fix it by hand, e.g. increment the PC yourself, then maybe you can continue. But this isn't guaranteed to work.

ebreak is used for other things besides gdb breakpoints, so you should not expect that this will ever work. For instance, __builtin_trap() emits an ebreak and this is supposed to cause a program to fail with a trap. GCC will sometimes emit an ebreak when it sees invalid code that the C standard says may result in a trap. Unfortunately, ebreak doesn't take an option, so we can't distinguish different kinds of traps in the ebreak instruction itself. Hence there is no way for gdb to know that some random ebreak instruction is supposed to be a breakpoint.

sunny-lan commented 3 years ago

Thanks!

jim-wilson commented 3 years ago

There was a thread on the FSF gdb mailing list that suggested if you set a breakpoint on top of the ebreak then it should work. The thread starts with https://sourceware.org/pipermail/gdb/2021-January/049122.html and the answer https://sourceware.org/pipermail/gdb/2021-January/049125.html