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