Mercurial > hg > chrpath
diff chrpath.c @ 1:bbbfb3f97919
implement 32 and 64 bit support
author | Peter Meerwald <p.meerwald@bct-electronic.com> |
---|---|
date | Fri, 20 Jul 2012 11:26:24 +0200 |
parents | b8f7423e385c |
children |
line wrap: on
line diff
--- a/chrpath.c Fri Jul 20 01:51:24 2012 +0200 +++ b/chrpath.c Fri Jul 20 11:26:24 2012 +0200 @@ -58,35 +58,19 @@ */ -int -chrpath(const char *filename, const char *newpath, int convert) -{ - int fd; - Elf_Ehdr ehdr; +static int +chrpath32(int fd, const char *filename, const char *newpath, Elf32_Ehdr *ehdr, int convert) { + Elf32_Phdr phdr; + Elf32_Shdr shdr; + Elf32_Dyn *dyns; 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)) + if (0 != elf32_find_dynamic_section(fd, ehdr, &phdr)) { perror("found no dynamic section"); return 1; @@ -124,14 +108,14 @@ return 2; } - if (lseek(fd, ehdr.e_shoff, SEEK_SET) == -1) + 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++) + for (i = 0; i < ehdr->e_shnum; i++) { if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr)) { @@ -142,7 +126,7 @@ if (shdr.sh_type == SHT_STRTAB) break; } - if (i == ehdr.e_shnum) + if (i == ehdr->e_shnum) { fprintf (stderr, "No string table found.\n"); free(dyns); @@ -258,3 +242,213 @@ return 0; } + +static int +chrpath64(int fd, const char *filename, const char *newpath, Elf64_Ehdr *ehdr, int convert) { + Elf64_Phdr phdr; + Elf64_Shdr shdr; + Elf64_Dyn *dyns; + int i; + int rpathoff; + char * strtab; + char * rpath; + unsigned int rpathlen; + int rpath_dyns_index; + + if (0 != elf64_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; +} + +int +chrpath(const char *filename, const char *newpath, int convert) +{ + int fd; + Elf32_Ehdr ehdr32; + Elf64_Ehdr ehdr64; + int oflags; + + if (NULL == newpath && 0 == convert) + oflags = O_RDONLY; + else + oflags = O_RDWR; + + fd = elf32_open(filename, oflags, &ehdr32); + if (fd >= 0) + return chrpath32(fd, filename, newpath, &ehdr32, convert); + + fd = elf64_open(filename, oflags, &ehdr64); + if (fd >= 0) + return chrpath64(fd, filename, newpath, &ehdr64, convert); + + perror ("elf_open"); + return 1; +}