Re: [PATCH] i386_stab_reg_to_regnum (4 <-> 5, ebp <-> esp)

Jim Blandy
2004-04-01T17:22:28Z

Brian Ford <ford@vss.fsi.com> writes:
> Notice that gcc regno 6 (ebp) and 7 (esp) map to regno 4 and 5
> respectively in the "default" (aka dbx, stabs, sdb) table. But, in
> the svr4 (aka dwarf, dwarf2, stabs-in-elf) table, they map to regno 5 and
> 4 respectively.
>
> I'm not sure if/how this should affect i386_register_names. I also hope
> that targets have not already coded around this bug so that fixing it will
> break something else :-). Please do have a look at these issues before
> applying the patch. I'm afraid they are over my head right now.

Yeah, wow. So, one thing that surprised me is that, for any given
platform, GCC always uses the same register numbering in STABS and
Dwarf 2 --- gcc/dwarf2out.c and gcc/dbxout.c both use
DBX_REGISTER_NUMBER. But if that's so, why does gdb/i386-tdep.c have
two separate (and different!) STABS and Dwarf register number
functions?

The points where they differ are in the numbering of the
floating-point registers, and in numbering %eip and %eflags. But it
doesn't look to me as if Dwarf and STABS actually do differ in the
numbering of floating-point registers:

$ cat fpregs.c
#include <stdio.h>
#include <stdlib.h>

double
foo (register int n)
{
register int i;
register double a = n * 1.5;
register double b = n * 2.25;
register double c = n * 3.125;
register double d = n * 4.0625;
register double e = n * 5.03125;

for (i = 0; i < n; i++)
{
if (i & 1) a = b + c; else a = c + e;
if (i & 2) b = c + d; else b = d + a;
if (i & 4) c = d + e; else c = e + b;
if (i & 8) d = e + a; else d = a + c;
if (i & 16) e = a + b; else e = b + d;
}

return a + b + c + d + e;
}

int
main (int argc, char **argv)
{
if (argc == 2)
printf ("%lf\n", foo (atoi (argv[1])));
}
$ gcc33 gcc -g -O fpregs.c -o fpregs
$ readelf -wi fpregs > fpregs.wi~
$ gcc33 gcc -gstabs+ -O fpregs.c -o fpregs
$ objdump --stabs fpregs > fpregs.stabs~
$

If I look at what fpregs.stabs~ says about foo's local variables, I
see:

268 RSYM 0 5 00000002 9327 n:r(0,1)
269 RSYM 0 7 00000000 9336 i:r(0,1)
270 RSYM 0 8 0000000f 9345 a:r(0,13)
271 RSYM 0 9 0000000b 9355 b:r(0,13)
272 RSYM 0 10 0000000e 9365 c:r(0,13)
273 RSYM 0 11 0000000d 9375 d:r(0,13)
274 RSYM 0 12 0000000c 9385 e:r(0,13)

The fifth column is the stab's value, which is the register number. 'a'
is assigned to register 15, 'b' is assigned register 11, and so on.

In fpregs.wi~, I see:

<2><1da2>: Abbrev Number: 31 (DW_TAG_formal_parameter)
DW_AT_name : n
DW_AT_decl_file : 1
DW_AT_decl_line : 5
DW_AT_type : <d0f>
DW_AT_location : 1 byte block: 52 (DW_OP_reg2; )
<2><1dad>: Abbrev Number: 32 (DW_TAG_variable)
DW_AT_name : i
DW_AT_decl_file : 1
DW_AT_decl_line : 7
DW_AT_type : <d0f>
DW_AT_location : 1 byte block: 50 (DW_OP_reg0; )
<2><1db8>: Abbrev Number: 32 (DW_TAG_variable)
DW_AT_name : a
DW_AT_decl_file : 1
DW_AT_decl_line : 8
DW_AT_type : <1df0>
DW_AT_location : 1 byte block: 5f (DW_OP_reg15; )
<2><1dc3>: Abbrev Number: 32 (DW_TAG_variable)
DW_AT_name : b
DW_AT_decl_file : 1
DW_AT_decl_line : 9
DW_AT_type : <1df0>
DW_AT_location : 1 byte block: 5b (DW_OP_reg11; )
<2><1dce>: Abbrev Number: 32 (DW_TAG_variable)
DW_AT_name : c
DW_AT_decl_file : 1
DW_AT_decl_line : 10
DW_AT_type : <1df0>
DW_AT_location : 1 byte block: 5e (DW_OP_reg14; )
<2><1dd9>: Abbrev Number: 32 (DW_TAG_variable)
DW_AT_name : d
DW_AT_decl_file : 1
DW_AT_decl_line : 11
DW_AT_type : <1df0>
DW_AT_location : 1 byte block: 5d (DW_OP_reg13; )
<2><1de4>: Abbrev Number: 32 (DW_TAG_variable)
DW_AT_name : e
DW_AT_decl_file : 1
DW_AT_decl_line : 12
DW_AT_type : <1df0>
DW_AT_location : 1 byte block: 5c (DW_OP_reg12; )

In other words, GCC is using the same numbering for floating-point
registers in both formats --- which verifies what we expected from
looking at the code anyway. So we're not crazy.

So I think the best fix is to have i386-tdep.c use two register number
translation functions that correspond to gcc/config/i386/i386.c's
dbx_register_map and svr4_dbx_register_map, and then register one
function or the other as both the stabs and dwarf 2 translation
functions, as appropriate for a given platform.

The problem is that this affects lots of other targets, which we can't
test. And it assumes that GCC has its register numberings right on
all those targets. I have no idea whether it does.

Having said all that, I'd guess the right immediate fix is to register
an osabi handler for GDB_OSABI_CYGWIN, down at the bottom of
gdb/i386-tdep.c:_initialize_i386_tdep, that plugs in the right
gdbarch_dwarf2_reg_to_regnum function for Cygwin. And leave the
existing _to_regnum functions unchanged.