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