1 /* Compress or decompress an ELF file.
2 Copyright (C) 2015, 2016, 2018 Red Hat, Inc.
3 This file is part of elfutils.
4
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 elfutils is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
18 #include <config.h>
19 #include <assert.h>
20 #include <argp.h>
21 #include <stdbool.h>
22 #include <stdlib.h>
23 #include <inttypes.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <locale.h>
27 #include <fcntl.h>
28 #include <fnmatch.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include ELFUTILS_HEADER(elf)
33 #include ELFUTILS_HEADER(ebl)
34 #include ELFUTILS_HEADER(dwelf)
35 #include <gelf.h>
36 #include "system.h"
37 #include "libeu.h"
38 #include "printversion.h"
39
40 /* Name and version of program. */
41 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
42
43 /* Bug report address. */
44 ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
45
46 static int verbose = 0; /* < 0, no warnings, > 0 extra verbosity. */
47 static bool force = false;
48 static bool permissive = false;
49 static const char *foutput = NULL;
50
51 #define T_UNSET 0
52 #define T_DECOMPRESS 1 /* none */
53 #define T_COMPRESS_ZLIB 2 /* zlib */
54 #define T_COMPRESS_GNU 3 /* zlib-gnu */
55 #define WORD_BITS (8U * sizeof (unsigned int))
56
57 static int type = T_UNSET;
58
59 struct section_pattern
60 {
61 char *pattern;
62 struct section_pattern *next;
63 };
64
65 static struct section_pattern *patterns = NULL;
66
67 static void
add_pattern(const char * pattern)68 add_pattern (const char *pattern)
69 {
70 struct section_pattern *p = xmalloc (sizeof *p);
71 p->pattern = xstrdup (pattern);
72 p->next = patterns;
73 patterns = p;
74 }
75
76 static void
free_patterns(void)77 free_patterns (void)
78 {
79 struct section_pattern *pattern = patterns;
80 while (pattern != NULL)
81 {
82 struct section_pattern *p = pattern;
83 pattern = p->next;
84 free (p->pattern);
85 free (p);
86 }
87 }
88
89 static error_t
parse_opt(int key,char * arg,struct argp_state * state)90 parse_opt (int key, char *arg __attribute__ ((unused)),
91 struct argp_state *state __attribute__ ((unused)))
92 {
93 switch (key)
94 {
95 case 'v':
96 verbose++;
97 break;
98
99 case 'q':
100 verbose--;
101 break;
102
103 case 'f':
104 force = true;
105 break;
106
107 case 'p':
108 permissive = true;
109 break;
110
111 case 'n':
112 add_pattern (arg);
113 break;
114
115 case 'o':
116 if (foutput != NULL)
117 argp_error (state, N_("-o option specified twice"));
118 else
119 foutput = arg;
120 break;
121
122 case 't':
123 if (type != T_UNSET)
124 argp_error (state, N_("-t option specified twice"));
125
126 if (strcmp ("none", arg) == 0)
127 type = T_DECOMPRESS;
128 else if (strcmp ("zlib", arg) == 0 || strcmp ("zlib-gabi", arg) == 0)
129 type = T_COMPRESS_ZLIB;
130 else if (strcmp ("zlib-gnu", arg) == 0 || strcmp ("gnu", arg) == 0)
131 type = T_COMPRESS_GNU;
132 else
133 argp_error (state, N_("unknown compression type '%s'"), arg);
134 break;
135
136 case ARGP_KEY_SUCCESS:
137 if (type == T_UNSET)
138 type = T_COMPRESS_ZLIB;
139 if (patterns == NULL)
140 add_pattern (".?(z)debug*");
141 break;
142
143 case ARGP_KEY_NO_ARGS:
144 /* We need at least one input file. */
145 argp_error (state, N_("No input file given"));
146 break;
147
148 case ARGP_KEY_ARGS:
149 if (foutput != NULL && state->argc - state->next > 1)
150 argp_error (state,
151 N_("Only one input file allowed together with '-o'"));
152 /* We only use this for checking the number of arguments, we don't
153 actually want to consume them. */
154 FALLTHROUGH;
155 default:
156 return ARGP_ERR_UNKNOWN;
157 }
158 return 0;
159 }
160
161 static bool
section_name_matches(const char * name)162 section_name_matches (const char *name)
163 {
164 struct section_pattern *pattern = patterns;
165 while (pattern != NULL)
166 {
167 if (fnmatch (pattern->pattern, name, FNM_EXTMATCH) == 0)
168 return true;
169 pattern = pattern->next;
170 }
171 return false;
172 }
173
174 static int
setshdrstrndx(Elf * elf,GElf_Ehdr * ehdr,size_t ndx)175 setshdrstrndx (Elf *elf, GElf_Ehdr *ehdr, size_t ndx)
176 {
177 if (ndx < SHN_LORESERVE)
178 ehdr->e_shstrndx = ndx;
179 else
180 {
181 ehdr->e_shstrndx = SHN_XINDEX;
182 Elf_Scn *zscn = elf_getscn (elf, 0);
183 GElf_Shdr zshdr_mem;
184 GElf_Shdr *zshdr = gelf_getshdr (zscn, &zshdr_mem);
185 if (zshdr == NULL)
186 return -1;
187 zshdr->sh_link = ndx;
188 if (gelf_update_shdr (zscn, zshdr) == 0)
189 return -1;
190 }
191
192 if (gelf_update_ehdr (elf, ehdr) == 0)
193 return -1;
194
195 return 0;
196 }
197
198 static int
compress_section(Elf_Scn * scn,size_t orig_size,const char * name,const char * newname,size_t ndx,bool gnu,bool compress,bool report_verbose)199 compress_section (Elf_Scn *scn, size_t orig_size, const char *name,
200 const char *newname, size_t ndx,
201 bool gnu, bool compress, bool report_verbose)
202 {
203 int res;
204 unsigned int flags = compress && force ? ELF_CHF_FORCE : 0;
205 if (gnu)
206 res = elf_compress_gnu (scn, compress ? 1 : 0, flags);
207 else
208 res = elf_compress (scn, compress ? ELFCOMPRESS_ZLIB : 0, flags);
209
210 if (res < 0)
211 error (0, 0, "Couldn't decompress section [%zd] %s: %s",
212 ndx, name, elf_errmsg (-1));
213 else
214 {
215 if (compress && res == 0)
216 {
217 if (verbose >= 0)
218 printf ("[%zd] %s NOT compressed, wouldn't be smaller\n",
219 ndx, name);
220 }
221
222 if (report_verbose && res > 0)
223 {
224 printf ("[%zd] %s %s", ndx, name,
225 compress ? "compressed" : "decompressed");
226 if (newname != NULL)
227 printf (" -> %s", newname);
228
229 /* Reload shdr, it has changed. */
230 GElf_Shdr shdr_mem;
231 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
232 if (shdr == NULL)
233 {
234 error (0, 0, "Couldn't get shdr for section [%zd]", ndx);
235 return -1;
236 }
237 float new = shdr->sh_size;
238 float orig = orig_size ?: 1;
239 printf (" (%zu => %" PRIu64 " %.2f%%)\n",
240 orig_size, shdr->sh_size, (new / orig) * 100);
241 }
242 }
243
244 return res;
245 }
246
247 static void
set_section(unsigned int * sections,size_t ndx)248 set_section (unsigned int *sections, size_t ndx)
249 {
250 sections[ndx / WORD_BITS] |= (1U << (ndx % WORD_BITS));
251 }
252
253 static bool
get_section(unsigned int * sections,size_t ndx)254 get_section (unsigned int *sections, size_t ndx)
255 {
256 return (sections[ndx / WORD_BITS] & (1U << (ndx % WORD_BITS))) != 0;
257 }
258
259 /* How many sections are we going to change? */
260 static size_t
get_sections(unsigned int * sections,size_t shnum)261 get_sections (unsigned int *sections, size_t shnum)
262 {
263 size_t s = 0;
264 for (size_t i = 0; i < shnum / WORD_BITS + 1; i++)
265 s += __builtin_popcount (sections[i]);
266 return s;
267 }
268
269 static int
process_file(const char * fname)270 process_file (const char *fname)
271 {
272 if (verbose > 0)
273 printf ("processing: %s\n", fname);
274
275 /* The input ELF. */
276 int fd = -1;
277 Elf *elf = NULL;
278
279 /* The output ELF. */
280 char *fnew = NULL;
281 int fdnew = -1;
282 Elf *elfnew = NULL;
283
284 /* Buffer for (one) new section name if necessary. */
285 char *snamebuf = NULL;
286
287 /* String table (and symbol table), if section names need adjusting. */
288 Dwelf_Strtab *names = NULL;
289 Dwelf_Strent **scnstrents = NULL;
290 Dwelf_Strent **symstrents = NULL;
291 char **scnnames = NULL;
292
293 /* Section data from names. */
294 void *namesbuf = NULL;
295
296 /* Which sections match and need to be (un)compressed. */
297 unsigned int *sections = NULL;
298
299 /* How many sections are we talking about? */
300 size_t shnum = 0;
301 int res = 1;
302
303 fd = open (fname, O_RDONLY);
304 if (fd < 0)
305 {
306 error (0, errno, "Couldn't open %s\n", fname);
307 goto cleanup;
308 }
309
310 elf = elf_begin (fd, ELF_C_READ, NULL);
311 if (elf == NULL)
312 {
313 error (0, 0, "Couldn't open ELF file %s for reading: %s",
314 fname, elf_errmsg (-1));
315 goto cleanup;
316 }
317
318 /* We don't handle ar files (or anything else), we probably should. */
319 Elf_Kind kind = elf_kind (elf);
320 if (kind != ELF_K_ELF)
321 {
322 if (kind == ELF_K_AR)
323 error (0, 0, "Cannot handle ar files: %s", fname);
324 else
325 error (0, 0, "Unknown file type: %s", fname);
326 goto cleanup;
327 }
328
329 struct stat st;
330 if (fstat (fd, &st) != 0)
331 {
332 error (0, errno, "Couldn't fstat %s", fname);
333 goto cleanup;
334 }
335
336 GElf_Ehdr ehdr;
337 if (gelf_getehdr (elf, &ehdr) == NULL)
338 {
339 error (0, 0, "Couldn't get ehdr for %s: %s", fname, elf_errmsg (-1));
340 goto cleanup;
341 }
342
343 /* Get the section header string table. */
344 size_t shdrstrndx;
345 if (elf_getshdrstrndx (elf, &shdrstrndx) != 0)
346 {
347 error (0, 0, "Couldn't get section header string table index in %s: %s",
348 fname, elf_errmsg (-1));
349 goto cleanup;
350 }
351
352 /* How many sections are we talking about? */
353 if (elf_getshdrnum (elf, &shnum) != 0)
354 {
355 error (0, 0, "Couldn't get number of sections in %s: %s",
356 fname, elf_errmsg (1));
357 goto cleanup;
358 }
359
360 if (shnum == 0)
361 {
362 error (0, 0, "ELF file %s has no sections", fname);
363 goto cleanup;
364 }
365
366 sections = xcalloc (shnum / 8 + 1, sizeof (unsigned int));
367
368 size_t phnum;
369 if (elf_getphdrnum (elf, &phnum) != 0)
370 {
371 error (0, 0, "Couldn't get phdrnum: %s", elf_errmsg (-1));
372 goto cleanup;
373 }
374
375 /* Whether we need to adjust any section names (going to/from GNU
376 naming). If so we'll need to build a new section header string
377 table. */
378 bool adjust_names = false;
379
380 /* If there are phdrs we want to maintain the layout of the
381 allocated sections in the file. */
382 bool layout = phnum != 0;
383
384 /* While going through all sections keep track of last section data
385 offset if needed to keep the layout. We are responsible for
386 adding the section offsets and headers (e_shoff) in that case
387 (which we will place after the last section). */
388 GElf_Off last_offset = 0;
389 if (layout)
390 last_offset = (ehdr.e_phoff
391 + gelf_fsize (elf, ELF_T_PHDR, phnum, EV_CURRENT));
392
393 /* Which section, if any, is a symbol table that shares a string
394 table with the section header string table? */
395 size_t symtabndx = 0;
396
397 /* We do three passes over all sections.
398
399 First an inspection pass over the old Elf to see which section
400 data needs to be copied and/or transformed, which sections need a
401 names change and whether there is a symbol table that might need
402 to be adjusted be if the section header name table is changed.
403
404 If nothing needs changing, and the input and output file are the
405 same, we are done.
406
407 Second a collection pass that creates the Elf sections and copies
408 the data. This pass will compress/decompress section data when
409 needed. And it will collect all data needed if we'll need to
410 construct a new string table. Afterwards the new string table is
411 constructed.
412
413 Third a fixup/adjustment pass over the new Elf that will adjust
414 any section references (names) and adjust the layout based on the
415 new sizes of the sections if necessary. This pass is optional if
416 we aren't responsible for the layout and the section header
417 string table hasn't been changed. */
418
419 /* Inspection pass. */
420 size_t maxnamelen = 0;
421 Elf_Scn *scn = NULL;
422 while ((scn = elf_nextscn (elf, scn)) != NULL)
423 {
424 size_t ndx = elf_ndxscn (scn);
425 if (ndx > shnum)
426 {
427 error (0, 0, "Unexpected section number %zd, expected only %zd",
428 ndx, shnum);
429 goto cleanup;
430 }
431
432 GElf_Shdr shdr_mem;
433 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
434 if (shdr == NULL)
435 {
436 error (0, 0, "Couldn't get shdr for section %zd", ndx);
437 goto cleanup;
438 }
439
440 const char *sname = elf_strptr (elf, shdrstrndx, shdr->sh_name);
441 if (sname == NULL)
442 {
443 error (0, 0, "Couldn't get name for section %zd", ndx);
444 goto cleanup;
445 }
446
447 if (section_name_matches (sname))
448 {
449 if (!force && type == T_DECOMPRESS
450 && (shdr->sh_flags & SHF_COMPRESSED) == 0
451 && !startswith (sname, ".zdebug"))
452 {
453 if (verbose > 0)
454 printf ("[%zd] %s already decompressed\n", ndx, sname);
455 }
456 else if (!force && type == T_COMPRESS_ZLIB
457 && (shdr->sh_flags & SHF_COMPRESSED) != 0)
458 {
459 if (verbose > 0)
460 printf ("[%zd] %s already compressed\n", ndx, sname);
461 }
462 else if (!force && type == T_COMPRESS_GNU
463 && startswith (sname, ".zdebug"))
464 {
465 if (verbose > 0)
466 printf ("[%zd] %s already GNU compressed\n", ndx, sname);
467 }
468 else if (shdr->sh_type != SHT_NOBITS
469 && (shdr->sh_flags & SHF_ALLOC) == 0)
470 {
471 set_section (sections, ndx);
472 /* Check if we might want to change this section name. */
473 if (! adjust_names
474 && ((type != T_COMPRESS_GNU
475 && startswith (sname, ".zdebug"))
476 || (type == T_COMPRESS_GNU
477 && startswith (sname, ".debug"))))
478 adjust_names = true;
479
480 /* We need a buffer this large if we change the names. */
481 if (adjust_names)
482 {
483 size_t slen = strlen (sname);
484 if (slen > maxnamelen)
485 maxnamelen = slen;
486 }
487 }
488 else
489 if (verbose >= 0)
490 printf ("[%zd] %s ignoring %s section\n", ndx, sname,
491 (shdr->sh_type == SHT_NOBITS ? "no bits" : "allocated"));
492 }
493
494 if (shdr->sh_type == SHT_SYMTAB)
495 {
496 /* Check if we might have to adjust the symbol name indexes. */
497 if (shdr->sh_link == shdrstrndx)
498 {
499 if (symtabndx != 0)
500 {
501 error (0, 0,
502 "Multiple symbol tables (%zd, %zd) using the same string table unsupported", symtabndx, ndx);
503 goto cleanup;
504 }
505 symtabndx = ndx;
506 }
507 }
508
509 /* Keep track of last allocated data offset. */
510 if (layout)
511 if ((shdr->sh_flags & SHF_ALLOC) != 0)
512 {
513 GElf_Off off = shdr->sh_offset + (shdr->sh_type != SHT_NOBITS
514 ? shdr->sh_size : 0);
515 if (last_offset < off)
516 last_offset = off;
517 }
518 }
519
520 if (foutput == NULL && get_sections (sections, shnum) == 0)
521 {
522 if (verbose > 0)
523 printf ("Nothing to do.\n");
524 res = 0;
525 goto cleanup;
526 }
527
528 if (adjust_names)
529 {
530 names = dwelf_strtab_init (true);
531 if (names == NULL)
532 {
533 error (0, 0, "Not enough memory for new strtab");
534 goto cleanup;
535 }
536 scnstrents = xmalloc (shnum
537 * sizeof (Dwelf_Strent *));
538 scnnames = xcalloc (shnum, sizeof (char *));
539 }
540
541 /* Create a new (temporary) ELF file for the result. */
542 if (foutput == NULL)
543 {
544 size_t fname_len = strlen (fname);
545 fnew = xmalloc (fname_len + sizeof (".XXXXXX"));
546 strcpy (mempcpy (fnew, fname, fname_len), ".XXXXXX");
547 fdnew = mkstemp (fnew);
548 }
549 else
550 {
551 fnew = xstrdup (foutput);
552 fdnew = open (fnew, O_WRONLY | O_CREAT, st.st_mode & ALLPERMS);
553 }
554
555 if (fdnew < 0)
556 {
557 error (0, errno, "Couldn't create output file %s", fnew);
558 /* Since we didn't create it we don't want to try to unlink it. */
559 free (fnew);
560 fnew = NULL;
561 goto cleanup;
562 }
563
564 elfnew = elf_begin (fdnew, ELF_C_WRITE, NULL);
565 if (elfnew == NULL)
566 {
567 error (0, 0, "Couldn't open new ELF %s for writing: %s",
568 fnew, elf_errmsg (-1));
569 goto cleanup;
570 }
571
572 /* Create the new ELF header and copy over all the data. */
573 if (gelf_newehdr (elfnew, gelf_getclass (elf)) == 0)
574 {
575 error (0, 0, "Couldn't create new ehdr: %s", elf_errmsg (-1));
576 goto cleanup;
577 }
578
579 GElf_Ehdr newehdr;
580 if (gelf_getehdr (elfnew, &newehdr) == NULL)
581 {
582 error (0, 0, "Couldn't get new ehdr: %s", elf_errmsg (-1));
583 goto cleanup;
584 }
585
586 newehdr.e_ident[EI_DATA] = ehdr.e_ident[EI_DATA];
587 newehdr.e_type = ehdr.e_type;
588 newehdr.e_machine = ehdr.e_machine;
589 newehdr.e_version = ehdr.e_version;
590 newehdr.e_entry = ehdr.e_entry;
591 newehdr.e_flags = ehdr.e_flags;
592
593 if (gelf_update_ehdr (elfnew, &newehdr) == 0)
594 {
595 error (0, 0, "Couldn't update ehdr: %s", elf_errmsg (-1));
596 goto cleanup;
597 }
598
599 /* Copy over the phdrs as is. */
600 if (phnum != 0)
601 {
602 if (gelf_newphdr (elfnew, phnum) == 0)
603 {
604 error (0, 0, "Couldn't create phdrs: %s", elf_errmsg (-1));
605 goto cleanup;
606 }
607
608 for (size_t cnt = 0; cnt < phnum; ++cnt)
609 {
610 GElf_Phdr phdr_mem;
611 GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
612 if (phdr == NULL)
613 {
614 error (0, 0, "Couldn't get phdr %zd: %s", cnt, elf_errmsg (-1));
615 goto cleanup;
616 }
617 if (gelf_update_phdr (elfnew, cnt, phdr) == 0)
618 {
619 error (0, 0, "Couldn't create phdr %zd: %s", cnt,
620 elf_errmsg (-1));
621 goto cleanup;
622 }
623 }
624 }
625
626 /* Possibly add a 'z' and zero terminator. */
627 if (maxnamelen > 0)
628 snamebuf = xmalloc (maxnamelen + 2);
629
630 /* We might want to read/adjust the section header strings and
631 symbol tables. If so, and those sections are to be compressed
632 then we will have to decompress it during the collection pass and
633 compress it again in the fixup pass. Don't compress unnecessary
634 and keep track of whether or not to compress them (later in the
635 fixup pass). Also record the original size, so we can report the
636 difference later when we do compress. */
637 int shstrtab_compressed = T_UNSET;
638 size_t shstrtab_size = 0;
639 char *shstrtab_name = NULL;
640 char *shstrtab_newname = NULL;
641 int symtab_compressed = T_UNSET;
642 size_t symtab_size = 0;
643 char *symtab_name = NULL;
644 char *symtab_newname = NULL;
645
646 /* Collection pass. Copy over the sections, (de)compresses matching
647 sections, collect names of sections and symbol table if
648 necessary. */
649 scn = NULL;
650 while ((scn = elf_nextscn (elf, scn)) != NULL)
651 {
652 size_t ndx = elf_ndxscn (scn);
653 assert (ndx < shnum);
654
655 /* (de)compress if section matched. */
656 char *sname = NULL;
657 char *newname = NULL;
658 if (get_section (sections, ndx))
659 {
660 GElf_Shdr shdr_mem;
661 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
662 if (shdr == NULL)
663 {
664 error (0, 0, "Couldn't get shdr for section %zd", ndx);
665 goto cleanup;
666 }
667
668 uint64_t size = shdr->sh_size;
669 sname = elf_strptr (elf, shdrstrndx, shdr->sh_name);
670 if (sname == NULL)
671 {
672 error (0, 0, "Couldn't get name for section %zd", ndx);
673 goto cleanup;
674 }
675
676 /* strdup sname, the shdrstrndx section itself might be
677 (de)compressed, invalidating the string pointers. */
678 sname = xstrdup (sname);
679
680 /* We might want to decompress (and rename), but not
681 compress during this pass since we might need the section
682 data in later passes. Skip those sections for now and
683 compress them in the fixup pass. */
684 bool skip_compress_section = (adjust_names
685 && (ndx == shdrstrndx
686 || ndx == symtabndx));
687
688 switch (type)
689 {
690 case T_DECOMPRESS:
691 if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
692 {
693 if (compress_section (scn, size, sname, NULL, ndx,
694 false, false, verbose > 0) < 0)
695 goto cleanup;
696 }
697 else if (startswith (sname, ".zdebug"))
698 {
699 snamebuf[0] = '.';
700 strcpy (&snamebuf[1], &sname[2]);
701 newname = snamebuf;
702 if (compress_section (scn, size, sname, newname, ndx,
703 true, false, verbose > 0) < 0)
704 goto cleanup;
705 }
706 else if (verbose > 0)
707 printf ("[%zd] %s already decompressed\n", ndx, sname);
708 break;
709
710 case T_COMPRESS_GNU:
711 if (startswith (sname, ".debug"))
712 {
713 if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
714 {
715 /* First decompress to recompress GNU style.
716 Don't report even when verbose. */
717 if (compress_section (scn, size, sname, NULL, ndx,
718 false, false, false) < 0)
719 goto cleanup;
720 }
721
722 snamebuf[0] = '.';
723 snamebuf[1] = 'z';
724 strcpy (&snamebuf[2], &sname[1]);
725 newname = snamebuf;
726
727 if (skip_compress_section)
728 {
729 if (ndx == shdrstrndx)
730 {
731 shstrtab_size = size;
732 shstrtab_compressed = T_COMPRESS_GNU;
733 if (shstrtab_name != NULL
734 || shstrtab_newname != NULL)
735 {
736 error (0, 0, "Internal error,"
737 " shstrtab_name already set,"
738 " while handling section [%zd] %s",
739 ndx, sname);
740 goto cleanup;
741 }
742 shstrtab_name = xstrdup (sname);
743 shstrtab_newname = xstrdup (newname);
744 }
745 else
746 {
747 symtab_size = size;
748 symtab_compressed = T_COMPRESS_GNU;
749 symtab_name = xstrdup (sname);
750 symtab_newname = xstrdup (newname);
751 }
752 }
753 else
754 {
755 int result = compress_section (scn, size, sname, newname,
756 ndx, true, true,
757 verbose > 0);
758 if (result < 0)
759 goto cleanup;
760
761 if (result == 0)
762 newname = NULL;
763 }
764 }
765 else if (verbose >= 0)
766 {
767 if (startswith (sname, ".zdebug"))
768 printf ("[%zd] %s unchanged, already GNU compressed",
769 ndx, sname);
770 else
771 printf ("[%zd] %s cannot GNU compress section not starting with .debug\n",
772 ndx, sname);
773 }
774 break;
775
776 case T_COMPRESS_ZLIB:
777 if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
778 {
779 if (startswith (sname, ".zdebug"))
780 {
781 /* First decompress to recompress zlib style.
782 Don't report even when verbose. */
783 if (compress_section (scn, size, sname, NULL, ndx,
784 true, false, false) < 0)
785 goto cleanup;
786
787 snamebuf[0] = '.';
788 strcpy (&snamebuf[1], &sname[2]);
789 newname = snamebuf;
790 }
791
792 if (skip_compress_section)
793 {
794 if (ndx == shdrstrndx)
795 {
796 shstrtab_size = size;
797 shstrtab_compressed = T_COMPRESS_ZLIB;
798 if (shstrtab_name != NULL
799 || shstrtab_newname != NULL)
800 {
801 error (0, 0, "Internal error,"
802 " shstrtab_name already set,"
803 " while handling section [%zd] %s",
804 ndx, sname);
805 goto cleanup;
806 }
807 shstrtab_name = xstrdup (sname);
808 shstrtab_newname = (newname == NULL
809 ? NULL : xstrdup (newname));
810 }
811 else
812 {
813 symtab_size = size;
814 symtab_compressed = T_COMPRESS_ZLIB;
815 symtab_name = xstrdup (sname);
816 symtab_newname = (newname == NULL
817 ? NULL : xstrdup (newname));
818 }
819 }
820 else if (compress_section (scn, size, sname, newname, ndx,
821 false, true, verbose > 0) < 0)
822 goto cleanup;
823 }
824 else if (verbose > 0)
825 printf ("[%zd] %s already compressed\n", ndx, sname);
826 break;
827 }
828
829 free (sname);
830 }
831
832 Elf_Scn *newscn = elf_newscn (elfnew);
833 if (newscn == NULL)
834 {
835 error (0, 0, "Couldn't create new section %zd", ndx);
836 goto cleanup;
837 }
838
839 GElf_Shdr shdr_mem;
840 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
841 if (shdr == NULL)
842 {
843 error (0, 0, "Couldn't get shdr for section %zd", ndx);
844 goto cleanup;
845 }
846
847 if (gelf_update_shdr (newscn, shdr) == 0)
848 {
849 error (0, 0, "Couldn't update section header %zd", ndx);
850 goto cleanup;
851 }
852
853 /* Except for the section header string table all data can be
854 copied as is. The section header string table will be
855 created later and the symbol table might be fixed up if
856 necessary. */
857 if (! adjust_names || ndx != shdrstrndx)
858 {
859 Elf_Data *data = elf_getdata (scn, NULL);
860 if (data == NULL)
861 {
862 error (0, 0, "Couldn't get data from section %zd", ndx);
863 goto cleanup;
864 }
865
866 Elf_Data *newdata = elf_newdata (newscn);
867 if (newdata == NULL)
868 {
869 error (0, 0, "Couldn't create new data for section %zd", ndx);
870 goto cleanup;
871 }
872
873 *newdata = *data;
874 }
875
876 /* Keep track of the (new) section names. */
877 if (adjust_names)
878 {
879 char *name;
880 if (newname != NULL)
881 name = newname;
882 else
883 {
884 name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
885 if (name == NULL)
886 {
887 error (0, 0, "Couldn't get name for section [%zd]", ndx);
888 goto cleanup;
889 }
890 }
891
892 /* We need to keep a copy of the name till the strtab is done. */
893 name = scnnames[ndx] = xstrdup (name);
894 if ((scnstrents[ndx] = dwelf_strtab_add (names, name)) == NULL)
895 {
896 error (0, 0, "No memory to add section name string table");
897 goto cleanup;
898 }
899
900 /* If the symtab shares strings then add those too. */
901 if (ndx == symtabndx)
902 {
903 /* If the section is (still) compressed we'll need to
904 uncompress it first to adjust the data, then
905 recompress it in the fixup pass. */
906 if (symtab_compressed == T_UNSET)
907 {
908 size_t size = shdr->sh_size;
909 if ((shdr->sh_flags == SHF_COMPRESSED) != 0)
910 {
911 /* Don't report the (internal) uncompression. */
912 if (compress_section (newscn, size, sname, NULL, ndx,
913 false, false, false) < 0)
914 goto cleanup;
915
916 symtab_size = size;
917 symtab_compressed = T_COMPRESS_ZLIB;
918 }
919 else if (startswith (name, ".zdebug"))
920 {
921 /* Don't report the (internal) uncompression. */
922 if (compress_section (newscn, size, sname, NULL, ndx,
923 true, false, false) < 0)
924 goto cleanup;
925
926 symtab_size = size;
927 symtab_compressed = T_COMPRESS_GNU;
928 }
929 }
930
931 Elf_Data *symd = elf_getdata (newscn, NULL);
932 if (symd == NULL)
933 {
934 error (0, 0, "Couldn't get symtab data for section [%zd] %s",
935 ndx, name);
936 goto cleanup;
937 }
938 size_t elsize = gelf_fsize (elfnew, ELF_T_SYM, 1, EV_CURRENT);
939 size_t syms = symd->d_size / elsize;
940 if (symstrents != NULL)
941 {
942 error (0, 0, "Internal error, symstrents already set,"
943 " while handling section [%zd] %s", ndx, name);
944 goto cleanup;
945 }
946 symstrents = xmalloc (syms * sizeof (Dwelf_Strent *));
947 for (size_t i = 0; i < syms; i++)
948 {
949 GElf_Sym sym_mem;
950 GElf_Sym *sym = gelf_getsym (symd, i, &sym_mem);
951 if (sym == NULL)
952 {
953 error (0, 0, "Couldn't get symbol %zd", i);
954 goto cleanup;
955 }
956 if (sym->st_name != 0)
957 {
958 /* Note we take the name from the original ELF,
959 since the new one will not have setup the
960 strtab yet. */
961 const char *symname = elf_strptr (elf, shdrstrndx,
962 sym->st_name);
963 if (symname == NULL)
964 {
965 error (0, 0, "Couldn't get symbol %zd name", i);
966 goto cleanup;
967 }
968 symstrents[i] = dwelf_strtab_add (names, symname);
969 if (symstrents[i] == NULL)
970 {
971 error (0, 0, "No memory to add to symbol name");
972 goto cleanup;
973 }
974 }
975 }
976 }
977 }
978 }
979
980 if (adjust_names)
981 {
982 /* We got all needed strings, put the new data in the shstrtab. */
983 if (verbose > 0)
984 printf ("[%zd] Updating section string table\n", shdrstrndx);
985
986 scn = elf_getscn (elfnew, shdrstrndx);
987 if (scn == NULL)
988 {
989 error (0, 0, "Couldn't get new section header string table [%zd]",
990 shdrstrndx);
991 goto cleanup;
992 }
993
994 Elf_Data *data = elf_newdata (scn);
995 if (data == NULL)
996 {
997 error (0, 0, "Couldn't create new section header string table data");
998 goto cleanup;
999 }
1000 if (dwelf_strtab_finalize (names, data) == NULL)
1001 {
1002 error (0, 0, "Not enough memory to create string table");
1003 goto cleanup;
1004 }
1005 namesbuf = data->d_buf;
1006
1007 GElf_Shdr shdr_mem;
1008 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1009 if (shdr == NULL)
1010 {
1011 error (0, 0, "Couldn't get shdr for new section strings %zd",
1012 shdrstrndx);
1013 goto cleanup;
1014 }
1015
1016 /* Note that we also might have to compress and possibly set
1017 sh_off below */
1018 shdr->sh_name = dwelf_strent_off (scnstrents[shdrstrndx]);
1019 shdr->sh_type = SHT_STRTAB;
1020 shdr->sh_flags = 0;
1021 shdr->sh_addr = 0;
1022 shdr->sh_offset = 0;
1023 shdr->sh_size = data->d_size;
1024 shdr->sh_link = SHN_UNDEF;
1025 shdr->sh_info = SHN_UNDEF;
1026 shdr->sh_addralign = 1;
1027 shdr->sh_entsize = 0;
1028
1029 if (gelf_update_shdr (scn, shdr) == 0)
1030 {
1031 error (0, 0, "Couldn't update new section strings [%zd]",
1032 shdrstrndx);
1033 goto cleanup;
1034 }
1035
1036 /* We might have to compress the data if the user asked us to,
1037 or if the section was already compressed (and the user didn't
1038 ask for decompression). Note somewhat identical code for
1039 symtab below. */
1040 if (shstrtab_compressed == T_UNSET)
1041 {
1042 /* The user didn't ask for compression, but maybe it was
1043 compressed in the original ELF file. */
1044 Elf_Scn *oldscn = elf_getscn (elf, shdrstrndx);
1045 if (oldscn == NULL)
1046 {
1047 error (0, 0, "Couldn't get section header string table [%zd]",
1048 shdrstrndx);
1049 goto cleanup;
1050 }
1051
1052 shdr = gelf_getshdr (oldscn, &shdr_mem);
1053 if (shdr == NULL)
1054 {
1055 error (0, 0, "Couldn't get shdr for old section strings [%zd]",
1056 shdrstrndx);
1057 goto cleanup;
1058 }
1059
1060 shstrtab_name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
1061 if (shstrtab_name == NULL)
1062 {
1063 error (0, 0, "Couldn't get name for old section strings [%zd]",
1064 shdrstrndx);
1065 goto cleanup;
1066 }
1067
1068 shstrtab_size = shdr->sh_size;
1069 if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
1070 shstrtab_compressed = T_COMPRESS_ZLIB;
1071 else if (startswith (shstrtab_name, ".zdebug"))
1072 shstrtab_compressed = T_COMPRESS_GNU;
1073 }
1074
1075 /* Should we (re)compress? */
1076 if (shstrtab_compressed != T_UNSET)
1077 {
1078 if (compress_section (scn, shstrtab_size, shstrtab_name,
1079 shstrtab_newname, shdrstrndx,
1080 shstrtab_compressed == T_COMPRESS_GNU,
1081 true, verbose > 0) < 0)
1082 goto cleanup;
1083 }
1084 }
1085
1086 /* Make sure to re-get the new ehdr. Adding phdrs and shdrs will
1087 have changed it. */
1088 if (gelf_getehdr (elfnew, &newehdr) == NULL)
1089 {
1090 error (0, 0, "Couldn't re-get new ehdr: %s", elf_errmsg (-1));
1091 goto cleanup;
1092 }
1093
1094 /* Set this after the sections have been created, otherwise section
1095 zero might not exist yet. */
1096 if (setshdrstrndx (elfnew, &newehdr, shdrstrndx) != 0)
1097 {
1098 error (0, 0, "Couldn't set new shdrstrndx: %s", elf_errmsg (-1));
1099 goto cleanup;
1100 }
1101
1102 /* Fixup pass. Adjust string table references, symbol table and
1103 layout if necessary. */
1104 if (layout || adjust_names)
1105 {
1106 scn = NULL;
1107 while ((scn = elf_nextscn (elfnew, scn)) != NULL)
1108 {
1109 size_t ndx = elf_ndxscn (scn);
1110
1111 GElf_Shdr shdr_mem;
1112 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1113 if (shdr == NULL)
1114 {
1115 error (0, 0, "Couldn't get shdr for section %zd", ndx);
1116 goto cleanup;
1117 }
1118
1119 /* Keep the offset of allocated sections so they are at the
1120 same place in the file. Add (possibly changed)
1121 unallocated ones after the allocated ones. */
1122 if ((shdr->sh_flags & SHF_ALLOC) == 0)
1123 {
1124 /* Zero means one. No alignment constraints. */
1125 size_t addralign = shdr->sh_addralign ?: 1;
1126 last_offset = (last_offset + addralign - 1) & ~(addralign - 1);
1127 shdr->sh_offset = last_offset;
1128 if (shdr->sh_type != SHT_NOBITS)
1129 last_offset += shdr->sh_size;
1130 }
1131
1132 if (adjust_names)
1133 shdr->sh_name = dwelf_strent_off (scnstrents[ndx]);
1134
1135 if (gelf_update_shdr (scn, shdr) == 0)
1136 {
1137 error (0, 0, "Couldn't update section header %zd", ndx);
1138 goto cleanup;
1139 }
1140
1141 if (adjust_names && ndx == symtabndx)
1142 {
1143 if (verbose > 0)
1144 printf ("[%zd] Updating symbol table\n", symtabndx);
1145
1146 Elf_Data *symd = elf_getdata (scn, NULL);
1147 if (symd == NULL)
1148 {
1149 error (0, 0, "Couldn't get new symtab data section [%zd]",
1150 ndx);
1151 goto cleanup;
1152 }
1153 size_t elsize = gelf_fsize (elfnew, ELF_T_SYM, 1, EV_CURRENT);
1154 size_t syms = symd->d_size / elsize;
1155 for (size_t i = 0; i < syms; i++)
1156 {
1157 GElf_Sym sym_mem;
1158 GElf_Sym *sym = gelf_getsym (symd, i, &sym_mem);
1159 if (sym == NULL)
1160 {
1161 error (0, 0, "2 Couldn't get symbol %zd", i);
1162 goto cleanup;
1163 }
1164
1165 if (sym->st_name != 0)
1166 {
1167 sym->st_name = dwelf_strent_off (symstrents[i]);
1168
1169 if (gelf_update_sym (symd, i, sym) == 0)
1170 {
1171 error (0, 0, "Couldn't update symbol %zd", i);
1172 goto cleanup;
1173 }
1174 }
1175 }
1176
1177 /* We might have to compress the data if the user asked
1178 us to, or if the section was already compressed (and
1179 the user didn't ask for decompression). Note
1180 somewhat identical code for shstrtab above. */
1181 if (symtab_compressed == T_UNSET)
1182 {
1183 /* The user didn't ask for compression, but maybe it was
1184 compressed in the original ELF file. */
1185 Elf_Scn *oldscn = elf_getscn (elf, symtabndx);
1186 if (oldscn == NULL)
1187 {
1188 error (0, 0, "Couldn't get symbol table [%zd]",
1189 symtabndx);
1190 goto cleanup;
1191 }
1192
1193 shdr = gelf_getshdr (oldscn, &shdr_mem);
1194 if (shdr == NULL)
1195 {
1196 error (0, 0, "Couldn't get old symbol table shdr [%zd]",
1197 symtabndx);
1198 goto cleanup;
1199 }
1200
1201 symtab_name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
1202 if (symtab_name == NULL)
1203 {
1204 error (0, 0, "Couldn't get old symbol table name [%zd]",
1205 symtabndx);
1206 goto cleanup;
1207 }
1208
1209 symtab_size = shdr->sh_size;
1210 if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
1211 symtab_compressed = T_COMPRESS_ZLIB;
1212 else if (startswith (symtab_name, ".zdebug"))
1213 symtab_compressed = T_COMPRESS_GNU;
1214 }
1215
1216 /* Should we (re)compress? */
1217 if (symtab_compressed != T_UNSET)
1218 {
1219 if (compress_section (scn, symtab_size, symtab_name,
1220 symtab_newname, symtabndx,
1221 symtab_compressed == T_COMPRESS_GNU,
1222 true, verbose > 0) < 0)
1223 goto cleanup;
1224 }
1225 }
1226 }
1227 }
1228
1229 /* If we have phdrs we want elf_update to layout the SHF_ALLOC
1230 sections precisely as in the original file. In that case we are
1231 also responsible for setting phoff and shoff */
1232 if (layout)
1233 {
1234 if (gelf_getehdr (elfnew, &newehdr) == NULL)
1235 {
1236 error (0, 0, "Couldn't get ehdr: %s", elf_errmsg (-1));
1237 goto cleanup;
1238 }
1239
1240 /* Position the shdrs after the last (unallocated) section. */
1241 const size_t offsize = gelf_fsize (elfnew, ELF_T_OFF, 1, EV_CURRENT);
1242 newehdr.e_shoff = ((last_offset + offsize - 1)
1243 & ~((GElf_Off) (offsize - 1)));
1244
1245 /* The phdrs go in the same place as in the original file.
1246 Normally right after the ELF header. */
1247 newehdr.e_phoff = ehdr.e_phoff;
1248
1249 if (gelf_update_ehdr (elfnew, &newehdr) == 0)
1250 {
1251 error (0, 0, "Couldn't update ehdr: %s", elf_errmsg (-1));
1252 goto cleanup;
1253 }
1254 }
1255
1256 elf_flagelf (elfnew, ELF_C_SET, ((layout ? ELF_F_LAYOUT : 0)
1257 | (permissive ? ELF_F_PERMISSIVE : 0)));
1258
1259 if (elf_update (elfnew, ELF_C_WRITE) < 0)
1260 {
1261 error (0, 0, "Couldn't write %s: %s", fnew, elf_errmsg (-1));
1262 goto cleanup;
1263 }
1264
1265 elf_end (elfnew);
1266 elfnew = NULL;
1267
1268 /* Try to match mode and owner.group of the original file.
1269 Note to set suid bits we have to make sure the owner is setup
1270 correctly first. Otherwise fchmod will drop them silently
1271 or fchown may clear them. */
1272 if (fchown (fdnew, st.st_uid, st.st_gid) != 0)
1273 if (verbose >= 0)
1274 error (0, errno, "Couldn't fchown %s", fnew);
1275 if (fchmod (fdnew, st.st_mode & ALLPERMS) != 0)
1276 if (verbose >= 0)
1277 error (0, errno, "Couldn't fchmod %s", fnew);
1278
1279 /* Finally replace the old file with the new file. */
1280 if (foutput == NULL)
1281 if (rename (fnew, fname) != 0)
1282 {
1283 error (0, errno, "Couldn't rename %s to %s", fnew, fname);
1284 goto cleanup;
1285 }
1286
1287 /* We are finally done with the new file, don't unlink it now. */
1288 free (fnew);
1289 fnew = NULL;
1290 res = 0;
1291
1292 cleanup:
1293 elf_end (elf);
1294 close (fd);
1295
1296 elf_end (elfnew);
1297 close (fdnew);
1298
1299 if (fnew != NULL)
1300 {
1301 unlink (fnew);
1302 free (fnew);
1303 fnew = NULL;
1304 }
1305
1306 free (snamebuf);
1307 if (names != NULL)
1308 {
1309 dwelf_strtab_free (names);
1310 free (scnstrents);
1311 free (symstrents);
1312 free (namesbuf);
1313 if (scnnames != NULL)
1314 {
1315 for (size_t n = 0; n < shnum; n++)
1316 free (scnnames[n]);
1317 free (scnnames);
1318 }
1319 }
1320
1321 free (sections);
1322 return res;
1323 }
1324
1325 int
main(int argc,char ** argv)1326 main (int argc, char **argv)
1327 {
1328 const struct argp_option options[] =
1329 {
1330 { "output", 'o', "FILE", 0,
1331 N_("Place (de)compressed output into FILE"),
1332 0 },
1333 { "type", 't', "TYPE", 0,
1334 N_("What type of compression to apply. TYPE can be 'none' (decompress), 'zlib' (ELF ZLIB compression, the default, 'zlib-gabi' is an alias) or 'zlib-gnu' (.zdebug GNU style compression, 'gnu' is an alias)"),
1335 0 },
1336 { "name", 'n', "SECTION", 0,
1337 N_("SECTION name to (de)compress, SECTION is an extended wildcard pattern (defaults to '.?(z)debug*')"),
1338 0 },
1339 { "verbose", 'v', NULL, 0,
1340 N_("Print a message for each section being (de)compressed"),
1341 0 },
1342 { "force", 'f', NULL, 0,
1343 N_("Force compression of section even if it would become larger or update/rewrite the file even if no section would be (de)compressed"),
1344 0 },
1345 { "permissive", 'p', NULL, 0,
1346 N_("Relax a few rules to handle slightly broken ELF files"),
1347 0 },
1348 { "quiet", 'q', NULL, 0,
1349 N_("Be silent when a section cannot be compressed"),
1350 0 },
1351 { NULL, 0, NULL, 0, NULL, 0 }
1352 };
1353
1354 const struct argp argp =
1355 {
1356 .options = options,
1357 .parser = parse_opt,
1358 .args_doc = N_("FILE..."),
1359 .doc = N_("Compress or decompress sections in an ELF file.")
1360 };
1361
1362 int remaining;
1363 if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0)
1364 return EXIT_FAILURE;
1365
1366 /* Should already be handled by ARGP_KEY_NO_ARGS case above,
1367 just sanity check. */
1368 if (remaining >= argc)
1369 error_exit (0, N_("No input file given"));
1370
1371 /* Likewise for the ARGP_KEY_ARGS case above, an extra sanity check. */
1372 if (foutput != NULL && remaining + 1 < argc)
1373 error_exit (0, N_("Only one input file allowed together with '-o'"));
1374
1375 elf_version (EV_CURRENT);
1376
1377 /* Process all the remaining files. */
1378 int result = 0;
1379 do
1380 result |= process_file (argv[remaining]);
1381 while (++remaining < argc);
1382
1383 free_patterns ();
1384 return result;
1385 }
1386