From fffd993df22e065682ca4178e172407a789ddca9 Mon Sep 17 00:00:00 2001 From: Edwin Groothuis Date: Thu, 3 Jul 2008 22:37:51 +0000 Subject: On 64 bit architectures, you can run 32 bit executables and the rtld can trace them, but ldd(1) doesn't know yet how to detect them: [/] root@ed-exigent>ldd `which httpd` ldd: /usr/local/sbin/httpd: can't read program header ldd: /usr/local/sbin/httpd: not a dynamic executable But... [/] root@ed-exigent>LD_32_TRACE_LOADED_OBJECTS==1 `which httpd` libm.so.4 => /lib32//libm.so.4 (0x280c8000) libaprutil-1.so.2 => /usr/local/lib/libaprutil-1.so.2 (0x280de000) libexpat.so.6 => /usr/local/lib/libexpat.so.6 (0x280f2000) libiconv.so.3 => /usr/local/lib/libiconv.so.3 (0x28110000) libapr-1.so.2 => /usr/local/lib/libapr-1.so.2 (0x281fd000) libcrypt.so.3 => /lib32//libcrypt.so.3 (0x2821d000) libpthread.so.2 => not found (0x0) libc.so.6 => /lib32//libc.so.6 (0x28235000) libpthread.so.2 => /usr/lib32/libpthread.so.2 (0x2830d000) Added support in ldd(1) for the LD_32_xxx environment variables if the architecture of the machine is >32 bits. If we ever go to 128 bit architectures this excercise will have to be repeated but thanks to earlier commits today it will be relative simple. PR: bin/124906 Submitted by: edwin Approved by: bde (mentor) MFC after: 1 week --- usr.bin/ldd/ldd.1 | 6 +++++ usr.bin/ldd/ldd.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 2 deletions(-) (limited to 'usr.bin') diff --git a/usr.bin/ldd/ldd.1 b/usr.bin/ldd/ldd.1 index 72afb3903c51..fab21eb2bcb0 100644 --- a/usr.bin/ldd/ldd.1 +++ b/usr.bin/ldd/ldd.1 @@ -64,6 +64,12 @@ option. It will print a report of all ELF binaries in the current directory, which link against libc.so.6: .Dl "find . -type f | xargs -n1 file -F " " | grep ELF | cut -f1 -d' ' | xargs ldd -f '%A %o\en' | grep libc.so.6" +.Sh BUGS +On 64 bit architectures, dlopen() cannot open 32 bit dynamic libraries, +so +.Nm +will show the error +.Qq "unsupported file layout" . .Sh SEE ALSO .Xr ld 1 , .Xr nm 1 , diff --git a/usr.bin/ldd/ldd.c b/usr.bin/ldd/ldd.c index 2d276b1287c8..9a7febac44bf 100644 --- a/usr.bin/ldd/ldd.c +++ b/usr.bin/ldd/ldd.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -54,6 +55,9 @@ static void usage(void); #define TYPE_UNKNOWN 0 #define TYPE_AOUT 1 #define TYPE_ELF 2 /* Architecture default */ +#if __ELF_WORD_SIZE > 32 +#define TYPE_ELF32 3 /* Explicit 32 bits on architectures >32 bits */ +#endif #define ENV_OBJECTS 0 #define ENV_OBJECTS_FMT1 1 @@ -69,6 +73,15 @@ const char *envdef[ENV_LAST] = { "LD_TRACE_LOADED_OBJECTS_PROGNAME", "LD_TRACE_LOADED_OBJECTS_ALL", }; +#if __ELF_WORD_SIZE > 32 +const char *env32[ENV_LAST] = { + "LD_32_TRACE_LOADED_OBJECTS", + "LD_32_TRACE_LOADED_OBJECTS_FMT1", + "LD_32_TRACE_LOADED_OBJECTS_FMT2", + "LD_32_TRACE_LOADED_OBJECTS_PROGNAME", + "LD_32_TRACE_LOADED_OBJECTS_ALL", +}; +#endif int main(int argc, char *argv[]) @@ -124,8 +137,6 @@ main(int argc, char *argv[]) int fd, status, is_shlib, rv, type; const char **env; - env = envdef; /* Temporary placeholder */ - if ((fd = open(*argv, O_RDONLY, 0)) < 0) { warn("%s", *argv); rval |= 1; @@ -138,6 +149,25 @@ main(int argc, char *argv[]) continue; } + switch (type) { + case TYPE_ELF: + case TYPE_AOUT: + env = envdef; + break; +#if __ELF_WORD_SIZE > 32 + case TYPE_ELF32: + env = env32; + break; +#endif + case TYPE_UNKNOWN: + default: + /* + * This shouldn't happen unless is_executable() + * is broken. + */ + errx(EDOOFUS, "unknown executable type"); + } + /* ld.so magic */ setenv(env[ENV_OBJECTS], "yes", 1); if (fmt1 != NULL) @@ -199,6 +229,7 @@ is_executable(const char *fname, int fd, int *is_shlib, int *type) { union { struct exec aout; + Elf32_Ehdr elf32; Elf_Ehdr elf; } hdr; int n; @@ -225,6 +256,49 @@ is_executable(const char *fname, int fd, int *is_shlib, int *type) return (1); } +#if __ELF_WORD_SIZE > 32 + if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) && + hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { + /* Handle 32 bit ELF objects */ + Elf32_Phdr phdr; + int dynamic, i; + + dynamic = 0; + *type = TYPE_ELF32; + + if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) { + warnx("%s: header too short", fname); + return (0); + } + for (i = 0; i < hdr.elf32.e_phnum; i++) { + if (read(fd, &phdr, hdr.elf32.e_phentsize) != + sizeof(phdr)) { + warnx("%s: can't read program header", fname); + return (0); + } + if (phdr.p_type == PT_DYNAMIC) { + dynamic = 1; + break; + } + } + + if (!dynamic) { + warnx("%s: not a dynamic ELF executable", fname); + return (0); + } + if (hdr.elf32.e_type == ET_DYN) { + if (hdr.elf32.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { + *is_shlib = 1; + return (1); + } + warnx("%s: not a FreeBSD ELF shared object", fname); + return (0); + } + + return (1); + } +#endif + if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) && hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) { /* Handle default ELF objects on this architecture */ -- cgit v1.2.3