Make bfd_byte an int8_t, flagword a uint32_t
[binutils-gdb.git] / bfd / compress.c
index a4e6a8ee7b5225cf805060f5e9f1c4ffb12ca949..844328b27a965f71295adb6d510b402cfdb565fa 100644 (file)
@@ -1,5 +1,5 @@
 /* Compressed section support (intended for debug sections).
-   Copyright (C) 2008-2022 Free Software Foundation, Inc.
+   Copyright (C) 2008-2023 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
 #include "elf-bfd.h"
 #include "libbfd.h"
 #include "safe-ctype.h"
+#include "libiberty.h"
 
 #define MAX_COMPRESSION_HEADER_SIZE 24
 
 /*
 CODE_FRAGMENT
+.{* Types of compressed DWARF debug sections.  *}
+.enum compressed_debug_section_type
+.{
+.  COMPRESS_DEBUG_NONE = 0,
+.  COMPRESS_DEBUG_GNU_ZLIB = 1 << 1,
+.  COMPRESS_DEBUG_GABI_ZLIB = 1 << 2,
+.  COMPRESS_DEBUG_ZSTD = 1 << 3,
+.  COMPRESS_UNKNOWN = 1 << 4
+.};
+.
+.{* Tuple for compressed_debug_section_type and their name.  *}
+.struct compressed_type_tuple
+.{
+.  enum compressed_debug_section_type type;
+.  const char *name;
+.};
+.
+.{* Compression header ch_type values.  *}
 .enum compression_type
 .{
 .  ch_none = 0,
@@ -66,6 +85,54 @@ CODE_FRAGMENT
 .
 */
 
+/* Display texts for type of compressed DWARF debug sections.  */
+static const struct compressed_type_tuple compressed_debug_section_names[] =
+{
+  { COMPRESS_DEBUG_NONE, "none" },
+  { COMPRESS_DEBUG_GABI_ZLIB, "zlib" },
+  { COMPRESS_DEBUG_GNU_ZLIB, "zlib-gnu" },
+  { COMPRESS_DEBUG_GABI_ZLIB, "zlib-gabi" },
+  { COMPRESS_DEBUG_ZSTD, "zstd" },
+};
+
+/*
+FUNCTION
+       bfd_get_compression_algorithm
+SYNOPSIS
+       enum compressed_debug_section_type
+         bfd_get_compression_algorithm (const char *name);
+DESCRIPTION
+       Return compressed_debug_section_type from a string representation.
+*/
+enum compressed_debug_section_type
+bfd_get_compression_algorithm (const char *name)
+{
+  for (unsigned i = 0; i < ARRAY_SIZE (compressed_debug_section_names); ++i)
+    if (strcasecmp (compressed_debug_section_names[i].name, name) == 0)
+      return compressed_debug_section_names[i].type;
+
+  return COMPRESS_UNKNOWN;
+}
+
+/*
+FUNCTION
+       bfd_get_compression_algorithm_name
+SYNOPSIS
+       const char *bfd_get_compression_algorithm_name
+         (enum compressed_debug_section_type type);
+DESCRIPTION
+       Return compression algorithm name based on the type.
+*/
+const char *
+bfd_get_compression_algorithm_name (enum compressed_debug_section_type type)
+{
+  for (unsigned i = 0; i < ARRAY_SIZE (compressed_debug_section_names); ++i)
+    if (type == compressed_debug_section_names[i].type)
+      return compressed_debug_section_names[i].name;
+
+  return NULL;
+}
+
 /*
 FUNCTION
        bfd_update_compression_header
@@ -196,9 +263,6 @@ SYNOPSIS
 
 DESCRIPTION
        Return the size of the compression header of SEC in ABFD.
-
-RETURNS
-       Return the size of the compression header in bytes.
 */
 
 int
@@ -225,53 +289,89 @@ bfd_get_compression_header_size (bfd *abfd, asection *sec)
 
 /*
 FUNCTION
-       bfd_convert_section_size
+       bfd_convert_section_setup
 
 SYNOPSIS
-       bfd_size_type bfd_convert_section_size
-         (bfd *ibfd, asection *isec, bfd *obfd, bfd_size_type size);
+       bool bfd_convert_section_setup
+         (bfd *ibfd, asection *isec, bfd *obfd,
+          const char **new_name, bfd_size_type *new_size);
 
 DESCRIPTION
-       Convert the size @var{size} of the section @var{isec} in input
-       BFD @var{ibfd} to the section size in output BFD @var{obfd}.
+       Do early setup for objcopy, when copying @var{isec} in input
+       BFD @var{ibfd} to output BFD @var{obfd}.  Returns the name and
+       size of the output section.
 */
 
-bfd_size_type
-bfd_convert_section_size (bfd *ibfd, sec_ptr isec, bfd *obfd,
-                         bfd_size_type size)
+bool
+bfd_convert_section_setup (bfd *ibfd, asection *isec, bfd *obfd,
+                          const char **new_name, bfd_size_type *new_size)
 {
   bfd_size_type hdr_size;
 
+  if ((isec->flags & SEC_DEBUGGING) != 0
+      && (isec->flags & SEC_HAS_CONTENTS) != 0)
+    {
+      const char *name = *new_name;
+
+      if ((obfd->flags & (BFD_DECOMPRESS | BFD_COMPRESS_GABI)) != 0)
+       {
+         /* When we decompress or compress with SHF_COMPRESSED,
+            convert section name from .zdebug_* to .debug_*.  */
+         if (startswith (name, ".zdebug_"))
+           {
+             name = bfd_zdebug_name_to_debug (obfd, name);
+             if (name == NULL)
+               return false;
+           }
+       }
+
+      /* PR binutils/18087: Compression does not always make a
+        section smaller.  So only rename the section when
+        compression has actually taken place.  If input section
+        name is .zdebug_*, we should never compress it again.  */
+      else if (isec->compress_status == COMPRESS_SECTION_DONE
+              && startswith (name, ".debug_"))
+       {
+         name = bfd_debug_name_to_zdebug (obfd, name);
+         if (name == NULL)
+           return false;
+       }
+      *new_name = name;
+    }
+  *new_size = bfd_section_size (isec);
+
   /* Do nothing if either input or output aren't ELF.  */
   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
-    return size;
+    return true;
 
   /* Do nothing if ELF classes of input and output are the same. */
   if (get_elf_backend_data (ibfd)->s->elfclass
       == get_elf_backend_data (obfd)->s->elfclass)
-    return size;
+    return true;
 
   /* Convert GNU property size.  */
   if (startswith (isec->name, NOTE_GNU_PROPERTY_SECTION_NAME))
-    return _bfd_elf_convert_gnu_property_size (ibfd, obfd);
+    {
+      *new_size = _bfd_elf_convert_gnu_property_size (ibfd, obfd);
+      return true;
+    }
 
   /* Do nothing if input file will be decompressed.  */
   if ((ibfd->flags & BFD_DECOMPRESS))
-    return size;
+    return true;
 
   /* Do nothing if the input section isn't a SHF_COMPRESSED section. */
   hdr_size = bfd_get_compression_header_size (ibfd, isec);
   if (hdr_size == 0)
-    return size;
+    return true;
 
   /* Adjust the size of the output SHF_COMPRESSED section.  */
   if (hdr_size == sizeof (Elf32_External_Chdr))
-    return (size - sizeof (Elf32_External_Chdr)
-           + sizeof (Elf64_External_Chdr));
+    *new_size += sizeof (Elf64_External_Chdr) - sizeof (Elf32_External_Chdr);
   else
-    return (size - sizeof (Elf64_External_Chdr)
-           + sizeof (Elf32_External_Chdr));
+    *new_size -= sizeof (Elf64_External_Chdr) - sizeof (Elf32_External_Chdr);
+  return true;
 }
 
 /*
@@ -579,7 +679,8 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec)
   if (compressed_size >= uncompressed_size)
     {
       memcpy (buffer, input_buffer, uncompressed_size);
-      elf_section_flags (sec) &= ~SHF_COMPRESSED;
+      if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+       elf_section_flags (sec) &= ~SHF_COMPRESSED;
       sec->compress_status = COMPRESS_SECTION_NONE;
     }
   else
@@ -616,7 +717,8 @@ DESCRIPTION
 bool
 bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
 {
-  bfd_size_type sz = bfd_get_section_limit_octets (abfd, sec);
+  bfd_size_type readsz = bfd_get_section_limit_octets (abfd, sec);
+  bfd_size_type allocsz = bfd_get_section_alloc_size (abfd, sec);
   bfd_byte *p = *ptr;
   bool ret;
   bfd_size_type save_size;
@@ -625,7 +727,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
   unsigned int compression_header_size;
   const unsigned int compress_status = sec->compress_status;
 
-  if (sz == 0)
+  if (allocsz == 0)
     {
       *ptr = NULL;
       return true;
@@ -640,7 +742,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
       _bfd_error_handler
        /* xgettext:c-format */
        (_("error: %pB(%pA) is too large (%#" PRIx64 " bytes)"),
-        abfd, sec, (uint64_t) sz);
+        abfd, sec, (uint64_t) readsz);
       return false;
     }
 
@@ -649,7 +751,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
     case COMPRESS_SECTION_NONE:
       if (p == NULL)
        {
-         p = (bfd_byte *) bfd_malloc (sz);
+         p = (bfd_byte *) bfd_malloc (allocsz);
          if (p == NULL)
            {
              /* PR 20801: Provide a more helpful error message.  */
@@ -657,12 +759,12 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
                _bfd_error_handler
                  /* xgettext:c-format */
                  (_("error: %pB(%pA) is too large (%#" PRIx64 " bytes)"),
-                 abfd, sec, (uint64_t) sz);
+                 abfd, sec, (uint64_t) allocsz);
              return false;
            }
        }
 
-      if (!bfd_get_section_contents (abfd, sec, p, 0, sz))
+      if (!bfd_get_section_contents (abfd, sec, p, 0, readsz))
        {
          if (*ptr != p)
            free (p);
@@ -695,7 +797,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
        goto fail_compressed;
 
       if (p == NULL)
-       p = (bfd_byte *) bfd_malloc (sz);
+       p = (bfd_byte *) bfd_malloc (allocsz);
       if (p == NULL)
        goto fail_compressed;
 
@@ -707,7 +809,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
       bool is_zstd = compress_status == DECOMPRESS_SECTION_ZSTD;
       if (!decompress_contents (
              is_zstd, compressed_buffer + compression_header_size,
-             sec->compressed_size - compression_header_size, p, sz))
+             sec->compressed_size - compression_header_size, p, readsz))
        {
          bfd_set_error (bfd_error_bad_value);
          if (p != *ptr)
@@ -726,14 +828,14 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
        return false;
       if (p == NULL)
        {
-         p = (bfd_byte *) bfd_malloc (sz);
+         p = (bfd_byte *) bfd_malloc (allocsz);
          if (p == NULL)
            return false;
          *ptr = p;
        }
       /* PR 17512; file: 5bc29788.  */
       if (p != sec->contents)
-       memcpy (p, sec->contents, sz);
+       memcpy (p, sec->contents, readsz);
       return true;
 
     default:
@@ -963,7 +1065,8 @@ bfd_init_section_compress_status (bfd *abfd, sec_ptr sec)
       || sec->size == 0
       || sec->rawsize != 0
       || sec->contents != NULL
-      || sec->compress_status != COMPRESS_SECTION_NONE)
+      || sec->compress_status != COMPRESS_SECTION_NONE
+      || _bfd_section_size_insane (abfd, sec))
     {
       bfd_set_error (bfd_error_invalid_operation);
       return false;
@@ -978,7 +1081,10 @@ bfd_init_section_compress_status (bfd *abfd, sec_ptr sec)
 
   if (!bfd_get_section_contents (abfd, sec, uncompressed_buffer,
                                 0, uncompressed_size))
-    return false;
+    {
+      free (uncompressed_buffer);
+      return false;
+    }
 
   sec->contents = uncompressed_buffer;
   if (bfd_compress_section_contents (abfd, sec) == 0)