Coverage Report

Created: 2025-06-22 06:57

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