Bug 5130

Summary: gdb doesn't notice when dynamically loaded shared objects are unloaded
Product: [Retired] Red Hat Linux Reporter: greg
Component: gdbAssignee: Cristian Gafton <gafton>
Status: CLOSED WONTFIX QA Contact:
Severity: high Docs Contact:
Priority: high    
Version: 6.0CC: allen.everhart, blizzard
Target Milestone: ---   
Target Release: ---   
Hardware: i386   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2000-02-15 21:49:27 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description greg 1999-09-14 15:53:28 UTC
this silly little test program demonstrates a bug in GNU
gdb 4.17.0.11
with Linux support as shipped with Red Hat Linux 6.0.  when
a dynamically
loaded shared object is unloaded, gdb doesn't adjust its
idea of the state
of the process accordingly.  run this program within gdb.
place a
breakpoint in main and run it.  type "i sharedlibrary" and
examine the list
of libraries.  now put a break on the call to dlclose().
notice how
libtgdb.so is in the list.  step over the call to dlclose
().  notice how
libtgdb.so is _still_ in the list.  the real trouble creeps
in when you
then load up another shared object.  any future objects
loaded do not
show up in gdb's list at all, and in fact none of their
symbols are
available within the debugger, making debugging
impossible.  as a developer
of component based software, i consider this to be a
critical bug in gdb.

see enclosed test case.

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2).
# To extract the files from this archive, save it to some
FILE, remove
# everything before the `!/bin/sh' line above, then type
`sh FILE'.
#
# Made on 1999-09-14 11:52 EDT by <greg>.
# Source directory was `/home/greg/testgdb'.
#
# Existing files will *not* be overwritten unless `-c' is
specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ----------------------------------------
--
#    321 -rw-r--r-- Makefile
#   1378 -rw-r--r-- testgdb.c
#     62 -rw-r--r-- testmod.c
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" =
FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider
getting and'
  $echo "installing GNU \`touch', distributed in GNU File
Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
if mkdir _sh09913; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= Makefile ==============
if test -f 'Makefile' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'Makefile' '(file already exists)'
else
  $echo 'x -' extracting 'Makefile' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
# Makefile for gdb shared library bug
X
CFLAGS = -Wall -fpic -ggdb
X
X.PHONY : all clean
X
all : libtgdb.so libtgdb2.so testgdb
X
clean :
X	rm testmod.o testgdb.o libtgdb.so libtgdb2.so
testgdb
X
libtgdb.so : testmod.o
X	gcc $^ -shared -o $@
X
libtgdb2.so : testmod.o
X	gcc $^ -shared -o $@
X
testgdb : testgdb.o
X	gcc $^ -o $@ -ldl
SHAR_EOF
  $shar_touch -am 0914114499 'Makefile' &&
  chmod 0644 'Makefile' ||
  $echo 'restore of' 'Makefile' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' )
>/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' )
>/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'Makefile:' 'MD5 check failed'
16070d1996cc8327f66fc86b14edcc12  Makefile
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c
< 'Makefile'`"
    test 321 -eq "$shar_count" ||
    $echo 'Makefile:' 'original size' '321,' 'current
size' "$shar_count!"
  fi
fi
# ============= testgdb.c ==============
if test -f 'testgdb.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'testgdb.c' '(file already exists)'
else
  $echo 'x -' extracting 'testgdb.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'testgdb.c' &&
/*
X * testgdb.c
X *
X * this silly little test program demonstrates a bug in
GNU gdb 4.17.0.11
X * with Linux support as shipped with Red Hat Linux 6.0.
when a dynamically
X * loaded shared object is unloaded, gdb doesn't adjust
its idea of the state
X * of the process accordingly.  run this program within
gdb.  place a
X * breakpoint in main and run it.  type "i sharedlibrary"
and examine the list
X * of libraries.  now put a break on the call to dlclose
().  notice how
X * libtgdb.so is in the list.  step over the call to
dlclose().  notice how
X * libtgdb.so is _still_ in the list.  the real trouble
creeps in when you
X * then load up another shared object.  any future objects
loaded do not
X * show up in gdb's list at all, and in fact none of their
symbols are
X * available within the debugger, making debugging
impossible.  as a developer
X * of component based software, i consider this to be a
critical bug in gdb.
X */
X
#include <stdio.h>
#include <dlfcn.h>
X
int main(
X    int				 argc,
X    char			*argv[]
X    )
{
X    void			*module;
X
X    if ((module = dlopen("./libtgdb.so", RTLD_LAZY |
RTLD_GLOBAL)) != NULL) {
X
X	dlclose(module);
X
X	if ((module = dlopen("./libtgdb2.so",
X			     RTLD_LAZY | RTLD_GLOBAL)) !=
NULL) {
X
X	    dlclose(module);
X
X	} else {
X
X	    fprintf(stderr, "%s\n", dlerror());
X
X	}
X
X    } else {
X
X	fprintf(stderr, "%s\n", dlerror());
X
X    }
X
X    return 0;
}
SHAR_EOF
  $shar_touch -am 0914114799 'testgdb.c' &&
  chmod 0644 'testgdb.c' ||
  $echo 'restore of' 'testgdb.c' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' )
>/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' )
>/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'testgdb.c:' 'MD5 check failed'
e15933f5cf6b82847e0121f87b31a9c0 testgdb.c
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c
< 'testgdb.c'`"
    test 1378 -eq "$shar_count" ||
    $echo 'testgdb.c:' 'original size' '1378,' 'current
size' "$shar_count!"
  fi
fi
# ============= testmod.c ==============
if test -f 'testmod.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'testmod.c' '(file already exists)'
else
  $echo 'x -' extracting 'testmod.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'testmod.c' &&
int spam = 5;
X
void doNothing(
X    void
X    )
{
X    return;
}
SHAR_EOF
  $shar_touch -am 0914113599 'testmod.c' &&
  chmod 0644 'testmod.c' ||
  $echo 'restore of' 'testmod.c' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' )
>/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' )
>/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'testmod.c:' 'MD5 check failed'
37c6cb0a8cf8533916bea542e3ee6eb6  testmod.c
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c
< 'testmod.c'`"
    test 62 -eq "$shar_count" ||
    $echo 'testmod.c:' 'original size' '62,' 'current
size' "$shar_count!"
  fi
fi
rm -fr _sh09913
exit 0

Comment 1 Jim Kingdon 1999-11-22 19:01:59 UTC
I may find time to look into this; it is a long-standing GDB
limitation for what it is worth.

Comment 2 Erik Troan 2000-02-15 21:49:59 UTC
This would take a major bit of work to fix in gdb; it's extremely unlikely
it's worth the trouble.

Comment 3 Allen Everhart 2004-02-27 05:19:29 UTC
I think its time to revisit this issue. It is not possible to use gdb 
to debug an Oracle PRO*C applications. It seems the Oracle9 client is 
making calls to dlclose and that is causing gdb to fail with the 
error message: "Error while reading shared library symbols" before 
main is called. If you have Oracle9 on Linux just build the 
sample1.pc program and attempt to debug it with gdb.