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