Home | History | Annotate | Line # | Download | only in bfd
compress.c revision 1.1.1.2
      1 /* Compressed section support (intended for debug sections).
      2    Copyright 2008, 2010, 2011, 2012
      3    Free Software Foundation, Inc.
      4 
      5    This file is part of BFD, the Binary File Descriptor library.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program; if not, write to the Free Software
     19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     20    MA 02110-1301, USA.  */
     21 
     22 #include "sysdep.h"
     23 #include "bfd.h"
     24 #include "libbfd.h"
     25 #ifdef HAVE_ZLIB_H
     26 #include <zlib.h>
     27 #endif
     28 
     29 #ifdef HAVE_ZLIB_H
     30 static bfd_boolean
     31 decompress_contents (bfd_byte *compressed_buffer,
     32 		     bfd_size_type compressed_size,
     33 		     bfd_byte *uncompressed_buffer,
     34 		     bfd_size_type uncompressed_size)
     35 {
     36   z_stream strm;
     37   int rc;
     38 
     39   /* It is possible the section consists of several compressed
     40      buffers concatenated together, so we uncompress in a loop.  */
     41   strm.zalloc = NULL;
     42   strm.zfree = NULL;
     43   strm.opaque = NULL;
     44   strm.avail_in = compressed_size - 12;
     45   strm.next_in = (Bytef*) compressed_buffer + 12;
     46   strm.avail_out = uncompressed_size;
     47 
     48   rc = inflateInit (&strm);
     49   while (strm.avail_in > 0 && strm.avail_out > 0)
     50     {
     51       if (rc != Z_OK)
     52 	return FALSE;
     53       strm.next_out = ((Bytef*) uncompressed_buffer
     54                        + (uncompressed_size - strm.avail_out));
     55       rc = inflate (&strm, Z_FINISH);
     56       if (rc != Z_STREAM_END)
     57 	return FALSE;
     58       rc = inflateReset (&strm);
     59     }
     60   rc = inflateEnd (&strm);
     61   return rc == Z_OK && strm.avail_out == 0;
     62 }
     63 #endif
     64 
     65 /*
     66 FUNCTION
     67 	bfd_compress_section_contents
     68 
     69 SYNOPSIS
     70 	bfd_boolean bfd_compress_section_contents
     71 	  (bfd *abfd, asection *section, bfd_byte *uncompressed_buffer,
     72 	   bfd_size_type uncompressed_size);
     73 
     74 DESCRIPTION
     75 
     76 	Compress data of the size specified in @var{uncompressed_size}
     77 	and pointed to by @var{uncompressed_buffer} using zlib and store
     78 	as the contents field.  This function assumes the contents
     79 	field was allocated using bfd_malloc() or equivalent.  If zlib
     80 	is not installed on this machine, the input is unmodified.
     81 
     82 	Return @code{TRUE} if the full section contents is compressed
     83 	successfully.
     84 */
     85 
     86 bfd_boolean
     87 bfd_compress_section_contents (bfd *abfd ATTRIBUTE_UNUSED,
     88 			       sec_ptr sec ATTRIBUTE_UNUSED,
     89 			       bfd_byte *uncompressed_buffer ATTRIBUTE_UNUSED,
     90 			       bfd_size_type uncompressed_size ATTRIBUTE_UNUSED)
     91 {
     92 #ifndef HAVE_ZLIB_H
     93   bfd_set_error (bfd_error_invalid_operation);
     94   return FALSE;
     95 #else
     96   uLong compressed_size;
     97   bfd_byte *compressed_buffer;
     98 
     99   compressed_size = compressBound (uncompressed_size) + 12;
    100   compressed_buffer = (bfd_byte *) bfd_malloc (compressed_size);
    101 
    102   if (compressed_buffer == NULL)
    103     return FALSE;
    104 
    105   if (compress ((Bytef*) compressed_buffer + 12,
    106 		&compressed_size,
    107 		(const Bytef*) uncompressed_buffer,
    108 		uncompressed_size) != Z_OK)
    109     {
    110       free (compressed_buffer);
    111       bfd_set_error (bfd_error_bad_value);
    112       return FALSE;
    113     }
    114 
    115   /* Write the zlib header.  In this case, it should be "ZLIB" followed
    116      by the uncompressed section size, 8 bytes in big-endian order.  */
    117   memcpy (compressed_buffer, "ZLIB", 4);
    118   compressed_buffer[11] = uncompressed_size; uncompressed_size >>= 8;
    119   compressed_buffer[10] = uncompressed_size; uncompressed_size >>= 8;
    120   compressed_buffer[9] = uncompressed_size; uncompressed_size >>= 8;
    121   compressed_buffer[8] = uncompressed_size; uncompressed_size >>= 8;
    122   compressed_buffer[7] = uncompressed_size; uncompressed_size >>= 8;
    123   compressed_buffer[6] = uncompressed_size; uncompressed_size >>= 8;
    124   compressed_buffer[5] = uncompressed_size; uncompressed_size >>= 8;
    125   compressed_buffer[4] = uncompressed_size;
    126   compressed_size += 12;
    127 
    128   /* Free the uncompressed contents if we compress in place.  */
    129   if (uncompressed_buffer == sec->contents)
    130     free (uncompressed_buffer);
    131 
    132   sec->contents = compressed_buffer;
    133   sec->size = compressed_size;
    134   sec->compress_status = COMPRESS_SECTION_DONE;
    135 
    136   return TRUE;
    137 #endif  /* HAVE_ZLIB_H */
    138 }
    139 
    140 /*
    141 FUNCTION
    142 	bfd_get_full_section_contents
    143 
    144 SYNOPSIS
    145 	bfd_boolean bfd_get_full_section_contents
    146 	  (bfd *abfd, asection *section, bfd_byte **ptr);
    147 
    148 DESCRIPTION
    149 	Read all data from @var{section} in BFD @var{abfd}, decompress
    150 	if needed, and store in @var{*ptr}.  If @var{*ptr} is NULL,
    151 	return @var{*ptr} with memory malloc'd by this function.
    152 
    153 	Return @code{TRUE} if the full section contents is retrieved
    154 	successfully.
    155 */
    156 
    157 bfd_boolean
    158 bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
    159 {
    160   bfd_size_type sz;
    161   bfd_byte *p = *ptr;
    162 #ifdef HAVE_ZLIB_H
    163   bfd_boolean ret;
    164   bfd_size_type save_size;
    165   bfd_size_type save_rawsize;
    166   bfd_byte *compressed_buffer;
    167 #endif
    168 
    169   if (abfd->direction != write_direction && sec->rawsize != 0)
    170     sz = sec->rawsize;
    171   else
    172     sz = sec->size;
    173   if (sz == 0)
    174     return TRUE;
    175 
    176   switch (sec->compress_status)
    177     {
    178     case COMPRESS_SECTION_NONE:
    179       if (p == NULL)
    180 	{
    181 	  p = (bfd_byte *) bfd_malloc (sz);
    182 	  if (p == NULL)
    183 	    return FALSE;
    184 	}
    185       if (!bfd_get_section_contents (abfd, sec, p, 0, sz))
    186 	{
    187 	  if (*ptr != p)
    188 	    free (p);
    189 	  return FALSE;
    190 	}
    191       *ptr = p;
    192       return TRUE;
    193 
    194     case DECOMPRESS_SECTION_SIZED:
    195 #ifndef HAVE_ZLIB_H
    196       bfd_set_error (bfd_error_invalid_operation);
    197       return FALSE;
    198 #else
    199       /* Read in the full compressed section contents.  */
    200       compressed_buffer = (bfd_byte *) bfd_malloc (sec->compressed_size);
    201       if (compressed_buffer == NULL)
    202 	return FALSE;
    203       save_rawsize = sec->rawsize;
    204       save_size = sec->size;
    205       /* Clear rawsize, set size to compressed size and set compress_status
    206 	 to COMPRESS_SECTION_NONE.  If the compressed size is bigger than
    207 	 the uncompressed size, bfd_get_section_contents will fail.  */
    208       sec->rawsize = 0;
    209       sec->size = sec->compressed_size;
    210       sec->compress_status = COMPRESS_SECTION_NONE;
    211       ret = bfd_get_section_contents (abfd, sec, compressed_buffer,
    212 				      0, sec->compressed_size);
    213       /* Restore rawsize and size.  */
    214       sec->rawsize = save_rawsize;
    215       sec->size = save_size;
    216       sec->compress_status = DECOMPRESS_SECTION_SIZED;
    217       if (!ret)
    218 	goto fail_compressed;
    219 
    220       if (p == NULL)
    221 	p = (bfd_byte *) bfd_malloc (sz);
    222       if (p == NULL)
    223 	goto fail_compressed;
    224 
    225       if (!decompress_contents (compressed_buffer, sec->compressed_size, p, sz))
    226 	{
    227 	  bfd_set_error (bfd_error_bad_value);
    228 	  if (p != *ptr)
    229 	    free (p);
    230 	fail_compressed:
    231 	  free (compressed_buffer);
    232 	  return FALSE;
    233 	}
    234 
    235       free (compressed_buffer);
    236       *ptr = p;
    237       return TRUE;
    238 #endif
    239 
    240     case COMPRESS_SECTION_DONE:
    241       if (p == NULL)
    242 	{
    243 	  p = (bfd_byte *) bfd_malloc (sz);
    244 	  if (p == NULL)
    245 	    return FALSE;
    246 	  *ptr = p;
    247 	}
    248       memcpy (p, sec->contents, sz);
    249       return TRUE;
    250 
    251     default:
    252       abort ();
    253     }
    254 }
    255 
    256 /*
    257 FUNCTION
    258 	bfd_cache_section_contents
    259 
    260 SYNOPSIS
    261 	void bfd_cache_section_contents
    262 	  (asection *sec, void *contents);
    263 
    264 DESCRIPTION
    265 	Stash @var(contents) so any following reads of @var(sec) do
    266 	not need to decompress again.
    267 */
    268 
    269 void
    270 bfd_cache_section_contents (asection *sec, void *contents)
    271 {
    272   if (sec->compress_status == DECOMPRESS_SECTION_SIZED)
    273     sec->compress_status = COMPRESS_SECTION_DONE;
    274   sec->contents = contents;
    275   sec->flags |= SEC_IN_MEMORY;
    276 }
    277 
    278 
    279 /*
    280 FUNCTION
    281 	bfd_is_section_compressed
    282 
    283 SYNOPSIS
    284 	bfd_boolean bfd_is_section_compressed
    285 	  (bfd *abfd, asection *section);
    286 
    287 DESCRIPTION
    288 	Return @code{TRUE} if @var{section} is compressed.
    289 */
    290 
    291 bfd_boolean
    292 bfd_is_section_compressed (bfd *abfd, sec_ptr sec)
    293 {
    294   bfd_byte compressed_buffer [12];
    295   unsigned int saved = sec->compress_status;
    296   bfd_boolean compressed;
    297 
    298   /* Don't decompress the section.  */
    299   sec->compress_status = COMPRESS_SECTION_NONE;
    300 
    301   /* Read the zlib header.  In this case, it should be "ZLIB" followed
    302      by the uncompressed section size, 8 bytes in big-endian order.  */
    303   compressed = (bfd_get_section_contents (abfd, sec, compressed_buffer, 0, 12)
    304 		&& CONST_STRNEQ ((char*) compressed_buffer, "ZLIB"));
    305 
    306   /* Restore compress_status.  */
    307   sec->compress_status = saved;
    308   return compressed;
    309 }
    310 
    311 /*
    312 FUNCTION
    313 	bfd_init_section_decompress_status
    314 
    315 SYNOPSIS
    316 	bfd_boolean bfd_init_section_decompress_status
    317 	  (bfd *abfd, asection *section);
    318 
    319 DESCRIPTION
    320 	Record compressed section size, update section size with
    321 	decompressed size and set compress_status to
    322 	DECOMPRESS_SECTION_SIZED.
    323 
    324 	Return @code{FALSE} if the section is not a valid compressed
    325 	section or zlib is not installed on this machine.  Otherwise,
    326 	return @code{TRUE}.
    327 */
    328 
    329 bfd_boolean
    330 bfd_init_section_decompress_status (bfd *abfd ATTRIBUTE_UNUSED,
    331 				    sec_ptr sec ATTRIBUTE_UNUSED)
    332 {
    333 #ifndef HAVE_ZLIB_H
    334   bfd_set_error (bfd_error_invalid_operation);
    335   return FALSE;
    336 #else
    337   bfd_byte compressed_buffer [12];
    338   bfd_size_type uncompressed_size;
    339 
    340   if (sec->rawsize != 0
    341       || sec->contents != NULL
    342       || sec->compress_status != COMPRESS_SECTION_NONE
    343       || !bfd_get_section_contents (abfd, sec, compressed_buffer, 0, 12))
    344     {
    345       bfd_set_error (bfd_error_invalid_operation);
    346       return FALSE;
    347     }
    348 
    349   /* Read the zlib header.  In this case, it should be "ZLIB" followed
    350      by the uncompressed section size, 8 bytes in big-endian order.  */
    351   if (! CONST_STRNEQ ((char*) compressed_buffer, "ZLIB"))
    352     {
    353       bfd_set_error (bfd_error_wrong_format);
    354       return FALSE;
    355     }
    356 
    357   uncompressed_size = compressed_buffer[4]; uncompressed_size <<= 8;
    358   uncompressed_size += compressed_buffer[5]; uncompressed_size <<= 8;
    359   uncompressed_size += compressed_buffer[6]; uncompressed_size <<= 8;
    360   uncompressed_size += compressed_buffer[7]; uncompressed_size <<= 8;
    361   uncompressed_size += compressed_buffer[8]; uncompressed_size <<= 8;
    362   uncompressed_size += compressed_buffer[9]; uncompressed_size <<= 8;
    363   uncompressed_size += compressed_buffer[10]; uncompressed_size <<= 8;
    364   uncompressed_size += compressed_buffer[11];
    365 
    366   sec->compressed_size = sec->size;
    367   sec->size = uncompressed_size;
    368   sec->compress_status = DECOMPRESS_SECTION_SIZED;
    369 
    370   return TRUE;
    371 #endif
    372 }
    373 
    374 /*
    375 FUNCTION
    376 	bfd_init_section_compress_status
    377 
    378 SYNOPSIS
    379 	bfd_boolean bfd_init_section_compress_status
    380 	  (bfd *abfd, asection *section);
    381 
    382 DESCRIPTION
    383 	If open for read, compress section, update section size with
    384 	compressed size and set compress_status to COMPRESS_SECTION_DONE.
    385 
    386 	Return @code{FALSE} if the section is not a valid compressed
    387 	section or zlib is not installed on this machine.  Otherwise,
    388 	return @code{TRUE}.
    389 */
    390 
    391 bfd_boolean
    392 bfd_init_section_compress_status (bfd *abfd ATTRIBUTE_UNUSED,
    393 				  sec_ptr sec ATTRIBUTE_UNUSED)
    394 {
    395 #ifndef HAVE_ZLIB_H
    396   bfd_set_error (bfd_error_invalid_operation);
    397   return FALSE;
    398 #else
    399   bfd_size_type uncompressed_size;
    400   bfd_byte *uncompressed_buffer;
    401   bfd_boolean ret;
    402 
    403   /* Error if not opened for read.  */
    404   if (abfd->direction != read_direction
    405       || sec->size == 0
    406       || sec->rawsize != 0
    407       || sec->contents != NULL
    408       || sec->compress_status != COMPRESS_SECTION_NONE)
    409     {
    410       bfd_set_error (bfd_error_invalid_operation);
    411       return FALSE;
    412     }
    413 
    414   /* Read in the full section contents and compress it.  */
    415   uncompressed_size = sec->size;
    416   uncompressed_buffer = (bfd_byte *) bfd_malloc (uncompressed_size);
    417   if (!bfd_get_section_contents (abfd, sec, uncompressed_buffer,
    418 				 0, uncompressed_size))
    419     ret = FALSE;
    420   else
    421     ret = bfd_compress_section_contents (abfd, sec,
    422 					 uncompressed_buffer,
    423 					 uncompressed_size);
    424 
    425   free (uncompressed_buffer);
    426   return ret;
    427 #endif
    428 }
    429