Program counter off by 4 bytes at breakpoint


(Benjamin Ou) #1

EDIT: Nevermind, this is a known issue in the 4.15 kernel; 4.19 fixes it.

Been experimenting with riscv-native GDB. Here’s my test program:

char text[] = "Vafgehpgvba frgf jnag gb or serr!";  
// Don't use the stack, because sp isn't set up.
volatile int mywait = 0;
int main() {

asm volatile("ebreak");
   
// Doesn't actually go on the stack, because there are lots of GPRs.
int i = 0;  
while (text[i]) {
    char lower = text[i] | 32;      
    if (lower >= 'a' && lower <= 'm')
        text[i] += 13;
    else if (lower > 'm' && lower <= 'z')
        text[i] -= 13;
    i++;    
    }
}  

The important part here is the inlined EBREAK instruction - this is a variant on an earlier test I did where I noticed the program counter was off when I inserted a breakpoint in GDB. I wanted to make sure it didn’t have something to do with GDB’s breakpoint insertion somehow messing up the PC.

Anyways, this is the decompiled object code:

00000000000103da <main>:
   103da:       1101                    addi    sp,sp,-32
   103dc:       ec22                    sd      s0,24(sp)
   103de:       1000                    addi    s0,sp,32
   103e0:       9002                    ebreak
   103e2:       0001                    nop
   103e4:       67c9                    lui     a5,0x12

As can be seen, the ebreak instruction is at address 103e0. However, this is the output of the signal log in GDB for this program:

(gdb) run

LNW: waitpid(-1, ...) returned 1403, ERRNO-OK
LLW: waitpid 1403 received Trace/breakpoint trap (stopped)
target_fetch_registers (pc) = e403010000000000 0x103e4 66532
CSBB: process 1403 stopped by software breakpoint
LNW: waitpid(-1, ...) returned 0, ERRNO-OK
RSRL: NOT resuming LWP process 1403, has pending status
LLW: trap ptid is process 1403.
LLW: exit
infrun: target_wait (-1.0.0, status) =
infrun:   1403.1403.0 [process 1403],
infrun:   status-&gt;kind = stopped, signal = GDB_SIGNAL_TRAP
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0x103e4

As can be seen, stop_pc is at 103e4, instead of 103e0. This is the exact same thing I’ve seen when the breakpoint is manually inserted instead of an inlined EBREAK instruction causing it. You can also see the four-byte shift skips over the two-byte compressed NOP, so this could cause some serious problems if trying to debug a program with compressed instructions.

I’m wondering if this could have to do with the riscv linux kernel’s trap handler not properly decrementing the PC. If it’s not that, does anyone have other ideas as to what could be causing this?


(Jim Wilson) #2

Yes, you need the 4.19 linux kernel to get enough fixes to make gdb work. This has the integer register support. The FP register support was added in 4.20.