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