xref: /aosp_15_r20/external/elfutils/tests/elfstrmerge.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Merge string sections.
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2015, 2016 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 
20*7304104dSAndroid Build Coastguard Worker #include <assert.h>
21*7304104dSAndroid Build Coastguard Worker #include <errno.h>
22*7304104dSAndroid Build Coastguard Worker #include <stdlib.h>
23*7304104dSAndroid Build Coastguard Worker #include <string.h>
24*7304104dSAndroid Build Coastguard Worker #include <sys/types.h>
25*7304104dSAndroid Build Coastguard Worker #include <sys/stat.h>
26*7304104dSAndroid Build Coastguard Worker #include <fcntl.h>
27*7304104dSAndroid Build Coastguard Worker #include <stdio.h>
28*7304104dSAndroid Build Coastguard Worker #include <inttypes.h>
29*7304104dSAndroid Build Coastguard Worker #include <unistd.h>
30*7304104dSAndroid Build Coastguard Worker 
31*7304104dSAndroid Build Coastguard Worker #include <system.h>
32*7304104dSAndroid Build Coastguard Worker #include <gelf.h>
33*7304104dSAndroid Build Coastguard Worker #include ELFUTILS_HEADER(dwelf)
34*7304104dSAndroid Build Coastguard Worker #include "elf-knowledge.h"
35*7304104dSAndroid Build Coastguard Worker 
36*7304104dSAndroid Build Coastguard Worker /* The original ELF file.  */
37*7304104dSAndroid Build Coastguard Worker static int fd = -1;
38*7304104dSAndroid Build Coastguard Worker static Elf *elf = NULL;
39*7304104dSAndroid Build Coastguard Worker static bool replace;
40*7304104dSAndroid Build Coastguard Worker 
41*7304104dSAndroid Build Coastguard Worker /* The new ELF file.  */
42*7304104dSAndroid Build Coastguard Worker static char *fnew = NULL;
43*7304104dSAndroid Build Coastguard Worker static int fdnew = -1;
44*7304104dSAndroid Build Coastguard Worker static Elf *elfnew = NULL;
45*7304104dSAndroid Build Coastguard Worker 
46*7304104dSAndroid Build Coastguard Worker /* The merged string table.  */
47*7304104dSAndroid Build Coastguard Worker static Dwelf_Strtab *strings = NULL;
48*7304104dSAndroid Build Coastguard Worker 
49*7304104dSAndroid Build Coastguard Worker /* Section name strents.  */
50*7304104dSAndroid Build Coastguard Worker static Dwelf_Strent **scnstrents = NULL;
51*7304104dSAndroid Build Coastguard Worker 
52*7304104dSAndroid Build Coastguard Worker /* Symbol name strends.  */
53*7304104dSAndroid Build Coastguard Worker static Dwelf_Strent **symstrents = NULL;
54*7304104dSAndroid Build Coastguard Worker 
55*7304104dSAndroid Build Coastguard Worker /* New ELF file buffers.  */
56*7304104dSAndroid Build Coastguard Worker static Elf_Data newstrtabdata = { .d_buf = NULL };
57*7304104dSAndroid Build Coastguard Worker static size_t newshnums = 0;
58*7304104dSAndroid Build Coastguard Worker static void **newscnbufs = NULL;
59*7304104dSAndroid Build Coastguard Worker 
60*7304104dSAndroid Build Coastguard Worker /* Release all files and resources allocated.  */
61*7304104dSAndroid Build Coastguard Worker static void
release(void)62*7304104dSAndroid Build Coastguard Worker release (void)
63*7304104dSAndroid Build Coastguard Worker {
64*7304104dSAndroid Build Coastguard Worker   /* The new string table.  */
65*7304104dSAndroid Build Coastguard Worker   if (strings != NULL)
66*7304104dSAndroid Build Coastguard Worker     dwelf_strtab_free (strings);
67*7304104dSAndroid Build Coastguard Worker 
68*7304104dSAndroid Build Coastguard Worker   free (scnstrents);
69*7304104dSAndroid Build Coastguard Worker   free (symstrents);
70*7304104dSAndroid Build Coastguard Worker   free (newstrtabdata.d_buf);
71*7304104dSAndroid Build Coastguard Worker 
72*7304104dSAndroid Build Coastguard Worker   /* Any new data buffers allocated.  */
73*7304104dSAndroid Build Coastguard Worker   for (size_t i = 0; i < newshnums; i++)
74*7304104dSAndroid Build Coastguard Worker     free (newscnbufs[i]);
75*7304104dSAndroid Build Coastguard Worker   free (newscnbufs);
76*7304104dSAndroid Build Coastguard Worker 
77*7304104dSAndroid Build Coastguard Worker   /* The new ELF file.  */
78*7304104dSAndroid Build Coastguard Worker   if (fdnew != -1)
79*7304104dSAndroid Build Coastguard Worker     {
80*7304104dSAndroid Build Coastguard Worker       unlink (fnew);
81*7304104dSAndroid Build Coastguard Worker       elf_end (elfnew);
82*7304104dSAndroid Build Coastguard Worker       close (fdnew);
83*7304104dSAndroid Build Coastguard Worker     }
84*7304104dSAndroid Build Coastguard Worker   // Don't release, we might need it in the error message.
85*7304104dSAndroid Build Coastguard Worker   // if (replace)
86*7304104dSAndroid Build Coastguard Worker   //   free (fnew);
87*7304104dSAndroid Build Coastguard Worker 
88*7304104dSAndroid Build Coastguard Worker   /* The original ELF file.  */
89*7304104dSAndroid Build Coastguard Worker   elf_end (elf);
90*7304104dSAndroid Build Coastguard Worker   close (fd);
91*7304104dSAndroid Build Coastguard Worker }
92*7304104dSAndroid Build Coastguard Worker 
93*7304104dSAndroid Build Coastguard Worker /* The various ways we can fail... Cleanup and show some message to
94*7304104dSAndroid Build Coastguard Worker    the user.  The file name may be NULL.  */
95*7304104dSAndroid Build Coastguard Worker static void __attribute__ ((noreturn))
fail(const char * msg,const char * fname)96*7304104dSAndroid Build Coastguard Worker fail (const char *msg, const char *fname)
97*7304104dSAndroid Build Coastguard Worker {
98*7304104dSAndroid Build Coastguard Worker   release ();
99*7304104dSAndroid Build Coastguard Worker   if (fname != NULL)
100*7304104dSAndroid Build Coastguard Worker     error (1, 0, "%s: %s", fname, msg);
101*7304104dSAndroid Build Coastguard Worker   else
102*7304104dSAndroid Build Coastguard Worker     error (1, 0, "%s", msg);
103*7304104dSAndroid Build Coastguard Worker   abort();
104*7304104dSAndroid Build Coastguard Worker }
105*7304104dSAndroid Build Coastguard Worker 
106*7304104dSAndroid Build Coastguard Worker static void __attribute__ ((noreturn))
fail_errno(const char * msg,const char * fname)107*7304104dSAndroid Build Coastguard Worker fail_errno (const char *msg, const char *fname)
108*7304104dSAndroid Build Coastguard Worker {
109*7304104dSAndroid Build Coastguard Worker   release ();
110*7304104dSAndroid Build Coastguard Worker   if (fname != NULL)
111*7304104dSAndroid Build Coastguard Worker     error (1, errno, "%s: %s", fname, msg);
112*7304104dSAndroid Build Coastguard Worker   else
113*7304104dSAndroid Build Coastguard Worker     error (1, errno, "%s", msg);
114*7304104dSAndroid Build Coastguard Worker   abort();
115*7304104dSAndroid Build Coastguard Worker }
116*7304104dSAndroid Build Coastguard Worker 
117*7304104dSAndroid Build Coastguard Worker static void __attribute__ ((noreturn))
fail_idx(const char * msg,const char * fname,size_t idx)118*7304104dSAndroid Build Coastguard Worker fail_idx (const char *msg, const char *fname, size_t idx)
119*7304104dSAndroid Build Coastguard Worker {
120*7304104dSAndroid Build Coastguard Worker   release ();
121*7304104dSAndroid Build Coastguard Worker   if (fname != NULL)
122*7304104dSAndroid Build Coastguard Worker     error (1, 0, "%s: %s %zd", fname, msg, idx);
123*7304104dSAndroid Build Coastguard Worker   else
124*7304104dSAndroid Build Coastguard Worker     error (1, 0, "%s %zd", msg, idx);
125*7304104dSAndroid Build Coastguard Worker   abort();
126*7304104dSAndroid Build Coastguard Worker }
127*7304104dSAndroid Build Coastguard Worker 
128*7304104dSAndroid Build Coastguard Worker static void __attribute__ ((noreturn))
fail_elf(const char * msg,const char * fname)129*7304104dSAndroid Build Coastguard Worker fail_elf (const char *msg, const char *fname)
130*7304104dSAndroid Build Coastguard Worker {
131*7304104dSAndroid Build Coastguard Worker   release ();
132*7304104dSAndroid Build Coastguard Worker   if (fname != NULL)
133*7304104dSAndroid Build Coastguard Worker     error (1, 0, "%s: %s: %s", fname, msg, elf_errmsg (-1));
134*7304104dSAndroid Build Coastguard Worker   else
135*7304104dSAndroid Build Coastguard Worker     error (1, 0, "%s: %s", msg, elf_errmsg (-1));
136*7304104dSAndroid Build Coastguard Worker   abort();
137*7304104dSAndroid Build Coastguard Worker }
138*7304104dSAndroid Build Coastguard Worker 
139*7304104dSAndroid Build Coastguard Worker static void __attribute__ ((noreturn))
fail_elf_idx(const char * msg,const char * fname,size_t idx)140*7304104dSAndroid Build Coastguard Worker fail_elf_idx (const char *msg, const char *fname, size_t idx)
141*7304104dSAndroid Build Coastguard Worker {
142*7304104dSAndroid Build Coastguard Worker   release ();
143*7304104dSAndroid Build Coastguard Worker   if (fname != NULL)
144*7304104dSAndroid Build Coastguard Worker     error (1, 0, "%s: %s %zd: %s", fname, msg, idx, elf_errmsg (-1));
145*7304104dSAndroid Build Coastguard Worker   else
146*7304104dSAndroid Build Coastguard Worker     error (1, 0, "%s %zd: %s", msg, idx, elf_errmsg (-1));
147*7304104dSAndroid Build Coastguard Worker   abort();
148*7304104dSAndroid Build Coastguard Worker }
149*7304104dSAndroid Build Coastguard Worker 
150*7304104dSAndroid Build Coastguard Worker /* section index mapping and sanity checking.  */
151*7304104dSAndroid Build Coastguard Worker static size_t
newsecndx(size_t secndx,size_t shdrstrndx,size_t shdrnum,const char * fname,const char * what,size_t widx,const char * member,size_t midx)152*7304104dSAndroid Build Coastguard Worker newsecndx (size_t secndx, size_t shdrstrndx, size_t shdrnum,
153*7304104dSAndroid Build Coastguard Worker 	   const char *fname,
154*7304104dSAndroid Build Coastguard Worker 	   const char *what, size_t widx,
155*7304104dSAndroid Build Coastguard Worker 	   const char *member, size_t midx)
156*7304104dSAndroid Build Coastguard Worker {
157*7304104dSAndroid Build Coastguard Worker   if (unlikely (secndx == 0 || secndx == shdrstrndx || secndx >= shdrnum))
158*7304104dSAndroid Build Coastguard Worker     {
159*7304104dSAndroid Build Coastguard Worker       /* Don't use fail... too specialized messages.  Call release
160*7304104dSAndroid Build Coastguard Worker 	 ourselves and then error.  Ignores midx if widx is
161*7304104dSAndroid Build Coastguard Worker 	 zero.  */
162*7304104dSAndroid Build Coastguard Worker       release ();
163*7304104dSAndroid Build Coastguard Worker       if (widx == 0)
164*7304104dSAndroid Build Coastguard Worker 	error (1, 0, "%s: bad section index %zd in %s for %s",
165*7304104dSAndroid Build Coastguard Worker 	       fname, secndx, what, member);
166*7304104dSAndroid Build Coastguard Worker       else if (midx == 0)
167*7304104dSAndroid Build Coastguard Worker 	error (1, 0, "%s: bad section index %zd in %s %zd for %s",
168*7304104dSAndroid Build Coastguard Worker 	       fname, secndx, what, widx, member);
169*7304104dSAndroid Build Coastguard Worker       else
170*7304104dSAndroid Build Coastguard Worker 	error (1, 0, "%s: bad section index %zd in %s %zd for %s %zd",
171*7304104dSAndroid Build Coastguard Worker 	       fname, secndx, what, widx, member, midx);
172*7304104dSAndroid Build Coastguard Worker     }
173*7304104dSAndroid Build Coastguard Worker 
174*7304104dSAndroid Build Coastguard Worker   return secndx < shdrstrndx ? secndx : secndx - 1;
175*7304104dSAndroid Build Coastguard Worker }
176*7304104dSAndroid Build Coastguard Worker 
177*7304104dSAndroid Build Coastguard Worker static void
new_data_buf(Elf_Data * d,const char * fname,size_t ndx,size_t shdrstrndx,size_t shdrnum)178*7304104dSAndroid Build Coastguard Worker new_data_buf (Elf_Data *d, const char *fname,
179*7304104dSAndroid Build Coastguard Worker 	      size_t ndx, size_t shdrstrndx, size_t shdrnum)
180*7304104dSAndroid Build Coastguard Worker {
181*7304104dSAndroid Build Coastguard Worker   size_t s = d->d_size;
182*7304104dSAndroid Build Coastguard Worker   if (s == 0)
183*7304104dSAndroid Build Coastguard Worker     fail_idx ("Expected data in section", fname, ndx);
184*7304104dSAndroid Build Coastguard Worker   void *b = malloc (d->d_size);
185*7304104dSAndroid Build Coastguard Worker   if (b == NULL)
186*7304104dSAndroid Build Coastguard Worker     fail_idx ("Couldn't allocated buffer for section", NULL, ndx);
187*7304104dSAndroid Build Coastguard Worker   newscnbufs[newsecndx (ndx, shdrstrndx, shdrnum, fname,
188*7304104dSAndroid Build Coastguard Worker 			"section", ndx, "d_buf", 0)] = d->d_buf = b;
189*7304104dSAndroid Build Coastguard Worker }
190*7304104dSAndroid Build Coastguard Worker 
191*7304104dSAndroid Build Coastguard Worker int
main(int argc,char ** argv)192*7304104dSAndroid Build Coastguard Worker main (int argc, char **argv)
193*7304104dSAndroid Build Coastguard Worker {
194*7304104dSAndroid Build Coastguard Worker   elf_version (EV_CURRENT);
195*7304104dSAndroid Build Coastguard Worker 
196*7304104dSAndroid Build Coastguard Worker   /* Basic command line handling.  Need to replace the input file?  */
197*7304104dSAndroid Build Coastguard Worker   if ((argc != 2 && argc != 4)
198*7304104dSAndroid Build Coastguard Worker       || (argc == 4 && strcmp (argv[1], "-o") != 0))
199*7304104dSAndroid Build Coastguard Worker     fail ("Usage argument: [-o <outputfile>] <inputfile>", NULL);
200*7304104dSAndroid Build Coastguard Worker   replace = argc == 2;
201*7304104dSAndroid Build Coastguard Worker 
202*7304104dSAndroid Build Coastguard Worker   /* Get the ELF file.  */
203*7304104dSAndroid Build Coastguard Worker   const char *fname;
204*7304104dSAndroid Build Coastguard Worker   if (replace)
205*7304104dSAndroid Build Coastguard Worker     fname = argv[1];
206*7304104dSAndroid Build Coastguard Worker   else
207*7304104dSAndroid Build Coastguard Worker     fname = argv[3];
208*7304104dSAndroid Build Coastguard Worker   fd = open (fname, O_RDONLY);
209*7304104dSAndroid Build Coastguard Worker   if (fd < 0)
210*7304104dSAndroid Build Coastguard Worker     fail_errno ("couldn't open", fname);
211*7304104dSAndroid Build Coastguard Worker 
212*7304104dSAndroid Build Coastguard Worker   elf = elf_begin (fd, ELF_C_READ, NULL);
213*7304104dSAndroid Build Coastguard Worker   if (elf == NULL)
214*7304104dSAndroid Build Coastguard Worker     fail_elf ("couldn't open ELF file for reading", fname);
215*7304104dSAndroid Build Coastguard Worker 
216*7304104dSAndroid Build Coastguard Worker   GElf_Ehdr ehdr;
217*7304104dSAndroid Build Coastguard Worker   if (gelf_getehdr (elf, &ehdr) == NULL)
218*7304104dSAndroid Build Coastguard Worker     fail_elf ("Couldn't get ehdr", fname);
219*7304104dSAndroid Build Coastguard Worker 
220*7304104dSAndroid Build Coastguard Worker   /* Get the section header string table.  */
221*7304104dSAndroid Build Coastguard Worker   size_t shdrstrndx;
222*7304104dSAndroid Build Coastguard Worker   if (elf_getshdrstrndx (elf, &shdrstrndx) != 0)
223*7304104dSAndroid Build Coastguard Worker     fail_elf ("couldn't get section header string table index", fname);
224*7304104dSAndroid Build Coastguard Worker 
225*7304104dSAndroid Build Coastguard Worker   Elf_Scn *shdrstrscn = elf_getscn (elf, shdrstrndx);
226*7304104dSAndroid Build Coastguard Worker   GElf_Shdr shdrstrshdr_mem;
227*7304104dSAndroid Build Coastguard Worker   GElf_Shdr *shdrstrshdr = gelf_getshdr (shdrstrscn, &shdrstrshdr_mem);
228*7304104dSAndroid Build Coastguard Worker   if (shdrstrshdr == NULL)
229*7304104dSAndroid Build Coastguard Worker     fail_elf ("couldn't get section header string table section", fname);
230*7304104dSAndroid Build Coastguard Worker 
231*7304104dSAndroid Build Coastguard Worker   if ((shdrstrshdr->sh_flags & SHF_ALLOC) != 0)
232*7304104dSAndroid Build Coastguard Worker     fail ("section header string table is an allocated section", fname);
233*7304104dSAndroid Build Coastguard Worker 
234*7304104dSAndroid Build Coastguard Worker   /* Get the symtab section.  */
235*7304104dSAndroid Build Coastguard Worker   size_t symtabndx = 0;
236*7304104dSAndroid Build Coastguard Worker   Elf_Scn *symtabscn = NULL;
237*7304104dSAndroid Build Coastguard Worker   GElf_Shdr symtabshdr_mem;
238*7304104dSAndroid Build Coastguard Worker   GElf_Shdr *symtabshdr = NULL;
239*7304104dSAndroid Build Coastguard Worker   while ((symtabscn = elf_nextscn (elf, symtabscn)) != NULL)
240*7304104dSAndroid Build Coastguard Worker     {
241*7304104dSAndroid Build Coastguard Worker       symtabshdr = gelf_getshdr (symtabscn, &symtabshdr_mem);
242*7304104dSAndroid Build Coastguard Worker       if (symtabshdr == NULL)
243*7304104dSAndroid Build Coastguard Worker 	fail_elf ("couldn't get shdr", fname);
244*7304104dSAndroid Build Coastguard Worker 
245*7304104dSAndroid Build Coastguard Worker       if (symtabshdr->sh_type == SHT_SYMTAB)
246*7304104dSAndroid Build Coastguard Worker 	{
247*7304104dSAndroid Build Coastguard Worker 	  /* Just pick the first, we don't expect more than one. */
248*7304104dSAndroid Build Coastguard Worker 	  symtabndx = elf_ndxscn (symtabscn);
249*7304104dSAndroid Build Coastguard Worker 	  break;
250*7304104dSAndroid Build Coastguard Worker 	}
251*7304104dSAndroid Build Coastguard Worker     }
252*7304104dSAndroid Build Coastguard Worker 
253*7304104dSAndroid Build Coastguard Worker   if (symtabshdr == NULL)
254*7304104dSAndroid Build Coastguard Worker     fail ("No symtab found", fname);
255*7304104dSAndroid Build Coastguard Worker 
256*7304104dSAndroid Build Coastguard Worker   if ((symtabshdr->sh_flags & SHF_ALLOC) != 0)
257*7304104dSAndroid Build Coastguard Worker     fail ("symtab is an allocated section", fname);
258*7304104dSAndroid Build Coastguard Worker 
259*7304104dSAndroid Build Coastguard Worker   /* Get the strtab of the symtab.  */
260*7304104dSAndroid Build Coastguard Worker   size_t strtabndx = symtabshdr->sh_link;
261*7304104dSAndroid Build Coastguard Worker   Elf_Scn *strtabscn = elf_getscn (elf, strtabndx);
262*7304104dSAndroid Build Coastguard Worker   GElf_Shdr strtabshdr_mem;
263*7304104dSAndroid Build Coastguard Worker   GElf_Shdr *strtabshdr = gelf_getshdr (strtabscn, &strtabshdr_mem);
264*7304104dSAndroid Build Coastguard Worker   if (strtabshdr == NULL)
265*7304104dSAndroid Build Coastguard Worker     fail_elf ("Couldn't get strtab section", fname);
266*7304104dSAndroid Build Coastguard Worker 
267*7304104dSAndroid Build Coastguard Worker   if (shdrstrndx == strtabndx)
268*7304104dSAndroid Build Coastguard Worker     {
269*7304104dSAndroid Build Coastguard Worker       error (0, 0, "%s: Nothing to do, shstrtab == strtab", fname);
270*7304104dSAndroid Build Coastguard Worker       release ();
271*7304104dSAndroid Build Coastguard Worker       return 0;
272*7304104dSAndroid Build Coastguard Worker     }
273*7304104dSAndroid Build Coastguard Worker 
274*7304104dSAndroid Build Coastguard Worker   if ((strtabshdr->sh_flags & SHF_ALLOC) != 0)
275*7304104dSAndroid Build Coastguard Worker     fail ("strtab is an allocated section", fname);
276*7304104dSAndroid Build Coastguard Worker 
277*7304104dSAndroid Build Coastguard Worker   size_t phnum;
278*7304104dSAndroid Build Coastguard Worker   if (elf_getphdrnum (elf, &phnum) != 0)
279*7304104dSAndroid Build Coastguard Worker     fail_elf ("Couldn't get number of phdrs", fname);
280*7304104dSAndroid Build Coastguard Worker 
281*7304104dSAndroid Build Coastguard Worker   /* If there are phdrs we want to maintain the layout of the
282*7304104dSAndroid Build Coastguard Worker      allocated sections in the file.  */
283*7304104dSAndroid Build Coastguard Worker   bool layout = phnum != 0;
284*7304104dSAndroid Build Coastguard Worker 
285*7304104dSAndroid Build Coastguard Worker   /* Create a new merged strings table that starts with the empty string.  */
286*7304104dSAndroid Build Coastguard Worker   strings = dwelf_strtab_init (true);
287*7304104dSAndroid Build Coastguard Worker   if (strings == NULL)
288*7304104dSAndroid Build Coastguard Worker     fail ("No memory to create merged string table", NULL);
289*7304104dSAndroid Build Coastguard Worker 
290*7304104dSAndroid Build Coastguard Worker   /* Add the strings from all the sections.  */
291*7304104dSAndroid Build Coastguard Worker   size_t shdrnum;
292*7304104dSAndroid Build Coastguard Worker   if (elf_getshdrnum (elf, &shdrnum) != 0)
293*7304104dSAndroid Build Coastguard Worker     fail_elf ("Couldn't get number of sections", fname);
294*7304104dSAndroid Build Coastguard Worker   scnstrents = malloc (shdrnum * sizeof (Dwelf_Strent *));
295*7304104dSAndroid Build Coastguard Worker   if (scnstrents == NULL)
296*7304104dSAndroid Build Coastguard Worker     fail ("couldn't allocate memory for section strings", NULL);
297*7304104dSAndroid Build Coastguard Worker 
298*7304104dSAndroid Build Coastguard Worker   /* While going through all sections keep track of last allocated
299*7304104dSAndroid Build Coastguard Worker      offset if needed to keep the layout.  We'll put any unallocated
300*7304104dSAndroid Build Coastguard Worker      sections behind those (strtab is unallocated and will change
301*7304104dSAndroid Build Coastguard Worker      size).  */
302*7304104dSAndroid Build Coastguard Worker   GElf_Off last_offset = 0;
303*7304104dSAndroid Build Coastguard Worker   if (layout)
304*7304104dSAndroid Build Coastguard Worker     last_offset = (ehdr.e_phoff
305*7304104dSAndroid Build Coastguard Worker 		   + gelf_fsize (elf, ELF_T_PHDR, phnum, EV_CURRENT));
306*7304104dSAndroid Build Coastguard Worker   Elf_Scn *scn = NULL;
307*7304104dSAndroid Build Coastguard Worker   while ((scn = elf_nextscn (elf, scn)) != NULL)
308*7304104dSAndroid Build Coastguard Worker     {
309*7304104dSAndroid Build Coastguard Worker       size_t scnnum = elf_ndxscn (scn);
310*7304104dSAndroid Build Coastguard Worker       GElf_Shdr shdr_mem;
311*7304104dSAndroid Build Coastguard Worker       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
312*7304104dSAndroid Build Coastguard Worker       if (shdr == NULL)
313*7304104dSAndroid Build Coastguard Worker 	fail_elf_idx ("couldn't get shdr", fname, scnnum);
314*7304104dSAndroid Build Coastguard Worker       /* Don't add the .shstrtab section itself, we'll not use it.  */
315*7304104dSAndroid Build Coastguard Worker       if (shdr->sh_name != 0 && scnnum != shdrstrndx)
316*7304104dSAndroid Build Coastguard Worker 	{
317*7304104dSAndroid Build Coastguard Worker 	  const char *sname = elf_strptr (elf, shdrstrndx, shdr->sh_name);
318*7304104dSAndroid Build Coastguard Worker 	  if (sname == NULL)
319*7304104dSAndroid Build Coastguard Worker 	    fail_elf_idx ("couldn't get section name", fname, scnnum);
320*7304104dSAndroid Build Coastguard Worker 	  if ((scnstrents[scnnum] = dwelf_strtab_add (strings, sname)) == NULL)
321*7304104dSAndroid Build Coastguard Worker 	    fail ("No memory to add to merged string table", NULL);
322*7304104dSAndroid Build Coastguard Worker 	}
323*7304104dSAndroid Build Coastguard Worker 
324*7304104dSAndroid Build Coastguard Worker       if (layout)
325*7304104dSAndroid Build Coastguard Worker 	if ((shdr->sh_flags & SHF_ALLOC) != 0)
326*7304104dSAndroid Build Coastguard Worker 	  {
327*7304104dSAndroid Build Coastguard Worker 	    GElf_Off off = shdr->sh_offset + (shdr->sh_type != SHT_NOBITS
328*7304104dSAndroid Build Coastguard Worker 					      ? shdr->sh_size : 0);
329*7304104dSAndroid Build Coastguard Worker 	    if (last_offset < off)
330*7304104dSAndroid Build Coastguard Worker 	      last_offset = off;
331*7304104dSAndroid Build Coastguard Worker 	  }
332*7304104dSAndroid Build Coastguard Worker     }
333*7304104dSAndroid Build Coastguard Worker 
334*7304104dSAndroid Build Coastguard Worker   /* Add the strings from all the symbols.  */
335*7304104dSAndroid Build Coastguard Worker   size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
336*7304104dSAndroid Build Coastguard Worker   Elf_Data *symd = elf_getdata (symtabscn, NULL);
337*7304104dSAndroid Build Coastguard Worker   if (symd == NULL)
338*7304104dSAndroid Build Coastguard Worker     fail_elf ("couldn't get symtab data", fname);
339*7304104dSAndroid Build Coastguard Worker   size_t symsnum = symd->d_size / elsize;
340*7304104dSAndroid Build Coastguard Worker   symstrents = malloc (symsnum * sizeof (Dwelf_Strent *));
341*7304104dSAndroid Build Coastguard Worker   if (symstrents == NULL)
342*7304104dSAndroid Build Coastguard Worker     fail_errno ("Couldn't allocate memory for symbol strings", NULL);
343*7304104dSAndroid Build Coastguard Worker   for (size_t i = 0; i < symsnum; i++)
344*7304104dSAndroid Build Coastguard Worker     {
345*7304104dSAndroid Build Coastguard Worker       GElf_Sym sym_mem;
346*7304104dSAndroid Build Coastguard Worker       GElf_Sym *sym = gelf_getsym (symd, i, &sym_mem);
347*7304104dSAndroid Build Coastguard Worker       if (sym == NULL)
348*7304104dSAndroid Build Coastguard Worker 	fail_elf_idx ("Couldn't get symbol", fname, i);
349*7304104dSAndroid Build Coastguard Worker       if (sym->st_name != 0)
350*7304104dSAndroid Build Coastguard Worker 	{
351*7304104dSAndroid Build Coastguard Worker 	  const char *sname = elf_strptr (elf, strtabndx, sym->st_name);
352*7304104dSAndroid Build Coastguard Worker 	  if (sname == NULL)
353*7304104dSAndroid Build Coastguard Worker 	    fail_elf_idx ("Couldn't get symbol name", fname, i);
354*7304104dSAndroid Build Coastguard Worker 	  if ((symstrents[i] = dwelf_strtab_add (strings, sname)) == NULL)
355*7304104dSAndroid Build Coastguard Worker 	    fail_idx ("No memory to add to merged string table symbol",
356*7304104dSAndroid Build Coastguard Worker 		      fname, i);
357*7304104dSAndroid Build Coastguard Worker 	}
358*7304104dSAndroid Build Coastguard Worker     }
359*7304104dSAndroid Build Coastguard Worker 
360*7304104dSAndroid Build Coastguard Worker   /* We got all strings, build the new string table and store it as
361*7304104dSAndroid Build Coastguard Worker      new strtab.  */
362*7304104dSAndroid Build Coastguard Worker   dwelf_strtab_finalize (strings, &newstrtabdata);
363*7304104dSAndroid Build Coastguard Worker 
364*7304104dSAndroid Build Coastguard Worker   /* We share at least the empty string so the result is at least 1
365*7304104dSAndroid Build Coastguard Worker      byte smaller.  */
366*7304104dSAndroid Build Coastguard Worker   if (newstrtabdata.d_size >= shdrstrshdr->sh_size + strtabshdr->sh_size)
367*7304104dSAndroid Build Coastguard Worker     fail ("Impossible, merged string table is larger", fname);
368*7304104dSAndroid Build Coastguard Worker 
369*7304104dSAndroid Build Coastguard Worker   struct stat st;
370*7304104dSAndroid Build Coastguard Worker   if (fstat (fd, &st) != 0)
371*7304104dSAndroid Build Coastguard Worker     fail_errno("Couldn't fstat", fname);
372*7304104dSAndroid Build Coastguard Worker 
373*7304104dSAndroid Build Coastguard Worker   /* Create a new (temporary) ELF file for the result.  */
374*7304104dSAndroid Build Coastguard Worker   if (replace)
375*7304104dSAndroid Build Coastguard Worker     {
376*7304104dSAndroid Build Coastguard Worker       size_t fname_len = strlen (fname);
377*7304104dSAndroid Build Coastguard Worker       fnew = malloc (fname_len + sizeof (".XXXXXX"));
378*7304104dSAndroid Build Coastguard Worker       if (fnew == NULL)
379*7304104dSAndroid Build Coastguard Worker 	fail_errno ("couldn't allocate memory for new file name", NULL);
380*7304104dSAndroid Build Coastguard Worker       strcpy (mempcpy (fnew, fname, fname_len), ".XXXXXX");
381*7304104dSAndroid Build Coastguard Worker 
382*7304104dSAndroid Build Coastguard Worker       fdnew = mkstemp (fnew);
383*7304104dSAndroid Build Coastguard Worker     }
384*7304104dSAndroid Build Coastguard Worker   else
385*7304104dSAndroid Build Coastguard Worker     {
386*7304104dSAndroid Build Coastguard Worker       fnew = argv[2];
387*7304104dSAndroid Build Coastguard Worker       fdnew = open (fnew, O_WRONLY | O_CREAT, st.st_mode & ALLPERMS);
388*7304104dSAndroid Build Coastguard Worker     }
389*7304104dSAndroid Build Coastguard Worker 
390*7304104dSAndroid Build Coastguard Worker   if (fdnew < 0)
391*7304104dSAndroid Build Coastguard Worker     fail_errno ("couldn't create output file", fnew);
392*7304104dSAndroid Build Coastguard Worker 
393*7304104dSAndroid Build Coastguard Worker   elfnew = elf_begin (fdnew, ELF_C_WRITE, NULL);
394*7304104dSAndroid Build Coastguard Worker   if (elfnew == NULL)
395*7304104dSAndroid Build Coastguard Worker     fail_elf ("couldn't open new ELF for writing", fnew);
396*7304104dSAndroid Build Coastguard Worker 
397*7304104dSAndroid Build Coastguard Worker   /* Create the new ELF header and copy over all the data.  */
398*7304104dSAndroid Build Coastguard Worker   if (gelf_newehdr (elfnew, gelf_getclass (elf)) == 0)
399*7304104dSAndroid Build Coastguard Worker     fail_elf ("Couldn't create new ehdr", fnew);
400*7304104dSAndroid Build Coastguard Worker   GElf_Ehdr newehdr;
401*7304104dSAndroid Build Coastguard Worker   if (gelf_getehdr (elfnew, &newehdr) == NULL)
402*7304104dSAndroid Build Coastguard Worker     fail_elf ("Couldn't get ehdr", fnew);
403*7304104dSAndroid Build Coastguard Worker 
404*7304104dSAndroid Build Coastguard Worker   newehdr.e_ident[EI_DATA] = ehdr.e_ident[EI_DATA];
405*7304104dSAndroid Build Coastguard Worker   newehdr.e_type = ehdr.e_type;
406*7304104dSAndroid Build Coastguard Worker   newehdr.e_machine = ehdr.e_machine;
407*7304104dSAndroid Build Coastguard Worker   newehdr.e_version = ehdr.e_version;
408*7304104dSAndroid Build Coastguard Worker   newehdr.e_entry = ehdr.e_entry;
409*7304104dSAndroid Build Coastguard Worker   newehdr.e_flags = ehdr.e_flags;
410*7304104dSAndroid Build Coastguard Worker 
411*7304104dSAndroid Build Coastguard Worker   /* The new file uses the new strtab as shstrtab.  */
412*7304104dSAndroid Build Coastguard Worker   size_t newstrtabndx = newsecndx (strtabndx, shdrstrndx, shdrnum,
413*7304104dSAndroid Build Coastguard Worker 				   fname, "ehdr", 0, "e_shstrndx", 0);
414*7304104dSAndroid Build Coastguard Worker   if (newstrtabndx < SHN_LORESERVE)
415*7304104dSAndroid Build Coastguard Worker     newehdr.e_shstrndx = newstrtabndx;
416*7304104dSAndroid Build Coastguard Worker   else
417*7304104dSAndroid Build Coastguard Worker     {
418*7304104dSAndroid Build Coastguard Worker       Elf_Scn *zscn = elf_getscn (elfnew, 0);
419*7304104dSAndroid Build Coastguard Worker       GElf_Shdr zshdr_mem;
420*7304104dSAndroid Build Coastguard Worker       GElf_Shdr *zshdr = gelf_getshdr (zscn, &zshdr_mem);
421*7304104dSAndroid Build Coastguard Worker       if (zshdr == NULL)
422*7304104dSAndroid Build Coastguard Worker 	fail_elf ("Couldn't get section zero", fnew);
423*7304104dSAndroid Build Coastguard Worker       zshdr->sh_link = strtabndx;
424*7304104dSAndroid Build Coastguard Worker       if (gelf_update_shdr (zscn, zshdr) == 0)
425*7304104dSAndroid Build Coastguard Worker 	fail_elf ("Couldn't update section zero", fnew);
426*7304104dSAndroid Build Coastguard Worker       newehdr.e_shstrndx = SHN_XINDEX;
427*7304104dSAndroid Build Coastguard Worker     }
428*7304104dSAndroid Build Coastguard Worker 
429*7304104dSAndroid Build Coastguard Worker   if (gelf_update_ehdr (elfnew, &newehdr) == 0)
430*7304104dSAndroid Build Coastguard Worker     fail ("Couldn't update ehdr", fnew);
431*7304104dSAndroid Build Coastguard Worker 
432*7304104dSAndroid Build Coastguard Worker   /* Copy the program headers if any.  */
433*7304104dSAndroid Build Coastguard Worker   if (phnum != 0)
434*7304104dSAndroid Build Coastguard Worker     {
435*7304104dSAndroid Build Coastguard Worker       if (gelf_newphdr (elfnew, phnum) == 0)
436*7304104dSAndroid Build Coastguard Worker 	fail_elf ("Couldn't create phdrs", fnew);
437*7304104dSAndroid Build Coastguard Worker 
438*7304104dSAndroid Build Coastguard Worker       for (size_t cnt = 0; cnt < phnum; ++cnt)
439*7304104dSAndroid Build Coastguard Worker 	{
440*7304104dSAndroid Build Coastguard Worker 	  GElf_Phdr phdr_mem;
441*7304104dSAndroid Build Coastguard Worker 	  GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
442*7304104dSAndroid Build Coastguard Worker 	  if (phdr == NULL)
443*7304104dSAndroid Build Coastguard Worker 	    fail_elf_idx ("Couldn't get phdr", fname, cnt);
444*7304104dSAndroid Build Coastguard Worker 	  if (gelf_update_phdr (elfnew, cnt, phdr) == 0)
445*7304104dSAndroid Build Coastguard Worker 	    fail_elf_idx ("Couldn't create phdr", fnew, cnt);
446*7304104dSAndroid Build Coastguard Worker 	}
447*7304104dSAndroid Build Coastguard Worker     }
448*7304104dSAndroid Build Coastguard Worker 
449*7304104dSAndroid Build Coastguard Worker   newshnums = shdrnum - 1;
450*7304104dSAndroid Build Coastguard Worker   newscnbufs = calloc (newshnums, sizeof (void *));
451*7304104dSAndroid Build Coastguard Worker   if (newscnbufs == NULL)
452*7304104dSAndroid Build Coastguard Worker     fail_errno ("Couldn't allocate memory for new section buffers", NULL);
453*7304104dSAndroid Build Coastguard Worker 
454*7304104dSAndroid Build Coastguard Worker   /* Copy the sections, except the shstrtab, fill the strtab with the
455*7304104dSAndroid Build Coastguard Worker      combined strings and adjust section references.  */
456*7304104dSAndroid Build Coastguard Worker   while ((scn = elf_nextscn (elf, scn)) != NULL)
457*7304104dSAndroid Build Coastguard Worker     {
458*7304104dSAndroid Build Coastguard Worker       size_t ndx = elf_ndxscn (scn);
459*7304104dSAndroid Build Coastguard Worker 
460*7304104dSAndroid Build Coastguard Worker       GElf_Shdr shdr_mem;
461*7304104dSAndroid Build Coastguard Worker       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
462*7304104dSAndroid Build Coastguard Worker       if (shdr == NULL)
463*7304104dSAndroid Build Coastguard Worker 	fail_elf_idx ("Couldn't get shdr", fname, ndx);
464*7304104dSAndroid Build Coastguard Worker 
465*7304104dSAndroid Build Coastguard Worker       /* Section zero is always created.  Skip the shtrtab.  */
466*7304104dSAndroid Build Coastguard Worker       if (ndx == 0 || ndx == shdrstrndx)
467*7304104dSAndroid Build Coastguard Worker 	continue;
468*7304104dSAndroid Build Coastguard Worker 
469*7304104dSAndroid Build Coastguard Worker       Elf_Scn *newscn = elf_newscn (elfnew);
470*7304104dSAndroid Build Coastguard Worker       if (newscn == NULL)
471*7304104dSAndroid Build Coastguard Worker 	fail_elf_idx ("couldn't create new section", fnew, ndx);
472*7304104dSAndroid Build Coastguard Worker 
473*7304104dSAndroid Build Coastguard Worker       GElf_Shdr newshdr;
474*7304104dSAndroid Build Coastguard Worker       newshdr.sh_name = (shdr->sh_name != 0
475*7304104dSAndroid Build Coastguard Worker 			 ? dwelf_strent_off (scnstrents[ndx]) : 0);
476*7304104dSAndroid Build Coastguard Worker       newshdr.sh_type = shdr->sh_type;
477*7304104dSAndroid Build Coastguard Worker       newshdr.sh_flags = shdr->sh_flags;
478*7304104dSAndroid Build Coastguard Worker       newshdr.sh_addr = shdr->sh_addr;
479*7304104dSAndroid Build Coastguard Worker       newshdr.sh_size = shdr->sh_size;
480*7304104dSAndroid Build Coastguard Worker       if (shdr->sh_link != 0)
481*7304104dSAndroid Build Coastguard Worker 	newshdr.sh_link = newsecndx (shdr->sh_link, shdrstrndx, shdrnum,
482*7304104dSAndroid Build Coastguard Worker 				     fname, "shdr", ndx, "sh_link", 0);
483*7304104dSAndroid Build Coastguard Worker       else
484*7304104dSAndroid Build Coastguard Worker 	newshdr.sh_link = 0;
485*7304104dSAndroid Build Coastguard Worker       if (SH_INFO_LINK_P (shdr) && shdr->sh_info != 0)
486*7304104dSAndroid Build Coastguard Worker 	newshdr.sh_info = newsecndx (shdr->sh_info, shdrstrndx, shdrnum,
487*7304104dSAndroid Build Coastguard Worker 				     fname, "shdr", ndx, "sh_info", 0);
488*7304104dSAndroid Build Coastguard Worker 
489*7304104dSAndroid Build Coastguard Worker       else
490*7304104dSAndroid Build Coastguard Worker 	newshdr.sh_info = shdr->sh_info;
491*7304104dSAndroid Build Coastguard Worker       newshdr.sh_entsize = shdr->sh_entsize;
492*7304104dSAndroid Build Coastguard Worker 
493*7304104dSAndroid Build Coastguard Worker       /* Some sections need a new data buffer because they need to
494*7304104dSAndroid Build Coastguard Worker 	 manipulate the original data.  Allocate and check here, so we
495*7304104dSAndroid Build Coastguard Worker 	 have a list of all data buffers we might need to release when
496*7304104dSAndroid Build Coastguard Worker 	 done.  */
497*7304104dSAndroid Build Coastguard Worker       Elf_Data *newdata = elf_newdata (newscn);
498*7304104dSAndroid Build Coastguard Worker       if (newdata == NULL)
499*7304104dSAndroid Build Coastguard Worker 	fail_elf_idx ("Couldn't create new data for section", fnew, ndx);
500*7304104dSAndroid Build Coastguard Worker       if (ndx == strtabndx)
501*7304104dSAndroid Build Coastguard Worker 	*newdata = newstrtabdata;
502*7304104dSAndroid Build Coastguard Worker       else
503*7304104dSAndroid Build Coastguard Worker 	{
504*7304104dSAndroid Build Coastguard Worker 	  /* The symtab, dynsym, group and symtab_shndx sections
505*7304104dSAndroid Build Coastguard Worker 	     contain section indexes. Symbol tables (symtab and
506*7304104dSAndroid Build Coastguard Worker 	     dynsym) contain indexes to strings. Update both if
507*7304104dSAndroid Build Coastguard Worker 	     necessary.  */
508*7304104dSAndroid Build Coastguard Worker 	  Elf_Data *data = elf_getdata (scn, NULL);
509*7304104dSAndroid Build Coastguard Worker 	  if (data == NULL)
510*7304104dSAndroid Build Coastguard Worker 	    fail_elf_idx ("Couldn't get data from section", fname, ndx);
511*7304104dSAndroid Build Coastguard Worker 	  *newdata = *data;
512*7304104dSAndroid Build Coastguard Worker 	  switch (shdr->sh_type)
513*7304104dSAndroid Build Coastguard Worker 	    {
514*7304104dSAndroid Build Coastguard Worker 	    case SHT_SYMTAB:
515*7304104dSAndroid Build Coastguard Worker 	    case SHT_DYNSYM:
516*7304104dSAndroid Build Coastguard Worker 	      {
517*7304104dSAndroid Build Coastguard Worker 		/* We need to update the section numbers of the
518*7304104dSAndroid Build Coastguard Worker 		   symbols and if this symbol table uses the strtab
519*7304104dSAndroid Build Coastguard Worker 		   section also the name indexes.  */
520*7304104dSAndroid Build Coastguard Worker 		const bool update_name = shdr->sh_link == strtabndx;
521*7304104dSAndroid Build Coastguard Worker 		if (update_name && ndx != symtabndx)
522*7304104dSAndroid Build Coastguard Worker 		  fail ("Only one symbol table using strtab expected", fname);
523*7304104dSAndroid Build Coastguard Worker 		new_data_buf (newdata, fname, ndx, shdrstrndx, shdrnum);
524*7304104dSAndroid Build Coastguard Worker 		size_t syms = (data->d_size
525*7304104dSAndroid Build Coastguard Worker 			       / gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT));
526*7304104dSAndroid Build Coastguard Worker 		for (size_t i = 0; i < syms; i++)
527*7304104dSAndroid Build Coastguard Worker 		  {
528*7304104dSAndroid Build Coastguard Worker 		    GElf_Sym sym;
529*7304104dSAndroid Build Coastguard Worker 		    if (gelf_getsym (data, i, &sym) == NULL)
530*7304104dSAndroid Build Coastguard Worker 		      fail_elf_idx ("Couldn't get symbol", fname, i);
531*7304104dSAndroid Build Coastguard Worker 
532*7304104dSAndroid Build Coastguard Worker 		    if (GELF_ST_TYPE (sym.st_info) == STT_SECTION
533*7304104dSAndroid Build Coastguard Worker 			&& sym.st_shndx == shdrstrndx)
534*7304104dSAndroid Build Coastguard Worker 		      fprintf (stderr, "WARNING:"
535*7304104dSAndroid Build Coastguard Worker 			       " symbol table [%zd] contains section symbol %zd"
536*7304104dSAndroid Build Coastguard Worker 			       " for old shdrstrndx %zd\n", ndx, i, shdrstrndx);
537*7304104dSAndroid Build Coastguard Worker 		    else if (sym.st_shndx != SHN_UNDEF
538*7304104dSAndroid Build Coastguard Worker 			     && sym.st_shndx < SHN_LORESERVE)
539*7304104dSAndroid Build Coastguard Worker 		      sym.st_shndx = newsecndx (sym.st_shndx, shdrstrndx, shdrnum,
540*7304104dSAndroid Build Coastguard Worker 					 fname, "section", ndx, "symbol", i);
541*7304104dSAndroid Build Coastguard Worker 		    if (update_name && sym.st_name != 0)
542*7304104dSAndroid Build Coastguard Worker 		      sym.st_name = dwelf_strent_off (symstrents[i]);
543*7304104dSAndroid Build Coastguard Worker 
544*7304104dSAndroid Build Coastguard Worker 		    /* We explicitly don't update the SHNDX table at
545*7304104dSAndroid Build Coastguard Worker 		       the same time, we do that below.  */
546*7304104dSAndroid Build Coastguard Worker 		    if (gelf_update_sym (newdata, i, &sym) == 0)
547*7304104dSAndroid Build Coastguard Worker 		      fail_elf_idx ("Couldn't update symbol", fnew, i);
548*7304104dSAndroid Build Coastguard Worker 		  }
549*7304104dSAndroid Build Coastguard Worker 	      }
550*7304104dSAndroid Build Coastguard Worker 	      break;
551*7304104dSAndroid Build Coastguard Worker 
552*7304104dSAndroid Build Coastguard Worker 	    case SHT_GROUP:
553*7304104dSAndroid Build Coastguard Worker 	      {
554*7304104dSAndroid Build Coastguard Worker 		new_data_buf (newdata, fname, ndx, shdrstrndx, shdrnum);
555*7304104dSAndroid Build Coastguard Worker 		/* A section group contains Elf32_Words. The first
556*7304104dSAndroid Build Coastguard Worker 		   word is a flag value, the rest of the words are
557*7304104dSAndroid Build Coastguard Worker 		   indexes of the sections belonging to the group.  */
558*7304104dSAndroid Build Coastguard Worker 		Elf32_Word *group = (Elf32_Word *) data->d_buf;
559*7304104dSAndroid Build Coastguard Worker 		Elf32_Word *newgroup = (Elf32_Word *) newdata->d_buf;
560*7304104dSAndroid Build Coastguard Worker 		size_t words = data->d_size / sizeof (Elf32_Word);
561*7304104dSAndroid Build Coastguard Worker 		if (words == 0)
562*7304104dSAndroid Build Coastguard Worker 		  fail_idx ("Not enough data in group section", fname, ndx);
563*7304104dSAndroid Build Coastguard Worker 		newgroup[0] = group[0];
564*7304104dSAndroid Build Coastguard Worker 		for (size_t i = 1; i < words; i++)
565*7304104dSAndroid Build Coastguard Worker 		  newgroup[i] = newsecndx (group[i], shdrstrndx, shdrnum,
566*7304104dSAndroid Build Coastguard Worker 					   fname, "section", ndx, "group", i);
567*7304104dSAndroid Build Coastguard Worker 	      }
568*7304104dSAndroid Build Coastguard Worker 	      break;
569*7304104dSAndroid Build Coastguard Worker 
570*7304104dSAndroid Build Coastguard Worker 	    case SHT_SYMTAB_SHNDX:
571*7304104dSAndroid Build Coastguard Worker 	      {
572*7304104dSAndroid Build Coastguard Worker 		new_data_buf (newdata, fname, ndx, shdrstrndx, shdrnum);
573*7304104dSAndroid Build Coastguard Worker 		/* A SHNDX just contains an array of section indexes
574*7304104dSAndroid Build Coastguard Worker 		   for the corresponding symbol table.  The entry is
575*7304104dSAndroid Build Coastguard Worker 		   SHN_UNDEF unless the corresponding symbol is
576*7304104dSAndroid Build Coastguard Worker 		   SHN_XINDEX.  */
577*7304104dSAndroid Build Coastguard Worker 		Elf32_Word *shndx = (Elf32_Word *) data->d_buf;
578*7304104dSAndroid Build Coastguard Worker 		Elf32_Word *newshndx = (Elf32_Word *) newdata->d_buf;
579*7304104dSAndroid Build Coastguard Worker 		size_t words = data->d_size / sizeof (Elf32_Word);
580*7304104dSAndroid Build Coastguard Worker 		for (size_t i = 0; i < words; i++)
581*7304104dSAndroid Build Coastguard Worker 		  if (shndx[i] == SHN_UNDEF)
582*7304104dSAndroid Build Coastguard Worker 		    newshndx[i] = SHN_UNDEF;
583*7304104dSAndroid Build Coastguard Worker 		  else
584*7304104dSAndroid Build Coastguard Worker 		    newshndx[i] = newsecndx (shndx[i], shdrstrndx, shdrnum,
585*7304104dSAndroid Build Coastguard Worker 					     fname, "section", ndx, "shndx", i);
586*7304104dSAndroid Build Coastguard Worker 	      }
587*7304104dSAndroid Build Coastguard Worker 	      break;
588*7304104dSAndroid Build Coastguard Worker 
589*7304104dSAndroid Build Coastguard Worker 	    case SHT_DYNAMIC:
590*7304104dSAndroid Build Coastguard Worker 	      FALLTHROUGH;
591*7304104dSAndroid Build Coastguard Worker 	      /* There are string indexes in here, but
592*7304104dSAndroid Build Coastguard Worker 		 they (should) point to a allocated string table,
593*7304104dSAndroid Build Coastguard Worker 		 which we don't alter.  */
594*7304104dSAndroid Build Coastguard Worker 	    default:
595*7304104dSAndroid Build Coastguard Worker 	      /* Nothing to do.  Section data doesn't contain section
596*7304104dSAndroid Build Coastguard Worker 		 or strtab indexes.  */
597*7304104dSAndroid Build Coastguard Worker 	      break;
598*7304104dSAndroid Build Coastguard Worker 	    }
599*7304104dSAndroid Build Coastguard Worker 	}
600*7304104dSAndroid Build Coastguard Worker 
601*7304104dSAndroid Build Coastguard Worker       /* When we are responsible for the layout explicitly set
602*7304104dSAndroid Build Coastguard Worker 	 sh_addralign, sh_size and sh_offset.  Otherwise libelf will
603*7304104dSAndroid Build Coastguard Worker 	 calculate those from the Elf_Data.  */
604*7304104dSAndroid Build Coastguard Worker       if (layout)
605*7304104dSAndroid Build Coastguard Worker 	{
606*7304104dSAndroid Build Coastguard Worker 	  /* We have just one Elf_Data.  */
607*7304104dSAndroid Build Coastguard Worker 	  newshdr.sh_size = newdata->d_size;
608*7304104dSAndroid Build Coastguard Worker 	  newshdr.sh_addralign = newdata->d_align;
609*7304104dSAndroid Build Coastguard Worker 
610*7304104dSAndroid Build Coastguard Worker 	  /* Keep the offset of allocated sections so they are at the
611*7304104dSAndroid Build Coastguard Worker 	     same place in the file. Add unallocated ones after the
612*7304104dSAndroid Build Coastguard Worker 	     allocated ones.  */
613*7304104dSAndroid Build Coastguard Worker 	  if ((shdr->sh_flags & SHF_ALLOC) != 0)
614*7304104dSAndroid Build Coastguard Worker 	    newshdr.sh_offset = shdr->sh_offset;
615*7304104dSAndroid Build Coastguard Worker 	  else
616*7304104dSAndroid Build Coastguard Worker 	    {
617*7304104dSAndroid Build Coastguard Worker 	      /* Zero means one.  No alignment constraints.  */
618*7304104dSAndroid Build Coastguard Worker 	      size_t addralign = newshdr.sh_addralign ?: 1;
619*7304104dSAndroid Build Coastguard Worker 	      last_offset = (last_offset + addralign - 1) & ~(addralign - 1);
620*7304104dSAndroid Build Coastguard Worker 	      newshdr.sh_offset = last_offset;
621*7304104dSAndroid Build Coastguard Worker 	      if (newshdr.sh_type != SHT_NOBITS)
622*7304104dSAndroid Build Coastguard Worker 		last_offset += newshdr.sh_size;
623*7304104dSAndroid Build Coastguard Worker 	    }
624*7304104dSAndroid Build Coastguard Worker 	}
625*7304104dSAndroid Build Coastguard Worker       else
626*7304104dSAndroid Build Coastguard Worker 	{
627*7304104dSAndroid Build Coastguard Worker 	  newshdr.sh_addralign = 0;
628*7304104dSAndroid Build Coastguard Worker 	  newshdr.sh_size = 0;
629*7304104dSAndroid Build Coastguard Worker 	  newshdr.sh_offset = 0;
630*7304104dSAndroid Build Coastguard Worker 	}
631*7304104dSAndroid Build Coastguard Worker 
632*7304104dSAndroid Build Coastguard Worker       if (gelf_update_shdr (newscn, &newshdr) == 0)
633*7304104dSAndroid Build Coastguard Worker 	fail_elf_idx ("Couldn't update section header", fnew, ndx);
634*7304104dSAndroid Build Coastguard Worker     }
635*7304104dSAndroid Build Coastguard Worker 
636*7304104dSAndroid Build Coastguard Worker   /* If we have phdrs we want elf_update to layout the SHF_ALLOC
637*7304104dSAndroid Build Coastguard Worker      sections precisely as in the original file.  In that case we are
638*7304104dSAndroid Build Coastguard Worker      also responsible for setting phoff and shoff */
639*7304104dSAndroid Build Coastguard Worker   if (layout)
640*7304104dSAndroid Build Coastguard Worker     {
641*7304104dSAndroid Build Coastguard Worker       /* Position the shdrs after the last (unallocated) section.  */
642*7304104dSAndroid Build Coastguard Worker       if (gelf_getehdr (elfnew, &newehdr) == NULL)
643*7304104dSAndroid Build Coastguard Worker 	fail_elf ("Couldn't get ehdr", fnew);
644*7304104dSAndroid Build Coastguard Worker       const size_t offsize = gelf_fsize (elf, ELF_T_OFF, 1, EV_CURRENT);
645*7304104dSAndroid Build Coastguard Worker       newehdr.e_shoff = ((last_offset + offsize - 1)
646*7304104dSAndroid Build Coastguard Worker 			 & ~((GElf_Off) (offsize - 1)));
647*7304104dSAndroid Build Coastguard Worker 
648*7304104dSAndroid Build Coastguard Worker       /* The phdrs go in the same place as in the original file.
649*7304104dSAndroid Build Coastguard Worker 	 Normally right after the ELF header.  */
650*7304104dSAndroid Build Coastguard Worker       newehdr.e_phoff = ehdr.e_phoff;
651*7304104dSAndroid Build Coastguard Worker 
652*7304104dSAndroid Build Coastguard Worker       if (gelf_update_ehdr (elfnew, &newehdr) == 0)
653*7304104dSAndroid Build Coastguard Worker 	fail_elf ("Couldn't update ehdr", fnew);
654*7304104dSAndroid Build Coastguard Worker 
655*7304104dSAndroid Build Coastguard Worker       elf_flagelf (elfnew, ELF_C_SET, ELF_F_LAYOUT);
656*7304104dSAndroid Build Coastguard Worker     }
657*7304104dSAndroid Build Coastguard Worker 
658*7304104dSAndroid Build Coastguard Worker   if (elf_update (elfnew, ELF_C_WRITE) == -1)
659*7304104dSAndroid Build Coastguard Worker     fail_elf ("Couldn't write ELF", fnew);
660*7304104dSAndroid Build Coastguard Worker 
661*7304104dSAndroid Build Coastguard Worker   elf_end (elfnew);
662*7304104dSAndroid Build Coastguard Worker   elfnew = NULL;
663*7304104dSAndroid Build Coastguard Worker 
664*7304104dSAndroid Build Coastguard Worker   /* Try to match mode and owner.group of the original file.  */
665*7304104dSAndroid Build Coastguard Worker   if (fchmod (fdnew, st.st_mode & ALLPERMS) != 0)
666*7304104dSAndroid Build Coastguard Worker     error (0, errno, "Couldn't fchmod %s", fnew);
667*7304104dSAndroid Build Coastguard Worker   if (fchown (fdnew, st.st_uid, st.st_gid) != 0)
668*7304104dSAndroid Build Coastguard Worker     error (0, errno, "Couldn't fchown %s", fnew);
669*7304104dSAndroid Build Coastguard Worker 
670*7304104dSAndroid Build Coastguard Worker   /* Finally replace the old file with the new merged strings file.  */
671*7304104dSAndroid Build Coastguard Worker   if (replace)
672*7304104dSAndroid Build Coastguard Worker     if (rename (fnew, fname) != 0)
673*7304104dSAndroid Build Coastguard Worker       fail_errno ("rename", fnew);
674*7304104dSAndroid Build Coastguard Worker 
675*7304104dSAndroid Build Coastguard Worker   /* We are finally done with the new file, don't unlink it now.  */
676*7304104dSAndroid Build Coastguard Worker   close (fdnew);
677*7304104dSAndroid Build Coastguard Worker   if (replace)
678*7304104dSAndroid Build Coastguard Worker     free (fnew);
679*7304104dSAndroid Build Coastguard Worker   fnew = NULL;
680*7304104dSAndroid Build Coastguard Worker   fdnew = -1;
681*7304104dSAndroid Build Coastguard Worker 
682*7304104dSAndroid Build Coastguard Worker   release ();
683*7304104dSAndroid Build Coastguard Worker   return 0;
684*7304104dSAndroid Build Coastguard Worker }
685