mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-05 15:15:42 +00:00
fcdc6c5aff198140e0e2c8b94eef48d340e04dbc
On Arch Linux, I get:
FAIL: gdb.base/dlmopen-ns-ids.exp: reopen a namespace
The symptom observed is that after stepping over the last dlmopen of the
test, "info sharedlibrary" does not show the library just opened. After
digging, I found that when stepping over that dlmopen call, the shlib
event breakpoint (that GDB inserts in glibc to get notified of dynamic
linker activity) does not get hit. I then saw that after the previous
dlclose, the shlib event breakpoints were suddenly all marked as
pending:
(gdb) maintenance info breakpoints
Num Type Disp Enb Address What
-1 shlib events keep n <PENDING>
-1.1 y- <PENDING>
The root cause of this problem is the fact that the dynamic linker path
specified in binaries contains a symlink:
$ readelf --program-headers /bin/ls | grep "Requesting program interpreter"
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
$ ls -l /lib64
lrwxrwxrwx 1 root root 7 May 3 15:26 /lib64 -> usr/lib
$ realpath /lib64/ld-linux-x86-64.so.2
/usr/lib/ld-linux-x86-64.so.2
As a result, the instances of the dynamic linker in the non-base
namespace have the real path instead of the original path:
(gdb) info sharedlibrary
From To NS Syms Read Shared Object Library
0x00007ffff7fc6000 0x00007ffff7fff000 [[0]] Yes /lib64/ld-linux-x86-64.so.2
...
0x00007ffff7fc6000 0x00007ffff7fff000 [[1]] Yes /usr/lib/ld-linux-x86-64.so.2
...
0x00007ffff7fc6000 0x00007ffff7fff000 [[1]] Yes /usr/lib/ld-linux-x86-64.so.2
...
0x00007ffff7fc6000 0x00007ffff7fff000 [[1]] Yes /usr/lib/ld-linux-x86-64.so.2
Notice that all instances of the dynamic loader have the same address
range. This is expected: the dynamic loader is really loaded just once
in memory, it's just that it's visible in the various namespaces, so
listed multiple times. Also, notice that the last three specify
namespace 1... seems like a separate bug to me (ignore it for now).
The fact that the paths differ between the first one and the subsequent
ones is not something we control: we receive those paths as-is from the
glibc link map.
Since these multiple solib entries are really the same mapping, we would
expect this code in solib_read_symbols to associate them to the same
objfile:
/* Have we already loaded this shared object? */
so.objfile = nullptr;
for (objfile *objfile : current_program_space->objfiles ())
{
if (filename_cmp (objfile_name (objfile), so.name.c_str ())
== 0
&& objfile->addr_low == so.addr_low)
{
so.objfile = objfile;
break;
}
}
But because the filenames differ, we end up creating two different
objfiles with the same symbols, same address ranges, etc. I would guess
that this is not a state we want.
When the dlclose call closes the last library from the non-base
namespace, the dynamic linker entry for that namespace is also
removed. From GDB's point of view, it just looks like an solib getting
unloaded. In update_solib_list, we have this code to check if the
objfile behind the solib is used by other solibs, and avoid deleting the
objfile if so:
bool still_in_use
= (gdb_iter->objfile != nullptr
&& solib_used (current_program_space, *gdb_iter));
/* Notify any observer that the shared object has been
unloaded before we remove it from GDB's tables. */
notify_solib_unloaded (current_program_space, *gdb_iter,
still_in_use, false);
/* Unless the user loaded it explicitly, free SO's objfile. */
if (gdb_iter->objfile != nullptr
&& !(gdb_iter->objfile->flags & OBJF_USERLOADED)
&& !still_in_use)
gdb_iter->objfile->unlink ();
Because this is the last solib to use that objfile instance, the objfile
is deleted. In the process, disable_breakpoints_in_unloaded_shlib (in
breakpoint.c) is called. The breakpoint locations for the shlib event
breakpoints get marked as "shlib_disabled", which then causes them (I
suppose) to not get inserted and be marked as pending. And then, when
stepping on the subsequent dlmopen call, GDB misses the load of the new
library.
It seems clear to me that, at least, the duplicate objfile detection in
solib_read_symbols needs to be fixed. Right now, to conclude that an
solib matches an existing objfile, it checks that:
- the two have equivalent paths (filename_cmp)
- the two have the same "low" address
In this patch, I remove the filename check. This makes it such that all
the solibs for dynamic linker entries will share the same objfile.
This assumes that no two different solibs / objfiles will have the same
low address. At first glance, it seems like a reasonable assumption to
make, but I don't know if there are some corner cases where this is not
true.
To fix my specific case, I could change the code to resolve the symlinks
and realize that these are all the same file. But I don't think it
would work in a general way. For example, if debugging remotely and
using the target: filesystem, we would need to resolve the symlink on
the target, and I don't think we can do that today (there is no
readlink/realpath operation in the target file I/O).
With this patch, gdb.base/dlmopen-ns-ids.exp passes cleanly:
# of expected passes 44
Change-Id: I3b60051085fb9597b7a72f50122c1104c969908e
Reviewed-By: Guinevere Larsen <guinevere@redhat.com>
…
…
…
…
…
…
…
…
…
…
…
README for GNU development tools This directory contains various GNU compilers, assemblers, linkers, debuggers, etc., plus their support routines, definitions, and documentation. If you are receiving this as part of a GDB release, see the file gdb/README. If with a binutils release, see binutils/README; if with a libg++ release, see libg++/README, etc. That'll give you info about this package -- supported targets, how to use it, how to report bugs, etc. It is now possible to automatically configure and build a variety of tools with one command. To build all of the tools contained herein, run the ``configure'' script here, e.g.: ./configure make To install them (by default in /usr/local/bin, /usr/local/lib, etc), then do: make install (If the configure script can't determine your type of computer, give it the name as an argument, for instance ``./configure sun4''. You can use the script ``config.sub'' to test whether a name is recognized; if it is, config.sub translates it to a triplet specifying CPU, vendor, and OS.) If you have more than one compiler on your system, it is often best to explicitly set CC in the environment before running configure, and to also set CC when running make. For example (assuming sh/bash/ksh): CC=gcc ./configure make A similar example using csh: setenv CC gcc ./configure make Much of the code and documentation enclosed is copyright by the Free Software Foundation, Inc. See the file COPYING or COPYING.LIB in the various directories, for a description of the GNU General Public License terms under which you can copy the files. REPORTING BUGS: Again, see gdb/README, binutils/README, etc., for info on where and how to report problems.
Description
Languages
C
50.5%
Makefile
22.7%
Assembly
13.2%
C++
5.9%
Roff
1.5%
Other
5.6%