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;
+}

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.