Bug 20373

Summary: Setting breakpoints in shared objects broken
Product: Base System Reporter: andy <andy>
Component: binAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 4.1-STABLE   
Hardware: Any   
OS: Any   

Description andy 2000-08-03 07:10:00 UTC
	Setting a breakpoint in an run-time loaded object from a
	C or C++ program does not work as expected.  The breakpoint
	appears to be set at the end of the function or at least
	the trap doesn't occur until function exit rather than
	at the breakpoint position.  See following typscript of
	a debug session using the attached sample program which
	loads a shared object and calls a function.  The sample is
	C++ (as that is where I first ran into the problem) but
	compiling it as C (with a couple of little mods) shows
	the same problem.

	This behaviour seems to have occurred *after* 4.0-RELEASE.


Script started on Thu Aug  3 15:34:59 2000
: bebop; make clean all
rm -f tst so.so
c++ -g -o tst tst.cpp
c++ -g -shared -o so.so so.cpp
: bebop; gdb tst
GNU gdb 4.18
Copyright 1998 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-unknown-freebsd"...
(gdb) set environment LD_LIBRARY_PATH .
(gdb) b dlopen
Breakpoint 1 at 0x8048814
(gdb) r so.so func
Starting program: /home/andy/tmp/bugs/c++-gdb-breakpoint/tst so.so func
Breakpoint 1 at 0x280f7c4f
Breakpoint 1 at 0x280520dd

Breakpoint 1, 0x280520dd in dlopen () from /usr/libexec/ld-elf.so.1
(gdb) fin
Run till exit from #0  0x280520dd in dlopen () from /usr/libexec/ld-elf.so.1
0x8048993 in main (argc=3, argv=0xbfbff308) at tst.cpp:14
14	    if ((h = dlopen(argv[1], RTLD_NOW)) == NULL)
(gdb) shared
Symbols already loaded for /usr/lib/libstdc++.so.3
Symbols already loaded for /usr/lib/libm.so.2
Symbols already loaded for /usr/lib/libc.so.4
Symbols already loaded for /home/andy/tmp/bugs/c++-gdb-breakpoint/./so.so
Symbols already loaded for /usr/libexec/ld-elf.so.1
(gdb) b func
Breakpoint 2 at 0x281554be: file so.cpp, line 12.
(gdb) c
Continuing.

Breakpoint 2, 0x281554be in func () at so.cpp:12
12	}                                          <==== last line of func()
(gdb) where
#0  0x281554be in func () at so.cpp:12
#1  0x8048a0d in main (argc=3, argv=0xbfbff308) at tst.cpp:18
#2  0x80488f1 in _start ()
(gdb) step
...  func() executes
main (argc=3, argv=0xbfbff308) at tst.cpp:19
19	    if (dlclose(h) == -1)
(gdb) cont

(deletia)
Script done on Thu Aug  3 15:36:13 2000

How-To-Repeat: 
	See attached shar file.  It has a simple test program that
	loads a shared object and calls a function in it.  If you
	debug this, set a break point on dlopen and "fin" from it
	so the loaded object's symbols are loaded, then set a break
	point on "func" and continue.  The break point doesn't
	occur until the function exits.


# 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:
#
#	Makefile
#	so.cpp
#	tst.cpp
#
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
Xall: tst so.so
X
Xtst: tst.cpp
X	c++ -g -o $@ tst.cpp
X
Xso.so: so.cpp
X	c++ -g -shared -o $@ so.cpp
X
Xtest:
X	@LD_LIBRARY_PATH=`pwd` ./tst so.so func
X
Xclean:
X	rm -f tst so.so
END-of-Makefile
echo x - so.cpp
sed 's/^X//' >so.cpp << 'END-of-so.cpp'
X#include <stdio.h>
X
Xextern "C"
Xvoid
Xfunc()
X{
X    for (int i = 0; i < 10; ++i)
X	printf(".");
X    printf("In function");
X    for (int i = 0; i < 10; ++i)
X	printf(".");
X    printf("\n");
X}
END-of-so.cpp
echo x - tst.cpp
sed 's/^X//' >tst.cpp << 'END-of-tst.cpp'
X#include <stdio.h>
X#include <dlfcn.h>
X#include <err.h>
X
Xint
Xmain(int argc, char **argv)
X{
X    void	*h;
X    void	(*fn)();
X
X    if (argc != 3)
X	errx(1, "usage: %s so ident", argv[0]);
X    if ((h = dlopen(argv[1], RTLD_NOW)) == NULL)
X	errx(1, "can't dlopen %s: %s", argv[1], dlerror());
X    if ((fn = (void (*)())dlsym(h, argv[2])) == NULL)
X	errx(2, "can't dlsym %s : %s", argv[2], dlerror());
X    (*fn)();
X    if (dlclose(h) == -1)
X	errx(3, "dlclose failed: %s", dlerror());
X    return 0;
X}
END-of-tst.cpp
exit
Comment 1 John Polstra freebsd_committer freebsd_triage 2000-08-03 21:31:06 UTC
Responsible Changed
From-To: freebsd-bugs->jdp

If the dynamic linker is broken then it is no doubt my fault.
Comment 2 John Polstra freebsd_committer freebsd_triage 2000-08-03 22:03:35 UTC
Responsible Changed
From-To: jdp->obrien

I looked into this problem and it appears to be a compiler bug, not 
a problem in the dynamic linker.  Examining the code at the 
breakpoint with the "x/i" command in gdb shows that the breakpoint 
is in fact being set at the right place.  The problem is that the 
line number information in the shared object seems to be wrong. 
It does not make any difference whether the shared object is 
loaded at runtime with dlopen or just linked into the executable. 
In either case the failure is the same. 

As a further test, I built your test case with gcc-2.7.2.3 on a 
FreeBSD 3.5-STABLE system and then tested it under -current using 
-current's dynamic linker and gdb.  That worked fine.  Yet the same 
test case when built with -current's compiler (gcc-2.95.2) failed 
just as you reported.
Comment 3 andy 2000-08-14 07:13:32 UTC
Thanks for verifying this John.  I thought I was going crazy for a while
(I'm working with
a very large program that makes extensive use of run-time loading of
shared objects. Not
being able to debug anything is hurting.  Hmmm, so what's happened in
stable and current
recently with the compiler?  Binutils?
--
Andy Newman
Comment 4 bbauman 2000-09-08 14:03:34 UTC
<html>
Here's some mail we received from Max Khon regarding this problem. He was
kind enough to include a patch, which can be obtained by doing a diff of
revisions 1.8 and 1.9 of elf32-i386.c in the CVS tree.<br>
<br>
Could someone please apply this patch or upgrade binutils to a more
recent version? It makes debugging Mozilla much more pleasant :-).<br>
<br>
Thanks.<br>
<br>
hi, there!<br>
On Thu, 7 Sep 2000, Bruce Bauman wrote:<br>
&gt; Thanks for your prompt reply. The e-mail I received didn't include
an <br>
&gt; attachment. I grabbed a copy of binutils-2.10.0.24 from a mirror
site, but <br>
&gt; it contained many changes from the version currently in
RELENG_4.<br>
sorry, forgot to attach file (as usual :)<br>
&gt; Is there a place where I can view the changes to the binutils tree
via <br>
&gt; cvsweb or something like that? Or is it easier for you to send us a
patch?<br>
<font color="#0000FF"><u><a href="http://sources.redhat.com/binutils" eudora="autourl">http://sources.redhat.com/binutils</a>/</font></u><font color="#000000">
<br>
you should apply patch for libbfd/elf32-i386.c (1.8 -&gt; 1.9) <br>
I attached a patch anyway.<br>
/fjoe<br>
<br>
</font><font color="#0000FF"><u>bfd.diff <br>
<br>
</font></u><font face="Courier New, Courier" color="#000000">--- contrib/binutils/bfd/elf32-i386.c.orig  Fri Aug 18 12:17:38 2000<br>
+++ contrib/binutils/bfd/elf32-i386.c  Fri Aug 18 12:18:09 2000<br>
@@ -1293,7 +1293,9 @@<br>
        &nbsp;&nbsp;&nbsp;&nbsp; sections against symbols defined externally<br>
        &nbsp;&nbsp;&nbsp;&nbsp; in shared libraries.&nbsp; We can't do anything<br>
        &nbsp;&nbsp;&nbsp;&nbsp; with them here.&nbsp; */<br>
-       &nbsp; || (input_section-&gt;flags &amp; SEC_DEBUGGING) != 0)))<br>
+       &nbsp; || ((input_section-&gt;flags &amp; SEC_DEBUGGING) != 0<br>
+       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; (h-&gt;elf_link_hash_flags<br>
+         &nbsp; &amp; ELF_LINK_HASH_DEF_DYNAMIC) != 0))))<br>
     {<br>
     &nbsp; /* In these cases, we don't need the relocation<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value.&nbsp; We check specially because in some<br>
<br>
<br>
</font></html>
Comment 5 David E. O'Brien freebsd_committer freebsd_triage 2000-09-19 18:07:18 UTC
State Changed
From-To: open->analyzed

1) GDB 4.x is not matched to Binutils 2.10.  A GDB 5.0 upgrade is in progress 
2) Binutils 2.10.0.24 is NOT, I repeat (NOT) the an offical Binutils release. 
It is a Linux-only version that exists be cause the Linux toolchain 
maintainer refuses to work properly with the Binutils developers.  This 
also explains why there are many differences between the offical 2.10 and 
this rouge version. 
3) It should have been clearly stated that "by doing a diff of revisions 1.8 
and 1.9 of elf32-i386.c in the CVS tree" refers to the Cygnus Sourceware 
anoncvs repository as there is no rev 1.9 in 
src/contrib/binutils/bfd/elf32-i386.c,v of the FreeBSD CVS repository.   
Rev 1.8 is the version in Binutils 2.10.0, rev 1.9 was committed after the 
binutils_2.10 release branch was created.  The Binutils maintainers do not 
feel there are any critical bugs in 2.10.0.  Thus they have not committed 
rev 1.9 to the binutils_2.10 release branch.  You are free to try to 
convience them that rev 1.9 should be committed to the binutils_2.10 
release branch so that it will show up in Binutils 2.10.1.  But that is a 
battle I do not wish to fight.
Comment 6 David E. O'Brien freebsd_committer freebsd_triage 2001-09-10 17:25:26 UTC
Responsible Changed
From-To: obrien->freebsd-bugs

I am not the maintainer.
Comment 7 Mark Peek freebsd_committer freebsd_triage 2002-07-03 15:42:41 UTC
State Changed
From-To: analyzed->patched

This is fixed in -current with the import of gdb-5.2.
Comment 8 Matteo Riondato freebsd_committer freebsd_triage 2005-07-31 13:03:54 UTC
State Changed
From-To: patched->closed

Fixed and MFCed