From b67fc38872af0d99da3558739b945109dc88bcb9 Mon Sep 17 00:00:00 2001 From: clifford Date: Sat, 30 Jan 2010 05:43:13 +0000 Subject: Clifford Wolf: Moved chrpath_linux.c to scripts (it belongs to release_linux) Added svn:ignore prop to objects directory git-svn-id: http://svn.clifford.at/openscad/trunk@371 b57f626f-c46c-0410-a088-ec61d464b74c diff --git a/scripts/chrpath_linux.c b/scripts/chrpath_linux.c new file mode 100644 index 0000000..000244a --- /dev/null +++ b/scripts/chrpath_linux.c @@ -0,0 +1,769 @@ +/*************************************************************************** + * * + * This is a pre-configured single file version of chrpath for linux. * + * It is used in the binary installer for OpenSCAD on Linux. * + * * + * This file has been created by running * + * cat *.h *.c | sed 's, *# *include *",//&,' > ../chrpath_linux.c * + * in the configured chrpath-0.13 source directory (as found in the debian * + * package repository as the original download site seams to be down). * + * * + * chrpath is licensed under the terms of GPLv2: * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * The Authors are: * + * * + * Geoffrey Keating * + * Implemented first version of chrpath.c based on first version of * + * killrpath. * + * Peeter Joot * + * Implemented first version of killrpath.c. * + * Petter Reinholdtsen * + * Collected both implementations and made userfriendly wrapper. * + * * + * With patches from: * + * * + * Darren Salt * + * David Hull * + * Bradford W. Johnson * + * Thomas Anders * + * Tollef Fog Heen * + * * + ***************************************************************************/ + + +/* config.h. Generated by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ELF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_GETOPT_H 1 + +/* Define to 1 if you have the `getopt_long' function. */ +#define HAVE_GETOPT_LONG 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LINK_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_LINK_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Name of package */ +#define PACKAGE "chrpath" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "pere@hungry.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME ""chrpath"" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING ""chrpath" "0.13"" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "-chrpath-" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION ""0.13"" + +/* The size of a `void *', as computed by sizeof. */ +#define SIZEOF_VOID_P 4 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "0.13" + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ +#ifndef PROTOS_H +#define PROTOS_H + +#include +//#include "config.h" + +#ifdef WORDS_BIGENDIAN +#define ELFDATA2 ELFDATA2MSB +#else +#define ELFDATA2 ELFDATA2LSB +#endif +#if SIZEOF_VOID_P == 8 +#define Elf_Ehdr Elf64_Ehdr +#define ELFCLASS ELFCLASS64 +#define Elf_Phdr Elf64_Phdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Dyn Elf64_Dyn +#elif SIZEOF_VOID_P == 4 +#define Elf_Ehdr Elf32_Ehdr +#define ELFCLASS ELFCLASS32 +#define Elf_Phdr Elf32_Phdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Dyn Elf32_Dyn +#else +#error "Unknown word size (SIZEOF_VOID_P)!" +#endif + +int killrpath(const char *filename); +int chrpath(const char *filename, const char *newpath, int convert); + +int elf_open(const char *filename, int flags, Elf_Ehdr *ehdr); +void elf_close(int fd); +int elf_find_dynamic_section(int fd, Elf_Ehdr *ehdr, Elf_Phdr *phdr); +const char *elf_tagname(int tag); +int elf_dynpath_tag(int tag); + +#endif /* PROTOS_H */ +/* + + +Re: changing embedded RPATH in existing executables. + + To: geoffk@ozemail.com.au + Subject: Re: changing embedded RPATH in existing executables. + From: (peeter joot) + Date: Fri, 30 Apr 1999 16:14:44 -0400 (EDT) + Cc: peeterj@ca.ibm.com, egcs@cygnus.com, libc-hacker@cygnus.com, linux-gcc@vger.rutgers.edu + Reply-To: + +> _Changing_ is a little tricky, but the attached program strips rpaths +> from executables (I find it essential for debugging the binutils). +> It's endian-dependent, if you want this for x86 you can just change +> the occurrences of 'MSB' to 'LSB' and compile (I should really fix +> that). + +Hi Geoff, + +With your program as a guide (and some peeks into libbfd, elf.h, a bit +of the glibc dynamic loader code, objdump, and a hex-editor) I was able to +figure out enough to find and change the rpath string. That was fun! + +This program assumes (unlike your original program) that there is only +one DT_RPATH tag in the dynamic section as even with multiple '-Wl,-rpath,' +commands in the link this seems to occur (they all get concatonated into +a : separated path). + +Thanks for your help. If you want to use this on non-x86 you have to change +the occurances of LSB back to MSB:) + +Peeter +-- +*/ + +#ifdef HAVE_CONFIG_H +//# include "config.h" +#endif + +#include +#include +#include +#include +#if defined(HAVE_LINK_H) +# include +#endif /* HAVE_LINK_H */ +#include +#include +#include +//#include "protos.h" + +/** + * Reads an ELF file, and reads or alters the RPATH setting. + * + * TODO: + * modify to add RPATH setting if none exists. + */ + + +int +chrpath(const char *filename, const char *newpath, int convert) +{ + int fd; + Elf_Ehdr ehdr; + int i; + Elf_Phdr phdr; + Elf_Shdr shdr; + Elf_Dyn *dyns; + int rpathoff; + char * strtab; + char * rpath; + unsigned int rpathlen; + int oflags; + int rpath_dyns_index; + + if (NULL == newpath && 0 == convert) + oflags = O_RDONLY; + else + oflags = O_RDWR; + + fd = elf_open(filename, oflags, &ehdr); + if (fd == -1) + { + perror ("elf_open"); + return 1; + } + + if (0 != elf_find_dynamic_section(fd, &ehdr, &phdr)) + { + perror("found no dynamic section"); + return 1; + } + + dyns = malloc(phdr.p_filesz); + if (dyns == NULL) + { + perror ("allocating memory for dynamic section"); + return 1; + } + memset(dyns, 0, phdr.p_filesz); + if (lseek(fd, phdr.p_offset, SEEK_SET) == -1 + || read(fd, dyns, phdr.p_filesz) != (int)phdr.p_filesz) + { + perror ("reading dynamic section"); + free(dyns); + return 1; + } + + rpathoff = -1; + for ( rpath_dyns_index = 0; dyns[rpath_dyns_index].d_tag != DT_NULL; + ++rpath_dyns_index ) + { + if ( elf_dynpath_tag(dyns[rpath_dyns_index].d_tag) ) + { + rpathoff = dyns[rpath_dyns_index].d_un.d_ptr; + break; + } + } + if (rpathoff == -1) + { + printf("%s: no rpath or runpath tag found.\n", filename); + free(dyns); + return 2; + } + + if (lseek(fd, ehdr.e_shoff, SEEK_SET) == -1) + { + perror ("positioning for sections"); + free(dyns); + return 1; + } + + for (i = 0; i < ehdr.e_shnum; i++) + { + if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr)) + { + perror ("reading section header"); + free(dyns); + return 1; + } + if (shdr.sh_type == SHT_STRTAB) + break; + } + if (i == ehdr.e_shnum) + { + fprintf (stderr, "No string table found.\n"); + free(dyns); + return 2; + } + strtab = (char *)malloc(shdr.sh_size); + if (strtab == NULL) + { + perror ("allocating memory for string table"); + free(dyns); + return 1; + } + memset(strtab, 0, shdr.sh_size); + + if (lseek(fd, shdr.sh_offset, SEEK_SET) == -1) + { + perror ("positioning for string table"); + free(strtab); + free(dyns); + return 1; + } + if (read(fd, strtab, shdr.sh_size) != (int)shdr.sh_size) + { + perror ("reading string table"); + free(strtab); + free(dyns); + return 1; + } + + if ((int)shdr.sh_size < rpathoff) + { + fprintf(stderr, "%s string offset not contained in string table", + elf_tagname(dyns[rpath_dyns_index].d_tag)); + free(strtab); + free(dyns); + return 5; + } + rpath = strtab+rpathoff; + +#if defined(DT_RUNPATH) + if (convert && dyns[rpath_dyns_index].d_tag == DT_RPATH) + { + dyns[rpath_dyns_index].d_tag = DT_RUNPATH; + if (lseek(fd, phdr.p_offset, SEEK_SET) == -1 + || write(fd, dyns, phdr.p_filesz) != (int)phdr.p_filesz) + { + perror ("converting RPATH to RUNPATH"); + return 1; + } + printf("%s: RPATH converted to RUNPATH\n", filename); + } +#endif /* DT_RUNPATH */ + + printf("%s: %s=%s\n", filename, elf_tagname(dyns[rpath_dyns_index].d_tag), + rpath); + + if (NULL == newpath) + { + free(dyns); + free(strtab); + return 0; + } + + rpathlen = strlen(rpath); + + /* + * Calculate the maximum rpath length (will be equal to rpathlen unless + * we have previously truncated it). + */ + for ( i = rpathoff + rpathlen ; (i < (int)shdr.sh_size + && strtab[i] == '\0') ; i++ ) + ; + i--; + + if (i > (int)(rpathoff + rpathlen)) + rpathlen = i - rpathoff; + + if (strlen(newpath) > rpathlen) + { + fprintf(stderr, "new rpath '%s' too large; maximum length %i\n", + newpath, rpathlen); + free(dyns); + free(strtab); + return 7; + } + + memset(rpath, 0, rpathlen); + strcpy(rpath, newpath); + + if (lseek(fd, shdr.sh_offset+rpathoff, SEEK_SET) == -1) + { + perror ("positioning for RPATH"); + free(dyns); + free(strtab); + return 1; + } + if (write(fd, rpath, rpathlen) != (int)rpathlen) + { + perror ("writing RPATH"); + free(dyns); + free(strtab); + return 1; + } + printf("%s: new %s: %s\n", filename, + elf_tagname(dyns[rpath_dyns_index].d_tag), rpath); + + elf_close(fd); + + free(dyns); + dyns = NULL; + + free(strtab); + + return 0; +} + +#ifdef HAVE_CONFIG_H +//# include "config.h" +#endif + +#include +#if defined(HAVE_SYS_LINK_H) +# include /* Find DT_RPATH on Solaris 2.6 */ +#endif /* HAVE_SYS_LINK_H */ +#include +#include +#include +#include +#include +#include +#include +//#include "protos.h" + +int +elf_open(const char *filename, int flags, Elf_Ehdr *ehdr) +{ + int fd; + + fd = open(filename, flags); + if (fd == -1) + { + perror ("open"); + return -1; + } + + if (read(fd, ehdr, sizeof(*ehdr)) != sizeof(*ehdr)) + { + perror ("reading header"); + close(fd); + return -1; + } + + if (0 != memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || + ehdr->e_ident[EI_CLASS] != ELFCLASS || + ehdr->e_ident[EI_DATA] != ELFDATA2 || + ehdr->e_ident[EI_VERSION] != EV_CURRENT) + { + fprintf(stderr, +#ifdef WORDS_BIGENDIAN + "`%s' probably isn't a %d-bit MSB-first ELF file.\n", +#else /* not WORD_BIGENDIAN */ + "`%s' probably isn't a %d-bit LSB-first ELF file.\n", +#endif /* not WORD_BIGENDIAN */ + filename, SIZEOF_VOID_P * 8); + close(fd); + errno = ENOEXEC; /* Hm, is this the best errno code to use? */ + return -1; + } + + if (ehdr->e_phentsize != sizeof(Elf_Phdr)) + { + fprintf(stderr, "section size was read as %d, not %d!\n", + ehdr->e_phentsize, sizeof(Elf_Phdr)); + close(fd); + return -1; + } + return fd; +} + +int +elf_find_dynamic_section(int fd, Elf_Ehdr *ehdr, Elf_Phdr *phdr) +{ + int i; + if (lseek(fd, ehdr->e_phoff, SEEK_SET) == -1) + { + perror ("positioning for sections"); + return 1; + } + + for (i = 0; i < ehdr->e_phnum; i++) + { + if (read(fd, phdr, sizeof(*phdr)) != sizeof(*phdr)) + { + perror ("reading section header"); + return 1; + } + if (phdr->p_type == PT_DYNAMIC) + break; + } + if (i == ehdr->e_phnum) + { + fprintf (stderr, "No dynamic section found.\n"); + return 2; + } + + if (0 == phdr->p_filesz) + { + fprintf (stderr, "Length of dynamic section is zero.\n"); + return 3; + } + + return 0; +} + +void +elf_close(int fd) +{ + close(fd); +} + +const char * +elf_tagname(int tag) +{ + switch (tag) { + case DT_RPATH: + return "RPATH"; + break; +#if defined(DT_RUNPATH) + case DT_RUNPATH: + return "RUNPATH"; + break; +#endif /* DT_RUNPATH */ + } + return "UNKNOWN"; +} + +int +elf_dynpath_tag(int tag) +{ + return ( tag == DT_RPATH +#if defined(DT_RUNPATH) + || tag == DT_RUNPATH +#endif /* DT_RUNPATH */ + ); +} +/* +Taken from another list: + +_Changing_ is a little tricky, but the attached program strips rpaths +from executables (I find it essential for debugging the binutils). +It's endian-dependent, if you want this for x86 you can just change +the occurrences of 'MSB' to 'LSB' and compile (I should really fix +that). + +-- +Geoffrey Keating +*/ + +#ifdef HAVE_CONFIG_H +//# include "config.h" +#endif + +#include +#include +#include +#include +#if defined(HAVE_LINK_H) +# include +#endif /* HAVE_LINK_H */ +#include +//#include "protos.h" +#include + +/* Reads an ELF file, nukes all the RPATH entries. */ + +int +killrpath(const char *filename) +{ + int fd; + Elf_Ehdr ehdr; + int i; + Elf_Phdr phdr; + Elf_Dyn *dyns; + int dynpos; + + fd = elf_open(filename, O_RDWR, &ehdr); + + if (fd == -1) + { + perror ("elf_open"); + return 1; + } + + if (0 != elf_find_dynamic_section(fd, &ehdr, &phdr)) + { + perror("found no dynamic section"); + return 1; + } + + dyns = malloc(phdr.p_memsz); + if (dyns == NULL) + { + perror ("allocating memory for dynamic section"); + return 1; + } + memset(dyns, 0, phdr.p_memsz); + if (lseek(fd, phdr.p_offset, SEEK_SET) == -1 + || read(fd, dyns, phdr.p_filesz) != (int)phdr.p_filesz) + { + perror ("reading dynamic section"); + return 1; + } + + dynpos = 0; + for (i = 0; dyns[i].d_tag != DT_NULL; i++) + { + dyns[dynpos] = dyns[i]; + if ( ! elf_dynpath_tag(dyns[i].d_tag) ) + dynpos++; + } + for (; dynpos < i; dynpos++) + dyns[dynpos].d_tag = DT_NULL; + + if (lseek(fd, phdr.p_offset, SEEK_SET) == -1 + || write(fd, dyns, phdr.p_filesz) != (int)phdr.p_filesz) + { + perror ("writing dynamic section"); + return 1; + } + + elf_close(fd); + + return 0; +} +/* + * Author: Petter Reinholdtsen + * date: 2001-01-20 + * + * Alter ELF rpath information (insert, modify, remove). + * + * Based on source from Peeter Joot and Geoffrey + * Keating . + */ + +#ifdef HAVE_CONFIG_H +//# include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif +//#include "protos.h" + +#ifdef HAVE_GETOPT_LONG +# define GETOPT_LONG getopt_long + +static struct option long_options[] = +{ + {"convert", 0, 0, 'c'}, + {"delete", 0, 0, 'd'}, + {"help", 0, 0, 'h'}, + {"keepgoing", 0, 0, 'k'}, + {"list", 0, 0, 'l'}, + {"replace", 1, 0, 'r'}, + {"version", 0, 0, 'v'} +}; + +#else /* not HAVE_GETOPT_LONG */ +# define GETOPT_LONG(argc,argv,optstr,lopts,lidx) getopt(argc,argv,optstr) +#endif /* not HAVE_GETOPT_LONG */ + +static void +usage(char *progname) +{ + printf("Usage: %s [-v|-d|-c|-r ] [ ...]\n\n", + progname); + printf(" -v|--version Display program version number\n"); + printf(" -d|--delete Delete current rpath/runpath setting\n"); +#if defined(DT_RUNPATH) + printf(" -c|--convert Convert rpath to runpath\n"); +#endif /* DT_RUNPATH */ + printf(" -r |--replace Replace current rpath/runpath setting\n"); + printf(" with the path given\n"); + printf(" -l|--list List the current rpath/runpath (default)\n"); + printf(" -h|--help Show this usage information.\n"); +#ifndef HAVE_GETOPT_LONG + printf("\n *** The long options are not available on this platform"); +#endif /* not HAVE_GETOPT_LONG */ +#if !defined(DT_RUNPATH) + printf("\n *** There is no support for runpath on this platform"); +#endif /* DT_RUNPATH */ + printf("\n"); +} + +int +main(int argc, char * const argv[]) +{ + int retval = 0; + int convert = 0; /* convert to given type */ + int remove = 0; /* remove or not */ + int keep_going = 0; /* Break on first error, or keep going? */ + char *newpath = NULL; /* insert this path */ + int opt; +#ifdef HAVE_GETOPT_LONG + int option_index = 0; +#endif /* HAVE_GETOPT_LONG */ + + if (argc < 2) + { + usage(argv[0]); + return 1; + } + + do { + opt = GETOPT_LONG(argc, argv, "cdhklr:v", long_options, &option_index); + switch (opt) + { +#if defined(DT_RUNPATH) + case 'c': + convert = 1; + break; +#endif /* DT_RUNPATH */ + case 'd': + remove = 1; + break; + case 'k': + keep_going = 1; + break; + case 'r': + newpath = optarg; + break; + case 'v': + printf("%s version %s\n", PACKAGE, VERSION); + exit(0); + break; + case 'l': /* This is the default action */ + newpath = NULL; + break; + case -1: + break; + default: + printf("Invalid argument '%c'\n", opt); + case 'h': + usage(argv[0]); + exit(0); + break; + } + } while (-1 != opt); + + while (optind < argc && (!retval || keep_going)) + { + if (remove) + retval |= killrpath(argv[optind++]); + else + /* list by default, replace if path is set */ + retval |= chrpath(argv[optind++], newpath, convert); + } + + return retval; +} diff --git a/src/chrpath_linux.c b/src/chrpath_linux.c deleted file mode 100644 index 000244a..0000000 --- a/src/chrpath_linux.c +++ /dev/null @@ -1,769 +0,0 @@ -/*************************************************************************** - * * - * This is a pre-configured single file version of chrpath for linux. * - * It is used in the binary installer for OpenSCAD on Linux. * - * * - * This file has been created by running * - * cat *.h *.c | sed 's, *# *include *",//&,' > ../chrpath_linux.c * - * in the configured chrpath-0.13 source directory (as found in the debian * - * package repository as the original download site seams to be down). * - * * - * chrpath is licensed under the terms of GPLv2: * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program 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 General Public License for more details. * - * * - * The Authors are: * - * * - * Geoffrey Keating * - * Implemented first version of chrpath.c based on first version of * - * killrpath. * - * Peeter Joot * - * Implemented first version of killrpath.c. * - * Petter Reinholdtsen * - * Collected both implementations and made userfriendly wrapper. * - * * - * With patches from: * - * * - * Darren Salt * - * David Hull * - * Bradford W. Johnson * - * Thomas Anders * - * Tollef Fog Heen * - * * - ***************************************************************************/ - - -/* config.h. Generated by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if you have the header file. */ -#define HAVE_ELF_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_GETOPT_H 1 - -/* Define to 1 if you have the `getopt_long' function. */ -#define HAVE_GETOPT_LONG 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LINK_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_LINK_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Name of package */ -#define PACKAGE "chrpath" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "pere@hungry.com" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME ""chrpath"" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING ""chrpath" "0.13"" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "-chrpath-" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION ""0.13"" - -/* The size of a `void *', as computed by sizeof. */ -#define SIZEOF_VOID_P 4 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -#define VERSION "0.13" - -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -/* #undef WORDS_BIGENDIAN */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ -#ifndef PROTOS_H -#define PROTOS_H - -#include -//#include "config.h" - -#ifdef WORDS_BIGENDIAN -#define ELFDATA2 ELFDATA2MSB -#else -#define ELFDATA2 ELFDATA2LSB -#endif -#if SIZEOF_VOID_P == 8 -#define Elf_Ehdr Elf64_Ehdr -#define ELFCLASS ELFCLASS64 -#define Elf_Phdr Elf64_Phdr -#define Elf_Shdr Elf64_Shdr -#define Elf_Dyn Elf64_Dyn -#elif SIZEOF_VOID_P == 4 -#define Elf_Ehdr Elf32_Ehdr -#define ELFCLASS ELFCLASS32 -#define Elf_Phdr Elf32_Phdr -#define Elf_Shdr Elf32_Shdr -#define Elf_Dyn Elf32_Dyn -#else -#error "Unknown word size (SIZEOF_VOID_P)!" -#endif - -int killrpath(const char *filename); -int chrpath(const char *filename, const char *newpath, int convert); - -int elf_open(const char *filename, int flags, Elf_Ehdr *ehdr); -void elf_close(int fd); -int elf_find_dynamic_section(int fd, Elf_Ehdr *ehdr, Elf_Phdr *phdr); -const char *elf_tagname(int tag); -int elf_dynpath_tag(int tag); - -#endif /* PROTOS_H */ -/* - - -Re: changing embedded RPATH in existing executables. - - To: geoffk@ozemail.com.au - Subject: Re: changing embedded RPATH in existing executables. - From: (peeter joot) - Date: Fri, 30 Apr 1999 16:14:44 -0400 (EDT) - Cc: peeterj@ca.ibm.com, egcs@cygnus.com, libc-hacker@cygnus.com, linux-gcc@vger.rutgers.edu - Reply-To: - -> _Changing_ is a little tricky, but the attached program strips rpaths -> from executables (I find it essential for debugging the binutils). -> It's endian-dependent, if you want this for x86 you can just change -> the occurrences of 'MSB' to 'LSB' and compile (I should really fix -> that). - -Hi Geoff, - -With your program as a guide (and some peeks into libbfd, elf.h, a bit -of the glibc dynamic loader code, objdump, and a hex-editor) I was able to -figure out enough to find and change the rpath string. That was fun! - -This program assumes (unlike your original program) that there is only -one DT_RPATH tag in the dynamic section as even with multiple '-Wl,-rpath,' -commands in the link this seems to occur (they all get concatonated into -a : separated path). - -Thanks for your help. If you want to use this on non-x86 you have to change -the occurances of LSB back to MSB:) - -Peeter --- -*/ - -#ifdef HAVE_CONFIG_H -//# include "config.h" -#endif - -#include -#include -#include -#include -#if defined(HAVE_LINK_H) -# include -#endif /* HAVE_LINK_H */ -#include -#include -#include -//#include "protos.h" - -/** - * Reads an ELF file, and reads or alters the RPATH setting. - * - * TODO: - * modify to add RPATH setting if none exists. - */ - - -int -chrpath(const char *filename, const char *newpath, int convert) -{ - int fd; - Elf_Ehdr ehdr; - int i; - Elf_Phdr phdr; - Elf_Shdr shdr; - Elf_Dyn *dyns; - int rpathoff; - char * strtab; - char * rpath; - unsigned int rpathlen; - int oflags; - int rpath_dyns_index; - - if (NULL == newpath && 0 == convert) - oflags = O_RDONLY; - else - oflags = O_RDWR; - - fd = elf_open(filename, oflags, &ehdr); - if (fd == -1) - { - perror ("elf_open"); - return 1; - } - - if (0 != elf_find_dynamic_section(fd, &ehdr, &phdr)) - { - perror("found no dynamic section"); - return 1; - } - - dyns = malloc(phdr.p_filesz); - if (dyns == NULL) - { - perror ("allocating memory for dynamic section"); - return 1; - } - memset(dyns, 0, phdr.p_filesz); - if (lseek(fd, phdr.p_offset, SEEK_SET) == -1 - || read(fd, dyns, phdr.p_filesz) != (int)phdr.p_filesz) - { - perror ("reading dynamic section"); - free(dyns); - return 1; - } - - rpathoff = -1; - for ( rpath_dyns_index = 0; dyns[rpath_dyns_index].d_tag != DT_NULL; - ++rpath_dyns_index ) - { - if ( elf_dynpath_tag(dyns[rpath_dyns_index].d_tag) ) - { - rpathoff = dyns[rpath_dyns_index].d_un.d_ptr; - break; - } - } - if (rpathoff == -1) - { - printf("%s: no rpath or runpath tag found.\n", filename); - free(dyns); - return 2; - } - - if (lseek(fd, ehdr.e_shoff, SEEK_SET) == -1) - { - perror ("positioning for sections"); - free(dyns); - return 1; - } - - for (i = 0; i < ehdr.e_shnum; i++) - { - if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr)) - { - perror ("reading section header"); - free(dyns); - return 1; - } - if (shdr.sh_type == SHT_STRTAB) - break; - } - if (i == ehdr.e_shnum) - { - fprintf (stderr, "No string table found.\n"); - free(dyns); - return 2; - } - strtab = (char *)malloc(shdr.sh_size); - if (strtab == NULL) - { - perror ("allocating memory for string table"); - free(dyns); - return 1; - } - memset(strtab, 0, shdr.sh_size); - - if (lseek(fd, shdr.sh_offset, SEEK_SET) == -1) - { - perror ("positioning for string table"); - free(strtab); - free(dyns); - return 1; - } - if (read(fd, strtab, shdr.sh_size) != (int)shdr.sh_size) - { - perror ("reading string table"); - free(strtab); - free(dyns); - return 1; - } - - if ((int)shdr.sh_size < rpathoff) - { - fprintf(stderr, "%s string offset not contained in string table", - elf_tagname(dyns[rpath_dyns_index].d_tag)); - free(strtab); - free(dyns); - return 5; - } - rpath = strtab+rpathoff; - -#if defined(DT_RUNPATH) - if (convert && dyns[rpath_dyns_index].d_tag == DT_RPATH) - { - dyns[rpath_dyns_index].d_tag = DT_RUNPATH; - if (lseek(fd, phdr.p_offset, SEEK_SET) == -1 - || write(fd, dyns, phdr.p_filesz) != (int)phdr.p_filesz) - { - perror ("converting RPATH to RUNPATH"); - return 1; - } - printf("%s: RPATH converted to RUNPATH\n", filename); - } -#endif /* DT_RUNPATH */ - - printf("%s: %s=%s\n", filename, elf_tagname(dyns[rpath_dyns_index].d_tag), - rpath); - - if (NULL == newpath) - { - free(dyns); - free(strtab); - return 0; - } - - rpathlen = strlen(rpath); - - /* - * Calculate the maximum rpath length (will be equal to rpathlen unless - * we have previously truncated it). - */ - for ( i = rpathoff + rpathlen ; (i < (int)shdr.sh_size - && strtab[i] == '\0') ; i++ ) - ; - i--; - - if (i > (int)(rpathoff + rpathlen)) - rpathlen = i - rpathoff; - - if (strlen(newpath) > rpathlen) - { - fprintf(stderr, "new rpath '%s' too large; maximum length %i\n", - newpath, rpathlen); - free(dyns); - free(strtab); - return 7; - } - - memset(rpath, 0, rpathlen); - strcpy(rpath, newpath); - - if (lseek(fd, shdr.sh_offset+rpathoff, SEEK_SET) == -1) - { - perror ("positioning for RPATH"); - free(dyns); - free(strtab); - return 1; - } - if (write(fd, rpath, rpathlen) != (int)rpathlen) - { - perror ("writing RPATH"); - free(dyns); - free(strtab); - return 1; - } - printf("%s: new %s: %s\n", filename, - elf_tagname(dyns[rpath_dyns_index].d_tag), rpath); - - elf_close(fd); - - free(dyns); - dyns = NULL; - - free(strtab); - - return 0; -} - -#ifdef HAVE_CONFIG_H -//# include "config.h" -#endif - -#include -#if defined(HAVE_SYS_LINK_H) -# include /* Find DT_RPATH on Solaris 2.6 */ -#endif /* HAVE_SYS_LINK_H */ -#include -#include -#include -#include -#include -#include -#include -//#include "protos.h" - -int -elf_open(const char *filename, int flags, Elf_Ehdr *ehdr) -{ - int fd; - - fd = open(filename, flags); - if (fd == -1) - { - perror ("open"); - return -1; - } - - if (read(fd, ehdr, sizeof(*ehdr)) != sizeof(*ehdr)) - { - perror ("reading header"); - close(fd); - return -1; - } - - if (0 != memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || - ehdr->e_ident[EI_CLASS] != ELFCLASS || - ehdr->e_ident[EI_DATA] != ELFDATA2 || - ehdr->e_ident[EI_VERSION] != EV_CURRENT) - { - fprintf(stderr, -#ifdef WORDS_BIGENDIAN - "`%s' probably isn't a %d-bit MSB-first ELF file.\n", -#else /* not WORD_BIGENDIAN */ - "`%s' probably isn't a %d-bit LSB-first ELF file.\n", -#endif /* not WORD_BIGENDIAN */ - filename, SIZEOF_VOID_P * 8); - close(fd); - errno = ENOEXEC; /* Hm, is this the best errno code to use? */ - return -1; - } - - if (ehdr->e_phentsize != sizeof(Elf_Phdr)) - { - fprintf(stderr, "section size was read as %d, not %d!\n", - ehdr->e_phentsize, sizeof(Elf_Phdr)); - close(fd); - return -1; - } - return fd; -} - -int -elf_find_dynamic_section(int fd, Elf_Ehdr *ehdr, Elf_Phdr *phdr) -{ - int i; - if (lseek(fd, ehdr->e_phoff, SEEK_SET) == -1) - { - perror ("positioning for sections"); - return 1; - } - - for (i = 0; i < ehdr->e_phnum; i++) - { - if (read(fd, phdr, sizeof(*phdr)) != sizeof(*phdr)) - { - perror ("reading section header"); - return 1; - } - if (phdr->p_type == PT_DYNAMIC) - break; - } - if (i == ehdr->e_phnum) - { - fprintf (stderr, "No dynamic section found.\n"); - return 2; - } - - if (0 == phdr->p_filesz) - { - fprintf (stderr, "Length of dynamic section is zero.\n"); - return 3; - } - - return 0; -} - -void -elf_close(int fd) -{ - close(fd); -} - -const char * -elf_tagname(int tag) -{ - switch (tag) { - case DT_RPATH: - return "RPATH"; - break; -#if defined(DT_RUNPATH) - case DT_RUNPATH: - return "RUNPATH"; - break; -#endif /* DT_RUNPATH */ - } - return "UNKNOWN"; -} - -int -elf_dynpath_tag(int tag) -{ - return ( tag == DT_RPATH -#if defined(DT_RUNPATH) - || tag == DT_RUNPATH -#endif /* DT_RUNPATH */ - ); -} -/* -Taken from another list: - -_Changing_ is a little tricky, but the attached program strips rpaths -from executables (I find it essential for debugging the binutils). -It's endian-dependent, if you want this for x86 you can just change -the occurrences of 'MSB' to 'LSB' and compile (I should really fix -that). - --- -Geoffrey Keating -*/ - -#ifdef HAVE_CONFIG_H -//# include "config.h" -#endif - -#include -#include -#include -#include -#if defined(HAVE_LINK_H) -# include -#endif /* HAVE_LINK_H */ -#include -//#include "protos.h" -#include - -/* Reads an ELF file, nukes all the RPATH entries. */ - -int -killrpath(const char *filename) -{ - int fd; - Elf_Ehdr ehdr; - int i; - Elf_Phdr phdr; - Elf_Dyn *dyns; - int dynpos; - - fd = elf_open(filename, O_RDWR, &ehdr); - - if (fd == -1) - { - perror ("elf_open"); - return 1; - } - - if (0 != elf_find_dynamic_section(fd, &ehdr, &phdr)) - { - perror("found no dynamic section"); - return 1; - } - - dyns = malloc(phdr.p_memsz); - if (dyns == NULL) - { - perror ("allocating memory for dynamic section"); - return 1; - } - memset(dyns, 0, phdr.p_memsz); - if (lseek(fd, phdr.p_offset, SEEK_SET) == -1 - || read(fd, dyns, phdr.p_filesz) != (int)phdr.p_filesz) - { - perror ("reading dynamic section"); - return 1; - } - - dynpos = 0; - for (i = 0; dyns[i].d_tag != DT_NULL; i++) - { - dyns[dynpos] = dyns[i]; - if ( ! elf_dynpath_tag(dyns[i].d_tag) ) - dynpos++; - } - for (; dynpos < i; dynpos++) - dyns[dynpos].d_tag = DT_NULL; - - if (lseek(fd, phdr.p_offset, SEEK_SET) == -1 - || write(fd, dyns, phdr.p_filesz) != (int)phdr.p_filesz) - { - perror ("writing dynamic section"); - return 1; - } - - elf_close(fd); - - return 0; -} -/* - * Author: Petter Reinholdtsen - * date: 2001-01-20 - * - * Alter ELF rpath information (insert, modify, remove). - * - * Based on source from Peeter Joot and Geoffrey - * Keating . - */ - -#ifdef HAVE_CONFIG_H -//# include "config.h" -#endif - -#include -#include -#include -#ifdef HAVE_GETOPT_H -#include -#endif -//#include "protos.h" - -#ifdef HAVE_GETOPT_LONG -# define GETOPT_LONG getopt_long - -static struct option long_options[] = -{ - {"convert", 0, 0, 'c'}, - {"delete", 0, 0, 'd'}, - {"help", 0, 0, 'h'}, - {"keepgoing", 0, 0, 'k'}, - {"list", 0, 0, 'l'}, - {"replace", 1, 0, 'r'}, - {"version", 0, 0, 'v'} -}; - -#else /* not HAVE_GETOPT_LONG */ -# define GETOPT_LONG(argc,argv,optstr,lopts,lidx) getopt(argc,argv,optstr) -#endif /* not HAVE_GETOPT_LONG */ - -static void -usage(char *progname) -{ - printf("Usage: %s [-v|-d|-c|-r ] [ ...]\n\n", - progname); - printf(" -v|--version Display program version number\n"); - printf(" -d|--delete Delete current rpath/runpath setting\n"); -#if defined(DT_RUNPATH) - printf(" -c|--convert Convert rpath to runpath\n"); -#endif /* DT_RUNPATH */ - printf(" -r |--replace Replace current rpath/runpath setting\n"); - printf(" with the path given\n"); - printf(" -l|--list List the current rpath/runpath (default)\n"); - printf(" -h|--help Show this usage information.\n"); -#ifndef HAVE_GETOPT_LONG - printf("\n *** The long options are not available on this platform"); -#endif /* not HAVE_GETOPT_LONG */ -#if !defined(DT_RUNPATH) - printf("\n *** There is no support for runpath on this platform"); -#endif /* DT_RUNPATH */ - printf("\n"); -} - -int -main(int argc, char * const argv[]) -{ - int retval = 0; - int convert = 0; /* convert to given type */ - int remove = 0; /* remove or not */ - int keep_going = 0; /* Break on first error, or keep going? */ - char *newpath = NULL; /* insert this path */ - int opt; -#ifdef HAVE_GETOPT_LONG - int option_index = 0; -#endif /* HAVE_GETOPT_LONG */ - - if (argc < 2) - { - usage(argv[0]); - return 1; - } - - do { - opt = GETOPT_LONG(argc, argv, "cdhklr:v", long_options, &option_index); - switch (opt) - { -#if defined(DT_RUNPATH) - case 'c': - convert = 1; - break; -#endif /* DT_RUNPATH */ - case 'd': - remove = 1; - break; - case 'k': - keep_going = 1; - break; - case 'r': - newpath = optarg; - break; - case 'v': - printf("%s version %s\n", PACKAGE, VERSION); - exit(0); - break; - case 'l': /* This is the default action */ - newpath = NULL; - break; - case -1: - break; - default: - printf("Invalid argument '%c'\n", opt); - case 'h': - usage(argv[0]); - exit(0); - break; - } - } while (-1 != opt); - - while (optind < argc && (!retval || keep_going)) - { - if (remove) - retval |= killrpath(argv[optind++]); - else - /* list by default, replace if path is set */ - retval |= chrpath(argv[optind++], newpath, convert); - } - - return retval; -} -- cgit v0.10.1