From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28767 invoked by alias); 15 Jul 2004 11:31:11 -0000 Mailing-List: contact gdb-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-owner@sources.redhat.com Received: (qmail 28756 invoked from network); 15 Jul 2004 11:31:09 -0000 Received: from unknown (HELO maynard.mail.mindspring.net) (207.69.200.243) by sourceware.org with SMTP; 15 Jul 2004 11:31:09 -0000 Received: from user-119a90a.biz.mindspring.com ([66.149.36.10] helo=berman.michael-chastain.com) by maynard.mail.mindspring.net with esmtp (Exim 3.33 #1) id 1Bl4SB-0000mp-00; Thu, 15 Jul 2004 07:31:07 -0400 Received: by berman.michael-chastain.com (Postfix, from userid 502) id E988A4B104; Thu, 15 Jul 2004 07:31:03 -0400 (EDT) To: gdb@sources.redhat.com, rolandz@poczta.fm Subject: Re: How to setup a breakpoint on constructor Message-Id: <20040715113103.E988A4B104@berman.michael-chastain.com> Date: Thu, 15 Jul 2004 13:55:00 -0000 From: mec.gnu@mindspring.com (Michael Elizabeth Chastain) X-SW-Source: 2004-07/txt/msg00164.txt.bz2 Hi Roland, Would you like to try a makeshift and experimental patch? ftp://ftp.shout.net/pub/users/mec/ctor-dtor-base.patch (Patch attached to this message too). You have to apply this to the libiberty/ subdirectory of a recent gdb, such as gdb 6.1.1, and then rebuild gdb. There's a lot of doco in the patch but it rambles. The basic idea is that I patched the demangler so that it demangles the different ctor's with different names: A::A() A::A$base() A::A$allocate() I don't know if it's a good idea for gdb to work this way, but I think it's worth getting some user feedback. Testing: I haven't run the test suite with this. I did test a small program (testsuite/gdb.cp/derivation.cc) and it works the way I think it should. Michael C === gdb has a problem with g++ constructors and destructors. This patch resolves the problem in a simple but crude way. The problem is described in the gdb PROBLEMS file: gdb/1091: Constructor breakpoints ignored gdb/1193: g++ 3.3 creates multiple constructors: gdb 5.3 can't set breakpoints When gcc 3.x compiles a C++ constructor or C++ destructor, it generates 2 or 3 different versions of the object code. These versions have unique mangled names (they have to, in order for linking to work), but they have identical source code names, which leads to a great deal of confusion. Specifically, if you set a breakpoint in a constructor or a destructor, gdb will put a breakpoint in one of the versions, but your program may execute the other version. This makes it impossible to set breakpoints reliably in constructors or destructors. gcc 3.x generates these multiple object code functions in order to implement virtual base classes. gcc 2.x generated just one object code function with a hidden parameter, but gcc 3.x conforms to a multi-vendor ABI for C++ which requires multiple object code functions. This patch changes the demangler so that it demangles different linkage names back to different source code names, so that gdb and gdb users are no longer confused by several object code functions with identical source code names. Before this patch: 08048544 _ZN1AC1Ev A::A() 080486e2 _ZN1AC2Ev A::A() After this patch: 08048544 _ZN1AC1Ev A::A() 080486e2 _ZN1AC2Ev A::A$base() You still have to understand that g++ emits two (sometimes three) copies of each constructor. The constructor with "C1" in the linkage name is the complete object constructor. Your program calls this constructor when it creates an object whose complete type is A, such as "new A". The constructor with "C2" in the linkage name is the base object constructor. Your program calls this constructor when it creates an object derived from A, such as "new B". Your program does *not* call the base object constructor for "new A". The difference between type "C1" and type "C2" has to do with virtual base classes. In C++, the constructor for the complete object initializes all the virtual bases, and constructors for base classes do not initialize any virtual bases. Here is an example: class A { ... }; class B1 : virtual public A { ... }; class B2 : virtual public A { ... }; class C : public B1, public B2 { ... }; When your program creates a C with "new C", your program calls the type C1 constructor for C::C. C::C (type C1) calls A::A (type C2) to initialize the virtual base. Then C::C (type C1) calls B1::B1 (type C2) and B2::B2 (type C2) to initialize the normal bases. If you understand virtual bases, all this should make sense. If you don't understand virtual bases, just remember the simple rule: "new Foo" calls Foo::Foo (type C1), and everything that Foo::Foo for all its bases is of type C2. There is also a constructor of type "C3". I have never actually seen one of these, but it would be marked "Foo::Foo$allocate". After you apply this patch and rebuild gdb, all the constructors with names 'Foo::Foo' are the complete object constructors. 'Foo::Foo$base' are the base object constructors, and 'Foo::Foo$allocate' are the allocating object constructors. All three constructors are compiled from the same source code. To set a breakpoint on the constructor, you actually have to set two or three breakpoints (usually just two). If you take the short-cut and just break on 'Foo::Foo', you will get breakpoints whenever 'new Foo' happens, but not when 'new Bar' happens if Bar is derived from Foo. You need to break on 'Foo::Foo$base' to get breakpoints for that. Michael C === Here is a typescript of a gdb session with this patch. Note how 'A::A()' is called for an object of type A, and 'A::A$base()' is called for objects of types D, E, F, and G, which have A as a base class. Script started on Thu Jul 15 07:14:52 2004 [mec.gnu@berman HEAD]$ ./gdb/gdb ~/tmp/a.out GNU gdb 2004-07-14-cvs 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 "i686-pc-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1". (gdb) break 'A::A^G A::A$base() A::A() (gdb) break 'A::A()' Breakpoint 1 at 0x8048547: file derivation.cc, line 7. (gdb) break 'A::A$base()' Breakpoint 2 at 0x80486e5: file derivation.cc, line 7. (gdb) run Starting program: /berman/home/mec.gnu/tmp/a.out Breakpoint 1, A (this=0xbffff888) at derivation.cc:8 8 a=1; (gdb) backtrace #0 A (this=0xbffff888) at derivation.cc:8 #1 0x08048481 in main () at derivation.cc:203 (gdb) list 203 198 199 200 int main(void) 201 { 202 203 A a_instance; 204 B b_instance; 205 C c_instance; 206 D d_instance; 207 E e_instance; (gdb) cont Continuing. Breakpoint 2, A (this=0xbffff850) at derivation.cc:8 8 a=1; (gdb) backtrace #0 A (this=0xbffff850) at derivation.cc:8 #1 0x0804859d in D (this=0xbffff850) at derivation.cc:58 #2 0x080484ae in main () at derivation.cc:206 (gdb) cont Continuing. Breakpoint 2, A (this=0xbffff830) at derivation.cc:8 8 a=1; (gdb) backtrace #0 A (this=0xbffff830) at derivation.cc:8 #1 0x080485eb in E (this=0xbffff830) at derivation.cc:74 #2 0x080484bd in main () at derivation.cc:207 (gdb) cont Continuing. Breakpoint 2, A (this=0xbffff810) at derivation.cc:8 8 a=1; (gdb) backtrace #0 A (this=0xbffff810) at derivation.cc:8 #1 0x08048639 in F (this=0xbffff810) at derivation.cc:90 #2 0x080484cf in main () at derivation.cc:208 (gdb) cont Continuing. Breakpoint 2, A (this=0xbffff7e0) at derivation.cc:8 8 a=1; (gdb) backtrace #0 A (this=0xbffff7e0) at derivation.cc:8 #1 0x08048687 in G (this=0xbffff7e0) at derivation.cc:108 #2 0x080484e1 in main () at derivation.cc:209 (gdb) cont Continuing. Program exited normally. (gdb) quit [mec.gnu@berman HEAD]$ exit Script done on Thu Jul 15 07:15:50 2004 === 2004-07-15 Michael Chastain * cp-demangle.c (d_print_comp) Return unique names for ctor and dtor names by decorating them with "$base", "$allocate", and "$delete". Index: cp-demangle.c =================================================================== RCS file: /cvs/src/src/libiberty/cp-demangle.c,v retrieving revision 1.51 diff -c -3 -p -r1.51 cp-demangle.c *** cp-demangle.c 28 Jun 2004 18:01:41 -0000 1.51 --- cp-demangle.c 15 Jul 2004 10:53:01 -0000 *************** d_print_comp (dpi, dc) *** 2978,2988 **** --- 2978,3012 ---- case DEMANGLE_COMPONENT_CTOR: d_print_comp (dpi, dc->u.s_ctor.name); + switch (dc->u.s_ctor.kind) + { + case gnu_v3_complete_object_ctor: + /* no decoration */ + break; + case gnu_v3_base_object_ctor: + d_append_string_constant (dpi, "$base"); + break; + case gnu_v3_complete_object_allocating_ctor: + d_append_string_constant (dpi, "$allocate"); + break; + } return; case DEMANGLE_COMPONENT_DTOR: d_append_char (dpi, '~'); d_print_comp (dpi, dc->u.s_dtor.name); + switch (dc->u.s_dtor.kind) + { + case gnu_v3_deleting_dtor: + d_append_string_constant (dpi, "$delete"); + break; + case gnu_v3_complete_object_dtor: + /* no decoration */ + break; + case gnu_v3_base_object_dtor: + d_append_string_constant (dpi, "$base"); + break; + } return; case DEMANGLE_COMPONENT_VTABLE: