dpdk: Add support for Mellanox ConnectX-4 devices
[vpp.git] / vppinfra / tools / elftool.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16   Copyright (c) 2008 Eliot Dresselhaus
17
18   Permission is hereby granted, free of charge, to any person obtaining
19   a copy of this software and associated documentation files (the
20   "Software"), to deal in the Software without restriction, including
21   without limitation the rights to use, copy, modify, merge, publish,
22   distribute, sublicense, and/or sell copies of the Software, and to
23   permit persons to whom the Software is furnished to do so, subject to
24   the following conditions:
25
26   The above copyright notice and this permission notice shall be
27   included in all copies or substantial portions of the Software.
28
29   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 */
37
38 #include <vppinfra/elf.h>
39
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43
44 #ifndef CLIB_UNIX
45 #error "unix only"
46 #endif
47
48 typedef struct {
49   elf_main_t elf_main;
50   char * input_file;
51   char * output_file;
52   char * set_interpreter;
53   char * set_rpath;
54   int unset_rpath;
55   int verbose;
56   int quiet;
57   int allow_elf_shared;
58   /* for use in the optimized / simplified case */
59   u64 file_size;
60   u64 interpreter_offset;
61   u64 rpath_offset;
62 } elf_tool_main_t;
63
64 static clib_error_t * elf_set_interpreter (elf_main_t * em, 
65                                            elf_tool_main_t * tm)
66 {
67   elf_segment_t * g;
68   elf_section_t * s;
69   clib_error_t * error;
70   char * interp = tm->set_interpreter;
71
72   switch (em->first_header.file_type)
73     {
74     case ELF_EXEC:
75       break;
76
77     case ELF_SHARED:
78       if (tm->allow_elf_shared)
79         break;
80       /* Note flowthrough */
81     default:
82       return clib_error_return (0, "unacceptable file_type");    
83     }
84
85   vec_foreach (g, em->segments)
86     {
87       if (g->header.type == ELF_SEGMENT_INTERP)
88         break;
89     }
90
91   if (g >= vec_end (em->segments))
92     return clib_error_return (0, "interpreter not found");
93
94   if (g->header.memory_size < 1 + strlen (interp))
95     return clib_error_return (0, "given interpreter does not fit; must be less than %d bytes (`%s' given)",
96                               g->header.memory_size, interp);
97
98   error = elf_get_section_by_start_address (em, g->header.virtual_address, &s);
99   if (error)
100     return error;
101
102   /* Put in new null terminated string. */
103   memset (s->contents, 0, vec_len (s->contents));
104   clib_memcpy (s->contents, interp, strlen (interp));
105
106   return 0;
107 }
108
109 static void
110 delete_rpath_for_section (elf_main_t * em, elf_section_t * s)
111 {
112   elf64_dynamic_entry_t * e;
113   elf64_dynamic_entry_t * new_es = 0;
114
115   vec_foreach (e, em->dynamic_entries)
116     {
117       switch (e->type)
118         {
119         case ELF_DYNAMIC_ENTRY_RPATH:
120         case ELF_DYNAMIC_ENTRY_RUN_PATH:
121           break;
122
123         default:
124           vec_add1 (new_es, e[0]);
125           break;
126         }
127     }
128
129   /* Pad so as to keep section size constant. */
130   {
131     elf64_dynamic_entry_t e_end;
132     e_end.type = ELF_DYNAMIC_ENTRY_END;
133     e_end.data = 0;
134     while (vec_len (new_es) < vec_len (em->dynamic_entries))
135       vec_add1 (new_es, e_end);
136   }
137
138   vec_free (em->dynamic_entries);
139   em->dynamic_entries = new_es;
140
141   elf_set_dynamic_entries (em);
142 }
143
144 static void delete_rpath (elf_main_t * em)
145 {
146   elf_section_t * s;
147
148   vec_foreach (s, em->sections)
149     {
150       switch (s->header.type)
151         {
152         case ELF_SECTION_DYNAMIC:
153           delete_rpath_for_section (em, s);
154           break;
155
156         default:
157           break;
158         }
159     }
160 }
161
162 static clib_error_t *
163 set_rpath_for_section (elf_main_t * em, elf_section_t * s, char * new_rpath)
164 {
165   elf64_dynamic_entry_t * e;
166   char * old_rpath;
167   int old_len, new_len = strlen (new_rpath);
168   u8 * new_string_table = vec_dup (em->dynamic_string_table);
169
170   vec_foreach (e, em->dynamic_entries)
171     {
172       switch (e->type)
173         {
174         case ELF_DYNAMIC_ENTRY_RPATH:
175         case ELF_DYNAMIC_ENTRY_RUN_PATH:
176           old_rpath = (char *) new_string_table + e->data;
177           old_len = strlen (old_rpath);
178           if (old_len < new_len)
179             return clib_error_return (0, "rpath of `%s' does not fit (old rpath `%s')",
180                                       new_rpath, old_rpath);
181           strcpy (old_rpath, new_rpath);
182           break;
183
184         default:
185           break;
186         }
187     }
188
189   elf_set_section_contents (em, em->dynamic_string_table_section_index,
190                             new_string_table,
191                             vec_bytes (new_string_table));
192
193   return 0;
194 }
195
196 static clib_error_t *
197 set_rpath (elf_main_t * em, char * rpath)
198 {
199   clib_error_t * error = 0;
200   elf_section_t * s;
201
202   vec_foreach (s, em->sections)
203     {
204       switch (s->header.type)
205         {
206         case ELF_SECTION_DYNAMIC:
207           error = set_rpath_for_section (em, s, rpath);
208           if (error)
209             return error;
210           break;
211
212         default:
213           break;
214         }
215     }
216
217   return error;
218 }
219
220 static clib_error_t *
221 set_interpreter_rpath (elf_tool_main_t * tm)
222 {
223   int ifd = -1, ofd = -1;
224   struct stat fd_stat;
225   u8 *idp = 0;                  /* warning be gone */
226   u64 mmap_length = 0, i;
227   u32 run_length;
228   u8 in_run;
229   u64 offset0 = 0, offset1 = 0;
230   clib_error_t * error = 0;
231   int fix_in_place = 0;
232
233   if (!strcmp (tm->input_file, tm->output_file))
234     fix_in_place = 1;
235
236   ifd = open (tm->input_file, O_RDWR);
237   if (ifd < 0)
238     {
239       error = clib_error_return_unix (0, "open `%s'", tm->input_file);
240       goto done;
241     }
242
243   if (fstat (ifd, &fd_stat) < 0)
244     {
245       error = clib_error_return_unix (0, "fstat `%s'", tm->input_file);
246       goto done;
247     }
248
249   if (!(fd_stat.st_mode & S_IFREG)) 
250     {
251       error = clib_error_return (0, "%s is not a regular file", tm->input_file);
252       goto done;
253     }
254
255   mmap_length = fd_stat.st_size;
256   if (mmap_length < 4)
257     {
258       error = clib_error_return (0, "%s too short", tm->input_file);
259       goto done;
260     }
261
262   /* COW-mapping, since we intend to write the fixups */
263   if (fix_in_place)
264     idp = mmap (0, mmap_length, PROT_READ | PROT_WRITE, MAP_SHARED, 
265               ifd, /* offset */ 0);
266   else
267     idp = mmap (0, mmap_length, PROT_READ | PROT_WRITE, MAP_PRIVATE, 
268               ifd, /* offset */ 0);
269   if (~pointer_to_uword (idp) == 0)
270     {
271       mmap_length = 0;
272       error = clib_error_return_unix (0, "mmap `%s'", tm->input_file);
273       goto done;
274     }
275   
276   if (idp[0] != 0x7f || idp[1] != 'E' || idp[2] != 'L' || idp[3] != 'F')
277     {
278       error = clib_error_return (0, "not an ELF file '%s'", tm->input_file);
279       goto done;
280     }
281
282   in_run = 0;
283   run_length = 0;
284
285   for (i = 0; i < mmap_length; i++)
286     {
287       if (idp[i] == '/')
288         {
289           if (in_run)
290             run_length++;
291           else
292             {
293               in_run = 1;
294               run_length = 1;
295             }
296         }
297       else
298         {
299           if (in_run && run_length >= 16)
300             {
301               if (offset0 == 0)
302                   offset0 = (i - run_length);
303               else if (offset1 == 0)
304                 {
305                   offset1 = (i - run_length);
306                   goto found_both;
307                 }
308             }
309           in_run = 0;
310           run_length = 0;
311         }
312     }
313
314   if (offset0 == 0)
315     {
316       error = clib_error_return (0, "no fixup markers in %s", 
317                                  tm->input_file);
318       goto done;
319     }
320
321  found_both:
322   if (0)
323     clib_warning ("offset0 %lld (0x%llx), offset1 %lld (0x%llx)", 
324                   offset0, offset0, offset1, offset1);
325
326   /* Executable file case */
327   if (offset0 && offset1)
328     {
329       tm->interpreter_offset = offset0;
330       tm->rpath_offset = offset1;
331     }
332   else /* shared library case */                         
333     {
334       tm->interpreter_offset = 0;
335       tm->rpath_offset = offset0;
336     }
337   
338   if (tm->interpreter_offset)
339     clib_memcpy (&idp[tm->interpreter_offset], tm->set_interpreter, 
340             strlen (tm->set_interpreter)+1);
341
342   if (tm->rpath_offset)
343     clib_memcpy (&idp[tm->rpath_offset], tm->set_rpath, 
344             strlen (tm->set_rpath)+1);
345
346   /* Write the output file... */
347   if (fix_in_place == 0)
348     {
349       ofd = open (tm->output_file, O_RDWR | O_CREAT | O_TRUNC, 0644);
350       if (ofd < 0)
351         {
352           error = clib_error_return_unix (0, "create `%s'", tm->output_file);
353           goto done;
354         }
355
356       if (write (ofd, idp, mmap_length) != mmap_length)
357         error = clib_error_return_unix (0, "write `%s'", tm->output_file);
358     }
359
360  done:
361   if (mmap_length > 0 && idp)
362     munmap (idp, mmap_length);
363   if (ifd >= 0)
364     close (ifd);
365   if (ofd >= 0)
366     close (ofd);
367   return error;
368 }
369
370
371 int main (int argc, char * argv[])
372 {
373   elf_tool_main_t _tm, * tm = &_tm;
374   elf_main_t * em = &tm->elf_main;
375   unformat_input_t i;
376   clib_error_t * error = 0;
377
378   memset (tm, 0, sizeof (tm[0]));
379   unformat_init_command_line (&i, argv);
380
381   while (unformat_check_input (&i) != UNFORMAT_END_OF_INPUT)
382     {
383       if (unformat (&i, "in %s", &tm->input_file))
384         ;
385       else if (unformat (&i, "out %s", &tm->output_file))
386         ;
387       else if (unformat (&i, "set-interpreter %s", &tm->set_interpreter))
388         ;
389       else if (unformat (&i, "set-rpath %s", &tm->set_rpath))
390         ;
391       else if (unformat (&i, "unset-rpath"))
392         tm->unset_rpath = 1;
393       else if (unformat (&i, "verbose"))
394         tm->verbose = ~0;
395       else if (unformat (&i, "verbose-symbols"))
396         tm->verbose |= FORMAT_ELF_MAIN_SYMBOLS;
397       else if (unformat (&i, "verbose-relocations"))
398         tm->verbose |= FORMAT_ELF_MAIN_RELOCATIONS;
399       else if (unformat (&i, "verbose-dynamic"))
400         tm->verbose |= FORMAT_ELF_MAIN_DYNAMIC;
401       else if (unformat (&i, "quiet"))
402         tm->quiet = 1;
403       else if (unformat (&i, "allow-elf-shared"))
404         tm->allow_elf_shared = 1;
405       else
406         {
407           error = unformat_parse_error (&i);
408           goto done;
409         }
410     }
411
412   if (! tm->input_file)
413     {
414       error = clib_error_return (0, "no input file");
415       goto done;
416     }
417
418   /* Do the typical case a stone-simple way... */
419   if (tm->quiet && tm->set_interpreter && tm->set_rpath && tm->output_file)
420     {
421       error = set_interpreter_rpath (tm);
422       goto done;
423     }
424
425   error = elf_read_file (em, tm->input_file);
426
427   if (error)
428     goto done;
429
430   if (tm->verbose)
431     fformat (stdout, "%U", format_elf_main, em, tm->verbose);
432
433   if (tm->set_interpreter)
434     {
435       error = elf_set_interpreter (em, tm);
436       if (error)
437         goto done;
438     }
439
440   if (tm->set_rpath)
441     {
442       error = set_rpath (em, tm->set_rpath);
443       if (error)
444         goto done;
445     }
446
447   if (tm->unset_rpath)
448     delete_rpath (em);
449
450   if (tm->output_file)
451     error = elf_write_file (em, tm->output_file);
452
453   elf_main_free (em);
454
455  done:
456   if (error)
457     {
458       if (tm->quiet == 0)
459         clib_error_report (error);
460       return 1;
461     }
462   else
463     return 0;
464 }