Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:16

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup rtl
0007  *
0008  * @brief RTEMS Run-Time Linker Archive
0009  */
0010 
0011 /*
0012  *  COPYRIGHT (c) 2018 Chris Johns <chrisj@rtems.org>
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #ifdef HAVE_CONFIG_H
0037 #include "config.h"
0038 #endif
0039 
0040 #include <ctype.h>
0041 #include <dirent.h>
0042 #include <errno.h>
0043 #include <fnmatch.h>
0044 #include <inttypes.h>
0045 #include <stdio.h>
0046 #include <string.h>
0047 
0048 #include <rtems/libio_.h>
0049 
0050 #include <rtems/rtl/rtl.h>
0051 #include "rtl-chain-iterator.h"
0052 #include <rtems/rtl/rtl-trace.h>
0053 #include "rtl-string.h"
0054 #include "rtl-error.h"
0055 
0056 /**
0057  * Archive headers.
0058  */
0059 #define RTEMS_RTL_AR_IDENT      "!<arch>\n"
0060 #define RTEMS_RTL_AR_IDENT_SIZE (sizeof (RTEMS_RTL_AR_IDENT) - 1)
0061 #define RTEMS_RTL_AR_FHDR_BASE  RTEMS_RTL_AR_IDENT_SIZE
0062 #define RTEMS_RTL_AR_FNAME      (0)
0063 #define RTEMS_RTL_AR_FNAME_SIZE (16)
0064 #define RTEMS_RTL_AR_SIZE       (48)
0065 #define RTEMS_RTL_AR_SIZE_SIZE  (10)
0066 #define RTEMS_RTL_AR_MAGIC      (58)
0067 #define RTEMS_RTL_AR_MAGIC_SIZE (2)
0068 #define RTEMS_RTL_AR_FHDR_SIZE  (60)
0069 
0070 /**
0071  * Read a 32bit value from the symbol table.
0072  */
0073 static unsigned int
0074 rtems_rtl_archive_read_32 (void* data)
0075 {
0076   uint8_t*     b = (uint8_t*) data;
0077   unsigned int v = b[0];
0078   v = (v << 8) | b[1];
0079   v = (v << 8) | b[2];
0080   v = (v << 8) | b[3];
0081   return v;
0082 }
0083 
0084 static void
0085 rtems_rtl_archive_set_error (int num, const char* text)
0086 {
0087   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0088     printf ("rtl: archive: error: %3d:  %s\n", num, text);
0089 }
0090 
0091 static uint64_t
0092 rtems_rtl_scan_decimal (const uint8_t* string, size_t len)
0093 {
0094   uint64_t value = 0;
0095 
0096   while (len && (*string != ' '))
0097   {
0098     value *= 10;
0099     value += *string - '0';
0100     ++string;
0101     --len;
0102   }
0103 
0104   return value;
0105 }
0106 
0107 static bool
0108 rtems_rtl_seek_read (int fd, off_t off, size_t len, uint8_t* buffer)
0109 {
0110   if (lseek (fd, off, SEEK_SET) < 0)
0111     return false;
0112   if (read (fd, buffer, len) != len)
0113     return false;
0114   return true;
0115 }
0116 
0117 /**
0118  * Archive iterator.
0119  */
0120 typedef bool (*rtems_rtl_archive_iterator) (rtems_rtl_archive* archive,
0121                         void*              data);
0122 
0123 /**
0124  * Chain iterator data.
0125  */
0126 typedef struct rtems_rtl_archive_chain_data
0127 {
0128   void*                      data;      /**< User's data. */
0129   rtems_rtl_archive_iterator iterator;  /**< The actual iterator. */
0130 } rtems_rtl_archive_chain_data;
0131 
0132 static bool
0133 rtems_rtl_archive_node_iterator (rtems_chain_node* node, void* data)
0134 {
0135   rtems_rtl_archive*            archive;
0136   rtems_rtl_archive_chain_data* chain_data;
0137   archive    = (rtems_rtl_archive*) node;
0138   chain_data = (rtems_rtl_archive_chain_data*) data;
0139   return chain_data->iterator (archive, chain_data->data);
0140 }
0141 
0142 static void
0143 rtems_rtl_archive_iterate_archives (rtems_rtl_archives*        archives,
0144                                     rtems_rtl_archive_iterator iterator,
0145                                     void*                      data)
0146 {
0147   rtems_rtl_archive_chain_data chain_data = {
0148     .data = data,
0149     .iterator = iterator
0150   };
0151   rtems_rtl_chain_iterate (&archives->archives,
0152                            rtems_rtl_archive_node_iterator,
0153                            &chain_data);
0154 }
0155 
0156 static bool
0157 rtems_rtl_rchive_name_end (const char c)
0158 {
0159   return c == '\0' || c == '\n' || c == '/';
0160 }
0161 
0162 static const char*
0163 rtems_rtl_archive_dup_name (const char* name)
0164 {
0165   size_t len = 0;
0166   char*  dup;
0167   while (!rtems_rtl_rchive_name_end (name[len]))
0168     ++len;
0169   dup = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, len + 1, true);
0170   if (dup != NULL)
0171     memcpy (dup, name, len);
0172   return dup;
0173 }
0174 
0175 static bool
0176 rtems_rtl_archive_match_name (const char* file_name, const char* name)
0177 {
0178   if (name != NULL)
0179   {
0180     while (!rtems_rtl_rchive_name_end (*file_name) &&
0181            !rtems_rtl_rchive_name_end (*name) && *file_name == *name)
0182     {
0183       ++file_name;
0184       ++name;
0185     }
0186     if (((*file_name == '\0') || (*file_name == '\n') || (*file_name == '/')) &&
0187         ((*name == '\0') || (*name == '/')))
0188       return true;
0189   }
0190   return false;
0191 }
0192 
0193 static bool
0194 rtems_rtl_archive_set_flags (rtems_rtl_archive* archive, void* data)
0195 {
0196   uint32_t mask = *((uint32_t*) data);
0197   archive->flags |= mask;
0198   return true;
0199 }
0200 
0201 typedef struct rtems_rtl_archive_find_data
0202 {
0203   rtems_rtl_archive* archive;
0204   const char*        path;
0205 } rtems_rtl_archive_find_data;
0206 
0207 static bool
0208 rtems_rtl_archive_finder (rtems_rtl_archive* archive, void* data)
0209 {
0210   rtems_rtl_archive_find_data* find;
0211   find = (rtems_rtl_archive_find_data*) data;
0212   if (strcmp (find->path, archive->name) == 0)
0213   {
0214     find->archive = archive;
0215     return false;
0216   }
0217   return true;
0218 }
0219 
0220 static rtems_rtl_archive*
0221 rtems_rtl_archive_find (rtems_rtl_archives* archives,
0222                         const char*         path)
0223 {
0224   rtems_rtl_archive_find_data find = {
0225     .archive = NULL,
0226     .path = path
0227   };
0228   rtems_rtl_archive_iterate_archives (archives,
0229                                       rtems_rtl_archive_finder,
0230                                       &find);
0231   return find.archive;
0232 }
0233 
0234 /*
0235  * Find an object file in archive that contains the symbol we are
0236  * searching for.
0237  *
0238  * The symbol search is performance sensitive. The archive's symbol table being
0239  * searched is the symbol table in the archive created by ranlib. This table is
0240  * not sorted so a sorted table of pointeres to the symbols is generated after
0241  * loading if there are enough symbols. For small symbol tables the search is
0242  * linear. The entire table is held in memory. At the time of writing this code
0243  * the symbol table for the SPARC architecture's libc is 16k.
0244  *
0245  * The ranlib table is:
0246  *
0247  *    [4]                - size of table in bytes
0248  *    [0..(entries x 4)] - 4 byte binary offsets into the archive
0249  *                         for each symbol
0250  *    [0..m]             - variable length table of strings, nul
0251  *                         separated and sorted
0252  *
0253  * Note: The loading of an object file from an archive uses an offset in the
0254  *       file name to speed the loading.
0255  */
0256 typedef struct rtems_rtl_archive_obj_data
0257 {
0258   const char*        symbol;   /**< The symbol to search for. */
0259   rtems_rtl_archive* archive;  /**< The archive the symbol is found
0260                                 *   in. */
0261   off_t              offset;   /**< The offset in the archive if found
0262                                 *   else 0 */
0263 } rtems_rtl_archive_obj_data;
0264 
0265 static int
0266 rtems_rtl_archive_symbol_compare (const void* a, const void* b)
0267 {
0268   const rtems_rtl_archive_symbol* sa;
0269   const rtems_rtl_archive_symbol* sb;
0270   sa = (const rtems_rtl_archive_symbol*) a;
0271   sb = (const rtems_rtl_archive_symbol*) b;
0272   return strcmp (sa->label, sb->label);
0273 }
0274 
0275 static bool
0276 rtems_rtl_archive_obj_finder (rtems_rtl_archive* archive, void* data)
0277 {
0278   const rtems_rtl_archive_symbols* symbols = &archive->symbols;
0279 
0280   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0281     printf ("rtl: archive: finder: %s: entries: %zu\n",
0282             archive->name, symbols->entries);
0283 
0284   /*
0285    * Make sure there is a valid symbol table.
0286    */
0287   if (symbols->base != NULL)
0288   {
0289     /*
0290      * Perform a linear search if there is no sorted symbol table.
0291      */
0292     rtems_rtl_archive_obj_data* search = (rtems_rtl_archive_obj_data*) data;
0293     if (symbols->symbols == NULL)
0294     {
0295       const char* symbol = symbols->names;
0296       size_t      entry;
0297       for (entry = 0; entry < symbols->entries; ++entry)
0298       {
0299         if (strcmp (search->symbol, symbol) == 0)
0300         {
0301           search->archive = archive;
0302           search->offset =
0303             rtems_rtl_archive_read_32 (symbols->base + ((entry + 1) * 4));
0304           return false;
0305         }
0306         symbol += strlen (symbol) + 1;
0307       }
0308     }
0309     else
0310     {
0311       rtems_rtl_archive_symbol*      match;
0312       const rtems_rtl_archive_symbol key = {
0313         .entry = -1,
0314         .label = search->symbol
0315       };
0316       match = bsearch (&key,
0317                        symbols->symbols,
0318                        symbols->entries,
0319                        sizeof (symbols->symbols[0]),
0320                        rtems_rtl_archive_symbol_compare);
0321       if (match != NULL)
0322       {
0323           search->archive = archive;
0324           search->offset =
0325             rtems_rtl_archive_read_32 (symbols->base + (match->entry * 4));
0326           return false;
0327       }
0328     }
0329   }
0330 
0331   /*
0332    * Next archive.
0333    */
0334   return true;
0335 }
0336 
0337 static rtems_rtl_archive*
0338 rtems_rtl_archive_new (rtems_rtl_archives* archives,
0339                        const char*         path,
0340                        const char*         name)
0341 {
0342   rtems_rtl_archive* archive;
0343   size_t             path_size;
0344   size_t             size;
0345   /*
0346    * Handle the case of the path being just '/', do not create '//'.
0347    */
0348   path_size = strlen (path);
0349   size = sizeof(rtems_rtl_archive) + path_size + strlen (name) + 1;
0350   if (path_size > 1)
0351     ++size;
0352   archive = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, size, true);
0353   if (archive == NULL)
0354   {
0355     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0356       printf ("rtl: archive: new: %s: no memory\n", name);
0357   }
0358   else
0359   {
0360     char* aname;
0361     archive->name = ((const char*) archive) + sizeof(rtems_rtl_archive);
0362     aname = (char*) archive->name;
0363     strcpy (aname, path);
0364     if (path_size > 1)
0365       strcat (aname, "/");
0366     strcat (aname, name);
0367     rtems_chain_set_off_chain (&archive->node);
0368     archive->flags |= RTEMS_RTL_ARCHIVE_LOAD;
0369   }
0370   return archive;
0371 }
0372 
0373 static void
0374 rtems_rtl_archive_del (rtems_rtl_archive* archive)
0375 {
0376   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0377     printf ("rtl: archive: del: %s\n",  archive->name);
0378   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, archive->symbols.base);
0379   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, archive->symbols.symbols);
0380   if (!rtems_chain_is_node_off_chain (&archive->node))
0381     rtems_chain_extract (&archive->node);
0382   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, archive);
0383 }
0384 
0385 static rtems_rtl_archive*
0386 rtems_rtl_archive_get (rtems_rtl_archives* archives,
0387                        const char*         path,
0388                        const char*         name)
0389 {
0390   rtems_rtl_archive* archive;
0391   /*
0392    * Getting a new archive turns the path and name into a single path the stat
0393    * function can use. No matter how you try some memory is needed so it is
0394    * easier to get a new archive object and delete it if it exists.
0395    */
0396   archive = rtems_rtl_archive_new (archives, path, name);
0397   if (archive != NULL)
0398   {
0399     struct stat sb;
0400     if (stat (archive->name, &sb) == 0)
0401     {
0402       if (S_ISREG (sb.st_mode))
0403       {
0404         rtems_rtl_archive* find_archive;
0405         find_archive = rtems_rtl_archive_find (archives, archive->name);
0406         if (find_archive == NULL)
0407         {
0408           rtems_chain_append (&archives->archives, &archive->node);
0409         }
0410         else
0411         {
0412           rtems_rtl_archive_del (archive);
0413           archive = find_archive;
0414         }
0415         archive->flags &= ~RTEMS_RTL_ARCHIVE_REMOVE;
0416         if (archive->mtime != sb.st_mtime)
0417         {
0418           archive->flags |= RTEMS_RTL_ARCHIVE_LOAD;
0419           archive->size = sb.st_size;
0420           archive->mtime = sb.st_mtime;
0421         }
0422       }
0423     }
0424   }
0425   return archive;
0426 }
0427 
0428 static bool
0429 rtems_rtl_archives_load_config (rtems_rtl_archives* archives)
0430 {
0431   struct stat sb;
0432 
0433   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0434     printf ("rtl: archive: config load: %s\n", archives->config_name);
0435 
0436   if (archives->config_name == NULL)
0437     return false;
0438 
0439   if (stat (archives->config_name, &sb) < 0)
0440   {
0441     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0442       printf ("rtl: archive: no config: %s\n", archives->config_name);
0443     return false;
0444   }
0445 
0446   /*
0447    * If the configuration has change reload it.
0448    */
0449   if (sb.st_mtime != archives->config_mtime)
0450   {
0451     int     fd;
0452     ssize_t r;
0453     char*   s;
0454     bool    in_comment;
0455 
0456     archives->config_mtime = sb.st_mtime;
0457     rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) archives->config);
0458     archives->config_length = 0;
0459     archives->config =
0460       rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, sb.st_size + 1, true);
0461     if (archives->config == NULL)
0462     {
0463       if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0464         printf ("rtl: archive: no memory for config\n");
0465       return false;
0466     }
0467 
0468     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0469       printf ("rtl: archive: config load: read %s\n", archives->config_name);
0470 
0471     fd = open (archives->config_name, O_RDONLY);
0472     if (fd < 0)
0473     {
0474       rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) archives->config);
0475       archives->config = NULL;
0476       archives->config_length = 0;
0477       if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0478         printf ("rtl: archive: config open error: %s\n", strerror (errno));
0479       return false;
0480     }
0481 
0482     r = read (fd, (void*) archives->config, sb.st_size);
0483     if (r < 0)
0484     {
0485       close (fd);
0486       rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) archives->config);
0487       archives->config = NULL;
0488       archives->config_length = 0;
0489       if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0490         printf ("rtl: archive: config read error: %s\n", strerror (errno));
0491       return false;
0492     }
0493 
0494     close (fd);
0495     archives->config_length = r;
0496 
0497     /*
0498      * Remove comments.
0499      */
0500     s = (char*) archives->config;
0501     in_comment = false;
0502     for (r = 0; r < archives->config_length; ++r, ++s)
0503     {
0504       if (*s == '#')
0505         in_comment = true;
0506       if (in_comment)
0507       {
0508         if (*s == '\n')
0509           in_comment = false;
0510         *s = '\0';
0511       }
0512     }
0513 
0514     /*
0515      * Create lines by turning '\r' and '\n' to '\0'.
0516      */
0517     s = (char*) archives->config;
0518     for (r = 0; r < archives->config_length; ++r, ++s)
0519     {
0520       if (*s == '\r' || *s == '\n')
0521         *s = '\0';
0522     }
0523 
0524     /*
0525      * Remove leading and trailing white space.
0526      */
0527     s = (char*) archives->config;
0528     r = 0;
0529     while (r < archives->config_length)
0530     {
0531       if (s[r] == '\0')
0532       {
0533         ++r;
0534       }
0535       else
0536       {
0537         size_t ls = strlen (&s[r]);
0538         size_t b = 0;
0539         while (b < ls && isspace ((unsigned char) s[r + b]))
0540         {
0541           s[r + b] = '\0';
0542           ++b;
0543         }
0544         b = ls - 1;
0545         while (b > 0 && isspace ((unsigned char) s[r + b]))
0546         {
0547           s[r + b] = '\0';
0548           --b;
0549         }
0550         r += ls;
0551       }
0552     }
0553 
0554     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0555     {
0556       int line = 1;
0557       printf ("rtl: archive: config:\n");
0558       r = 0;
0559       while (r < archives->config_length)
0560       {
0561         const char* cs = &archives->config[r];
0562         size_t      len = strlen (cs);
0563         if (len > 0)
0564         {
0565           printf (" %3d: %s\n", line, cs);
0566           ++line;
0567         }
0568         r += len + 1;
0569       }
0570     }
0571   }
0572 
0573   return true;
0574 }
0575 
0576 void
0577 rtems_rtl_archives_open (rtems_rtl_archives* archives, const char* config)
0578 {
0579   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0580     printf ("rtl: archive: open: %s\n", config);
0581   memset (archives, 0, sizeof (rtems_rtl_archives));
0582   archives->config_name = rtems_rtl_strdup (config);
0583   rtems_chain_initialize_empty (&archives->archives);
0584 }
0585 
0586 void
0587 rtems_rtl_archives_close (rtems_rtl_archives* archives)
0588 {
0589   rtems_chain_node* node;
0590   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0591     printf ("rtl: archive: close: count=%zu\n",
0592             rtems_chain_node_count_unprotected (&archives->archives));
0593   node = rtems_chain_first (&archives->archives);
0594   while (!rtems_chain_is_tail (&archives->archives, node))
0595   {
0596     rtems_rtl_archive* archive = (rtems_rtl_archive*) node;
0597     rtems_chain_node*  next_node = rtems_chain_next (node);
0598     rtems_rtl_archive_del (archive);
0599     node = next_node;
0600   }
0601   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) archives->config);
0602   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, archives);
0603 }
0604 
0605 static void
0606 rtems_rtl_archives_remove (rtems_rtl_archives* archives)
0607 {
0608   rtems_chain_node* node = rtems_chain_first (&archives->archives);
0609   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0610     printf ("rtl: archive: refresh: remove: checking %zu archive(s)\n",
0611             rtems_chain_node_count_unprotected (&archives->archives));
0612   while (!rtems_chain_is_tail (&archives->archives, node))
0613   {
0614     rtems_rtl_archive* archive = (rtems_rtl_archive*) node;
0615     rtems_chain_node*  next_node = rtems_chain_next (node);
0616     if ((archive->flags & RTEMS_RTL_ARCHIVE_REMOVE) != 0)
0617     {
0618       archive->flags &= ~RTEMS_RTL_ARCHIVE_REMOVE;
0619       if ((archive->flags & RTEMS_RTL_ARCHIVE_USER_LOAD) == 0)
0620         rtems_rtl_archive_del (archive);
0621     }
0622     node = next_node;
0623   }
0624 }
0625 
0626 static bool
0627 rtems_rtl_archive_loader (rtems_rtl_archive* archive, void* data)
0628 {
0629   int* loaded = (int*) data;
0630 
0631   if ((archive->flags & RTEMS_RTL_ARCHIVE_LOAD) != 0)
0632   {
0633     int         fd;
0634     off_t       offset = 0;
0635     size_t      size = 0;
0636     const char* name = "/";
0637 
0638     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0639       printf ("rtl: archive: loader: %s\n", archive->name);
0640 
0641     fd = open (archive->name, O_RDONLY);
0642     if (fd < 0)
0643     {
0644       if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0645         printf ("rtl: archive: loader: open error: %s: %s\n",
0646                 archive->name, strerror (errno));
0647       rtems_rtl_archive_set_error (errno, "opening archive file");
0648       return true;
0649     }
0650 
0651     if (rtems_rtl_obj_archive_find_obj (fd,
0652                                         archive->size,
0653                                         &name,
0654                                         &offset,
0655                                         &size,
0656                                         &archive->enames,
0657                                         rtems_rtl_archive_set_error))
0658     {
0659       if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0660         printf ("rtl: archive: loader: symbols: off=0x%08jx size=%zu\n",
0661                 offset, size);
0662 
0663       /*
0664        * Reallocate the symbol table memory if it has changed size.
0665        * Note, an updated library may have the same symbol table.
0666        */
0667       if (archive->symbols.size != size)
0668       {
0669         rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, archive->symbols.base);
0670         archive->symbols.base = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
0671                                                      size,
0672                                                      false);
0673         if (archive->symbols.base == NULL)
0674         {
0675           close (fd);
0676           memset (&archive->symbols, 0, sizeof (archive->symbols));
0677           rtems_rtl_archive_set_error (ENOMEM, "symbol table memory");
0678           return true;
0679         }
0680       }
0681 
0682       /*
0683        * Read the symbol table into memory and hold.
0684        */
0685       if (!rtems_rtl_seek_read (fd, offset, size, archive->symbols.base))
0686       {
0687         rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, archive->symbols.base);
0688         close (fd);
0689         memset (&archive->symbols, 0, sizeof (archive->symbols));
0690         rtems_rtl_archive_set_error (errno, "reading symbols");
0691         return true;
0692       }
0693 
0694       /*
0695        * The first 4 byte value is the number of entries. Range check the
0696        * value so the alloc size does not overflow (Coverity 1442636).
0697        */
0698       archive->symbols.entries =
0699         rtems_rtl_archive_read_32 (archive->symbols.base);
0700       if (archive->symbols.entries >= (SIZE_MAX / sizeof (rtems_rtl_archive_symbol)))
0701       {
0702         rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, archive->symbols.base);
0703         close (fd);
0704         memset (&archive->symbols, 0, sizeof (archive->symbols));
0705         rtems_rtl_archive_set_error (errno, "too many symbols");
0706         return true;
0707       }
0708 
0709       archive->symbols.size   = size;
0710       archive->symbols.names  = archive->symbols.base;
0711       archive->symbols.names += (archive->symbols.entries + 1) * 4;
0712 
0713       /*
0714        * Create a sorted symbol table.
0715        */
0716       size = archive->symbols.entries * sizeof (rtems_rtl_archive_symbol);
0717       archive->symbols.symbols =
0718         rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, size, true);
0719       if (archive->symbols.symbols != NULL)
0720       {
0721         const char* symbol = archive->symbols.names;
0722         size_t      e;
0723         for (e = 0; e < archive->symbols.entries; ++e)
0724         {
0725           archive->symbols.symbols[e].entry = e + 1;
0726           archive->symbols.symbols[e].label = symbol;
0727           symbol += strlen (symbol) + 1;
0728         }
0729         qsort (archive->symbols.symbols,
0730                archive->symbols.entries,
0731                sizeof (rtems_rtl_archive_symbol),
0732                rtems_rtl_archive_symbol_compare);
0733       }
0734 
0735       if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0736         printf ("rtl: archive: loader: symbols: " \
0737                 "base=%p entries=%zu names=%p (0x%08x) symbols=%p\n",
0738                 archive->symbols.base,
0739                 archive->symbols.entries,
0740                 archive->symbols.names,
0741                 (unsigned int) (archive->symbols.entries + 1) * 4,
0742                 archive->symbols.symbols);
0743 
0744       if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVE_SYMS) &&
0745           archive->symbols.entries > 0)
0746       {
0747         size_t e;
0748         printf ("rtl: archive: symbols: %s\n", archive->name );
0749         for (e = 0; e < archive->symbols.entries; ++e)
0750         {
0751           printf(" %6zu: %6zu %s\n", e + 1,
0752                  archive->symbols.symbols[e].entry,
0753                  archive->symbols.symbols[e].label);
0754         }
0755       }
0756     }
0757 
0758     close (fd);
0759 
0760     archive->flags &= ~RTEMS_RTL_ARCHIVE_LOAD;
0761 
0762     ++(*loaded);
0763   }
0764 
0765   return true;
0766 }
0767 
0768 static bool
0769 rtems_rtl_archives_load (rtems_rtl_archives* archives)
0770 {
0771   int loaded = 0;
0772   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0773     printf ("rtl: archive: archive: load\n");
0774   rtems_rtl_archive_iterate_archives (archives,
0775                                       rtems_rtl_archive_loader,
0776                                       &loaded);
0777   return loaded > 0;
0778 }
0779 
0780 bool
0781 rtems_rtl_archives_refresh (rtems_rtl_archives* archives)
0782 {
0783   size_t   config_path = 0;
0784   uint32_t flags = RTEMS_RTL_ARCHIVE_REMOVE;
0785 
0786   /*
0787    * Reload the configuration file if it has not been loaded or has been
0788    * updated.
0789    */
0790   if (!rtems_rtl_archives_load_config (archives))
0791     return false;
0792 
0793   /*
0794    * Assume all existing archives are to be removed. If an existing archive
0795    * is ccnfigured and found teh remove flags is cleared. At the of the
0796    * refresh end remove any archives with this flag still set.
0797    */
0798   rtems_rtl_archive_iterate_archives (archives,
0799                                       rtems_rtl_archive_set_flags,
0800                                       &flags);
0801 
0802   while (config_path < archives->config_length)
0803   {
0804     const char* dirname = &archives->config[config_path];
0805     char*       basename;
0806     const char  root[2] = { '/', '\0' };
0807     DIR*        dir;
0808 
0809     if (*dirname == '\0')
0810     {
0811       ++config_path;
0812       continue;
0813     }
0814 
0815     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0816       printf ("rtl: archive: refresh: %s\n", dirname);
0817 
0818     config_path += strlen (dirname);
0819 
0820     /*
0821      * Relative paths do not work in the config. Must be absolute.
0822      */
0823     if (dirname[0] != '/')
0824     {
0825       if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0826         printf ("rtl: archive: refresh: relative paths ignored: %s\n", dirname);
0827       continue;
0828     }
0829 
0830     /*
0831      * Scan the parent directory of the glob path matching file names.
0832      */
0833     basename = strrchr (dirname, '/');
0834     if (basename == NULL)
0835       continue;
0836 
0837     if (basename == dirname)
0838       dirname = &root[0];
0839 
0840     *basename = '\0';
0841     ++basename;
0842 
0843     dir = opendir (dirname);
0844 
0845     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0846       printf ("rtl: archive: refresh: %s %sfound\n",
0847               dirname, dir == NULL ? ": not " : "");
0848 
0849     if (dir != NULL)
0850     {
0851       while (true)
0852       {
0853         struct dirent  entry;
0854         struct dirent* result = NULL;
0855 
0856         if (readdir_r (dir, &entry, &result) != 0)
0857         {
0858           if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0859             printf ("rtl: archive: refresh: readdir error\n");
0860           break;
0861         }
0862 
0863         if (result == NULL)
0864           break;
0865 
0866         if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0867           printf ("rtl: archive: refresh: checking: %s (pattern: %s)\n",
0868                   entry.d_name, basename);
0869 
0870         if (fnmatch (basename, entry.d_name, 0) == 0)
0871         {
0872           rtems_rtl_archive* archive;
0873           archive = rtems_rtl_archive_get (archives, dirname, entry.d_name);
0874           if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0875             printf ("rtl: archive: refresh: %s: %sfound\n",
0876                     entry.d_name, archive == NULL ? ": not " : "");
0877         }
0878       }
0879       closedir (dir);
0880     }
0881 
0882     --basename;
0883     *basename = '/';
0884   }
0885 
0886   /*
0887    * Remove all archives flagged to be removed.
0888    */
0889   rtems_rtl_archives_remove (archives);
0890 
0891   /*
0892    * Load any new archives. If any are loaded set the archive search flag in
0893    * any unresolved external symbols so the archives are searched. The archive
0894    * search flag avoids searching for symbols we know are not in the known
0895    * archives,
0896    */
0897   if (rtems_rtl_archives_load (archives))
0898     rtems_rtl_unresolved_set_archive_search ();
0899 
0900   return true;
0901 }
0902 
0903 bool
0904 rtems_rtl_archive_load (rtems_rtl_archives* archives, const char* name)
0905 {
0906   if (archives != NULL)
0907   {
0908     rtems_rtl_archive* archive;
0909     int                loaded = 0;
0910 
0911     archive = rtems_rtl_archive_get (archives, "", name);
0912     if (archive == NULL)
0913     {
0914       rtems_rtl_set_error (ENOENT, "archive not found");
0915       return false;
0916     }
0917 
0918     archive->flags |= RTEMS_RTL_ARCHIVE_USER_LOAD;
0919 
0920     rtems_rtl_archive_loader (archive, &loaded);
0921     if (loaded == 0)
0922     {
0923       rtems_rtl_archive_del (archive);
0924       rtems_rtl_set_error (ENOENT, "archive load falied");
0925     }
0926 
0927     return true;
0928   }
0929   return false;
0930 }
0931 
0932 rtems_rtl_archive_search
0933 rtems_rtl_archive_obj_load (rtems_rtl_archives* archives,
0934                             const char*         symbol,
0935                             bool                load)
0936 {
0937   rtems_rtl_obj*       obj;
0938   rtems_chain_control* pending;
0939   int                  fd;
0940   size_t               archive_count;
0941 
0942   rtems_rtl_archive_obj_data search = {
0943     .symbol  = symbol,
0944     .archive = NULL,
0945     .offset  = 0
0946   };
0947 
0948   archive_count = rtems_chain_node_count_unprotected (&archives->archives);
0949 
0950   if (archive_count == 0)
0951   {
0952     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0953       printf ("rtl: archive: load: no archives\n");
0954     return rtems_rtl_archive_search_no_config;
0955   }
0956 
0957   pending = rtems_rtl_pending_unprotected ();
0958   if (pending == NULL)
0959   {
0960     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0961       printf ("rtl: archive: load: no pending list\n");
0962     return rtems_rtl_archive_search_not_found;
0963   }
0964 
0965   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0966     printf ("rtl: archive: load: searching %zu archives\n", archive_count);
0967 
0968   rtems_rtl_archive_iterate_archives (archives,
0969                                       rtems_rtl_archive_obj_finder,
0970                                       &search);
0971 
0972   if (search.archive == NULL)
0973   {
0974     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0975       printf ("rtl: archive: load: not found: %s\n", symbol);
0976     return rtems_rtl_archive_search_not_found;
0977   }
0978 
0979   if (!load)
0980   {
0981     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0982       printf ("rtl: archive: load: found (no load): %s\n", symbol);
0983     return rtems_rtl_archive_search_found;
0984   }
0985 
0986   obj = rtems_rtl_obj_alloc ();
0987   if (obj == NULL)
0988   {
0989     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
0990       printf ("rtl: archive: alloc: no memory: %s\n",
0991               search.archive->name);
0992     return rtems_rtl_archive_search_error;
0993   }
0994 
0995   obj->aname = rtems_rtl_strdup (search.archive->name);
0996 
0997   fd = open (obj->aname, O_RDONLY);
0998   if (fd < 0)
0999   {
1000     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
1001       printf ("rtl: archive: load: open error: %s: %s\n",
1002               obj->aname, strerror (errno));
1003     rtems_rtl_obj_free (obj);
1004     return rtems_rtl_archive_search_error;
1005   }
1006 
1007   obj->oname = NULL;
1008   obj->ooffset = search.offset;
1009 
1010   if (!rtems_rtl_obj_archive_find_obj (fd,
1011                                        search.archive->size,
1012                                        &obj->oname,
1013                                        &obj->ooffset,
1014                                        &obj->fsize,
1015                                        &search.archive->enames,
1016                                        rtems_rtl_archive_set_error))
1017   {
1018     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
1019       printf ("rtl: archive: load: load error: %s:%s\n",
1020               obj->aname, obj->oname);
1021     close (fd);
1022     rtems_rtl_obj_free (obj);
1023     return rtems_rtl_archive_search_error;
1024   }
1025 
1026   obj->fname = rtems_rtl_strdup (obj->aname);
1027   obj->ooffset -= RTEMS_RTL_AR_FHDR_SIZE;
1028   obj->fsize = search.archive->size;
1029 
1030   close (fd);
1031 
1032   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
1033     printf ("rtl: archive: loading: %s:%s@0x%08jx size:%zu\n",
1034             obj->aname, obj->oname, obj->ooffset, obj->fsize);
1035 
1036   rtems_chain_append (pending, &obj->link);
1037 
1038   if (!rtems_rtl_obj_load (obj))
1039   {
1040     if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
1041       printf ("rtl: archive: loading: error: %s:%s@0x%08jx: %s\n",
1042               obj->aname, obj->oname, obj->ooffset,
1043               rtems_rtl_last_error_unprotected ());
1044     rtems_chain_extract (&obj->link);
1045     rtems_rtl_obj_free (obj);
1046     rtems_rtl_obj_caches_flush ();
1047     return rtems_rtl_archive_search_error;
1048   }
1049 
1050   rtems_rtl_obj_caches_flush ();
1051 
1052   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
1053     printf ("rtl: archive: loading: loaded: %s:%s@0x%08jx\n",
1054             obj->aname, obj->oname, obj->ooffset);
1055 
1056   return rtems_rtl_archive_search_loaded;
1057 }
1058 
1059 bool
1060 rtems_rtl_obj_archive_find_obj (int                     fd,
1061                                 size_t                  fsize,
1062                                 const char**            name,
1063                                 off_t*                  ooffset,
1064                                 size_t*                 osize,
1065                                 off_t*                  extended_file_names,
1066                                 rtems_rtl_archive_error error)
1067 {
1068   uint8_t header[RTEMS_RTL_AR_FHDR_SIZE];
1069   bool    scanning;
1070 
1071   if (name == NULL)
1072   {
1073     error (errno, "invalid object name");
1074     *ooffset = 0;
1075     *osize = 0;
1076     return false;
1077   }
1078 
1079   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
1080     printf ("rtl: archive: find obj: %s @ 0x%08jx\n", *name, *ooffset);
1081 
1082   if (read (fd, &header[0], RTEMS_RTL_AR_IDENT_SIZE) !=  RTEMS_RTL_AR_IDENT_SIZE)
1083   {
1084     error (errno, "reading archive identifer");
1085     *ooffset = 0;
1086     *osize = 0;
1087     return false;
1088   }
1089 
1090   if (memcmp (header, RTEMS_RTL_AR_IDENT, RTEMS_RTL_AR_IDENT_SIZE) != 0)
1091   {
1092     error (EINVAL, "invalid archive identifer");
1093     *ooffset = 0;
1094     *osize = 0;
1095     return false;
1096   }
1097 
1098   /*
1099    * Seek to the current offset in the archive and if we have a valid archive
1100    * file header present check the file name for a match with the oname field
1101    * of the object descriptor. If the archive header is not valid and it is the
1102    * first pass reset the offset and start the search again in case the offset
1103    * provided is not valid any more.
1104    *
1105    * The archive can have a symbol table at the start. Ignore it. A symbol
1106    * table has the file name '/'.
1107    *
1108    * The archive can also have the GNU extended file name table. This
1109    * complicates the processing. If the object's file name starts with '/' the
1110    * remainder of the file name is an offset into the extended file name
1111    * table. To find the extended file name table we need to scan from start of
1112    * the archive for a file name of '//'. Once found we remeber the table's
1113    * start and can direct seek to file name location. In other words the scan
1114    * only happens once.
1115    *
1116    * If the name had the offset encoded we go straight to that location.
1117    */
1118 
1119   if (*ooffset != 0)
1120     scanning = false;
1121   else
1122   {
1123     if (*name == NULL)
1124     {
1125       error (errno, "invalid object name and archive offset");
1126       *ooffset = 0;
1127       *osize = 0;
1128       return false;
1129     }
1130     scanning = true;
1131     *ooffset = RTEMS_RTL_AR_FHDR_BASE;
1132     *osize = 0;
1133   }
1134 
1135   while (*ooffset < fsize)
1136   {
1137     /*
1138      * Clean up any existing data.
1139      */
1140     memset (header, 0, sizeof (header));
1141 
1142     if (!rtems_rtl_seek_read (fd, *ooffset, RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
1143     {
1144       error (errno, "seek/read archive file header");
1145       *ooffset = 0;
1146       *osize = 0;
1147       return false;
1148     }
1149 
1150     if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
1151         (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
1152     {
1153       if (scanning)
1154       {
1155         error (EINVAL, "invalid archive file header");
1156         *ooffset = 0;
1157         *osize = 0;
1158         return false;
1159       }
1160 
1161       scanning = true;
1162       *ooffset = RTEMS_RTL_AR_FHDR_BASE;
1163       continue;
1164     }
1165 
1166     /*
1167      * The archive header is always aligned to an even address.
1168      */
1169     *osize = (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
1170                                       RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
1171 
1172     /*
1173      * Check for the GNU extensions.
1174      */
1175     if (header[0] == '/')
1176     {
1177       const char* name_ = *name;
1178       off_t extended_off;
1179 
1180       switch (header[1])
1181       {
1182         case ' ':
1183           /*
1184            * SVR4/GNU Symbols table. Nothing more to do.
1185            */
1186           *ooffset += RTEMS_RTL_AR_FHDR_SIZE;
1187           return true;
1188         case '/':
1189           /*
1190            * Extended file names table. Remember. If asked to find this file
1191            * return the result.
1192            */
1193           *extended_file_names = *ooffset + RTEMS_RTL_AR_FHDR_SIZE;
1194           if (name_[0] == '/' && name_[1] == '/')
1195           {
1196             *ooffset = *ooffset + RTEMS_RTL_AR_FHDR_SIZE;
1197             return true;
1198           }
1199           break;
1200         case '0':
1201         case '1':
1202         case '2':
1203         case '3':
1204         case '4':
1205         case '5':
1206         case '6':
1207         case '7':
1208         case '8':
1209         case '9':
1210           /*
1211            * Offset into the extended file name table. If we do not have the
1212            * offset to the extended file name table find it.
1213            */
1214           extended_off =
1215             rtems_rtl_scan_decimal (&header[1], RTEMS_RTL_AR_FNAME_SIZE);
1216 
1217           if (*extended_file_names == 0)
1218           {
1219             off_t off = RTEMS_RTL_AR_IDENT_SIZE;
1220             while (*extended_file_names == 0)
1221             {
1222               off_t esize;
1223 
1224               if (!rtems_rtl_seek_read (fd, off,
1225                                         RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
1226               {
1227                 error (errno, "seeking/reading archive ext file name header");
1228                 *ooffset = 0;
1229                 *osize = 0;
1230                 return false;
1231               }
1232 
1233               if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
1234                   (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
1235               {
1236                 error (errno, "invalid archive file header");
1237                 *ooffset = 0;
1238                 *osize = 0;
1239                 return false;
1240               }
1241 
1242               if ((header[0] == '/') && (header[1] == '/'))
1243               {
1244                 *extended_file_names = off + RTEMS_RTL_AR_FHDR_SIZE;
1245                 break;
1246               }
1247 
1248               esize =
1249                 (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
1250                                          RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
1251               off += esize + RTEMS_RTL_AR_FHDR_SIZE;
1252             }
1253           }
1254 
1255           if (*extended_file_names != 0)
1256           {
1257             /*
1258              * We know the offset in the archive to the extended file. Read the
1259              * name from the table and compare with the name we are after.
1260              */
1261             #define RTEMS_RTL_MAX_FILE_SIZE (256)
1262             char ename[RTEMS_RTL_MAX_FILE_SIZE];
1263 
1264             if (!rtems_rtl_seek_read (fd, *extended_file_names + extended_off,
1265                                       RTEMS_RTL_MAX_FILE_SIZE, (uint8_t*) &ename[0]))
1266             {
1267               error (errno, "invalid archive ext file seek/read");
1268               *ooffset = 0;
1269               *osize = 0;
1270               return false;
1271             }
1272 
1273             /*
1274              * If there is no name memory the user is asking us to return the
1275              * name in the archive at the offset.
1276              */
1277             if (*name == NULL)
1278               *name = rtems_rtl_archive_dup_name (ename);
1279             if (rtems_rtl_archive_match_name (*name, ename))
1280             {
1281               *ooffset += RTEMS_RTL_AR_FHDR_SIZE;
1282               return true;
1283             }
1284           }
1285           break;
1286         default:
1287           /*
1288            * Ignore the file because we do not know what it it.
1289            */
1290           break;
1291       }
1292     }
1293     else
1294     {
1295       const char* ename = (const char*) &header[RTEMS_RTL_AR_FNAME];
1296       if (*name == NULL)
1297         *name = rtems_rtl_archive_dup_name (ename);
1298       if (rtems_rtl_archive_match_name (*name, ename))
1299       {
1300         *ooffset += RTEMS_RTL_AR_FHDR_SIZE;
1301         return true;
1302       }
1303     }
1304 
1305     *ooffset += *osize + RTEMS_RTL_AR_FHDR_SIZE;
1306   }
1307 
1308   error (ENOENT, "object file not found");
1309   *ooffset = 0;
1310   *osize = 0;
1311   return false;
1312 
1313 }