This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Large number of C++ regressions in past couple of days


On Sat, Jul 15, 2000 at 11:14:20AM -0700, H . J . Lu wrote:
> On Sat, Jul 15, 2000 at 11:08:27AM -0700, Zack Weinberg wrote:
> > On Sat, Jul 15, 2000 at 10:41:25AM -0700, H . J . Lu wrote:
> > > On Sat, Jul 15, 2000 at 10:38:58AM -0700, Zack Weinberg wrote:
> > > > 
> > > > I'm suddenly getting a huge flood of C++ regressions.  See the list at
> > > > the end.  They all appear to have something to do with exception
> > > > handling.
> > > 
> > > Have you enabled shared libstdc++? Are you building gcc under glibc 2?
> > 
> > No and yes (2.1.3), respectively.
> 
> As you may know, the EH ABI has changed. But the old EH functions are
> still in libc.so in glibc.

This is a different problem.  Here's a debug trace - note that, due to
optimization, the debug info is useless, so I'm working at the
assembly level.

$ gdb ./g++-brendan-eh1-C
(gdb) r
Program received signal SIGSEGV, Segmentation fault.
0x8049bf7 in find_fde (pc=0x804906f)    at frame-dwarf2.c:479
479         {
(gdb) bt
#0  0x8049bf7 in find_fde (pc=0x804906f)   at frame-dwarf2.c:479
#1  0x804a460 in __frame_state_for (pc_target=0x804906f, state_in=0xbffffa94)
    at frame-dwarf2.c:609
#2  0x8049085 in __throw () at libgcc2.c:3168
#3  0x8048285 in Foo::goodTest (this=0xbffffb54) at g++.brendan/eh1.C:42
#4  0x80482c7 in main () at g++.brendan/eh1.C:57
(gdb) disas $pc $pc + 20
Dump of assembler code from 0x8049bf7 to 0x8049c0b:
0x8049bf7 <find_fde+39>:        mov    (%esi),%eax
0x8049bf9 <find_fde+41>:        test   %eax,%eax
0x8049bfb <find_fde+43>:        jne    0x8049c0b <find_fde+59>
0x8049bfd <find_fde+45>:        sub    $0xc,%esp
0x8049c00 <find_fde+48>:        push   %esi
0x8049c01 <find_fde+49>:        call   0x8049a50 <frame_init>
0x8049c06 <find_fde+54>:        mov    (%esi),%eax
0x8049c08 <find_fde+56>:        add    $0x10,%esp
(gdb) info registers
eax            0x804906f        134516847
ecx            0x807ef70        134737776
edx            0xbffffa94       -1073743212
ebx            0x807da28        134732328
esp            0xbffff964       -1073743516
ebp            0xbffff97c       -1073743492
esi    ****    0x10101010       269488144
edi            0x0      0
eip            0x8049bf7        134519799

We're in the loop at the top of find_fde:

  /* Linear search through the objects, to find the one containing the pc. */
  for (ob = objects; ob; ob = ob->next)
    {
      if (ob->pc_begin == 0)
	frame_init (ob);
      if (pc >= ob->pc_begin && pc < ob->pc_end)
	break;
    }

(gdb) p objects
$1 = (struct object *) 0x10101010

Hmmm...

(gdb) b __register_frame_info
(gdb) r
Breakpoint 1, 0x80497a4 in __register_frame_info (begin=0x807ce60, 
    ob=0x807db40) at /work/src/proto.gcc/gcc/frame-dwarf2.c:479
(gdb) p objects
$2 = (struct object *) 0x0
(gdb) stepi # until the return from __r_f_i
(gdb) p objects
$3 = (struct object *) 0x807db40
(gdb) p *$3
$4 = {pc_begin = 0x0, pc_end = 0x0, fde_begin = 0x807ce60, fde_array = 0x0, 
  count = 0, next = 0x0}

Okay - that looks fine so far...

(gdb) watch *(long *) &objects
Hardware watchpoint 2: *(long *) &objects
(gdb) c
Hardware watchpoint 2: *(long *) &objects

Old value = 0x0807db40
New value = 0x1007db40
0x804841a in init_reg_size_table () at /work/src/proto.gcc/gcc/libgcc2.c:3167
(gdb) disas $pc
0x80483c0 <init_reg_size_table>:      push   %ebp
0x80483c1 <init_reg_size_table+1>:    mov    %esp,%ebp
0x80483c3 <init_reg_size_table+3>:    push   %ebx
0x80483c4 <init_reg_size_table+4>:    call   0x8048300 <__default_terminate+16>
0x80483c9 <init_reg_size_table+9>:    add    $0x3565f,%ebx
0x80483cf <init_reg_size_table+15>:   mov    $0x1,%ecx
0x80483d4 <init_reg_size_table+20>:   movb   $0x8,0x248(%ebx)
...
0x804841a <init_reg_size_table+90>:     movb   $0x10,0x23e(%ebx)
0x8048421 <init_reg_size_table+97>:     movb   $0x10,0x23d(%ebx)
...
0x80484b4 <init_reg_size_table+244>:    movb   $0x4,0x224(%ebx)
0x80484bb <init_reg_size_table+251>:    mov    %ecx,0xffffe170(%ebx)
0x80484c1 <init_reg_size_table+257>:    pop    %ebx
0x80484c2 <init_reg_size_table+258>:    pop    %ebp
0x80484c3 <init_reg_size_table+259>:    ret    


Aha! That's where 0x10101010 came from.

Here's the source listing of init_reg_size_table:

static int dwarf_reg_size_table_initialized = 0;
static char dwarf_reg_size_table[DWARF_FRAME_REGISTERS];

static void
init_reg_size_table (void)
{
  __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table);
  dwarf_reg_size_table_initialized = 1;
}

(gdb) p &dwarf_reg_size_table
$9 = (char (*)[17]) 0x807dc4c
(gdb) p &objects
$10 = (struct object **) 0x807dc64
(gdb) p (unsigned long) $10 - (unsigned long)$9
$11 = 24

The 'objects' list head is located 24 bytes after the beginning of
dwarf_reg_size_table.  DWARF_FRAME_REGISTERS is 17, so presumably we
have some padding between objects and d_r_s_t.  But
__builtin_init_dwarf_reg_size_table expands to 33 movb instructions,
which write over the 33 consecutive bytes starting at 0x224(%ebx) -
which is the address of dwarf_reg_size_table.

In other words, __b_i_d_r_s_t expects to be initializing an array of
33 bytes, but we're only giving it 17.  Boom.

This can't have anything to do with glibc; the array and the
initialization routine are right next to each other in the same file.
Here's the code of the routine that expands bidrst:

void
expand_builtin_init_dwarf_reg_sizes (address)
     tree address;
{
  int i;
  enum machine_mode mode = TYPE_MODE (char_type_node);
  rtx addr = expand_expr (address, NULL_RTX, VOIDmode, 0);
  rtx mem = gen_rtx_MEM (mode, addr);

  i = MAX (FIRST_PSEUDO_REGISTER, DWARF_FRAME_REGISTERS); /*******/
  while (i--)
    {
      int offset = DWARF_FRAME_REGNUM (i) * GET_MODE_SIZE (mode);
      int size = GET_MODE_SIZE (reg_raw_mode[i]);

      if (offset < 0)
        continue;

      emit_move_insn (change_address (mem, mode,
                                      plus_constant (addr, offset)),
                      GEN_INT (size));
    }
}

Note the MAX() expression.  That appeared with this change, although
it appears to be unrelated to it:

2000-07-14  Jason Merrill  <jason@redhat.com>

        * dwarf2out.c (dwarf2out_frame_debug_expr): If we store the CFA
        register in the stack and later in another register, use the new
        register.

--- dwarf2out.c 2000/06/30 07:51:39     1.183
+++ dwarf2out.c 2000/07/14 17:40:38     1.184
@@ -626,7 +626,8 @@ expand_builtin_init_dwarf_reg_sizes (add
   rtx addr = expand_expr (address, NULL_RTX, VOIDmode, 0);
   rtx mem = gen_rtx_MEM (mode, addr);
 
-  for (i = 0; i < DWARF_FRAME_REGISTERS; ++i)
+  i = MAX (FIRST_PSEUDO_REGISTER, DWARF_FRAME_REGISTERS);
+  while (i--)
     {
       int offset = DWARF_FRAME_REGNUM (i) * GET_MODE_SIZE (mode);
       int size = GET_MODE_SIZE (reg_raw_mode[i]);

Jason, what was the intent of that change?

zw

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]