1 /* Compress or decompress a section.
2 Copyright (C) 2015 Red Hat, Inc.
3 This file is part of elfutils.
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
8 * the GNU Lesser General Public License as published by the Free
9 Software Foundation; either version 3 of the License, or (at
10 your option) any later version
14 * the GNU General Public License as published by the Free
15 Software Foundation; either version 2 of the License, or (at
16 your option) any later version
18 or both in parallel, as here.
20 elfutils is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
25 You should have received copies of the GNU General Public License and
26 the GNU Lesser General Public License along with this program. If
27 not, see <http://www.gnu.org/licenses/>. */
40 #include <sys/param.h>
45 # define MAX(a, b) ((a) > (b) ? (a) : (b))
48 /* Given a section, uses the (in-memory) Elf_Data to extract the
49 original data size (including the given header size) and data
50 alignment. Returns a buffer that has at least hsize bytes (for the
51 caller to fill in with a header) plus zlib compressed date. Also
52 returns the new buffer size in new_size (hsize + compressed data
53 size). Returns (void *) -1 when FORCE is false and the compressed
54 data would be bigger than the original data. */
57 __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data,
58 size_t *orig_size, size_t *orig_addralign,
59 size_t *new_size, bool force)
61 /* The compressed data is the on-disk data. We simplify the
62 implementation a bit by asking for the (converted) in-memory
63 data (which might be all there is if the user created it with
64 elf_newdata) and then convert back to raw if needed before
65 compressing. Should be made a bit more clever to directly
66 use raw if that is directly available. */
67 Elf_Data *data = elf_getdata (scn, NULL);
71 /* When not forced and we immediately know we would use more data by
72 compressing, because of the header plus zlib overhead (five bytes
73 per 16 KB block, plus a one-time overhead of six bytes for the
74 entire stream), don't do anything. */
75 Elf_Data *next_data = elf_getdata (scn, data);
76 if (next_data == NULL && !force
77 && data->d_size <= hsize + 5 + 6)
80 *orig_addralign = data->d_align;
81 *orig_size = data->d_size;
83 /* Guess an output block size. 1/8th of the original Elf_Data plus
84 hsize. Make the first chunk twice that size (25%), then increase
85 by a block (12.5%) when necessary. */
86 size_t block = (data->d_size / 8) + hsize;
87 size_t out_size = 2 * block;
88 void *out_buf = malloc (out_size);
91 __libelf_seterrno (ELF_E_NOMEM);
95 /* Caller gets to fill in the header at the start. Just skip it here. */
102 int zrc = deflateInit (&z, Z_BEST_COMPRESSION);
105 __libelf_seterrno (ELF_E_COMPRESS_ERROR);
112 /* Cleanup and return result. Don't leak memory. */
113 void *deflate_cleanup (void *result)
117 if (ei_data != MY_ELFDATA)
122 /* Loop over data buffers. */
123 int flush = Z_NO_FLUSH;
126 /* Convert to raw if different endianess. */
128 if (ei_data != MY_ELFDATA)
130 /* Don't do this conversion in place, we might want to keep
131 the original data around, caller decides. */
132 cdata.d_buf = malloc (data->d_size);
133 if (cdata.d_buf == NULL)
135 __libelf_seterrno (ELF_E_NOMEM);
136 return deflate_cleanup (NULL);
138 if (gelf_xlatetof (scn->elf, &cdata, data, ei_data) == NULL)
139 return deflate_cleanup (NULL);
142 z.avail_in = cdata.d_size;
143 z.next_in = cdata.d_buf;
145 /* Get next buffer to see if this is the last one. */
149 *orig_addralign = MAX (*orig_addralign, data->d_align);
150 *orig_size += data->d_size;
151 next_data = elf_getdata (scn, data);
156 /* Flush one data buffer. */
159 z.avail_out = out_size - used;
160 z.next_out = out_buf + used;
161 zrc = deflate (&z, flush);
162 if (zrc == Z_STREAM_ERROR)
164 __libelf_seterrno (ELF_E_COMPRESS_ERROR);
165 return deflate_cleanup (NULL);
167 used += (out_size - used) - z.avail_out;
169 /* Bail out if we are sure the user doesn't want the
170 compression forced and we are using more compressed data
171 than original data. */
172 if (!force && flush == Z_FINISH && used >= *orig_size)
173 return deflate_cleanup ((void *) -1);
175 if (z.avail_out == 0)
177 void *bigger = realloc (out_buf, out_size + block);
180 __libelf_seterrno (ELF_E_NOMEM);
181 return deflate_cleanup (NULL);
187 while (z.avail_out == 0); /* Need more output buffer. */
189 if (ei_data != MY_ELFDATA)
195 while (flush != Z_FINISH); /* More data blocks. */
197 zrc = deflateEnd (&z);
200 __libelf_seterrno (ELF_E_COMPRESS_ERROR);
201 return deflate_cleanup (NULL);
210 __libelf_decompress (void *buf_in, size_t size_in, size_t size_out)
212 void *buf_out = malloc (size_out);
213 if (unlikely (buf_out == NULL))
215 __libelf_seterrno (ELF_E_NOMEM);
224 .avail_out = size_out
226 int zrc = inflateInit (&z);
227 while (z.avail_in > 0 && likely (zrc == Z_OK))
229 z.next_out = buf_out + (size_out - z.avail_out);
230 zrc = inflate (&z, Z_FINISH);
231 if (unlikely (zrc != Z_STREAM_END))
236 zrc = inflateReset (&z);
238 if (likely (zrc == Z_OK))
239 zrc = inflateEnd (&z);
241 if (unlikely (zrc != Z_OK) || unlikely (z.avail_out != 0))
244 __libelf_seterrno (ELF_E_DECOMPRESS_ERROR);
253 __libelf_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign)
256 if (gelf_getchdr (scn, &chdr) == NULL)
259 if (chdr.ch_type != ELFCOMPRESS_ZLIB)
261 __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
265 if (! powerof2 (chdr.ch_addralign))
267 __libelf_seterrno (ELF_E_INVALID_ALIGN);
271 /* Take the in-memory representation, so we can even handle a
272 section that has just been constructed (maybe it was copied
273 over from some other ELF file first with elf_newdata). This
274 is slightly inefficient when the raw data needs to be
275 converted since then we'll be converting the whole buffer and
277 Elf_Data *data = elf_getdata (scn, NULL);
281 int elfclass = scn->elf->class;
282 size_t hsize = (elfclass == ELFCLASS32
283 ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
284 size_t size_in = data->d_size - hsize;
285 void *buf_in = data->d_buf + hsize;
286 void *buf_out = __libelf_decompress (buf_in, size_in, chdr.ch_size);
287 *size_out = chdr.ch_size;
288 *addralign = chdr.ch_addralign;
294 __libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size, size_t align,
297 /* This is the new raw data, replace and possibly free old data. */
298 scn->rawdata.d.d_off = 0;
299 scn->rawdata.d.d_version = __libelf_version;
300 scn->rawdata.d.d_buf = buf;
301 scn->rawdata.d.d_size = size;
302 scn->rawdata.d.d_align = align;
303 scn->rawdata.d.d_type = type;
305 /* Existing existing data is no longer valid. */
306 scn->data_list_rear = NULL;
307 if (scn->data_base != scn->rawdata_base)
308 free (scn->data_base);
309 scn->data_base = NULL;
310 if (scn->elf->map_address == NULL
311 || scn->rawdata_base == scn->zdata_base)
312 free (scn->rawdata_base);
314 scn->rawdata_base = buf;
318 elf_compress (Elf_Scn *scn, int type, unsigned int flags)
323 if ((flags & ~ELF_CHF_FORCE) != 0)
325 __libelf_seterrno (ELF_E_INVALID_OPERAND);
329 bool force = (flags & ELF_CHF_FORCE) != 0;
333 if (gelf_getehdr (elf, &ehdr) == NULL)
336 int elfclass = elf->class;
337 int elfdata = ehdr.e_ident[EI_DATA];
339 Elf64_Xword sh_flags;
341 Elf64_Xword sh_addralign;
342 if (elfclass == ELFCLASS32)
344 Elf32_Shdr *shdr = elf32_getshdr (scn);
348 sh_flags = shdr->sh_flags;
349 sh_type = shdr->sh_type;
350 sh_addralign = shdr->sh_addralign;
354 Elf64_Shdr *shdr = elf64_getshdr (scn);
358 sh_flags = shdr->sh_flags;
359 sh_type = shdr->sh_type;
360 sh_addralign = shdr->sh_addralign;
363 if ((sh_flags & SHF_ALLOC) != 0)
365 __libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
369 if (sh_type == SHT_NULL || sh_type == SHT_NOBITS)
371 __libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
375 int compressed = (sh_flags & SHF_COMPRESSED);
376 if (type == ELFCOMPRESS_ZLIB)
378 /* Compress/Deflate. */
381 __libelf_seterrno (ELF_E_ALREADY_COMPRESSED);
385 size_t hsize = (elfclass == ELFCLASS32
386 ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
387 size_t orig_size, orig_addralign, new_size;
388 void *out_buf = __libelf_compress (scn, hsize, elfdata,
389 &orig_size, &orig_addralign,
392 /* Compression would make section larger, don't change anything. */
393 if (out_buf == (void *) -1)
396 /* Compression failed, return error. */
400 /* Put the header in front of the data. */
401 if (elfclass == ELFCLASS32)
404 chdr.ch_type = ELFCOMPRESS_ZLIB;
405 chdr.ch_size = orig_size;
406 chdr.ch_addralign = orig_addralign;
407 if (elfdata != MY_ELFDATA)
409 CONVERT (chdr.ch_type);
410 CONVERT (chdr.ch_size);
411 CONVERT (chdr.ch_addralign);
413 memcpy (out_buf, &chdr, sizeof (Elf32_Chdr));
418 chdr.ch_type = ELFCOMPRESS_ZLIB;
419 chdr.ch_reserved = 0;
420 chdr.ch_size = orig_size;
421 chdr.ch_addralign = sh_addralign;
422 if (elfdata != MY_ELFDATA)
424 CONVERT (chdr.ch_type);
425 CONVERT (chdr.ch_reserved);
426 CONVERT (chdr.ch_size);
427 CONVERT (chdr.ch_addralign);
429 memcpy (out_buf, &chdr, sizeof (Elf64_Chdr));
432 /* Note we keep the sh_entsize as is, we assume it is setup
433 correctly and ignored when SHF_COMPRESSED is set. */
434 if (elfclass == ELFCLASS32)
436 Elf32_Shdr *shdr = elf32_getshdr (scn);
437 shdr->sh_size = new_size;
438 shdr->sh_addralign = 1;
439 shdr->sh_flags |= SHF_COMPRESSED;
443 Elf64_Shdr *shdr = elf64_getshdr (scn);
444 shdr->sh_size = new_size;
445 shdr->sh_addralign = 1;
446 shdr->sh_flags |= SHF_COMPRESSED;
449 __libelf_reset_rawdata (scn, out_buf, new_size, 1, ELF_T_CHDR);
451 /* The section is now compressed, we could keep the uncompressed
452 data around, but since that might have been multiple Elf_Data
453 buffers let the user uncompress it explicitly again if they
454 want it to simplify bookkeeping. */
455 scn->zdata_base = NULL;
461 /* Decompress/Inflate. */
464 __libelf_seterrno (ELF_E_NOT_COMPRESSED);
468 /* If the data is already decompressed (by elf_strptr), then we
469 only need to setup the rawdata and section header. XXX what
470 about elf_newdata? */
471 if (scn->zdata_base == NULL)
473 size_t size_out, addralign;
474 void *buf_out = __libelf_decompress_elf (scn, &size_out, &addralign);
478 scn->zdata_base = buf_out;
479 scn->zdata_size = size_out;
480 scn->zdata_align = addralign;
483 /* Note we keep the sh_entsize as is, we assume it is setup
484 correctly and ignored when SHF_COMPRESSED is set. */
485 if (elfclass == ELFCLASS32)
487 Elf32_Shdr *shdr = elf32_getshdr (scn);
488 shdr->sh_size = scn->zdata_size;
489 shdr->sh_addralign = scn->zdata_align;
490 shdr->sh_flags &= ~SHF_COMPRESSED;
494 Elf64_Shdr *shdr = elf64_getshdr (scn);
495 shdr->sh_size = scn->zdata_size;
496 shdr->sh_addralign = scn->zdata_align;
497 shdr->sh_flags &= ~SHF_COMPRESSED;
500 __libelf_reset_rawdata (scn, scn->zdata_base,
501 scn->zdata_size, scn->zdata_align,
502 __libelf_data_type (elf, sh_type));
508 __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);