Port-arm archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Ping: [PATCH] - gdb crashes in call command



Hello,

Could someone please let me know how to get in touch with the gdb maintainer for ARM?

For reference, the original patch was sent on the 26th of September.

Thanks,
--Gopikrishnan Sidhardhan


-------- Forwarded Message --------
Subject: [PATCH] - gdb crashes in call command
Date: Thu, 26 Sep 2019 11:02:20 +0530
From: Gopikrishnan S <gokrix%yahoo.com@localhost>
To: port-arm%NetBSD.org@localhost

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