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