bogus breakpoint

Allen Hopkins allenh@eecs.berkeley.edu
Tue Feb 8 18:16:00 GMT 2005


I have a problem that exists with g++ 3.3.3, and later, but not in 3.0
or 2.95 (in between, I'm not sure).
A breakpoint set on a line of code that is tagged with a #line directive
ends up set at an address having nothing to do with that line.

(This is Redhat Linux 2.6.10-1.9_FC2smp, on an Intel platform.)

I'm using gdb, and #line directives inserted into generated .cpp code, 
to debug some higher-level code from which the .cpp code is generated.
The idea is that I can set breakpoints on lines of the higher-level
source code (which has a .mmm suffix and sort of resembles C), and gdb
displays the .mmm code as the source being debugged.

Often, one line of .mmm code generates many lines of .cpp code, so there
are several successive lines of .cpp code tagged with the same #line
directive.  Here's a very simple example from the demonstration case:

     #include "P.h"
     #include "Node.h"

     #line 34 "P.mmm"
     void P::thread()
     #line 34 "P.mmm"
       {
     #line 34 "P.mmm"
         Node* testNode = new Node("Clyde");
     #line 41 "P.mmm"
         int w = 0;
     #line 42 "P.mmm"
         w = w + 1;
     #line 42 "P.mmm"
         delete testNode;
     #line 46 "P.mmm"
       };

If I set a breakpoint at P.mmm:42, the breakpoint should be at the
address of the statement

     w = w + 1;

(since it is the first statement that gdb thinks is on line P.mmm:42).
Instead, the breakpoint ends up in the default destructor of Node,
according to gdb.

There are two things I can do to make this weird behavior go away:
One is to add an explicit empty destructor to the definition of Node.

The other is to remove *another* statement that deletes a Node in
*another file* in the program.  Then a breakpoint at P.mmm:42 in *this*
file acts as expected.

Is there anything about this that makes sense, or is this just the makings
of a g++ bug report?

-Allen Hopkins

Here the testcase in a shar:

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	C.cpp
#	C.h
#	C.mmm
#	gcclist.mail
#	gdb.ini
#	main.cpp
#	makefile
#	Node.h
#	P.cpp
#	P.h
#	P.mmm
#	README
#
echo x - C.cpp
sed 's/^X//' >C.cpp << 'END-of-C.cpp'
X#include "C.h"
X#include "Node.h"
X
X#line 34 "C.mmm"
Xvoid C::thread()
X#line 34 "C.mmm"
X  {
X#line 34 "C.mmm"
X    Node* testNode = new Node("Clem");
X#line 36 "C.mmm"
X    int r = 0;
X#line 41 "C.mmm"
X    r = r + 1;
X#line 41 "C.mmm"
X    delete testNode;
X#line 45 "C.mmm"
X  };
END-of-C.cpp
echo x - C.h
sed 's/^X//' >C.h << 'END-of-C.h'
X#ifndef MMSCS_C_H
X#define MMSCS_C_H
X
Xclass C {
X    public:
X        C() {};
X        void thread();
X};
X
X#endif
END-of-C.h
echo x - C.mmm
sed 's/^X//' >C.mmm << 'END-of-C.mmm'
X/*
X  @Copyright (c) 2004 The Regents of the University of California.
X  All rights reserved.
X
X  Permission is hereby granted, without written agreement and without
X  license or royalty fees, to use, copy, modify, and distribute this
X  software and its documentation for any purpose, provided that the
X  above copyright notice and the following two paragraphs appear in all
X  copies of this software and that appropriate acknowledgments are made
X  to the research of the Metropolis group.
X
X  IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
X  FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
X  ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
X  THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
X  SUCH DAMAGE.
X
X  THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
X  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
X  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
X  PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
X  CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
X  ENHANCEMENTS, OR MODIFICATIONS.
X
X  METROPOLIS_COPYRIGHT_VERSION_1
X  COPYRIGHTENDKEY
X*/
Xpackage bogus_bkpt;
X
Xprocess C {
X
X    port IntReader port0;
X
X    public C(String name) {}
X    void thread() {
X        int r = 0;
X
X        while (r < 30) {
X            await {
X                (port0.num() > 0; port0.IntReader; port0.IntReader) {
X                    r = port0.readInt();
X                }
X            }
X        }
X    }
X}
END-of-C.mmm
echo x - gcclist.mail
sed 's/^X//' >gcclist.mail << 'END-of-gcclist.mail'
XI have a problem that exists with g++ 3.3.3, and later, but not in 3.0
Xor 2.95 (in between, I'm not sure).
XA breakpoint set on a line of code that is tagged with a #line directive
Xends up set at an address having nothing to do with that line.
X
X(This is Redhat Linux 2.6.10-1.9_FC2smp, on an Intel platform.)
X
XI'm using gdb, and #line directives inserted into generated .cpp code, to
Xdebug the some higher-level code from which the .cpp code is generated.
XThe idea is that I can set breakpoints on lines of the higher-level
Xsource code (which has a .mmm suffix and sort of resembles C), and gdb
Xdisplays the .mmm code as the source being debugged.
X
XOften, one line of .mmm code generates many lines of .cpp code, so there
Xare several successive lines of .cpp code tagged with the same #line
Xdirective.  Here's a very simple example from the demonstration case:
X
X    #include "P.h"
X    #include "Node.h"
X
X    #line 34 "P.mmm"
X    void P::thread()
X    #line 34 "P.mmm"
X      {
X    #line 34 "P.mmm"
X        Node* testNode = new Node("Clyde");
X    #line 41 "P.mmm"
X        int w = 0;
X    #line 42 "P.mmm"
X        w = w + 1;
X    #line 42 "P.mmm"
X        delete testNode;
X    #line 46 "P.mmm"
X      };
X
XIf I set a breakpoint at P.mmm:42, the breakpoint should be at the
Xaddress of the statement
X
X    w = w + 1;
X
X(since it is the first statement that gdb thinks is on line P.mmm:42).
XInstead, the breakpoint ends up in the default destructor of Node,
Xaccording to gdb.
X
XThere are two things I can do to make this weird behavior go away:
XOne is to add an explicit empty destructor to the definition of Node.
X
XThe other is to remove *another* statement that deletes a Node in
X*another file* in the program.  Then a breakpoint at P.mmm:42 in *this*
Xfile acts as expected.
X
XIs there anything about this that makes sense, or is this just the makings
Xof a g++ bug report?
X
X-Allen Hopkins
X
END-of-gcclist.mail
echo x - gdb.ini
sed 's/^X//' >gdb.ini << 'END-of-gdb.ini'
Xb P::thread()
Xd 1
Xb P.mmm:41
Xb P.mmm:42
Xi b
Xquit
END-of-gdb.ini
echo x - main.cpp
sed 's/^X//' >main.cpp << 'END-of-main.cpp'
X#include "C.h"
X#include "P.h"
X
Xint main(int argc, char* argv[])
X{
X  P* Producer0 = new P();
X  C* Consumer = new C();
X  Producer0->thread();
X  Consumer->thread();
X}
END-of-main.cpp
echo x - makefile
sed 's/^X//' >makefile << 'END-of-makefile'
X
X// CXX = c++
XCXX = /users/allenh/gcc343/bin/g++
XLD_LIBRARY_DIR = /users/allenh/gcc343/lib
X
XCXX_FLAGS = -ggdb -Wno-deprecated
X
X# Adding -O2 makes the "bug" go away:
X# CXX_FLAGS = -O2 -ggdb -Wno-deprecated
X
Xall: run.x
X
XC.o: C.cpp C.h Node.h
X	$(CXX) -c $(CXX_FLAGS) C.cpp -o C.o
X
XP.o: P.cpp P.h Node.h
X	$(CXX) -c $(CXX_FLAGS) P.cpp -o P.o
X
Xmain.o: ./main.cpp
X	$(CXX) -c $(CXX_FLAGS) ./main.cpp
X
Xrun.x: C.o P.o main.o
X	 $(CXX) $(CXX_FLAGS) -o run.x C.o P.o main.o -lm
X
Xtest:   clean run.x
X	LD_LIBRARY_PATH=$${LD_LIBRARY_PATH}:$(LD_LIBRARY_DIR);	\
X	export LD_LIBRARY_PATH; \
X            gdb -x gdb.ini run.x
X
Xclean:
X	$(RM) *.o run.x
X
XFORCE:
END-of-makefile
echo x - Node.h
sed 's/^X//' >Node.h << 'END-of-Node.h'
X#ifndef MMSCS_NODE_H
X#define MMSCS_NODE_H
X#include <string>
X
Xclass Node {
X    public:
X        std::string intfcName;
X
X        Node(const char *i) {
X            intfcName = (char*)i;
X        }
X
X        // Adding this explicit destructor makes the bug go away:
X        // ~Node() {}
X};
X
X#endif
END-of-Node.h
echo x - P.cpp
sed 's/^X//' >P.cpp << 'END-of-P.cpp'
X#include "P.h"
X#include "Node.h"
X
X#line 34 "P.mmm"
Xvoid P::thread()
X#line 34 "P.mmm"
X  {
X#line 34 "P.mmm"
X    Node* testNode = new Node("Clyde");
X#line 41 "P.mmm"
X    int w = 0;
X#line 42 "P.mmm"
X    w = w + 1;
X#line 42 "P.mmm"
X    delete testNode;
X#line 46 "P.mmm"
X  };
END-of-P.cpp
echo x - P.h
sed 's/^X//' >P.h << 'END-of-P.h'
X#ifndef MMSCS_P_H
X#define MMSCS_P_H
X
Xclass P {
X    public:
X        P() {};
X        void thread();
X};
X
X#endif
END-of-P.h
echo x - P.mmm
sed 's/^X//' >P.mmm << 'END-of-P.mmm'
X/*
X  @Copyright (c) 2004 The Regents of the University of California.
X  All rights reserved.
X
X  Permission is hereby granted, without written agreement and without
X  license or royalty fees, to use, copy, modify, and distribute this
X  software and its documentation for any purpose, provided that the
X  above copyright notice and the following two paragraphs appear in all
X  copies of this software and that appropriate acknowledgments are made
X  to the research of the Metropolis group.
X
X  IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
X  FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
X  ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
X  THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
X  SUCH DAMAGE.
X
X  THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
X  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
X  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
X  PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
X  CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
X  ENHANCEMENTS, OR MODIFICATIONS.
X
X  METROPOLIS_COPYRIGHT_VERSION_1
X  COPYRIGHTENDKEY
X*/
Xpackage bogus_bkpt;
X
Xprocess P {
X
X    port IntWriter port1;
X
X    public P(String name) {}
X    void thread() {
X        int w = 0;
X
X        while (w < 30) {
X            await {
X                (port1.nspace() > 0; port1.IntWriter; port1.IntWriter) {
X                    port1.writeInt(w);
X                    w = w + 1;
X                }
X            }
X        }
X    }
X}
END-of-P.mmm
echo x - README
sed 's/^X//' >README << 'END-of-README'
X
XIn real life, C.cpp is generated from C.mmm, and likewise P.cpp
Xfrom P.mmm.  Here, the .cpp files have been hacked way down to the essence
Xof the problem.
X
XTwo lines in P.cpp are tagged as line 42 of P.mmm.  (In real life, there
Xare several more lines in between, all with the same #line tag.)
XA gdb breakpoint set at P.mmm:42 should be set at the address of the
Xfirst line-42 statement, like breakpoint 3 here (using my workaround of
Xan explicit empty destructor in Node.h -- see below):
X
X-----
X> gdb run.x
X> GNU gdb Red Hat Linux (6.0post-0.20040223.19rh)
X> Copyright 2004 Free Software Foundation, Inc.
X> GDB is free software, covered by the GNU General Public License, and 
you are
X> welcome to change it and/or distribute copies of it under certain 
conditions.
X> Type "show copying" to see the conditions.
X> There is absolutely no warranty for GDB.  Type "show warranty" for 
details.
X> This GDB was configured as "i386-redhat-linux-gnu"...Using host 
libthread_db library "/lib/tls/libthread_db.so.1".
X>
X> (gdb) b P::thread()
X> Breakpoint 1 at 0x804867f: file P.mmm, line 34.
X> (gdb) b P.mmm:41
X> Breakpoint 2 at 0x80486c8: file P.mmm, line 41.
X> (gdb) b P.mmm:42
X> Breakpoint 3 at 0x80486cf: file P.mmm, line 42.
X> (gdb) info b
X> Num Type           Disp Enb Address    What
X> 1   breakpoint     keep y   0x0804867f in P::thread() at P.mmm:34
X> 2   breakpoint     keep y   0x080486c8 in P::thread() at P.mmm:41
X> 3   breakpoint     keep y   0x080486cf in P::thread() at P.mmm:42
X> (gdb) run
X> Starting program: /users/allenh/bogus_bkpt/run.x
X> /users/allenh/bogus_bkpt/run.x: /usr/local/lib/libstdc++.so.6: no 
version information available (required by /users/allenh/bogus_bkpt/run.x)
X> /users/allenh/bogus_bkpt/run.x: /usr/local/lib/libstdc++.so.6: no 
version information available (required by /users/allenh/bogus_bkpt/run.x)
X>
X> Breakpoint 1, P::thread (this=0x929a008) at P.mmm:34
X> 34          public P(String name) {}
X> (gdb) c
X> Continuing.
X>
X> Breakpoint 2, P::thread (this=0x929a008) at P.mmm:41
X> 41                          port1.writeInt(w);
X> (gdb) c
X> Continuing.
X>
X> Breakpoint 3, P::thread (this=0x929a008) at P.mmm:42
X> 42                          w = w + 1;
X> (gdb) where
X> #0  P::thread (this=0x929a008) at P.mmm:42
X> #1  0x08048756 in main (argc=1, argv=0xbfe17404) at ./main.cpp:8
X> (gdb)
X-----
X
XInstead, here's how the breakpoint ends up (breakpoint 3):
X
X-----
X> gdb run.x
X> GNU gdb Red Hat Linux (6.0post-0.20040223.19rh)
X> Copyright 2004 Free Software Foundation, Inc.
X> GDB is free software, covered by the GNU General Public License, and 
you are
X> welcome to change it and/or distribute copies of it under certain 
conditions.
X> Type "show copying" to see the conditions.
X> There is absolutely no warranty for GDB.  Type "show warranty" for 
details.
X> This GDB was configured as "i386-redhat-linux-gnu"...Using host 
libthread_db library "/lib/tls/libthread_db.so.1".
X>
X> (gdb) b P::thread()
X> Breakpoint 1 at 0x804867f: file P.mmm, line 34.
X> (gdb) b P.mmm:41
X> Breakpoint 2 at 0x80486c8: file P.mmm, line 41.
X> (gdb) b P.mmm:42
X> Breakpoint 3 at 0x8048618: file P.mmm, line 42.
X> (gdb) info b
X> Num Type           Disp Enb Address    What
X> 1   breakpoint     keep y   0x0804867f in P::thread() at P.mmm:34
X> 2   breakpoint     keep y   0x080486c8 in P::thread() at P.mmm:41
X> 3   breakpoint     keep y   0x08048618 in ~Node at P.mmm:42
X> (gdb) run
X> Starting program: /users/allenh/bogus_bkpt/run.x
X> /users/allenh/bogus_bkpt/run.x: /usr/local/lib/libstdc++.so.6: no 
version information available (required by /users/allenh/bogus_bkpt/run.x)
X> /users/allenh/bogus_bkpt/run.x: /usr/local/lib/libstdc++.so.6: no 
version information available (required by /users/allenh/bogus_bkpt/run.x)
X>
X> Breakpoint 1, P::thread (this=0x863f008) at P.mmm:34
X> 34          public P(String name) {}
X> (gdb) c
X> Continuing.
X>
X> Breakpoint 2, P::thread (this=0x863f008) at P.mmm:41
X> 41                          port1.writeInt(w);
X> (gdb) c
X> Continuing.
X>
X> Breakpoint 3, ~Node (this=0x863f008) at P.mmm:42
X> 42                          w = w + 1;
X> (gdb) where
X> #0  ~Node (this=0x863f008) at P.mmm:42
X> #1  0x080486eb in P::thread (this=0x863f008) at P.mmm:42
X> #2  0x08048756 in main (argc=1, argv=0xbff7b374) at ./main.cpp:8
X> (gdb)
X-----
X
XBoth P.cpp and C.cpp have statements that delete a Node.  If I comment
Xout the one in C.cpp, the breakpoint weirdness in P.cpp goes away.
X
XAnother thing that makes it go away, which I'm currently relying on as
Xa workaround, is to add an explict empty destructor to Node.h.
END-of-README
exit





More information about the Gcc-help mailing list