xref: /aosp_15_r20/external/elfutils/libelf/elf_compress.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Compress or decompress a section.
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2015, 2016 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2023, Mark J. Wielaard <[email protected]>
4*7304104dSAndroid Build Coastguard Worker    This file is part of elfutils.
5*7304104dSAndroid Build Coastguard Worker 
6*7304104dSAndroid Build Coastguard Worker    This file is free software; you can redistribute it and/or modify
7*7304104dSAndroid Build Coastguard Worker    it under the terms of either
8*7304104dSAndroid Build Coastguard Worker 
9*7304104dSAndroid Build Coastguard Worker      * the GNU Lesser General Public License as published by the Free
10*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 3 of the License, or (at
11*7304104dSAndroid Build Coastguard Worker        your option) any later version
12*7304104dSAndroid Build Coastguard Worker 
13*7304104dSAndroid Build Coastguard Worker    or
14*7304104dSAndroid Build Coastguard Worker 
15*7304104dSAndroid Build Coastguard Worker      * the GNU General Public License as published by the Free
16*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 2 of the License, or (at
17*7304104dSAndroid Build Coastguard Worker        your option) any later version
18*7304104dSAndroid Build Coastguard Worker 
19*7304104dSAndroid Build Coastguard Worker    or both in parallel, as here.
20*7304104dSAndroid Build Coastguard Worker 
21*7304104dSAndroid Build Coastguard Worker    elfutils is distributed in the hope that it will be useful, but
22*7304104dSAndroid Build Coastguard Worker    WITHOUT ANY WARRANTY; without even the implied warranty of
23*7304104dSAndroid Build Coastguard Worker    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24*7304104dSAndroid Build Coastguard Worker    General Public License for more details.
25*7304104dSAndroid Build Coastguard Worker 
26*7304104dSAndroid Build Coastguard Worker    You should have received copies of the GNU General Public License and
27*7304104dSAndroid Build Coastguard Worker    the GNU Lesser General Public License along with this program.  If
28*7304104dSAndroid Build Coastguard Worker    not, see <http://www.gnu.org/licenses/>.  */
29*7304104dSAndroid Build Coastguard Worker 
30*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
31*7304104dSAndroid Build Coastguard Worker # include <config.h>
32*7304104dSAndroid Build Coastguard Worker #endif
33*7304104dSAndroid Build Coastguard Worker 
34*7304104dSAndroid Build Coastguard Worker #include <libelf.h>
35*7304104dSAndroid Build Coastguard Worker #include "libelfP.h"
36*7304104dSAndroid Build Coastguard Worker #include "common.h"
37*7304104dSAndroid Build Coastguard Worker 
38*7304104dSAndroid Build Coastguard Worker #include <stddef.h>
39*7304104dSAndroid Build Coastguard Worker #include <stdlib.h>
40*7304104dSAndroid Build Coastguard Worker #include <string.h>
41*7304104dSAndroid Build Coastguard Worker #include <zlib.h>
42*7304104dSAndroid Build Coastguard Worker 
43*7304104dSAndroid Build Coastguard Worker #ifdef USE_ZSTD
44*7304104dSAndroid Build Coastguard Worker #include <zstd.h>
45*7304104dSAndroid Build Coastguard Worker #endif
46*7304104dSAndroid Build Coastguard Worker 
47*7304104dSAndroid Build Coastguard Worker /* Cleanup and return result.  Don't leak memory.  */
48*7304104dSAndroid Build Coastguard Worker static void *
do_deflate_cleanup(void * result,z_stream * z,void * out_buf,Elf_Data * cdatap)49*7304104dSAndroid Build Coastguard Worker do_deflate_cleanup (void *result, z_stream *z, void *out_buf,
50*7304104dSAndroid Build Coastguard Worker                     Elf_Data *cdatap)
51*7304104dSAndroid Build Coastguard Worker {
52*7304104dSAndroid Build Coastguard Worker   deflateEnd (z);
53*7304104dSAndroid Build Coastguard Worker   free (out_buf);
54*7304104dSAndroid Build Coastguard Worker   if (cdatap != NULL)
55*7304104dSAndroid Build Coastguard Worker     free (cdatap->d_buf);
56*7304104dSAndroid Build Coastguard Worker   return result;
57*7304104dSAndroid Build Coastguard Worker }
58*7304104dSAndroid Build Coastguard Worker 
59*7304104dSAndroid Build Coastguard Worker #define deflate_cleanup(result, cdata) \
60*7304104dSAndroid Build Coastguard Worker     do_deflate_cleanup(result, &z, out_buf, cdata)
61*7304104dSAndroid Build Coastguard Worker 
62*7304104dSAndroid Build Coastguard Worker static
63*7304104dSAndroid Build Coastguard Worker void *
__libelf_compress_zlib(Elf_Scn * scn,size_t hsize,int ei_data,size_t * orig_size,size_t * orig_addralign,size_t * new_size,bool force,Elf_Data * data,Elf_Data * next_data,void * out_buf,size_t out_size,size_t block)64*7304104dSAndroid Build Coastguard Worker __libelf_compress_zlib (Elf_Scn *scn, size_t hsize, int ei_data,
65*7304104dSAndroid Build Coastguard Worker 			size_t *orig_size, size_t *orig_addralign,
66*7304104dSAndroid Build Coastguard Worker 			size_t *new_size, bool force,
67*7304104dSAndroid Build Coastguard Worker 			Elf_Data *data, Elf_Data *next_data,
68*7304104dSAndroid Build Coastguard Worker 			void *out_buf, size_t out_size, size_t block)
69*7304104dSAndroid Build Coastguard Worker {
70*7304104dSAndroid Build Coastguard Worker   /* Caller gets to fill in the header at the start.  Just skip it here.  */
71*7304104dSAndroid Build Coastguard Worker   size_t used = hsize;
72*7304104dSAndroid Build Coastguard Worker 
73*7304104dSAndroid Build Coastguard Worker   z_stream z;
74*7304104dSAndroid Build Coastguard Worker   z.zalloc = Z_NULL;
75*7304104dSAndroid Build Coastguard Worker   z.zfree = Z_NULL;
76*7304104dSAndroid Build Coastguard Worker   z.opaque = Z_NULL;
77*7304104dSAndroid Build Coastguard Worker   int zrc = deflateInit (&z, Z_BEST_COMPRESSION);
78*7304104dSAndroid Build Coastguard Worker   if (zrc != Z_OK)
79*7304104dSAndroid Build Coastguard Worker     {
80*7304104dSAndroid Build Coastguard Worker       __libelf_seterrno (ELF_E_COMPRESS_ERROR);
81*7304104dSAndroid Build Coastguard Worker       return deflate_cleanup(NULL, NULL);
82*7304104dSAndroid Build Coastguard Worker     }
83*7304104dSAndroid Build Coastguard Worker 
84*7304104dSAndroid Build Coastguard Worker   Elf_Data cdata;
85*7304104dSAndroid Build Coastguard Worker   cdata.d_buf = NULL;
86*7304104dSAndroid Build Coastguard Worker 
87*7304104dSAndroid Build Coastguard Worker   /* Loop over data buffers.  */
88*7304104dSAndroid Build Coastguard Worker   int flush = Z_NO_FLUSH;
89*7304104dSAndroid Build Coastguard Worker   do
90*7304104dSAndroid Build Coastguard Worker     {
91*7304104dSAndroid Build Coastguard Worker       /* Convert to raw if different endianness.  */
92*7304104dSAndroid Build Coastguard Worker       cdata = *data;
93*7304104dSAndroid Build Coastguard Worker       bool convert = ei_data != MY_ELFDATA && data->d_size > 0;
94*7304104dSAndroid Build Coastguard Worker       if (convert)
95*7304104dSAndroid Build Coastguard Worker 	{
96*7304104dSAndroid Build Coastguard Worker 	  /* Don't do this conversion in place, we might want to keep
97*7304104dSAndroid Build Coastguard Worker 	     the original data around, caller decides.  */
98*7304104dSAndroid Build Coastguard Worker 	  cdata.d_buf = malloc (data->d_size);
99*7304104dSAndroid Build Coastguard Worker 	  if (cdata.d_buf == NULL)
100*7304104dSAndroid Build Coastguard Worker 	    {
101*7304104dSAndroid Build Coastguard Worker 	      __libelf_seterrno (ELF_E_NOMEM);
102*7304104dSAndroid Build Coastguard Worker 	      return deflate_cleanup (NULL, NULL);
103*7304104dSAndroid Build Coastguard Worker 	    }
104*7304104dSAndroid Build Coastguard Worker 	  if (gelf_xlatetof (scn->elf, &cdata, data, ei_data) == NULL)
105*7304104dSAndroid Build Coastguard Worker 	    return deflate_cleanup (NULL, &cdata);
106*7304104dSAndroid Build Coastguard Worker 	}
107*7304104dSAndroid Build Coastguard Worker 
108*7304104dSAndroid Build Coastguard Worker       z.avail_in = cdata.d_size;
109*7304104dSAndroid Build Coastguard Worker       z.next_in = cdata.d_buf;
110*7304104dSAndroid Build Coastguard Worker 
111*7304104dSAndroid Build Coastguard Worker       /* Get next buffer to see if this is the last one.  */
112*7304104dSAndroid Build Coastguard Worker       data = next_data;
113*7304104dSAndroid Build Coastguard Worker       if (data != NULL)
114*7304104dSAndroid Build Coastguard Worker 	{
115*7304104dSAndroid Build Coastguard Worker 	  *orig_addralign = MAX (*orig_addralign, data->d_align);
116*7304104dSAndroid Build Coastguard Worker 	  *orig_size += data->d_size;
117*7304104dSAndroid Build Coastguard Worker 	  next_data = elf_getdata (scn, data);
118*7304104dSAndroid Build Coastguard Worker 	}
119*7304104dSAndroid Build Coastguard Worker       else
120*7304104dSAndroid Build Coastguard Worker 	flush = Z_FINISH;
121*7304104dSAndroid Build Coastguard Worker 
122*7304104dSAndroid Build Coastguard Worker       /* Flush one data buffer.  */
123*7304104dSAndroid Build Coastguard Worker       do
124*7304104dSAndroid Build Coastguard Worker 	{
125*7304104dSAndroid Build Coastguard Worker 	  z.avail_out = out_size - used;
126*7304104dSAndroid Build Coastguard Worker 	  z.next_out = out_buf + used;
127*7304104dSAndroid Build Coastguard Worker 	  zrc = deflate (&z, flush);
128*7304104dSAndroid Build Coastguard Worker 	  if (zrc == Z_STREAM_ERROR)
129*7304104dSAndroid Build Coastguard Worker 	    {
130*7304104dSAndroid Build Coastguard Worker 	      __libelf_seterrno (ELF_E_COMPRESS_ERROR);
131*7304104dSAndroid Build Coastguard Worker 	      return deflate_cleanup (NULL, convert ? &cdata : NULL);
132*7304104dSAndroid Build Coastguard Worker 	    }
133*7304104dSAndroid Build Coastguard Worker 	  used += (out_size - used) - z.avail_out;
134*7304104dSAndroid Build Coastguard Worker 
135*7304104dSAndroid Build Coastguard Worker 	  /* Bail out if we are sure the user doesn't want the
136*7304104dSAndroid Build Coastguard Worker 	     compression forced and we are using more compressed data
137*7304104dSAndroid Build Coastguard Worker 	     than original data.  */
138*7304104dSAndroid Build Coastguard Worker 	  if (!force && flush == Z_FINISH && used >= *orig_size)
139*7304104dSAndroid Build Coastguard Worker 	    return deflate_cleanup ((void *) -1, convert ? &cdata : NULL);
140*7304104dSAndroid Build Coastguard Worker 
141*7304104dSAndroid Build Coastguard Worker 	  if (z.avail_out == 0)
142*7304104dSAndroid Build Coastguard Worker 	    {
143*7304104dSAndroid Build Coastguard Worker 	      void *bigger = realloc (out_buf, out_size + block);
144*7304104dSAndroid Build Coastguard Worker 	      if (bigger == NULL)
145*7304104dSAndroid Build Coastguard Worker 		{
146*7304104dSAndroid Build Coastguard Worker 		  __libelf_seterrno (ELF_E_NOMEM);
147*7304104dSAndroid Build Coastguard Worker 		  return deflate_cleanup (NULL, convert ? &cdata : NULL);
148*7304104dSAndroid Build Coastguard Worker 		}
149*7304104dSAndroid Build Coastguard Worker 	      out_buf = bigger;
150*7304104dSAndroid Build Coastguard Worker 	      out_size += block;
151*7304104dSAndroid Build Coastguard Worker 	    }
152*7304104dSAndroid Build Coastguard Worker 	}
153*7304104dSAndroid Build Coastguard Worker       while (z.avail_out == 0); /* Need more output buffer.  */
154*7304104dSAndroid Build Coastguard Worker 
155*7304104dSAndroid Build Coastguard Worker       if (convert)
156*7304104dSAndroid Build Coastguard Worker 	{
157*7304104dSAndroid Build Coastguard Worker 	  free (cdata.d_buf);
158*7304104dSAndroid Build Coastguard Worker 	  cdata.d_buf = NULL;
159*7304104dSAndroid Build Coastguard Worker 	}
160*7304104dSAndroid Build Coastguard Worker     }
161*7304104dSAndroid Build Coastguard Worker   while (flush != Z_FINISH); /* More data blocks.  */
162*7304104dSAndroid Build Coastguard Worker 
163*7304104dSAndroid Build Coastguard Worker   if (zrc != Z_STREAM_END)
164*7304104dSAndroid Build Coastguard Worker     {
165*7304104dSAndroid Build Coastguard Worker       __libelf_seterrno (ELF_E_COMPRESS_ERROR);
166*7304104dSAndroid Build Coastguard Worker       return deflate_cleanup (NULL, NULL);
167*7304104dSAndroid Build Coastguard Worker     }
168*7304104dSAndroid Build Coastguard Worker 
169*7304104dSAndroid Build Coastguard Worker   deflateEnd (&z);
170*7304104dSAndroid Build Coastguard Worker   *new_size = used;
171*7304104dSAndroid Build Coastguard Worker   return out_buf;
172*7304104dSAndroid Build Coastguard Worker }
173*7304104dSAndroid Build Coastguard Worker 
174*7304104dSAndroid Build Coastguard Worker #ifdef USE_ZSTD_COMPRESS
175*7304104dSAndroid Build Coastguard Worker /* Cleanup and return result.  Don't leak memory.  */
176*7304104dSAndroid Build Coastguard Worker static void *
do_zstd_cleanup(void * result,ZSTD_CCtx * const cctx,void * out_buf,Elf_Data * cdatap)177*7304104dSAndroid Build Coastguard Worker do_zstd_cleanup (void *result, ZSTD_CCtx * const cctx, void *out_buf,
178*7304104dSAndroid Build Coastguard Worker 		 Elf_Data *cdatap)
179*7304104dSAndroid Build Coastguard Worker {
180*7304104dSAndroid Build Coastguard Worker   ZSTD_freeCCtx (cctx);
181*7304104dSAndroid Build Coastguard Worker   free (out_buf);
182*7304104dSAndroid Build Coastguard Worker   if (cdatap != NULL)
183*7304104dSAndroid Build Coastguard Worker     free (cdatap->d_buf);
184*7304104dSAndroid Build Coastguard Worker   return result;
185*7304104dSAndroid Build Coastguard Worker }
186*7304104dSAndroid Build Coastguard Worker 
187*7304104dSAndroid Build Coastguard Worker #define zstd_cleanup(result, cdata) \
188*7304104dSAndroid Build Coastguard Worker     do_zstd_cleanup(result, cctx, out_buf, cdata)
189*7304104dSAndroid Build Coastguard Worker 
190*7304104dSAndroid Build Coastguard Worker static
191*7304104dSAndroid Build Coastguard Worker void *
__libelf_compress_zstd(Elf_Scn * scn,size_t hsize,int ei_data,size_t * orig_size,size_t * orig_addralign,size_t * new_size,bool force,Elf_Data * data,Elf_Data * next_data,void * out_buf,size_t out_size,size_t block)192*7304104dSAndroid Build Coastguard Worker __libelf_compress_zstd (Elf_Scn *scn, size_t hsize, int ei_data,
193*7304104dSAndroid Build Coastguard Worker 			size_t *orig_size, size_t *orig_addralign,
194*7304104dSAndroid Build Coastguard Worker 			size_t *new_size, bool force,
195*7304104dSAndroid Build Coastguard Worker 			Elf_Data *data, Elf_Data *next_data,
196*7304104dSAndroid Build Coastguard Worker 			void *out_buf, size_t out_size, size_t block)
197*7304104dSAndroid Build Coastguard Worker {
198*7304104dSAndroid Build Coastguard Worker   /* Caller gets to fill in the header at the start.  Just skip it here.  */
199*7304104dSAndroid Build Coastguard Worker   size_t used = hsize;
200*7304104dSAndroid Build Coastguard Worker 
201*7304104dSAndroid Build Coastguard Worker   ZSTD_CCtx* const cctx = ZSTD_createCCtx();
202*7304104dSAndroid Build Coastguard Worker   Elf_Data cdata;
203*7304104dSAndroid Build Coastguard Worker   cdata.d_buf = NULL;
204*7304104dSAndroid Build Coastguard Worker 
205*7304104dSAndroid Build Coastguard Worker   /* Loop over data buffers.  */
206*7304104dSAndroid Build Coastguard Worker   ZSTD_EndDirective mode = ZSTD_e_continue;
207*7304104dSAndroid Build Coastguard Worker 
208*7304104dSAndroid Build Coastguard Worker   do
209*7304104dSAndroid Build Coastguard Worker     {
210*7304104dSAndroid Build Coastguard Worker       /* Convert to raw if different endianness.  */
211*7304104dSAndroid Build Coastguard Worker       cdata = *data;
212*7304104dSAndroid Build Coastguard Worker       bool convert = ei_data != MY_ELFDATA && data->d_size > 0;
213*7304104dSAndroid Build Coastguard Worker       if (convert)
214*7304104dSAndroid Build Coastguard Worker 	{
215*7304104dSAndroid Build Coastguard Worker 	  /* Don't do this conversion in place, we might want to keep
216*7304104dSAndroid Build Coastguard Worker 	     the original data around, caller decides.  */
217*7304104dSAndroid Build Coastguard Worker 	  cdata.d_buf = malloc (data->d_size);
218*7304104dSAndroid Build Coastguard Worker 	  if (cdata.d_buf == NULL)
219*7304104dSAndroid Build Coastguard Worker 	    {
220*7304104dSAndroid Build Coastguard Worker 	      __libelf_seterrno (ELF_E_NOMEM);
221*7304104dSAndroid Build Coastguard Worker 	      return zstd_cleanup (NULL, NULL);
222*7304104dSAndroid Build Coastguard Worker 	    }
223*7304104dSAndroid Build Coastguard Worker 	  if (gelf_xlatetof (scn->elf, &cdata, data, ei_data) == NULL)
224*7304104dSAndroid Build Coastguard Worker 	    return zstd_cleanup (NULL, &cdata);
225*7304104dSAndroid Build Coastguard Worker 	}
226*7304104dSAndroid Build Coastguard Worker 
227*7304104dSAndroid Build Coastguard Worker       ZSTD_inBuffer ib = { cdata.d_buf, cdata.d_size, 0 };
228*7304104dSAndroid Build Coastguard Worker 
229*7304104dSAndroid Build Coastguard Worker       /* Get next buffer to see if this is the last one.  */
230*7304104dSAndroid Build Coastguard Worker       data = next_data;
231*7304104dSAndroid Build Coastguard Worker       if (data != NULL)
232*7304104dSAndroid Build Coastguard Worker 	{
233*7304104dSAndroid Build Coastguard Worker 	  *orig_addralign = MAX (*orig_addralign, data->d_align);
234*7304104dSAndroid Build Coastguard Worker 	  *orig_size += data->d_size;
235*7304104dSAndroid Build Coastguard Worker 	  next_data = elf_getdata (scn, data);
236*7304104dSAndroid Build Coastguard Worker 	}
237*7304104dSAndroid Build Coastguard Worker       else
238*7304104dSAndroid Build Coastguard Worker 	mode = ZSTD_e_end;
239*7304104dSAndroid Build Coastguard Worker 
240*7304104dSAndroid Build Coastguard Worker       /* Flush one data buffer.  */
241*7304104dSAndroid Build Coastguard Worker       for (;;)
242*7304104dSAndroid Build Coastguard Worker 	{
243*7304104dSAndroid Build Coastguard Worker 	  ZSTD_outBuffer ob = { out_buf + used, out_size - used, 0 };
244*7304104dSAndroid Build Coastguard Worker 	  size_t ret = ZSTD_compressStream2 (cctx, &ob, &ib, mode);
245*7304104dSAndroid Build Coastguard Worker 	  if (ZSTD_isError (ret))
246*7304104dSAndroid Build Coastguard Worker 	    {
247*7304104dSAndroid Build Coastguard Worker 	      __libelf_seterrno (ELF_E_COMPRESS_ERROR);
248*7304104dSAndroid Build Coastguard Worker 	      return zstd_cleanup (NULL, convert ? &cdata : NULL);
249*7304104dSAndroid Build Coastguard Worker 	    }
250*7304104dSAndroid Build Coastguard Worker 	  used += ob.pos;
251*7304104dSAndroid Build Coastguard Worker 
252*7304104dSAndroid Build Coastguard Worker 	  /* Bail out if we are sure the user doesn't want the
253*7304104dSAndroid Build Coastguard Worker 	     compression forced and we are using more compressed data
254*7304104dSAndroid Build Coastguard Worker 	     than original data.  */
255*7304104dSAndroid Build Coastguard Worker 	  if (!force && mode == ZSTD_e_end && used >= *orig_size)
256*7304104dSAndroid Build Coastguard Worker 	    return zstd_cleanup ((void *) -1, convert ? &cdata : NULL);
257*7304104dSAndroid Build Coastguard Worker 
258*7304104dSAndroid Build Coastguard Worker 	  if (ret > 0)
259*7304104dSAndroid Build Coastguard Worker 	    {
260*7304104dSAndroid Build Coastguard Worker 	      void *bigger = realloc (out_buf, out_size + block);
261*7304104dSAndroid Build Coastguard Worker 	      if (bigger == NULL)
262*7304104dSAndroid Build Coastguard Worker 		{
263*7304104dSAndroid Build Coastguard Worker 		  __libelf_seterrno (ELF_E_NOMEM);
264*7304104dSAndroid Build Coastguard Worker 		  return zstd_cleanup (NULL, convert ? &cdata : NULL);
265*7304104dSAndroid Build Coastguard Worker 		}
266*7304104dSAndroid Build Coastguard Worker 	      out_buf = bigger;
267*7304104dSAndroid Build Coastguard Worker 	      out_size += block;
268*7304104dSAndroid Build Coastguard Worker 	    }
269*7304104dSAndroid Build Coastguard Worker 	  else
270*7304104dSAndroid Build Coastguard Worker 	    break;
271*7304104dSAndroid Build Coastguard Worker 	}
272*7304104dSAndroid Build Coastguard Worker 
273*7304104dSAndroid Build Coastguard Worker       if (convert)
274*7304104dSAndroid Build Coastguard Worker 	{
275*7304104dSAndroid Build Coastguard Worker 	  free (cdata.d_buf);
276*7304104dSAndroid Build Coastguard Worker 	  cdata.d_buf = NULL;
277*7304104dSAndroid Build Coastguard Worker 	}
278*7304104dSAndroid Build Coastguard Worker     }
279*7304104dSAndroid Build Coastguard Worker   while (mode != ZSTD_e_end); /* More data blocks.  */
280*7304104dSAndroid Build Coastguard Worker 
281*7304104dSAndroid Build Coastguard Worker   ZSTD_freeCCtx (cctx);
282*7304104dSAndroid Build Coastguard Worker   *new_size = used;
283*7304104dSAndroid Build Coastguard Worker   return out_buf;
284*7304104dSAndroid Build Coastguard Worker }
285*7304104dSAndroid Build Coastguard Worker #endif
286*7304104dSAndroid Build Coastguard Worker 
287*7304104dSAndroid Build Coastguard Worker /* Given a section, uses the (in-memory) Elf_Data to extract the
288*7304104dSAndroid Build Coastguard Worker    original data size (including the given header size) and data
289*7304104dSAndroid Build Coastguard Worker    alignment.  Returns a buffer that has at least hsize bytes (for the
290*7304104dSAndroid Build Coastguard Worker    caller to fill in with a header) plus zlib compressed date.  Also
291*7304104dSAndroid Build Coastguard Worker    returns the new buffer size in new_size (hsize + compressed data
292*7304104dSAndroid Build Coastguard Worker    size).  Returns (void *) -1 when FORCE is false and the compressed
293*7304104dSAndroid Build Coastguard Worker    data would be bigger than the original data.  */
294*7304104dSAndroid Build Coastguard Worker void *
295*7304104dSAndroid Build Coastguard Worker internal_function
__libelf_compress(Elf_Scn * scn,size_t hsize,int ei_data,size_t * orig_size,size_t * orig_addralign,size_t * new_size,bool force,bool use_zstd)296*7304104dSAndroid Build Coastguard Worker __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data,
297*7304104dSAndroid Build Coastguard Worker 		   size_t *orig_size, size_t *orig_addralign,
298*7304104dSAndroid Build Coastguard Worker 		   size_t *new_size, bool force, bool use_zstd)
299*7304104dSAndroid Build Coastguard Worker {
300*7304104dSAndroid Build Coastguard Worker   /* The compressed data is the on-disk data.  We simplify the
301*7304104dSAndroid Build Coastguard Worker      implementation a bit by asking for the (converted) in-memory
302*7304104dSAndroid Build Coastguard Worker      data (which might be all there is if the user created it with
303*7304104dSAndroid Build Coastguard Worker      elf_newdata) and then convert back to raw if needed before
304*7304104dSAndroid Build Coastguard Worker      compressing.  Should be made a bit more clever to directly
305*7304104dSAndroid Build Coastguard Worker      use raw if that is directly available.  */
306*7304104dSAndroid Build Coastguard Worker   Elf_Data *data = elf_getdata (scn, NULL);
307*7304104dSAndroid Build Coastguard Worker   if (data == NULL)
308*7304104dSAndroid Build Coastguard Worker     return NULL;
309*7304104dSAndroid Build Coastguard Worker 
310*7304104dSAndroid Build Coastguard Worker   /* When not forced and we immediately know we would use more data by
311*7304104dSAndroid Build Coastguard Worker      compressing, because of the header plus zlib overhead (five bytes
312*7304104dSAndroid Build Coastguard Worker      per 16 KB block, plus a one-time overhead of six bytes for the
313*7304104dSAndroid Build Coastguard Worker      entire stream), don't do anything.
314*7304104dSAndroid Build Coastguard Worker      Size estimation for ZSTD compression would be similar.  */
315*7304104dSAndroid Build Coastguard Worker   Elf_Data *next_data = elf_getdata (scn, data);
316*7304104dSAndroid Build Coastguard Worker   if (next_data == NULL && !force
317*7304104dSAndroid Build Coastguard Worker       && data->d_size <= hsize + 5 + 6)
318*7304104dSAndroid Build Coastguard Worker     return (void *) -1;
319*7304104dSAndroid Build Coastguard Worker 
320*7304104dSAndroid Build Coastguard Worker   *orig_addralign = data->d_align;
321*7304104dSAndroid Build Coastguard Worker   *orig_size = data->d_size;
322*7304104dSAndroid Build Coastguard Worker 
323*7304104dSAndroid Build Coastguard Worker   /* Guess an output block size. 1/8th of the original Elf_Data plus
324*7304104dSAndroid Build Coastguard Worker      hsize.  Make the first chunk twice that size (25%), then increase
325*7304104dSAndroid Build Coastguard Worker      by a block (12.5%) when necessary.  */
326*7304104dSAndroid Build Coastguard Worker   size_t block = (data->d_size / 8) + hsize;
327*7304104dSAndroid Build Coastguard Worker   size_t out_size = 2 * block;
328*7304104dSAndroid Build Coastguard Worker   void *out_buf = malloc (out_size);
329*7304104dSAndroid Build Coastguard Worker   if (out_buf == NULL)
330*7304104dSAndroid Build Coastguard Worker     {
331*7304104dSAndroid Build Coastguard Worker       __libelf_seterrno (ELF_E_NOMEM);
332*7304104dSAndroid Build Coastguard Worker       return NULL;
333*7304104dSAndroid Build Coastguard Worker     }
334*7304104dSAndroid Build Coastguard Worker 
335*7304104dSAndroid Build Coastguard Worker   if (use_zstd)
336*7304104dSAndroid Build Coastguard Worker     {
337*7304104dSAndroid Build Coastguard Worker #ifdef USE_ZSTD_COMPRESS
338*7304104dSAndroid Build Coastguard Worker       return __libelf_compress_zstd (scn, hsize, ei_data, orig_size,
339*7304104dSAndroid Build Coastguard Worker 				   orig_addralign, new_size, force,
340*7304104dSAndroid Build Coastguard Worker 				   data, next_data, out_buf, out_size,
341*7304104dSAndroid Build Coastguard Worker 				   block);
342*7304104dSAndroid Build Coastguard Worker #else
343*7304104dSAndroid Build Coastguard Worker     __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
344*7304104dSAndroid Build Coastguard Worker     return NULL;
345*7304104dSAndroid Build Coastguard Worker #endif
346*7304104dSAndroid Build Coastguard Worker     }
347*7304104dSAndroid Build Coastguard Worker   else
348*7304104dSAndroid Build Coastguard Worker     return __libelf_compress_zlib (scn, hsize, ei_data, orig_size,
349*7304104dSAndroid Build Coastguard Worker 				   orig_addralign, new_size, force,
350*7304104dSAndroid Build Coastguard Worker 				   data, next_data, out_buf, out_size,
351*7304104dSAndroid Build Coastguard Worker 				   block);
352*7304104dSAndroid Build Coastguard Worker }
353*7304104dSAndroid Build Coastguard Worker 
354*7304104dSAndroid Build Coastguard Worker void *
355*7304104dSAndroid Build Coastguard Worker internal_function
__libelf_decompress_zlib(void * buf_in,size_t size_in,size_t size_out)356*7304104dSAndroid Build Coastguard Worker __libelf_decompress_zlib (void *buf_in, size_t size_in, size_t size_out)
357*7304104dSAndroid Build Coastguard Worker {
358*7304104dSAndroid Build Coastguard Worker   /* Catch highly unlikely compression ratios so we don't allocate
359*7304104dSAndroid Build Coastguard Worker      some giant amount of memory for nothing. The max compression
360*7304104dSAndroid Build Coastguard Worker      factor 1032:1 comes from http://www.zlib.net/zlib_tech.html  */
361*7304104dSAndroid Build Coastguard Worker   if (unlikely (size_out / 1032 > size_in))
362*7304104dSAndroid Build Coastguard Worker     {
363*7304104dSAndroid Build Coastguard Worker       __libelf_seterrno (ELF_E_INVALID_DATA);
364*7304104dSAndroid Build Coastguard Worker       return NULL;
365*7304104dSAndroid Build Coastguard Worker     }
366*7304104dSAndroid Build Coastguard Worker 
367*7304104dSAndroid Build Coastguard Worker   /* Malloc might return NULL when requesting zero size.  This is highly
368*7304104dSAndroid Build Coastguard Worker      unlikely, it would only happen when the compression was forced.
369*7304104dSAndroid Build Coastguard Worker      But we do need a non-NULL buffer to return and set as result.
370*7304104dSAndroid Build Coastguard Worker      Just make sure to always allocate at least 1 byte.  */
371*7304104dSAndroid Build Coastguard Worker   void *buf_out = malloc (size_out ?: 1);
372*7304104dSAndroid Build Coastguard Worker   if (unlikely (buf_out == NULL))
373*7304104dSAndroid Build Coastguard Worker     {
374*7304104dSAndroid Build Coastguard Worker       __libelf_seterrno (ELF_E_NOMEM);
375*7304104dSAndroid Build Coastguard Worker       return NULL;
376*7304104dSAndroid Build Coastguard Worker     }
377*7304104dSAndroid Build Coastguard Worker 
378*7304104dSAndroid Build Coastguard Worker   z_stream z =
379*7304104dSAndroid Build Coastguard Worker     {
380*7304104dSAndroid Build Coastguard Worker       .next_in = buf_in,
381*7304104dSAndroid Build Coastguard Worker       .avail_in = size_in,
382*7304104dSAndroid Build Coastguard Worker       .next_out = buf_out,
383*7304104dSAndroid Build Coastguard Worker       .avail_out = size_out
384*7304104dSAndroid Build Coastguard Worker     };
385*7304104dSAndroid Build Coastguard Worker   int zrc = inflateInit (&z);
386*7304104dSAndroid Build Coastguard Worker   while (z.avail_in > 0 && likely (zrc == Z_OK))
387*7304104dSAndroid Build Coastguard Worker     {
388*7304104dSAndroid Build Coastguard Worker       z.next_out = buf_out + (size_out - z.avail_out);
389*7304104dSAndroid Build Coastguard Worker       zrc = inflate (&z, Z_FINISH);
390*7304104dSAndroid Build Coastguard Worker       if (unlikely (zrc != Z_STREAM_END))
391*7304104dSAndroid Build Coastguard Worker 	{
392*7304104dSAndroid Build Coastguard Worker 	  zrc = Z_DATA_ERROR;
393*7304104dSAndroid Build Coastguard Worker 	  break;
394*7304104dSAndroid Build Coastguard Worker 	}
395*7304104dSAndroid Build Coastguard Worker       zrc = inflateReset (&z);
396*7304104dSAndroid Build Coastguard Worker     }
397*7304104dSAndroid Build Coastguard Worker 
398*7304104dSAndroid Build Coastguard Worker   if (unlikely (zrc != Z_OK) || unlikely (z.avail_out != 0))
399*7304104dSAndroid Build Coastguard Worker     {
400*7304104dSAndroid Build Coastguard Worker       free (buf_out);
401*7304104dSAndroid Build Coastguard Worker       buf_out = NULL;
402*7304104dSAndroid Build Coastguard Worker       __libelf_seterrno (ELF_E_DECOMPRESS_ERROR);
403*7304104dSAndroid Build Coastguard Worker     }
404*7304104dSAndroid Build Coastguard Worker 
405*7304104dSAndroid Build Coastguard Worker   inflateEnd(&z);
406*7304104dSAndroid Build Coastguard Worker   return buf_out;
407*7304104dSAndroid Build Coastguard Worker }
408*7304104dSAndroid Build Coastguard Worker 
409*7304104dSAndroid Build Coastguard Worker #ifdef USE_ZSTD
410*7304104dSAndroid Build Coastguard Worker static void *
__libelf_decompress_zstd(void * buf_in,size_t size_in,size_t size_out)411*7304104dSAndroid Build Coastguard Worker __libelf_decompress_zstd (void *buf_in, size_t size_in, size_t size_out)
412*7304104dSAndroid Build Coastguard Worker {
413*7304104dSAndroid Build Coastguard Worker   /* Malloc might return NULL when requesting zero size.  This is highly
414*7304104dSAndroid Build Coastguard Worker      unlikely, it would only happen when the compression was forced.
415*7304104dSAndroid Build Coastguard Worker      But we do need a non-NULL buffer to return and set as result.
416*7304104dSAndroid Build Coastguard Worker      Just make sure to always allocate at least 1 byte.  */
417*7304104dSAndroid Build Coastguard Worker   void *buf_out = malloc (size_out ?: 1);
418*7304104dSAndroid Build Coastguard Worker   if (unlikely (buf_out == NULL))
419*7304104dSAndroid Build Coastguard Worker     {
420*7304104dSAndroid Build Coastguard Worker       __libelf_seterrno (ELF_E_NOMEM);
421*7304104dSAndroid Build Coastguard Worker       return NULL;
422*7304104dSAndroid Build Coastguard Worker     }
423*7304104dSAndroid Build Coastguard Worker 
424*7304104dSAndroid Build Coastguard Worker   size_t ret = ZSTD_decompress (buf_out, size_out, buf_in, size_in);
425*7304104dSAndroid Build Coastguard Worker   if (unlikely (ZSTD_isError (ret)) || unlikely (ret != size_out))
426*7304104dSAndroid Build Coastguard Worker     {
427*7304104dSAndroid Build Coastguard Worker       free (buf_out);
428*7304104dSAndroid Build Coastguard Worker       __libelf_seterrno (ELF_E_DECOMPRESS_ERROR);
429*7304104dSAndroid Build Coastguard Worker       return NULL;
430*7304104dSAndroid Build Coastguard Worker     }
431*7304104dSAndroid Build Coastguard Worker   else
432*7304104dSAndroid Build Coastguard Worker     return buf_out;
433*7304104dSAndroid Build Coastguard Worker }
434*7304104dSAndroid Build Coastguard Worker #endif
435*7304104dSAndroid Build Coastguard Worker 
436*7304104dSAndroid Build Coastguard Worker void *
437*7304104dSAndroid Build Coastguard Worker internal_function
__libelf_decompress(int chtype,void * buf_in,size_t size_in,size_t size_out)438*7304104dSAndroid Build Coastguard Worker __libelf_decompress (int chtype, void *buf_in, size_t size_in, size_t size_out)
439*7304104dSAndroid Build Coastguard Worker {
440*7304104dSAndroid Build Coastguard Worker   if (chtype == ELFCOMPRESS_ZLIB)
441*7304104dSAndroid Build Coastguard Worker     return __libelf_decompress_zlib (buf_in, size_in, size_out);
442*7304104dSAndroid Build Coastguard Worker   else
443*7304104dSAndroid Build Coastguard Worker     {
444*7304104dSAndroid Build Coastguard Worker #ifdef USE_ZSTD
445*7304104dSAndroid Build Coastguard Worker     return __libelf_decompress_zstd (buf_in, size_in, size_out);
446*7304104dSAndroid Build Coastguard Worker #else
447*7304104dSAndroid Build Coastguard Worker     __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
448*7304104dSAndroid Build Coastguard Worker     return NULL;
449*7304104dSAndroid Build Coastguard Worker #endif
450*7304104dSAndroid Build Coastguard Worker     }
451*7304104dSAndroid Build Coastguard Worker }
452*7304104dSAndroid Build Coastguard Worker 
453*7304104dSAndroid Build Coastguard Worker void *
454*7304104dSAndroid Build Coastguard Worker internal_function
__libelf_decompress_elf(Elf_Scn * scn,size_t * size_out,size_t * addralign)455*7304104dSAndroid Build Coastguard Worker __libelf_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign)
456*7304104dSAndroid Build Coastguard Worker {
457*7304104dSAndroid Build Coastguard Worker   GElf_Chdr chdr;
458*7304104dSAndroid Build Coastguard Worker   if (gelf_getchdr (scn, &chdr) == NULL)
459*7304104dSAndroid Build Coastguard Worker     return NULL;
460*7304104dSAndroid Build Coastguard Worker 
461*7304104dSAndroid Build Coastguard Worker   bool unknown_compression = false;
462*7304104dSAndroid Build Coastguard Worker   if (chdr.ch_type != ELFCOMPRESS_ZLIB)
463*7304104dSAndroid Build Coastguard Worker     {
464*7304104dSAndroid Build Coastguard Worker       if (chdr.ch_type != ELFCOMPRESS_ZSTD)
465*7304104dSAndroid Build Coastguard Worker 	unknown_compression = true;
466*7304104dSAndroid Build Coastguard Worker 
467*7304104dSAndroid Build Coastguard Worker #ifndef USE_ZSTD
468*7304104dSAndroid Build Coastguard Worker       if (chdr.ch_type == ELFCOMPRESS_ZSTD)
469*7304104dSAndroid Build Coastguard Worker 	unknown_compression = true;
470*7304104dSAndroid Build Coastguard Worker #endif
471*7304104dSAndroid Build Coastguard Worker     }
472*7304104dSAndroid Build Coastguard Worker 
473*7304104dSAndroid Build Coastguard Worker   if (unknown_compression)
474*7304104dSAndroid Build Coastguard Worker     {
475*7304104dSAndroid Build Coastguard Worker       __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
476*7304104dSAndroid Build Coastguard Worker       return NULL;
477*7304104dSAndroid Build Coastguard Worker     }
478*7304104dSAndroid Build Coastguard Worker 
479*7304104dSAndroid Build Coastguard Worker   if (! powerof2 (chdr.ch_addralign))
480*7304104dSAndroid Build Coastguard Worker     {
481*7304104dSAndroid Build Coastguard Worker       __libelf_seterrno (ELF_E_INVALID_ALIGN);
482*7304104dSAndroid Build Coastguard Worker       return NULL;
483*7304104dSAndroid Build Coastguard Worker     }
484*7304104dSAndroid Build Coastguard Worker 
485*7304104dSAndroid Build Coastguard Worker   /* Take the in-memory representation, so we can even handle a
486*7304104dSAndroid Build Coastguard Worker      section that has just been constructed (maybe it was copied
487*7304104dSAndroid Build Coastguard Worker      over from some other ELF file first with elf_newdata).  This
488*7304104dSAndroid Build Coastguard Worker      is slightly inefficient when the raw data needs to be
489*7304104dSAndroid Build Coastguard Worker      converted since then we'll be converting the whole buffer and
490*7304104dSAndroid Build Coastguard Worker      not just Chdr.  */
491*7304104dSAndroid Build Coastguard Worker   Elf_Data *data = elf_getdata (scn, NULL);
492*7304104dSAndroid Build Coastguard Worker   if (data == NULL)
493*7304104dSAndroid Build Coastguard Worker     return NULL;
494*7304104dSAndroid Build Coastguard Worker 
495*7304104dSAndroid Build Coastguard Worker   int elfclass = scn->elf->class;
496*7304104dSAndroid Build Coastguard Worker   size_t hsize = (elfclass == ELFCLASS32
497*7304104dSAndroid Build Coastguard Worker 		  ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
498*7304104dSAndroid Build Coastguard Worker   size_t size_in = data->d_size - hsize;
499*7304104dSAndroid Build Coastguard Worker   void *buf_in = data->d_buf + hsize;
500*7304104dSAndroid Build Coastguard Worker   void *buf_out
501*7304104dSAndroid Build Coastguard Worker     = __libelf_decompress (chdr.ch_type, buf_in, size_in, chdr.ch_size);
502*7304104dSAndroid Build Coastguard Worker 
503*7304104dSAndroid Build Coastguard Worker   *size_out = chdr.ch_size;
504*7304104dSAndroid Build Coastguard Worker   *addralign = chdr.ch_addralign;
505*7304104dSAndroid Build Coastguard Worker   return buf_out;
506*7304104dSAndroid Build Coastguard Worker }
507*7304104dSAndroid Build Coastguard Worker 
508*7304104dSAndroid Build Coastguard Worker /* Assumes buf is a malloced buffer.  */
509*7304104dSAndroid Build Coastguard Worker void
510*7304104dSAndroid Build Coastguard Worker internal_function
__libelf_reset_rawdata(Elf_Scn * scn,void * buf,size_t size,size_t align,Elf_Type type)511*7304104dSAndroid Build Coastguard Worker __libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size, size_t align,
512*7304104dSAndroid Build Coastguard Worker 			Elf_Type type)
513*7304104dSAndroid Build Coastguard Worker {
514*7304104dSAndroid Build Coastguard Worker   /* This is the new raw data, replace and possibly free old data.  */
515*7304104dSAndroid Build Coastguard Worker   scn->rawdata.d.d_off = 0;
516*7304104dSAndroid Build Coastguard Worker   scn->rawdata.d.d_version = EV_CURRENT;
517*7304104dSAndroid Build Coastguard Worker   scn->rawdata.d.d_buf = buf;
518*7304104dSAndroid Build Coastguard Worker   scn->rawdata.d.d_size = size;
519*7304104dSAndroid Build Coastguard Worker   scn->rawdata.d.d_align = align;
520*7304104dSAndroid Build Coastguard Worker   scn->rawdata.d.d_type = type;
521*7304104dSAndroid Build Coastguard Worker 
522*7304104dSAndroid Build Coastguard Worker   /* Existing existing data is no longer valid.  */
523*7304104dSAndroid Build Coastguard Worker   scn->data_list_rear = NULL;
524*7304104dSAndroid Build Coastguard Worker   if (scn->data_base != scn->rawdata_base)
525*7304104dSAndroid Build Coastguard Worker     free (scn->data_base);
526*7304104dSAndroid Build Coastguard Worker   scn->data_base = NULL;
527*7304104dSAndroid Build Coastguard Worker   if (scn->zdata_base != buf
528*7304104dSAndroid Build Coastguard Worker       && scn->zdata_base != scn->rawdata_base)
529*7304104dSAndroid Build Coastguard Worker     {
530*7304104dSAndroid Build Coastguard Worker       free (scn->zdata_base);
531*7304104dSAndroid Build Coastguard Worker       scn->zdata_base = NULL;
532*7304104dSAndroid Build Coastguard Worker     }
533*7304104dSAndroid Build Coastguard Worker   if (scn->elf->map_address == NULL
534*7304104dSAndroid Build Coastguard Worker       || scn->rawdata_base == scn->zdata_base
535*7304104dSAndroid Build Coastguard Worker       || (scn->flags & ELF_F_MALLOCED) != 0)
536*7304104dSAndroid Build Coastguard Worker     {
537*7304104dSAndroid Build Coastguard Worker       free (scn->rawdata_base);
538*7304104dSAndroid Build Coastguard Worker       scn->rawdata_base = NULL;
539*7304104dSAndroid Build Coastguard Worker       scn->zdata_base = NULL;
540*7304104dSAndroid Build Coastguard Worker     }
541*7304104dSAndroid Build Coastguard Worker 
542*7304104dSAndroid Build Coastguard Worker   scn->rawdata_base = buf;
543*7304104dSAndroid Build Coastguard Worker   scn->flags |= ELF_F_MALLOCED;
544*7304104dSAndroid Build Coastguard Worker 
545*7304104dSAndroid Build Coastguard Worker   /* Pretend we (tried to) read the data from the file and setup the
546*7304104dSAndroid Build Coastguard Worker      data (might have to convert the Chdr to native format).  */
547*7304104dSAndroid Build Coastguard Worker   scn->data_read = 1;
548*7304104dSAndroid Build Coastguard Worker   scn->flags |= ELF_F_FILEDATA;
549*7304104dSAndroid Build Coastguard Worker   __libelf_set_data_list_rdlock (scn, 1);
550*7304104dSAndroid Build Coastguard Worker }
551*7304104dSAndroid Build Coastguard Worker 
552*7304104dSAndroid Build Coastguard Worker int
elf_compress(Elf_Scn * scn,int type,unsigned int flags)553*7304104dSAndroid Build Coastguard Worker elf_compress (Elf_Scn *scn, int type, unsigned int flags)
554*7304104dSAndroid Build Coastguard Worker {
555*7304104dSAndroid Build Coastguard Worker   if (scn == NULL)
556*7304104dSAndroid Build Coastguard Worker     return -1;
557*7304104dSAndroid Build Coastguard Worker 
558*7304104dSAndroid Build Coastguard Worker   if ((flags & ~ELF_CHF_FORCE) != 0)
559*7304104dSAndroid Build Coastguard Worker     {
560*7304104dSAndroid Build Coastguard Worker       __libelf_seterrno (ELF_E_INVALID_OPERAND);
561*7304104dSAndroid Build Coastguard Worker       return -1;
562*7304104dSAndroid Build Coastguard Worker     }
563*7304104dSAndroid Build Coastguard Worker 
564*7304104dSAndroid Build Coastguard Worker   bool force = (flags & ELF_CHF_FORCE) != 0;
565*7304104dSAndroid Build Coastguard Worker 
566*7304104dSAndroid Build Coastguard Worker   Elf *elf = scn->elf;
567*7304104dSAndroid Build Coastguard Worker   GElf_Ehdr ehdr;
568*7304104dSAndroid Build Coastguard Worker   if (gelf_getehdr (elf, &ehdr) == NULL)
569*7304104dSAndroid Build Coastguard Worker     return -1;
570*7304104dSAndroid Build Coastguard Worker 
571*7304104dSAndroid Build Coastguard Worker   int elfclass = elf->class;
572*7304104dSAndroid Build Coastguard Worker   int elfdata = ehdr.e_ident[EI_DATA];
573*7304104dSAndroid Build Coastguard Worker 
574*7304104dSAndroid Build Coastguard Worker   Elf64_Xword sh_flags;
575*7304104dSAndroid Build Coastguard Worker   Elf64_Word sh_type;
576*7304104dSAndroid Build Coastguard Worker   Elf64_Xword sh_addralign;
577*7304104dSAndroid Build Coastguard Worker   if (elfclass == ELFCLASS32)
578*7304104dSAndroid Build Coastguard Worker     {
579*7304104dSAndroid Build Coastguard Worker       Elf32_Shdr *shdr = elf32_getshdr (scn);
580*7304104dSAndroid Build Coastguard Worker       if (shdr == NULL)
581*7304104dSAndroid Build Coastguard Worker 	return -1;
582*7304104dSAndroid Build Coastguard Worker 
583*7304104dSAndroid Build Coastguard Worker       sh_flags = shdr->sh_flags;
584*7304104dSAndroid Build Coastguard Worker       sh_type = shdr->sh_type;
585*7304104dSAndroid Build Coastguard Worker       sh_addralign = shdr->sh_addralign;
586*7304104dSAndroid Build Coastguard Worker     }
587*7304104dSAndroid Build Coastguard Worker   else
588*7304104dSAndroid Build Coastguard Worker     {
589*7304104dSAndroid Build Coastguard Worker       Elf64_Shdr *shdr = elf64_getshdr (scn);
590*7304104dSAndroid Build Coastguard Worker       if (shdr == NULL)
591*7304104dSAndroid Build Coastguard Worker 	return -1;
592*7304104dSAndroid Build Coastguard Worker 
593*7304104dSAndroid Build Coastguard Worker       sh_flags = shdr->sh_flags;
594*7304104dSAndroid Build Coastguard Worker       sh_type = shdr->sh_type;
595*7304104dSAndroid Build Coastguard Worker       sh_addralign = shdr->sh_addralign;
596*7304104dSAndroid Build Coastguard Worker     }
597*7304104dSAndroid Build Coastguard Worker 
598*7304104dSAndroid Build Coastguard Worker   if ((sh_flags & SHF_ALLOC) != 0)
599*7304104dSAndroid Build Coastguard Worker     {
600*7304104dSAndroid Build Coastguard Worker       __libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
601*7304104dSAndroid Build Coastguard Worker       return -1;
602*7304104dSAndroid Build Coastguard Worker     }
603*7304104dSAndroid Build Coastguard Worker 
604*7304104dSAndroid Build Coastguard Worker   if (sh_type == SHT_NULL || sh_type == SHT_NOBITS)
605*7304104dSAndroid Build Coastguard Worker     {
606*7304104dSAndroid Build Coastguard Worker       __libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
607*7304104dSAndroid Build Coastguard Worker       return -1;
608*7304104dSAndroid Build Coastguard Worker     }
609*7304104dSAndroid Build Coastguard Worker 
610*7304104dSAndroid Build Coastguard Worker   int compressed = (sh_flags & SHF_COMPRESSED);
611*7304104dSAndroid Build Coastguard Worker   if (type == ELFCOMPRESS_ZLIB || type == ELFCOMPRESS_ZSTD)
612*7304104dSAndroid Build Coastguard Worker     {
613*7304104dSAndroid Build Coastguard Worker       /* Compress/Deflate.  */
614*7304104dSAndroid Build Coastguard Worker       if (compressed == 1)
615*7304104dSAndroid Build Coastguard Worker 	{
616*7304104dSAndroid Build Coastguard Worker 	  __libelf_seterrno (ELF_E_ALREADY_COMPRESSED);
617*7304104dSAndroid Build Coastguard Worker 	  return -1;
618*7304104dSAndroid Build Coastguard Worker 	}
619*7304104dSAndroid Build Coastguard Worker 
620*7304104dSAndroid Build Coastguard Worker       size_t hsize = (elfclass == ELFCLASS32
621*7304104dSAndroid Build Coastguard Worker 		      ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
622*7304104dSAndroid Build Coastguard Worker       size_t orig_size, orig_addralign, new_size;
623*7304104dSAndroid Build Coastguard Worker       void *out_buf = __libelf_compress (scn, hsize, elfdata,
624*7304104dSAndroid Build Coastguard Worker 					 &orig_size, &orig_addralign,
625*7304104dSAndroid Build Coastguard Worker 					 &new_size, force,
626*7304104dSAndroid Build Coastguard Worker 					 type == ELFCOMPRESS_ZSTD);
627*7304104dSAndroid Build Coastguard Worker 
628*7304104dSAndroid Build Coastguard Worker       /* Compression would make section larger, don't change anything.  */
629*7304104dSAndroid Build Coastguard Worker       if (out_buf == (void *) -1)
630*7304104dSAndroid Build Coastguard Worker 	return 0;
631*7304104dSAndroid Build Coastguard Worker 
632*7304104dSAndroid Build Coastguard Worker       /* Compression failed, return error.  */
633*7304104dSAndroid Build Coastguard Worker       if (out_buf == NULL)
634*7304104dSAndroid Build Coastguard Worker 	return -1;
635*7304104dSAndroid Build Coastguard Worker 
636*7304104dSAndroid Build Coastguard Worker       /* Put the header in front of the data.  */
637*7304104dSAndroid Build Coastguard Worker       if (elfclass == ELFCLASS32)
638*7304104dSAndroid Build Coastguard Worker 	{
639*7304104dSAndroid Build Coastguard Worker 	  Elf32_Chdr chdr;
640*7304104dSAndroid Build Coastguard Worker 	  chdr.ch_type = type;
641*7304104dSAndroid Build Coastguard Worker 	  chdr.ch_size = orig_size;
642*7304104dSAndroid Build Coastguard Worker 	  chdr.ch_addralign = orig_addralign;
643*7304104dSAndroid Build Coastguard Worker 	  if (elfdata != MY_ELFDATA)
644*7304104dSAndroid Build Coastguard Worker 	    {
645*7304104dSAndroid Build Coastguard Worker 	      CONVERT (chdr.ch_type);
646*7304104dSAndroid Build Coastguard Worker 	      CONVERT (chdr.ch_size);
647*7304104dSAndroid Build Coastguard Worker 	      CONVERT (chdr.ch_addralign);
648*7304104dSAndroid Build Coastguard Worker 	    }
649*7304104dSAndroid Build Coastguard Worker 	  memcpy (out_buf, &chdr, sizeof (Elf32_Chdr));
650*7304104dSAndroid Build Coastguard Worker 	}
651*7304104dSAndroid Build Coastguard Worker       else
652*7304104dSAndroid Build Coastguard Worker 	{
653*7304104dSAndroid Build Coastguard Worker 	  Elf64_Chdr chdr;
654*7304104dSAndroid Build Coastguard Worker 	  chdr.ch_type = type;
655*7304104dSAndroid Build Coastguard Worker 	  chdr.ch_reserved = 0;
656*7304104dSAndroid Build Coastguard Worker 	  chdr.ch_size = orig_size;
657*7304104dSAndroid Build Coastguard Worker 	  chdr.ch_addralign = sh_addralign;
658*7304104dSAndroid Build Coastguard Worker 	  if (elfdata != MY_ELFDATA)
659*7304104dSAndroid Build Coastguard Worker 	    {
660*7304104dSAndroid Build Coastguard Worker 	      CONVERT (chdr.ch_type);
661*7304104dSAndroid Build Coastguard Worker 	      CONVERT (chdr.ch_reserved);
662*7304104dSAndroid Build Coastguard Worker 	      CONVERT (chdr.ch_size);
663*7304104dSAndroid Build Coastguard Worker 	      CONVERT (chdr.ch_addralign);
664*7304104dSAndroid Build Coastguard Worker 	    }
665*7304104dSAndroid Build Coastguard Worker 	  memcpy (out_buf, &chdr, sizeof (Elf64_Chdr));
666*7304104dSAndroid Build Coastguard Worker 	}
667*7304104dSAndroid Build Coastguard Worker 
668*7304104dSAndroid Build Coastguard Worker       /* Note we keep the sh_entsize as is, we assume it is setup
669*7304104dSAndroid Build Coastguard Worker 	 correctly and ignored when SHF_COMPRESSED is set.  */
670*7304104dSAndroid Build Coastguard Worker       if (elfclass == ELFCLASS32)
671*7304104dSAndroid Build Coastguard Worker 	{
672*7304104dSAndroid Build Coastguard Worker 	  Elf32_Shdr *shdr = elf32_getshdr (scn);
673*7304104dSAndroid Build Coastguard Worker 	  shdr->sh_size = new_size;
674*7304104dSAndroid Build Coastguard Worker 	  shdr->sh_addralign = __libelf_type_align (ELFCLASS32, ELF_T_CHDR);
675*7304104dSAndroid Build Coastguard Worker 	  shdr->sh_flags |= SHF_COMPRESSED;
676*7304104dSAndroid Build Coastguard Worker 	}
677*7304104dSAndroid Build Coastguard Worker       else
678*7304104dSAndroid Build Coastguard Worker 	{
679*7304104dSAndroid Build Coastguard Worker 	  Elf64_Shdr *shdr = elf64_getshdr (scn);
680*7304104dSAndroid Build Coastguard Worker 	  shdr->sh_size = new_size;
681*7304104dSAndroid Build Coastguard Worker 	  shdr->sh_addralign = __libelf_type_align (ELFCLASS64, ELF_T_CHDR);
682*7304104dSAndroid Build Coastguard Worker 	  shdr->sh_flags |= SHF_COMPRESSED;
683*7304104dSAndroid Build Coastguard Worker 	}
684*7304104dSAndroid Build Coastguard Worker 
685*7304104dSAndroid Build Coastguard Worker       __libelf_reset_rawdata (scn, out_buf, new_size, 1, ELF_T_CHDR);
686*7304104dSAndroid Build Coastguard Worker 
687*7304104dSAndroid Build Coastguard Worker       /* The section is now compressed, we could keep the uncompressed
688*7304104dSAndroid Build Coastguard Worker 	 data around, but since that might have been multiple Elf_Data
689*7304104dSAndroid Build Coastguard Worker 	 buffers let the user uncompress it explicitly again if they
690*7304104dSAndroid Build Coastguard Worker 	 want it to simplify bookkeeping.  */
691*7304104dSAndroid Build Coastguard Worker       free (scn->zdata_base);
692*7304104dSAndroid Build Coastguard Worker       scn->zdata_base = NULL;
693*7304104dSAndroid Build Coastguard Worker 
694*7304104dSAndroid Build Coastguard Worker       return 1;
695*7304104dSAndroid Build Coastguard Worker     }
696*7304104dSAndroid Build Coastguard Worker   else if (type == 0)
697*7304104dSAndroid Build Coastguard Worker     {
698*7304104dSAndroid Build Coastguard Worker       /* Decompress/Inflate.  */
699*7304104dSAndroid Build Coastguard Worker       if (compressed == 0)
700*7304104dSAndroid Build Coastguard Worker 	{
701*7304104dSAndroid Build Coastguard Worker 	  __libelf_seterrno (ELF_E_NOT_COMPRESSED);
702*7304104dSAndroid Build Coastguard Worker 	  return -1;
703*7304104dSAndroid Build Coastguard Worker 	}
704*7304104dSAndroid Build Coastguard Worker 
705*7304104dSAndroid Build Coastguard Worker       /* If the data is already decompressed (by elf_strptr), then we
706*7304104dSAndroid Build Coastguard Worker 	 only need to setup the rawdata and section header. XXX what
707*7304104dSAndroid Build Coastguard Worker 	 about elf_newdata?  */
708*7304104dSAndroid Build Coastguard Worker       if (scn->zdata_base == NULL)
709*7304104dSAndroid Build Coastguard Worker 	{
710*7304104dSAndroid Build Coastguard Worker 	  size_t size_out, addralign;
711*7304104dSAndroid Build Coastguard Worker 	  void *buf_out = __libelf_decompress_elf (scn, &size_out, &addralign);
712*7304104dSAndroid Build Coastguard Worker 	  if (buf_out == NULL)
713*7304104dSAndroid Build Coastguard Worker 	    return -1;
714*7304104dSAndroid Build Coastguard Worker 
715*7304104dSAndroid Build Coastguard Worker 	  scn->zdata_base = buf_out;
716*7304104dSAndroid Build Coastguard Worker 	  scn->zdata_size = size_out;
717*7304104dSAndroid Build Coastguard Worker 	  scn->zdata_align = addralign;
718*7304104dSAndroid Build Coastguard Worker 	}
719*7304104dSAndroid Build Coastguard Worker 
720*7304104dSAndroid Build Coastguard Worker       /* Note we keep the sh_entsize as is, we assume it is setup
721*7304104dSAndroid Build Coastguard Worker 	 correctly and ignored when SHF_COMPRESSED is set.  */
722*7304104dSAndroid Build Coastguard Worker       if (elfclass == ELFCLASS32)
723*7304104dSAndroid Build Coastguard Worker 	{
724*7304104dSAndroid Build Coastguard Worker 	  Elf32_Shdr *shdr = elf32_getshdr (scn);
725*7304104dSAndroid Build Coastguard Worker 	  shdr->sh_size = scn->zdata_size;
726*7304104dSAndroid Build Coastguard Worker 	  shdr->sh_addralign = scn->zdata_align;
727*7304104dSAndroid Build Coastguard Worker 	  shdr->sh_flags &= ~SHF_COMPRESSED;
728*7304104dSAndroid Build Coastguard Worker 	}
729*7304104dSAndroid Build Coastguard Worker       else
730*7304104dSAndroid Build Coastguard Worker 	{
731*7304104dSAndroid Build Coastguard Worker 	  Elf64_Shdr *shdr = elf64_getshdr (scn);
732*7304104dSAndroid Build Coastguard Worker 	  shdr->sh_size = scn->zdata_size;
733*7304104dSAndroid Build Coastguard Worker 	  shdr->sh_addralign = scn->zdata_align;
734*7304104dSAndroid Build Coastguard Worker 	  shdr->sh_flags &= ~SHF_COMPRESSED;
735*7304104dSAndroid Build Coastguard Worker 	}
736*7304104dSAndroid Build Coastguard Worker 
737*7304104dSAndroid Build Coastguard Worker       __libelf_reset_rawdata (scn, scn->zdata_base,
738*7304104dSAndroid Build Coastguard Worker 			      scn->zdata_size, scn->zdata_align,
739*7304104dSAndroid Build Coastguard Worker 			      __libelf_data_type (&ehdr, sh_type,
740*7304104dSAndroid Build Coastguard Worker 						  scn->zdata_align));
741*7304104dSAndroid Build Coastguard Worker 
742*7304104dSAndroid Build Coastguard Worker       return 1;
743*7304104dSAndroid Build Coastguard Worker     }
744*7304104dSAndroid Build Coastguard Worker   else
745*7304104dSAndroid Build Coastguard Worker     {
746*7304104dSAndroid Build Coastguard Worker       __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
747*7304104dSAndroid Build Coastguard Worker       return -1;
748*7304104dSAndroid Build Coastguard Worker     }
749*7304104dSAndroid Build Coastguard Worker }
750