resetting manifest requested domain to floor
[platform/upstream/chrpath.git] / chrpath.c
1 /*
2 <URL:http://gcc.gnu.org/ml/gcc/1999-04n/msg01105.html>
3
4 Re: changing embedded RPATH in existing executables.
5
6   To: geoffk@ozemail.com.au
7   Subject: Re: changing embedded RPATH in existing executables.
8   From: <peeter_joot@VNET.IBM.COM> (peeter joot)
9   Date: Fri, 30 Apr 1999 16:14:44 -0400 (EDT)
10   Cc: peeterj@ca.ibm.com, egcs@cygnus.com, libc-hacker@cygnus.com, linux-gcc@vger.rutgers.edu
11   Reply-To: <peeter_joot@VNET.IBM.COM>
12
13 > _Changing_ is a little tricky, but the attached program strips rpaths
14 > from executables (I find it essential for debugging the binutils).
15 > It's endian-dependent, if you want this for x86 you can just change
16 > the occurrences of 'MSB' to 'LSB' and compile (I should really fix
17 > that).
18
19 Hi Geoff,
20
21 With your program as a guide (and some peeks into libbfd, elf.h, a bit
22 of the glibc dynamic loader code, objdump, and a hex-editor) I was able to
23 figure out enough to find and change the rpath string.  That was fun!
24
25 This program assumes (unlike your original program) that there is only
26 one DT_RPATH tag in the dynamic section as even with multiple '-Wl,-rpath,'
27 commands in the link this seems to occur (they all get concatonated into
28 a : separated path).
29
30 Thanks for your help.  If you want to use this on non-x86 you have to change
31 the occurances of LSB back to MSB:)
32
33 Peeter
34 --
35 */
36
37 #ifdef HAVE_CONFIG_H
38 #  include "config.h"
39 #endif
40
41 #include <stdio.h>
42 #include <unistd.h>
43 #include <fcntl.h>
44 #include <elf.h>
45 #if defined(HAVE_LINK_H)
46 #  include <link.h>
47 #endif /* HAVE_LINK_H */
48 #include <stdlib.h>
49 #include <string.h>
50 #include <sys/stat.h>
51 #include "protos.h"
52
53 /**
54  * Reads an ELF file, and reads or alters the RPATH setting.
55  *
56  * TODO:
57  *  modify to add RPATH setting if none exists.
58  */
59
60
61 int
62 chrpath(const char *filename, const char *newpath, int convert)
63 {
64   int fd;
65   Elf_Ehdr ehdr;
66   int i;
67   Elf_Phdr phdr;
68   Elf_Shdr shdr;
69   Elf_Dyn *dyns;
70   int rpathoff;
71   char * strtab;
72   char * rpath;
73   unsigned int rpathlen;
74   int oflags;
75   int rpath_dyns_index;
76
77   if (NULL == newpath && 0 == convert)
78      oflags = O_RDONLY;
79   else
80      oflags = O_RDWR;
81
82   fd = elf_open(filename, oflags, &ehdr);
83   if (fd == -1)
84   {
85     perror ("elf_open");
86     return 1;
87   }
88
89    if (0 != elf_find_dynamic_section(fd, &ehdr, &phdr))
90    {
91      perror("found no dynamic section");
92      return 1;
93    }
94
95   dyns = malloc(phdr.p_filesz);
96   if (dyns == NULL)
97     {
98       perror ("allocating memory for dynamic section");
99       return 1;
100     }
101   memset(dyns, 0, phdr.p_filesz);
102   if (lseek(fd, phdr.p_offset, SEEK_SET) == -1
103       || read(fd, dyns, phdr.p_filesz) != (int)phdr.p_filesz)
104     {
105       perror ("reading dynamic section");
106       free(dyns);
107       return 1;
108     }
109
110   rpathoff = -1;
111   for ( rpath_dyns_index = 0; dyns[rpath_dyns_index].d_tag != DT_NULL;
112         ++rpath_dyns_index )
113     {
114       if ( elf_dynpath_tag(dyns[rpath_dyns_index].d_tag) )
115       {
116          rpathoff = dyns[rpath_dyns_index].d_un.d_ptr;
117          break;
118       }
119     }
120   if (rpathoff == -1)
121     {
122       printf("%s: no rpath or runpath tag found.\n", filename);
123       free(dyns);
124       return 2;
125     }
126
127   if (lseek(fd, ehdr.e_shoff, SEEK_SET) == -1)
128   {
129     perror ("positioning for sections");
130     free(dyns);
131     return 1;
132   }
133
134   for (i = 0; i < ehdr.e_shnum; i++)
135   {
136     if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
137     {
138       perror ("reading section header");
139       free(dyns);
140       return 1;
141     }
142     if (shdr.sh_type == SHT_STRTAB)
143       break;
144   }
145   if (i == ehdr.e_shnum)
146     {
147       fprintf (stderr, "No string table found.\n");
148       free(dyns);
149       return 2;
150     }
151   strtab = (char *)malloc(shdr.sh_size);
152   if (strtab == NULL)
153     {
154       perror ("allocating memory for string table");
155       free(dyns);
156       return 1;
157     }
158   memset(strtab, 0, shdr.sh_size);
159
160   if (lseek(fd, shdr.sh_offset, SEEK_SET) == -1)
161   {
162     perror ("positioning for string table");
163     free(strtab);
164     free(dyns);
165     return 1;
166   }
167   if (read(fd, strtab, shdr.sh_size) != (int)shdr.sh_size)
168   {
169     perror ("reading string table");
170     free(strtab);
171     free(dyns);
172     return 1;
173   }
174
175   if ((int)shdr.sh_size < rpathoff)
176   {
177     fprintf(stderr, "%s string offset not contained in string table",
178             elf_tagname(dyns[rpath_dyns_index].d_tag));
179     free(strtab);
180     free(dyns);
181     return 5;
182   }
183   rpath = strtab+rpathoff;
184
185 #if defined(DT_RUNPATH)
186   if (convert && dyns[rpath_dyns_index].d_tag == DT_RPATH)
187   {
188     dyns[rpath_dyns_index].d_tag = DT_RUNPATH;
189     if (lseek(fd, phdr.p_offset, SEEK_SET) == -1
190         || write(fd, dyns, phdr.p_filesz) != (int)phdr.p_filesz)
191     {
192       perror ("converting RPATH to RUNPATH");
193       return 1;
194     }
195     printf("%s: RPATH converted to RUNPATH\n", filename);
196   }
197 #endif /* DT_RUNPATH */
198
199   printf("%s: %s=%s\n", filename, elf_tagname(dyns[rpath_dyns_index].d_tag),
200          rpath);
201
202   if (NULL == newpath)
203   {
204     free(dyns);
205     free(strtab);
206     return 0;
207   }
208
209   rpathlen = strlen(rpath);
210
211   /*
212    * Calculate the maximum rpath length (will be equal to rpathlen unless
213    * we have previously truncated it).
214    */
215   for ( i = rpathoff + rpathlen ; (i < (int)shdr.sh_size
216                                    && strtab[i] == '\0') ; i++ )
217     ;
218   i--;
219
220   if (i > (int)(rpathoff + rpathlen))
221      rpathlen = i - rpathoff;
222
223   if (strlen(newpath) > rpathlen)
224   {
225     fprintf(stderr, "new rpath '%s' too large; maximum length %i\n",
226             newpath, rpathlen);
227     free(dyns);
228     free(strtab);
229     return 7;
230   }
231
232   memset(rpath, 0, rpathlen);
233   strcpy(rpath, newpath);
234
235   if (lseek(fd, shdr.sh_offset+rpathoff, SEEK_SET) == -1)
236   {
237     perror ("positioning for RPATH");
238     free(dyns);
239     free(strtab);
240     return 1;
241   }
242   if (write(fd, rpath, rpathlen) != (int)rpathlen)
243   {
244     perror ("writing RPATH");
245     free(dyns);
246     free(strtab);
247     return 1;
248   }
249   printf("%s: new %s: %s\n", filename,
250          elf_tagname(dyns[rpath_dyns_index].d_tag), rpath);
251
252   elf_close(fd);
253
254   free(dyns);
255   dyns = NULL;
256
257   free(strtab);
258
259   return 0;
260 }