xref: /aosp_15_r20/external/elfutils/src/elfcompress.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
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