Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

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