| Summary: | Setting breakpoints in shared objects broken | ||
|---|---|---|---|
| Product: | Base System | Reporter: | andy <andy> |
| Component: | bin | Assignee: | freebsd-bugs (Nobody) <bugs> |
| Status: | Closed FIXED | ||
| Severity: | Affects Only Me | ||
| Priority: | Normal | ||
| Version: | 4.1-STABLE | ||
| Hardware: | Any | ||
| OS: | Any | ||
Responsible Changed From-To: freebsd-bugs->jdp If the dynamic linker is broken then it is no doubt my fault. 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. 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 <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> > Thanks for your prompt reply. The e-mail I received didn't include an <br> > attachment. I grabbed a copy of binutils-2.10.0.24 from a mirror site, but <br> > it contained many changes from the version currently in RELENG_4.<br> sorry, forgot to attach file (as usual :)<br> > Is there a place where I can view the changes to the binutils tree via <br> > 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 -> 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> sections against symbols defined externally<br> in shared libraries. We can't do anything<br> with them here. */<br> - || (input_section->flags & SEC_DEBUGGING) != 0)))<br> + || ((input_section->flags & SEC_DEBUGGING) != 0<br> + && (h->elf_link_hash_flags<br> + & ELF_LINK_HASH_DEF_DYNAMIC) != 0))))<br> {<br> /* In these cases, we don't need the relocation<br> value. We check specially because in some<br> <br> <br> </font></html> 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. Responsible Changed From-To: obrien->freebsd-bugs I am not the maintainer. State Changed From-To: analyzed->patched This is fixed in -current with the import of gdb-5.2. State Changed From-To: patched->closed Fixed and MFCed |
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