source: rtems/cpukit/libdl/rtl-shell.c @ b36c5209

Last change on this file since b36c5209 was b36c5209, checked in by Chris Johns <chrisj@…>, on May 3, 2019 at 12:15:20 AM

libdl: Do not access the ELF file while the allocator is locked.

  • Load symbols before allocation.
  • Parse reloc records and place any reloc recs in a cache to use while the allocator is locked.
  • Relocate symbols after section allocation.
  • Split section loading into allocation/locating and loading.
  • Update all arch back-ends with a new reloc interface to control tramp handling.
  • Add -a and -t to the object list shell command.

Closes #3741

  • Property mode set to 100644
File size: 32.4 KB
Line 
1/*
2 *  COPYRIGHT (c) 2012, 2018 Chris Johns <chrisj@rtems.org>
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.org/license/LICENSE.
7 */
8/**
9 * @file
10 *
11 * @ingroup rtems_rtld
12 *
13 * @brief RTEMS Run-Time Link Editor Shell Commands
14 *
15 * A simple RTL command to aid using the RTL.
16 */
17
18#if HAVE_CONFIG_H
19#include "config.h"
20#endif
21
22#include <inttypes.h>
23#include <rtems/inttypes.h>
24
25#include <sys/stat.h>
26#include <regex.h>
27#include <string.h>
28
29#include <dlfcn.h>
30
31#include <rtems/printer.h>
32#include <rtems/rtl/rtl.h>
33#include <rtems/rtl/rtl-archive.h>
34#include <rtems/rtl/rtl-shell.h>
35#include <rtems/rtl/rtl-trace.h>
36#include "rtl-chain-iterator.h"
37
38/**
39 * The type of the shell handlers we have.
40 */
41typedef int (*rtems_rtl_shell_handler) (const rtems_printer* printer, int argc, char *argv[]);
42
43/**
44 * Table of handlers we parse to invoke the command.
45 */
46typedef struct
47{
48  const char*             name;    /**< The sub-command's name. */
49  rtems_rtl_shell_handler handler; /**< The sub-command's handler. */
50  const char*             help;    /**< The sub-command's help. */
51} rtems_rtl_shell_cmd;
52
53/**
54 * Object summary data.
55 */
56typedef struct
57{
58  int    count;   /**< The number of object files. */
59  size_t exec;    /**< The amount of executable memory allocated. */
60  size_t symbols; /**< The amount of symbol memory allocated. */
61} rtems_rtl_obj_summary;
62
63/**
64 * Object summary iterator.
65 */
66static bool
67rtems_rtl_obj_summary_iterator (rtems_chain_node* node, void* data)
68{
69  rtems_rtl_obj_summary* summary = data;
70  rtems_rtl_obj*         obj = (rtems_rtl_obj*) node;
71  ++summary->count;
72  summary->exec += obj->exec_size;
73  summary->symbols += obj->global_size;
74  return true;
75}
76
77/**
78 * Count the number of symbols.
79 */
80static int
81rtems_rtl_count_symbols (rtems_rtl_data* rtl)
82{
83  int count;
84  int bucket;
85  for (count = 0, bucket = 0; bucket < rtl->globals.nbuckets; ++bucket)
86    count += rtems_rtl_chain_count (&rtl->globals.buckets[bucket]);
87  return count;
88}
89
90static int
91rtems_rtl_shell_status (const rtems_printer* printer,
92                        int                  argc,
93                        char*                argv[])
94{
95  rtems_rtl_obj_summary summary;
96  size_t                total_memory;
97  rtems_rtl_data*       rtl;
98
99  rtl = rtems_rtl_lock ();
100  if (rtl == NULL)
101  {
102    rtems_printf (printer, "error: cannot lock the linker\n");
103    return 1;
104  }
105
106  summary.count   = 0;
107  summary.exec    = 0;
108  summary.symbols = 0;
109  rtems_rtl_chain_iterate (&rtl->objects,
110                           rtems_rtl_obj_summary_iterator,
111                           &summary);
112  /*
113   * Currently does not include the name strings in the obj struct.
114   */
115  total_memory =
116    sizeof (*rtl) + (summary.count * sizeof (rtems_rtl_obj)) +
117    summary.exec + summary.symbols;
118
119  rtems_printf (printer, "Runtime Linker Status:\n");
120  rtems_printf (printer, "        paths: %s\n", rtl->paths);
121  rtems_printf (printer, "      objects: %d\n", summary.count);
122  rtems_printf (printer, " total memory: %zi\n", total_memory);
123  rtems_printf (printer, "  exec memory: %zi\n", summary.exec);
124  rtems_printf (printer, "   sym memory: %zi\n", summary.symbols);
125  rtems_printf (printer, "      symbols: %d\n", rtems_rtl_count_symbols (rtl));
126
127  rtems_rtl_unlock ();
128
129  return 0;
130}
131
132/**
133 * Object print data.
134 */
135typedef struct
136{
137  const rtems_printer* printer;      /**< The RTEMS printer. */
138  rtems_rtl_data*      rtl;          /**< The RTL data. */
139  int                  indent;       /**< Spaces to indent. */
140  bool                 oname;        /**< Print object names. */
141  bool                 names;        /**< Print details of all names. */
142  bool                 stats;        /**< Print stats. */
143  bool                 memory_map;   /**< Print the memory map. */
144  bool                 symbols;      /**< Print the global symbols. */
145  bool                 dependencies; /**< Print any dependencies. */
146  bool                 trampolines;  /**< Print trampoline stats. */
147  bool                 base;         /**< Include the base object file. */
148  const char*          re_name;      /**< Name regx to filter on. */
149  const char*          re_symbol;    /**< Symbol regx to filter on. */
150} rtems_rtl_obj_print;
151
152/**
153 * Parse an argument.
154 */
155static bool
156rtems_rtl_parse_opt (const char opt, int argc, char *argv[])
157{
158  size_t arg;
159  for (arg = 1; arg < argc; ++arg)
160  {
161    if (argv[arg][0] == '-')
162    {
163      size_t len = strlen (argv[arg]);
164      size_t i;
165      for (i = 1; i < len; ++i)
166        if (argv[arg][i] == opt)
167          return true;
168    }
169  }
170  return false;
171}
172
173static bool
174rtems_rtl_check_opts (const rtems_printer* printer,
175                      const char*          opts,
176                      int                  argc,
177                      char*                argv[])
178{
179  size_t olen = strlen (opts);
180  size_t arg;
181  for (arg = 1; arg < argc; ++arg)
182  {
183    if (argv[arg][0] == '-')
184    {
185      size_t len = strlen (argv[arg]);
186      size_t i;
187      for (i = 1; i < len; ++i)
188      {
189        bool found = false;
190        size_t       o;
191        for (o = 0; o < olen; ++o)
192        {
193          if (argv[arg][i] == opts[o])
194          {
195            found = true;
196            break;
197          }
198        }
199        if (!found)
200        {
201          rtems_printf (printer, "error: invalid option: %c (%s)\n",
202                        argv[arg][i], argv[arg]);
203          return false;
204        }
205      }
206    }
207  }
208  return true;
209}
210
211static ssize_t
212rtems_rtl_parse_arg_index (const char  opt,
213                           const char* skip_opts,
214                           int         argc,
215                           char*       argv[])
216{
217  ssize_t arg;
218  for (arg = 1; arg < argc; ++arg)
219  {
220    if (argv[arg][0] == '-')
221    {
222      /*
223       * We can check the next char because there has to be a valid char or a
224       * nul.
225       */
226      if (argv[arg][1] != '\0')
227      {
228        size_t len = skip_opts != NULL ? strlen (skip_opts) : 0;
229        size_t i;
230        for (i = 0; i < len; ++i)
231        {
232          if (skip_opts[i] == argv[arg][1])
233          {
234            ++arg;
235            break;
236          }
237        }
238      }
239    }
240    else
241    {
242      if (opt == ' ')
243        return arg;
244    }
245    /*
246     * Is this an option and does it match what we are looking for?
247     */
248    if (argv[arg][0] == '-' && argv[arg][1] == opt && arg < argc)
249      return arg + 1;
250  }
251  return -1;
252}
253
254static const char*
255rtems_rtl_parse_arg (const char  opt,
256                     const char* skip_opts,
257                     int         argc,
258                     char*       argv[])
259{
260  ssize_t arg = rtems_rtl_parse_arg_index (opt, skip_opts, argc, argv);
261  if (arg < 0)
262    return NULL;
263  return argv[arg];
264}
265
266/**
267 * Regx matching.
268 */
269static bool
270rtems_rtl_regx_compile (const rtems_printer* printer,
271                        const char*          label,
272                        regex_t*             rege,
273                        const char*          expression)
274{
275  int r = regcomp (rege, expression, REG_EXTENDED | REG_NOSUB);
276  if (r != 0)
277  {
278    char rerror[128];
279    regerror (r, rege, rerror, sizeof(rerror));
280    rtems_printf (printer, "error: %s: %s\n", label, rerror);
281    return false;
282  }
283  return true;
284}
285
286static int
287rtems_rtl_regx_match (const rtems_printer* printer,
288                      const char*          label,
289                      regex_t*             rege,
290                      const char*          string)
291{
292  int r = regexec (rege, string, 0, NULL, 0);
293  if (r != 0 && r != REG_NOMATCH)
294  {
295    char rerror[128];
296    regerror (r, rege, rerror, sizeof(rerror));
297    rtems_printf (printer, "error: %s: %s\n", label, rerror);
298    regfree (rege);
299    return -1;
300  }
301  return r == 0 ? 1 : 0;
302}
303
304/**
305 * Print the obj name.
306 */
307static void
308rtems_rtl_print_obj_name (const rtems_rtl_obj_print* print, rtems_rtl_obj* obj)
309{
310  rtems_printf (print->printer, "%-*c", print->indent, ' ');
311  if (rtems_rtl_obj_aname (obj) != NULL)
312    rtems_printf (print->printer, "%s:", rtems_rtl_obj_aname (obj));
313  rtems_printf (print->printer, "%s\n", rtems_rtl_obj_oname (obj));
314}
315
316/**
317 * Print symbols.
318 */
319static bool
320rtems_rtl_print_symbols (rtems_rtl_obj_print* print,
321                         rtems_rtl_obj*       obj,
322                         int                  indent,
323                         bool                 show_name)
324{
325  regex_t rege;
326  int     max_len = 0;
327  int     s;
328
329  if (print->re_symbol != NULL &&
330      !rtems_rtl_regx_compile (print->printer,
331                               "symbol filter",
332                               &rege, print->re_symbol))
333  {
334    return false;
335  }
336
337  for (s = 0; s < obj->global_syms; ++s)
338  {
339    const char* sym = obj->global_table[s].name;
340    int         len;
341
342    if (print->re_symbol != NULL)
343    {
344      int r = rtems_rtl_regx_match (print->printer, "symbol match", &rege, sym);
345      if (r < 0)
346        return false;
347      if (!r)
348        continue;
349    }
350
351    len = strlen (obj->global_table[s].name);
352    if (len > max_len)
353      max_len = len;
354  }
355
356  for (s = 0; s < obj->global_syms; ++s)
357  {
358    const char* sym = obj->global_table[s].name;
359    if (print->re_symbol != NULL)
360    {
361      int r = rtems_rtl_regx_match (print->printer, "symbol match", &rege, sym);
362      if (r < 0)
363        return false;
364      if (r == 0)
365        continue;
366    }
367    if (show_name)
368    {
369      show_name = false;
370      rtems_rtl_print_obj_name (print, obj);
371    }
372    rtems_printf (print->printer, "%-*c%-*s = %p\n", indent + 2, ' ',
373                  max_len, sym, obj->global_table[s].value);
374  }
375
376  regfree (&rege);
377
378  return true;
379}
380
381/**
382 * Dependencies printer.
383 */
384typedef struct
385{
386  const rtems_rtl_obj_print* print;     /**< The print data. */
387  bool                       first;     /**< Is this the first line printed. */
388  bool                       show_name; /**< Show the object name. */
389  size_t                     indent;    /**< The indent. */
390} rtems_rtl_dep_data;
391
392static bool
393rtems_rtl_dependencies (rtems_rtl_obj* obj, rtems_rtl_obj* dependent, void* data)
394{
395  rtems_rtl_dep_data* dd = (rtems_rtl_dep_data*) data;
396  if (dd->first)
397  {
398    dd->first = false;
399    if (dd->show_name)
400    {
401      dd->show_name = false;
402      rtems_rtl_print_obj_name (dd->print, obj);
403    }
404    rtems_printf (dd->print->printer, "%-*cdependencies  : ", dd->indent, ' ');
405    dd->indent += strlen ("dependencies :");
406  }
407  else
408  {
409    rtems_printf (dd->print->printer, "\n%-*c: ", (int) dd->indent, ' ');
410  }
411  rtems_printf (dd->print->printer, "%s", dependent->oname);
412  return false;
413}
414
415/**
416 * Object printer.
417 */
418static bool
419rtems_rtl_obj_printer (rtems_rtl_obj_print* print, rtems_rtl_obj* obj)
420{
421  char flags_str[33];
422  int  indent = print->indent + 1;
423  bool show_name = true;
424
425  /*
426   * Skip the base module unless asked to show it.
427   */
428  if (!print->base && (obj == print->rtl->base))
429      return true;
430
431  if (print->re_name != NULL)
432  {
433    regex_t rege;
434    int     r = 0;
435
436    if (!rtems_rtl_regx_compile (print->printer,
437                                 "name filter",
438                                 &rege, print->re_name))
439    {
440      return false;
441    }
442
443    if (rtems_rtl_obj_aname (obj) != NULL)
444    {
445      r = rtems_rtl_regx_match (print->printer,
446                                "aname match",
447                                &rege,
448                                rtems_rtl_obj_aname (obj));
449      if (r < 0)
450        return false;
451    }
452
453    if (r == 0)
454    {
455      r = rtems_rtl_regx_match (print->printer,
456                                "oname match",
457                                &rege,
458                                rtems_rtl_obj_oname (obj));
459      if (r < 0)
460        return false;
461    }
462
463    regfree (&rege);
464
465    if (r == 0)
466      return true;
467  }
468
469  if (print->names || print->memory_map || print->stats ||
470      (!print->names && !print->memory_map && !print->stats &&
471       !print->symbols && !print->dependencies))
472  {
473    show_name = false;
474    rtems_rtl_print_obj_name (print, obj);
475  }
476
477  if (print->names)
478  {
479    rtems_printf (print->printer,
480                  "%-*cfile name     : %s\n",
481                  indent, ' ', rtems_rtl_obj_fname (obj));
482    rtems_printf (print->printer,
483                  "%-*carchive name  : %s\n",
484                  indent, ' ', rtems_rtl_obj_aname (obj));
485    strcpy (flags_str, "--");
486    if (obj->flags & RTEMS_RTL_OBJ_LOCKED)
487      flags_str[0] = 'L';
488    if (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED)
489      flags_str[1] = 'U';
490    rtems_printf (print->printer,
491                  "%-*cflags         : %s\n", indent, ' ', flags_str);
492    rtems_printf (print->printer,
493                  "%-*cfile offset   : %" PRIdoff_t "\n", indent, ' ', obj->ooffset);
494    rtems_printf (print->printer,
495                  "%-*cfile size     : %zi\n", indent, ' ', obj->fsize);
496  }
497  if (print->memory_map)
498  {
499    rtems_printf (print->printer,
500                  "%-*cexec size     : %zi\n", indent, ' ', obj->exec_size);
501    rtems_printf (print->printer,
502                  "%-*ctext base     : %p (%zi)\n", indent, ' ',
503                  obj->text_base, obj->text_size);
504    rtems_printf (print->printer,
505                  "%-*cconst base    : %p (%zi)\n", indent, ' ',
506                  obj->const_base, obj->const_size);
507    rtems_printf (print->printer,
508                  "%-*cdata base     : %p (%zi)\n", indent, ' ',
509                  obj->data_base, obj->data_size);
510    rtems_printf (print->printer,
511                  "%-*cbss base      : %p (%zi)\n", indent, ' ',
512                  obj->bss_base, obj->bss_size);
513  }
514  if (print->stats)
515  {
516    rtems_printf (print->printer, "%-*cunresolved    : %zu\n", indent, ' ', obj->unresolved);
517    rtems_printf (print->printer, "%-*cusers         : %zu\n", indent, ' ', obj->users);
518    rtems_printf (print->printer, "%-*creferences    : %zu\n", indent, ' ', obj->refs);
519    rtems_printf (print->printer, "%-*ctrampolines   : %zu\n", indent, ' ',
520                  rtems_rtl_obj_trampolines (obj));
521    rtems_printf (print->printer, "%-*csymbols       : %zi\n", indent, ' ', obj->global_syms);
522    rtems_printf (print->printer, "%-*csymbol memory : %zi\n", indent, ' ', obj->global_size);
523  }
524  if (print->symbols)
525  {
526    if (!rtems_rtl_print_symbols (print, obj, indent, show_name))
527      return false;
528  }
529  if (print->dependencies)
530  {
531    rtems_rtl_dep_data dd = {
532      .print = print,
533      .first = true,
534      .show_name = show_name,
535      .indent = indent
536    };
537    rtems_rtl_obj_iterate_dependents (obj, rtems_rtl_dependencies, &dd);
538    if (!dd.first)
539      rtems_printf (print->printer, "\n");
540  }
541  if (print->trampolines)
542  {
543    if (obj->tramp_size == 0)
544    {
545      rtems_printf (print->printer, "%-*ctrampolines: not supported\n", indent, ' ');
546    }
547    else
548    {
549      size_t slots = rtems_rtl_obj_trampoline_slots (obj);
550      size_t used = rtems_rtl_obj_trampolines (obj);
551      rtems_printf (print->printer, "%-*ctrampolines:\n", indent, ' ');
552      rtems_printf (print->printer, "%-*cslots     : %zu\n", indent + 4, ' ',
553                    slots);
554      rtems_printf (print->printer, "%-*csize      : %zu\n", indent + 4, ' ',
555                    obj->tramps_size);
556      rtems_printf (print->printer, "%-*cslot size : %zu\n", indent + 4, ' ',
557                    obj->tramp_size);
558      rtems_printf (print->printer, "%-*cused      : %zu\n", indent + 4, ' ',
559                    used);
560      rtems_printf (print->printer, "%-*crelocs    : %zu\n", indent + 4, ' ',
561                    obj->tramp_relocs);
562      rtems_printf (print->printer, "%-*cunresolved: %zu\n", indent + 4, ' ',
563                    slots - obj->tramp_relocs);
564      rtems_printf (print->printer, "%-*cyield     : %zu%%\n", indent + 4, ' ',
565                    slots ? (used * 100) / slots : 0);
566    }
567  }
568  return true;
569}
570
571/**
572 * Object unresolved symbols printer.
573 */
574static bool
575rtems_rtl_unresolved_printer (rtems_rtl_unresolv_rec* rec,
576                              void*                   data)
577{
578  rtems_rtl_obj_print* print = (rtems_rtl_obj_print*) data;
579  if (rec->type == rtems_rtl_unresolved_symbol)
580    rtems_printf (print->printer,
581                  "%-*c%s\n", print->indent + 2, ' ', rec->rec.name.name);
582  return false;
583}
584
585/**
586 * Object print iterator.
587 */
588static bool
589rtems_rtl_obj_print_iterator (rtems_chain_node* node, void* data)
590{
591  rtems_rtl_obj_print* print = data;
592  rtems_rtl_obj*       obj = (rtems_rtl_obj*) node;
593  return rtems_rtl_obj_printer (print, obj);
594}
595
596int
597rtems_rtl_shell_list (const rtems_printer* printer, int argc, char* argv[])
598{
599  rtems_rtl_obj_print print = { 0 };
600  if (!rtems_rtl_check_opts (printer, "anlmsdbt", argc, argv))
601    return 1;
602  print.printer = printer;
603  print.indent = 1;
604  print.oname = true;
605  if (rtems_rtl_parse_opt ('a', argc, argv))
606  {
607    print.names = true;
608    print.stats = true;
609    print.memory_map = true;
610    print.symbols = true;
611    print.dependencies = true;
612    print.trampolines = true;
613  }
614  else
615  {
616    print.names = rtems_rtl_parse_opt ('n', argc, argv);
617    print.stats = rtems_rtl_parse_opt ('l', argc, argv);;
618    print.memory_map = rtems_rtl_parse_opt ('m', argc, argv);;
619    print.symbols = rtems_rtl_parse_opt ('s', argc, argv);
620    print.dependencies = rtems_rtl_parse_opt ('d', argc, argv);;
621    print.trampolines = rtems_rtl_parse_opt ('t', argc, argv);;
622    print.base = rtems_rtl_parse_opt ('b', argc, argv);;
623    print.re_name = rtems_rtl_parse_arg (' ', NULL, argc, argv);
624  }
625  print.re_symbol = NULL;
626  print.rtl = rtems_rtl_lock ();
627  if (print.rtl == NULL)
628  {
629    rtems_printf (print.printer, "error: cannot lock the linker\n");
630    return 1;
631  }
632  rtems_rtl_chain_iterate (&print.rtl->objects,
633                           rtems_rtl_obj_print_iterator,
634                           &print);
635  rtems_rtl_unlock ();
636  return 0;
637}
638
639int
640rtems_rtl_shell_sym (const rtems_printer* printer, int argc, char* argv[])
641{
642  rtems_rtl_obj_print print = { 0 };
643  if (!rtems_rtl_check_opts (printer, "buo", argc, argv))
644    return 1;
645  print.printer = printer;
646  print.indent = 1;
647  print.oname = true;
648  print.names = false;
649  print.stats = false;
650  print.memory_map = false;
651  print.symbols = !rtems_rtl_parse_opt ('u', argc, argv);;
652  print.dependencies = false;
653  print.base = rtems_rtl_parse_opt ('b', argc, argv);
654  print.re_name = rtems_rtl_parse_arg ('o', NULL, argc, argv);;
655  print.re_symbol = rtems_rtl_parse_arg (' ', "ou", argc, argv);
656  print.rtl = rtems_rtl_lock ();
657  if (print.rtl == NULL)
658  {
659    rtems_printf (print.printer, "error: cannot lock the linker\n");
660    return 1;
661  }
662  if (print.symbols)
663  {
664    rtems_rtl_chain_iterate (&print.rtl->objects,
665                             rtems_rtl_obj_print_iterator,
666                             &print);
667  }
668  if (rtems_rtl_parse_opt ('u', argc, argv))
669  {
670    rtems_printf (printer, "Unresolved:\n");
671    rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_printer, &print);
672  }
673  rtems_rtl_unlock ();
674  return 0;
675}
676
677int
678rtems_rtl_shell_object (const rtems_printer* printer, int argc, char* argv[])
679{
680  size_t arg;
681
682  --argc;
683  ++argv;
684
685  for (arg = 0; arg < argc; ++arg)
686  {
687    if (argv[arg][0] == '-')
688    {
689      switch (argv[arg][1])
690      {
691        case 'h':
692        case '?':
693          rtems_printf (printer, "obj commands:\n");
694          rtems_printf (printer, " load <file>\n");
695          rtems_printf (printer, " unload <file>\n");
696          break;
697        default:
698          rtems_printf (printer, "error: invalid option: %s\n", argv[arg]);
699          return 1;
700      }
701    }
702    else
703    {
704      break;
705    }
706  }
707
708  if (arg >= argc)
709  {
710    rtems_printf (printer, "error: no obj command\n");
711    return 1;
712  }
713
714  if (strcmp (argv[arg], "load") == 0)
715  {
716    void* handle;
717    int   unresolved;
718
719    ++arg;
720    if (arg >= argc)
721    {
722      rtems_printf (printer, "error: no object file to load\n");
723      return 1;
724    }
725
726    handle = dlopen (argv[arg], RTLD_NOW | RTLD_GLOBAL);
727    if (handle == NULL)
728    {
729      rtems_printf (printer, "error: load: %s: %s\n", argv[arg], dlerror ());
730      return 1;
731    }
732
733    if (dlinfo (RTLD_SELF, RTLD_DI_UNRESOLVED, &unresolved) < 0)
734    {
735      rtems_printf (printer, "error: %s: %s\n", argv[arg], dlerror ());
736      return 1;
737    }
738
739    if (unresolved != 0)
740    {
741      rtems_printf (printer, "warning: unresolved symbols present\n");
742      return 1;
743    }
744  }
745  else if (strcmp (argv[arg], "unload") == 0)
746  {
747    rtems_rtl_data* rtl;
748    rtems_rtl_obj*  obj;
749
750    ++arg;
751    if (arg >= argc)
752    {
753      rtems_printf (printer, "error: no object file to load\n");
754      return 1;
755    }
756
757    rtl = rtems_rtl_lock ();
758    if (rtl == NULL)
759    {
760      rtems_printf (printer, "error: cannot lock RTL\n");
761      return 1;
762    }
763
764    obj = rtems_rtl_find_obj (argv[arg]);
765    if (obj == NULL)
766    {
767      rtems_rtl_unlock ();
768      rtems_printf (printer, "error: unload: %s: %s\n", argv[arg], dlerror ());
769      return 1;
770    }
771
772    if (!rtems_rtl_unload (obj))
773    {
774      rtems_rtl_unlock ();
775      rtems_printf (printer, "error: unload: %s: %s\n", argv[arg], dlerror ());
776      return 1;
777    }
778
779    rtems_rtl_unlock ();
780  }
781  else
782  {
783    rtems_printf (printer, "error: unknown obj command: %s\n", argv[arg]);
784    return 1;
785  }
786
787  return 0;
788}
789
790int
791rtems_rtl_shell_archive (const rtems_printer* printer, int argc, char* argv[])
792{
793  rtems_rtl_data*   rtl;
794  rtems_chain_node* node;
795  const char*       re_name;
796  bool              details;
797  bool              symbols;
798  bool              duplicates;
799  regex_t           rege;
800
801  if (!rtems_rtl_check_opts (printer, "dsl", argc, argv))
802    return 1;
803
804  details = rtems_rtl_parse_opt ('l', argc, argv);
805  symbols = rtems_rtl_parse_opt ('s', argc, argv);
806  duplicates = rtems_rtl_parse_opt ('d', argc, argv);
807
808  re_name = rtems_rtl_parse_arg (' ', NULL, argc, argv);
809
810  if (re_name != NULL)
811  {
812    if (!rtems_rtl_regx_compile (printer,
813                                 "name filter",
814                                 &rege,
815                                 re_name))
816    {
817      return false;
818    }
819  }
820
821  rtl = rtems_rtl_lock ();
822  if (rtl == NULL)
823  {
824    rtems_printf (printer, "error: cannot lock the linker\n");
825    return 1;
826  }
827
828  node = rtems_chain_first (&rtl->archives.archives);
829
830  while (!rtems_chain_is_tail (&rtl->archives.archives, node))
831  {
832    #define SYM_DUPLICATE (1 << ((8 * sizeof (size_t)) - 1))
833
834    rtems_rtl_archive* archive = (rtems_rtl_archive*) node;
835
836    if (re_name != NULL)
837    {
838      int r = rtems_rtl_regx_match (printer,
839                                    "name match",
840                                    &rege,
841                                    archive->name);
842      if (r < 0)
843      {
844        rtems_rtl_unlock ();
845        return false;
846      }
847
848      if (r == 0)
849      {
850        node = rtems_chain_next (node);
851        continue;
852      }
853    }
854
855    rtems_printf (printer, "%s%c\n",
856                  archive->name,
857                  details | symbols | duplicates ? ':' : ' ');
858
859    if (details)
860    {
861      rtems_printf (printer, "  size    : %zu\n", archive->size);
862      rtems_printf (printer, "  symbols : %zu\n", archive->symbols.entries);
863      rtems_printf (printer, "  refs    : %zu\n", archive->refs);
864      rtems_printf (printer, "  flags   : %" PRIx32 "\n", archive->flags);
865    }
866
867    if (symbols)
868    {
869      const char* symbol = archive->symbols.names;
870      int         indent = 0;
871      size_t      s;
872
873      rtems_printf (printer, "  symbols :");
874
875      for (s = 0; s < archive->symbols.entries; ++s)
876      {
877        if (archive->symbols.symbols != NULL)
878          symbol = archive->symbols.symbols[s].label;
879
880        rtems_printf (printer, "%-*c%s\n", indent, ' ', symbol);
881        indent = 12;
882
883        if (archive->symbols.symbols == NULL)
884          symbol += strlen (symbol) + 1;
885      }
886
887      if (indent == 0)
888        rtems_printf (printer, "\n");
889    }
890
891    if (duplicates)
892    {
893      rtems_chain_node* match_node;
894      int               indent = 0;
895      bool              show_dups = true;
896
897      match_node = rtems_chain_first (&rtl->archives.archives);
898
899      while (!rtems_chain_is_tail (&rtl->archives.archives, match_node))
900      {
901        rtems_rtl_archive* match_archive = (rtems_rtl_archive*) match_node;
902        const char*        symbol = archive->symbols.names;
903        size_t             s;
904
905        for (s = 0; s < archive->symbols.entries; ++s)
906        {
907          if (archive->symbols.symbols == NULL ||
908              (archive->symbols.symbols[s].entry & SYM_DUPLICATE) == 0)
909          {
910            const char* match_symbol = match_archive->symbols.names;
911            size_t      ms;
912
913            if (archive->symbols.symbols != NULL)
914              symbol = archive->symbols.symbols[s].label;
915
916            for (ms = 0; ms < match_archive->symbols.entries; ++ms)
917            {
918              if (match_archive->symbols.symbols != NULL)
919                match_symbol = match_archive->symbols.symbols[ms].label;
920
921              if (symbol != match_symbol && strcmp (symbol, match_symbol) == 0)
922              {
923                if (show_dups)
924                {
925                  show_dups = false;
926                  rtems_printf (printer, "  dups    :");
927                }
928                rtems_printf (printer, "%-*c%s (%s)\n",
929                              indent, ' ', symbol, archive->name);
930                indent = 12;
931
932                if (match_archive->symbols.symbols != NULL)
933                  match_archive->symbols.symbols[ms].entry |= SYM_DUPLICATE;
934              }
935
936              if (match_archive->symbols.symbols == NULL)
937                match_symbol += strlen (match_symbol) + 1;
938            }
939          }
940
941          if (archive->symbols.symbols == NULL)
942            symbol += strlen (symbol) + 1;
943        }
944
945        match_node = rtems_chain_next (match_node);
946      }
947
948      if (indent == 0)
949        rtems_printf (printer, "\n");
950    }
951
952    node = rtems_chain_next (node);
953  }
954
955  regfree (&rege);
956
957  node = rtems_chain_first (&rtl->archives.archives);
958
959  while (!rtems_chain_is_tail (&rtl->archives.archives, node))
960  {
961    rtems_rtl_archive* archive = (rtems_rtl_archive*) node;
962    if (archive->symbols.symbols != NULL)
963    {
964      size_t s;
965      for (s = 0; s < archive->symbols.entries; ++s)
966        archive->symbols.symbols[s].entry &= ~SYM_DUPLICATE;
967    }
968    node = rtems_chain_next (node);
969  }
970
971  rtems_rtl_unlock ();
972
973  return 0;
974}
975
976int
977rtems_rtl_shell_call (const rtems_printer* printer, int argc, char* argv[])
978{
979  #define CALL_ARG_COUNT (4)
980
981  typedef void (*csig_none)(void);
982  typedef void (*csig_argv)(int argc, const char* argv[]);
983  typedef void (*csig_s)(const char* str);
984  typedef void (*csig_u)(unsigned int i1, unsigned int i2, unsigned int i3, unsigned int i4);
985  typedef void (*csig_i)(int i1, int i2, int i3, int i4);
986
987  union {
988    char         s[64 + 1];
989    unsigned int u[CALL_ARG_COUNT];
990    int          i[CALL_ARG_COUNT];
991  } values = { 0 };
992  bool               keep_locked = false;
993  bool               args_s = false;
994  bool               args_i = false;
995  bool               args_u = false;
996  ssize_t            label;
997  rtems_rtl_data*    rtl;
998  rtems_rtl_obj_sym* sym;
999  rtems_rtl_obj*     obj;
1000
1001
1002  if (!rtems_rtl_check_opts (printer, "lsui", argc, argv))
1003    return 1;
1004
1005  keep_locked = rtems_rtl_parse_opt ('l', argc, argv);
1006  args_s = rtems_rtl_parse_opt ('s', argc, argv);
1007  args_u = rtems_rtl_parse_opt ('u', argc, argv);
1008  args_i = rtems_rtl_parse_opt ('i', argc, argv);
1009
1010  if (args_s || args_u || args_i)
1011  {
1012    int c = 0;
1013    c += args_s ? 1 : 0;
1014    c += args_u ? 1 : 0;
1015    c += args_i ? 1 : 0;
1016    if (c > 1)
1017    {
1018      rtems_printf (printer,
1019                    "error: too many options, only one -sul at a time\n");
1020      return 1;
1021    }
1022  }
1023
1024  label = rtems_rtl_parse_arg_index (' ', NULL, argc, argv);
1025  if (label < 0)
1026  {
1027    rtems_printf (printer, "error: no symbol found on command line\n");
1028    return 1;
1029  }
1030
1031  if ((label + 1) < argc)
1032  {
1033    if (args_s)
1034    {
1035      size_t arg;
1036      for (arg = label + 1; arg < argc; ++arg)
1037      {
1038        size_t o = strlen (values.s);
1039        if (strlen (argv[arg]) + 1 >= (sizeof (values.s) - o))
1040        {
1041          rtems_printf (printer, "error: string args too big\n");
1042          return 1;
1043        }
1044        if (o > 0)
1045          values.s[o++] = ' ';
1046        strcat (values.s, argv[arg]);
1047      }
1048    }
1049    else if (args_u || args_i)
1050    {
1051      size_t arg;
1052      size_t i;
1053      if (argc > (label + 1 + CALL_ARG_COUNT))
1054      {
1055        rtems_printf (printer, "error: too many args\n");
1056        return 1;
1057      }
1058      for (i = 0, arg = label + 1; arg < argc; ++arg)
1059      {
1060        if (args_u)
1061          values.u[i] = strtoul (argv[arg], 0, 0);
1062        else
1063          values.i[i] = strtol (argv[arg], 0, 0);
1064        ++i;
1065      }
1066    }
1067  }
1068
1069  rtl = rtems_rtl_lock ();
1070  if (rtl == NULL)
1071  {
1072    rtems_printf (printer, "error: cannot lock the linker\n");
1073    return 1;
1074  }
1075
1076  sym = rtems_rtl_symbol_global_find (argv[label]);
1077  if (sym == NULL)
1078  {
1079    rtems_rtl_unlock ();
1080    rtems_printf (printer, "error: symbol not found: %s\n", argv[label]);
1081    return 1;
1082  }
1083
1084  obj = rtems_rtl_find_obj_with_symbol (sym);
1085  if (obj == NULL)
1086  {
1087    rtems_rtl_unlock ();
1088    rtems_printf (printer, "error: symbol obj not found: %s\n", argv[label]);
1089    return 1;
1090  }
1091
1092  if (!rtems_rtl_obj_text_inside (obj, (const void*) sym->value))
1093  {
1094    rtems_rtl_unlock ();
1095    rtems_printf (printer, "error: symbol not in obj text: %s\n", argv[label]);
1096    return 1;
1097  }
1098
1099  /*
1100   * Lock the object file while it is being called.
1101   */
1102  rtems_rtl_obj_inc_reference (obj);
1103
1104  rtems_rtl_unlock ();
1105
1106  if (args_s)
1107  {
1108    csig_s call = (csig_s) sym->value;
1109    call (values.s);
1110  }
1111  else if (args_u)
1112  {
1113    csig_u call = (csig_u) sym->value;
1114    call (values.u[0], values.u[1], values.u[2], values.u[3]);
1115  }
1116  else if (args_i)
1117  {
1118    csig_i call = (csig_i) sym->value;
1119    call (values.i[0], values.i[1], values.i[2], values.i[3]);
1120  }
1121  else
1122  {
1123    int cargc = argc - (label + 1);
1124    if (cargc == 0)
1125    {
1126      csig_none call = (csig_none) sym->value;
1127      call ();
1128    }
1129    else
1130    {
1131      csig_argv   call = (csig_argv) sym->value;
1132      const char* cargv = argv[label + 1];
1133      call (cargc, &cargv);
1134    }
1135  }
1136
1137  if (!keep_locked)
1138  {
1139    rtl = rtems_rtl_lock ();
1140    if (rtl == NULL)
1141    {
1142      rtems_printf (printer, "error: cannot lock the linker\n");
1143      return 1;
1144    }
1145
1146    obj = rtems_rtl_find_obj_with_symbol (sym);
1147    if (obj == NULL)
1148    {
1149      rtems_rtl_unlock ();
1150      rtems_printf (printer, "error: symbol obj not found: %s\n", argv[label]);
1151      return 1;
1152    }
1153
1154    rtems_rtl_obj_dec_reference (obj);
1155
1156    rtems_rtl_unlock ();
1157  }
1158
1159  return 0;
1160}
1161
1162static void
1163rtems_rtl_shell_usage (const rtems_printer* printer, const char* arg)
1164{
1165  rtems_printf (printer, "%s: Runtime Linker\n", arg);
1166  rtems_printf (printer, "  %s [-hl] <command>\n", arg);
1167  rtems_printf (printer, "   where:\n");
1168  rtems_printf (printer, "     command: A n RTL command. See -l for a list plus help.\n");
1169  rtems_printf (printer, "     -h:      This help\n");
1170  rtems_printf (printer, "     -l:      The command list.\n");
1171}
1172
1173int
1174rtems_rtl_shell_command (int argc, char* argv[])
1175{
1176  const rtems_rtl_shell_cmd table[] =
1177  {
1178    { "status", rtems_rtl_shell_status,
1179      "Display the status of the RTL" },
1180    { "list", rtems_rtl_shell_list,
1181      "\tList the object files currently loaded" },
1182    { "sym", rtems_rtl_shell_sym,
1183      "\tDisplay the symbols, sym [<name>], sym -o <obj> [<name>]" },
1184    { "obj", rtems_rtl_shell_object,
1185      "\tDisplay the object details, obj <name>" },
1186    { "call", rtems_rtl_shell_call,
1187      "\tCall a symbol" },
1188    { "ar", rtems_rtl_shell_archive,
1189      "\tDisplay the archive details, ar [-ls] <name>" },
1190    { "trace", rtems_rtl_trace_shell_command,
1191      "\tControl the RTL trace flags, trace [-h]" }
1192  };
1193
1194  rtems_printer printer;
1195  int           arg;
1196  int           t;
1197
1198  rtems_print_printer_printf (&printer);
1199
1200  for (arg = 1; arg < argc; arg++)
1201  {
1202    if (argv[arg][0] != '-')
1203      break;
1204
1205    switch (argv[arg][1])
1206    {
1207      case 'h':
1208        rtems_rtl_shell_usage (&printer, argv[0]);
1209        return 0;
1210      case 'l':
1211        rtems_printf (&printer, "%s: commands are:\n", argv[0]);
1212        for (t = 0;
1213             t < (sizeof (table) / sizeof (const rtems_rtl_shell_cmd));
1214             ++t)
1215          rtems_printf (&printer, "  %s\t%s\n", table[t].name, table[t].help);
1216        return 0;
1217      default:
1218        rtems_printf (&printer, "error: unknown option: %s\n", argv[arg]);
1219        return 1;
1220    }
1221  }
1222
1223  if ((argc - arg) < 1)
1224    rtems_printf (&printer, "error: you need to provide a command, try %s -h\n",
1225                  argv[0]);
1226  else
1227  {
1228    for (t = 0;
1229         t < (sizeof (table) / sizeof (const rtems_rtl_shell_cmd));
1230         ++t)
1231    {
1232      if (strncmp (argv[arg], table[t].name, strlen (argv[arg])) == 0)
1233        return table[t].handler (&printer, argc - 1, argv + 1);
1234    }
1235    rtems_printf (&printer, "error: command not found: %s (try -h)\n", argv[arg]);
1236  }
1237
1238  return 1;
1239}
Note: See TracBrowser for help on using the repository browser.