aboutsummaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.base/sym-file-loader.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2014-04-14 17:23:55 +0100
committerPedro Alves <palves@redhat.com>2014-04-15 12:59:12 +0100
commit2d1baf521e08bc390d604aaf1326347cc130ce1f (patch)
treeded0acfed3bbb5d062867e12eec6767536d297f2 /gdb/testsuite/gdb.base/sym-file-loader.c
parent7dd6df0171796757f404a549c76f0d9b9192c849 (diff)
downloadgdb-2d1baf521e08bc390d604aaf1326347cc130ce1f.zip
gdb-2d1baf521e08bc390d604aaf1326347cc130ce1f.tar.gz
gdb-2d1baf521e08bc390d604aaf1326347cc130ce1f.tar.bz2
Make sym-file.exp work with remote targets and hosts.
The main issue here is that this test passes the host's absolute path to the library to load to the "dlopen"-like routine, which doesn't work when either the target or the host are remote, unless a shared filesystem has been set up. Tests that dynamically load a library solve this by dlopen'ing by basename, and setting rpath to $ORIGIN. See gdb_compile. This test doesn't use dlopen, but instead uses its own simple elf loader. The fix is to pass this loader the library basename, and teach it to look up the library by basename in the executable's directory as well, i.e., assuming/emulating RPATH=$ORIGIN. Tested on x86_64 Fedora 17, native and gdbserver. I looked around in the web to figure out Linux's /proc/self/exe equivalents in other ELF OSs. I think I covered all relevant, but if not, I think it'll be simple enough to add more. (Note the test is skipped on non-ELF targets.) Tested on x86_64 Fedora 17, native and gdbserver. gdb/testsuite/ 2014-04-15 Pedro Alves <palves@redhat.com> * gdb.base/sym-file-loader.c: Include <limits.h>. (SELF_LINK): New define. (get_origin): New function. (load_shlib): Use it. * gdb.base/sym-file.exp: Don't early return if the target is remote. Use runto_main, and issue fail is that fails. Use gdb_load_shlibs. (shlib_name): Delete. (lib_so, lib_syms, lib_dlopen): New globals. Use them throughout.
Diffstat (limited to 'gdb/testsuite/gdb.base/sym-file-loader.c')
-rw-r--r--gdb/testsuite/gdb.base/sym-file-loader.c70
1 files changed, 67 insertions, 3 deletions
diff --git a/gdb/testsuite/gdb.base/sym-file-loader.c b/gdb/testsuite/gdb.base/sym-file-loader.c
index 65c48be..625788a 100644
--- a/gdb/testsuite/gdb.base/sym-file-loader.c
+++ b/gdb/testsuite/gdb.base/sym-file-loader.c
@@ -15,6 +15,7 @@
#include <unistd.h>
#include <fcntl.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -77,6 +78,48 @@ load (uint8_t *addr, Elf_External_Phdr *phdr, struct segment *tail_seg)
return seg;
}
+#ifdef __linux__
+# define SELF_LINK "/proc/self/exe"
+#elif defined NETBSD
+# define SELK_LINK "/proc/curproc/exe"
+#elif defined __OpenBSD__ || defined __FreeBSD__ || defined __DragonFly__
+# define SELK_LINK "/proc/curproc/file"
+#elif defined SunOS
+# define SELK_LINK "/proc/self/path/a.out"
+#endif
+
+/* Like RPATH=$ORIGIN, return the dirname of the current
+ executable. */
+
+static const char *
+get_origin (void)
+{
+ static char self_path[PATH_MAX];
+ static ssize_t self_path_len;
+
+ if (self_path_len == 0)
+ {
+#ifdef SELF_LINK
+ self_path_len = readlink (SELF_LINK, self_path, PATH_MAX - 1);
+ if (self_path_len != -1)
+ {
+ char *dirsep;
+
+ self_path[self_path_len] = '\0';
+ dirsep = strrchr (self_path, '/');
+ *dirsep = '\0';
+ }
+#else
+ self_path_len = -1;
+#endif
+ }
+
+ if (self_path_len == -1)
+ return NULL;
+ else
+ return self_path;
+}
+
/* Mini shared library loader. No reallocation
is performed for the sake of simplicity. */
@@ -85,16 +128,37 @@ load_shlib (const char *file, Elf_External_Ehdr **ehdr_out,
struct segment **seg_out)
{
uint64_t i;
- int fd;
+ int fd = -1;
off_t fsize;
uint8_t *addr;
Elf_External_Ehdr *ehdr;
Elf_External_Phdr *phdr;
struct segment *head_seg = NULL;
struct segment *tail_seg = NULL;
+ const char *origin;
+ char *path;
+
+ /* Map the lib in memory for reading.
+
+ If the file name is relative, try looking it up relative to the
+ main executable's path. I.e., emulate RPATH=$ORIGIN. */
+ if (file[0] != '/')
+ {
+ origin = get_origin ();
+ if (origin == NULL)
+ {
+ fprintf (stderr, "get_origin not implemented.");
+ return -1;
+ }
+
+ path = alloca (strlen (origin) + 1 + strlen (file) + 1);
+ sprintf (path, "%s/%s", origin, file);
+ fd = open (path, O_RDONLY);
+ }
+
+ if (fd < 0)
+ fd = open (file, O_RDONLY);
- /* Map the lib in memory for reading. */
- fd = open (file, O_RDONLY);
if (fd < 0)
{
perror ("fopen failed.");