Port-arm archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[PATCH] - gdb crashes in call command
Hello,
I have NetBSD 8.99.51 running on a Raspberry Pi 3B. When invoking a
function in the inferior from the gdb command line with the call command
gdb crashes:
Reading symbols from test...
(gdb) b main
Breakpoint 1 at 0x106f0: file test.c, line 13.
(gdb) r
Starting program: /home/gopikris/C/test
Breakpoint 1, main () at test.c:13
13 printf("Hello, World!\n");
(gdb) li 0
1 #include <stdlib.h>
2 #include <stdio.h>
3
4 static int m = 10;
5
6 int func(int p)
7 {
8 return m + p;
9 }
10
(gdb)
11 int main(void)
12 {
13 printf("Hello, World!\n");
14 return EXIT_SUCCESS;
15 }
(gdb) call func(1)
[ 547105.5763672] sorry, pid 10467 was killed: orphaned traced process
Segmentation fault (core dumped)
We never get a proper stack-trace for this crash, since it is caused by
a stack corruption as described below.
gdb is crashing in the function regcache::restore() in regcache.c, on
the 19th iteration of the following loop:
/* Copy over any registers, being careful to only restore those that
were both saved and need to be restored. The full [0 ..
gdbarch_num_regs
+ gdbarch_num_pseudo_regs) range is checked since some
architectures need
to save/restore `cooked' registers that live in memory. */
for (regnum = 0; regnum < m_descr->nr_cooked_registers; regnum++)
{
if (gdbarch_register_reggroup_p (gdbarch, regnum, restore_reggroup))
{
if (src->m_register_status[regnum] == REG_VALID)
cooked_write (regnum, src->register_buffer (regnum));
}
}
The loop executes from regnum == 0 to regnum == 90, since
m_descr->nr_cooked_registers is 91, by virtue of the constant
ARM_NUM_REGS in the enum gdb_regnum in arch/arm.h being 91.
cooked_write() ultimately calls arm_nbsd_nat_target::store_registers()
with regno == 19, which in turn passes this regno to store_register().
In store_reg() the default case (cases other than special registers like
cpsr, sp, lr, and pc) is to update the regno-th member of the array
regs.r. But for arm, regs.r is an array of length 13 and so when regno
is greater than 12 this overwrites various parts of the stack. In
particular, it overwrites the area of the stack where the r11 register
is stored at function entry, and thus at function exit gdb goes off into
the weeds with a wrong pc.
The solution in the patch pasted below is for
arm_nbsd_nat_target::store_registers() to call store_register() only
when we know that regnum corresponds to a register defined in struct
reg, i.e., only when the regnum corresponds to ARM_A1_REGNUM (reg.r[0])
to ARM_PC_REGNUM(reg.r_pc) and for ARM_PS_REGNUM (reg.r_cpsr).
A corresponding change has been made in fetch_registers as well.
This change applies only to the NetBSD version of gdb. The upstream code
is subtly different and thus does not have this bug (but may have other
bugs).
-------------Begin patch-----------------
diff --git a/usr/src/external/gpl3/gdb/dist/gdb/arm-nbsd-nat.c
b/usr/src/external/gpl3/gdb/dist/gdb/arm-nbsd-nat.c
index e4b6119a16..d3040c2cd2 100644
--- a/usr/src/external/gpl3/gdb/dist/gdb/arm-nbsd-nat.c
+++ b/usr/src/external/gpl3/gdb/dist/gdb/arm-nbsd-nat.c
@@ -47,6 +47,7 @@ public:
void store_registers (struct regcache *, int) override;
};
+static int arm_nbsd_nat_debug;
static arm_nbsd_nat_target the_arm_nbsd_nat_target;
extern int arm_apcs_32;
@@ -257,9 +258,13 @@ arm_nbsd_nat_target::fetch_registers (struct
regcache *regcache, int regno)
if (regno >= 0)
{
if (regno >= ARM_D0_REGNUM && regno <= ARM_FPSCR_REGNUM)
- fetch_fp_register (regcache, regno);
+ fetch_fp_register (regcache, regno);
+ else if ((regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM) ||
+ (regno == ARM_PS_REGNUM))
+ fetch_register (regcache, regno);
else
- fetch_register (regcache, regno);
+ if (arm_nbsd_nat_debug)
+ warning (_("Cannot access register %d on NetBSD."), regno);
}
else
{
@@ -443,9 +448,13 @@ arm_nbsd_nat_target::store_registers (struct
regcache *regcache, int regno)
if (regno >= 0)
{
if (regno >= ARM_D0_REGNUM && regno <= ARM_FPSCR_REGNUM)
- store_fp_register (regcache, regno);
+ store_fp_register (regcache, regno);
+ else if ((regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM) ||
+ (regno == ARM_PS_REGNUM))
+ store_register (regcache, regno);
else
- store_register (regcache, regno);
+ if (arm_nbsd_nat_debug)
+ warning (_("Cannot access register %d on NetBSD."), regno);
}
else
{
---------------End patch-------------------
Thanks,
--Gopikrishnan Sidhardhan
Home |
Main Index |
Thread Index |
Old Index