LCOV - code coverage report
Current view: top level - libelf - elf_compress.c (source / functions) Coverage Total Hit
Test: elfutils-0.193 Lines: 86.4 % 323 279
Test Date: 2025-08-30 14:31:09 Functions: 100.0 % 11 11
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 72.1 % 172 124

             Branch data     Line data    Source code
       1                 :             : /* Compress or decompress a section.
       2                 :             :    Copyright (C) 2015, 2016 Red Hat, Inc.
       3                 :             :    Copyright (C) 2023, Mark J. Wielaard <mark@klomp.org>
       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 *
      49                 :         132 : do_deflate_cleanup (void *result, z_stream *z, void *out_buf,
      50                 :             :                     Elf_Data *cdatap)
      51                 :             : {
      52                 :         132 :   deflateEnd (z);
      53                 :         132 :   free (out_buf);
      54         [ +  + ]:         132 :   if (cdatap != NULL)
      55                 :          58 :     free (cdatap->d_buf);
      56                 :         132 :   return result;
      57                 :             : }
      58                 :             : 
      59                 :             : #define deflate_cleanup(result, cdata) \
      60                 :             :     do_deflate_cleanup(result, &z, out_buf, cdata)
      61                 :             : 
      62                 :             : static
      63                 :             : void *
      64                 :        1400 : __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                 :        1400 :   size_t used = hsize;
      72                 :             : 
      73                 :        1400 :   z_stream z;
      74                 :        1400 :   z.zalloc = Z_NULL;
      75                 :        1400 :   z.zfree = Z_NULL;
      76                 :        1400 :   z.opaque = Z_NULL;
      77                 :        1400 :   int zrc = deflateInit (&z, Z_BEST_COMPRESSION);
      78         [ -  + ]:        1400 :   if (zrc != Z_OK)
      79                 :             :     {
      80                 :           0 :       __libelf_seterrno (ELF_E_COMPRESS_ERROR);
      81                 :           0 :       return deflate_cleanup(NULL, NULL);
      82                 :             :     }
      83                 :             : 
      84                 :        1400 :   Elf_Data cdata;
      85                 :        1400 :   cdata.d_buf = NULL;
      86                 :             : 
      87                 :             :   /* Loop over data buffers.  */
      88                 :        1400 :   int flush = Z_NO_FLUSH;
      89                 :        1416 :   do
      90                 :             :     {
      91                 :             :       /* Convert to raw if different endianness.  */
      92                 :        1416 :       cdata = *data;
      93   [ +  +  +  - ]:        1416 :       bool convert = ei_data != MY_ELFDATA && data->d_size > 0;
      94                 :         596 :       if (convert)
      95                 :             :         {
      96                 :             :           /* Don't do this conversion in place, we might want to keep
      97                 :             :              the original data around, caller decides.  */
      98                 :         596 :           cdata.d_buf = malloc (data->d_size);
      99         [ -  + ]:         596 :           if (cdata.d_buf == NULL)
     100                 :             :             {
     101                 :           0 :               __libelf_seterrno (ELF_E_NOMEM);
     102                 :           0 :               return deflate_cleanup (NULL, NULL);
     103                 :             :             }
     104         [ -  + ]:         596 :           if (gelf_xlatetof (scn->elf, &cdata, data, ei_data) == NULL)
     105                 :           0 :             return deflate_cleanup (NULL, &cdata);
     106                 :             :         }
     107                 :             : 
     108                 :        1416 :       z.avail_in = cdata.d_size;
     109                 :        1416 :       z.next_in = cdata.d_buf;
     110                 :             : 
     111                 :             :       /* Get next buffer to see if this is the last one.  */
     112                 :        1416 :       data = next_data;
     113         [ +  + ]:        1416 :       if (data != NULL)
     114                 :             :         {
     115                 :          16 :           *orig_addralign = MAX (*orig_addralign, data->d_align);
     116                 :          16 :           *orig_size += data->d_size;
     117                 :          16 :           next_data = elf_getdata (scn, data);
     118                 :             :         }
     119                 :             :       else
     120                 :        1416 :         flush = Z_FINISH;
     121                 :             : 
     122                 :             :       /* Flush one data buffer.  */
     123                 :        3348 :       do
     124                 :             :         {
     125                 :        3348 :           z.avail_out = out_size - used;
     126                 :        3348 :           z.next_out = out_buf + used;
     127                 :        3348 :           zrc = deflate (&z, flush);
     128         [ -  + ]:        3348 :           if (zrc == Z_STREAM_ERROR)
     129                 :             :             {
     130                 :           0 :               __libelf_seterrno (ELF_E_COMPRESS_ERROR);
     131         [ #  # ]:           0 :               return deflate_cleanup (NULL, convert ? &cdata : NULL);
     132                 :             :             }
     133                 :        3348 :           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   [ +  +  +  + ]:        3348 :           if (!force && flush == Z_FINISH && used >= *orig_size)
     139         [ +  + ]:         206 :             return deflate_cleanup ((void *) -1, convert ? &cdata : NULL);
     140                 :             : 
     141         [ +  + ]:        3216 :           if (z.avail_out == 0)
     142                 :             :             {
     143                 :        1932 :               void *bigger = realloc (out_buf, out_size + block);
     144         [ -  + ]:        1932 :               if (bigger == NULL)
     145                 :             :                 {
     146                 :           0 :                   __libelf_seterrno (ELF_E_NOMEM);
     147         [ #  # ]:           0 :                   return deflate_cleanup (NULL, convert ? &cdata : NULL);
     148                 :             :                 }
     149                 :             :               out_buf = bigger;
     150                 :             :               out_size += block;
     151                 :             :             }
     152                 :             :         }
     153         [ +  + ]:        3216 :       while (z.avail_out == 0); /* Need more output buffer.  */
     154                 :             : 
     155         [ +  + ]:        1284 :       if (convert)
     156                 :             :         {
     157                 :         538 :           free (cdata.d_buf);
     158                 :         538 :           cdata.d_buf = NULL;
     159                 :             :         }
     160                 :             :     }
     161         [ +  + ]:        1284 :   while (flush != Z_FINISH); /* More data blocks.  */
     162                 :             : 
     163         [ -  + ]:        1268 :   if (zrc != Z_STREAM_END)
     164                 :             :     {
     165                 :           0 :       __libelf_seterrno (ELF_E_COMPRESS_ERROR);
     166                 :           0 :       return deflate_cleanup (NULL, NULL);
     167                 :             :     }
     168                 :             : 
     169                 :        1268 :   deflateEnd (&z);
     170                 :        1268 :   *new_size = used;
     171                 :        1268 :   return out_buf;
     172                 :             : }
     173                 :             : 
     174                 :             : #ifdef USE_ZSTD_COMPRESS
     175                 :             : /* Cleanup and return result.  Don't leak memory.  */
     176                 :             : static void *
     177                 :         104 : do_zstd_cleanup (void *result, ZSTD_CCtx * const cctx, void *out_buf,
     178                 :             :                  Elf_Data *cdatap)
     179                 :             : {
     180                 :         104 :   ZSTD_freeCCtx (cctx);
     181                 :         104 :   free (out_buf);
     182         [ +  + ]:         104 :   if (cdatap != NULL)
     183                 :          48 :     free (cdatap->d_buf);
     184                 :         104 :   return result;
     185                 :             : }
     186                 :             : 
     187                 :             : #define zstd_cleanup(result, cdata) \
     188                 :             :     do_zstd_cleanup(result, cctx, out_buf, cdata)
     189                 :             : 
     190                 :             : static
     191                 :             : void *
     192                 :         464 : __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                 :         464 :   size_t used = hsize;
     200                 :             : 
     201                 :         464 :   ZSTD_CCtx* const cctx = ZSTD_createCCtx();
     202                 :         464 :   Elf_Data cdata;
     203                 :         464 :   cdata.d_buf = NULL;
     204                 :             : 
     205                 :             :   /* Loop over data buffers.  */
     206                 :         464 :   ZSTD_EndDirective mode = ZSTD_e_continue;
     207                 :             : 
     208                 :         464 :   do
     209                 :             :     {
     210                 :             :       /* Convert to raw if different endianness.  */
     211                 :         464 :       cdata = *data;
     212   [ +  +  +  - ]:         464 :       bool convert = ei_data != MY_ELFDATA && data->d_size > 0;
     213                 :         240 :       if (convert)
     214                 :             :         {
     215                 :             :           /* Don't do this conversion in place, we might want to keep
     216                 :             :              the original data around, caller decides.  */
     217                 :         240 :           cdata.d_buf = malloc (data->d_size);
     218         [ -  + ]:         240 :           if (cdata.d_buf == NULL)
     219                 :             :             {
     220                 :           0 :               __libelf_seterrno (ELF_E_NOMEM);
     221                 :         104 :               return zstd_cleanup (NULL, NULL);
     222                 :             :             }
     223         [ -  + ]:         240 :           if (gelf_xlatetof (scn->elf, &cdata, data, ei_data) == NULL)
     224                 :           0 :             return zstd_cleanup (NULL, &cdata);
     225                 :             :         }
     226                 :             : 
     227                 :         464 :       ZSTD_inBuffer ib = { cdata.d_buf, cdata.d_size, 0 };
     228                 :             : 
     229                 :             :       /* Get next buffer to see if this is the last one.  */
     230                 :         464 :       data = next_data;
     231         [ -  + ]:         464 :       if (data != NULL)
     232                 :             :         {
     233                 :           0 :           *orig_addralign = MAX (*orig_addralign, data->d_align);
     234                 :           0 :           *orig_size += data->d_size;
     235                 :           0 :           next_data = elf_getdata (scn, data);
     236                 :             :         }
     237                 :             :       else
     238                 :         464 :         mode = ZSTD_e_end;
     239                 :             : 
     240                 :             :       /* Flush one data buffer.  */
     241                 :        1856 :       for (;;)
     242                 :         696 :         {
     243                 :        1160 :           ZSTD_outBuffer ob = { out_buf + used, out_size - used, 0 };
     244                 :        1160 :           size_t ret = ZSTD_compressStream2 (cctx, &ob, &ib, mode);
     245         [ -  + ]:        1160 :           if (ZSTD_isError (ret))
     246                 :             :             {
     247                 :           0 :               __libelf_seterrno (ELF_E_COMPRESS_ERROR);
     248         [ -  - ]:         104 :               return zstd_cleanup (NULL, convert ? &cdata : NULL);
     249                 :             :             }
     250                 :        1160 :           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   [ +  -  +  + ]:        1160 :           if (!force && mode == ZSTD_e_end && used >= *orig_size)
     256         [ +  + ]:         160 :             return zstd_cleanup ((void *) -1, convert ? &cdata : NULL);
     257                 :             : 
     258         [ +  + ]:        1056 :           if (ret > 0)
     259                 :             :             {
     260                 :         696 :               void *bigger = realloc (out_buf, out_size + block);
     261         [ -  + ]:         696 :               if (bigger == NULL)
     262                 :             :                 {
     263                 :           0 :                   __libelf_seterrno (ELF_E_NOMEM);
     264         [ #  # ]:           0 :                   return zstd_cleanup (NULL, convert ? &cdata : NULL);
     265                 :             :                 }
     266                 :         696 :               out_buf = bigger;
     267                 :         696 :               out_size += block;
     268                 :             :             }
     269                 :             :           else
     270                 :             :             break;
     271                 :             :         }
     272                 :             : 
     273         [ +  + ]:         360 :       if (convert)
     274                 :             :         {
     275                 :         192 :           free (cdata.d_buf);
     276                 :         192 :           cdata.d_buf = NULL;
     277                 :             :         }
     278                 :             :     }
     279         [ -  + ]:         360 :   while (mode != ZSTD_e_end); /* More data blocks.  */
     280                 :             : 
     281                 :         360 :   ZSTD_freeCCtx (cctx);
     282                 :         360 :   *new_size = used;
     283                 :         360 :   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
     296                 :        1920 : __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                 :        1920 :   Elf_Data *data = elf_getdata (scn, NULL);
     307         [ -  + ]:        1920 :   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                 :        1920 :   Elf_Data *next_data = elf_getdata (scn, data);
     316         [ +  + ]:        1920 :   if (next_data == NULL && !force
     317         [ +  + ]:        1428 :       && data->d_size <= hsize + 5 + 6)
     318                 :             :     return (void *) -1;
     319                 :             : 
     320                 :        1864 :   *orig_addralign = data->d_align;
     321                 :        1864 :   *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                 :        1864 :   size_t block = (data->d_size / 8) + hsize;
     327                 :        1864 :   size_t out_size = 2 * block;
     328                 :        1864 :   void *out_buf = malloc (out_size);
     329         [ -  + ]:        1864 :   if (out_buf == NULL)
     330                 :             :     {
     331                 :           0 :       __libelf_seterrno (ELF_E_NOMEM);
     332                 :           0 :       return NULL;
     333                 :             :     }
     334                 :             : 
     335         [ +  + ]:        1864 :   if (use_zstd)
     336                 :             :     {
     337                 :             : #ifdef USE_ZSTD_COMPRESS
     338                 :         464 :       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                 :        1400 :     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
     356                 :        2552 : __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         [ -  + ]:        2552 :   if (unlikely (size_out / 1032 > size_in))
     362                 :             :     {
     363                 :           0 :       __libelf_seterrno (ELF_E_INVALID_DATA);
     364                 :           0 :       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                 :        2552 :   void *buf_out = malloc (size_out ?: 1);
     372         [ -  + ]:        2552 :   if (unlikely (buf_out == NULL))
     373                 :             :     {
     374                 :           0 :       __libelf_seterrno (ELF_E_NOMEM);
     375                 :           0 :       return NULL;
     376                 :             :     }
     377                 :             : 
     378                 :        2552 :   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                 :        2552 :   int zrc = inflateInit (&z);
     386   [ +  +  +  - ]:        5104 :   while (z.avail_in > 0 && likely (zrc == Z_OK))
     387                 :             :     {
     388                 :        2552 :       z.next_out = buf_out + (size_out - z.avail_out);
     389                 :        2552 :       zrc = inflate (&z, Z_FINISH);
     390         [ +  - ]:        2552 :       if (unlikely (zrc != Z_STREAM_END))
     391                 :             :         {
     392                 :             :           zrc = Z_DATA_ERROR;
     393                 :             :           break;
     394                 :             :         }
     395                 :        2552 :       zrc = inflateReset (&z);
     396                 :             :     }
     397                 :             : 
     398   [ +  -  -  + ]:        2552 :   if (unlikely (zrc != Z_OK) || unlikely (z.avail_out != 0))
     399                 :             :     {
     400                 :           0 :       free (buf_out);
     401                 :           0 :       buf_out = NULL;
     402                 :           0 :       __libelf_seterrno (ELF_E_DECOMPRESS_ERROR);
     403                 :             :     }
     404                 :             : 
     405                 :        2552 :   inflateEnd(&z);
     406                 :        2552 :   return buf_out;
     407                 :             : }
     408                 :             : 
     409                 :             : #ifdef USE_ZSTD
     410                 :             : static void *
     411                 :         180 : __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                 :         180 :   void *buf_out = malloc (size_out ?: 1);
     418         [ -  + ]:         180 :   if (unlikely (buf_out == NULL))
     419                 :             :     {
     420                 :           0 :       __libelf_seterrno (ELF_E_NOMEM);
     421                 :           0 :       return NULL;
     422                 :             :     }
     423                 :             : 
     424                 :         180 :   size_t ret = ZSTD_decompress (buf_out, size_out, buf_in, size_in);
     425   [ +  -  -  + ]:         180 :   if (unlikely (ZSTD_isError (ret)) || unlikely (ret != size_out))
     426                 :             :     {
     427                 :           0 :       free (buf_out);
     428                 :           0 :       __libelf_seterrno (ELF_E_DECOMPRESS_ERROR);
     429                 :           0 :       return NULL;
     430                 :             :     }
     431                 :             :   else
     432                 :             :     return buf_out;
     433                 :             : }
     434                 :             : #endif
     435                 :             : 
     436                 :             : void *
     437                 :             : internal_function
     438                 :        2732 : __libelf_decompress (int chtype, void *buf_in, size_t size_in, size_t size_out)
     439                 :             : {
     440         [ +  + ]:        2732 :   if (chtype == ELFCOMPRESS_ZLIB)
     441                 :        2552 :     return __libelf_decompress_zlib (buf_in, size_in, size_out);
     442                 :             :   else
     443                 :             :     {
     444                 :             : #ifdef USE_ZSTD
     445                 :         180 :     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
     455                 :        2140 : __libelf_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign)
     456                 :             : {
     457                 :        2140 :   GElf_Chdr chdr;
     458         [ -  + ]:        2140 :   if (gelf_getchdr (scn, &chdr) == NULL)
     459                 :             :     return NULL;
     460                 :             : 
     461                 :        2140 :   bool unknown_compression = false;
     462         [ +  + ]:        2140 :   if (chdr.ch_type != ELFCOMPRESS_ZLIB)
     463                 :             :     {
     464         [ -  + ]:         180 :       if (chdr.ch_type != ELFCOMPRESS_ZSTD)
     465                 :           0 :         unknown_compression = true;
     466                 :             : 
     467                 :             : #ifndef USE_ZSTD
     468                 :             :       if (chdr.ch_type == ELFCOMPRESS_ZSTD)
     469                 :             :         unknown_compression = true;
     470                 :             : #endif
     471                 :             :     }
     472                 :             : 
     473                 :           0 :   if (unknown_compression)
     474                 :             :     {
     475                 :           0 :       __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
     476                 :           0 :       return NULL;
     477                 :             :     }
     478                 :             : 
     479         [ -  + ]:        2140 :   if (! powerof2 (chdr.ch_addralign))
     480                 :             :     {
     481                 :           0 :       __libelf_seterrno (ELF_E_INVALID_ALIGN);
     482                 :           0 :       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                 :        2140 :   Elf_Data *data = elf_getdata (scn, NULL);
     492         [ -  + ]:        2140 :   if (data == NULL)
     493                 :             :     return NULL;
     494                 :             : 
     495                 :        2140 :   int elfclass = scn->elf->class;
     496                 :        4280 :   size_t hsize = (elfclass == ELFCLASS32
     497         [ +  + ]:        2140 :                   ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
     498                 :        2140 :   size_t size_in = data->d_size - hsize;
     499                 :        2140 :   void *buf_in = data->d_buf + hsize;
     500                 :        2140 :   void *buf_out
     501                 :        2140 :     = __libelf_decompress (chdr.ch_type, buf_in, size_in, chdr.ch_size);
     502                 :             : 
     503                 :        2140 :   *size_out = chdr.ch_size;
     504                 :        2140 :   *addralign = chdr.ch_addralign;
     505                 :        2140 :   return buf_out;
     506                 :             : }
     507                 :             : 
     508                 :             : /* Assumes buf is a malloced buffer.  */
     509                 :             : void
     510                 :             : internal_function
     511                 :        4352 : __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                 :        4352 :   scn->rawdata.d.d_off = 0;
     516                 :        4352 :   scn->rawdata.d.d_version = EV_CURRENT;
     517                 :        4352 :   scn->rawdata.d.d_buf = buf;
     518                 :        4352 :   scn->rawdata.d.d_size = size;
     519                 :        4352 :   scn->rawdata.d.d_align = align;
     520                 :        4352 :   scn->rawdata.d.d_type = type;
     521                 :             : 
     522                 :             :   /* Remove the old data.  */
     523                 :        4352 :   Elf_Data_List *runp = scn->data_list.next;
     524         [ +  + ]:        4368 :   while (runp != NULL)
     525                 :             :     {
     526                 :          16 :       Elf_Data_List *oldp = runp;
     527                 :          16 :       runp = runp->next;
     528         [ +  - ]:          16 :       if ((oldp->flags & ELF_F_MALLOCED) != 0)
     529                 :          16 :         free (oldp);
     530                 :             :     }
     531                 :             :   /* Existing existing data is no longer valid.  */
     532                 :        4352 :   scn->data_list.next = NULL;
     533                 :        4352 :   scn->data_list_rear = NULL;
     534         [ +  + ]:        4352 :   if (scn->data_base != scn->rawdata_base)
     535                 :        1092 :     free (scn->data_base);
     536                 :        4352 :   scn->data_base = NULL;
     537         [ +  + ]:        4352 :   if (scn->zdata_base != buf
     538         [ +  + ]:        2220 :       && scn->zdata_base != scn->rawdata_base)
     539                 :             :     {
     540                 :        2192 :       free (scn->zdata_base);
     541                 :        2192 :       scn->zdata_base = NULL;
     542                 :             :     }
     543         [ +  + ]:        4352 :   if (scn->elf->map_address == NULL
     544         [ +  - ]:        1544 :       || scn->rawdata_base == scn->zdata_base
     545         [ +  + ]:        1544 :       || (scn->flags & ELF_F_MALLOCED) != 0)
     546                 :             :     {
     547                 :        2812 :       free (scn->rawdata_base);
     548                 :        2812 :       scn->rawdata_base = NULL;
     549                 :        2812 :       scn->zdata_base = NULL;
     550                 :             :     }
     551                 :             : 
     552                 :        4352 :   scn->rawdata_base = buf;
     553                 :        4352 :   scn->flags |= ELF_F_MALLOCED;
     554                 :             : 
     555                 :             :   /* Pretend we (tried to) read the data from the file and setup the
     556                 :             :      data (might have to convert the Chdr to native format).  */
     557                 :        4352 :   scn->data_read = 1;
     558                 :        4352 :   scn->flags |= ELF_F_FILEDATA;
     559                 :        4352 :   __libelf_set_data_list_rdlock (scn, 1);
     560                 :        4352 : }
     561                 :             : 
     562                 :             : int
     563                 :      801610 : elf_compress (Elf_Scn *scn, int type, unsigned int flags)
     564                 :             : {
     565         [ -  + ]:      801610 :   if (scn == NULL)
     566                 :             :     return -1;
     567                 :             : 
     568         [ -  + ]:      801610 :   if ((flags & ~ELF_CHF_FORCE) != 0)
     569                 :             :     {
     570                 :           0 :       __libelf_seterrno (ELF_E_INVALID_OPERAND);
     571                 :           0 :       return -1;
     572                 :             :     }
     573                 :             : 
     574                 :      801610 :   bool force = (flags & ELF_CHF_FORCE) != 0;
     575                 :             : 
     576                 :      801610 :   Elf *elf = scn->elf;
     577                 :      801610 :   GElf_Ehdr ehdr;
     578         [ -  + ]:      801610 :   if (gelf_getehdr (elf, &ehdr) == NULL)
     579                 :             :     return -1;
     580                 :             : 
     581                 :      801610 :   int elfclass = elf->class;
     582                 :      801610 :   int elfdata = ehdr.e_ident[EI_DATA];
     583                 :             : 
     584                 :      801610 :   Elf64_Xword sh_flags;
     585                 :      801610 :   Elf64_Word sh_type;
     586                 :      801610 :   Elf64_Xword sh_addralign;
     587                 :      801610 :   union shdr
     588                 :             :   {
     589                 :             :     Elf32_Shdr *s32;
     590                 :             :     Elf64_Shdr *s64;
     591                 :             :   } shdr;
     592         [ +  + ]:      801610 :   if (elfclass == ELFCLASS32)
     593                 :             :     {
     594                 :      793306 :       shdr.s32 = elf32_getshdr (scn);
     595         [ -  + ]:      793306 :       if (shdr.s32 == NULL)
     596                 :             :         return -1;
     597                 :             : 
     598                 :      793306 :       sh_flags = shdr.s32->sh_flags;
     599                 :      793306 :       sh_type = shdr.s32->sh_type;
     600                 :      793306 :       sh_addralign = shdr.s32->sh_addralign;
     601                 :             :     }
     602                 :             :   else
     603                 :             :     {
     604                 :        8304 :       shdr.s64 = elf64_getshdr (scn);
     605         [ -  + ]:        8304 :       if (shdr.s64 == NULL)
     606                 :             :         return -1;
     607                 :             : 
     608                 :        8304 :       sh_flags = shdr.s64->sh_flags;
     609                 :        8304 :       sh_type = shdr.s64->sh_type;
     610                 :        8304 :       sh_addralign = shdr.s64->sh_addralign;
     611                 :             :     }
     612                 :             : 
     613         [ +  + ]:      801610 :   if ((sh_flags & SHF_ALLOC) != 0)
     614                 :             :     {
     615                 :      313912 :       __libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
     616                 :      313912 :       return -1;
     617                 :             :     }
     618                 :             : 
     619         [ +  + ]:      487698 :   if (sh_type == SHT_NULL || sh_type == SHT_NOBITS)
     620                 :             :     {
     621                 :      131156 :       __libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
     622                 :      131156 :       return -1;
     623                 :             :     }
     624                 :             : 
     625                 :      356542 :   int compressed = (sh_flags & SHF_COMPRESSED);
     626         [ +  + ]:      356542 :   if (type == ELFCOMPRESS_ZLIB || type == ELFCOMPRESS_ZSTD)
     627                 :             :     {
     628                 :             :       /* Compress/Deflate.  */
     629                 :        1086 :       if (compressed == 1)
     630                 :             :         {
     631                 :             :           __libelf_seterrno (ELF_E_ALREADY_COMPRESSED);
     632                 :             :           return -1;
     633                 :             :         }
     634                 :             : 
     635                 :        2172 :       size_t hsize = (elfclass == ELFCLASS32
     636         [ +  + ]:        1086 :                       ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
     637                 :        1086 :       size_t orig_size, orig_addralign, new_size;
     638                 :        1086 :       void *out_buf = __libelf_compress (scn, hsize, elfdata,
     639                 :             :                                          &orig_size, &orig_addralign,
     640                 :             :                                          &new_size, force,
     641                 :             :                                          type == ELFCOMPRESS_ZSTD);
     642                 :             : 
     643                 :             :       /* Compression would make section larger, don't change anything.  */
     644         [ +  + ]:        1086 :       if (out_buf == (void *) -1)
     645                 :             :         return 0;
     646                 :             : 
     647                 :             :       /* Compression failed, return error.  */
     648         [ +  - ]:         900 :       if (out_buf == NULL)
     649                 :             :         return -1;
     650                 :             : 
     651                 :             :       /* Put the header in front of the data.  */
     652         [ +  + ]:         900 :       if (elfclass == ELFCLASS32)
     653                 :             :         {
     654                 :         342 :           Elf32_Chdr chdr;
     655                 :         342 :           chdr.ch_type = type;
     656                 :         342 :           chdr.ch_size = orig_size;
     657                 :         342 :           chdr.ch_addralign = orig_addralign;
     658         [ +  + ]:         342 :           if (elfdata != MY_ELFDATA)
     659                 :             :             {
     660                 :         192 :               CONVERT (chdr.ch_type);
     661                 :         192 :               CONVERT (chdr.ch_size);
     662                 :         192 :               CONVERT (chdr.ch_addralign);
     663                 :             :             }
     664                 :         342 :           memcpy (out_buf, &chdr, sizeof (Elf32_Chdr));
     665                 :             :         }
     666                 :             :       else
     667                 :             :         {
     668                 :         558 :           Elf64_Chdr chdr;
     669                 :         558 :           chdr.ch_type = type;
     670                 :         558 :           chdr.ch_reserved = 0;
     671                 :         558 :           chdr.ch_size = orig_size;
     672                 :         558 :           chdr.ch_addralign = sh_addralign;
     673         [ +  + ]:         558 :           if (elfdata != MY_ELFDATA)
     674                 :             :             {
     675                 :         190 :               CONVERT (chdr.ch_type);
     676                 :         190 :               CONVERT (chdr.ch_reserved);
     677                 :         190 :               CONVERT (chdr.ch_size);
     678                 :         190 :               CONVERT (chdr.ch_addralign);
     679                 :             :             }
     680                 :         558 :           memcpy (out_buf, &chdr, sizeof (Elf64_Chdr));
     681                 :             :         }
     682                 :             : 
     683                 :             :       /* Note we keep the sh_entsize as is, we assume it is setup
     684                 :             :          correctly and ignored when SHF_COMPRESSED is set.  */
     685         [ +  + ]:         900 :       if (elfclass == ELFCLASS32)
     686                 :             :         {
     687                 :         342 :           shdr.s32->sh_size = new_size;
     688                 :         342 :           shdr.s32->sh_addralign = __libelf_type_align (ELFCLASS32,
     689                 :             :                                                         ELF_T_CHDR);
     690                 :         342 :           shdr.s32->sh_flags |= SHF_COMPRESSED;
     691                 :             :         }
     692                 :             :       else
     693                 :             :         {
     694                 :         558 :           shdr.s64->sh_size = new_size;
     695                 :         558 :           shdr.s64->sh_addralign = __libelf_type_align (ELFCLASS64,
     696                 :             :                                                         ELF_T_CHDR);
     697                 :         558 :           shdr.s64->sh_flags |= SHF_COMPRESSED;
     698                 :             :         }
     699                 :             : 
     700                 :         900 :       __libelf_reset_rawdata (scn, out_buf, new_size, 1, ELF_T_CHDR);
     701                 :             : 
     702                 :             :       /* The section is now compressed, we could keep the uncompressed
     703                 :             :          data around, but since that might have been multiple Elf_Data
     704                 :             :          buffers let the user uncompress it explicitly again if they
     705                 :             :          want it to simplify bookkeeping.  */
     706                 :         900 :       free (scn->zdata_base);
     707                 :         900 :       scn->zdata_base = NULL;
     708                 :             : 
     709                 :         900 :       return 1;
     710                 :             :     }
     711         [ +  - ]:      355456 :   else if (type == 0)
     712                 :             :     {
     713                 :             :       /* Decompress/Inflate.  */
     714         [ +  + ]:      355456 :       if (compressed == 0)
     715                 :             :         {
     716                 :      353324 :           __libelf_seterrno (ELF_E_NOT_COMPRESSED);
     717                 :      353324 :           return -1;
     718                 :             :         }
     719                 :             : 
     720                 :             :       /* If the data is already decompressed (by elf_strptr), then we
     721                 :             :          only need to setup the rawdata and section header. XXX what
     722                 :             :          about elf_newdata?  */
     723         [ +  + ]:        2132 :       if (scn->zdata_base == NULL)
     724                 :             :         {
     725                 :        2128 :           size_t size_out, addralign;
     726                 :        2128 :           void *buf_out = __libelf_decompress_elf (scn, &size_out, &addralign);
     727         [ -  + ]:        2128 :           if (buf_out == NULL)
     728                 :           0 :             return -1;
     729                 :             : 
     730                 :        2128 :           scn->zdata_base = buf_out;
     731                 :        2128 :           scn->zdata_size = size_out;
     732                 :        2128 :           scn->zdata_align = addralign;
     733                 :             :         }
     734                 :             : 
     735                 :             :       /* Note we keep the sh_entsize as is, we assume it is setup
     736                 :             :          correctly and ignored when SHF_COMPRESSED is set.  */
     737         [ +  + ]:        2132 :       if (elfclass == ELFCLASS32)
     738                 :             :         {
     739                 :         520 :           shdr.s32->sh_size = scn->zdata_size;
     740                 :         520 :           shdr.s32->sh_addralign = scn->zdata_align;
     741                 :         520 :           shdr.s32->sh_flags &= ~SHF_COMPRESSED;
     742                 :             :         }
     743                 :             :       else
     744                 :             :         {
     745                 :        1612 :           shdr.s64->sh_size = scn->zdata_size;
     746                 :        1612 :           shdr.s64->sh_addralign = scn->zdata_align;
     747                 :        1612 :           shdr.s64->sh_flags &= ~SHF_COMPRESSED;
     748                 :             :         }
     749                 :             : 
     750                 :        2132 :       __libelf_reset_rawdata (scn, scn->zdata_base,
     751                 :             :                               scn->zdata_size, scn->zdata_align,
     752                 :             :                               __libelf_data_type (&ehdr, sh_type,
     753                 :             :                                                   scn->zdata_align));
     754                 :             : 
     755                 :        2132 :       return 1;
     756                 :             :     }
     757                 :             :   else
     758                 :             :     {
     759                 :           0 :       __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
     760                 :           0 :       return -1;
     761                 :             :     }
     762                 :             : }
        

Generated by: LCOV version 2.0-1