[rtems commit] libdl: Add an archive command

Chris Johns chrisj at rtems.org
Fri Mar 22 03:18:06 UTC 2019


Module:    rtems
Branch:    master
Commit:    dad6fd4333c4b05af08bd78714acefb5a86f1af9
Changeset: http://git.rtems.org/rtems/commit/?id=dad6fd4333c4b05af08bd78714acefb5a86f1af9

Author:    Chris Johns <chrisj at rtems.org>
Date:      Sun Mar 10 07:04:42 2019 +1300

libdl: Add an archive command

- The archive command lists archives, symbols and any duplicate
  symbols.
- Change the RTL shell commands to the rtems_printer to allow
  the output to be captured.

---

 cpukit/include/rtems/rtl/rtl-archive.h |    1 +
 cpukit/include/rtems/rtl/rtl-shell.h   |   28 +
 cpukit/include/rtems/rtl/rtl-trace.h   |    6 +-
 cpukit/libdl/rtl-archive.c             |   49 +-
 cpukit/libdl/rtl-shell.c               | 1052 +++++++++++++++++++++++++++-----
 cpukit/libdl/rtl-trace.c               |   16 +-
 testsuites/libtests/Makefile.am        |   52 ++
 testsuites/libtests/configure.ac       |    1 +
 testsuites/libtests/dl10/dl-load.c     |  141 +++++
 testsuites/libtests/dl10/dl-load.h     |   21 +
 testsuites/libtests/dl10/dl-o1.c       |   61 ++
 testsuites/libtests/dl10/dl-o1.h       |   23 +
 testsuites/libtests/dl10/dl-o2.c       |   39 ++
 testsuites/libtests/dl10/dl-o2.h       |   25 +
 testsuites/libtests/dl10/dl-o3.c       |   40 ++
 testsuites/libtests/dl10/dl-o3.h       |   15 +
 testsuites/libtests/dl10/dl-o4.c       |   40 ++
 testsuites/libtests/dl10/dl-o4.h       |   29 +
 testsuites/libtests/dl10/dl-o5.c       |   36 ++
 testsuites/libtests/dl10/dl-o5.h       |   30 +
 testsuites/libtests/dl10/dl-o6.c       |   18 +
 testsuites/libtests/dl10/dl10.doc      |   22 +
 testsuites/libtests/dl10/dl10.scn      |   41 ++
 testsuites/libtests/dl10/init.c        |  137 +++++
 testsuites/testdata/rtems.tcfg         |    1 +
 25 files changed, 1752 insertions(+), 172 deletions(-)

diff --git a/cpukit/include/rtems/rtl/rtl-archive.h b/cpukit/include/rtems/rtl/rtl-archive.h
index 8aa163e..174bebb 100644
--- a/cpukit/include/rtems/rtl/rtl-archive.h
+++ b/cpukit/include/rtems/rtl/rtl-archive.h
@@ -31,6 +31,7 @@
 
 #include <rtems.h>
 #include <rtems/chain.h>
+#include <rtems/printer.h>
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/cpukit/include/rtems/rtl/rtl-shell.h b/cpukit/include/rtems/rtl/rtl-shell.h
index b0a6e8d..9230b61 100644
--- a/cpukit/include/rtems/rtl/rtl-shell.h
+++ b/cpukit/include/rtems/rtl/rtl-shell.h
@@ -16,6 +16,8 @@
 #if !defined (_RTEMS_RTL_SHELL_H_)
 #define _RTEMS_RTL_SHELL_H_
 
+#include <rtems/print.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
@@ -30,6 +32,32 @@ extern "C" {
  */
 int rtems_rtl_shell_command (int argc, char* argv[]);
 
+/**
+ * List object files.
+ */
+int rtems_rtl_shell_list (const rtems_printer* printer, int argc, char* argv[]);
+
+/**
+ * Symbols.
+ */
+int rtems_rtl_shell_sym (const rtems_printer* printer, int argc, char* argv[]);
+
+/**
+ * Object files.
+ */
+int rtems_rtl_shell_object (const rtems_printer* printer, int argc, char* argv[]);
+
+
+/**
+ * Archive files.
+ */
+int rtems_rtl_shell_archive (const rtems_printer* printer, int argc, char* argv[]);
+
+/**
+ * Call text symbol.
+ */
+int rtems_rtl_shell_call (const rtems_printer* printer, int argc, char* argv[]);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/cpukit/include/rtems/rtl/rtl-trace.h b/cpukit/include/rtems/rtl/rtl-trace.h
index cd39214..06c72c8 100644
--- a/cpukit/include/rtems/rtl/rtl-trace.h
+++ b/cpukit/include/rtems/rtl/rtl-trace.h
@@ -23,6 +23,8 @@ extern "C" {
 #include <stdbool.h>
 #include <stdint.h>
 
+#include <rtems/printer.h>
+
 /**
  * Set to 1 to build trace support in to the RTL code.
  */
@@ -98,7 +100,9 @@ rtems_rtl_trace_mask rtems_rtl_trace_clear_mask (rtems_rtl_trace_mask mask);
  * Add shell trace shell command.
  */
 #if RTEMS_RTL_TRACE
-int rtems_rtl_trace_shell_command (int argc, char *argv[]);
+int rtems_rtl_trace_shell_command (const rtems_printer* printer,
+				   int                  argc,
+				   char*                argv[]);
 #endif
 
 #ifdef __cplusplus
diff --git a/cpukit/libdl/rtl-archive.c b/cpukit/libdl/rtl-archive.c
index 77ad2b0..34e4535 100644
--- a/cpukit/libdl/rtl-archive.c
+++ b/cpukit/libdl/rtl-archive.c
@@ -34,12 +34,6 @@
 #include "rtl-error.h"
 
 /**
- * The archive symbols threshold after which a sorted symbol table is
- * created.
- */
-#define RTEMS_RTL_ARCHIVE_SYMBOLS_SORT (8)
-
-/**
  * Archive headers.
  */
 #define RTEMS_RTL_AR_IDENT      "!<arch>\n"
@@ -223,8 +217,8 @@ rtems_rtl_archive_find (rtems_rtl_archives* archives,
  *
  * The symbol search is performance sensitive. The archive's symbol table being
  * searched is the symbol table in the archive created by ranlib. This table is
- * not sorted so a sorted table of pointered to the symbols is generated after
- * loading if there are enough symbols. For small symbol tables the searc is
+ * not sorted so a sorted table of pointeres to the symbols is generated after
+ * loading if there are enough symbols. For small symbol tables the search is
  * linear. The entire table is held in memory. At the time of writing this code
  * the symbol table for the SPARC architecture's libc is 16k.
  *
@@ -286,7 +280,7 @@ rtems_rtl_archive_obj_finder (rtems_rtl_archive* archive, void* data)
         {
           search->archive = archive;
           search->offset =
-            rtems_rtl_archive_read_32 (symbols->base + (entry * 4));
+            rtems_rtl_archive_read_32 (symbols->base + ((entry + 1) * 4));
           return false;
         }
         symbol += strlen (symbol) + 1;
@@ -647,8 +641,8 @@ rtems_rtl_archive_loader (rtems_rtl_archive* archive, void* data)
                 offset, size);
 
       /*
-       * Reallocation the symbol table memory if it has changed size.
-       * Note, an updated library may have te same symbol table.
+       * Reallocate the symbol table memory if it has changed size.
+       * Note, an updated library may have the same symbol table.
        */
       if (archive->symbols.size != size)
       {
@@ -697,28 +691,25 @@ rtems_rtl_archive_loader (rtems_rtl_archive* archive, void* data)
       archive->symbols.names += (archive->symbols.entries + 1) * 4;
 
       /*
-       * Created a sorted symbol table if over the threshold number of symbols.
+       * Create a sorted symbol table.
        */
-      if (archive->symbols.entries > RTEMS_RTL_ARCHIVE_SYMBOLS_SORT)
+      size = archive->symbols.entries * sizeof (rtems_rtl_archive_symbol);
+      archive->symbols.symbols =
+        rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, size, true);
+      if (archive->symbols.symbols != NULL)
       {
-        size = archive->symbols.entries * sizeof (rtems_rtl_archive_symbol);
-        archive->symbols.symbols =
-          rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, size, true);
-        if (archive->symbols.symbols != NULL)
+        const char* symbol = archive->symbols.names;
+        size_t      e;
+        for (e = 0; e < archive->symbols.entries; ++e)
         {
-          const char* symbol = archive->symbols.names;
-          size_t      e;
-          for (e = 0; e < archive->symbols.entries; ++e)
-          {
-            archive->symbols.symbols[e].entry = e + 1;
-            archive->symbols.symbols[e].label = symbol;
-            symbol += strlen (symbol) + 1;
-          }
-          qsort (archive->symbols.symbols,
-                 archive->symbols.entries,
-                 sizeof (rtems_rtl_archive_symbol),
-                 rtems_rtl_archive_symbol_compare);
+          archive->symbols.symbols[e].entry = e + 1;
+          archive->symbols.symbols[e].label = symbol;
+          symbol += strlen (symbol) + 1;
         }
+        qsort (archive->symbols.symbols,
+               archive->symbols.entries,
+               sizeof (rtems_rtl_archive_symbol),
+               rtems_rtl_archive_symbol_compare);
       }
 
       if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
diff --git a/cpukit/libdl/rtl-shell.c b/cpukit/libdl/rtl-shell.c
index 7458fb5..5641830 100644
--- a/cpukit/libdl/rtl-shell.c
+++ b/cpukit/libdl/rtl-shell.c
@@ -22,10 +22,15 @@
 #include <inttypes.h>
 #include <rtems/inttypes.h>
 
-#include <stdio.h>
+#include <sys/stat.h>
+#include <regex.h>
 #include <string.h>
 
+#include <dlfcn.h>
+
+#include <rtems/printer.h>
 #include <rtems/rtl/rtl.h>
+#include <rtems/rtl/rtl-archive.h>
 #include <rtems/rtl/rtl-shell.h>
 #include <rtems/rtl/rtl-trace.h>
 #include "rtl-chain-iterator.h"
@@ -33,7 +38,7 @@
 /**
  * The type of the shell handlers we have.
  */
-typedef int (*rtems_rtl_shell_handler) (rtems_rtl_data* rtl, int argc, char *argv[]);
+typedef int (*rtems_rtl_shell_handler) (const rtems_printer* printer, int argc, char *argv[]);
 
 /**
  * Table of handlers we parse to invoke the command.
@@ -83,10 +88,20 @@ rtems_rtl_count_symbols (rtems_rtl_data* rtl)
 }
 
 static int
-rtems_rtl_shell_status (rtems_rtl_data* rtl, int argc, char *argv[])
+rtems_rtl_shell_status (const rtems_printer* printer,
+                        int                  argc,
+                        char*                argv[])
 {
   rtems_rtl_obj_summary summary;
   size_t                total_memory;
+  rtems_rtl_data*       rtl;
+
+  rtl = rtems_rtl_lock ();
+  if (rtl == NULL)
+  {
+    rtems_printf (printer, "error: cannot lock the linker\n");
+    return 1;
+  }
 
   summary.count   = 0;
   summary.exec    = 0;
@@ -101,13 +116,15 @@ rtems_rtl_shell_status (rtems_rtl_data* rtl, int argc, char *argv[])
     sizeof (*rtl) + (summary.count * sizeof (rtems_rtl_obj)) +
     summary.exec + summary.symbols;
 
-  printf ("Runtime Linker Status:\n");
-  printf ("        paths: %s\n", rtl->paths);
-  printf ("      objects: %d\n", summary.count);
-  printf (" total memory: %zi\n", total_memory);
-  printf ("  exec memory: %zi\n", summary.exec);
-  printf ("   sym memory: %zi\n", summary.symbols);
-  printf ("      symbols: %d\n", rtems_rtl_count_symbols (rtl));
+  rtems_printf (printer, "Runtime Linker Status:\n");
+  rtems_printf (printer, "        paths: %s\n", rtl->paths);
+  rtems_printf (printer, "      objects: %d\n", summary.count);
+  rtems_printf (printer, " total memory: %zi\n", total_memory);
+  rtems_printf (printer, "  exec memory: %zi\n", summary.exec);
+  rtems_printf (printer, "   sym memory: %zi\n", summary.symbols);
+  rtems_printf (printer, "      symbols: %d\n", rtems_rtl_count_symbols (rtl));
+
+  rtems_rtl_unlock ();
 
   return 0;
 }
@@ -117,68 +134,280 @@ rtems_rtl_shell_status (rtems_rtl_data* rtl, int argc, char *argv[])
  */
 typedef struct
 {
-  rtems_rtl_data* rtl;          /**< The RTL data. */
-  int             indent;       /**< Spaces to indent. */
-  bool            sep1;         /**< Print a separator. */
-  bool            oname;        /**< Print object names. */
-  bool            names;        /**< Print details of all names. */
-  bool            memory_map;   /**< Print the memory map. */
-  bool            symbols;      /**< Print the global symbols. */
-  bool            dependencies; /**< Print any dependencies. */
-  bool            base;         /**< Include the base object file. */
+  const rtems_printer* printer;      /**< The RTEMS printer. */
+  rtems_rtl_data*      rtl;          /**< The RTL data. */
+  int                  indent;       /**< Spaces to indent. */
+  bool                 oname;        /**< Print object names. */
+  bool                 names;        /**< Print details of all names. */
+  bool                 stats;        /**< Print stats. */
+  bool                 memory_map;   /**< Print the memory map. */
+  bool                 symbols;      /**< Print the global symbols. */
+  bool                 dependencies; /**< Print any dependencies. */
+  bool                 base;         /**< Include the base object file. */
+  const char*          re_name;      /**< Name regx to filter on. */
+  const char*          re_symbol;    /**< Symbol regx to filter on. */
 } rtems_rtl_obj_print;
 
 /**
  * Parse an argument.
  */
 static bool
-rtems_rtl_parse_arg (const char* opt, int argc, char *argv[])
+rtems_rtl_parse_opt (const char opt, int argc, char *argv[])
 {
-  int arg;
-  for (arg = 0; arg < argc; ++arg)
-    if (strncmp (opt, argv[arg], 2) == 0)
-      return true;
+  size_t arg;
+  for (arg = 1; arg < argc; ++arg)
+  {
+    if (argv[arg][0] == '-')
+    {
+      size_t len = strlen (argv[arg]);
+      size_t i;
+      for (i = 1; i < len; ++i)
+        if (argv[arg][i] == opt)
+          return true;
+    }
+  }
   return false;
 }
 
+static bool
+rtems_rtl_check_opts (const rtems_printer* printer,
+                      const char*          opts,
+                      int                  argc,
+                      char*                argv[])
+{
+  size_t olen = strlen (opts);
+  size_t arg;
+  for (arg = 1; arg < argc; ++arg)
+  {
+    if (argv[arg][0] == '-')
+    {
+      size_t len = strlen (argv[arg]);
+      size_t i;
+      for (i = 1; i < len; ++i)
+      {
+        bool found = false;
+        size_t       o;
+        for (o = 0; o < olen; ++o)
+        {
+          if (argv[arg][i] == opts[o])
+          {
+            found = true;
+            break;
+          }
+        }
+        if (!found)
+        {
+          rtems_printf (printer, "error: invalid option: %c (%s)\n",
+                        argv[arg][i], argv[arg]);
+          return false;
+        }
+      }
+    }
+  }
+  return true;
+}
+
+static ssize_t
+rtems_rtl_parse_arg_index (const char  opt,
+                           const char* skip_opts,
+                           int         argc,
+                           char*       argv[])
+{
+  ssize_t arg;
+  for (arg = 1; arg < argc; ++arg)
+  {
+    if (argv[arg][0] == '-')
+    {
+      /*
+       * We can check the next char because there has to be a valid char or a
+       * nul.
+       */
+      if (argv[arg][1] != '\0')
+      {
+        size_t len = skip_opts != NULL ? strlen (skip_opts) : 0;
+        size_t i;
+        for (i = 0; i < len; ++i)
+        {
+          if (skip_opts[i] == argv[arg][1])
+          {
+            ++arg;
+            break;
+          }
+        }
+      }
+    }
+    else
+    {
+      if (opt == ' ')
+        return arg;
+    }
+    /*
+     * Is this an option and does it match what we are looking for?
+     */
+    if (argv[arg][0] == '-' && argv[arg][1] == opt && arg < argc)
+      return arg + 1;
+  }
+  return -1;
+}
+
+static const char*
+rtems_rtl_parse_arg (const char  opt,
+                     const char* skip_opts,
+                     int         argc,
+                     char*       argv[])
+{
+  ssize_t arg = rtems_rtl_parse_arg_index (opt, skip_opts, argc, argv);
+  if (arg < 0)
+    return NULL;
+  return argv[arg];
+}
+
 /**
- * See if -b for base is set.
+ * Regx matching.
  */
 static bool
-rtems_rtl_base_arg (int argc, char *argv[])
+rtems_rtl_regx_compile (const rtems_printer* printer,
+                        const char*          label,
+                        regex_t*             rege,
+                        const char*          expression)
 {
-  return rtems_rtl_parse_arg ("-b", argc, argv);
+  int r = regcomp (rege, expression, REG_EXTENDED | REG_NOSUB);
+  if (r != 0)
+  {
+    char rerror[128];
+    regerror (r, rege, rerror, sizeof(rerror));
+    rtems_printf (printer, "error: %s: %s\n", label, rerror);
+    return false;
+  }
+  return true;
+}
+
+static int
+rtems_rtl_regx_match (const rtems_printer* printer,
+                      const char*          label,
+                      regex_t*             rege,
+                      const char*          string)
+{
+  int r = regexec (rege, string, 0, NULL, 0);
+  if (r != 0 && r != REG_NOMATCH)
+  {
+    char rerror[128];
+    regerror (r, rege, rerror, sizeof(rerror));
+    rtems_printf (printer, "error: %s: %s\n", label, rerror);
+    regfree (rege);
+    return -1;
+  }
+  return r == 0 ? 1 : 0;
 }
 
 /**
- * See if -s for base is set.
+ * Print the obj name.
+ */
+static void
+rtems_rtl_print_obj_name (const rtems_rtl_obj_print* print, rtems_rtl_obj* obj)
+{
+  rtems_printf (print->printer, "%-*c", print->indent, ' ');
+  if (rtems_rtl_obj_aname (obj) != NULL)
+    rtems_printf (print->printer, "%s:", rtems_rtl_obj_aname (obj));
+  rtems_printf (print->printer, "%s\n", rtems_rtl_obj_oname (obj));
+}
+
+/**
+ * Print symbols.
  */
 static bool
-rtems_rtl_symbols_arg (int argc, char *argv[])
+rtems_rtl_print_symbols (rtems_rtl_obj_print* print,
+                         rtems_rtl_obj*       obj,
+                         int                  indent,
+                         bool                 show_name)
 {
-  return rtems_rtl_parse_arg ("-s", argc, argv);
+  regex_t rege;
+  int     max_len = 0;
+  int     s;
+
+  if (print->re_symbol != NULL &&
+      !rtems_rtl_regx_compile (print->printer,
+                               "symbol filter",
+                               &rege, print->re_symbol))
+  {
+    return false;
+  }
+
+  for (s = 0; s < obj->global_syms; ++s)
+  {
+    const char* sym = obj->global_table[s].name;
+    int         len;
+
+    if (print->re_symbol != NULL)
+    {
+      int r = rtems_rtl_regx_match (print->printer, "symbol match", &rege, sym);
+      if (r < 0)
+        return false;
+      if (!r)
+        continue;
+    }
+
+    len = strlen (obj->global_table[s].name);
+    if (len > max_len)
+      max_len = len;
+  }
+
+  for (s = 0; s < obj->global_syms; ++s)
+  {
+    const char* sym = obj->global_table[s].name;
+    if (print->re_symbol != NULL)
+    {
+      int r = rtems_rtl_regx_match (print->printer, "symbol match", &rege, sym);
+      if (r < 0)
+        return false;
+      if (r == 0)
+        continue;
+    }
+    if (show_name)
+    {
+      show_name = false;
+      rtems_rtl_print_obj_name (print, obj);
+    }
+    rtems_printf (print->printer, "%-*c%-*s = %p\n", indent + 2, ' ',
+                  max_len, sym, obj->global_table[s].value);
+  }
+
+  regfree (&rege);
+
+  return true;
 }
 
 /**
- * Dependenncies printer.
+ * Dependencies printer.
  */
 typedef struct
 {
-  bool   first;   /**< Is this the first line printed. */
-  size_t indent;  /**< The indent. */
+  const rtems_rtl_obj_print* print;     /**< The print data. */
+  bool                       first;     /**< Is this the first line printed. */
+  bool                       show_name; /**< Show the object name. */
+  size_t                     indent;    /**< The indent. */
 } rtems_rtl_dep_data;
 
 static bool
-rtems_rtl_dependencies (rtems_rtl_obj* obj,
-                        rtems_rtl_obj* dependent,
-                        void*          data)
+rtems_rtl_dependencies (rtems_rtl_obj* obj, rtems_rtl_obj* dependent, void* data)
 {
   rtems_rtl_dep_data* dd = (rtems_rtl_dep_data*) data;
-  if (!dd->first)
-    printf ("\n%-*c: ", (int) dd->indent, ' ');
-  else
+  if (dd->first)
+  {
     dd->first = false;
-  printf ("%s", dependent->oname);
+    if (dd->show_name)
+    {
+      dd->show_name = false;
+      rtems_rtl_print_obj_name (dd->print, obj);
+    }
+    rtems_printf (dd->print->printer, "%-*cdependencies  : ", dd->indent, ' ');
+    dd->indent += strlen ("dependencies :");
+  }
+  else
+  {
+    rtems_printf (dd->print->printer, "\n%-*c: ", (int) dd->indent, ' ');
+  }
+  rtems_printf (dd->print->printer, "%s", dependent->oname);
   return false;
 }
 
@@ -189,6 +418,8 @@ static bool
 rtems_rtl_obj_printer (rtems_rtl_obj_print* print, rtems_rtl_obj* obj)
 {
   char flags_str[33];
+  int  indent = print->indent + 1;
+  bool show_name = true;
 
   /*
    * Skip the base module unless asked to show it.
@@ -196,72 +427,114 @@ rtems_rtl_obj_printer (rtems_rtl_obj_print* print, rtems_rtl_obj* obj)
   if (!print->base && (obj == print->rtl->base))
       return true;
 
-  if (print->sep1)
+  if (print->re_name != NULL)
   {
-    printf ("%-*c--------------\n", print->indent, ' ');
+    regex_t rege;
+    int     r = 0;
+
+    if (!rtems_rtl_regx_compile (print->printer,
+                                 "name filter",
+                                 &rege, print->re_name))
+    {
+      return false;
+    }
+
+    if (rtems_rtl_obj_aname (obj) != NULL)
+    {
+      r = rtems_rtl_regx_match (print->printer,
+                                "aname match",
+                                &rege,
+                                rtems_rtl_obj_aname (obj));
+      if (r < 0)
+        return false;
+    }
+
+    if (r == 0)
+    {
+      r = rtems_rtl_regx_match (print->printer,
+                                "oname match",
+                                &rege,
+                                rtems_rtl_obj_oname (obj));
+      if (r < 0)
+        return false;
+    }
+
+    regfree (&rege);
+
+    if (r == 0)
+      return true;
   }
-  if (print->oname)
+
+  if (print->names || print->memory_map || print->stats ||
+      (!print->names && !print->memory_map && !print->stats &&
+       !print->symbols && !print->dependencies))
   {
-    printf ("%-*cobject name   : %s\n",
-            print->indent, ' ', rtems_rtl_obj_oname (obj));
+    show_name = false;
+    rtems_rtl_print_obj_name (print, obj);
   }
+
   if (print->names)
   {
-    printf ("%-*cfile name     : %s\n",
-            print->indent, ' ', rtems_rtl_obj_fname (obj));
-    printf ("%-*carchive name  : %s\n",
-            print->indent, ' ', rtems_rtl_obj_aname (obj));
+    rtems_printf (print->printer,
+                  "%-*cfile name     : %s\n",
+                  indent, ' ', rtems_rtl_obj_fname (obj));
+    rtems_printf (print->printer,
+                  "%-*carchive name  : %s\n",
+                  indent, ' ', rtems_rtl_obj_aname (obj));
     strcpy (flags_str, "--");
     if (obj->flags & RTEMS_RTL_OBJ_LOCKED)
       flags_str[0] = 'L';
     if (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED)
       flags_str[1] = 'U';
-    printf ("%-*cflags         : %s\n", print->indent, ' ', flags_str);
-    printf ("%-*cfile offset   : %" PRIdoff_t "\n", print->indent, ' ', obj->ooffset);
-    printf ("%-*cfile size     : %zi\n", print->indent, ' ', obj->fsize);
+    rtems_printf (print->printer,
+                  "%-*cflags         : %s\n", indent, ' ', flags_str);
+    rtems_printf (print->printer,
+                  "%-*cfile offset   : %" PRIdoff_t "\n", indent, ' ', obj->ooffset);
+    rtems_printf (print->printer,
+                  "%-*cfile size     : %zi\n", indent, ' ', obj->fsize);
   }
   if (print->memory_map)
   {
-    printf ("%-*cexec size     : %zi\n", print->indent, ' ', obj->exec_size);
-    printf ("%-*ctext base     : %p (%zi)\n", print->indent, ' ',
-            obj->text_base, obj->text_size);
-    printf ("%-*cconst base    : %p (%zi)\n", print->indent, ' ',
-            obj->const_base, obj->const_size);
-    printf ("%-*cdata base     : %p (%zi)\n", print->indent, ' ',
-            obj->data_base, obj->data_size);
-    printf ("%-*cbss base      : %p (%zi)\n", print->indent, ' ',
-            obj->bss_base, obj->bss_size);
-  }
-  printf ("%-*cunresolved    : %zu\n", print->indent, ' ', obj->unresolved);
-  printf ("%-*cusers         : %zu\n", print->indent, ' ', obj->users);
-  printf ("%-*creferences    : %zu\n", print->indent, ' ', obj->refs);
-  printf ("%-*csymbols       : %zi\n", print->indent, ' ', obj->global_syms);
-  printf ("%-*csymbol memory : %zi\n", print->indent, ' ', obj->global_size);
+    rtems_printf (print->printer,
+                  "%-*cexec size     : %zi\n", indent, ' ', obj->exec_size);
+    rtems_printf (print->printer,
+                  "%-*ctext base     : %p (%zi)\n", indent, ' ',
+                  obj->text_base, obj->text_size);
+    rtems_printf (print->printer,
+                  "%-*cconst base    : %p (%zi)\n", indent, ' ',
+                  obj->const_base, obj->const_size);
+    rtems_printf (print->printer,
+                  "%-*cdata base     : %p (%zi)\n", indent, ' ',
+                  obj->data_base, obj->data_size);
+    rtems_printf (print->printer,
+                  "%-*cbss base      : %p (%zi)\n", indent, ' ',
+                  obj->bss_base, obj->bss_size);
+  }
+  if (print->stats)
+  {
+    rtems_printf (print->printer, "%-*cunresolved    : %zu\n", indent, ' ', obj->unresolved);
+    rtems_printf (print->printer, "%-*cusers         : %zu\n", indent, ' ', obj->users);
+    rtems_printf (print->printer, "%-*creferences    : %zu\n", indent, ' ', obj->refs);
+    rtems_printf (print->printer, "%-*csymbols       : %zi\n", indent, ' ', obj->global_syms);
+    rtems_printf (print->printer, "%-*csymbol memory : %zi\n", indent, ' ', obj->global_size);
+  }
   if (print->symbols)
   {
-    int max_len = 0;
-    int s;
-    for (s = 0; s < obj->global_syms; ++s)
-    {
-      int len = strlen (obj->global_table[s].name);
-      if (len > max_len)
-        max_len = len;
-    }
-    for (s = 0; s < obj->global_syms; ++s)
-      printf ("%-*c%-*s = %p\n", print->indent + 2, ' ',
-              max_len, obj->global_table[s].name, obj->global_table[s].value);
+    if (!rtems_rtl_print_symbols (print, obj, indent, show_name))
+      return false;
   }
   if (print->dependencies)
   {
     rtems_rtl_dep_data dd = {
+      .print = print,
       .first = true,
-      .indent = strlen ("dependencies :") + print->indent
+      .show_name = show_name,
+      .indent = indent
     };
-    printf ("%-*cdependencies  : ", print->indent, ' ');
     rtems_rtl_obj_iterate_dependents (obj, rtems_rtl_dependencies, &dd);
-    printf ("\n");
+    if (!dd.first)
+      rtems_printf (print->printer, "\n");
   }
-  printf ("\n");
   return true;
 }
 
@@ -274,7 +547,8 @@ rtems_rtl_unresolved_printer (rtems_rtl_unresolv_rec* rec,
 {
   rtems_rtl_obj_print* print = (rtems_rtl_obj_print*) data;
   if (rec->type == rtems_rtl_unresolved_symbol)
-    printf ("%-*c%s\n", print->indent + 2, ' ', rec->rec.name.name);
+    rtems_printf (print->printer,
+                  "%-*c%s\n", print->indent + 2, ' ', rec->rec.name.name);
   return false;
 }
 
@@ -289,61 +563,568 @@ rtems_rtl_obj_print_iterator (rtems_chain_node* node, void* data)
   return rtems_rtl_obj_printer (print, obj);
 }
 
-static int
-rtems_rtl_shell_list (rtems_rtl_data* rtl, int argc, char *argv[])
+int
+rtems_rtl_shell_list (const rtems_printer* printer, int argc, char* argv[])
 {
-  rtems_rtl_obj_print print;
-  print.rtl = rtl;
+  rtems_rtl_obj_print print = { 0 };
+  if (!rtems_rtl_check_opts (printer, "nlmsdb", argc, argv))
+    return 1;
+  print.printer = printer;
   print.indent = 1;
-  print.sep1 = true;
   print.oname = true;
-  print.names = true;
-  print.memory_map = true;
-  print.symbols = rtems_rtl_symbols_arg (argc, argv);
-  print.dependencies = true;
-  print.base = false;
-  rtems_rtl_chain_iterate (&rtl->objects,
+  print.names = rtems_rtl_parse_opt ('n', argc, argv);
+  print.stats = rtems_rtl_parse_opt ('l', argc, argv);;
+  print.memory_map = rtems_rtl_parse_opt ('m', argc, argv);;
+  print.symbols = rtems_rtl_parse_opt ('s', argc, argv);
+  print.dependencies = rtems_rtl_parse_opt ('d', argc, argv);;
+  print.base = rtems_rtl_parse_opt ('b', argc, argv);;
+  print.re_name = rtems_rtl_parse_arg (' ', NULL, argc, argv);
+  print.re_symbol = NULL;
+  print.rtl = rtems_rtl_lock ();
+  if (print.rtl == NULL)
+  {
+    rtems_printf (print.printer, "error: cannot lock the linker\n");
+    return 1;
+  }
+  rtems_rtl_chain_iterate (&print.rtl->objects,
                            rtems_rtl_obj_print_iterator,
                            &print);
+  rtems_rtl_unlock ();
   return 0;
 }
 
-static int
-rtems_rtl_shell_sym (rtems_rtl_data* rtl, int argc, char *argv[])
+int
+rtems_rtl_shell_sym (const rtems_printer* printer, int argc, char* argv[])
 {
-  rtems_rtl_obj_print print;
-  print.rtl = rtl;
+  rtems_rtl_obj_print print = { 0 };
+  if (!rtems_rtl_check_opts (printer, "buo", argc, argv))
+    return 1;
+  print.printer = printer;
   print.indent = 1;
-  print.sep1 = true;
   print.oname = true;
   print.names = false;
+  print.stats = false;
   print.memory_map = false;
-  print.symbols = true;
+  print.symbols = !rtems_rtl_parse_opt ('u', argc, argv);;
   print.dependencies = false;
-  print.base = rtems_rtl_base_arg (argc, argv);
-  rtems_rtl_chain_iterate (&rtl->objects,
-                           rtems_rtl_obj_print_iterator,
-                           &print);
-  printf ("Unresolved:\n");
-  rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_printer, &print);
+  print.base = rtems_rtl_parse_opt ('b', argc, argv);
+  print.re_name = rtems_rtl_parse_arg ('o', NULL, argc, argv);;
+  print.re_symbol = rtems_rtl_parse_arg (' ', "ou", argc, argv);
+  print.rtl = rtems_rtl_lock ();
+  if (print.rtl == NULL)
+  {
+    rtems_printf (print.printer, "error: cannot lock the linker\n");
+    return 1;
+  }
+  if (print.symbols)
+  {
+    rtems_rtl_chain_iterate (&print.rtl->objects,
+                             rtems_rtl_obj_print_iterator,
+                             &print);
+  }
+  if (rtems_rtl_parse_opt ('u', argc, argv))
+  {
+    rtems_printf (printer, "Unresolved:\n");
+    rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_printer, &print);
+  }
+  rtems_rtl_unlock ();
   return 0;
 }
 
-static int
-rtems_rtl_shell_object (rtems_rtl_data* rtl, int argc, char *argv[])
+int
+rtems_rtl_shell_object (const rtems_printer* printer, int argc, char* argv[])
 {
+  size_t arg;
+
+  --argc;
+  ++argv;
+
+  for (arg = 0; arg < argc; ++arg)
+  {
+    if (argv[arg][0] == '-')
+    {
+      switch (argv[arg][1])
+      {
+        case 'h':
+        case '?':
+          rtems_printf (printer, "obj commands:\n");
+          rtems_printf (printer, " load <file>\n");
+          rtems_printf (printer, " unload <file>\n");
+          break;
+        default:
+          rtems_printf (printer, "error: invalid option: %s\n", argv[arg]);
+          return 1;
+      }
+    }
+    else
+    {
+      break;
+    }
+  }
+
+  if (arg >= argc)
+  {
+    rtems_printf (printer, "error: no obj command\n");
+    return 1;
+  }
+
+  if (strcmp (argv[arg], "load") == 0)
+  {
+    void* handle;
+    int   unresolved;
+
+    ++arg;
+    if (arg >= argc)
+    {
+      rtems_printf (printer, "error: no object file to load\n");
+      return 1;
+    }
+
+    handle = dlopen (argv[arg], RTLD_NOW | RTLD_GLOBAL);
+    if (handle == NULL)
+    {
+      rtems_printf (printer, "error: load: %s: %s\n", argv[arg], dlerror ());
+      return 1;
+    }
+
+    if (dlinfo (RTLD_SELF, RTLD_DI_UNRESOLVED, &unresolved) < 0)
+    {
+      rtems_printf (printer, "error: %s: %s\n", argv[arg], dlerror ());
+      return 1;
+    }
+
+    if (unresolved != 0)
+    {
+      rtems_printf (printer, "warning: unresolved symbols present\n");
+      return 1;
+    }
+  }
+  else if (strcmp (argv[arg], "unload") == 0)
+  {
+    rtems_rtl_data* rtl;
+    rtems_rtl_obj*  obj;
+
+    ++arg;
+    if (arg >= argc)
+    {
+      rtems_printf (printer, "error: no object file to load\n");
+      return 1;
+    }
+
+    rtl = rtems_rtl_lock ();
+    if (rtl == NULL)
+    {
+      rtems_printf (printer, "error: cannot lock RTL\n");
+      return 1;
+    }
+
+    obj = rtems_rtl_find_obj (argv[arg]);
+    if (obj == NULL)
+    {
+      rtems_rtl_unlock ();
+      rtems_printf (printer, "error: unload: %s: %s\n", argv[arg], dlerror ());
+      return 1;
+    }
+
+    if (!rtems_rtl_unload (obj))
+    {
+      rtems_rtl_unlock ();
+      rtems_printf (printer, "error: unload: %s: %s\n", argv[arg], dlerror ());
+      return 1;
+    }
+
+    rtems_rtl_unlock ();
+  }
+  else
+  {
+    rtems_printf (printer, "error: unknown obj command: %s\n", argv[arg]);
+    return 1;
+  }
+
+  return 0;
+}
+
+int
+rtems_rtl_shell_archive (const rtems_printer* printer, int argc, char* argv[])
+{
+  rtems_rtl_data*   rtl;
+  rtems_chain_node* node;
+  const char*       re_name;
+  bool              details;
+  bool              symbols;
+  bool              duplicates;
+  regex_t           rege;
+
+  if (!rtems_rtl_check_opts (printer, "dsl", argc, argv))
+    return 1;
+
+  details = rtems_rtl_parse_opt ('l', argc, argv);
+  symbols = rtems_rtl_parse_opt ('s', argc, argv);
+  duplicates = rtems_rtl_parse_opt ('d', argc, argv);
+
+  re_name = rtems_rtl_parse_arg (' ', NULL, argc, argv);
+
+  if (re_name != NULL)
+  {
+    if (!rtems_rtl_regx_compile (printer,
+                                 "name filter",
+                                 &rege,
+                                 re_name))
+    {
+      return false;
+    }
+  }
+
+  rtl = rtems_rtl_lock ();
+  if (rtl == NULL)
+  {
+    rtems_printf (printer, "error: cannot lock the linker\n");
+    return 1;
+  }
+
+  node = rtems_chain_first (&rtl->archives.archives);
+
+  while (!rtems_chain_is_tail (&rtl->archives.archives, node))
+  {
+    #define SYM_DUPLICATE (1 << ((8 * sizeof (size_t)) - 1))
+
+    rtems_rtl_archive* archive = (rtems_rtl_archive*) node;
+
+    if (re_name != NULL)
+    {
+      int r = rtems_rtl_regx_match (printer,
+                                    "name match",
+                                    &rege,
+                                    archive->name);
+      if (r < 0)
+      {
+        rtems_rtl_unlock ();
+        return false;
+      }
+
+      if (r == 0)
+      {
+        node = rtems_chain_next (node);
+        continue;
+      }
+    }
+
+    rtems_printf (printer, "%s%c\n",
+                  archive->name,
+                  details | symbols | duplicates ? ':' : ' ');
+
+    if (details)
+    {
+      rtems_printf (printer, "  size    : %zu\n", archive->size);
+      rtems_printf (printer, "  symbols : %zu\n", archive->symbols.entries);
+      rtems_printf (printer, "  refs    : %zu\n", archive->refs);
+      rtems_printf (printer, "  flags   : %" PRIx32 "\n", archive->flags);
+    }
+
+    if (symbols)
+    {
+      const char* symbol = archive->symbols.names;
+      int         indent = 0;
+      size_t      s;
+
+      rtems_printf (printer, "  symbols :");
+
+      for (s = 0; s < archive->symbols.entries; ++s)
+      {
+        if (archive->symbols.symbols != NULL)
+          symbol = archive->symbols.symbols[s].label;
+
+        rtems_printf (printer, "%-*c%s\n", indent, ' ', symbol);
+        indent = 12;
+
+        if (archive->symbols.symbols == NULL)
+          symbol += strlen (symbol) + 1;
+      }
+
+      if (indent == 0)
+        rtems_printf (printer, "\n");
+    }
+
+    if (duplicates)
+    {
+      rtems_chain_node* match_node;
+      int               indent = 0;
+      bool              show_dups = true;
+
+      match_node = rtems_chain_first (&rtl->archives.archives);
+
+      while (!rtems_chain_is_tail (&rtl->archives.archives, match_node))
+      {
+        rtems_rtl_archive* match_archive = (rtems_rtl_archive*) match_node;
+        const char*        symbol = archive->symbols.names;
+        size_t             s;
+
+        for (s = 0; s < archive->symbols.entries; ++s)
+        {
+          if (archive->symbols.symbols == NULL ||
+              (archive->symbols.symbols[s].entry & SYM_DUPLICATE) == 0)
+          {
+            const char* match_symbol = match_archive->symbols.names;
+            size_t      ms;
+
+            if (archive->symbols.symbols != NULL)
+              symbol = archive->symbols.symbols[s].label;
+
+            for (ms = 0; ms < match_archive->symbols.entries; ++ms)
+            {
+              if (match_archive->symbols.symbols != NULL)
+                match_symbol = match_archive->symbols.symbols[ms].label;
+
+              if (symbol != match_symbol && strcmp (symbol, match_symbol) == 0)
+              {
+                if (show_dups)
+                {
+                  show_dups = false;
+                  rtems_printf (printer, "  dups    :");
+                }
+                rtems_printf (printer, "%-*c%s (%s)\n",
+                              indent, ' ', symbol, archive->name);
+                indent = 12;
+
+                if (match_archive->symbols.symbols != NULL)
+                  match_archive->symbols.symbols[ms].entry |= SYM_DUPLICATE;
+              }
+
+              if (match_archive->symbols.symbols == NULL)
+                match_symbol += strlen (match_symbol) + 1;
+            }
+          }
+
+          if (archive->symbols.symbols == NULL)
+            symbol += strlen (symbol) + 1;
+        }
+
+        match_node = rtems_chain_next (match_node);
+      }
+
+      if (indent == 0)
+        rtems_printf (printer, "\n");
+    }
+
+    node = rtems_chain_next (node);
+  }
+
+  regfree (&rege);
+
+  node = rtems_chain_first (&rtl->archives.archives);
+
+  while (!rtems_chain_is_tail (&rtl->archives.archives, node))
+  {
+    rtems_rtl_archive* archive = (rtems_rtl_archive*) node;
+    if (archive->symbols.symbols != NULL)
+    {
+      size_t s;
+      for (s = 0; s < archive->symbols.entries; ++s)
+        archive->symbols.symbols[s].entry &= ~SYM_DUPLICATE;
+    }
+    node = rtems_chain_next (node);
+  }
+
+  rtems_rtl_unlock ();
+
+  return 0;
+}
+
+int
+rtems_rtl_shell_call (const rtems_printer* printer, int argc, char* argv[])
+{
+  #define CALL_ARG_COUNT (4)
+
+  typedef void (*csig_none)(void);
+  typedef void (*csig_argv)(int argc, const char* argv[]);
+  typedef void (*csig_s)(const char* str);
+  typedef void (*csig_u)(unsigned int i1, unsigned int i2, unsigned int i3, unsigned int i4);
+  typedef void (*csig_i)(int i1, int i2, int i3, int i4);
+
+  union {
+    char         s[64 + 1];
+    unsigned int u[CALL_ARG_COUNT];
+    int          i[CALL_ARG_COUNT];
+  } values = { 0 };
+  bool               keep_locked = false;
+  bool               args_s = false;
+  bool               args_i = false;
+  bool               args_u = false;
+  ssize_t            label;
+  rtems_rtl_data*    rtl;
+  rtems_rtl_obj_sym* sym;
+  rtems_rtl_obj*     obj;
+
+
+  if (!rtems_rtl_check_opts (printer, "lsui", argc, argv))
+    return 1;
+
+  keep_locked = rtems_rtl_parse_opt ('l', argc, argv);
+  args_s = rtems_rtl_parse_opt ('s', argc, argv);
+  args_u = rtems_rtl_parse_opt ('u', argc, argv);
+  args_i = rtems_rtl_parse_opt ('i', argc, argv);
+
+  if (args_s || args_u || args_i)
+  {
+    int c = 0;
+    c += args_s ? 1 : 0;
+    c += args_u ? 1 : 0;
+    c += args_i ? 1 : 0;
+    if (c > 1)
+    {
+      rtems_printf (printer,
+                    "error: too many options, only one -sul at a time\n");
+      return 1;
+    }
+  }
+
+  label = rtems_rtl_parse_arg_index (' ', NULL, argc, argv);
+  if (label < 0)
+  {
+    rtems_printf (printer, "error: no symbol found on command line\n");
+    return 1;
+  }
+
+  if ((label + 1) < argc)
+  {
+    if (args_s)
+    {
+      size_t arg;
+      for (arg = label + 1; arg < argc; ++arg)
+      {
+        size_t o = strlen (values.s);
+        if (strlen (argv[arg]) + 1 >= (sizeof (values.s) - o))
+        {
+          rtems_printf (printer, "error: string args too big\n");
+          return 1;
+        }
+        if (o > 0)
+          values.s[o++] = ' ';
+        strcat (values.s, argv[arg]);
+      }
+    }
+    else if (args_u || args_i)
+    {
+      size_t arg;
+      size_t i;
+      if (argc > (label + 1 + CALL_ARG_COUNT))
+      {
+        rtems_printf (printer, "error: too many args\n");
+        return 1;
+      }
+      for (i = 0, arg = label + 1; arg < argc; ++arg)
+      {
+        if (args_u)
+          values.u[i] = strtoul (argv[arg], 0, 0);
+        else
+          values.i[i] = strtol (argv[arg], 0, 0);
+        ++i;
+      }
+    }
+  }
+
+  rtl = rtems_rtl_lock ();
+  if (rtl == NULL)
+  {
+    rtems_printf (printer, "error: cannot lock the linker\n");
+    return 1;
+  }
+
+  sym = rtems_rtl_symbol_global_find (argv[label]);
+  if (sym == NULL)
+  {
+    rtems_rtl_unlock ();
+    rtems_printf (printer, "error: symbol not found: %s\n", argv[label]);
+    return 1;
+  }
+
+  obj = rtems_rtl_find_obj_with_symbol (sym);
+  if (obj == NULL)
+  {
+    rtems_rtl_unlock ();
+    rtems_printf (printer, "error: symbol obj not found: %s\n", argv[label]);
+    return 1;
+  }
+
+  if (!rtems_rtl_obj_text_inside (obj, (const void*) sym->value))
+  {
+    rtems_rtl_unlock ();
+    rtems_printf (printer, "error: symbol not in obj text: %s\n", argv[label]);
+    return 1;
+  }
+
+  /*
+   * Lock the object file while it is being called.
+   */
+  rtems_rtl_obj_inc_reference (obj);
+
+  rtems_rtl_unlock ();
+
+  if (args_s)
+  {
+    csig_s call = (csig_s) sym->value;
+    call (values.s);
+  }
+  else if (args_u)
+  {
+    csig_u call = (csig_u) sym->value;
+    call (values.u[0], values.u[1], values.u[2], values.u[3]);
+  }
+  else if (args_i)
+  {
+    csig_i call = (csig_i) sym->value;
+    call (values.i[0], values.i[1], values.i[2], values.i[3]);
+  }
+  else
+  {
+    int cargc = argc - (label + 1);
+    if (cargc == 0)
+    {
+      csig_none call = (csig_none) sym->value;
+      call ();
+    }
+    else
+    {
+      csig_argv   call = (csig_argv) sym->value;
+      const char* cargv = argv[label + 1];
+      call (cargc, &cargv);
+    }
+  }
+
+  if (!keep_locked)
+  {
+    rtl = rtems_rtl_lock ();
+    if (rtl == NULL)
+    {
+      rtems_printf (printer, "error: cannot lock the linker\n");
+      return 1;
+    }
+
+    obj = rtems_rtl_find_obj_with_symbol (sym);
+    if (obj == NULL)
+    {
+      rtems_rtl_unlock ();
+      rtems_printf (printer, "error: symbol obj not found: %s\n", argv[label]);
+      return 1;
+    }
+
+    rtems_rtl_obj_dec_reference (obj);
+
+    rtems_rtl_unlock ();
+  }
+
   return 0;
 }
 
 static void
-rtems_rtl_shell_usage (const char* arg)
+rtems_rtl_shell_usage (const rtems_printer* printer, const char* arg)
 {
-  printf ("%s: Runtime Linker\n", arg);
-  printf ("  %s [-hl] <command>\n", arg);
-  printf ("   where:\n");
-  printf ("     command: A n RTL command. See -l for a list plus help.\n");
-  printf ("     -h:      This help\n");
-  printf ("     -l:      The command list.\n");
+  rtems_printf (printer, "%s: Runtime Linker\n", arg);
+  rtems_printf (printer, "  %s [-hl] <command>\n", arg);
+  rtems_printf (printer, "   where:\n");
+  rtems_printf (printer, "     command: A n RTL command. See -l for a list plus help.\n");
+  rtems_printf (printer, "     -h:      This help\n");
+  rtems_printf (printer, "     -l:      The command list.\n");
 }
 
 int
@@ -358,11 +1139,20 @@ rtems_rtl_shell_command (int argc, char* argv[])
     { "sym", rtems_rtl_shell_sym,
       "\tDisplay the symbols, sym [<name>], sym -o <obj> [<name>]" },
     { "obj", rtems_rtl_shell_object,
-      "\tDisplay the object details, obj <name>" }
+      "\tDisplay the object details, obj <name>" },
+    { "call", rtems_rtl_shell_call,
+      "\tCall a symbol" },
+    { "ar", rtems_rtl_shell_archive,
+      "\tDisplay the archive details, ar [-ls] <name>" },
+    { "trace", rtems_rtl_trace_shell_command,
+      "\tControl the RTL trace flags, trace [-h]" }
   };
 
-  int arg;
-  int t;
+  rtems_printer printer;
+  int           arg;
+  int           t;
+
+  rtems_print_printer_printf (&printer);
 
   for (arg = 1; arg < argc; arg++)
   {
@@ -372,23 +1162,24 @@ rtems_rtl_shell_command (int argc, char* argv[])
     switch (argv[arg][1])
     {
       case 'h':
-        rtems_rtl_shell_usage (argv[0]);
+        rtems_rtl_shell_usage (&printer, argv[0]);
         return 0;
       case 'l':
-        printf ("%s: commands are:\n", argv[0]);
+        rtems_printf (&printer, "%s: commands are:\n", argv[0]);
         for (t = 0;
              t < (sizeof (table) / sizeof (const rtems_rtl_shell_cmd));
              ++t)
-          printf ("  %s\t%s\n", table[t].name, table[t].help);
+          rtems_printf (&printer, "  %s\t%s\n", table[t].name, table[t].help);
         return 0;
       default:
-        printf ("error: unknown option: %s\n", argv[arg]);
+        rtems_printf (&printer, "error: unknown option: %s\n", argv[arg]);
         return 1;
     }
   }
 
   if ((argc - arg) < 1)
-    printf ("error: you need to provide a command, try %s -h\n", argv[0]);
+    rtems_printf (&printer, "error: you need to provide a command, try %s -h\n",
+                  argv[0]);
   else
   {
     for (t = 0;
@@ -396,20 +1187,9 @@ rtems_rtl_shell_command (int argc, char* argv[])
          ++t)
     {
       if (strncmp (argv[arg], table[t].name, strlen (argv[arg])) == 0)
-      {
-        rtems_rtl_data* rtl = rtems_rtl_lock ();
-        int             r;
-        if (!rtl)
-        {
-          printf ("error: cannot lock the linker\n");
-          return 1;
-        }
-        r = table[t].handler (rtl, argc - 1, argv + 1);
-        rtems_rtl_unlock ();
-        return r;
-      }
+        return table[t].handler (&printer, argc - 1, argv + 1);
     }
-    printf ("error: command not found: %s (try -h)\n", argv[arg]);
+    rtems_printf (&printer, "error: command not found: %s (try -h)\n", argv[arg]);
   }
 
   return 1;
diff --git a/cpukit/libdl/rtl-trace.c b/cpukit/libdl/rtl-trace.c
index e09ec06..2793baa 100644
--- a/cpukit/libdl/rtl-trace.c
+++ b/cpukit/libdl/rtl-trace.c
@@ -54,7 +54,9 @@ rtems_rtl_trace_clear_mask (rtems_rtl_trace_mask mask)
 }
 
 int
-rtems_rtl_trace_shell_command (int argc, char *argv[])
+rtems_rtl_trace_shell_command (const rtems_printer* printer,
+                               int                  argc,
+                               char*                argv[])
 {
   const char* table[] =
   {
@@ -71,7 +73,9 @@ rtems_rtl_trace_shell_command (int argc, char *argv[])
     "unresolved",
     "cache",
     "archives",
-    "dependency"
+    "archive-syms",
+    "dependency",
+    "bit-alloc"
   };
 
   rtems_rtl_trace_mask set_value = 0;
@@ -87,15 +91,15 @@ rtems_rtl_trace_shell_command (int argc, char *argv[])
       switch (argv[arg][1])
       {
         case 'h':
-          printf ("usage: %s [-hl] [set/clear] [flags]\n", argv[0]);
+          rtems_printf (printer, "usage: %s [-hl] [set/clear] [flags]\n", argv[0]);
           return 0;
         case 'l':
-          printf ("%s: valid flags to set or clear are:\n", argv[0]);
+          rtems_printf (printer, "%s: valid flags to set or clear are:\n", argv[0]);
           for (t = 0; t < (sizeof (table) / sizeof (const char*)); t++)
-            printf ("  %s\n", table[t]);
+            rtems_printf (printer, "  %s\n", table[t]);
           return 0;
         default:
-          printf ("error: unknown option\n");
+          rtems_printf (printer, "error: unknown option\n");
           return 1;
       }
     }
diff --git a/testsuites/libtests/Makefile.am b/testsuites/libtests/Makefile.am
index 789380c..fe6f7d8 100644
--- a/testsuites/libtests/Makefile.am
+++ b/testsuites/libtests/Makefile.am
@@ -649,6 +649,58 @@ CLEANFILES += dl09.pre dl09-sym.o dl09-o1.o dl09-o2.o dl09-o3.o dl09-o4.o \
 endif
 endif
 
+if DLTESTS
+if TEST_dl10
+lib_tests += dl10
+lib_screens += dl10/dl10.scn
+lib_docs += dl10/dl10.doc
+dl10_SOURCES = dl10/init.c dl10/dl-load.c dl10-tar.c dl10-tar.h
+dl10_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_dl10) $(support_includes)
+dl10/init.c: dl10-tar.o
+dl10.pre: $(dl10_OBJECTS) $(dl10_DEPENDENCIES)
+	@rm -f dl10.pre dl10-syms.o
+	$(AM_V_CCLD)$(LINK.c) $(CPU_CFLAGS) $(AM_CFLAGS) $(AM_LDFLAGS) -o $@ $+
+dl10-o1.o: dl10/dl-o1.c Makefile
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+dl10-o2.o: dl10/dl-o2.c Makefile
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+dl10-o3.o: dl10/dl-o3.c Makefile
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+dl10-o4.o: dl10/dl-o4.c Makefile
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+dl10-o5.o: dl10/dl-o5.c Makefile
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+dl10-o6.o: dl10/dl-o6.c Makefile
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+etc/libdl-dl10.conf:
+	mkdir etc; \
+	echo "#" > $@
+	echo "  # blah blah" >>  $@
+	echo "/libdl10*.a" >> $@
+	echo "" >> $@
+noinst_LIBRARIES = libdl10_1.a libdl10_2.a
+libdl10_1_a_SOURCES = dl10-o2.c dl10-o4.c
+libdl10_2_a_SOURCES = dl10-o3.c dl10-o5.c dl10-o6.c
+dl10.tar: etc/libdl-dl10.conf dl10-o1.o libdl10_1.a libdl10_2.a
+	@rm -f $@
+	$(AM_V_GEN)$(PAX) -w -f $@ $+
+dl10-tar.c: dl10.tar
+	$(AM_V_GEN)$(BIN2C) -C $< $@
+dl10-tar.h: dl10.tar
+	$(AM_V_GEN)$(BIN2C) -H $< $@
+dl10-tar.o: dl10-tar.c dl10-tar.h
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+dl10-sym.o: dl10.pre
+	$(AM_V_GEN)rtems-syms -e -c "$(CFLAGS)" -o $@ $<
+dl10$(EXEEXT):  $(dl10_OBJECTS) $(dl10_DEPENDENCIES) dl10-sym.o
+	@rm -f $@
+	$(AM_V_CCLD)$(LINK.c) $(CPU_CFLAGS) $(AM_CFLAGS) $(AM_LDFLAGS) -o $@ $+
+CLEANFILES += dl10.pre dl10-sym.o libdl10_1.a libdl10_2.a dl10-o1.o dl10-o2.o \
+		dl10-o3.o dl10-o4.o dl10-o5.o dl10-o6.o \
+		dl10.tar dl10-tar.h etc/libdl-dl10.conf
+endif
+endif
+
 if TEST_dumpbuf01
 lib_tests += dumpbuf01
 lib_screens += dumpbuf01/dumpbuf01.scn
diff --git a/testsuites/libtests/configure.ac b/testsuites/libtests/configure.ac
index 3bcc0ec..a6879a7 100644
--- a/testsuites/libtests/configure.ac
+++ b/testsuites/libtests/configure.ac
@@ -134,6 +134,7 @@ RTEMS_TEST_CHECK([dl06])
 RTEMS_TEST_CHECK([dl07])
 RTEMS_TEST_CHECK([dl08])
 RTEMS_TEST_CHECK([dl09])
+RTEMS_TEST_CHECK([dl10])
 RTEMS_TEST_CHECK([dumpbuf01])
 RTEMS_TEST_CHECK([dup2])
 RTEMS_TEST_CHECK([exit01])
diff --git a/testsuites/libtests/dl10/dl-load.c b/testsuites/libtests/dl10/dl-load.c
new file mode 100644
index 0000000..dee1d6e
--- /dev/null
+++ b/testsuites/libtests/dl10/dl-load.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2014 Chris Johns <chrisj at rtems.org>.
+ * All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#define TEST_TRACE 0
+#if TEST_TRACE
+ #define DEBUG_TRACE (RTEMS_RTL_TRACE_DETAIL | \
+                      RTEMS_RTL_TRACE_WARNING | \
+                      RTEMS_RTL_TRACE_LOAD | \
+                      RTEMS_RTL_TRACE_UNLOAD | \
+                      RTEMS_RTL_TRACE_SYMBOL | \
+                      RTEMS_RTL_TRACE_RELOC | \
+                      RTEMS_RTL_TRACE_LOAD_SECT | \
+                      RTEMS_RTL_TRACE_ALLOCATOR | \
+                      RTEMS_RTL_TRACE_UNRESOLVED | \
+                      RTEMS_RTL_TRACE_ARCHIVES | \
+                      RTEMS_RTL_TRACE_DEPENDENCY)
+ /* RTEMS_RTL_TRACE_ALL */
+#define DL_DEBUG_TRACE DEBUG_TRACE
+#define DL_DEBUG_CMD   1
+#else
+#define DL_DEBUG_TRACE 0
+#define DL_DEBUG_CMD    0
+#endif
+
+#include <dlfcn.h>
+
+#include "dl-load.h"
+
+#include <tmacros.h>
+
+#include <rtems/rtl/rtl-shell.h>
+#include <rtems/rtl/rtl-trace.h>
+
+typedef int (*call_sig)(void);
+
+static void dl_load_dump (void)
+{
+#if DL_DEBUG_CMD
+  char* list[] = { "rtl", "list", NULL };
+  char* sym[] = { "rtl", "sym", NULL };
+  printf ("RTL List:\n");
+  rtems_rtl_shell_command (2, list);
+  printf ("RTL Sym:\n");
+  rtems_rtl_shell_command (2, sym);
+#endif
+}
+
+static bool dl_check_resolved(void* handle, bool has_unresolved)
+{
+  int unresolved = 0;
+  if (dlinfo (handle, RTLD_DI_UNRESOLVED, &unresolved) == 0)
+    return 1;
+  if (has_unresolved)
+  {
+    if (unresolved == 0)
+    {
+      dl_load_dump();
+      return false;
+    }
+  }
+  else
+  {
+    if (unresolved != 0)
+    {
+      dl_load_dump();
+      return false;
+    }
+  }
+  printf ("handel: %p: no unresolved externals\n", handle);
+  return true;
+}
+
+static void* dl_load_obj(const char* name, bool has_unresolved)
+{
+  void* handle;
+
+  printf("load: %s\n", name);
+
+  handle = dlopen (name, RTLD_NOW | RTLD_GLOBAL);
+  if (!handle)
+  {
+    printf("dlopen failed: %s\n", dlerror());
+    return NULL;
+  }
+
+  dl_check_resolved (handle, has_unresolved);
+
+  printf ("handle: %p loaded\n", handle);
+
+  return handle;
+}
+
+static void dl_close (void* handle)
+{
+  int r;
+  printf ("handle: %p closing\n", handle);
+  r = dlclose (handle);
+  if (r != 0)
+    printf("dlclose failed: %s\n", dlerror());
+  rtems_test_assert (r == 0);
+}
+
+static int dl_call (void* handle, const char* func)
+{
+  call_sig call = dlsym (handle, func);
+  if (call == NULL)
+  {
+    printf("dlsym failed: symbol not found: %s\n", func);
+    return 1;
+  }
+  call ();
+  return 0;
+}
+
+int dl_load_test(void)
+{
+  void* o1;
+
+  printf ("Test source (link in strstr): %s\n", dl_localise_file (__FILE__));
+
+#if DL_DEBUG_TRACE
+  rtems_rtl_trace_set_mask (DL_DEBUG_TRACE);
+#endif
+
+  o1 = dl_load_obj("/dl10-o1.o", false);
+  if (!o1)
+    return 1;
+
+  if (!dl_check_resolved (o1, false))
+    return 1;
+
+  dl_load_dump ();
+
+  return 0;
+}
diff --git a/testsuites/libtests/dl10/dl-load.h b/testsuites/libtests/dl10/dl-load.h
new file mode 100644
index 0000000..7287291
--- /dev/null
+++ b/testsuites/libtests/dl10/dl-load.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014, 2018 Chris Johns <chrisj at rtems.org>.  All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <string.h>
+
+#if !defined(_DL_LOAD_H_)
+#define _DL_LOAD_H_
+
+static inline const char* dl_localise_file (const char* file)
+{
+  return (const char*) strstr (file, "testsuites");
+}
+
+int dl_load_test(void);
+
+#endif
diff --git a/testsuites/libtests/dl10/dl-o1.c b/testsuites/libtests/dl10/dl-o1.c
new file mode 100644
index 0000000..e6173f3
--- /dev/null
+++ b/testsuites/libtests/dl10/dl-o1.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018 Chris Johns <chrisj at rtems.org>.
+ * All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include "dl-o1.h"
+
+#include <rtems/test.h>
+#include "dl-load.h"
+#include "dl-o1.h"
+#include "dl-o2.h"
+
+#define printf(...) rtems_printf(&rtems_test_printer, __VA_ARGS__);
+
+/*
+ * Create some symbols. The uninitialised will be in the common section with
+ * separated text and data and this means there is no actual section in the ELF
+ * file, the details for this are in the symbols.
+ */
+int         dl01_bss1;            /* unitialised, .bss */
+float       dl01_bss2[30];        /* unitialised, .bss */
+char        dl01_bss3[10];        /* unitialised, .bss */
+int         dl01_data1 = 1;       /* initialised, .data */
+float       dl01_data2 = 0.3333;  /* initialised, .data */
+const int   dl01_const1 = 3;      /* read-only, .const */
+const float dl01_const2 = 0.666;  /* read-only, .const */
+int dl01_func1(void)              /* code, .text */
+{
+  return 4;
+}
+
+/*
+ * Yes a decl in the source. This is a modules main and I could not find which
+ * header main is defined in.
+ */
+int rtems_main_o1 (void);
+
+#define DL_NAME       "dlo1"
+#define PAINT_VAR(_v) sizeof(_v), &_v, _v
+
+int rtems_main_o1 (void)
+{
+  printf (DL_NAME ": module: %s\n", dl_localise_file (__FILE__));
+  printf (DL_NAME ":         dl01_bss1: %4zu: %p: %d\n",   PAINT_VAR (dl01_bss1));
+  printf (DL_NAME ":         dl01_bss2: %4zu: %p: %f\n",   PAINT_VAR (dl01_bss2[0]));
+  printf (DL_NAME ":         dl01_bss3: %4zu: %p: %02x\n", PAINT_VAR (dl01_bss3[0]));
+  printf (DL_NAME ":        dl01_data1: %4zu: %p: %d\n",   PAINT_VAR (dl01_data1));
+  /* no  %f in the rtems test printer */
+  printf (DL_NAME ":        dl01_data2: %4zu: %p: %f\n",   PAINT_VAR (dl01_data2));
+  printf (DL_NAME ":       dl01_const1: %4zu: %p: %d\n",   PAINT_VAR (dl01_const1));
+  printf (DL_NAME ":       dl01_const2: %4zu: %p: %f\n",   PAINT_VAR (dl01_const2));
+  printf (DL_NAME ":        dl01_func1: %4zu: %p\n",       sizeof(dl01_func1), &dl01_func1);
+
+  rtems_main_o2 ();
+
+  return 0;
+}
diff --git a/testsuites/libtests/dl10/dl-o1.h b/testsuites/libtests/dl10/dl-o1.h
new file mode 100644
index 0000000..f6a10f1
--- /dev/null
+++ b/testsuites/libtests/dl10/dl-o1.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018 Chris Johns <chrisj at rtems.org>.
+ * All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if !defined(DL01_H)
+#define DL01_H
+
+extern int         dl01_bss1;
+extern float       dl01_bss2[30];
+extern char        dl01_bss3[10];
+extern int         dl01_data1;
+extern float       dl01_data2;
+extern const int   dl01_const1;
+extern const float dl01_const2;
+
+int dl01_func1(void);
+
+#endif
diff --git a/testsuites/libtests/dl10/dl-o2.c b/testsuites/libtests/dl10/dl-o2.c
new file mode 100644
index 0000000..e58c875
--- /dev/null
+++ b/testsuites/libtests/dl10/dl-o2.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014 Chris Johns <chrisj at rtems.org>.  All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include "dl-load.h"
+#include "dl-o2.h"
+#include "dl-o3.h"
+
+#include <rtems/test.h>
+
+#define printf(...) rtems_printf(&rtems_test_printer, __VA_ARGS__);
+
+int   dl02_bss1;
+float dl02_bss2[7];
+char  dl02_bss3[21];
+int   dl02_data1;
+float dl02_data2;
+
+#define DL_NAME       "dlo2"
+#define PAINT_VAR(_v) sizeof(_v), &_v, _v
+
+int rtems_main_o2 (void)
+{
+  printf (DL_NAME ": module: %s\n", dl_localise_file (__FILE__));
+  printf (DL_NAME ":         dl02_bss1: %4zu: %p: %d\n",   PAINT_VAR (dl02_bss1));
+  printf (DL_NAME ":         dl02_bss2: %4zu: %p: %f\n",   PAINT_VAR (dl02_bss2[0]));
+  printf (DL_NAME ":         dl02_bss3: %4zu: %p: %02x\n", PAINT_VAR (dl02_bss3[0]));
+  printf (DL_NAME ":        dl02_data1: %4zu: %p: %d\n",   PAINT_VAR (dl02_data1));
+  /* no %f in the rtems test printer */
+  printf (DL_NAME ":        dl02_data2: %4zu: %p: %f\n",   PAINT_VAR (dl02_data2));
+
+  rtems_main_o3 ();
+
+  return 0;
+}
diff --git a/testsuites/libtests/dl10/dl-o2.h b/testsuites/libtests/dl10/dl-o2.h
new file mode 100644
index 0000000..d6c1820
--- /dev/null
+++ b/testsuites/libtests/dl10/dl-o2.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018 Chris Johns <chrisj at rtems.org>.
+ * All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if !defined(DL02_H)
+#define DL02_H
+
+/*
+ * A set of variables in dl-o2 reference by dl-03.
+ */
+
+extern int   dl02_bss1;
+extern float dl02_bss2[7];
+extern char  dl02_bss3[21];
+extern int   dl02_data1;
+extern float dl02_data2;
+
+int rtems_main_o2 (void);
+
+#endif
diff --git a/testsuites/libtests/dl10/dl-o3.c b/testsuites/libtests/dl10/dl-o3.c
new file mode 100644
index 0000000..c84b3d7
--- /dev/null
+++ b/testsuites/libtests/dl10/dl-o3.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014 Chris Johns <chrisj at rtems.org>.  All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include "dl-load.h"
+#include "dl-o3.h"
+#include "dl-o4.h"
+#include "dl-o5.h"
+
+#include <inttypes.h>
+#include <rtems/test.h>
+
+#define printf(...) rtems_printf(&rtems_test_printer, __VA_ARGS__);
+
+#define DL_NAME      "dlo3"
+#define PAINT_VAR(_v) sizeof(_v), &_v, _v
+
+int rtems_main_o3 ()
+{
+  printf (DL_NAME ": module: %s\n", dl_localise_file (__FILE__));
+  printf (DL_NAME ":   dl04_unresolv_1: %4zu: %p: %d\n",          PAINT_VAR (dl04_unresolv_1));
+  printf (DL_NAME ":   dl04_unresolv_2: %4zu: %p: %f\n",          PAINT_VAR (dl04_unresolv_2));
+  printf (DL_NAME ":   dl04_unresolv_3: %4zu: %p: %02x\n",        PAINT_VAR (dl04_unresolv_3));
+  printf (DL_NAME ":   dl04_unresolv_4: %4zu: %p: %p\n",          PAINT_VAR (dl04_unresolv_4));
+  printf (DL_NAME ":   dl04_unresolv_5: %4zu: %p: %d\n",          PAINT_VAR (dl04_unresolv_5));
+  printf (DL_NAME ":   dl04_unresolv_6: %4zu: %p: %s\n",          PAINT_VAR (dl04_unresolv_6));
+  printf (DL_NAME ":   dl05_unresolv_1: %4zu: %p: %" PRIu64 "\n", PAINT_VAR (dl05_unresolv_1));
+  printf (DL_NAME ":   dl05_unresolv_2: %4zu: %p: %" PRIu16 "\n", PAINT_VAR (dl05_unresolv_2));
+  printf (DL_NAME ":   dl05_unresolv_3: %4zu: %p: %" PRIu32 "\n", PAINT_VAR (dl05_unresolv_3));
+  printf (DL_NAME ":   dl05_unresolv_4: %4zu: %p: %" PRIu8  "\n", PAINT_VAR (dl05_unresolv_4));
+  printf (DL_NAME ":   dl05_unresolv_5: %4zu: %p: %" PRIi64 "\n", PAINT_VAR (dl05_unresolv_5));
+
+  rtems_main_o4 ();
+
+  return 0;
+}
diff --git a/testsuites/libtests/dl10/dl-o3.h b/testsuites/libtests/dl10/dl-o3.h
new file mode 100644
index 0000000..8c5d18d
--- /dev/null
+++ b/testsuites/libtests/dl10/dl-o3.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018 Chris Johns <chrisj at rtems.org>.
+ * All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if !defined(DL03_H)
+#define DL03_H
+
+int rtems_main_o3 (void);
+
+#endif
diff --git a/testsuites/libtests/dl10/dl-o4.c b/testsuites/libtests/dl10/dl-o4.c
new file mode 100644
index 0000000..72dfbc6
--- /dev/null
+++ b/testsuites/libtests/dl10/dl-o4.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014 Chris Johns <chrisj at rtems.org>.  All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include "dl-load.h"
+#include "dl-o4.h"
+#include "dl-o5.h"
+
+#include <rtems/test.h>
+
+#define printf(...) rtems_printf(&rtems_test_printer, __VA_ARGS__);
+
+int         dl04_unresolv_1;
+float       dl04_unresolv_2;
+char        dl04_unresolv_3;
+char*       dl04_unresolv_4;
+const int   dl04_unresolv_5 = 4;
+const char* dl04_unresolv_6 = "dl-O4";
+
+#define DL_NAME       "dlo4"
+#define PAINT_VAR(_v) sizeof(_v), &_v, _v
+
+int rtems_main_o4 (void)
+{
+  printf (DL_NAME ": module: %s\n", dl_localise_file (__FILE__));
+  printf (DL_NAME ":   dl04_unresolv_1: %4zu: %p: %d\n",   PAINT_VAR (dl04_unresolv_1));
+  printf (DL_NAME ":   dl04_unresolv_2: %4zu: %p: %f\n",   PAINT_VAR (dl04_unresolv_2));
+  printf (DL_NAME ":   dl04_unresolv_3: %4zu: %p: %02x\n", PAINT_VAR (dl04_unresolv_3));
+  printf (DL_NAME ":   dl04_unresolv_4: %4zu: %p: %p\n",   PAINT_VAR (dl04_unresolv_4));
+  printf (DL_NAME ":   dl04_unresolv_5: %4zu: %p: %d\n",   PAINT_VAR (dl04_unresolv_5));
+  printf (DL_NAME ":   dl04_unresolv_6: %4zu: %p: %s\n",   PAINT_VAR (dl04_unresolv_6));
+
+  rtems_main_o5 ();
+
+  return 0;
+}
diff --git a/testsuites/libtests/dl10/dl-o4.h b/testsuites/libtests/dl10/dl-o4.h
new file mode 100644
index 0000000..bab9fc1
--- /dev/null
+++ b/testsuites/libtests/dl10/dl-o4.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018 Chris Johns <chrisj at rtems.org>.
+ * All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if !defined(DL04_H)
+#define DL04_H
+
+/*
+ * A set of variables in dl-o4 referenced by dl-03 and unresolved when dl-o3 is
+ * loaded. They are all uninitialised variables with various sizes in a mixed
+ * order to get various alignments. These and dl-o5 variables are designed to
+ * force the dependent tables to grow.
+ */
+
+extern int         dl04_unresolv_1;
+extern float       dl04_unresolv_2;
+extern char        dl04_unresolv_3;
+extern char*       dl04_unresolv_4;
+extern const int   dl04_unresolv_5;
+extern const char* dl04_unresolv_6;
+
+int rtems_main_o4 (void);
+
+#endif
diff --git a/testsuites/libtests/dl10/dl-o5.c b/testsuites/libtests/dl10/dl-o5.c
new file mode 100644
index 0000000..be49639
--- /dev/null
+++ b/testsuites/libtests/dl10/dl-o5.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014 Chris Johns <chrisj at rtems.org>.  All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include "dl-load.h"
+#include "dl-o5.h"
+
+#include <inttypes.h>
+#include <rtems/test.h>
+
+#define printf(...) rtems_printf(&rtems_test_printer, __VA_ARGS__);
+
+uint64_t dl05_unresolv_1;
+uint16_t dl05_unresolv_2;
+uint32_t dl05_unresolv_3;
+uint8_t  dl05_unresolv_4;
+int64_t  dl05_unresolv_5;
+
+#define DL_NAME       "dlo5"
+#define PAINT_VAR(_v) sizeof(_v), &_v, _v
+
+int rtems_main_o5 (void)
+{
+  printf (DL_NAME ": module: %s\n", dl_localise_file (__FILE__));
+  printf (DL_NAME ":   dl05_unresolv_1: %4zu: %p: %" PRIu64 "\n", PAINT_VAR (dl05_unresolv_1));
+  printf (DL_NAME ":   dl05_unresolv_2: %4zu: %p: %" PRIu16 "\n", PAINT_VAR (dl05_unresolv_2));
+  printf (DL_NAME ":   dl05_unresolv_3: %4zu: %p: %" PRIu32 "\n", PAINT_VAR (dl05_unresolv_3));
+  printf (DL_NAME ":   dl05_unresolv_4: %4zu: %p: %" PRIu8  "\n", PAINT_VAR (dl05_unresolv_4));
+  printf (DL_NAME ":   dl05_unresolv_5: %4zu: %p: %" PRIi64 "\n", PAINT_VAR (dl05_unresolv_5));
+
+  return 0;
+}
diff --git a/testsuites/libtests/dl10/dl-o5.h b/testsuites/libtests/dl10/dl-o5.h
new file mode 100644
index 0000000..bb4ce46
--- /dev/null
+++ b/testsuites/libtests/dl10/dl-o5.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018 Chris Johns <chrisj at rtems.org>.
+ * All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <stdint.h>
+
+#if !defined(DL05_H)
+#define DL05_H
+
+/*
+ * A set of variables in dl-o5 referenced by dl-03 and unresolved when dl-o3 is
+ * loaded. They are all uninitialised variables with various sizes in a mixed
+ * order to get various alignments. These and dl-o4 variables are designed to
+ * force the dependent tables to grow.
+ */
+
+extern uint64_t dl05_unresolv_1;
+extern uint16_t dl05_unresolv_2;
+extern uint32_t dl05_unresolv_3;
+extern uint8_t  dl05_unresolv_4;
+extern int64_t  dl05_unresolv_5;
+
+int rtems_main_o5 (void);
+
+#endif
diff --git a/testsuites/libtests/dl10/dl-o6.c b/testsuites/libtests/dl10/dl-o6.c
new file mode 100644
index 0000000..5e03a30
--- /dev/null
+++ b/testsuites/libtests/dl10/dl-o6.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2014 Chris Johns <chrisj at rtems.org>.  All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include "dl-load.h"
+
+#include <inttypes.h>
+#include <rtems/test.h>
+
+int rtems_main_o5 (void)
+{
+  /* duplicate symbol in archive */
+  return 0;
+}
diff --git a/testsuites/libtests/dl10/dl10.doc b/testsuites/libtests/dl10/dl10.doc
new file mode 100644
index 0000000..82469da
--- /dev/null
+++ b/testsuites/libtests/dl10/dl10.doc
@@ -0,0 +1,22 @@
+# Copyright (c) 2019 Chris Johns <chrisj at rtems.org>
+#
+# The license and distribution terms for this file may be
+# found in the file LICENSE in this distribution or at
+# http://www.rtems.org/license/LICENSE.
+#
+
+This file describes the directives and concepts tested by this test set.
+
+test set name: dl10
+
+directives:
+
+  dlopen
+  dlinfo
+  dlsym
+  dlclose
+
+concepts:
+
++ Load modules from archives that have duplicate symbols.
++ Wait a shell prompt to test the RTL commands.
diff --git a/testsuites/libtests/dl10/dl10.scn b/testsuites/libtests/dl10/dl10.scn
new file mode 100644
index 0000000..dec2c42
--- /dev/null
+++ b/testsuites/libtests/dl10/dl10.scn
@@ -0,0 +1,41 @@
+*** BEGIN OF TEST libdl (RTL) 10 ***
+*** TEST VERSION: 5.0.0.c1aa9685eaa9d5d321c965a2aa44f868b7834c23
+*** TEST STATE: EXPECTED-PASS
+*** TEST BUILD: RTEMS_NETWORKING RTEMS_POSIX_API
+*** TEST TOOLS: 7.4.0 20181206 (RTEMS 5, RSB 98588a55961a92f5d27bfd756dfc9e31b2b1bf98, Newlib 3e24fbf6f)
+RTL (libdl) commands: dl, rtl
+
+
+RTEMS Shell on /dev/foobar. Use 'help' to list commands.
+SHLL [/] # rtl obj load dl10-o1.o
+SHLL [/] # rtl list -l
+ dl10-o1.o
+  unresolved    : 0
+  users         : 1
+  references    : 0
+  symbols       : 9
+  symbol memory : 281
+ /libdl10_1.a:dl10-o2.o
+  unresolved    : 0
+  users         : 0
+  references    : 1
+  symbols       : 6
+  symbol memory : 186
+ /libdl10_2.a:dl10-o5.o
+  unresolved    : 0
+  users         : 0
+  references    : 2
+  symbols       : 6
+  symbol memory : 214
+ /libdl10_2.a:dl10-o3.o
+  unresolved    : 0
+  users         : 0
+  references    : 1
+  symbols       : 1
+  symbol memory : 34
+ /libdl10_1.a:dl10-o4.o
+  unresolved    : 0
+  users         : 0
+  references    : 1
+  symbols       : 7
+  symbol memory : 250
diff --git a/testsuites/libtests/dl10/init.c b/testsuites/libtests/dl10/init.c
new file mode 100644
index 0000000..d297567
--- /dev/null
+++ b/testsuites/libtests/dl10/init.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2018 Chris Johns <chrisj at rtems.org>.  All rights reserved.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include "tmacros.h"
+
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <rtems/rtl/dlfcn-shell.h>
+#include <rtems/rtl/rtl.h>
+#include <rtems/rtl/rtl-shell.h>
+#include <rtems/shell.h>
+#include <rtems/untar.h>
+
+#include "dl-load.h"
+
+const char rtems_test_name[] = "libdl (RTL) 10";
+
+/* forward declarations to avoid warnings */
+static rtems_task Init(rtems_task_argument argument);
+
+#include "dl10-tar.h"
+
+#define TARFILE_START dl10_tar
+#define TARFILE_SIZE  dl10_tar_size
+
+static int test(void)
+{
+#if USE_SHELL_CMD
+  int ret;
+  ret = dl_load_test();
+  if (ret)
+    rtems_test_exit(ret);
+#endif
+  return 0;
+}
+
+static void Init(rtems_task_argument arg)
+{
+  int e;
+
+  TEST_BEGIN();
+
+  e = Untar_FromMemory((void *)TARFILE_START, (size_t)TARFILE_SIZE);
+  if (e != 0)
+  {
+    printf ("error: untar failed: %d\n", e);
+    rtems_test_exit (1);
+    exit (1);
+  }
+
+  e = symlink ("libdl-dl10.conf", "/etc/libdl.conf");
+  if (e != 0)
+  {
+    printf ("error: untar failed: %d\n", e);
+    rtems_test_exit (1);
+    exit (1);
+  }
+
+  test();
+
+  rtems_shell_init_environment ();
+
+  printf ("RTL (libdl) commands: dl, rtl\n\n");
+
+  if (rtems_shell_add_cmd ("rtl",
+                           "rtl",
+                           "rtl -l",
+                           rtems_rtl_shell_command) == NULL)
+  {
+    printf("command add failed\n");
+    rtems_test_exit(1);
+    exit (1);
+  }
+
+  rtems_shell_init ("SHLL",
+                    RTEMS_MINIMUM_STACK_SIZE * 4,
+                    100,
+                    "/dev/foobar",
+                    false,
+                    true,
+                    NULL);
+
+  TEST_END();
+
+  rtems_test_exit(0);
+}
+
+#define CONFIGURE_SHELL_COMMANDS_INIT
+#define CONFIGURE_SHELL_COMMANDS_ALL
+
+/*
+ * Remove the commands that pull in libblock.
+ */
+#define CONFIGURE_SHELL_NO_COMMAND_BLKSYNC
+#define CONFIGURE_SHELL_NO_COMMAND_BLKSTATS
+#define CONFIGURE_SHELL_NO_COMMAND_FDISK
+#define CONFIGURE_SHELL_NO_COMMAND_MKRFS
+#define CONFIGURE_SHELL_NO_COMMAND_DEBUGRFS
+
+#include <rtems/shellconfig.h>
+
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+
+#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 10
+
+#define CONFIGURE_MAXIMUM_TASKS 4
+
+#define CONFIGURE_MAXIMUM_SEMAPHORES 4
+
+#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT_TASK_STACK_SIZE (8U * 1024U)
+
+#define CONFIGURE_INIT_TASK_ATTRIBUTES   (RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT)
+
+#define CONFIGURE_UNIFIED_WORK_AREAS
+
+#define CONFIGURE_UNLIMITED_OBJECTS
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>
diff --git a/testsuites/testdata/rtems.tcfg b/testsuites/testdata/rtems.tcfg
index 255a5e1..f58cd4a 100644
--- a/testsuites/testdata/rtems.tcfg
+++ b/testsuites/testdata/rtems.tcfg
@@ -19,6 +19,7 @@ user-input: fileio
 user-input: monitor
 user-input: termios
 user-input: top
+user-input: dl10
 
 #
 # Benchmarks



More information about the vc mailing list