[prev in list] [next in list] [prev in thread] [next in thread] 

List:       netbsd-port-arm
Subject:    [PATCH] - gdb crashes in call command.
From:       Gopikrishnan S <gokrix () yahoo ! com>
Date:       2019-09-25 21:07:26
Message-ID: 909128281.6768892.1569445646516 () mail ! yahoo ! com
[Download RAW message or body]

------=_Part_6768891_1887562626.1569445646515
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable



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 the crash is caused by a \
stack corruption as described below.


I debugged this and found out that gdb was crashing in the function \
regcache::restore() in regcache.c, in 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)=


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic