I ran into some failures for test-case gdb.dwarf2/dw2-lines.exp on arm-linux with target board unix/mthumb. The simplest way to reproduce what I think is the root cause for those failures is: ... $ gcc src/gdb/testsuite/gdb.dwarf2/dw2-lines.c -mthumb $ gdb -q -batch a.out -ex "b bar" Breakpoint 1 at 0x4f2 ... with bar disassembly looking like: ... 000004ec <bar>: 4ec: b580 push {r7, lr} 4ee: af00 add r7, sp, #0 000004f0 <bar_label>: 4f0: 2001 movs r0, #1 4f2: f7ff fff1 bl 4d8 <foo> ... The insn at 4f0 has nothing to do with stack setup, and shouldn't be skipped. Interestingly, with -marm (using arm_analyze_prologue) we do get the desired result: ... $ gcc src/gdb/testsuite/gdb.dwarf2/dw2-lines.c -marm $ gdb -q -batch a.out -ex "b bar" Breakpoint 1 at 0x500 ... while the disassembly is very similar: ... 000004f8 <bar>: 4f8: e92d4800 push {fp, lr} 4fc: e28db004 add fp, sp, #4 00000500 <bar_label>: 500: e3a00001 mov r0, #1 504: ebfffff3 bl 4d8 <foo> ... With arm_analyze_prologue, the mov insn is unrecognized, and so we hit this code: ... { /* The optimizer might shove anything into the prologue, if we build up cache (cache != NULL) from scanning prologue, we just skip what we don't recognize and scan further to make cache as complete as possible. However, if we skip prologue, we'll stop immediately on unrecognized instruction. */ unrecognized_pc = current_pc; if (cache != NULL) continue; else break; } ... and because cache == NULL, we break and return unrecognized_pc == 0x500. With thumb_analyze_prologue, the movs insn is recognized. Making it unrecognized: ... diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index f36ce631a08..2b244da0b5c 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -1150,7 +1150,7 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, /* Skip register copies, i.e. saves to another register instead of the stack. */ ; - else if ((insn & 0xf800) == 0x2000) /* movs Rd, #imm */ + else if (false && (insn & 0xf800) == 0x2000) /* movs Rd, #imm */ /* Recognize constant loads; even with small stacks these are necessary on Thumb. */ regs[bits (insn, 8, 10)] = pv_constant (bits (insn, 0, 7)); ... makes us hit this simple : ... else { /* The optimizer might shove anything into the prologue, so we just skip what we don't recognize. */ unrecognized_pc = start; } ... which sets unrecognized_pc to 0x4f0 and gets us the desired result: ... $ gdb -q -batch a.out -ex "b bar" Breakpoint 1 at 0x4f0 ... It's possible that we need to add a similar: ... if (cache == nullptr) break; ... because a subsequent unrecognized instruction would overwrite unrecognized_pc, which is not what we want. Anyway, the question is whether indeed the movs insn can be part of actual stack setup. If not, than AFAIU we can get away with: ... diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index f36ce631a08..8bafeb2e0f6 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -1150,7 +1150,7 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, /* Skip register copies, i.e. saves to another register instead of the stack. */ ; - else if ((insn & 0xf800) == 0x2000) /* movs Rd, #imm */ + else if (cache != nullptr && (insn & 0xf800) == 0x2000) /* movs Rd, #imm */ /* Recognize constant loads; even with small stacks these are necessary on Thumb. */ regs[bits (insn, 8, 10)] = pv_constant (bits (insn, 0, 7)); ... If so then, we need to keep track of insn-after-last-stack-related-insn, and return that.
The master branch has been updated by Tom de Vries <vries@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=798bb5cc53edfa13673038b7d76ff09dadfaacb5 commit 798bb5cc53edfa13673038b7d76ff09dadfaacb5 Author: Tom de Vries <tdevries@suse.de> Date: Fri Aug 16 14:22:46 2024 +0200 [gdb/testsuite] Fix gdb.dwarf2/dw2-fixed-point.exp on arm-linux With test-case gdb.dwarf2/dw2-fixed-point.exp on arm-linux I run into: ... (gdb) PASS: gdb.dwarf2/dw2-fixed-point.exp: set lang ada print pck.fp1_var^M $1 = 0.3125^M (gdb) FAIL: gdb.dwarf2/dw2-fixed-point.exp: print pck.fp1_var ... The problem is that the thumb prologue analyzer overshoot, setting the breakpoint for main after line 49: ... 46 int 47 main (void) 48 { 49 pck__fp1_var++; ... and consequently we see the value of pck.fp1_var after line 49 instead of before line 49. This is PR tdep/31981. Work around this by removing line 49 and all similar subsequent lines, which turn out to be dead code. Approved-By: Luis Machado <luis.machado@arm.com> Tested on arm-linux.
The master branch has been updated by Tom de Vries <vries@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=3bd0f5c4d9924be476bdcf6a3d77d7b212d22523 commit 3bd0f5c4d9924be476bdcf6a3d77d7b212d22523 Author: Tom de Vries <tdevries@suse.de> Date: Wed Sep 4 10:07:19 2024 +0200 [gdb/testsuite] Fix gdb.dwarf2/dw2-lines.exp on arm-linux With test-case gdb.dwarf2/dw2-lines.exp on arm-linux, I run into: ... (gdb) break bar_label^M Breakpoint 2 at 0x4004f6: file dw2-lines.c, line 29.^M (gdb) continue^M Continuing.^M ^M Breakpoint 2, bar () at dw2-lines.c:29^M 29 foo (2);^M (gdb) PASS: $exp: cv=2: cdw=32: lv=2: ldw=32: continue to breakpoint: foo \(1\) ... The pass is incorrect because the continue lands at line 29 with "foo (2)" instead of line line 27 with "foo (1)". A minimal version is: ... $ gdb -q -batch dw2-lines.cv-2-cdw-32-lv-2-ldw-32 -ex "b bar_label" Breakpoint 1 at 0x4f6: file dw2-lines.c, line 29. ... where: ... 000004ec <bar>: 4ec: b580 push {r7, lr} 4ee: af00 add r7, sp, #0 000004f0 <bar_label>: 4f0: 2001 movs r0, #1 4f2: f7ff fff1 bl 4d8 <foo> 000004f6 <bar_label_2>: 4f6: 2002 movs r0, #2 4f8: f7ff ffee bl 4d8 <foo> ... So, how does this happen? In short: - skip_prologue_sal calls arm_skip_prologue with pc == 0x4ec, - thumb_analyze_prologue returns 0x4f2 (overshooting by 1 insn, PR tdep/31981), and - skip_prologue_sal decides that we're mid-line, and updates to 0x4f6. However, this is a test-case about .debug_line info, so why didn't arm_skip_prologue use the line info to skip the prologue? The answer is that the line info starts at bar_label, not at bar. Fixing that allows us to work around PR tdep/31981. Likewise in gdb.dwarf2/dw2-line-number-zero.exp. Instead, add a new test-case gdb.arch/skip-prologue.exp that is dedicated to checking quality of architecture-specific prologue analysis, without being written in an architecture-specific way. If fails on arm-linux for both marm and mthumb: ... FAIL: gdb.arch/skip-prologue.exp: f2: $bp_addr == $prologue_end_addr (skipped too much) FAIL: gdb.arch/skip-prologue.exp: f4: $bp_addr == $prologue_end_addr (skipped too much) ... and passes for: - x86_64-linux for {m64,m32}x{-fno-PIE/-no-pie,-fPIE/-pie} - aarch64-linux. Tested on arm-linux.