bfd_get_size cache
authorAlan Modra <amodra@gmail.com>
Wed, 19 Feb 2020 02:44:28 +0000 (13:14 +1030)
committerAlan Modra <amodra@gmail.com>
Wed, 19 Feb 2020 02:44:28 +0000 (13:14 +1030)
We have calls to bfd_get_size when swapping in ELF section headers.
Since object files can have a large number of sections, it's worth
caching the file size rather than making lots of stat system calls.

* bfd.c (struct bfd): Move format and direction to other
bitfields.  Add "size".
* bfdio.c (bfd_get_size): Cache size when not writing file.
* opncls.c (bfd_get_debug_link_info_1): Allow for bfd_get_size
returning zero, ie. unknown.
(bfd_get_alt_debug_link_info): Likewise.
* bfd-in2.h: Regenerate.

bfd/ChangeLog
bfd/bfd-in2.h
bfd/bfd.c
bfd/bfdio.c
bfd/opncls.c

index fe2ffd341a0cb496e90ea84180170265a93ae141..58dbb567f2f16544c0028862437bd50d7a8c2dfa 100644 (file)
@@ -1,3 +1,13 @@
+2020-02-19  Alan Modra  <amodra@gmail.com>
+
+       * bfd.c (struct bfd): Move format and direction to other
+       bitfields.  Add "size".
+       * bfdio.c (bfd_get_size): Cache size when not writing file.
+       * opncls.c (bfd_get_debug_link_info_1): Allow for bfd_get_size
+       returning zero, ie. unknown.
+       (bfd_get_alt_debug_link_info): Likewise.
+       * bfd-in2.h: Regenerate.
+
 2020-02-19  Alan Modra  <amodra@gmail.com>
 
        * coffgen.c (_bfd_coff_get_external_symbols): Don't call
index 6b30f5fbd80666b0ba9502ba1026e4c2f60a52d7..2d56fdad41dc97c366dcc3a01ebff725fb70eb74 100644 (file)
@@ -6497,12 +6497,6 @@ struct bfd
   /* A unique identifier of the BFD  */
   unsigned int id;
 
-  /* The format which belongs to the BFD. (object, core, etc.)  */
-  ENUM_BITFIELD (bfd_format) format : 3;
-
-  /* The direction with which the BFD was opened.  */
-  ENUM_BITFIELD (bfd_direction) direction : 2;
-
   /* Format_specific flags.  */
   flagword flags;
 
@@ -6606,6 +6600,12 @@ struct bfd
    | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT \
    | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON)
 
+  /* The format which belongs to the BFD. (object, core, etc.)  */
+  ENUM_BITFIELD (bfd_format) format : 3;
+
+  /* The direction with which the BFD was opened.  */
+  ENUM_BITFIELD (bfd_direction) direction : 2;
+
   /* Is the file descriptor being cached?  That is, can it be closed as
      needed, and re-opened when accessed later?  */
   unsigned int cacheable : 1;
@@ -6695,7 +6695,7 @@ struct bfd
 
   /* Symbol table for output BFD (with symcount entries).
      Also used by the linker to cache input BFD symbols.  */
-  struct bfd_symbol  **outsymbols;
+  struct bfd_symbol **outsymbols;
 
   /* Used for input and output.  */
   unsigned int symcount;
@@ -6706,6 +6706,11 @@ struct bfd
   /* Pointer to structure which contains architecture information.  */
   const struct bfd_arch_info *arch_info;
 
+  /* Cached length of file for bfd_get_size.  0 until bfd_get_size is
+     called, 1 if stat returns an error or the file size is too large to
+     return in ufile_ptr.  Both 0 and 1 should be treated as "unknown".  */
+  ufile_ptr size;
+
   /* Stuff only useful for archives.  */
   void *arelt_data;
   struct bfd *my_archive;      /* The containing archive BFD.  */
index 574cebd8de2531e4aebe3fd76e2264463eed1113..463f94bb945ce1816f6442fe9c50c04c46c53413 100644 (file)
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -85,12 +85,6 @@ CODE_FRAGMENT
 .  {* A unique identifier of the BFD  *}
 .  unsigned int id;
 .
-.  {* The format which belongs to the BFD. (object, core, etc.)  *}
-.  ENUM_BITFIELD (bfd_format) format : 3;
-.
-.  {* The direction with which the BFD was opened.  *}
-.  ENUM_BITFIELD (bfd_direction) direction : 2;
-.
 .  {* Format_specific flags.  *}
 .  flagword flags;
 .
@@ -194,6 +188,12 @@ CODE_FRAGMENT
 .   | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT \
 .   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON)
 .
+.  {* The format which belongs to the BFD. (object, core, etc.)  *}
+.  ENUM_BITFIELD (bfd_format) format : 3;
+.
+.  {* The direction with which the BFD was opened.  *}
+.  ENUM_BITFIELD (bfd_direction) direction : 2;
+.
 .  {* Is the file descriptor being cached?  That is, can it be closed as
 .     needed, and re-opened when accessed later?  *}
 .  unsigned int cacheable : 1;
@@ -283,7 +283,7 @@ CODE_FRAGMENT
 .
 .  {* Symbol table for output BFD (with symcount entries).
 .     Also used by the linker to cache input BFD symbols.  *}
-.  struct bfd_symbol  **outsymbols;
+.  struct bfd_symbol **outsymbols;
 .
 .  {* Used for input and output.  *}
 .  unsigned int symcount;
@@ -294,6 +294,11 @@ CODE_FRAGMENT
 .  {* Pointer to structure which contains architecture information.  *}
 .  const struct bfd_arch_info *arch_info;
 .
+.  {* Cached length of file for bfd_get_size.  0 until bfd_get_size is
+.     called, 1 if stat returns an error or the file size is too large to
+.     return in ufile_ptr.  Both 0 and 1 should be treated as "unknown".  *}
+.  ufile_ptr size;
+.
 .  {* Stuff only useful for archives.  *}
 .  void *arelt_data;
 .  struct bfd *my_archive;      {* The containing archive BFD.  *}
index fd81b93cd9f3017352f95de9636d902b3e105fab..49e09585264daeb43512a5cc16f02a9f1c434a0c 100644 (file)
@@ -415,17 +415,32 @@ DESCRIPTION
        of space for the 15 bazillon byte table it is about to read.
        This function at least allows us to answer the question, "is the
        size reasonable?".
+
+       A return value of zero indicates the file size is unknown.
 */
 
 ufile_ptr
 bfd_get_size (bfd *abfd)
 {
-  struct stat buf;
+  /* A size of 0 means we haven't yet called bfd_stat.  A size of 1
+     means we have a cached value of 0, ie. unknown.  */
+  if (abfd->size <= 1 || bfd_write_p (abfd))
+    {
+      struct stat buf;
 
-  if (bfd_stat (abfd, &buf) != 0)
-    return 0;
+      if (abfd->size == 1 && !bfd_write_p (abfd))
+       return 0;
 
-  return buf.st_size;
+      if (bfd_stat (abfd, &buf) != 0
+         || buf.st_size == 0
+         || buf.st_size - (ufile_ptr) buf.st_size != 0)
+       {
+         abfd->size = 1;
+         return 0;
+       }
+      abfd->size = buf.st_size;
+    }
+  return abfd->size;
 }
 
 /*
index a03ad51c8fae9a3a19ec610234f969621877b885..796202d31a581bcab7992681ab74bd9f51e812ea 100644 (file)
@@ -1209,6 +1209,7 @@ bfd_get_debug_link_info_1 (bfd *abfd, void *crc32_out)
   unsigned int crc_offset;
   char *name;
   bfd_size_type size;
+  ufile_ptr file_size;
 
   BFD_ASSERT (abfd);
   BFD_ASSERT (crc32_out);
@@ -1219,9 +1220,10 @@ bfd_get_debug_link_info_1 (bfd *abfd, void *crc32_out)
     return NULL;
 
   size = bfd_section_size (sect);
+  file_size = bfd_get_size (abfd);
 
   /* PR 22794: Make sure that the section has a reasonable size.  */
-  if (size < 8 || size >= bfd_get_size (abfd))
+  if (size < 8 || (file_size != 0 && size >= file_size))
     return NULL;
 
   if (!bfd_malloc_and_get_section (abfd, sect, &contents))
@@ -1298,6 +1300,7 @@ bfd_get_alt_debug_link_info (bfd * abfd, bfd_size_type *buildid_len,
   unsigned int buildid_offset;
   char *name;
   bfd_size_type size;
+  ufile_ptr file_size;
 
   BFD_ASSERT (abfd);
   BFD_ASSERT (buildid_len);
@@ -1309,7 +1312,8 @@ bfd_get_alt_debug_link_info (bfd * abfd, bfd_size_type *buildid_len,
     return NULL;
 
   size = bfd_section_size (sect);
-  if (size < 8 || size >= bfd_get_size (abfd))
+  file_size = bfd_get_size (abfd);
+  if (size < 8 || (file_size != 0 && size >= file_size))
     return NULL;
 
   if (!bfd_malloc_and_get_section (abfd, sect, & contents))