Line data Source code
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
66 144 : add_pattern (const char *pattern)
67 : {
68 144 : struct section_pattern *p = xmalloc (sizeof *p);
69 144 : p->pattern = xstrdup (pattern);
70 144 : p->next = patterns;
71 144 : patterns = p;
72 144 : }
73 :
74 : static void
75 144 : free_patterns (void)
76 : {
77 144 : struct section_pattern *pattern = patterns;
78 432 : while (pattern != NULL)
79 : {
80 144 : struct section_pattern *p = pattern;
81 144 : pattern = p->next;
82 144 : free (p->pattern);
83 144 : free (p);
84 : }
85 144 : }
86 :
87 : static error_t
88 1152 : parse_opt (int key, char *arg __attribute__ ((unused)),
89 : struct argp_state *state __attribute__ ((unused)))
90 : {
91 1152 : switch (key)
92 : {
93 120 : case 'v':
94 120 : verbose++;
95 120 : break;
96 :
97 22 : case 'q':
98 22 : verbose--;
99 22 : break;
100 :
101 23 : case 'f':
102 23 : force = true;
103 23 : break;
104 :
105 0 : case 'p':
106 0 : permissive = true;
107 0 : break;
108 :
109 11 : case 'n':
110 11 : add_pattern (arg);
111 11 : break;
112 :
113 134 : case 'o':
114 134 : if (foutput != NULL)
115 0 : argp_error (state, N_("-o option specified twice"));
116 : else
117 134 : foutput = arg;
118 : break;
119 :
120 122 : case 't':
121 122 : if (type != T_UNSET)
122 0 : argp_error (state, N_("-t option specified twice"));
123 :
124 122 : if (strcmp ("none", arg) == 0)
125 73 : type = T_DECOMPRESS;
126 49 : else if (strcmp ("zlib", arg) == 0 || strcmp ("zlib-gabi", arg) == 0)
127 25 : type = T_COMPRESS_ZLIB;
128 24 : else if (strcmp ("zlib-gnu", arg) == 0 || strcmp ("gnu", arg) == 0)
129 24 : type = T_COMPRESS_GNU;
130 : else
131 0 : argp_error (state, N_("unknown compression type '%s'"), arg);
132 : break;
133 :
134 144 : case ARGP_KEY_SUCCESS:
135 144 : if (type == T_UNSET)
136 22 : type = T_COMPRESS_ZLIB;
137 144 : if (patterns == NULL)
138 133 : add_pattern (".?(z)debug*");
139 : break;
140 :
141 0 : case ARGP_KEY_NO_ARGS:
142 : /* We need at least one input file. */
143 0 : argp_error (state, N_("No input file given"));
144 0 : break;
145 :
146 144 : case ARGP_KEY_ARGS:
147 144 : if (foutput != NULL && state->argc - state->next > 1)
148 0 : 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
160 2967 : section_name_matches (const char *name)
161 : {
162 2967 : struct section_pattern *pattern = patterns;
163 8176 : while (pattern != NULL)
164 : {
165 2967 : if (fnmatch (pattern->pattern, name, FNM_EXTMATCH) == 0)
166 : return true;
167 2242 : pattern = pattern->next;
168 : }
169 : return false;
170 : }
171 :
172 : static int
173 144 : setshdrstrndx (Elf *elf, GElf_Ehdr *ehdr, size_t ndx)
174 : {
175 144 : if (ndx < SHN_LORESERVE)
176 144 : ehdr->e_shstrndx = ndx;
177 : else
178 : {
179 0 : ehdr->e_shstrndx = SHN_XINDEX;
180 0 : Elf_Scn *zscn = elf_getscn (elf, 0);
181 : GElf_Shdr zshdr_mem;
182 0 : GElf_Shdr *zshdr = gelf_getshdr (zscn, &zshdr_mem);
183 0 : if (zshdr == NULL)
184 0 : return -1;
185 0 : zshdr->sh_link = ndx;
186 0 : if (gelf_update_shdr (zscn, zshdr) == 0)
187 : return -1;
188 : }
189 :
190 144 : if (gelf_update_ehdr (elf, ehdr) == 0)
191 : return -1;
192 :
193 144 : return 0;
194 : }
195 :
196 : static int
197 596 : 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 596 : unsigned int flags = compress && force ? ELF_CHF_FORCE : 0;
203 596 : if (gnu)
204 244 : res = elf_compress_gnu (scn, compress ? 1 : 0, flags);
205 : else
206 352 : res = elf_compress (scn, compress ? ELFCOMPRESS_ZLIB : 0, flags);
207 :
208 596 : if (res < 0)
209 0 : error (0, 0, "Couldn't decompress section [%zd] %s: %s",
210 : ndx, name, elf_errmsg (-1));
211 : else
212 : {
213 596 : if (compress && res == 0)
214 : {
215 48 : if (verbose >= 0)
216 : printf ("[%zd] %s NOT compressed, wouldn't be smaller\n",
217 : ndx, name);
218 : }
219 :
220 596 : if (report_verbose && res > 0)
221 : {
222 880 : printf ("[%zd] %s %s", ndx, name,
223 : compress ? "compressed" : "decompressed");
224 440 : if (newname != NULL)
225 : printf (" -> %s", newname);
226 :
227 : /* Reload shdr, it has changed. */
228 : GElf_Shdr shdr_mem;
229 440 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
230 440 : if (shdr == NULL)
231 : {
232 0 : error (0, 0, "Couldn't get shdr for section [%zd]", ndx);
233 0 : return -1;
234 : }
235 440 : float new = shdr->sh_size;
236 440 : float orig = orig_size ?: 1;
237 880 : printf (" (%zu => %" PRIu64 " %.2f%%)\n",
238 440 : orig_size, shdr->sh_size, (new / orig) * 100);
239 : }
240 : }
241 :
242 : return res;
243 : }
244 :
245 : static int
246 144 : process_file (const char *fname)
247 : {
248 144 : if (verbose > 0)
249 : printf ("processing: %s\n", fname);
250 :
251 : /* The input ELF. */
252 144 : int fd = -1;
253 144 : Elf *elf = NULL;
254 :
255 : /* The output ELF. */
256 144 : char *fnew = NULL;
257 144 : int fdnew = -1;
258 144 : Elf *elfnew = NULL;
259 :
260 : /* Buffer for (one) new section name if necessary. */
261 144 : char *snamebuf = NULL;
262 :
263 : /* String table (and symbol table), if section names need adjusting. */
264 144 : Dwelf_Strtab *names = NULL;
265 144 : Dwelf_Strent **scnstrents = NULL;
266 144 : Dwelf_Strent **symstrents = NULL;
267 144 : char **scnnames = NULL;
268 :
269 : /* Section data from names. */
270 144 : void *namesbuf = NULL;
271 :
272 : /* Which sections match and need to be (un)compressed. */
273 144 : unsigned int *sections = NULL;
274 :
275 : /* How many sections are we talking about? */
276 144 : size_t shnum = 0;
277 :
278 : #define WORD_BITS (8U * sizeof (unsigned int))
279 : void set_section (size_t ndx)
280 : {
281 596 : sections[ndx / WORD_BITS] |= (1U << (ndx % WORD_BITS));
282 : }
283 :
284 : bool get_section (size_t ndx)
285 : {
286 2967 : 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 20 : for (size_t i = 0; i < shnum / WORD_BITS + 1; i++)
294 20 : s += __builtin_popcount (sections[i]);
295 : return s;
296 : }
297 :
298 144 : int cleanup (int res)
299 : {
300 144 : elf_end (elf);
301 144 : close (fd);
302 :
303 144 : elf_end (elfnew);
304 144 : close (fdnew);
305 :
306 144 : if (fnew != NULL)
307 : {
308 0 : unlink (fnew);
309 0 : free (fnew);
310 0 : fnew = NULL;
311 : }
312 :
313 144 : free (snamebuf);
314 144 : if (names != NULL)
315 : {
316 56 : dwelf_strtab_free (names);
317 56 : free (scnstrents);
318 56 : free (symstrents);
319 56 : free (namesbuf);
320 56 : if (scnnames != NULL)
321 : {
322 936 : for (size_t n = 0; n < shnum; n++)
323 936 : free (scnnames[n]);
324 56 : free (scnnames);
325 : }
326 : }
327 :
328 144 : free (sections);
329 :
330 144 : return res;
331 : }
332 :
333 144 : fd = open (fname, O_RDONLY);
334 144 : if (fd < 0)
335 : {
336 0 : error (0, errno, "Couldn't open %s\n", fname);
337 0 : return cleanup (-1);
338 : }
339 :
340 144 : elf = elf_begin (fd, ELF_C_READ, NULL);
341 144 : if (elf == NULL)
342 : {
343 0 : error (0, 0, "Couldn't open ELF file %s for reading: %s",
344 : fname, elf_errmsg (-1));
345 0 : return cleanup (-1);
346 : }
347 :
348 : /* We dont' handle ar files (or anything else), we probably should. */
349 144 : Elf_Kind kind = elf_kind (elf);
350 144 : if (kind != ELF_K_ELF)
351 : {
352 0 : 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 0 : return cleanup (-1);
357 : }
358 :
359 : struct stat st;
360 288 : if (fstat (fd, &st) != 0)
361 : {
362 0 : error (0, errno, "Couldn't fstat %s", fname);
363 0 : return cleanup (-1);
364 : }
365 :
366 : GElf_Ehdr ehdr;
367 144 : if (gelf_getehdr (elf, &ehdr) == NULL)
368 : {
369 0 : error (0, 0, "Couldn't get ehdr for %s: %s", fname, elf_errmsg (-1));
370 0 : return cleanup (-1);
371 : }
372 :
373 : /* Get the section header string table. */
374 : size_t shdrstrndx;
375 144 : if (elf_getshdrstrndx (elf, &shdrstrndx) != 0)
376 : {
377 0 : error (0, 0, "Couldn't get section header string table index in %s: %s",
378 : fname, elf_errmsg (-1));
379 0 : return cleanup (-1);
380 : }
381 :
382 : /* How many sections are we talking about? */
383 144 : if (elf_getshdrnum (elf, &shnum) != 0)
384 : {
385 0 : error (0, 0, "Couldn't get number of sections in %s: %s",
386 : fname, elf_errmsg (1));
387 0 : return cleanup (-1);
388 : }
389 :
390 144 : if (shnum == 0)
391 : {
392 0 : error (0, 0, "ELF file %s has no sections", fname);
393 0 : return cleanup (-1);
394 : }
395 :
396 144 : sections = xcalloc (shnum / 8 + 1, sizeof (unsigned int));
397 :
398 : size_t phnum;
399 144 : if (elf_getphdrnum (elf, &phnum) != 0)
400 : {
401 0 : error (0, 0, "Couldn't get phdrnum: %s", elf_errmsg (-1));
402 0 : 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 144 : 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 144 : 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 144 : GElf_Off last_offset = 0;
419 144 : if (layout)
420 276 : last_offset = (ehdr.e_phoff
421 138 : + 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 3111 : while ((scn = elf_nextscn (elf, scn)) != NULL)
453 : {
454 2967 : size_t ndx = elf_ndxscn (scn);
455 2967 : if (ndx > shnum)
456 : {
457 0 : error (0, 0, "Unexpected section number %zd, expected only %zd",
458 : ndx, shnum);
459 0 : cleanup (-1);
460 : }
461 :
462 : GElf_Shdr shdr_mem;
463 2967 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
464 2967 : if (shdr == NULL)
465 : {
466 0 : error (0, 0, "Couldn't get shdr for section %zd", ndx);
467 0 : return cleanup (-1);
468 : }
469 :
470 2967 : const char *sname = elf_strptr (elf, shdrstrndx, shdr->sh_name);
471 2967 : if (sname == NULL)
472 : {
473 0 : error (0, 0, "Couldn't get name for section %zd", ndx);
474 0 : return cleanup (-1);
475 : }
476 :
477 2967 : if (section_name_matches (sname))
478 : {
479 725 : if (!force && type == T_DECOMPRESS
480 373 : && (shdr->sh_flags & SHF_COMPRESSED) == 0
481 251 : && strncmp (sname, ".zdebug", strlen (".zdebug")) != 0)
482 : {
483 129 : if (verbose > 0)
484 : printf ("[%zd] %s already decompressed\n", ndx, sname);
485 : }
486 596 : else if (!force && type == T_COMPRESS_ZLIB
487 122 : && (shdr->sh_flags & SHF_COMPRESSED) != 0)
488 : {
489 0 : if (verbose > 0)
490 : printf ("[%zd] %s already compressed\n", ndx, sname);
491 : }
492 596 : else if (!force && type == T_COMPRESS_GNU
493 122 : && strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
494 : {
495 0 : if (verbose > 0)
496 : printf ("[%zd] %s already GNU compressed\n", ndx, sname);
497 : }
498 596 : else if (shdr->sh_type != SHT_NOBITS
499 596 : && (shdr->sh_flags & SHF_ALLOC) == 0)
500 : {
501 596 : set_section (ndx);
502 : /* Check if we might want to change this section name. */
503 596 : if (! adjust_names
504 408 : && ((type != T_COMPRESS_GNU
505 384 : && strncmp (sname, ".zdebug",
506 : strlen (".zdebug")) == 0)
507 376 : || (type == T_COMPRESS_GNU
508 24 : && 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 540 : if (adjust_names)
514 : {
515 244 : size_t slen = strlen (sname);
516 244 : if (slen > maxnamelen)
517 62 : maxnamelen = slen;
518 : }
519 : }
520 : else
521 0 : if (verbose >= 0)
522 0 : printf ("[%zd] %s ignoring %s section\n", ndx, sname,
523 : (shdr->sh_type == SHT_NOBITS ? "no bits" : "allocated"));
524 : }
525 :
526 2967 : if (shdr->sh_type == SHT_SYMTAB)
527 : {
528 : /* Check if we might have to adjust the symbol name indexes. */
529 144 : if (shdr->sh_link == shdrstrndx)
530 : {
531 60 : if (symtabndx != 0)
532 : {
533 0 : error (0, 0,
534 : "Multiple symbol tables (%zd, %zd) using the same string table unsupported", symtabndx, ndx);
535 0 : return cleanup (-1);
536 : }
537 : symtabndx = ndx;
538 : }
539 : }
540 :
541 : /* Keep track of last allocated data offset. */
542 2967 : if (layout)
543 2703 : if ((shdr->sh_flags & SHF_ALLOC) != 0)
544 : {
545 3040 : GElf_Off off = shdr->sh_offset + (shdr->sh_type != SHT_NOBITS
546 1520 : ? shdr->sh_size : 0);
547 1520 : if (last_offset < off)
548 1422 : last_offset = off;
549 : }
550 : }
551 :
552 154 : if (foutput == NULL && get_sections () == 0)
553 : {
554 0 : if (verbose > 0)
555 : printf ("Nothing to do.\n");
556 0 : fnew = NULL;
557 0 : return cleanup (0);
558 : }
559 :
560 144 : if (adjust_names)
561 : {
562 56 : names = dwelf_strtab_init (true);
563 56 : if (names == NULL)
564 : {
565 0 : error (0, 0, "Not enough memory for new strtab");
566 0 : return cleanup (-1);
567 : }
568 56 : scnstrents = xmalloc (shnum
569 : * sizeof (Dwelf_Strent *));
570 56 : scnnames = xcalloc (shnum, sizeof (char *));
571 : }
572 :
573 : /* Create a new (temporary) ELF file for the result. */
574 144 : if (foutput == NULL)
575 : {
576 10 : size_t fname_len = strlen (fname);
577 10 : fnew = xmalloc (fname_len + sizeof (".XXXXXX"));
578 30 : strcpy (mempcpy (fnew, fname, fname_len), ".XXXXXX");
579 10 : fdnew = mkstemp (fnew);
580 : }
581 : else
582 : {
583 134 : fnew = xstrdup (foutput);
584 268 : fdnew = open (fnew, O_WRONLY | O_CREAT, st.st_mode & ALLPERMS);
585 : }
586 :
587 144 : if (fdnew < 0)
588 : {
589 0 : 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 0 : free (fnew);
592 0 : fnew = NULL;
593 0 : return cleanup (-1);
594 : }
595 :
596 144 : elfnew = elf_begin (fdnew, ELF_C_WRITE, NULL);
597 144 : if (elfnew == NULL)
598 : {
599 0 : error (0, 0, "Couldn't open new ELF %s for writing: %s",
600 : fnew, elf_errmsg (-1));
601 0 : return cleanup (-1);
602 : }
603 :
604 : /* Create the new ELF header and copy over all the data. */
605 144 : if (gelf_newehdr (elfnew, gelf_getclass (elf)) == 0)
606 : {
607 0 : error (0, 0, "Couldn't create new ehdr: %s", elf_errmsg (-1));
608 0 : return cleanup (-1);
609 : }
610 :
611 : GElf_Ehdr newehdr;
612 144 : if (gelf_getehdr (elfnew, &newehdr) == NULL)
613 : {
614 0 : error (0, 0, "Couldn't get new ehdr: %s", elf_errmsg (-1));
615 0 : return cleanup (-1);
616 : }
617 :
618 144 : newehdr.e_ident[EI_DATA] = ehdr.e_ident[EI_DATA];
619 144 : newehdr.e_type = ehdr.e_type;
620 144 : newehdr.e_machine = ehdr.e_machine;
621 144 : newehdr.e_version = ehdr.e_version;
622 144 : newehdr.e_entry = ehdr.e_entry;
623 144 : newehdr.e_flags = ehdr.e_flags;
624 :
625 144 : if (gelf_update_ehdr (elfnew, &newehdr) == 0)
626 : {
627 0 : error (0, 0, "Couldn't update ehdr: %s", elf_errmsg (-1));
628 0 : return cleanup (-1);
629 : }
630 :
631 : /* Copy over the phdrs as is. */
632 144 : if (phnum != 0)
633 : {
634 138 : if (gelf_newphdr (elfnew, phnum) == 0)
635 : {
636 0 : error (0, 0, "Couldn't create phdrs: %s", elf_errmsg (-1));
637 0 : return cleanup (-1);
638 : }
639 :
640 1256 : for (size_t cnt = 0; cnt < phnum; ++cnt)
641 : {
642 : GElf_Phdr phdr_mem;
643 559 : GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
644 559 : if (phdr == NULL)
645 : {
646 0 : error (0, 0, "Couldn't get phdr %zd: %s", cnt, elf_errmsg (-1));
647 0 : return cleanup (-1);
648 : }
649 559 : if (gelf_update_phdr (elfnew, cnt, phdr) == 0)
650 : {
651 0 : error (0, 0, "Couldn't create phdr %zd: %s", cnt,
652 : elf_errmsg (-1));
653 0 : return cleanup (-1);
654 : }
655 : }
656 : }
657 :
658 : /* Possibly add a 'z' and zero terminator. */
659 144 : if (maxnamelen > 0)
660 56 : 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 3111 : while ((scn = elf_nextscn (elf, scn)) != NULL)
683 : {
684 2967 : size_t ndx = elf_ndxscn (scn);
685 2967 : assert (ndx < shnum);
686 :
687 : /* (de)compress if section matched. */
688 2967 : char *sname = NULL;
689 2967 : char *newname = NULL;
690 2967 : if (get_section (ndx))
691 : {
692 : GElf_Shdr shdr_mem;
693 596 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
694 596 : if (shdr == NULL)
695 : {
696 0 : error (0, 0, "Couldn't get shdr for section %zd", ndx);
697 0 : return cleanup (-1);
698 : }
699 :
700 596 : uint64_t size = shdr->sh_size;
701 596 : sname = elf_strptr (elf, shdrstrndx, shdr->sh_name);
702 596 : if (sname == NULL)
703 : {
704 0 : error (0, 0, "Couldn't get name for section %zd", ndx);
705 0 : return cleanup (-1);
706 : }
707 :
708 : /* strdup sname, the shdrstrndx section itself might be
709 : (de)compressed, invalidating the string pointers. */
710 596 : 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 596 : bool skip_compress_section = (adjust_names
717 596 : && (ndx == shdrstrndx
718 244 : || ndx == symtabndx));
719 :
720 596 : switch (type)
721 : {
722 244 : case T_DECOMPRESS:
723 244 : if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
724 : {
725 122 : if (compress_section (scn, size, sname, NULL, ndx,
726 : false, false, verbose > 0) < 0)
727 0 : return cleanup (-1);
728 : }
729 122 : else if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
730 : {
731 122 : snamebuf[0] = '.';
732 244 : strcpy (&snamebuf[1], &sname[2]);
733 122 : newname = snamebuf;
734 122 : if (compress_section (scn, size, sname, newname, ndx,
735 : true, false, verbose > 0) < 0)
736 0 : return cleanup (-1);
737 : }
738 0 : else if (verbose > 0)
739 : printf ("[%zd] %s already decompressed\n", ndx, sname);
740 : break;
741 :
742 122 : case T_COMPRESS_GNU:
743 122 : if (strncmp (sname, ".debug", strlen (".debug")) == 0)
744 : {
745 122 : if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
746 : {
747 : /* First decompress to recompress GNU style.
748 : Don't report even when verbose. */
749 0 : if (compress_section (scn, size, sname, NULL, ndx,
750 : false, false, false) < 0)
751 0 : return cleanup (-1);
752 : }
753 :
754 122 : snamebuf[0] = '.';
755 122 : snamebuf[1] = 'z';
756 244 : strcpy (&snamebuf[2], &sname[1]);
757 122 : newname = snamebuf;
758 :
759 122 : if (skip_compress_section)
760 : {
761 0 : if (ndx == shdrstrndx)
762 : {
763 0 : shstrtab_size = size;
764 0 : shstrtab_compressed = T_COMPRESS_GNU;
765 0 : shstrtab_name = xstrdup (sname);
766 0 : shstrtab_newname = xstrdup (newname);
767 : }
768 : else
769 : {
770 0 : symtab_size = size;
771 0 : symtab_compressed = T_COMPRESS_GNU;
772 0 : symtab_name = xstrdup (sname);
773 0 : symtab_newname = xstrdup (newname);
774 : }
775 : }
776 : else
777 : {
778 122 : int res = compress_section (scn, size, sname, newname,
779 : ndx, true, true,
780 : verbose > 0);
781 122 : if (res < 0)
782 0 : return cleanup (-1);
783 :
784 122 : if (res == 0)
785 24 : newname = NULL;
786 : }
787 : }
788 0 : else if (verbose >= 0)
789 : {
790 0 : 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 230 : case T_COMPRESS_ZLIB:
800 230 : if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
801 : {
802 230 : if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
803 : {
804 : /* First decompress to recompress zlib style.
805 : Don't report even when verbose. */
806 0 : if (compress_section (scn, size, sname, NULL, ndx,
807 : true, false, false) < 0)
808 0 : return cleanup (-1);
809 :
810 0 : snamebuf[0] = '.';
811 0 : strcpy (&snamebuf[1], &sname[2]);
812 0 : newname = snamebuf;
813 : }
814 :
815 230 : if (skip_compress_section)
816 : {
817 0 : if (ndx == shdrstrndx)
818 : {
819 0 : shstrtab_size = size;
820 0 : shstrtab_compressed = T_COMPRESS_ZLIB;
821 0 : shstrtab_name = xstrdup (sname);
822 : shstrtab_newname = (newname == NULL
823 0 : ? NULL : xstrdup (newname));
824 : }
825 : else
826 : {
827 0 : symtab_size = size;
828 0 : symtab_compressed = T_COMPRESS_ZLIB;
829 0 : symtab_name = xstrdup (sname);
830 : symtab_newname = (newname == NULL
831 0 : ? NULL : xstrdup (newname));
832 : }
833 : }
834 230 : else if (compress_section (scn, size, sname, newname, ndx,
835 : false, true, verbose > 0) < 0)
836 0 : return cleanup (-1);
837 : }
838 0 : else if (verbose > 0)
839 : printf ("[%zd] %s already compressed\n", ndx, sname);
840 : break;
841 : }
842 :
843 596 : free (sname);
844 : }
845 :
846 2967 : Elf_Scn *newscn = elf_newscn (elfnew);
847 2967 : if (newscn == NULL)
848 : {
849 0 : error (0, 0, "Couldn't create new section %zd", ndx);
850 0 : return cleanup (-1);
851 : }
852 :
853 : GElf_Shdr shdr_mem;
854 2967 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
855 2967 : if (shdr == NULL)
856 : {
857 0 : error (0, 0, "Couldn't get shdr for section %zd", ndx);
858 0 : return cleanup (-1);
859 : }
860 :
861 2967 : if (gelf_update_shdr (newscn, shdr) == 0)
862 : {
863 0 : error (0, 0, "Couldn't update section header %zd", ndx);
864 0 : 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 2967 : if (! adjust_names || ndx != shdrstrndx)
872 : {
873 2911 : Elf_Data *data = elf_getdata (scn, NULL);
874 2911 : if (data == NULL)
875 : {
876 0 : error (0, 0, "Couldn't get data from section %zd", ndx);
877 0 : return cleanup (-1);
878 : }
879 :
880 2911 : Elf_Data *newdata = elf_newdata (newscn);
881 2911 : if (newdata == NULL)
882 : {
883 0 : error (0, 0, "Couldn't create new data for section %zd", ndx);
884 0 : return cleanup (-1);
885 : }
886 :
887 2911 : *newdata = *data;
888 : }
889 :
890 : /* Keep track of the (new) section names. */
891 2967 : if (adjust_names)
892 : {
893 : char *name;
894 880 : if (newname != NULL)
895 : name = newname;
896 : else
897 : {
898 660 : name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
899 660 : if (name == NULL)
900 : {
901 0 : error (0, 0, "Couldn't get name for section [%zd]", ndx);
902 0 : return cleanup (-1);
903 : }
904 : }
905 :
906 : /* We need to keep a copy of the name till the strtab is done. */
907 880 : name = scnnames[ndx] = xstrdup (name);
908 880 : if ((scnstrents[ndx] = dwelf_strtab_add (names, name)) == NULL)
909 : {
910 0 : error (0, 0, "No memory to add section name string table");
911 0 : return cleanup (-1);
912 : }
913 :
914 : /* If the symtab shares strings then add those too. */
915 880 : 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 28 : if (symtab_compressed == T_UNSET)
921 : {
922 28 : size_t size = shdr->sh_size;
923 28 : if ((shdr->sh_flags == SHF_COMPRESSED) != 0)
924 : {
925 : /* Don't report the (internal) uncompression. */
926 0 : if (compress_section (newscn, size, sname, NULL, ndx,
927 : false, false, false) < 0)
928 0 : return cleanup (-1);
929 :
930 : symtab_size = size;
931 : symtab_compressed = T_COMPRESS_ZLIB;
932 : }
933 28 : else if (strncmp (name, ".zdebug", strlen (".zdebug")) == 0)
934 : {
935 : /* Don't report the (internal) uncompression. */
936 0 : if (compress_section (newscn, size, sname, NULL, ndx,
937 : true, false, false) < 0)
938 0 : return cleanup (-1);
939 :
940 : symtab_size = size;
941 : symtab_compressed = T_COMPRESS_GNU;
942 : }
943 : }
944 :
945 28 : Elf_Data *symd = elf_getdata (newscn, NULL);
946 28 : if (symd == NULL)
947 : {
948 0 : error (0, 0, "Couldn't get symtab data for section [%zd] %s",
949 : ndx, name);
950 0 : return cleanup (-1);
951 : }
952 28 : size_t elsize = gelf_fsize (elfnew, ELF_T_SYM, 1, EV_CURRENT);
953 28 : size_t syms = symd->d_size / elsize;
954 28 : symstrents = xmalloc (syms * sizeof (Dwelf_Strent *));
955 2990 : for (size_t i = 0; i < syms; i++)
956 : {
957 : GElf_Sym sym_mem;
958 1467 : GElf_Sym *sym = gelf_getsym (symd, i, &sym_mem);
959 1467 : if (sym == NULL)
960 : {
961 0 : error (0, 0, "Couldn't get symbol %zd", i);
962 0 : return cleanup (-1);
963 : }
964 1467 : 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 1053 : const char *symname = elf_strptr (elf, shdrstrndx,
970 : sym->st_name);
971 1053 : if (symname == NULL)
972 : {
973 0 : error (0, 0, "Couldn't get symbol %zd name", i);
974 0 : return cleanup (-1);
975 : }
976 1053 : symstrents[i] = dwelf_strtab_add (names, symname);
977 1053 : if (symstrents[i] == NULL)
978 : {
979 0 : error (0, 0, "No memory to add to symbol name");
980 0 : return cleanup (-1);
981 : }
982 : }
983 : }
984 : }
985 : }
986 : }
987 :
988 144 : if (adjust_names)
989 : {
990 : /* We got all needed strings, put the new data in the shstrtab. */
991 56 : if (verbose > 0)
992 56 : printf ("[%zd] Updating section string table\n", shdrstrndx);
993 :
994 56 : scn = elf_getscn (elfnew, shdrstrndx);
995 56 : if (scn == NULL)
996 : {
997 0 : error (0, 0, "Couldn't get new section header string table [%zd]",
998 : shdrstrndx);
999 0 : return cleanup (-1);
1000 : }
1001 :
1002 56 : Elf_Data *data = elf_newdata (scn);
1003 56 : if (data == NULL)
1004 : {
1005 0 : error (0, 0, "Couldn't create new section header string table data");
1006 0 : return cleanup (-1);
1007 : }
1008 56 : if (dwelf_strtab_finalize (names, data) == NULL)
1009 : {
1010 0 : error (0, 0, "Not enough memory to create string table");
1011 0 : return cleanup (-1);
1012 : }
1013 56 : namesbuf = data->d_buf;
1014 :
1015 : GElf_Shdr shdr_mem;
1016 56 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1017 56 : if (shdr == NULL)
1018 : {
1019 0 : error (0, 0, "Couldn't get shdr for new section strings %zd",
1020 : shdrstrndx);
1021 0 : return cleanup (-1);
1022 : }
1023 :
1024 : /* Note that we also might have to compress and possibly set
1025 : sh_off below */
1026 56 : shdr->sh_name = dwelf_strent_off (scnstrents[shdrstrndx]);
1027 56 : shdr->sh_type = SHT_STRTAB;
1028 56 : shdr->sh_flags = 0;
1029 56 : shdr->sh_addr = 0;
1030 56 : shdr->sh_offset = 0;
1031 56 : shdr->sh_size = data->d_size;
1032 56 : shdr->sh_link = SHN_UNDEF;
1033 56 : shdr->sh_info = SHN_UNDEF;
1034 56 : shdr->sh_addralign = 1;
1035 56 : shdr->sh_entsize = 0;
1036 :
1037 56 : if (gelf_update_shdr (scn, shdr) == 0)
1038 : {
1039 0 : error (0, 0, "Couldn't update new section strings [%zd]",
1040 : shdrstrndx);
1041 0 : 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 56 : 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 56 : Elf_Scn *oldscn = elf_getscn (elf, shdrstrndx);
1053 56 : if (oldscn == NULL)
1054 : {
1055 0 : error (0, 0, "Couldn't get section header string table [%zd]",
1056 : shdrstrndx);
1057 0 : return cleanup (-1);
1058 : }
1059 :
1060 56 : shdr = gelf_getshdr (oldscn, &shdr_mem);
1061 56 : if (shdr == NULL)
1062 : {
1063 0 : error (0, 0, "Couldn't get shdr for old section strings [%zd]",
1064 : shdrstrndx);
1065 0 : return cleanup (-1);
1066 : }
1067 :
1068 56 : shstrtab_name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
1069 56 : if (shstrtab_name == NULL)
1070 : {
1071 0 : error (0, 0, "Couldn't get name for old section strings [%zd]",
1072 : shdrstrndx);
1073 0 : return cleanup (-1);
1074 : }
1075 :
1076 56 : shstrtab_size = shdr->sh_size;
1077 56 : if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
1078 : shstrtab_compressed = T_COMPRESS_ZLIB;
1079 56 : else if (strncmp (shstrtab_name, ".zdebug", strlen (".zdebug")) == 0)
1080 0 : shstrtab_compressed = T_COMPRESS_GNU;
1081 : }
1082 :
1083 : /* Should we (re)compress? */
1084 56 : if (shstrtab_compressed != T_UNSET)
1085 : {
1086 0 : if (compress_section (scn, shstrtab_size, shstrtab_name,
1087 : shstrtab_newname, shdrstrndx,
1088 : shstrtab_compressed == T_COMPRESS_GNU,
1089 : true, verbose > 0) < 0)
1090 0 : 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 144 : if (gelf_getehdr (elfnew, &newehdr) == NULL)
1097 : {
1098 0 : error (0, 0, "Couldn't re-get new ehdr: %s", elf_errmsg (-1));
1099 0 : return cleanup (-1);
1100 : }
1101 :
1102 : /* Set this after the sections have been created, otherwise section
1103 : zero might not exist yet. */
1104 144 : if (setshdrstrndx (elfnew, &newehdr, shdrstrndx) != 0)
1105 : {
1106 0 : error (0, 0, "Couldn't set new shdrstrndx: %s", elf_errmsg (-1));
1107 0 : return cleanup (-1);
1108 : }
1109 :
1110 : /* Fixup pass. Adjust string table references, symbol table and
1111 : layout if necessary. */
1112 144 : if (layout || adjust_names)
1113 : {
1114 : scn = NULL;
1115 2841 : while ((scn = elf_nextscn (elfnew, scn)) != NULL)
1116 : {
1117 2703 : size_t ndx = elf_ndxscn (scn);
1118 :
1119 : GElf_Shdr shdr_mem;
1120 2703 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1121 2703 : if (shdr == NULL)
1122 : {
1123 0 : error (0, 0, "Couldn't get shdr for section %zd", ndx);
1124 0 : 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 2703 : if ((shdr->sh_flags & SHF_ALLOC) == 0)
1131 : {
1132 : /* Zero means one. No alignment constraints. */
1133 1183 : size_t addralign = shdr->sh_addralign ?: 1;
1134 1183 : last_offset = (last_offset + addralign - 1) & ~(addralign - 1);
1135 1183 : shdr->sh_offset = last_offset;
1136 1183 : if (shdr->sh_type != SHT_NOBITS)
1137 1183 : last_offset += shdr->sh_size;
1138 : }
1139 :
1140 2703 : if (adjust_names)
1141 880 : shdr->sh_name = dwelf_strent_off (scnstrents[ndx]);
1142 :
1143 2703 : if (gelf_update_shdr (scn, shdr) == 0)
1144 : {
1145 0 : error (0, 0, "Couldn't update section header %zd", ndx);
1146 0 : return cleanup (-1);
1147 : }
1148 :
1149 2703 : if (adjust_names && ndx == symtabndx)
1150 : {
1151 28 : if (verbose > 0)
1152 : printf ("[%zd] Updating symbol table\n", symtabndx);
1153 :
1154 28 : Elf_Data *symd = elf_getdata (scn, NULL);
1155 28 : if (symd == NULL)
1156 : {
1157 0 : error (0, 0, "Couldn't get new symtab data section [%zd]",
1158 : ndx);
1159 0 : return cleanup (-1);
1160 : }
1161 28 : size_t elsize = gelf_fsize (elfnew, ELF_T_SYM, 1, EV_CURRENT);
1162 28 : size_t syms = symd->d_size / elsize;
1163 2990 : for (size_t i = 0; i < syms; i++)
1164 : {
1165 : GElf_Sym sym_mem;
1166 1467 : GElf_Sym *sym = gelf_getsym (symd, i, &sym_mem);
1167 1467 : if (sym == NULL)
1168 : {
1169 0 : error (0, 0, "2 Couldn't get symbol %zd", i);
1170 0 : return cleanup (-1);
1171 : }
1172 :
1173 1467 : if (sym->st_name != 0)
1174 : {
1175 1053 : sym->st_name = dwelf_strent_off (symstrents[i]);
1176 :
1177 1053 : if (gelf_update_sym (symd, i, sym) == 0)
1178 : {
1179 0 : error (0, 0, "Couldn't update symbol %zd", i);
1180 0 : 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 28 : 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 28 : Elf_Scn *oldscn = elf_getscn (elf, symtabndx);
1194 28 : if (oldscn == NULL)
1195 : {
1196 0 : error (0, 0, "Couldn't get symbol table [%zd]",
1197 : symtabndx);
1198 0 : return cleanup (-1);
1199 : }
1200 :
1201 28 : shdr = gelf_getshdr (oldscn, &shdr_mem);
1202 28 : if (shdr == NULL)
1203 : {
1204 0 : error (0, 0, "Couldn't get old symbol table shdr [%zd]",
1205 : symtabndx);
1206 0 : return cleanup (-1);
1207 : }
1208 :
1209 28 : symtab_name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
1210 28 : if (symtab_name == NULL)
1211 : {
1212 0 : error (0, 0, "Couldn't get old symbol table name [%zd]",
1213 : symtabndx);
1214 0 : return cleanup (-1);
1215 : }
1216 :
1217 28 : symtab_size = shdr->sh_size;
1218 28 : if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
1219 : symtab_compressed = T_COMPRESS_ZLIB;
1220 28 : else if (strncmp (symtab_name, ".zdebug",
1221 : strlen (".zdebug")) == 0)
1222 0 : symtab_compressed = T_COMPRESS_GNU;
1223 : }
1224 :
1225 : /* Should we (re)compress? */
1226 28 : if (symtab_compressed != T_UNSET)
1227 : {
1228 0 : if (compress_section (scn, symtab_size, symtab_name,
1229 : symtab_newname, symtabndx,
1230 : symtab_compressed == T_COMPRESS_GNU,
1231 : true, verbose > 0) < 0)
1232 0 : 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 144 : if (layout)
1242 : {
1243 138 : if (gelf_getehdr (elfnew, &newehdr) == NULL)
1244 : {
1245 0 : error (0, 0, "Couldn't get ehdr: %s", elf_errmsg (-1));
1246 0 : return cleanup (-1);
1247 : }
1248 :
1249 : /* Position the shdrs after the last (unallocated) section. */
1250 138 : const size_t offsize = gelf_fsize (elfnew, ELF_T_OFF, 1, EV_CURRENT);
1251 276 : newehdr.e_shoff = ((last_offset + offsize - 1)
1252 138 : & ~((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 138 : newehdr.e_phoff = ehdr.e_phoff;
1257 :
1258 138 : if (gelf_update_ehdr (elfnew, &newehdr) == 0)
1259 : {
1260 0 : error (0, 0, "Couldn't update ehdr: %s", elf_errmsg (-1));
1261 0 : return cleanup (-1);
1262 : }
1263 : }
1264 :
1265 288 : elf_flagelf (elfnew, ELF_C_SET, ((layout ? ELF_F_LAYOUT : 0)
1266 144 : | (permissive ? ELF_F_PERMISSIVE : 0)));
1267 :
1268 144 : if (elf_update (elfnew, ELF_C_WRITE) < 0)
1269 : {
1270 0 : error (0, 0, "Couldn't write %s: %s", fnew, elf_errmsg (-1));
1271 0 : return cleanup (-1);
1272 : }
1273 :
1274 144 : elf_end (elfnew);
1275 144 : 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 144 : if (fchown (fdnew, st.st_uid, st.st_gid) != 0)
1282 0 : if (verbose >= 0)
1283 0 : error (0, errno, "Couldn't fchown %s", fnew);
1284 144 : if (fchmod (fdnew, st.st_mode & ALLPERMS) != 0)
1285 0 : if (verbose >= 0)
1286 0 : error (0, errno, "Couldn't fchmod %s", fnew);
1287 :
1288 : /* Finally replace the old file with the new file. */
1289 144 : if (foutput == NULL)
1290 10 : if (rename (fnew, fname) != 0)
1291 : {
1292 0 : error (0, errno, "Couldn't rename %s to %s", fnew, fname);
1293 0 : return cleanup (-1);
1294 : }
1295 :
1296 : /* We are finally done with the new file, don't unlink it now. */
1297 144 : free (fnew);
1298 144 : fnew = NULL;
1299 :
1300 144 : return cleanup (0);
1301 : }
1302 :
1303 : int
1304 144 : main (int argc, char **argv)
1305 : {
1306 144 : 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 144 : 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 144 : 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 144 : 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 144 : if (foutput != NULL && remaining + 1 < argc)
1351 : error (EXIT_FAILURE, 0,
1352 : N_("Only one input file allowed together with '-o'"));
1353 :
1354 144 : elf_version (EV_CURRENT);
1355 :
1356 : /* Process all the remaining files. */
1357 144 : int result = 0;
1358 : do
1359 144 : result |= process_file (argv[remaining]);
1360 144 : while (++remaining < argc);
1361 :
1362 144 : free_patterns ();
1363 144 : return result;
1364 : }
|