source: rtems/cpukit/libdl/rtl-archive.c @ 62b01ab

5
Last change on this file since 62b01ab was 62b01ab, checked in by Chris Johns <chrisj@…>, on 02/18/19 at 01:18:50

libdl/archive: Fix the config file string index while removing tailing white space.

Coverity issue 1442540

Updates #3686

  • Property mode set to 100644
File size: 36.0 KB
Line 
1/*
2 *  COPYRIGHT (c) 2018 Chris Johns <chrisj@rtems.org>
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.org/license/LICENSE.
7 */
8/**
9 * @file
10 *
11 * @ingroup rtl
12 *
13 * @brief RTEMS Run-Time Linker Archive
14 */
15
16#if HAVE_CONFIG_H
17#include "config.h"
18#endif
19
20#include <ctype.h>
21#include <dirent.h>
22#include <errno.h>
23#include <fnmatch.h>
24#include <inttypes.h>
25#include <stdio.h>
26#include <string.h>
27
28#include <rtems/libio_.h>
29
30#include <rtems/rtl/rtl.h>
31#include "rtl-chain-iterator.h"
32#include <rtems/rtl/rtl-trace.h>
33#include "rtl-string.h"
34#include "rtl-error.h"
35
36/**
37 * The archive symbols threshold after which a sorted symbol table is
38 * created.
39 */
40#define RTEMS_RTL_ARCHIVE_SYMBOLS_SORT (8)
41
42/**
43 * Archive headers.
44 */
45#define RTEMS_RTL_AR_IDENT      "!<arch>\n"
46#define RTEMS_RTL_AR_IDENT_SIZE (sizeof (RTEMS_RTL_AR_IDENT) - 1)
47#define RTEMS_RTL_AR_FHDR_BASE  RTEMS_RTL_AR_IDENT_SIZE
48#define RTEMS_RTL_AR_FNAME      (0)
49#define RTEMS_RTL_AR_FNAME_SIZE (16)
50#define RTEMS_RTL_AR_SIZE       (48)
51#define RTEMS_RTL_AR_SIZE_SIZE  (10)
52#define RTEMS_RTL_AR_MAGIC      (58)
53#define RTEMS_RTL_AR_MAGIC_SIZE (2)
54#define RTEMS_RTL_AR_FHDR_SIZE  (60)
55
56/**
57 * Read a 32bit value from the symbol table.
58 */
59static unsigned int
60rtems_rtl_archive_read_32 (void* data)
61{
62  uint8_t*     b = (uint8_t*) data;
63  unsigned int v = b[0];
64  v = (v << 8) | b[1];
65  v = (v << 8) | b[2];
66  v = (v << 8) | b[3];
67  return v;
68}
69
70static void
71rtems_rtl_archive_set_error (int num, const char* text)
72{
73  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
74    printf ("rtl: archive: error: %3d:  %s\n", num, text);
75}
76
77static uint64_t
78rtems_rtl_scan_decimal (const uint8_t* string, size_t len)
79{
80  uint64_t value = 0;
81
82  while (len && (*string != ' '))
83  {
84    value *= 10;
85    value += *string - '0';
86    ++string;
87    --len;
88  }
89
90  return value;
91}
92
93static bool
94rtems_rtl_seek_read (int fd, off_t off, size_t len, uint8_t* buffer)
95{
96  if (lseek (fd, off, SEEK_SET) < 0)
97    return false;
98  if (read (fd, buffer, len) != len)
99    return false;
100  return true;
101}
102
103/**
104 * Archive iterator.
105 */
106typedef bool (*rtems_rtl_archive_iterator) (rtems_rtl_archive* archive,
107                                            void*              data);
108
109/**
110 * Chain iterator data.
111 */
112typedef struct rtems_rtl_archive_chain_data
113{
114  void*                      data;      /**< User's data. */
115  rtems_rtl_archive_iterator iterator;  /**< The actual iterator. */
116} rtems_rtl_archive_chain_data;
117
118static bool
119rtems_rtl_archive_node_iterator (rtems_chain_node* node, void* data)
120{
121  rtems_rtl_archive*            archive;
122  rtems_rtl_archive_chain_data* chain_data;
123  archive    = (rtems_rtl_archive*) node;
124  chain_data = (rtems_rtl_archive_chain_data*) data;
125  return chain_data->iterator (archive, chain_data->data);
126}
127
128static void
129rtems_rtl_archive_iterate_archives (rtems_rtl_archives*        archives,
130                                    rtems_rtl_archive_iterator iterator,
131                                    void*                      data)
132{
133  rtems_rtl_archive_chain_data chain_data = {
134    .data = data,
135    .iterator = iterator
136  };
137  rtems_rtl_chain_iterate (&archives->archives,
138                           rtems_rtl_archive_node_iterator,
139                           &chain_data);
140}
141
142static bool
143rtems_rtl_rchive_name_end (const char c)
144{
145  return c == '\0' || c == '\n' || c == '/';
146}
147
148static const char*
149rtems_rtl_archive_dup_name (const char* name)
150{
151  size_t len = 0;
152  char*  dup;
153  while (!rtems_rtl_rchive_name_end (name[len]))
154    ++len;
155  dup = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, len + 1, true);
156  if (dup != NULL)
157    memcpy (dup, name, len);
158  return dup;
159}
160
161static bool
162rtems_rtl_archive_match_name (const char* file_name, const char* name)
163{
164  if (name != NULL)
165  {
166    while (!rtems_rtl_rchive_name_end (*file_name) &&
167           !rtems_rtl_rchive_name_end (*name) && *file_name == *name)
168    {
169      ++file_name;
170      ++name;
171    }
172    if (((*file_name == '\0') || (*file_name == '\n') || (*file_name == '/')) &&
173        ((*name == '\0') || (*name == '/')))
174      return true;
175  }
176  return false;
177}
178
179static bool
180rtems_rtl_archive_set_flags (rtems_rtl_archive* archive, void* data)
181{
182  uint32_t mask = *((uint32_t*) data);
183  archive->flags |= mask;
184  return true;
185}
186
187typedef struct rtems_rtl_archive_find_data
188{
189  rtems_rtl_archive* archive;
190  const char*        path;
191} rtems_rtl_archive_find_data;
192
193static bool
194rtems_rtl_archive_finder (rtems_rtl_archive* archive, void* data)
195{
196  rtems_rtl_archive_find_data* find;
197  find = (rtems_rtl_archive_find_data*) data;
198  if (strcmp (find->path, archive->name) == 0)
199  {
200    find->archive = archive;
201    return false;
202  }
203  return true;
204}
205
206static rtems_rtl_archive*
207rtems_rtl_archive_find (rtems_rtl_archives* archives,
208                        const char*         path)
209{
210  rtems_rtl_archive_find_data find = {
211    .archive = NULL,
212    .path = path
213  };
214  rtems_rtl_archive_iterate_archives (archives,
215                                      rtems_rtl_archive_finder,
216                                      &find);
217  return find.archive;
218}
219
220/*
221 * Find an object file in archive that contains the symbol we are
222 * searching for.
223 *
224 * The symbol search is performance sensitive. The archive's symbol table being
225 * searched is the symbol table in the archive created by ranlib. This table is
226 * not sorted so a sorted table of pointered to the symbols is generated after
227 * loading if there are enough symbols. For small symbol tables the searc is
228 * linear. The entire table is held in memory. At the time of writing this code
229 * the symbol table for the SPARC architecture's libc is 16k.
230 *
231 * The ranlib table is:
232 *
233 *    [4]                - size of table in bytes
234 *    [0..(entries x 4)] - 4 byte binary offsets into the archive
235 *                         for each symbol
236 *    [0..m]             - variable length table of strings, nul
237 *                         separated and sorted
238 *
239 * Note: The loading of an object file from an archive uses an offset in the
240 *       file name to speed the loading.
241 */
242typedef struct rtems_rtl_archive_obj_data
243{
244  const char*        symbol;   /**< The symbol to search for. */
245  rtems_rtl_archive* archive;  /**< The archive the symbol is found
246                                *   in. */
247  off_t              offset;   /**< The offset in the archive if found
248                                *   else 0 */
249} rtems_rtl_archive_obj_data;
250
251static int
252rtems_rtl_archive_symbol_compare (const void* a, const void* b)
253{
254  const rtems_rtl_archive_symbol* sa;
255  const rtems_rtl_archive_symbol* sb;
256  sa = (const rtems_rtl_archive_symbol*) a;
257  sb = (const rtems_rtl_archive_symbol*) b;
258  return strcmp (sa->label, sb->label);
259}
260
261static bool
262rtems_rtl_archive_obj_finder (rtems_rtl_archive* archive, void* data)
263{
264  const rtems_rtl_archive_symbols* symbols = &archive->symbols;
265
266  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
267    printf ("rtl: archive: finder: %s: entries: %zu\n",
268            archive->name, symbols->entries);
269
270  /*
271   * Make sure there is a valid symbol table.
272   */
273  if (symbols->base != NULL)
274  {
275    /*
276     * Perform a linear search if there is no sorted symbol table.
277     */
278    rtems_rtl_archive_obj_data* search = (rtems_rtl_archive_obj_data*) data;
279    if (symbols->symbols == NULL)
280    {
281      const char* symbol = symbols->names;
282      size_t      entry;
283      for (entry = 0; entry < symbols->entries; ++entry)
284      {
285        if (strcmp (search->symbol, symbol) == 0)
286        {
287          search->archive = archive;
288          search->offset =
289            rtems_rtl_archive_read_32 (symbols->base + (entry * 4));
290          return false;
291        }
292        symbol += strlen (symbol) + 1;
293      }
294    }
295    else
296    {
297      rtems_rtl_archive_symbol*      match;
298      const rtems_rtl_archive_symbol key = {
299        .entry = -1,
300        .label = search->symbol
301      };
302      match = bsearch (&key,
303                       symbols->symbols,
304                       symbols->entries,
305                       sizeof (symbols->symbols[0]),
306                       rtems_rtl_archive_symbol_compare);
307      if (match != NULL)
308      {
309          search->archive = archive;
310          search->offset =
311            rtems_rtl_archive_read_32 (symbols->base + (match->entry * 4));
312          return false;
313      }
314    }
315  }
316
317  /*
318   * Next archive.
319   */
320  return true;
321}
322
323static rtems_rtl_archive*
324rtems_rtl_archive_new (rtems_rtl_archives* archives,
325                       const char*         path,
326                       const char*         name)
327{
328  rtems_rtl_archive* archive;
329  size_t             path_size;
330  size_t             size;
331  /*
332   * Handle the case of the path being just '/', do not create '//'.
333   */
334  path_size = strlen (path);
335  size = sizeof(rtems_rtl_archive) + path_size + strlen (name) + 1;
336  if (path_size > 1)
337    ++size;
338  archive = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, size, true);
339  if (archive == NULL)
340  {
341    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
342      printf ("rtl: archive: new: %s: no memory\n", name);
343  }
344  else
345  {
346    char* aname;
347    archive->name = ((const char*) archive) + sizeof(rtems_rtl_archive);
348    aname = (char*) archive->name;
349    strcpy (aname, path);
350    if (path_size > 1)
351      strcat (aname, "/");
352    strcat (aname, name);
353    rtems_chain_set_off_chain (&archive->node);
354    archive->flags |= RTEMS_RTL_ARCHIVE_LOAD;
355  }
356  return archive;
357}
358
359static void
360rtems_rtl_archive_del (rtems_rtl_archive* archive)
361{
362  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
363    printf ("rtl: archive: del: %s\n",  archive->name);
364  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, archive->symbols.base);
365  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, archive->symbols.symbols);
366  if (!rtems_chain_is_node_off_chain (&archive->node))
367    rtems_chain_extract (&archive->node);
368  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, archive);
369}
370
371static rtems_rtl_archive*
372rtems_rtl_archive_get (rtems_rtl_archives* archives,
373                       const char*         path,
374                       const char*         name)
375{
376  rtems_rtl_archive* archive;
377  /*
378   * Getting a new archive turns the path and name into a single path the stat
379   * function can use. No matter how you try some memory is needed so it is
380   * easier to get a new archive object and delete it if it exists.
381   */
382  archive = rtems_rtl_archive_new (archives, path, name);
383  if (archive != NULL)
384  {
385    struct stat sb;
386    if (stat (archive->name, &sb) == 0)
387    {
388      if (S_ISREG (sb.st_mode))
389      {
390        rtems_rtl_archive* find_archive;
391        find_archive = rtems_rtl_archive_find (archives, archive->name);
392        if (find_archive == NULL)
393        {
394          rtems_chain_append (&archives->archives, &archive->node);
395        }
396        else
397        {
398          rtems_rtl_archive_del (archive);
399          archive = find_archive;
400        }
401        archive->flags &= ~RTEMS_RTL_ARCHIVE_REMOVE;
402        if (archive->mtime != sb.st_mtime)
403        {
404          archive->flags |= RTEMS_RTL_ARCHIVE_LOAD;
405          archive->size = sb.st_size;
406          archive->mtime = sb.st_mtime;
407        }
408      }
409    }
410  }
411  return archive;
412}
413
414static bool
415rtems_rtl_archives_load_config (rtems_rtl_archives* archives)
416{
417  struct stat sb;
418
419  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
420    printf ("rtl: archive: config load: %s\n", archives->config_name);
421
422  if (archives->config_name == NULL)
423    return false;
424
425  if (stat (archives->config_name, &sb) < 0)
426  {
427    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
428      printf ("rtl: archive: no config: %s\n", archives->config_name);
429    return false;
430  }
431
432  /*
433   * If the configuration has change reload it.
434   */
435  if (sb.st_mtime != archives->config_mtime)
436  {
437    int     fd;
438    ssize_t r;
439    char*   s;
440    bool    in_comment;
441
442    archives->config_mtime = sb.st_mtime;
443    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) archives->config);
444    archives->config_length = 0;
445    archives->config =
446      rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, sb.st_size + 1, true);
447    if (archives->config == NULL)
448    {
449      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
450        printf ("rtl: archive: no memory for config\n");
451      return false;
452    }
453
454    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
455      printf ("rtl: archive: config load: read %s\n", archives->config_name);
456
457    fd = open (archives->config_name, O_RDONLY);
458    if (fd < 0)
459    {
460      rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) archives->config);
461      archives->config = NULL;
462      archives->config_length = 0;
463      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
464        printf ("rtl: archive: config open error: %s\n", strerror (errno));
465      return false;
466    }
467
468    r = read (fd, (void*) archives->config, sb.st_size);
469    if (r < 0)
470    {
471      close (fd);
472      rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) archives->config);
473      archives->config = NULL;
474      archives->config_length = 0;
475      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
476        printf ("rtl: archive: config read error: %s\n", strerror (errno));
477      return false;
478    }
479
480    close (fd);
481    archives->config_length = r;
482
483    /*
484     * Remove comments.
485     */
486    s = (char*) archives->config;
487    in_comment = false;
488    for (r = 0; r < archives->config_length; ++r, ++s)
489    {
490      if (*s == '#')
491        in_comment = true;
492      if (in_comment)
493      {
494        if (*s == '\n')
495          in_comment = false;
496        *s = '\0';
497      }
498    }
499
500    /*
501     * Create lines by turning '\r' and '\n' to '\0'.
502     */
503    s = (char*) archives->config;
504    for (r = 0; r < archives->config_length; ++r, ++s)
505    {
506      if (*s == '\r' || *s == '\n')
507        *s = '\0';
508    }
509
510    /*
511     * Remove leading and trailing white space.
512     */
513    s = (char*) archives->config;
514    r = 0;
515    while (r < archives->config_length)
516    {
517      if (s[r] == '\0')
518      {
519        ++r;
520      }
521      else
522      {
523        size_t ls = strlen (&s[r]);
524        size_t b = 0;
525        while (b < ls && isspace (s[r + b]))
526        {
527          s[r + b] = '\0';
528          ++b;
529        }
530        b = ls - 1;
531        while (b > 0 && isspace (s[r + b]))
532        {
533          s[r + b] = '\0';
534          --b;
535        }
536        r += ls;
537      }
538    }
539
540    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
541    {
542      int line = 1;
543      printf ("rtl: archive: config:\n");
544      r = 0;
545      while (r < archives->config_length)
546      {
547        const char* cs = &archives->config[r];
548        size_t      len = strlen (cs);
549        if (len > 0)
550        {
551          printf (" %3d: %s\n", line, cs);
552          ++line;
553        }
554        r += len + 1;
555      }
556    }
557  }
558
559  return true;
560}
561
562void
563rtems_rtl_archives_open (rtems_rtl_archives* archives, const char* config)
564{
565  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
566    printf ("rtl: archive: open: %s\n", config);
567  memset (archives, 0, sizeof (rtems_rtl_archives));
568  archives->config_name = rtems_rtl_strdup (config);
569  rtems_chain_initialize_empty (&archives->archives);
570}
571
572void
573rtems_rtl_archives_close (rtems_rtl_archives* archives)
574{
575  rtems_chain_node* node;
576  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
577    printf ("rtl: archive: close: count=%zu\n",
578            rtems_chain_node_count_unprotected (&archives->archives));
579  node = rtems_chain_first (&archives->archives);
580  while (!rtems_chain_is_tail (&archives->archives, node))
581  {
582    rtems_rtl_archive* archive = (rtems_rtl_archive*) node;
583    rtems_chain_node*  next_node = rtems_chain_next (node);
584    rtems_rtl_archive_del (archive);
585    node = next_node;
586  }
587  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) archives->config);
588  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, archives);
589}
590
591static void
592rtems_rtl_archives_remove (rtems_rtl_archives* archives)
593{
594  rtems_chain_node* node = rtems_chain_first (&archives->archives);
595  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
596    printf ("rtl: archive: refresh: remove: checking %zu archive(s)\n",
597            rtems_chain_node_count_unprotected (&archives->archives));
598  while (!rtems_chain_is_tail (&archives->archives, node))
599  {
600    rtems_rtl_archive* archive = (rtems_rtl_archive*) node;
601    rtems_chain_node*  next_node = rtems_chain_next (node);
602    if ((archive->flags & RTEMS_RTL_ARCHIVE_REMOVE) != 0)
603    {
604      archive->flags &= ~RTEMS_RTL_ARCHIVE_REMOVE;
605      if ((archive->flags & RTEMS_RTL_ARCHIVE_USER_LOAD) == 0)
606        rtems_rtl_archive_del (archive);
607    }
608    node = next_node;
609  }
610}
611
612static bool
613rtems_rtl_archive_loader (rtems_rtl_archive* archive, void* data)
614{
615  int* loaded = (int*) data;
616
617  if ((archive->flags & RTEMS_RTL_ARCHIVE_LOAD) != 0)
618  {
619    int         fd;
620    off_t       offset = 0;
621    size_t      size = 0;
622    const char* name = "/";
623
624    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
625      printf ("rtl: archive: loader: %s\n", archive->name);
626
627    fd = open (archive->name, O_RDONLY);
628    if (fd < 0)
629    {
630      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
631        printf ("rtl: archive: loader: open error: %s: %s\n",
632                archive->name, strerror (errno));
633      rtems_rtl_archive_set_error (errno, "opening archive file");
634      return true;
635    }
636
637    if (rtems_rtl_obj_archive_find_obj (fd,
638                                        archive->size,
639                                        &name,
640                                        &offset,
641                                        &size,
642                                        &archive->enames,
643                                        rtems_rtl_archive_set_error))
644    {
645      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
646        printf ("rtl: archive: loader: symbols: off=0x%08jx size=%zu\n",
647                offset, size);
648
649      /*
650       * Reallocation the symbol table memory if it has changed size.
651       * Note, an updated library may have te same symbol table.
652       */
653      if (archive->symbols.size != size)
654      {
655        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, archive->symbols.base);
656        archive->symbols.base = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
657                                                     size,
658                                                     false);
659        if (archive->symbols.base == NULL)
660        {
661          close (fd);
662          memset (&archive->symbols, 0, sizeof (archive->symbols));
663          rtems_rtl_archive_set_error (ENOMEM, "symbol table memory");
664          return true;
665        }
666      }
667
668      /*
669       * Read the symbol table into memory and hold.
670       */
671      if (!rtems_rtl_seek_read (fd, offset, size, archive->symbols.base))
672      {
673        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, archive->symbols.base);
674        close (fd);
675        memset (&archive->symbols, 0, sizeof (archive->symbols));
676        rtems_rtl_archive_set_error (errno, "reading symbols");
677        return true;
678      }
679
680      /*
681       * The first 4 byte value is the number of entries.
682       */
683      archive->symbols.entries =
684        rtems_rtl_archive_read_32 (archive->symbols.base);
685      archive->symbols.size   = size;
686      archive->symbols.names  = archive->symbols.base;
687      archive->symbols.names += (archive->symbols.entries + 1) * 4;
688
689      /*
690       * Created a sorted symbol table if over the threshold number of symbols.
691       */
692      if (archive->symbols.entries > RTEMS_RTL_ARCHIVE_SYMBOLS_SORT)
693      {
694        const size_t size =
695          archive->symbols.entries * sizeof (rtems_rtl_archive_symbol);
696        archive->symbols.symbols =
697          rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, size, true);
698        if (archive->symbols.symbols != NULL)
699        {
700          const char* symbol = archive->symbols.names;
701          size_t      e;
702          for (e = 0; e < archive->symbols.entries; ++e)
703          {
704            archive->symbols.symbols[e].entry = e + 1;
705            archive->symbols.symbols[e].label = symbol;
706            symbol += strlen (symbol) + 1;
707          }
708          qsort (archive->symbols.symbols,
709                 archive->symbols.entries,
710                 sizeof (rtems_rtl_archive_symbol),
711                 rtems_rtl_archive_symbol_compare);
712        }
713      }
714
715      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
716        printf ("rtl: archive: loader: symbols: " \
717                "base=%p entries=%zu names=%p (0x%08x) symbols=%p\n",
718                archive->symbols.base,
719                archive->symbols.entries,
720                archive->symbols.names,
721                (unsigned int) (archive->symbols.entries + 1) * 4,
722                archive->symbols.symbols);
723
724      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVE_SYMS) &&
725          archive->symbols.entries > 0)
726      {
727        size_t e;
728        printf ("rtl: archive: symbols: %s\n", archive->name );
729        for (e = 0; e < archive->symbols.entries; ++e)
730        {
731          printf(" %6zu: %6zu %s\n", e + 1,
732                 archive->symbols.symbols[e].entry,
733                 archive->symbols.symbols[e].label);
734        }
735      }
736    }
737
738    close (fd);
739
740    archive->flags &= ~RTEMS_RTL_ARCHIVE_LOAD;
741
742    ++(*loaded);
743  }
744
745  return true;
746}
747
748static bool
749rtems_rtl_archives_load (rtems_rtl_archives* archives)
750{
751  int loaded = 0;
752  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
753    printf ("rtl: archive: archive: load\n");
754  rtems_rtl_archive_iterate_archives (archives,
755                                      rtems_rtl_archive_loader,
756                                      &loaded);
757  return loaded > 0;
758}
759
760bool
761rtems_rtl_archives_refresh (rtems_rtl_archives* archives)
762{
763  size_t   config_path = 0;
764  uint32_t flags = RTEMS_RTL_ARCHIVE_REMOVE;
765
766  /*
767   * Reload the configuration file if it has not been loaded or has been
768   * updated.
769   */
770  if (!rtems_rtl_archives_load_config (archives))
771    return false;
772
773  /*
774   * Assume all existing archives are to be removed. If an existing archive
775   * is ccnfigured and found teh remove flags is cleared. At the of the
776   * refresh end remove any archives with this flag still set.
777   */
778  rtems_rtl_archive_iterate_archives (archives,
779                                      rtems_rtl_archive_set_flags,
780                                      &flags);
781
782  while (config_path < archives->config_length)
783  {
784    const char* dirname = &archives->config[config_path];
785    char*       basename;
786    const char  root[2] = { '/', '\0' };
787    DIR*        dir;
788
789    if (*dirname == '\0')
790    {
791      ++config_path;
792      continue;
793    }
794
795    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
796      printf ("rtl: archive: refresh: %s\n", dirname);
797
798    config_path += strlen (dirname);
799
800    /*
801     * Relative paths do not work in the config. Must be absolute.
802     */
803    if (dirname[0] != '/')
804    {
805      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
806        printf ("rtl: archive: refresh: relative paths ignored: %s\n", dirname);
807      continue;
808    }
809
810    /*
811     * Scan the parent directory of the glob path matching file names.
812     */
813    basename = strrchr (dirname, '/');
814    if (basename == NULL)
815      continue;
816
817    if (basename == dirname)
818      dirname = &root[0];
819
820    *basename = '\0';
821    ++basename;
822
823    dir = opendir (dirname);
824
825    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
826      printf ("rtl: archive: refresh: %s %sfound\n",
827              dirname, dir == NULL ? ": not " : "");
828
829    if (dir != NULL)
830    {
831      while (true)
832      {
833        struct dirent  entry;
834        struct dirent* result = NULL;
835
836        if (readdir_r (dir, &entry, &result) != 0)
837        {
838          if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
839            printf ("rtl: archive: refresh: readdir error\n");
840          break;
841        }
842
843        if (result == NULL)
844          break;
845
846        if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
847          printf ("rtl: archive: refresh: checking: %s (pattern: %s)\n",
848                  entry.d_name, basename);
849
850        if (fnmatch (basename, entry.d_name, 0) == 0)
851        {
852          rtems_rtl_archive* archive;
853          archive = rtems_rtl_archive_get (archives, dirname, entry.d_name);
854          if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
855            printf ("rtl: archive: refresh: %s: %sfound\n",
856                    entry.d_name, archive == NULL ? ": not " : "");
857        }
858      }
859      closedir (dir);
860    }
861
862    --basename;
863    *basename = '/';
864  }
865
866  /*
867   * Remove all archives flagged to be removed.
868   */
869  rtems_rtl_archives_remove (archives);
870
871  /*
872   * Load any new archives. If any are loaded set the archive search flag in
873   * any unresolved external symbols so the archives are searched. The archive
874   * search flag avoids searching for symbols we know are not in the known
875   * archives,
876   */
877  if (rtems_rtl_archives_load (archives))
878    rtems_rtl_unresolved_set_archive_search ();
879
880  return true;
881}
882
883bool
884rtems_rtl_archive_load (rtems_rtl_archives* archives, const char* name)
885{
886  if (archives != NULL)
887  {
888    rtems_rtl_archive* archive;
889    int                loaded = 0;
890
891    archive = rtems_rtl_archive_get (archives, "", name);
892    if (archive == NULL)
893    {
894      rtems_rtl_set_error (ENOENT, "archive not found");
895      return false;
896    }
897
898    archive->flags |= RTEMS_RTL_ARCHIVE_USER_LOAD;
899
900    rtems_rtl_archive_loader (archive, &loaded);
901    if (loaded == 0)
902    {
903      rtems_rtl_archive_del (archive);
904      rtems_rtl_set_error (ENOENT, "archive load falied");
905    }
906
907    return true;
908  }
909  return false;
910}
911
912rtems_rtl_archive_search
913rtems_rtl_archive_obj_load (rtems_rtl_archives* archives,
914                            const char*         symbol,
915                            bool                load)
916{
917  rtems_rtl_obj*       obj;
918  rtems_chain_control* pending;
919  int                  fd;
920  size_t               archive_count;
921
922  rtems_rtl_archive_obj_data search = {
923    .symbol  = symbol,
924    .archive = NULL,
925    .offset  = 0
926  };
927
928  archive_count = rtems_chain_node_count_unprotected (&archives->archives);
929
930  if (archive_count == 0)
931  {
932    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
933      printf ("rtl: archive: load: no archives\n");
934    return rtems_rtl_archive_search_no_config;
935  }
936
937  pending = rtems_rtl_pending_unprotected ();
938  if (pending == NULL)
939  {
940    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
941      printf ("rtl: archive: load: no pending list\n");
942    return rtems_rtl_archive_search_not_found;
943  }
944
945  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
946    printf ("rtl: archive: load: searching %zu archives\n", archive_count);
947
948  rtems_rtl_archive_iterate_archives (archives,
949                                      rtems_rtl_archive_obj_finder,
950                                      &search);
951
952  if (search.archive == NULL)
953  {
954    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
955      printf ("rtl: archive: load: not found: %s\n", symbol);
956    return rtems_rtl_archive_search_not_found;
957  }
958
959  if (!load)
960  {
961    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
962      printf ("rtl: archive: load: found (no load): %s\n", symbol);
963    return rtems_rtl_archive_search_found;
964  }
965
966  obj = rtems_rtl_obj_alloc ();
967  if (obj == NULL)
968  {
969    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
970      printf ("rtl: archive: alloc: no memory: %s\n",
971              search.archive->name);
972    return rtems_rtl_archive_search_error;
973  }
974
975  obj->aname = rtems_rtl_strdup (search.archive->name);
976
977  fd = open (obj->aname, O_RDONLY);
978  if (fd < 0)
979  {
980    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
981      printf ("rtl: archive: load: open error: %s: %s\n",
982              obj->aname, strerror (errno));
983    rtems_rtl_obj_free (obj);
984    return rtems_rtl_archive_search_error;
985  }
986
987  obj->oname = NULL;
988  obj->ooffset = search.offset;
989
990  if (!rtems_rtl_obj_archive_find_obj (fd,
991                                       search.archive->size,
992                                       &obj->oname,
993                                       &obj->ooffset,
994                                       &obj->fsize,
995                                       &search.archive->enames,
996                                       rtems_rtl_archive_set_error))
997  {
998    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
999      printf ("rtl: archive: load: load error: %s:%s\n",
1000              obj->aname, obj->oname);
1001    close (fd);
1002    rtems_rtl_obj_free (obj);
1003    return rtems_rtl_archive_search_error;
1004  }
1005
1006  obj->fname = rtems_rtl_strdup (obj->aname);
1007  obj->ooffset -= RTEMS_RTL_AR_FHDR_SIZE;
1008  obj->fsize = search.archive->size;
1009
1010  close (fd);
1011
1012  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
1013    printf ("rtl: archive: loading: %s:%s@0x%08jx size:%zu\n",
1014            obj->aname, obj->oname, obj->ooffset, obj->fsize);
1015
1016  rtems_chain_append (pending, &obj->link);
1017
1018  if (!rtems_rtl_obj_load (obj))
1019  {
1020    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
1021      printf ("rtl: archive: loading: error: %s:%s@0x%08jx: %s\n",
1022              obj->aname, obj->oname, obj->ooffset,
1023              rtems_rtl_last_error_unprotected ());
1024    rtems_chain_extract (&obj->link);
1025    rtems_rtl_obj_free (obj);
1026    rtems_rtl_obj_caches_flush ();
1027    return rtems_rtl_archive_search_error;
1028  }
1029
1030  rtems_rtl_obj_caches_flush ();
1031
1032  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
1033    printf ("rtl: archive: loading: loaded: %s:%s@0x%08jx\n",
1034            obj->aname, obj->oname, obj->ooffset);
1035
1036  return rtems_rtl_archive_search_loaded;
1037}
1038
1039bool
1040rtems_rtl_obj_archive_find_obj (int                     fd,
1041                                size_t                  fsize,
1042                                const char**            name,
1043                                off_t*                  ooffset,
1044                                size_t*                 osize,
1045                                off_t*                  extended_file_names,
1046                                rtems_rtl_archive_error error)
1047{
1048  uint8_t header[RTEMS_RTL_AR_FHDR_SIZE];
1049  bool    scanning;
1050
1051  if (name == NULL)
1052  {
1053    error (errno, "invalid object name");
1054    *ooffset = 0;
1055    *osize = 0;
1056    return false;
1057  }
1058
1059  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
1060    printf ("rtl: archive: find obj: %s @ 0x%08jx\n", *name, *ooffset);
1061
1062  if (read (fd, &header[0], RTEMS_RTL_AR_IDENT_SIZE) !=  RTEMS_RTL_AR_IDENT_SIZE)
1063  {
1064    error (errno, "reading archive identifer");
1065    *ooffset = 0;
1066    *osize = 0;
1067    return false;
1068  }
1069
1070  if (memcmp (header, RTEMS_RTL_AR_IDENT, RTEMS_RTL_AR_IDENT_SIZE) != 0)
1071  {
1072    error (EINVAL, "invalid archive identifer");
1073    *ooffset = 0;
1074    *osize = 0;
1075    return false;
1076  }
1077
1078  /*
1079   * Seek to the current offset in the archive and if we have a valid archive
1080   * file header present check the file name for a match with the oname field
1081   * of the object descriptor. If the archive header is not valid and it is the
1082   * first pass reset the offset and start the search again in case the offset
1083   * provided is not valid any more.
1084   *
1085   * The archive can have a symbol table at the start. Ignore it. A symbol
1086   * table has the file name '/'.
1087   *
1088   * The archive can also have the GNU extended file name table. This
1089   * complicates the processing. If the object's file name starts with '/' the
1090   * remainder of the file name is an offset into the extended file name
1091   * table. To find the extended file name table we need to scan from start of
1092   * the archive for a file name of '//'. Once found we remeber the table's
1093   * start and can direct seek to file name location. In other words the scan
1094   * only happens once.
1095   *
1096   * If the name had the offset encoded we go straight to that location.
1097   */
1098
1099  if (*ooffset != 0)
1100    scanning = false;
1101  else
1102  {
1103    if (*name == NULL)
1104    {
1105      error (errno, "invalid object name and archive offset");
1106      *ooffset = 0;
1107      *osize = 0;
1108      return false;
1109    }
1110    scanning = true;
1111    *ooffset = RTEMS_RTL_AR_FHDR_BASE;
1112    *osize = 0;
1113  }
1114
1115  while (*ooffset < fsize)
1116  {
1117    /*
1118     * Clean up any existing data.
1119     */
1120    memset (header, 0, sizeof (header));
1121
1122    if (!rtems_rtl_seek_read (fd, *ooffset, RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
1123    {
1124      error (errno, "seek/read archive file header");
1125      *ooffset = 0;
1126      *osize = 0;
1127      return false;
1128    }
1129
1130    if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
1131        (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
1132    {
1133      if (scanning)
1134      {
1135        error (EINVAL, "invalid archive file header");
1136        *ooffset = 0;
1137        *osize = 0;
1138        return false;
1139      }
1140
1141      scanning = true;
1142      *ooffset = RTEMS_RTL_AR_FHDR_BASE;
1143      continue;
1144    }
1145
1146    /*
1147     * The archive header is always aligned to an even address.
1148     */
1149    *osize = (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
1150                                      RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
1151
1152    /*
1153     * Check for the GNU extensions.
1154     */
1155    if (header[0] == '/')
1156    {
1157      off_t extended_off;
1158
1159      switch (header[1])
1160      {
1161        case ' ':
1162          /*
1163           * SVR4/GNU Symbols table. Nothing more to do.
1164           */
1165          *ooffset += RTEMS_RTL_AR_FHDR_SIZE;
1166          return true;
1167        case '/':
1168          /*
1169           * Extended file names table. Remember. If asked to find this file
1170           * return the result.
1171           */
1172          *extended_file_names = *ooffset + RTEMS_RTL_AR_FHDR_SIZE;
1173          if (*name[0] == '/' && *name[1] == '/')
1174          {
1175            *ooffset = *ooffset + RTEMS_RTL_AR_FHDR_SIZE;
1176            return true;
1177          }
1178          break;
1179        case '0':
1180        case '1':
1181        case '2':
1182        case '3':
1183        case '4':
1184        case '5':
1185        case '6':
1186        case '7':
1187        case '8':
1188        case '9':
1189          /*
1190           * Offset into the extended file name table. If we do not have the
1191           * offset to the extended file name table find it.
1192           */
1193          extended_off =
1194            rtems_rtl_scan_decimal (&header[1], RTEMS_RTL_AR_FNAME_SIZE);
1195
1196          if (*extended_file_names == 0)
1197          {
1198            off_t off = RTEMS_RTL_AR_IDENT_SIZE;
1199            while (*extended_file_names == 0)
1200            {
1201              off_t esize;
1202
1203              if (!rtems_rtl_seek_read (fd, off,
1204                                        RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
1205              {
1206                error (errno, "seeking/reading archive ext file name header");
1207                *ooffset = 0;
1208                *osize = 0;
1209                return false;
1210              }
1211
1212              if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
1213                  (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
1214              {
1215                error (errno, "invalid archive file header");
1216                *ooffset = 0;
1217                *osize = 0;
1218                return false;
1219              }
1220
1221              if ((header[0] == '/') && (header[1] == '/'))
1222              {
1223                *extended_file_names = off + RTEMS_RTL_AR_FHDR_SIZE;
1224                break;
1225              }
1226
1227              esize =
1228                (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
1229                                         RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
1230              off += esize + RTEMS_RTL_AR_FHDR_SIZE;
1231            }
1232          }
1233
1234          if (*extended_file_names != 0)
1235          {
1236            /*
1237             * We know the offset in the archive to the extended file. Read the
1238             * name from the table and compare with the name we are after.
1239             */
1240            #define RTEMS_RTL_MAX_FILE_SIZE (256)
1241            char ename[RTEMS_RTL_MAX_FILE_SIZE];
1242
1243            if (!rtems_rtl_seek_read (fd, *extended_file_names + extended_off,
1244                                      RTEMS_RTL_MAX_FILE_SIZE, (uint8_t*) &ename[0]))
1245            {
1246              error (errno, "invalid archive ext file seek/read");
1247              *ooffset = 0;
1248              *osize = 0;
1249              return false;
1250            }
1251
1252            /*
1253             * If there is no name memory the user is asking us to return the
1254             * name in the archive at the offset.
1255             */
1256            if (*name == NULL)
1257              *name = rtems_rtl_archive_dup_name (ename);
1258            if (rtems_rtl_archive_match_name (*name, ename))
1259            {
1260              *ooffset += RTEMS_RTL_AR_FHDR_SIZE;
1261              return true;
1262            }
1263          }
1264          break;
1265        default:
1266          /*
1267           * Ignore the file because we do not know what it it.
1268           */
1269          break;
1270      }
1271    }
1272    else
1273    {
1274      const char* ename = (const char*) &header[RTEMS_RTL_AR_FNAME];
1275      if (*name == NULL)
1276        *name = rtems_rtl_archive_dup_name (ename);
1277      if (rtems_rtl_archive_match_name (*name, ename))
1278      {
1279        *ooffset += RTEMS_RTL_AR_FHDR_SIZE;
1280        return true;
1281      }
1282    }
1283
1284    *ooffset += *osize + RTEMS_RTL_AR_FHDR_SIZE;
1285  }
1286
1287  error (ENOENT, "object file not found");
1288  *ooffset = 0;
1289  *osize = 0;
1290  return false;
1291
1292}
Note: See TracBrowser for help on using the repository browser.