Bug 117826 - (IT_49459) CRM #310828: gcc/c++ produces 2 copies of constructors on RHEL 3
CRM #310828: gcc/c++ produces 2 copies of constructors on RHEL 3
Status: CLOSED ERRATA
Product: Red Hat Enterprise Linux 3
Classification: Red Hat
Component: gdb (Show other bugs)
3.0
All Linux
medium Severity medium
: ---
: ---
Assigned To: Jeff Johnston
Jay Turner
:
Depends On:
Blocks: 146413 193763
  Show dependency treegraph
 
Reported: 2004-03-08 18:46 EST by Don Howard
Modified: 2015-01-07 19:07 EST (History)
7 users (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2005-05-19 08:09:48 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)
C++ test case that results in 2 copies of each constructor (1.56 KB, application/octet-stream)
2004-03-08 18:50 EST, Don Howard
no flags Details
new test case provided by client (487 bytes, application/x-gzip)
2005-01-12 14:15 EST, Dave Maley
no flags Details

  None (edit)
Description Don Howard 2004-03-08 18:46:33 EST
client is reporting a problem w/ the way gcc is producing debug 
symbol tables under RHEL3. 
---------- 
Action by: dmaley 
By default, gcc and g++/c++ do not produce debug symbol tables in 
the correct  
format for debugging on RedHat Enterprise Linux 3.0.  
  
This seems to be the case for RHEL 3 on x86, x86-64 (Opteron) AND 
ia64 (Itanium).  
  
One *should* simply be able to add the flag "-g" to the compile line 
to get an  
executable that can be debugged by gdb.  This appears to be broken 
on RHEL3.  
  
Using the attached source files:  
  
## the following will produce an executable that gdb  
## on RedHat Enterprise Linux will not properly debug  
  
g++ -g -o stuff main1.C IntArray.C  
  
## the following will produce the proper debug symbol table 
information  
## for gdb on RedHat Enterprise Linux  
  
g++ -gstabs+ -o stuff2 main1.C IntArray.C  
  
If you look at the debug symbol tables that are generated, by 
examining the  
assembly code, it looks like the default debug information is going 
into  
seperate .debug_* sections.  It appears that gdb expects to see the 
debug  
information as .stabs.
Comment 1 Don Howard 2004-03-08 18:50:35 EST
Created attachment 98388 [details]
C++ test case that results in 2 copies of each constructor
Comment 2 Don Howard 2004-03-08 18:51:29 EST
Ok, after digging some more I came across this: 
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=3187 - gcc lays down two 
copies of constructors 
 
This appears to be what is happening here: 
 
gdb) p IntArray 
$1 = {void (IntArray * const, int)} 0x8048ae8 <IntArray> 
... 
 
gdb) where 
#0  0x08048ca3 in IntArray::init(int const*, int) (this=0xbfffb660, 
array=0x0, 
    sz=12) at IntArray.C:42 
#1  0x08048b47 in IntArray (this=0xbfffb660, sz=12) at IntArray.C:11 
 
 
This could be the cause of gdb's confusion, so I am setting this 
back as a gcc bug... 
 
 
 
08048ae8 <_ZN8IntArrayC2Ei>: 
 8048ae8:       55                      push   %ebp 
 8048ae9:       89 e5                   mov    %esp,%ebp 
 8048aeb:       83 ec 08                sub    $0x8,%esp 
 8048aee:       8b 45 08                mov    0x8(%ebp),%eax 
 8048af1:       c7 00 a8 a7 04 08       movl   $0x804a7a8,(%eax) 
 8048af7:       8b 45 0c                mov    0xc(%ebp),%eax 
 8048afa:       89 45 fc                mov    %eax,0xfffffffc(%ebp) 
 8048afd:       c7 45 f8 00 00 00 00    movl   $0x0,0xfffffff8(%ebp) 
 8048b04:       83 ec 04                sub    $0x4,%esp 
 8048b07:       ff 75 fc                pushl  0xfffffffc(%ebp) 
 8048b0a:       ff 75 f8                pushl  0xfffffff8(%ebp) 
 8048b0d:       ff 75 08                pushl  0x8(%ebp) 
 8048b10:       e8 0b 01 00 00          call   8048c20 
<_ZN8IntArray4initEPKii> 
 8048b15:       83 c4 10                add    $0x10,%esp 
 8048b18:       c9                      leave 
 8048b19:       c3                      ret 
 
08048b1a <_ZN8IntArrayC1Ei>: 
 8048b1a:       55                      push   %ebp 
 8048b1b:       89 e5                   mov    %esp,%ebp 
 8048b1d:       83 ec 08                sub    $0x8,%esp 
 8048b20:       8b 45 08                mov    0x8(%ebp),%eax 
 8048b23:       c7 00 a8 a7 04 08       movl   $0x804a7a8,(%eax) 
 8048b29:       8b 45 0c                mov    0xc(%ebp),%eax 
 8048b2c:       89 45 fc                mov    %eax,0xfffffffc(%ebp) 
 8048b2f:       c7 45 f8 00 00 00 00    movl   $0x0,0xfffffff8(%ebp) 
 8048b36:       83 ec 04                sub    $0x4,%esp 
 8048b39:       ff 75 fc                pushl  0xfffffffc(%ebp) 
 8048b3c:       ff 75 f8                pushl  0xfffffff8(%ebp) 
 8048b3f:       ff 75 08                pushl  0x8(%ebp) 
 8048b42:       e8 d9 00 00 00          call   8048c20 
<_ZN8IntArray4initEPKii> 
 8048b47:       83 c4 10                add    $0x10,%esp 
 8048b4a:       c9                      leave 
 8048b4b:       c3                      ret 
 
Comment 3 Don Howard 2004-03-08 19:03:00 EST
gnu bug reports: 
 
for gcc	 
	http://gcc.gnu.org/bugzilla/show_bug.cgi?id=3187 
for gdb  
	http://gcc.gnu.org/bugzilla/show_bug.cgi?id=10512 
 
 
Comment 4 Jakub Jelinek 2004-03-09 05:16:37 EST
The 2 entry-points of a C++ constructor (in-charge vs. not-in-charge) is required by the ABI
(http://www.codesourcery.com/cxx-abi/).
gdb handles DWARF2 debugging information, if gdb shipped in RHEL3
doesn't handle multiple entry points, it is likely gdb's fault.
Comment 5 David Lawrence 2004-03-15 13:53:31 EST
Changing product and version.
Comment 6 David Lawrence 2004-03-15 13:54:53 EST
Changing product and version.
Comment 8 Don Howard 2004-06-03 18:15:26 EDT
When I asked about fixing this in gdb the response was "maybe in 
RHEL 4". 
 
There is some chance that it can be fixed in gcc with a decloning 
patch described here: 
 
 
http://gcc.gnu.org/ml/gcc-patches/2002-08/msg00354.html 
I asked gcc folks about this last month, but I've not been able to 
persue it.  I'll try to get this issue moving again. 
 
Comment 9 Don Howard 2004-06-03 19:52:33 EDT
After a further interview with Jason Merrill, it turns out that the 
patch mentioned above won't address the problem.   
Comment 16 Jay Turner 2004-08-19 11:12:14 EDT
So this issue should be removed from the U3 blocker list and added to
the U4 one?  Just trying to close the loop and get U3 out the door.
Comment 22 Jeff Johnston 2004-11-09 18:24:15 EST
A patch has been applied to gdb as of release .48 to expose the
multiple constructors and destructors for the purpose of setting
breakpoints.  The "new" constructor will have the regular name.  The
base constructor will have $base appended to the constructor name, and
the allocation constructor will have $allocate appended.  

For example, if the constructor is A::A(), the end-user can set
breakpoints on A::A(), A::A$base(), and A::$allocate().  Using
single-quotes and the tab key will show what constructors there are
(usually just the new constructor and base constructor).  The base
constructor is called when an inheriting class runs its constructor. 
It is recommended that the end-user apply breakpoints to all versions
of the constructor that exist.  

There are likewise, 3 destructor names.  Regular, $base, and $delete.
 Again, the single-quote and tab-key can be used to expose the names
or the breakpoints can be set explicitly.

Additional work is required in gdb internals to make this transparent
to the end-user (i.e. so only one breakpoint is set using the regular
constructor/destructor names).  For the mean-time, this patch will
allow debugging to work.
Comment 37 John Flanagan 2004-12-21 14:36:55 EST
An advisory has been issued which should help the problem
described in this bug report. This report is therefore being
closed with a resolution of ERRATA. For more information
on the solution and/or where to find the updated files,
please follow the link below. You may reopen this bug report
if the solution does not work for you.

http://rhn.redhat.com/errata/RHBA-2004-561.html
Comment 38 Dave Maley 2005-01-12 14:11:36 EST
client does not feel that the original problem she reported has been resolved -
reopening

*******************************************************

I have another very simple example of the mismatch between the native compiler
and the native debugger on RedHat EL3.

In this example, the debugger WILL NOT stop at a valid breakpoint.  The
breakpoint is set in a constructor; the constructor is *declared* in a header
file, but *defined* in a .C file.

The interesting thing is that if the program is built on RedHat 7.2, then it can
be successfully debugged on RHEL3.  *HOWEVER* if the program is built on RHEL3,
then it will not stop on breakpoints set on line numbers.

If you look at the debug symbol tables generated by the two systems, they are
very different.  On RH 7.2 -g produces the SAME debug information as -gstabs+. 
On RHEL3 -g produces the SAME debug information as -gdwarf-2.  However, the
-gstabs+ information produced on RHEL3 is *NOT THE SAME* as the -gstabs+
generated on RH 7.2.  PLEASE try it yourself.

Build it simply like this:
c++ -g A.C main.C -o test.schizo

Here are some examples:
------------------------------------------------------------------------------
Built on RH 7.2, debugged on RH 7.2:

[psycho:134] gdb test.g.psycho
GNU gdb Red Hat Linux 7.x (5.0rh-15) (MI_OUT)
Copyright 2001 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux"...
(gdb) b 'A::A(void)'  
Breakpoint 1 at 0x8048759: file A.C, line 6.
(gdb) r
Starting program: /wv/cst1/qa/project/tests/sst/GdbTestCase/evelyn/test.g.psycho  


Before A ctor

Breakpoint 1, A::A (this=0x8049c00) at A.C:6
6          int foobar = 0;
(gdb) b 11
Breakpoint 2 at 0x804876d: file A.C, line 11.
(gdb) c
Continuing.

Breakpoint 2, A::A (this=0x8049c00) at A.C:11
11         foobar = foo * bar;
(gdb) quit

** Note that it successfully stops on line 11 in the A::A constructor.
------------------------------------------------------------------------------
Built on RH 7.2, debugged on RHEL 3:

[schizo:147] gdb test.g.psycho
GNU gdb Red Hat Linux (6.1post-1.20040607.52rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db
library "/lib/tls/libthread_db.so.1".

(gdb) b 'A::A(void)'  
Breakpoint 1 at 0x8048759: file A.C, line 6.
(gdb) r
Starting program: /wv/cst1/qa/project/tests/sst/GdbTestCase/evelyn/test.g.psycho  





Before A ctor

Breakpoint 1, A::A (this=0x8049c00) at A.C:6
6          int foobar = 0;
(gdb) b 11
Breakpoint 2 at 0x804876d: file A.C, line 11.
(gdb) c
Continuing.

Breakpoint 2, A::A (this=0x8049c00) at A.C:11
11         foobar = foo * bar;
(gdb) quit
** Note that it successfully stops on line 11 in the A::A constructor.

------------------------------------------------------------------------------
Built on RHEL 3, debugged on RHEL 3:

[schizo:149] gdb test.g.schizo
GNU gdb Red Hat Linux (6.1post-1.20040607.52rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db
library "/lib/tls/libthread_db.so.1".

(gdb) b 'A::
A::A$base()   A::A()        A::callme()   A::~A$base()  A::~A()
(gdb) b 'A::A()'  
Breakpoint 1 at 0x80487d0: file A.C, line 5.
(gdb) r
Starting program: /wv/cst1/qa/project/tests/sst/GdbTestCase/evelyn/test.g.schizo  

Before A ctor

Breakpoint 1, A (this=0x8049f50) at A.C:6
6          int foobar = 0;
(gdb) b 11
Breakpoint 2 at 0x8048784: file A.C, line 11.
(gdb) c
Continuing.
In ctor ; foobar = 200
After A ctor
In callme
After callme

Program exited normally.
(gdb)  

** Note that it *DOES NOT STOP* on line 11 in the A::A constructor.
------------------------------------------------------------------------------

she then followed-up in a voicemail stating that when she compiled this second
test case on 7.2 using the GNUPRO 03R1 compiler, which is gcc3.2 based, and
tried to debug under the GNUPRO 03R1 GDB, it also fails like above.  So she
feels that her original assertion was correct when she opened this ticket almost
a year ago in that the debuug symbol table being generated by 3.2 based GCC is
mismatched and doesn't work w/ current GDB versions.
Comment 39 Dave Maley 2005-01-12 14:15:01 EST
Created attachment 109682 [details]
new test case provided by client
Comment 40 Jeff Johnston 2005-01-12 15:12:38 EST
I have reproduced the problem.  What is happening is that it is yet another
problem with gcc creating two versions of the constructor with the same name at
different locations.  When you set the breakpoint at line 11, it is setting this
in the function based on the current file you are in.  In this case it finds the
first A::A which is A::A$base (i.e. the base constructor called by classes which
inherit A).  You are running A::A and so never hit the breakpoint.  I am looking
into a fix for this.
Comment 41 Dave Maley 2005-01-13 10:48:42 EST
update provided by client:
---------------------------

I can't seem to figure out how to force the debugger to stop on that line.  (I
even tried building gdb 6.3)  Here is another thing I tried: 
 
------------------------------------------------------------------------------ 
[schizo:154] gdb test.g.schizo 
GNU gdb Red Hat Linux (6.1post-1.20040607.52rh) 
Copyright 2004 Free Software Foundation, Inc. 
GDB is free software, covered by the GNU General Public License, and you are 
welcome to change it and/or distribute copies of it under certain conditions. 
Type "show copying" to see the conditions. 
There is absolutely no warranty for GDB.  Type "show warranty" for details. 
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db
library "/lib/tls/libthread_db.so.1". 
 
(gdb) b 'A::A 
A::A$base()  A::A()        
(gdb) b 'A::A$base()'  
Breakpoint 1 at 0x804876a: file A.C, line 5. 
(gdb) b 'A::A 
A::A$base()  A::A()        
(gdb) b 'A::A()'  
Breakpoint 2 at 0x80487d0: file A.C, line 5. 
(gdb) r 
Starting program: /wv/cst1/qa/project/tests/sst/GdbTestCase/evelyn/test.g.schizo  
 
 
 
 
 
Before A ctor 
 
Breakpoint 2, A (this=0x8049f50) at A.C:6 
6          int foobar = 0; 
(gdb) s 
8          foo = 10; 
(gdb) s 
9          bar = 20; 
(gdb) b 11 
Breakpoint 3 at 0x8048784: file A.C, line 11. 
(gdb) c 
Continuing. 
In ctor ; foobar = 200 
After A ctor 
In callme 
After callme 
 
Program exited normally. 
(gdb) quit 
Comment 42 Jeff Johnston 2005-01-13 11:39:09 EST
You would have to break by address.  If you do a readelf -wl on the executable
you will notice that the constructor is repeated in the line table.  Gdb looks
for line 11 in the file and finds essentially the first reference.  It can't
just always look forward for another line 11 as you will note that multiple
instructions can make up line 11 and with optimization line 11 can be strewn
about the executable.  In this case, the first line 11 is in the base
constructor which is not getting called in your run of the executable.  What you
can do is note the difference between the line 11 breakpoint and the A$base()
breakpoint.  Next add that difference to the A() breakpoint address to give you
the address you want to break at.  It is extremely ugly, but it does work around
the problem in the sample program.  Remember to specify b *0x.... where 0x.....
is the calculated address.  When you reach the breakpoint, gdb prints out line
11 as desired.
Comment 43 Jeff Johnston 2005-01-21 12:08:12 EST
A patch has been built into gdb as of gdb-6.3.0.0-0.7  The following is an
excerpt of running the test program with the new patch.

Breakpoint 1, main () at main.C:5
5	   int foo = 1;
(gdb) b 'A::A
A::A$base()  A::A()       
(gdb) b 'A::A()' 
Breakpoint 2 at 0x8048bc0: file a.C, line 5.
(gdb) c
Continuing.
Before A ctor

Breakpoint 2, A (this=0x9f85008) at a.C:6
6	   int foobar = 0;
(gdb) b 11
Breakpoint 3 at 0x8048b74: file a.C, line 11.
Breakpoint 4 at 0x8048bda: file a.C, line 11.
warning: Multiple breakpoints were set.
warning: Use the "delete" command to delete unwanted breakpoints.
(gdb) c
Continuing.

Breakpoint 4, A (this=0x9f85008) at a.C:11
11	   foobar = foo * bar;
(gdb) c
Continuing.
In ctor ; foobar = 200
After A ctor
In callme
After callme

Program exited normally.
(gdb) quit
Comment 45 Dave Maley 2005-01-26 12:49:46 EST
feedback from client on her 6.1post-1.20040607.52.3 testing:
-------------------------------------------------------------------------------------------

Dave-

This latest version of gdb appears to fix the breakpointing problems, but not
the local variable display problems.  So we are closer, but not done yet.

Here is the new gdb, run on RHEL3, using the second testcase produced on a RH
7.2 system:

[schizo:124] gdb test.g.psycho
GNU gdb Red Hat Linux (6.1post-1.20040607.52.3rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db
library "/lib/tls/libthread_db.so.1".

(gdb) b 'A::A(void)'  
Breakpoint 1 at 0x8048759: file A.C, line 6.
(gdb) r
Starting program: /wv/cst1/qa/project/tests/sst/GdbTestCase/evelyn/test.g.psycho

Before A ctor

Breakpoint 1, A::A (this=0x8049c00) at A.C:6
6          int foobar = 0;
(gdb) b 11
Breakpoint 2 at 0x804876d: file A.C, line 11.
(gdb) c
Continuing.

Breakpoint 2, A::A (this=0x8049c00) at A.C:11
11         foobar = foo * bar;
(gdb) s
13         cout << "In ctor ; foobar = " << foobar << endl;
(gdb) p foobar
$1 = 200
(gdb) c
Continuing.
In ctor ; foobar = 200
After A ctor
In callme
After callme

Program exited normally.
(gdb) q
------------------------------------------------------------------------------
Here is the same test, but compiled on RHEL3, using the new gdb:

[schizo:130] gdb test.g.schizo
GNU gdb Red Hat Linux (6.1post-1.20040607.52.3rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db
library "/lib/tls/libthread_db.so.1".

(gdb) b 'A::A
A::A$base()  A::A()        
(gdb) b 'A::A()'  
Breakpoint 1 at 0x80487d0: file A.C, line 5.
(gdb) r
Starting program: /wv/cst1/qa/project/tests/sst/GdbTestCase/evelyn/test.g.schizo  

Before A ctor

Breakpoint 1, A (this=0x8049f50) at A.C:6
6          int foobar = 0;
(gdb) b 11
Breakpoint 2 at 0x8048784: file A.C, line 11.
Breakpoint 3 at 0x80487ea: file A.C, line 11.
warning: Multiple breakpoints were set.
warning: Use the "delete" command to delete unwanted breakpoints.
(gdb) c
Continuing.

Breakpoint 3, A (this=0x8049f50) at A.C:11
11         foobar = foo * bar;
(gdb) s
13         cout << "In ctor ; foobar = " << foobar << endl;
(gdb) p foobar
No symbol "foobar" in current context.
(gdb) p foo
$1 = 10
(gdb) p bar
$2 = 20
(gdb) c
Continuing.
In ctor ; foobar = 200
After A ctor
In callme
After callme

Program exited normally.
(gdb) q 
Comment 49 Jeff Johnston 2005-01-31 12:08:32 EST
An update.  The 3.2.3 compiler was not generating sufficient debug info for gdb
to find the local variable foobar in the "in-charge" constructor.  It was
generating information about the variable in the "not-in-charge" constructor
(one that that gets called by an inheriting classes constructor).  I had noticed
that the 3.4.3 compiler "was" generating the correct information and the fixes I
have been making above work with the test case.  Note that with optimization,
the variable foobar is removed by the compiler and the cout statement is reduced
to use a constant of 200 (i.e. gdb will not find foobar in this case).

A backport of gcc code has been made and a fix has been built into gcc-3.2.3-51.
 I have confirmed that gdb can break in both constructors, break by line in both
constructors, and that foobar prints correctly.
Comment 50 Elena Zannoni 2005-01-31 12:20:16 EST
Please, see bugzilla 146416.
Comment 54 Tim Powers 2005-05-19 08:09:48 EDT
An advisory has been issued which should help the problem
described in this bug report. This report is therefore being
closed with a resolution of ERRATA. For more information
on the solution and/or where to find the updated files,
please follow the link below. You may reopen this bug report
if the solution does not work for you.

http://rhn.redhat.com/errata/RHBA-2005-187.html

Note You need to log in before you can comment on or make changes to this bug.