This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
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