/*
* COPYRIGHT (c) 2012, 2018 Chris Johns <chrisj@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.
*/
/**
* @file
*
* @ingroup rtems_rtld
*
* @brief RTEMS Run-Time Link Editor Shell Commands
*
* A simple RTL command to aid using the RTL.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <inttypes.h>
#include <rtems/inttypes.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"
/**
* The type of the shell handlers we have.
*/
typedef int (*rtems_rtl_shell_handler) (const rtems_printer* printer, int argc, char *argv[]);
/**
* Table of handlers we parse to invoke the command.
*/
typedef struct
{
const char* name; /**< The sub-command's name. */
rtems_rtl_shell_handler handler; /**< The sub-command's handler. */
const char* help; /**< The sub-command's help. */
} rtems_rtl_shell_cmd;
/**
* Object summary data.
*/
typedef struct
{
int count; /**< The number of object files. */
size_t exec; /**< The amount of executable memory allocated. */
size_t symbols; /**< The amount of symbol memory allocated. */
} rtems_rtl_obj_summary;
/**
* Object summary iterator.
*/
static bool
rtems_rtl_obj_summary_iterator (rtems_chain_node* node, void* data)
{
rtems_rtl_obj_summary* summary = data;
rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
++summary->count;
summary->exec += obj->exec_size;
summary->symbols += obj->global_size;
return true;
}
/**
* Count the number of symbols.
*/
static int
rtems_rtl_count_symbols (rtems_rtl_data* rtl)
{
int count;
int bucket;
for (count = 0, bucket = 0; bucket < rtl->globals.nbuckets; ++bucket)
count += rtems_rtl_chain_count (&rtl->globals.buckets[bucket]);
return count;
}
static int
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;
summary.symbols = 0;
rtems_rtl_chain_iterate (&rtl->objects,
rtems_rtl_obj_summary_iterator,
&summary);
/*
* Currently does not include the name strings in the obj struct.
*/
total_memory =
sizeof (*rtl) + (summary.count * sizeof (rtems_rtl_obj)) +
summary.exec + summary.symbols;
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;
}
/**
* Object print data.
*/
typedef struct
{
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 trampolines; /**< Print trampoline stats. */
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_opt (const char opt, int argc, char *argv[])
{
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];
}
/**
* Regx matching.
*/
static bool
rtems_rtl_regx_compile (const rtems_printer* printer,
const char* label,
regex_t* rege,
const char* expression)
{
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;
}
/**
* 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_print_symbols (rtems_rtl_obj_print* print,
rtems_rtl_obj* obj,
int indent,
bool show_name)
{
regex_t rege;
int max_len = 0;
int s;
if (print->re_symbol != NULL &&
!rtems_rtl_regx_compile (print->printer,
"symbol filter",
®e, 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", ®e, 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", ®e, 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 (®e);
return true;
}
/**
* Dependencies printer.
*/
typedef struct
{
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_dep_data* dd = (rtems_rtl_dep_data*) data;
if (dd->first)
{
dd->first = false;
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;
}
/**
* Object printer.
*/
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.
*/
if (!print->base && (obj == print->rtl->base))
return true;
if (print->re_name != NULL)
{
regex_t rege;
int r = 0;
if (!rtems_rtl_regx_compile (print->printer,
"name filter",
®e, print->re_name))
{
return false;
}
if (rtems_rtl_obj_aname (obj) != NULL)
{
r = rtems_rtl_regx_match (print->printer,
"aname match",
®e,
rtems_rtl_obj_aname (obj));
if (r < 0)
return false;
}
if (r == 0)
{
r = rtems_rtl_regx_match (print->printer,
"oname match",
®e,
rtems_rtl_obj_oname (obj));
if (r < 0)
return false;
}
regfree (®e);
if (r == 0)
return true;
}
if (print->names || print->memory_map || print->stats ||
(!print->names && !print->memory_map && !print->stats &&
!print->symbols && !print->dependencies))
{
show_name = false;
rtems_rtl_print_obj_name (print, obj);
}
if (print->names)
{
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';
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)
{
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, "%-*ctrampolines : %zu\n", indent, ' ',
rtems_rtl_obj_trampolines (obj));
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)
{
if (!rtems_rtl_print_symbols (print, obj, indent, show_name))
return false;
}
if (print->dependencies)
{
rtems_rtl_dep_data dd = {
.print = print,
.first = true,
.show_name = show_name,
.indent = indent
};
rtems_rtl_obj_iterate_dependents (obj, rtems_rtl_dependencies, &dd);
if (!dd.first)
rtems_printf (print->printer, "\n");
}
if (print->trampolines)
{
if (obj->tramp_size == 0)
{
rtems_printf (print->printer, "%-*ctrampolines: not supported\n", indent, ' ');
}
else
{
size_t slots = rtems_rtl_obj_trampoline_slots (obj);
size_t used = rtems_rtl_obj_trampolines (obj);
rtems_printf (print->printer, "%-*ctrampolines:\n", indent, ' ');
rtems_printf (print->printer, "%-*cslots : %zu\n", indent + 4, ' ',
slots);
rtems_printf (print->printer, "%-*csize : %zu\n", indent + 4, ' ',
obj->tramps_size);
rtems_printf (print->printer, "%-*cslot size : %zu\n", indent + 4, ' ',
obj->tramp_size);
rtems_printf (print->printer, "%-*cused : %zu\n", indent + 4, ' ',
used);
rtems_printf (print->printer, "%-*crelocs : %zu\n", indent + 4, ' ',
obj->tramp_relocs);
rtems_printf (print->printer, "%-*cunresolved: %zu\n", indent + 4, ' ',
slots - obj->tramp_relocs);
rtems_printf (print->printer, "%-*cyield : %zu%%\n", indent + 4, ' ',
slots ? (used * 100) / slots : 0);
}
}
return true;
}
/**
* Object unresolved symbols printer.
*/
static bool
rtems_rtl_unresolved_printer (rtems_rtl_unresolv_rec* rec,
void* data)
{
rtems_rtl_obj_print* print = (rtems_rtl_obj_print*) data;
if (rec->type == rtems_rtl_unresolved_symbol)
rtems_printf (print->printer,
"%-*c%s\n", print->indent + 2, ' ', rec->rec.name.name);
return false;
}
/**
* Object print iterator.
*/
static bool
rtems_rtl_obj_print_iterator (rtems_chain_node* node, void* data)
{
rtems_rtl_obj_print* print = data;
rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
return rtems_rtl_obj_printer (print, obj);
}
int
rtems_rtl_shell_list (const rtems_printer* printer, int argc, char* argv[])
{
rtems_rtl_obj_print print = { 0 };
if (!rtems_rtl_check_opts (printer, "anlmsdbt", argc, argv))
return 1;
print.printer = printer;
print.indent = 1;
print.oname = true;
if (rtems_rtl_parse_opt ('a', argc, argv))
{
print.names = true;
print.stats = true;
print.memory_map = true;
print.symbols = true;
print.dependencies = true;
print.trampolines = true;
}
else
{
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.trampolines = rtems_rtl_parse_opt ('t', 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;
}
int
rtems_rtl_shell_sym (const rtems_printer* printer, int argc, char* argv[])
{
rtems_rtl_obj_print print = { 0 };
if (!rtems_rtl_check_opts (printer, "buo", argc, argv))
return 1;
print.printer = printer;
print.indent = 1;
print.oname = true;
print.names = false;
print.stats = false;
print.memory_map = false;
print.symbols = !rtems_rtl_parse_opt ('u', argc, argv);;
print.dependencies = false;
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;
}
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",
®e,
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",
®e,
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 (®e);
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 rtems_printer* printer, const char* arg)
{
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
rtems_rtl_shell_command (int argc, char* argv[])
{
const rtems_rtl_shell_cmd table[] =
{
{ "status", rtems_rtl_shell_status,
"Display the status of the RTL" },
{ "list", rtems_rtl_shell_list,
"\tList the object files currently loaded" },
{ "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>" },
{ "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]" }
};
rtems_printer printer;
int arg;
int t;
rtems_print_printer_printf (&printer);
for (arg = 1; arg < argc; arg++)
{
if (argv[arg][0] != '-')
break;
switch (argv[arg][1])
{
case 'h':
rtems_rtl_shell_usage (&printer, argv[0]);
return 0;
case 'l':
rtems_printf (&printer, "%s: commands are:\n", argv[0]);
for (t = 0;
t < (sizeof (table) / sizeof (const rtems_rtl_shell_cmd));
++t)
rtems_printf (&printer, " %s\t%s\n", table[t].name, table[t].help);
return 0;
default:
rtems_printf (&printer, "error: unknown option: %s\n", argv[arg]);
return 1;
}
}
if ((argc - arg) < 1)
rtems_printf (&printer, "error: you need to provide a command, try %s -h\n",
argv[0]);
else
{
for (t = 0;
t < (sizeof (table) / sizeof (const rtems_rtl_shell_cmd));
++t)
{
if (strncmp (argv[arg], table[t].name, strlen (argv[arg])) == 0)
return table[t].handler (&printer, argc - 1, argv + 1);
}
rtems_printf (&printer, "error: command not found: %s (try -h)\n", argv[arg]);
}
return 1;
}