This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] elf: Remove pldd (BZ#18035)
- From: Adhemerval Zanella <adhemerval dot zanella at linaro dot org>
- To: libc-alpha at sourceware dot org
- Date: Wed, 10 Apr 2019 16:04:50 -0300
- Subject: [PATCH] elf: Remove pldd (BZ#18035)
As reported in bugzilla itself and on man-pages [1] it has been
broken since 2.19. Also, its design tie glibc internal definition
by duplicate struct layouts and dynamic loader objects.
Also, as noted by man-pages the same behavior can be obtained with
$ gdb -ex "set confirm off" -ex "set height 0" -ex "info shared" \
-ex "quit" -p $pid | grep '^0x.*0x'
Or with external tools as 'lsof'. An alternative way to show the
dynamic shared objects liked into a process on Linux would be to
use the /proc/<pid>/maps instead as following example:
---
import sys, os
def main(argv):
with open('/proc/' + argv[0] + '/maps', 'r') as maps:
segs = {}
st = os.stat('/proc/' + argv[0] + '/exe')
for line in maps:
fields = line.split()
if len(fields) < 5:
continue
major,minor = fields[3].split(':')
dev = os.makedev(int(major), int(minor))
inode = int(fields[4])
if dev == 0 or inode == 0:
continue
# Skip the map entry if the device + inode pair match that of the exe.
if dev == st.st_dev or inode == st.st_ino:
continue
# Check if file is accessible.
try:
segst = os.stat(fields[5])
except OSError:
continue
# Print only executable segments.
if 'x' in fields[1]:
print(fields[5])
if __name__ == '__main__':
main(sys.argv[1:])
---
Checked on x86_64-linux-gnu.
* elf/pldd-xx.c: Remove file.
* elf/pldd.c: Likewise.
* sysdeps/unix/sysv/linux/Makefile [$(subdir) == elf] (pldd): Remove
rule.
[1] http://man7.org/linux/man-pages/man1/pldd.1.html
---
elf/pldd-xx.c | 251 ----------------------
elf/pldd.c | 344 -------------------------------
sysdeps/unix/sysv/linux/Makefile | 4 -
3 files changed, 599 deletions(-)
delete mode 100644 elf/pldd-xx.c
delete mode 100644 elf/pldd.c
diff --git a/elf/pldd-xx.c b/elf/pldd-xx.c
deleted file mode 100644
index 547f840ee1..0000000000
--- a/elf/pldd-xx.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/* Copyright (C) 2011-2019 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#define E(name) E_(name, CLASS)
-#define E_(name, cl) E__(name, cl)
-#define E__(name, cl) name##cl
-#define EW(type) EW_(Elf, CLASS, type)
-#define EW_(e, w, t) EW__(e, w, _##t)
-#define EW__(e, w, t) e##w##t
-
-#define pldd_assert(name, exp) \
- typedef int __assert_##name[((exp) != 0) - 1]
-
-
-struct E(link_map)
-{
- EW(Addr) l_addr;
- EW(Addr) l_name;
- EW(Addr) l_ld;
- EW(Addr) l_next;
- EW(Addr) l_prev;
- EW(Addr) l_real;
- Lmid_t l_ns;
- EW(Addr) l_libname;
-};
-#if CLASS == __ELF_NATIVE_CLASS
-pldd_assert (l_addr, (offsetof (struct link_map, l_addr)
- == offsetof (struct E(link_map), l_addr)));
-pldd_assert (l_name, (offsetof (struct link_map, l_name)
- == offsetof (struct E(link_map), l_name)));
-pldd_assert (l_next, (offsetof (struct link_map, l_next)
- == offsetof (struct E(link_map), l_next)));
-#endif
-
-
-struct E(libname_list)
-{
- EW(Addr) name;
- EW(Addr) next;
-};
-#if CLASS == __ELF_NATIVE_CLASS
-pldd_assert (name, (offsetof (struct libname_list, name)
- == offsetof (struct E(libname_list), name)));
-pldd_assert (next, (offsetof (struct libname_list, next)
- == offsetof (struct E(libname_list), next)));
-#endif
-
-struct E(r_debug)
-{
- int r_version;
-#if CLASS == 64
- int pad;
-#endif
- EW(Addr) r_map;
-};
-#if CLASS == __ELF_NATIVE_CLASS
-pldd_assert (r_version, (offsetof (struct r_debug, r_version)
- == offsetof (struct E(r_debug), r_version)));
-pldd_assert (r_map, (offsetof (struct r_debug, r_map)
- == offsetof (struct E(r_debug), r_map)));
-#endif
-
-
-static int
-
-E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
-{
- EW(Addr) phdr = 0;
- unsigned int phnum = 0;
- unsigned int phent = 0;
-
- EW(auxv_t) *auxvXX = (EW(auxv_t) *) auxv;
- for (int i = 0; i < auxv_size / sizeof (EW(auxv_t)); ++i)
- switch (auxvXX[i].a_type)
- {
- case AT_PHDR:
- phdr = auxvXX[i].a_un.a_val;
- break;
- case AT_PHNUM:
- phnum = auxvXX[i].a_un.a_val;
- break;
- case AT_PHENT:
- phent = auxvXX[i].a_un.a_val;
- break;
- default:
- break;
- }
-
- if (phdr == 0 || phnum == 0 || phent == 0)
- error (EXIT_FAILURE, 0, gettext ("cannot find program header of process"));
-
- EW(Phdr) *p = alloca (phnum * phent);
- if (pread64 (memfd, p, phnum * phent, phdr) != phnum * phent)
- {
- error (0, 0, gettext ("cannot read program header"));
- return EXIT_FAILURE;
- }
-
- /* Determine the load offset. We need this for interpreting the
- other program header entries so we do this in a separate loop.
- Fortunately it is the first time unless someone does something
- stupid when linking the application. */
- EW(Addr) offset = 0;
- for (unsigned int i = 0; i < phnum; ++i)
- if (p[i].p_type == PT_PHDR)
- {
- offset = phdr - p[i].p_vaddr;
- break;
- }
-
- EW(Addr) list = 0;
- char *interp = NULL;
- for (unsigned int i = 0; i < phnum; ++i)
- if (p[i].p_type == PT_DYNAMIC)
- {
- EW(Dyn) *dyn = xmalloc (p[i].p_filesz);
- if (pread64 (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr)
- != p[i].p_filesz)
- {
- error (0, 0, gettext ("cannot read dynamic section"));
- return EXIT_FAILURE;
- }
-
- /* Search for the DT_DEBUG entry. */
- for (unsigned int j = 0; j < p[i].p_filesz / sizeof (EW(Dyn)); ++j)
- if (dyn[j].d_tag == DT_DEBUG && dyn[j].d_un.d_ptr != 0)
- {
- struct E(r_debug) r;
- if (pread64 (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr)
- != sizeof (r))
- {
- error (0, 0, gettext ("cannot read r_debug"));
- return EXIT_FAILURE;
- }
-
- if (r.r_map != 0)
- {
- list = r.r_map;
- break;
- }
- }
-
- free (dyn);
- break;
- }
- else if (p[i].p_type == PT_INTERP)
- {
- interp = alloca (p[i].p_filesz);
- if (pread64 (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr)
- != p[i].p_filesz)
- {
- error (0, 0, gettext ("cannot read program interpreter"));
- return EXIT_FAILURE;
- }
- }
-
- if (list == 0)
- {
- if (interp == NULL)
- {
- // XXX check whether the executable itself is the loader
- return EXIT_FAILURE;
- }
-
- // XXX perhaps try finding ld.so and _r_debug in it
-
- return EXIT_FAILURE;
- }
-
- /* Print the PID and program name first. */
- printf ("%lu:\t%s\n", (unsigned long int) pid, exe);
-
- /* Iterate over the list of objects and print the information. */
- struct scratch_buffer tmpbuf;
- scratch_buffer_init (&tmpbuf);
- int status = 0;
- do
- {
- struct E(link_map) m;
- if (pread64 (memfd, &m, sizeof (m), list) != sizeof (m))
- {
- error (0, 0, gettext ("cannot read link map"));
- status = EXIT_FAILURE;
- goto out;
- }
-
- EW(Addr) name_offset = m.l_name;
- again:
- while (1)
- {
- ssize_t n = pread64 (memfd, tmpbuf.data, tmpbuf.length, name_offset);
- if (n == -1)
- {
- error (0, 0, gettext ("cannot read object name"));
- status = EXIT_FAILURE;
- goto out;
- }
-
- if (memchr (tmpbuf.data, '\0', n) != NULL)
- break;
-
- if (!scratch_buffer_grow (&tmpbuf))
- {
- error (0, 0, gettext ("cannot allocate buffer for object name"));
- status = EXIT_FAILURE;
- goto out;
- }
- }
-
- if (((char *)tmpbuf.data)[0] == '\0' && name_offset == m.l_name
- && m.l_libname != 0)
- {
- /* Try the l_libname element. */
- struct E(libname_list) ln;
- if (pread64 (memfd, &ln, sizeof (ln), m.l_libname) == sizeof (ln))
- {
- name_offset = ln.name;
- goto again;
- }
- }
-
- /* Skip over the executable. */
- if (((char *)tmpbuf.data)[0] != '\0')
- printf ("%s\n", (char *)tmpbuf.data);
-
- list = m.l_next;
- }
- while (list != 0);
-
- out:
- scratch_buffer_free (&tmpbuf);
- return status;
-}
-
-
-#undef CLASS
diff --git a/elf/pldd.c b/elf/pldd.c
deleted file mode 100644
index f3fac4e487..0000000000
--- a/elf/pldd.c
+++ /dev/null
@@ -1,344 +0,0 @@
-/* List dynamic shared objects linked into given process.
- Copyright (C) 2011-2019 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#include <alloca.h>
-#include <argp.h>
-#include <assert.h>
-#include <dirent.h>
-#include <elf.h>
-#include <errno.h>
-#include <error.h>
-#include <fcntl.h>
-#include <libintl.h>
-#include <link.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ptrace.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <scratch_buffer.h>
-
-#include <ldsodefs.h>
-#include <version.h>
-
-/* Global variables. */
-extern char *program_invocation_short_name;
-#define PACKAGE _libc_intl_domainname
-
-/* External functions. */
-#include <programs/xmalloc.h>
-
-/* Name and version of program. */
-static void print_version (FILE *stream, struct argp_state *state);
-void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
-
-/* Function to print some extra text in the help message. */
-static char *more_help (int key, const char *text, void *input);
-
-/* Definitions of arguments for argp functions. */
-static const struct argp_option options[] =
-{
- { NULL, 0, NULL, 0, NULL }
-};
-
-/* Short description of program. */
-static const char doc[] = N_("\
-List dynamic shared objects loaded into process.");
-
-/* Strings for arguments in help texts. */
-static const char args_doc[] = N_("PID");
-
-/* Prototype for option handler. */
-static error_t parse_opt (int key, char *arg, struct argp_state *state);
-
-/* Data structure to communicate with argp functions. */
-static struct argp argp =
-{
- options, parse_opt, args_doc, doc, NULL, more_help, NULL
-};
-
-// File descriptor of /proc/*/mem file.
-static int memfd;
-
-/* Name of the executable */
-static char *exe;
-
-/* Local functions. */
-static int get_process_info (int dfd, long int pid);
-static void wait_for_ptrace_stop (long int pid);
-
-
-int
-main (int argc, char *argv[])
-{
- /* Parse and process arguments. */
- int remaining;
- argp_parse (&argp, argc, argv, 0, &remaining, NULL);
-
- if (remaining != argc - 1)
- {
- fprintf (stderr,
- gettext ("Exactly one parameter with process ID required.\n"));
- argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name);
- return 1;
- }
-
- assert (sizeof (pid_t) == sizeof (int)
- || sizeof (pid_t) == sizeof (long int));
- char *endp;
- errno = 0;
- long int pid = strtol (argv[remaining], &endp, 10);
- if (pid < 0 || (pid == ULONG_MAX && errno == ERANGE) || *endp != '\0'
- || (sizeof (pid_t) < sizeof (pid) && pid > INT_MAX))
- error (EXIT_FAILURE, 0, gettext ("invalid process ID '%s'"),
- argv[remaining]);
-
- /* Determine the program name. */
- char buf[7 + 3 * sizeof (pid)];
- snprintf (buf, sizeof (buf), "/proc/%lu", pid);
- int dfd = open (buf, O_RDONLY | O_DIRECTORY);
- if (dfd == -1)
- error (EXIT_FAILURE, errno, gettext ("cannot open %s"), buf);
-
- struct scratch_buffer exebuf;
- scratch_buffer_init (&exebuf);
- ssize_t nexe;
- while ((nexe = readlinkat (dfd, "exe",
- exebuf.data, exebuf.length)) == exebuf.length)
- {
- if (!scratch_buffer_grow (&exebuf))
- {
- nexe = -1;
- break;
- }
- }
- if (nexe == -1)
- exe = (char *) "<program name undetermined>";
- else
- {
- exe = exebuf.data;
- exe[nexe] = '\0';
- }
-
- /* Stop all threads since otherwise the list of loaded modules might
- change while we are reading it. */
- struct thread_list
- {
- pid_t tid;
- struct thread_list *next;
- } *thread_list = NULL;
-
- int taskfd = openat (dfd, "task", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
- if (taskfd == 1)
- error (EXIT_FAILURE, errno, gettext ("cannot open %s/task"), buf);
- DIR *dir = fdopendir (taskfd);
- if (dir == NULL)
- error (EXIT_FAILURE, errno, gettext ("cannot prepare reading %s/task"),
- buf);
-
- struct dirent64 *d;
- while ((d = readdir64 (dir)) != NULL)
- {
- if (! isdigit (d->d_name[0]))
- continue;
-
- errno = 0;
- long int tid = strtol (d->d_name, &endp, 10);
- if (tid < 0 || (tid == ULONG_MAX && errno == ERANGE) || *endp != '\0'
- || (sizeof (pid_t) < sizeof (pid) && tid > INT_MAX))
- error (EXIT_FAILURE, 0, gettext ("invalid thread ID '%s'"),
- d->d_name);
-
- if (ptrace (PTRACE_ATTACH, tid, NULL, NULL) != 0)
- {
- /* There might be a race between reading the directory and
- threads terminating. Ignore errors attaching to unknown
- threads unless this is the main thread. */
- if (errno == ESRCH && tid != pid)
- continue;
-
- error (EXIT_FAILURE, errno, gettext ("cannot attach to process %lu"),
- tid);
- }
-
- wait_for_ptrace_stop (tid);
-
- struct thread_list *newp = alloca (sizeof (*newp));
- newp->tid = tid;
- newp->next = thread_list;
- thread_list = newp;
- }
-
- closedir (dir);
-
- int status = get_process_info (dfd, pid);
-
- assert (thread_list != NULL);
- do
- {
- ptrace (PTRACE_DETACH, thread_list->tid, NULL, NULL);
- thread_list = thread_list->next;
- }
- while (thread_list != NULL);
-
- close (dfd);
-
- return status;
-}
-
-
-/* Wait for PID to enter ptrace-stop state after being attached. */
-static void
-wait_for_ptrace_stop (long int pid)
-{
- int status;
-
- /* While waiting for SIGSTOP being delivered to the tracee we have to
- reinject any other pending signal. Ignore all other errors. */
- while (waitpid (pid, &status, __WALL) == pid && WIFSTOPPED (status))
- {
- /* The STOP signal should not be delivered to the tracee. */
- if (WSTOPSIG (status) == SIGSTOP)
- return;
- if (ptrace (PTRACE_CONT, pid, NULL,
- (void *) (uintptr_t) WSTOPSIG (status)))
- /* The only possible error is that the process died. */
- return;
- }
-}
-
-
-/* Handle program arguments. */
-static error_t
-parse_opt (int key, char *arg, struct argp_state *state)
-{
- switch (key)
- {
- default:
- return ARGP_ERR_UNKNOWN;
- }
- return 0;
-}
-
-
-/* Print bug-reporting information in the help message. */
-static char *
-more_help (int key, const char *text, void *input)
-{
- char *tp = NULL;
- switch (key)
- {
- case ARGP_KEY_HELP_EXTRA:
- /* We print some extra information. */
- if (asprintf (&tp, gettext ("\
-For bug reporting instructions, please see:\n\
-%s.\n"), REPORT_BUGS_TO) < 0)
- return NULL;
- return tp;
- default:
- break;
- }
- return (char *) text;
-}
-
-/* Print the version information. */
-static void
-print_version (FILE *stream, struct argp_state *state)
-{
- fprintf (stream, "pldd %s%s\n", PKGVERSION, VERSION);
- fprintf (stream, gettext ("\
-Copyright (C) %s Free Software Foundation, Inc.\n\
-This is free software; see the source for copying conditions. There is NO\n\
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "2019");
- fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
-}
-
-
-#define CLASS 32
-#include "pldd-xx.c"
-#define CLASS 64
-#include "pldd-xx.c"
-
-
-static int
-get_process_info (int dfd, long int pid)
-{
- memfd = openat (dfd, "mem", O_RDONLY);
- if (memfd == -1)
- goto no_info;
-
- int fd = openat (dfd, "exe", O_RDONLY);
- if (fd == -1)
- {
- no_info:
- error (0, errno, gettext ("cannot get information about process %lu"),
- pid);
- return EXIT_FAILURE;
- }
-
- char e_ident[EI_NIDENT];
- if (read (fd, e_ident, EI_NIDENT) != EI_NIDENT)
- goto no_info;
-
- close (fd);
-
- if (memcmp (e_ident, ELFMAG, SELFMAG) != 0)
- {
- error (0, 0, gettext ("process %lu is no ELF program"), pid);
- return EXIT_FAILURE;
- }
-
- fd = openat (dfd, "auxv", O_RDONLY);
- if (fd == -1)
- goto no_info;
-
- size_t auxv_size = 0;
- void *auxv = NULL;
- while (1)
- {
- auxv_size += 512;
- auxv = xrealloc (auxv, auxv_size);
-
- ssize_t n = pread (fd, auxv, auxv_size, 0);
- if (n < 0)
- goto no_info;
- if (n < auxv_size)
- {
- auxv_size = n;
- break;
- }
- }
-
- close (fd);
-
- int retval;
- if (e_ident[EI_CLASS] == ELFCLASS32)
- retval = find_maps32 (pid, auxv, auxv_size);
- else
- retval = find_maps64 (pid, auxv, auxv_size);
-
- free (auxv);
- close (memfd);
-
- return retval;
-}
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 52ac6ad484..e799473b17 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -212,10 +212,6 @@ sysdep-rtld-routines += dl-brk dl-sbrk dl-getcwd dl-openat64 dl-opendir \
dl-fxstatat64
libof-lddlibc4 = lddlibc4
-
-others += pldd
-install-bin += pldd
-$(objpfx)pldd: $(objpfx)xmalloc.o
endif
ifeq ($(subdir),rt)
--
2.17.1