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