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