Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup rtems_rtld
0007  *
0008  * @brief RTEMS Run-Time Link Editor Shell Commands
0009  *
0010  * A simple RTL command to aid using the RTL.
0011  */
0012 
0013 /*
0014  *  COPYRIGHT (c) 2012, 2018 Chris Johns <chrisj@rtems.org>
0015  *
0016  * Redistribution and use in source and binary forms, with or without
0017  * modification, are permitted provided that the following conditions
0018  * are met:
0019  * 1. Redistributions of source code must retain the above copyright
0020  *    notice, this list of conditions and the following disclaimer.
0021  * 2. Redistributions in binary form must reproduce the above copyright
0022  *    notice, this list of conditions and the following disclaimer in the
0023  *    documentation and/or other materials provided with the distribution.
0024  *
0025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0026  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0027  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0028  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0029  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0030  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0031  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0032  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0033  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0034  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0035  * POSSIBILITY OF SUCH DAMAGE.
0036  */
0037 
0038 #ifdef HAVE_CONFIG_H
0039 #include "config.h"
0040 #endif
0041 
0042 #include <inttypes.h>
0043 #include <rtems/inttypes.h>
0044 
0045 #include <sys/stat.h>
0046 #include <regex.h>
0047 #include <string.h>
0048 
0049 #include <dlfcn.h>
0050 
0051 #include <rtems/printer.h>
0052 #include <rtems/rtl/rtl.h>
0053 #include <rtems/rtl/rtl-archive.h>
0054 #include <rtems/rtl/rtl-shell.h>
0055 #include <rtems/rtl/rtl-trace.h>
0056 #include "rtl-chain-iterator.h"
0057 
0058 /**
0059  * The type of the shell handlers we have.
0060  */
0061 typedef int (*rtems_rtl_shell_handler) (const rtems_printer* printer, int argc, char *argv[]);
0062 
0063 /**
0064  * Table of handlers we parse to invoke the command.
0065  */
0066 typedef struct
0067 {
0068   const char*             name;    /**< The sub-command's name. */
0069   rtems_rtl_shell_handler handler; /**< The sub-command's handler. */
0070   const char*             help;    /**< The sub-command's help. */
0071 } rtems_rtl_shell_cmd;
0072 
0073 /**
0074  * Object summary data.
0075  */
0076 typedef struct
0077 {
0078   int    count;   /**< The number of object files. */
0079   size_t exec;    /**< The amount of executable memory allocated. */
0080   size_t symbols; /**< The amount of symbol memory allocated. */
0081 } rtems_rtl_obj_summary;
0082 
0083 /**
0084  * Object summary iterator.
0085  */
0086 static bool
0087 rtems_rtl_obj_summary_iterator (rtems_chain_node* node, void* data)
0088 {
0089   rtems_rtl_obj_summary* summary = data;
0090   rtems_rtl_obj*         obj = (rtems_rtl_obj*) node;
0091   ++summary->count;
0092   summary->exec += obj->exec_size;
0093   summary->symbols += obj->global_size;
0094   return true;
0095 }
0096 
0097 /**
0098  * Count the number of symbols.
0099  */
0100 static int
0101 rtems_rtl_count_symbols (rtems_rtl_data* rtl)
0102 {
0103   int count;
0104   int bucket;
0105   for (count = 0, bucket = 0; bucket < rtl->globals.nbuckets; ++bucket)
0106     count += rtems_rtl_chain_count (&rtl->globals.buckets[bucket]);
0107   return count;
0108 }
0109 
0110 static int
0111 rtems_rtl_shell_status (const rtems_printer* printer,
0112                         int                  argc,
0113                         char*                argv[])
0114 {
0115   rtems_rtl_obj_summary summary;
0116   size_t                total_memory;
0117   rtems_rtl_data*       rtl;
0118 
0119   rtl = rtems_rtl_lock ();
0120   if (rtl == NULL)
0121   {
0122     rtems_printf (printer, "error: cannot lock the linker\n");
0123     return 1;
0124   }
0125 
0126   summary.count   = 0;
0127   summary.exec    = 0;
0128   summary.symbols = 0;
0129   rtems_rtl_chain_iterate (&rtl->objects,
0130                            rtems_rtl_obj_summary_iterator,
0131                            &summary);
0132   /*
0133    * Currently does not include the name strings in the obj struct.
0134    */
0135   total_memory =
0136     sizeof (*rtl) + (summary.count * sizeof (rtems_rtl_obj)) +
0137     summary.exec + summary.symbols;
0138 
0139   rtems_printf (printer, "Runtime Linker Status:\n");
0140   rtems_printf (printer, "        paths: %s\n", rtl->paths);
0141   rtems_printf (printer, "      objects: %d\n", summary.count);
0142   rtems_printf (printer, " total memory: %zi\n", total_memory);
0143   rtems_printf (printer, "  exec memory: %zi\n", summary.exec);
0144   rtems_printf (printer, "   sym memory: %zi\n", summary.symbols);
0145   rtems_printf (printer, "      symbols: %d\n", rtems_rtl_count_symbols (rtl));
0146 
0147   rtems_rtl_unlock ();
0148 
0149   return 0;
0150 }
0151 
0152 /**
0153  * Object print data.
0154  */
0155 typedef struct
0156 {
0157   const rtems_printer* printer;      /**< The RTEMS printer. */
0158   rtems_rtl_data*      rtl;          /**< The RTL data. */
0159   int                  indent;       /**< Spaces to indent. */
0160   bool                 oname;        /**< Print object names. */
0161   bool                 names;        /**< Print details of all names. */
0162   bool                 stats;        /**< Print stats. */
0163   bool                 memory_map;   /**< Print the memory map. */
0164   bool                 symbols;      /**< Print the global symbols. */
0165   bool                 dependencies; /**< Print any dependencies. */
0166   bool                 trampolines;  /**< Print trampoline stats. */
0167   bool                 base;         /**< Include the base object file. */
0168   const char*          re_name;      /**< Name regx to filter on. */
0169   const char*          re_symbol;    /**< Symbol regx to filter on. */
0170 } rtems_rtl_obj_print;
0171 
0172 /**
0173  * Parse an argument.
0174  */
0175 static bool
0176 rtems_rtl_parse_opt (const char opt, int argc, char *argv[])
0177 {
0178   size_t arg;
0179   for (arg = 1; arg < argc; ++arg)
0180   {
0181     if (argv[arg][0] == '-')
0182     {
0183       size_t len = strlen (argv[arg]);
0184       size_t i;
0185       for (i = 1; i < len; ++i)
0186         if (argv[arg][i] == opt)
0187           return true;
0188     }
0189   }
0190   return false;
0191 }
0192 
0193 static bool
0194 rtems_rtl_check_opts (const rtems_printer* printer,
0195                       const char*          opts,
0196                       int                  argc,
0197                       char*                argv[])
0198 {
0199   size_t olen = strlen (opts);
0200   size_t arg;
0201   for (arg = 1; arg < argc; ++arg)
0202   {
0203     if (argv[arg][0] == '-')
0204     {
0205       size_t len = strlen (argv[arg]);
0206       size_t i;
0207       for (i = 1; i < len; ++i)
0208       {
0209         bool found = false;
0210         size_t       o;
0211         for (o = 0; o < olen; ++o)
0212         {
0213           if (argv[arg][i] == opts[o])
0214           {
0215             found = true;
0216             break;
0217           }
0218         }
0219         if (!found)
0220         {
0221           rtems_printf (printer, "error: invalid option: %c (%s)\n",
0222                         argv[arg][i], argv[arg]);
0223           return false;
0224         }
0225       }
0226     }
0227   }
0228   return true;
0229 }
0230 
0231 static ssize_t
0232 rtems_rtl_parse_arg_index (const char  opt,
0233                            const char* skip_opts,
0234                            int         argc,
0235                            char*       argv[])
0236 {
0237   ssize_t arg;
0238   for (arg = 1; arg < argc; ++arg)
0239   {
0240     if (argv[arg][0] == '-')
0241     {
0242       /*
0243        * We can check the next char because there has to be a valid char or a
0244        * nul.
0245        */
0246       if (argv[arg][1] != '\0')
0247       {
0248         size_t len = skip_opts != NULL ? strlen (skip_opts) : 0;
0249         size_t i;
0250         for (i = 0; i < len; ++i)
0251         {
0252           if (skip_opts[i] == argv[arg][1])
0253           {
0254             ++arg;
0255             break;
0256           }
0257         }
0258       }
0259     }
0260     else
0261     {
0262       if (opt == ' ')
0263         return arg;
0264     }
0265     /*
0266      * Is this an option and does it match what we are looking for?
0267      */
0268     if (arg < argc && argv[arg][0] == '-' && argv[arg][1] == opt)
0269       return arg + 1;
0270   }
0271   return -1;
0272 }
0273 
0274 static const char*
0275 rtems_rtl_parse_arg (const char  opt,
0276                      const char* skip_opts,
0277                      int         argc,
0278                      char*       argv[])
0279 {
0280   ssize_t arg = rtems_rtl_parse_arg_index (opt, skip_opts, argc, argv);
0281   if (arg < 0)
0282     return NULL;
0283   return argv[arg];
0284 }
0285 
0286 /**
0287  * Regx matching.
0288  */
0289 static bool
0290 rtems_rtl_regx_compile (const rtems_printer* printer,
0291                         const char*          label,
0292                         regex_t*             rege,
0293                         const char*          expression)
0294 {
0295   int r = regcomp (rege, expression, REG_EXTENDED | REG_NOSUB);
0296   if (r != 0)
0297   {
0298     char rerror[128];
0299     regerror (r, rege, rerror, sizeof(rerror));
0300     rtems_printf (printer, "error: %s: %s\n", label, rerror);
0301     return false;
0302   }
0303   return true;
0304 }
0305 
0306 static int
0307 rtems_rtl_regx_match (const rtems_printer* printer,
0308                       const char*          label,
0309                       regex_t*             rege,
0310                       const char*          string)
0311 {
0312   int r = regexec (rege, string, 0, NULL, 0);
0313   if (r != 0 && r != REG_NOMATCH)
0314   {
0315     char rerror[128];
0316     regerror (r, rege, rerror, sizeof(rerror));
0317     rtems_printf (printer, "error: %s: %s\n", label, rerror);
0318     regfree (rege);
0319     return -1;
0320   }
0321   return r == 0 ? 1 : 0;
0322 }
0323 
0324 /**
0325  * Print the obj name.
0326  */
0327 static void
0328 rtems_rtl_print_obj_name (const rtems_rtl_obj_print* print, rtems_rtl_obj* obj)
0329 {
0330   rtems_printf (print->printer, "%-*c", print->indent, ' ');
0331   if (rtems_rtl_obj_aname (obj) != NULL)
0332     rtems_printf (print->printer, "%s:", rtems_rtl_obj_aname (obj));
0333   rtems_printf (print->printer, "%s\n", rtems_rtl_obj_oname (obj));
0334 }
0335 
0336 /**
0337  * Print symbols.
0338  */
0339 static bool
0340 rtems_rtl_print_symbols (rtems_rtl_obj_print* print,
0341                          rtems_rtl_obj*       obj,
0342                          int                  indent,
0343                          bool                 show_name)
0344 {
0345   regex_t rege;
0346   int     max_len = 0;
0347   int     s;
0348 
0349   if (print->re_symbol != NULL &&
0350       !rtems_rtl_regx_compile (print->printer,
0351                                "symbol filter",
0352                                &rege, print->re_symbol))
0353   {
0354     return false;
0355   }
0356 
0357   for (s = 0; s < obj->global_syms; ++s)
0358   {
0359     const char* sym = obj->global_table[s].name;
0360     int         len;
0361 
0362     if (print->re_symbol != NULL)
0363     {
0364       int r = rtems_rtl_regx_match (print->printer, "symbol match", &rege, sym);
0365       if (r < 0)
0366         return false;
0367       if (!r)
0368         continue;
0369     }
0370 
0371     len = strlen (obj->global_table[s].name);
0372     if (len > max_len)
0373       max_len = len;
0374   }
0375 
0376   for (s = 0; s < obj->global_syms; ++s)
0377   {
0378     const char* sym = obj->global_table[s].name;
0379     if (print->re_symbol != NULL)
0380     {
0381       int r = rtems_rtl_regx_match (print->printer, "symbol match", &rege, sym);
0382       if (r < 0)
0383         return false;
0384       if (r == 0)
0385         continue;
0386     }
0387     if (show_name)
0388     {
0389       show_name = false;
0390       rtems_rtl_print_obj_name (print, obj);
0391     }
0392     rtems_printf (print->printer, "%-*c%-*s = %p\n", indent + 2, ' ',
0393                   max_len, sym, obj->global_table[s].value);
0394   }
0395 
0396   regfree (&rege);
0397 
0398   return true;
0399 }
0400 
0401 /**
0402  * Dependencies printer.
0403  */
0404 typedef struct
0405 {
0406   const rtems_rtl_obj_print* print;     /**< The print data. */
0407   bool                       first;     /**< Is this the first line printed. */
0408   bool                       show_name; /**< Show the object name. */
0409   int                        indent;    /**< The indent. */
0410 } rtems_rtl_dep_data;
0411 
0412 static bool
0413 rtems_rtl_dependencies (rtems_rtl_obj* obj, rtems_rtl_obj* dependent, void* data)
0414 {
0415   rtems_rtl_dep_data* dd = (rtems_rtl_dep_data*) data;
0416   if (dd->first)
0417   {
0418     dd->first = false;
0419     if (dd->show_name)
0420     {
0421       dd->show_name = false;
0422       rtems_rtl_print_obj_name (dd->print, obj);
0423     }
0424     rtems_printf (dd->print->printer, "%-*cdependencies  : ", dd->indent, ' ');
0425     dd->indent += strlen ("dependencies :");
0426   }
0427   else
0428   {
0429     rtems_printf (dd->print->printer, "\n%-*c: ", (int) dd->indent, ' ');
0430   }
0431   rtems_printf (dd->print->printer, "%s", dependent->oname);
0432   return false;
0433 }
0434 
0435 /**
0436  * Object printer.
0437  */
0438 static bool
0439 rtems_rtl_obj_printer (rtems_rtl_obj_print* print, rtems_rtl_obj* obj)
0440 {
0441   char flags_str[33];
0442   int  indent = print->indent + 1;
0443   bool show_name = true;
0444 
0445   /*
0446    * Skip the base module unless asked to show it.
0447    */
0448   if (!print->base && (obj == print->rtl->base))
0449       return true;
0450 
0451   if (print->re_name != NULL)
0452   {
0453     regex_t rege;
0454     int     r = 0;
0455 
0456     if (!rtems_rtl_regx_compile (print->printer,
0457                                  "name filter",
0458                                  &rege, print->re_name))
0459     {
0460       return false;
0461     }
0462 
0463     if (rtems_rtl_obj_aname (obj) != NULL)
0464     {
0465       r = rtems_rtl_regx_match (print->printer,
0466                                 "aname match",
0467                                 &rege,
0468                                 rtems_rtl_obj_aname (obj));
0469       if (r < 0)
0470         return false;
0471     }
0472 
0473     if (r == 0)
0474     {
0475       r = rtems_rtl_regx_match (print->printer,
0476                                 "oname match",
0477                                 &rege,
0478                                 rtems_rtl_obj_oname (obj));
0479       if (r < 0)
0480         return false;
0481     }
0482 
0483     regfree (&rege);
0484 
0485     if (r == 0)
0486       return true;
0487   }
0488 
0489   if (print->names || print->memory_map || print->stats ||
0490       (!print->names && !print->memory_map && !print->stats &&
0491        !print->symbols && !print->dependencies))
0492   {
0493     show_name = false;
0494     rtems_rtl_print_obj_name (print, obj);
0495   }
0496 
0497   if (print->names)
0498   {
0499     rtems_printf (print->printer,
0500                   "%-*cfile name     : %s\n",
0501                   indent, ' ', rtems_rtl_obj_fname (obj));
0502     rtems_printf (print->printer,
0503                   "%-*carchive name  : %s\n",
0504                   indent, ' ', rtems_rtl_obj_aname (obj));
0505     strcpy (flags_str, "--");
0506     if (obj->flags & RTEMS_RTL_OBJ_LOCKED)
0507       flags_str[0] = 'L';
0508     if (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED)
0509       flags_str[1] = 'U';
0510     rtems_printf (print->printer,
0511                   "%-*cflags         : %s\n", indent, ' ', flags_str);
0512     rtems_printf (print->printer,
0513                   "%-*cfile offset   : %" PRIdoff_t "\n", indent, ' ', obj->ooffset);
0514     rtems_printf (print->printer,
0515                   "%-*cfile size     : %zi\n", indent, ' ', obj->fsize);
0516   }
0517   if (print->memory_map)
0518   {
0519     rtems_printf (print->printer,
0520                   "%-*cexec size     : %zi\n", indent, ' ', obj->exec_size);
0521     rtems_printf (print->printer,
0522                   "%-*ctext base     : %p (%zi)\n", indent, ' ',
0523                   obj->text_base, obj->text_size);
0524     rtems_printf (print->printer,
0525                   "%-*cconst base    : %p (%zi)\n", indent, ' ',
0526                   obj->const_base, obj->const_size);
0527     rtems_printf (print->printer,
0528                   "%-*cdata base     : %p (%zi)\n", indent, ' ',
0529                   obj->data_base, obj->data_size);
0530     rtems_printf (print->printer,
0531                   "%-*cbss base      : %p (%zi)\n", indent, ' ',
0532                   obj->bss_base, obj->bss_size);
0533   }
0534   if (print->stats)
0535   {
0536     rtems_printf (print->printer, "%-*cunresolved    : %zu\n", indent, ' ', obj->unresolved);
0537     rtems_printf (print->printer, "%-*cusers         : %zu\n", indent, ' ', obj->users);
0538     rtems_printf (print->printer, "%-*creferences    : %zu\n", indent, ' ', obj->refs);
0539     rtems_printf (print->printer, "%-*ctrampolines   : %zu\n", indent, ' ',
0540                   rtems_rtl_obj_trampolines (obj));
0541     rtems_printf (print->printer, "%-*csymbols       : %zi\n", indent, ' ', obj->global_syms);
0542     rtems_printf (print->printer, "%-*csymbol memory : %zi\n", indent, ' ', obj->global_size);
0543   }
0544   if (print->symbols)
0545   {
0546     if (!rtems_rtl_print_symbols (print, obj, indent, show_name))
0547       return false;
0548   }
0549   if (print->dependencies)
0550   {
0551     rtems_rtl_dep_data dd = {
0552       .print = print,
0553       .first = true,
0554       .show_name = show_name,
0555       .indent = indent
0556     };
0557     rtems_rtl_obj_iterate_dependents (obj, rtems_rtl_dependencies, &dd);
0558     if (!dd.first)
0559       rtems_printf (print->printer, "\n");
0560   }
0561   if (print->trampolines)
0562   {
0563     if (obj->tramp_size == 0)
0564     {
0565       rtems_printf (print->printer, "%-*ctrampolines: not supported\n", indent, ' ');
0566     }
0567     else
0568     {
0569       size_t slots = rtems_rtl_obj_trampoline_slots (obj);
0570       size_t used = rtems_rtl_obj_trampolines (obj);
0571       rtems_printf (print->printer, "%-*ctrampolines:\n", indent, ' ');
0572       rtems_printf (print->printer, "%-*cslots     : %zu\n", indent + 4, ' ',
0573                     slots);
0574       rtems_printf (print->printer, "%-*csize      : %zu\n", indent + 4, ' ',
0575                     obj->tramp_size);
0576       rtems_printf (print->printer, "%-*cslot size : %zu\n", indent + 4, ' ',
0577                     obj->tramp_size);
0578       rtems_printf (print->printer, "%-*cused      : %zu\n", indent + 4, ' ',
0579                     used);
0580       rtems_printf (print->printer, "%-*crelocs    : %zu\n", indent + 4, ' ',
0581                     obj->tramp_relocs);
0582       rtems_printf (print->printer, "%-*cunresolved: %zu\n", indent + 4, ' ',
0583                     slots - obj->tramp_relocs);
0584       rtems_printf (print->printer, "%-*cyield     : %zu%%\n", indent + 4, ' ',
0585                     slots ? (used * 100) / slots : 0);
0586     }
0587   }
0588   return true;
0589 }
0590 
0591 /**
0592  * Object unresolved symbols printer.
0593  */
0594 static bool
0595 rtems_rtl_unresolved_printer (rtems_rtl_unresolv_rec* rec,
0596                               void*                   data)
0597 {
0598   rtems_rtl_obj_print* print = (rtems_rtl_obj_print*) data;
0599   if (rec->type == rtems_rtl_unresolved_symbol)
0600     rtems_printf (print->printer,
0601                   "%-*c%s\n", print->indent + 2, ' ', rec->rec.name.name);
0602   return false;
0603 }
0604 
0605 /**
0606  * Object print iterator.
0607  */
0608 static bool
0609 rtems_rtl_obj_print_iterator (rtems_chain_node* node, void* data)
0610 {
0611   rtems_rtl_obj_print* print = data;
0612   rtems_rtl_obj*       obj = (rtems_rtl_obj*) node;
0613   return rtems_rtl_obj_printer (print, obj);
0614 }
0615 
0616 int
0617 rtems_rtl_shell_list (const rtems_printer* printer, int argc, char* argv[])
0618 {
0619   rtems_rtl_obj_print print = { 0 };
0620   if (!rtems_rtl_check_opts (printer, "anlmsdbt", argc, argv))
0621     return 1;
0622   print.printer = printer;
0623   print.indent = 1;
0624   print.oname = true;
0625   if (rtems_rtl_parse_opt ('a', argc, argv))
0626   {
0627     print.names = true;
0628     print.stats = true;
0629     print.memory_map = true;
0630     print.symbols = true;
0631     print.dependencies = true;
0632     print.trampolines = true;
0633   }
0634   else
0635   {
0636     print.names = rtems_rtl_parse_opt ('n', argc, argv);
0637     print.stats = rtems_rtl_parse_opt ('l', argc, argv);;
0638     print.memory_map = rtems_rtl_parse_opt ('m', argc, argv);;
0639     print.symbols = rtems_rtl_parse_opt ('s', argc, argv);
0640     print.dependencies = rtems_rtl_parse_opt ('d', argc, argv);;
0641     print.trampolines = rtems_rtl_parse_opt ('t', argc, argv);;
0642     print.base = rtems_rtl_parse_opt ('b', argc, argv);;
0643     print.re_name = rtems_rtl_parse_arg (' ', NULL, argc, argv);
0644   }
0645   print.re_symbol = NULL;
0646   print.rtl = rtems_rtl_lock ();
0647   if (print.rtl == NULL)
0648   {
0649     rtems_printf (print.printer, "error: cannot lock the linker\n");
0650     return 1;
0651   }
0652   rtems_rtl_chain_iterate (&print.rtl->objects,
0653                            rtems_rtl_obj_print_iterator,
0654                            &print);
0655   rtems_rtl_unlock ();
0656   return 0;
0657 }
0658 
0659 int
0660 rtems_rtl_shell_sym (const rtems_printer* printer, int argc, char* argv[])
0661 {
0662   rtems_rtl_obj_print print = { 0 };
0663   if (!rtems_rtl_check_opts (printer, "buo", argc, argv))
0664     return 1;
0665   print.printer = printer;
0666   print.indent = 1;
0667   print.oname = true;
0668   print.names = false;
0669   print.stats = false;
0670   print.memory_map = false;
0671   print.symbols = !rtems_rtl_parse_opt ('u', argc, argv);;
0672   print.dependencies = false;
0673   print.base = rtems_rtl_parse_opt ('b', argc, argv);
0674   print.re_name = rtems_rtl_parse_arg ('o', NULL, argc, argv);;
0675   print.re_symbol = rtems_rtl_parse_arg (' ', "ou", argc, argv);
0676   print.rtl = rtems_rtl_lock ();
0677   if (print.rtl == NULL)
0678   {
0679     rtems_printf (print.printer, "error: cannot lock the linker\n");
0680     return 1;
0681   }
0682   if (print.symbols)
0683   {
0684     rtems_rtl_chain_iterate (&print.rtl->objects,
0685                              rtems_rtl_obj_print_iterator,
0686                              &print);
0687   }
0688   if (rtems_rtl_parse_opt ('u', argc, argv))
0689   {
0690     rtems_printf (printer, "Unresolved:\n");
0691     rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_printer, &print);
0692   }
0693   rtems_rtl_unlock ();
0694   return 0;
0695 }
0696 
0697 int
0698 rtems_rtl_shell_object (const rtems_printer* printer, int argc, char* argv[])
0699 {
0700   size_t arg;
0701 
0702   --argc;
0703   ++argv;
0704 
0705   for (arg = 0; arg < argc; ++arg)
0706   {
0707     if (argv[arg][0] == '-')
0708     {
0709       switch (argv[arg][1])
0710       {
0711         case 'h':
0712         case '?':
0713           rtems_printf (printer, "obj commands:\n");
0714           rtems_printf (printer, " load <file>\n");
0715           rtems_printf (printer, " unload <file>\n");
0716           break;
0717         default:
0718           rtems_printf (printer, "error: invalid option: %s\n", argv[arg]);
0719           return 1;
0720       }
0721     }
0722     else
0723     {
0724       break;
0725     }
0726   }
0727 
0728   if (arg >= argc)
0729   {
0730     rtems_printf (printer, "error: no obj command\n");
0731     return 1;
0732   }
0733 
0734   if (strcmp (argv[arg], "load") == 0)
0735   {
0736     void* handle;
0737     int   unresolved;
0738 
0739     ++arg;
0740     if (arg >= argc)
0741     {
0742       rtems_printf (printer, "error: no object file to load\n");
0743       return 1;
0744     }
0745 
0746     handle = dlopen (argv[arg], RTLD_NOW | RTLD_GLOBAL);
0747     if (handle == NULL)
0748     {
0749       rtems_printf (printer, "error: load: %s: %s\n", argv[arg], dlerror ());
0750       return 1;
0751     }
0752 
0753     if (dlinfo (RTLD_SELF, RTLD_DI_UNRESOLVED, &unresolved) < 0)
0754     {
0755       rtems_printf (printer, "error: %s: %s\n", argv[arg], dlerror ());
0756       return 1;
0757     }
0758 
0759     if (unresolved != 0)
0760     {
0761       rtems_printf (printer, "warning: unresolved symbols present\n");
0762       return 1;
0763     }
0764   }
0765   else if (strcmp (argv[arg], "unload") == 0)
0766   {
0767     rtems_rtl_data* rtl;
0768     rtems_rtl_obj*  obj;
0769 
0770     ++arg;
0771     if (arg >= argc)
0772     {
0773       rtems_printf (printer, "error: no object file to load\n");
0774       return 1;
0775     }
0776 
0777     rtl = rtems_rtl_lock ();
0778     if (rtl == NULL)
0779     {
0780       rtems_printf (printer, "error: cannot lock RTL\n");
0781       return 1;
0782     }
0783 
0784     obj = rtems_rtl_find_obj (argv[arg]);
0785     if (obj == NULL)
0786     {
0787       rtems_rtl_unlock ();
0788       rtems_printf (printer, "error: unload: %s: %s\n", argv[arg], dlerror ());
0789       return 1;
0790     }
0791 
0792     if (!rtems_rtl_unload (obj))
0793     {
0794       rtems_rtl_unlock ();
0795       rtems_printf (printer, "error: unload: %s: %s\n", argv[arg], dlerror ());
0796       return 1;
0797     }
0798 
0799     rtems_rtl_unlock ();
0800   }
0801   else
0802   {
0803     rtems_printf (printer, "error: unknown obj command: %s\n", argv[arg]);
0804     return 1;
0805   }
0806 
0807   return 0;
0808 }
0809 
0810 int
0811 rtems_rtl_shell_archive (const rtems_printer* printer, int argc, char* argv[])
0812 {
0813   rtems_rtl_data*   rtl;
0814   rtems_chain_node* node;
0815   const char*       re_name;
0816   bool              details;
0817   bool              symbols;
0818   bool              duplicates;
0819   regex_t           rege;
0820 
0821   if (!rtems_rtl_check_opts (printer, "dsl", argc, argv))
0822     return 1;
0823 
0824   details = rtems_rtl_parse_opt ('l', argc, argv);
0825   symbols = rtems_rtl_parse_opt ('s', argc, argv);
0826   duplicates = rtems_rtl_parse_opt ('d', argc, argv);
0827 
0828   re_name = rtems_rtl_parse_arg (' ', NULL, argc, argv);
0829 
0830   if (re_name != NULL)
0831   {
0832     if (!rtems_rtl_regx_compile (printer,
0833                                  "name filter",
0834                                  &rege,
0835                                  re_name))
0836     {
0837       return false;
0838     }
0839   }
0840 
0841   rtl = rtems_rtl_lock ();
0842   if (rtl == NULL)
0843   {
0844     rtems_printf (printer, "error: cannot lock the linker\n");
0845     return 1;
0846   }
0847 
0848   node = rtems_chain_first (&rtl->archives.archives);
0849 
0850   while (!rtems_chain_is_tail (&rtl->archives.archives, node))
0851   {
0852     #define SYM_DUPLICATE (((size_t) 1) << ((8 * sizeof (size_t)) - 1))
0853 
0854     rtems_rtl_archive* archive = (rtems_rtl_archive*) node;
0855 
0856     if (re_name != NULL)
0857     {
0858       int r = rtems_rtl_regx_match (printer,
0859                                     "name match",
0860                                     &rege,
0861                                     archive->name);
0862       if (r < 0)
0863       {
0864         rtems_rtl_unlock ();
0865         return false;
0866       }
0867 
0868       if (r == 0)
0869       {
0870         node = rtems_chain_next (node);
0871         continue;
0872       }
0873     }
0874 
0875     rtems_printf (printer, "%s%c\n",
0876                   archive->name,
0877                   details | symbols | duplicates ? ':' : ' ');
0878 
0879     if (details)
0880     {
0881       rtems_printf (printer, "  size    : %zu\n", archive->size);
0882       rtems_printf (printer, "  symbols : %zu\n", archive->symbols.entries);
0883       rtems_printf (printer, "  refs    : %zu\n", archive->refs);
0884       rtems_printf (printer, "  flags   : %" PRIx32 "\n", archive->flags);
0885     }
0886 
0887     if (symbols)
0888     {
0889       const char* symbol = archive->symbols.names;
0890       int         indent = 0;
0891       size_t      s;
0892 
0893       rtems_printf (printer, "  symbols :");
0894 
0895       for (s = 0; s < archive->symbols.entries; ++s)
0896       {
0897         if (archive->symbols.symbols != NULL)
0898           symbol = archive->symbols.symbols[s].label;
0899 
0900         rtems_printf (printer, "%-*c%s\n", indent, ' ', symbol);
0901         indent = 12;
0902 
0903         if (archive->symbols.symbols == NULL)
0904           symbol += strlen (symbol) + 1;
0905       }
0906 
0907       if (indent == 0)
0908         rtems_printf (printer, "\n");
0909     }
0910 
0911     if (duplicates)
0912     {
0913       rtems_chain_node* match_node;
0914       int               indent = 0;
0915       bool              show_dups = true;
0916 
0917       match_node = rtems_chain_first (&rtl->archives.archives);
0918 
0919       while (!rtems_chain_is_tail (&rtl->archives.archives, match_node))
0920       {
0921         rtems_rtl_archive* match_archive = (rtems_rtl_archive*) match_node;
0922         const char*        symbol = archive->symbols.names;
0923         size_t             s;
0924 
0925         for (s = 0; s < archive->symbols.entries; ++s)
0926         {
0927           if (archive->symbols.symbols == NULL ||
0928               (archive->symbols.symbols[s].entry & SYM_DUPLICATE) == 0)
0929           {
0930             const char* match_symbol = match_archive->symbols.names;
0931             size_t      ms;
0932 
0933             if (archive->symbols.symbols != NULL)
0934               symbol = archive->symbols.symbols[s].label;
0935 
0936             for (ms = 0; ms < match_archive->symbols.entries; ++ms)
0937             {
0938               if (match_archive->symbols.symbols != NULL)
0939                 match_symbol = match_archive->symbols.symbols[ms].label;
0940 
0941               if (symbol != match_symbol && strcmp (symbol, match_symbol) == 0)
0942               {
0943                 if (show_dups)
0944                 {
0945                   show_dups = false;
0946                   rtems_printf (printer, "  dups    :");
0947                 }
0948                 rtems_printf (printer, "%-*c%s (%s)\n",
0949                               indent, ' ', symbol, archive->name);
0950                 indent = 12;
0951 
0952                 if (match_archive->symbols.symbols != NULL)
0953                   match_archive->symbols.symbols[ms].entry |= SYM_DUPLICATE;
0954               }
0955 
0956               if (match_archive->symbols.symbols == NULL)
0957                 match_symbol += strlen (match_symbol) + 1;
0958             }
0959           }
0960 
0961           if (archive->symbols.symbols == NULL)
0962             symbol += strlen (symbol) + 1;
0963         }
0964 
0965         match_node = rtems_chain_next (match_node);
0966       }
0967 
0968       if (indent == 0)
0969         rtems_printf (printer, "\n");
0970     }
0971 
0972     node = rtems_chain_next (node);
0973   }
0974 
0975   regfree (&rege);
0976 
0977   node = rtems_chain_first (&rtl->archives.archives);
0978 
0979   while (!rtems_chain_is_tail (&rtl->archives.archives, node))
0980   {
0981     rtems_rtl_archive* archive = (rtems_rtl_archive*) node;
0982     if (archive->symbols.symbols != NULL)
0983     {
0984       size_t s;
0985       for (s = 0; s < archive->symbols.entries; ++s)
0986         archive->symbols.symbols[s].entry &= ~SYM_DUPLICATE;
0987     }
0988     node = rtems_chain_next (node);
0989   }
0990 
0991   rtems_rtl_unlock ();
0992 
0993   return 0;
0994 }
0995 
0996 int
0997 rtems_rtl_shell_call (const rtems_printer* printer, int argc, char* argv[])
0998 {
0999   #define CALL_ARG_COUNT (4)
1000 
1001   typedef void (*csig_none)(void);
1002   typedef void (*csig_argv)(int argc, const char* argv[]);
1003   typedef void (*csig_s)(const char* str);
1004   typedef void (*csig_u)(unsigned int i1, unsigned int i2, unsigned int i3, unsigned int i4);
1005   typedef void (*csig_i)(int i1, int i2, int i3, int i4);
1006 
1007   union {
1008     char         s[64 + 1];
1009     unsigned int u[CALL_ARG_COUNT];
1010     int          i[CALL_ARG_COUNT];
1011   } values = { 0 };
1012   bool               keep_locked = false;
1013   bool               args_s = false;
1014   bool               args_i = false;
1015   bool               args_u = false;
1016   ssize_t            label;
1017   rtems_rtl_data*    rtl;
1018   rtems_rtl_obj_sym* sym;
1019   rtems_rtl_obj*     obj;
1020 
1021 
1022   if (!rtems_rtl_check_opts (printer, "lsui", argc, argv))
1023     return 1;
1024 
1025   keep_locked = rtems_rtl_parse_opt ('l', argc, argv);
1026   args_s = rtems_rtl_parse_opt ('s', argc, argv);
1027   args_u = rtems_rtl_parse_opt ('u', argc, argv);
1028   args_i = rtems_rtl_parse_opt ('i', argc, argv);
1029 
1030   if (args_s || args_u || args_i)
1031   {
1032     int c = 0;
1033     c += args_s ? 1 : 0;
1034     c += args_u ? 1 : 0;
1035     c += args_i ? 1 : 0;
1036     if (c > 1)
1037     {
1038       rtems_printf (printer,
1039                     "error: too many options, only one -sul at a time\n");
1040       return 1;
1041     }
1042   }
1043 
1044   label = rtems_rtl_parse_arg_index (' ', NULL, argc, argv);
1045   if (label < 0)
1046   {
1047     rtems_printf (printer, "error: no symbol found on command line\n");
1048     return 1;
1049   }
1050 
1051   if ((label + 1) < argc)
1052   {
1053     if (args_s)
1054     {
1055       size_t arg;
1056       for (arg = label + 1; arg < argc; ++arg)
1057       {
1058         size_t o = strlen (values.s);
1059         if (strlen (argv[arg]) + 1 >= (sizeof (values.s) - o))
1060         {
1061           rtems_printf (printer, "error: string args too big\n");
1062           return 1;
1063         }
1064         if (o > 0)
1065           values.s[o++] = ' ';
1066         strcat (values.s, argv[arg]);
1067       }
1068     }
1069     else if (args_u || args_i)
1070     {
1071       size_t arg;
1072       size_t i;
1073       if (argc > (label + 1 + CALL_ARG_COUNT))
1074       {
1075         rtems_printf (printer, "error: too many args\n");
1076         return 1;
1077       }
1078       for (i = 0, arg = label + 1; arg < argc; ++arg)
1079       {
1080         if (args_u)
1081           values.u[i] = strtoul (argv[arg], 0, 0);
1082         else
1083           values.i[i] = strtol (argv[arg], 0, 0);
1084         ++i;
1085       }
1086     }
1087   }
1088 
1089   rtl = rtems_rtl_lock ();
1090   if (rtl == NULL)
1091   {
1092     rtems_printf (printer, "error: cannot lock the linker\n");
1093     return 1;
1094   }
1095 
1096   sym = rtems_rtl_symbol_global_find (argv[label]);
1097   if (sym == NULL)
1098   {
1099     rtems_rtl_unlock ();
1100     rtems_printf (printer, "error: symbol not found: %s\n", argv[label]);
1101     return 1;
1102   }
1103 
1104   obj = rtems_rtl_find_obj_with_symbol (sym);
1105   if (obj == NULL)
1106   {
1107     rtems_rtl_unlock ();
1108     rtems_printf (printer, "error: symbol obj not found: %s\n", argv[label]);
1109     return 1;
1110   }
1111 
1112   if (!rtems_rtl_obj_text_inside (obj, (const void*) sym->value))
1113   {
1114     rtems_rtl_unlock ();
1115     rtems_printf (printer, "error: symbol not in obj text: %s\n", argv[label]);
1116     return 1;
1117   }
1118 
1119   /*
1120    * Lock the object file while it is being called.
1121    */
1122   rtems_rtl_obj_inc_reference (obj);
1123 
1124   rtems_rtl_unlock ();
1125 
1126   if (args_s)
1127   {
1128     csig_s call = (csig_s) sym->value;
1129     call (values.s);
1130   }
1131   else if (args_u)
1132   {
1133     csig_u call = (csig_u) sym->value;
1134     call (values.u[0], values.u[1], values.u[2], values.u[3]);
1135   }
1136   else if (args_i)
1137   {
1138     csig_i call = (csig_i) sym->value;
1139     call (values.i[0], values.i[1], values.i[2], values.i[3]);
1140   }
1141   else
1142   {
1143     int cargc = argc - (label + 1);
1144     if (cargc == 0)
1145     {
1146       csig_none call = (csig_none) sym->value;
1147       call ();
1148     }
1149     else
1150     {
1151       csig_argv   call = (csig_argv) sym->value;
1152       const char* cargv = argv[label + 1];
1153       call (cargc, &cargv);
1154     }
1155   }
1156 
1157   if (!keep_locked)
1158   {
1159     rtl = rtems_rtl_lock ();
1160     if (rtl == NULL)
1161     {
1162       rtems_printf (printer, "error: cannot lock the linker\n");
1163       return 1;
1164     }
1165 
1166     obj = rtems_rtl_find_obj_with_symbol (sym);
1167     if (obj == NULL)
1168     {
1169       rtems_rtl_unlock ();
1170       rtems_printf (printer, "error: symbol obj not found: %s\n", argv[label]);
1171       return 1;
1172     }
1173 
1174     rtems_rtl_obj_dec_reference (obj);
1175 
1176     rtems_rtl_unlock ();
1177   }
1178 
1179   return 0;
1180 }
1181 
1182 static void
1183 rtems_rtl_shell_usage (const rtems_printer* printer, const char* arg)
1184 {
1185   rtems_printf (printer, "%s: Runtime Linker\n", arg);
1186   rtems_printf (printer, "  %s [-hl] <command>\n", arg);
1187   rtems_printf (printer, "   where:\n");
1188   rtems_printf (printer, "     command: A n RTL command. See -l for a list plus help.\n");
1189   rtems_printf (printer, "     -h:      This help\n");
1190   rtems_printf (printer, "     -l:      The command list.\n");
1191 }
1192 
1193 int
1194 rtems_rtl_shell_command (int argc, char* argv[])
1195 {
1196   const rtems_rtl_shell_cmd table[] =
1197   {
1198     { "status", rtems_rtl_shell_status,
1199       "Display the status of the RTL" },
1200     { "list", rtems_rtl_shell_list,
1201       "\tList the object files currently loaded" },
1202     { "sym", rtems_rtl_shell_sym,
1203       "\tDisplay the symbols, sym [<name>], sym -o <obj> [<name>]" },
1204     { "obj", rtems_rtl_shell_object,
1205       "\tDisplay the object details, obj <name>" },
1206     { "call", rtems_rtl_shell_call,
1207       "\tCall a symbol" },
1208     { "ar", rtems_rtl_shell_archive,
1209       "\tDisplay the archive details, ar [-ls] <name>" },
1210     { "trace", rtems_rtl_trace_shell_command,
1211       "\tControl the RTL trace flags, trace [-h]" }
1212   };
1213 
1214   rtems_printer printer;
1215   int           arg;
1216   int           t;
1217 
1218   rtems_print_printer_printf (&printer);
1219 
1220   for (arg = 1; arg < argc; arg++)
1221   {
1222     if (argv[arg][0] != '-')
1223       break;
1224 
1225     switch (argv[arg][1])
1226     {
1227       case 'h':
1228         rtems_rtl_shell_usage (&printer, argv[0]);
1229         return 0;
1230       case 'l':
1231         rtems_printf (&printer, "%s: commands are:\n", argv[0]);
1232         for (t = 0;
1233              t < (sizeof (table) / sizeof (const rtems_rtl_shell_cmd));
1234              ++t)
1235           rtems_printf (&printer, "  %s\t%s\n", table[t].name, table[t].help);
1236         return 0;
1237       default:
1238         rtems_printf (&printer, "error: unknown option: %s\n", argv[arg]);
1239         return 1;
1240     }
1241   }
1242 
1243   if ((argc - arg) < 1)
1244     rtems_printf (&printer, "error: you need to provide a command, try %s -h\n",
1245                   argv[0]);
1246   else
1247   {
1248     for (t = 0;
1249          t < (sizeof (table) / sizeof (const rtems_rtl_shell_cmd));
1250          ++t)
1251     {
1252       if (strncmp (argv[arg], table[t].name, strlen (argv[arg])) == 0)
1253         return table[t].handler (&printer, argc - 1, argv + 1);
1254     }
1255     rtems_printf (&printer, "error: command not found: %s (try -h)\n", argv[arg]);
1256   }
1257 
1258   return 1;
1259 }