/* SPDX-License-Identifier: BSD-2-Clause */ /** * @file * * @ingroup rtems_rtld * * @brief RTEMS Run-Time Link Editor Shell Commands * * A simple RTL command to aid using the RTL. */ /* * COPYRIGHT (c) 2012, 2018 Chris Johns * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #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 \n"); rtems_printf (printer, " unload \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] \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 [], sym -o []" }, { "obj", rtems_rtl_shell_object, "\tDisplay the object details, obj " }, { "call", rtems_rtl_shell_call, "\tCall a symbol" }, { "ar", rtems_rtl_shell_archive, "\tDisplay the archive details, ar [-ls] " }, { "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; }