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