From dad6fd4333c4b05af08bd78714acefb5a86f1af9 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sun, 10 Mar 2019 07:04:42 +1300 Subject: libdl: Add an archive command - The archive command lists archives, symbols and any duplicate symbols. - Change the RTL shell commands to the rtems_printer to allow the output to be captured. --- cpukit/libdl/rtl-archive.c | 49 +-- cpukit/libdl/rtl-shell.c | 1052 ++++++++++++++++++++++++++++++++++++++------ cpukit/libdl/rtl-trace.c | 16 +- 3 files changed, 946 insertions(+), 171 deletions(-) (limited to 'cpukit/libdl') diff --git a/cpukit/libdl/rtl-archive.c b/cpukit/libdl/rtl-archive.c index 77ad2b0d30..34e45357ba 100644 --- a/cpukit/libdl/rtl-archive.c +++ b/cpukit/libdl/rtl-archive.c @@ -33,12 +33,6 @@ #include "rtl-string.h" #include "rtl-error.h" -/** - * The archive symbols threshold after which a sorted symbol table is - * created. - */ -#define RTEMS_RTL_ARCHIVE_SYMBOLS_SORT (8) - /** * Archive headers. */ @@ -223,8 +217,8 @@ rtems_rtl_archive_find (rtems_rtl_archives* archives, * * The symbol search is performance sensitive. The archive's symbol table being * searched is the symbol table in the archive created by ranlib. This table is - * not sorted so a sorted table of pointered to the symbols is generated after - * loading if there are enough symbols. For small symbol tables the searc is + * not sorted so a sorted table of pointeres to the symbols is generated after + * loading if there are enough symbols. For small symbol tables the search is * linear. The entire table is held in memory. At the time of writing this code * the symbol table for the SPARC architecture's libc is 16k. * @@ -286,7 +280,7 @@ rtems_rtl_archive_obj_finder (rtems_rtl_archive* archive, void* data) { search->archive = archive; search->offset = - rtems_rtl_archive_read_32 (symbols->base + (entry * 4)); + rtems_rtl_archive_read_32 (symbols->base + ((entry + 1) * 4)); return false; } symbol += strlen (symbol) + 1; @@ -647,8 +641,8 @@ rtems_rtl_archive_loader (rtems_rtl_archive* archive, void* data) offset, size); /* - * Reallocation the symbol table memory if it has changed size. - * Note, an updated library may have te same symbol table. + * Reallocate the symbol table memory if it has changed size. + * Note, an updated library may have the same symbol table. */ if (archive->symbols.size != size) { @@ -697,28 +691,25 @@ rtems_rtl_archive_loader (rtems_rtl_archive* archive, void* data) archive->symbols.names += (archive->symbols.entries + 1) * 4; /* - * Created a sorted symbol table if over the threshold number of symbols. + * Create a sorted symbol table. */ - if (archive->symbols.entries > RTEMS_RTL_ARCHIVE_SYMBOLS_SORT) + size = archive->symbols.entries * sizeof (rtems_rtl_archive_symbol); + archive->symbols.symbols = + rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, size, true); + if (archive->symbols.symbols != NULL) { - size = archive->symbols.entries * sizeof (rtems_rtl_archive_symbol); - archive->symbols.symbols = - rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, size, true); - if (archive->symbols.symbols != NULL) + const char* symbol = archive->symbols.names; + size_t e; + for (e = 0; e < archive->symbols.entries; ++e) { - const char* symbol = archive->symbols.names; - size_t e; - for (e = 0; e < archive->symbols.entries; ++e) - { - archive->symbols.symbols[e].entry = e + 1; - archive->symbols.symbols[e].label = symbol; - symbol += strlen (symbol) + 1; - } - qsort (archive->symbols.symbols, - archive->symbols.entries, - sizeof (rtems_rtl_archive_symbol), - rtems_rtl_archive_symbol_compare); + archive->symbols.symbols[e].entry = e + 1; + archive->symbols.symbols[e].label = symbol; + symbol += strlen (symbol) + 1; } + qsort (archive->symbols.symbols, + archive->symbols.entries, + sizeof (rtems_rtl_archive_symbol), + rtems_rtl_archive_symbol_compare); } if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES)) diff --git a/cpukit/libdl/rtl-shell.c b/cpukit/libdl/rtl-shell.c index 7458fb5608..56418303ff 100644 --- a/cpukit/libdl/rtl-shell.c +++ b/cpukit/libdl/rtl-shell.c @@ -22,10 +22,15 @@ #include #include -#include +#include +#include #include +#include + +#include #include +#include #include #include #include "rtl-chain-iterator.h" @@ -33,7 +38,7 @@ /** * The type of the shell handlers we have. */ -typedef int (*rtems_rtl_shell_handler) (rtems_rtl_data* rtl, int argc, char *argv[]); +typedef int (*rtems_rtl_shell_handler) (const rtems_printer* printer, int argc, char *argv[]); /** * Table of handlers we parse to invoke the command. @@ -83,10 +88,20 @@ rtems_rtl_count_symbols (rtems_rtl_data* rtl) } static int -rtems_rtl_shell_status (rtems_rtl_data* rtl, int argc, char *argv[]) +rtems_rtl_shell_status (const rtems_printer* printer, + int argc, + char* argv[]) { rtems_rtl_obj_summary summary; size_t total_memory; + rtems_rtl_data* rtl; + + rtl = rtems_rtl_lock (); + if (rtl == NULL) + { + rtems_printf (printer, "error: cannot lock the linker\n"); + return 1; + } summary.count = 0; summary.exec = 0; @@ -101,13 +116,15 @@ rtems_rtl_shell_status (rtems_rtl_data* rtl, int argc, char *argv[]) sizeof (*rtl) + (summary.count * sizeof (rtems_rtl_obj)) + summary.exec + summary.symbols; - printf ("Runtime Linker Status:\n"); - printf (" paths: %s\n", rtl->paths); - printf (" objects: %d\n", summary.count); - printf (" total memory: %zi\n", total_memory); - printf (" exec memory: %zi\n", summary.exec); - printf (" sym memory: %zi\n", summary.symbols); - printf (" symbols: %d\n", rtems_rtl_count_symbols (rtl)); + rtems_printf (printer, "Runtime Linker Status:\n"); + rtems_printf (printer, " paths: %s\n", rtl->paths); + rtems_printf (printer, " objects: %d\n", summary.count); + rtems_printf (printer, " total memory: %zi\n", total_memory); + rtems_printf (printer, " exec memory: %zi\n", summary.exec); + rtems_printf (printer, " sym memory: %zi\n", summary.symbols); + rtems_printf (printer, " symbols: %d\n", rtems_rtl_count_symbols (rtl)); + + rtems_rtl_unlock (); return 0; } @@ -117,68 +134,280 @@ rtems_rtl_shell_status (rtems_rtl_data* rtl, int argc, char *argv[]) */ typedef struct { - rtems_rtl_data* rtl; /**< The RTL data. */ - int indent; /**< Spaces to indent. */ - bool sep1; /**< Print a separator. */ - bool oname; /**< Print object names. */ - bool names; /**< Print details of all names. */ - bool memory_map; /**< Print the memory map. */ - bool symbols; /**< Print the global symbols. */ - bool dependencies; /**< Print any dependencies. */ - bool base; /**< Include the base object file. */ + const rtems_printer* printer; /**< The RTEMS printer. */ + rtems_rtl_data* rtl; /**< The RTL data. */ + int indent; /**< Spaces to indent. */ + bool oname; /**< Print object names. */ + bool names; /**< Print details of all names. */ + bool stats; /**< Print stats. */ + bool memory_map; /**< Print the memory map. */ + bool symbols; /**< Print the global symbols. */ + bool dependencies; /**< Print any dependencies. */ + bool base; /**< Include the base object file. */ + const char* re_name; /**< Name regx to filter on. */ + const char* re_symbol; /**< Symbol regx to filter on. */ } rtems_rtl_obj_print; /** * Parse an argument. */ static bool -rtems_rtl_parse_arg (const char* opt, int argc, char *argv[]) +rtems_rtl_parse_opt (const char opt, int argc, char *argv[]) { - int arg; - for (arg = 0; arg < argc; ++arg) - if (strncmp (opt, argv[arg], 2) == 0) - return true; + size_t arg; + for (arg = 1; arg < argc; ++arg) + { + if (argv[arg][0] == '-') + { + size_t len = strlen (argv[arg]); + size_t i; + for (i = 1; i < len; ++i) + if (argv[arg][i] == opt) + return true; + } + } return false; } +static bool +rtems_rtl_check_opts (const rtems_printer* printer, + const char* opts, + int argc, + char* argv[]) +{ + size_t olen = strlen (opts); + size_t arg; + for (arg = 1; arg < argc; ++arg) + { + if (argv[arg][0] == '-') + { + size_t len = strlen (argv[arg]); + size_t i; + for (i = 1; i < len; ++i) + { + bool found = false; + size_t o; + for (o = 0; o < olen; ++o) + { + if (argv[arg][i] == opts[o]) + { + found = true; + break; + } + } + if (!found) + { + rtems_printf (printer, "error: invalid option: %c (%s)\n", + argv[arg][i], argv[arg]); + return false; + } + } + } + } + return true; +} + +static ssize_t +rtems_rtl_parse_arg_index (const char opt, + const char* skip_opts, + int argc, + char* argv[]) +{ + ssize_t arg; + for (arg = 1; arg < argc; ++arg) + { + if (argv[arg][0] == '-') + { + /* + * We can check the next char because there has to be a valid char or a + * nul. + */ + if (argv[arg][1] != '\0') + { + size_t len = skip_opts != NULL ? strlen (skip_opts) : 0; + size_t i; + for (i = 0; i < len; ++i) + { + if (skip_opts[i] == argv[arg][1]) + { + ++arg; + break; + } + } + } + } + else + { + if (opt == ' ') + return arg; + } + /* + * Is this an option and does it match what we are looking for? + */ + if (argv[arg][0] == '-' && argv[arg][1] == opt && arg < argc) + return arg + 1; + } + return -1; +} + +static const char* +rtems_rtl_parse_arg (const char opt, + const char* skip_opts, + int argc, + char* argv[]) +{ + ssize_t arg = rtems_rtl_parse_arg_index (opt, skip_opts, argc, argv); + if (arg < 0) + return NULL; + return argv[arg]; +} + /** - * See if -b for base is set. + * Regx matching. */ static bool -rtems_rtl_base_arg (int argc, char *argv[]) +rtems_rtl_regx_compile (const rtems_printer* printer, + const char* label, + regex_t* rege, + const char* expression) { - return rtems_rtl_parse_arg ("-b", argc, argv); + int r = regcomp (rege, expression, REG_EXTENDED | REG_NOSUB); + if (r != 0) + { + char rerror[128]; + regerror (r, rege, rerror, sizeof(rerror)); + rtems_printf (printer, "error: %s: %s\n", label, rerror); + return false; + } + return true; +} + +static int +rtems_rtl_regx_match (const rtems_printer* printer, + const char* label, + regex_t* rege, + const char* string) +{ + int r = regexec (rege, string, 0, NULL, 0); + if (r != 0 && r != REG_NOMATCH) + { + char rerror[128]; + regerror (r, rege, rerror, sizeof(rerror)); + rtems_printf (printer, "error: %s: %s\n", label, rerror); + regfree (rege); + return -1; + } + return r == 0 ? 1 : 0; } /** - * See if -s for base is set. + * Print the obj name. + */ +static void +rtems_rtl_print_obj_name (const rtems_rtl_obj_print* print, rtems_rtl_obj* obj) +{ + rtems_printf (print->printer, "%-*c", print->indent, ' '); + if (rtems_rtl_obj_aname (obj) != NULL) + rtems_printf (print->printer, "%s:", rtems_rtl_obj_aname (obj)); + rtems_printf (print->printer, "%s\n", rtems_rtl_obj_oname (obj)); +} + +/** + * Print symbols. */ static bool -rtems_rtl_symbols_arg (int argc, char *argv[]) +rtems_rtl_print_symbols (rtems_rtl_obj_print* print, + rtems_rtl_obj* obj, + int indent, + bool show_name) { - return rtems_rtl_parse_arg ("-s", argc, argv); + regex_t rege; + int max_len = 0; + int s; + + if (print->re_symbol != NULL && + !rtems_rtl_regx_compile (print->printer, + "symbol filter", + ®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; } /** - * Dependenncies printer. + * Dependencies printer. */ typedef struct { - bool first; /**< Is this the first line printed. */ - size_t indent; /**< The indent. */ + const rtems_rtl_obj_print* print; /**< The print data. */ + bool first; /**< Is this the first line printed. */ + bool show_name; /**< Show the object name. */ + size_t indent; /**< The indent. */ } rtems_rtl_dep_data; static bool -rtems_rtl_dependencies (rtems_rtl_obj* obj, - rtems_rtl_obj* dependent, - void* data) +rtems_rtl_dependencies (rtems_rtl_obj* obj, rtems_rtl_obj* dependent, void* data) { rtems_rtl_dep_data* dd = (rtems_rtl_dep_data*) data; - if (!dd->first) - printf ("\n%-*c: ", (int) dd->indent, ' '); - else + if (dd->first) + { dd->first = false; - printf ("%s", dependent->oname); + if (dd->show_name) + { + dd->show_name = false; + rtems_rtl_print_obj_name (dd->print, obj); + } + rtems_printf (dd->print->printer, "%-*cdependencies : ", dd->indent, ' '); + dd->indent += strlen ("dependencies :"); + } + else + { + rtems_printf (dd->print->printer, "\n%-*c: ", (int) dd->indent, ' '); + } + rtems_printf (dd->print->printer, "%s", dependent->oname); return false; } @@ -189,6 +418,8 @@ static bool rtems_rtl_obj_printer (rtems_rtl_obj_print* print, rtems_rtl_obj* obj) { char flags_str[33]; + int indent = print->indent + 1; + bool show_name = true; /* * Skip the base module unless asked to show it. @@ -196,72 +427,114 @@ rtems_rtl_obj_printer (rtems_rtl_obj_print* print, rtems_rtl_obj* obj) if (!print->base && (obj == print->rtl->base)) return true; - if (print->sep1) + if (print->re_name != NULL) { - printf ("%-*c--------------\n", print->indent, ' '); + regex_t rege; + int r = 0; + + if (!rtems_rtl_regx_compile (print->printer, + "name filter", + ®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->oname) + + if (print->names || print->memory_map || print->stats || + (!print->names && !print->memory_map && !print->stats && + !print->symbols && !print->dependencies)) { - printf ("%-*cobject name : %s\n", - print->indent, ' ', rtems_rtl_obj_oname (obj)); + show_name = false; + rtems_rtl_print_obj_name (print, obj); } + if (print->names) { - printf ("%-*cfile name : %s\n", - print->indent, ' ', rtems_rtl_obj_fname (obj)); - printf ("%-*carchive name : %s\n", - print->indent, ' ', rtems_rtl_obj_aname (obj)); + rtems_printf (print->printer, + "%-*cfile name : %s\n", + indent, ' ', rtems_rtl_obj_fname (obj)); + rtems_printf (print->printer, + "%-*carchive name : %s\n", + indent, ' ', rtems_rtl_obj_aname (obj)); strcpy (flags_str, "--"); if (obj->flags & RTEMS_RTL_OBJ_LOCKED) flags_str[0] = 'L'; if (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED) flags_str[1] = 'U'; - printf ("%-*cflags : %s\n", print->indent, ' ', flags_str); - printf ("%-*cfile offset : %" PRIdoff_t "\n", print->indent, ' ', obj->ooffset); - printf ("%-*cfile size : %zi\n", print->indent, ' ', obj->fsize); + rtems_printf (print->printer, + "%-*cflags : %s\n", indent, ' ', flags_str); + rtems_printf (print->printer, + "%-*cfile offset : %" PRIdoff_t "\n", indent, ' ', obj->ooffset); + rtems_printf (print->printer, + "%-*cfile size : %zi\n", indent, ' ', obj->fsize); } if (print->memory_map) { - printf ("%-*cexec size : %zi\n", print->indent, ' ', obj->exec_size); - printf ("%-*ctext base : %p (%zi)\n", print->indent, ' ', - obj->text_base, obj->text_size); - printf ("%-*cconst base : %p (%zi)\n", print->indent, ' ', - obj->const_base, obj->const_size); - printf ("%-*cdata base : %p (%zi)\n", print->indent, ' ', - obj->data_base, obj->data_size); - printf ("%-*cbss base : %p (%zi)\n", print->indent, ' ', - obj->bss_base, obj->bss_size); - } - printf ("%-*cunresolved : %zu\n", print->indent, ' ', obj->unresolved); - printf ("%-*cusers : %zu\n", print->indent, ' ', obj->users); - printf ("%-*creferences : %zu\n", print->indent, ' ', obj->refs); - printf ("%-*csymbols : %zi\n", print->indent, ' ', obj->global_syms); - printf ("%-*csymbol memory : %zi\n", print->indent, ' ', obj->global_size); + rtems_printf (print->printer, + "%-*cexec size : %zi\n", indent, ' ', obj->exec_size); + rtems_printf (print->printer, + "%-*ctext base : %p (%zi)\n", indent, ' ', + obj->text_base, obj->text_size); + rtems_printf (print->printer, + "%-*cconst base : %p (%zi)\n", indent, ' ', + obj->const_base, obj->const_size); + rtems_printf (print->printer, + "%-*cdata base : %p (%zi)\n", indent, ' ', + obj->data_base, obj->data_size); + rtems_printf (print->printer, + "%-*cbss base : %p (%zi)\n", indent, ' ', + obj->bss_base, obj->bss_size); + } + if (print->stats) + { + rtems_printf (print->printer, "%-*cunresolved : %zu\n", indent, ' ', obj->unresolved); + rtems_printf (print->printer, "%-*cusers : %zu\n", indent, ' ', obj->users); + rtems_printf (print->printer, "%-*creferences : %zu\n", indent, ' ', obj->refs); + rtems_printf (print->printer, "%-*csymbols : %zi\n", indent, ' ', obj->global_syms); + rtems_printf (print->printer, "%-*csymbol memory : %zi\n", indent, ' ', obj->global_size); + } if (print->symbols) { - int max_len = 0; - int s; - for (s = 0; s < obj->global_syms; ++s) - { - int len = strlen (obj->global_table[s].name); - if (len > max_len) - max_len = len; - } - for (s = 0; s < obj->global_syms; ++s) - printf ("%-*c%-*s = %p\n", print->indent + 2, ' ', - max_len, obj->global_table[s].name, obj->global_table[s].value); + if (!rtems_rtl_print_symbols (print, obj, indent, show_name)) + return false; } if (print->dependencies) { rtems_rtl_dep_data dd = { + .print = print, .first = true, - .indent = strlen ("dependencies :") + print->indent + .show_name = show_name, + .indent = indent }; - printf ("%-*cdependencies : ", print->indent, ' '); rtems_rtl_obj_iterate_dependents (obj, rtems_rtl_dependencies, &dd); - printf ("\n"); + if (!dd.first) + rtems_printf (print->printer, "\n"); } - printf ("\n"); return true; } @@ -274,7 +547,8 @@ rtems_rtl_unresolved_printer (rtems_rtl_unresolv_rec* rec, { rtems_rtl_obj_print* print = (rtems_rtl_obj_print*) data; if (rec->type == rtems_rtl_unresolved_symbol) - printf ("%-*c%s\n", print->indent + 2, ' ', rec->rec.name.name); + rtems_printf (print->printer, + "%-*c%s\n", print->indent + 2, ' ', rec->rec.name.name); return false; } @@ -289,61 +563,568 @@ rtems_rtl_obj_print_iterator (rtems_chain_node* node, void* data) return rtems_rtl_obj_printer (print, obj); } -static int -rtems_rtl_shell_list (rtems_rtl_data* rtl, int argc, char *argv[]) +int +rtems_rtl_shell_list (const rtems_printer* printer, int argc, char* argv[]) { - rtems_rtl_obj_print print; - print.rtl = rtl; + rtems_rtl_obj_print print = { 0 }; + if (!rtems_rtl_check_opts (printer, "nlmsdb", argc, argv)) + return 1; + print.printer = printer; print.indent = 1; - print.sep1 = true; print.oname = true; - print.names = true; - print.memory_map = true; - print.symbols = rtems_rtl_symbols_arg (argc, argv); - print.dependencies = true; - print.base = false; - rtems_rtl_chain_iterate (&rtl->objects, + print.names = rtems_rtl_parse_opt ('n', argc, argv); + print.stats = rtems_rtl_parse_opt ('l', argc, argv);; + print.memory_map = rtems_rtl_parse_opt ('m', argc, argv);; + print.symbols = rtems_rtl_parse_opt ('s', argc, argv); + print.dependencies = rtems_rtl_parse_opt ('d', argc, argv);; + print.base = rtems_rtl_parse_opt ('b', argc, argv);; + print.re_name = rtems_rtl_parse_arg (' ', NULL, argc, argv); + print.re_symbol = NULL; + print.rtl = rtems_rtl_lock (); + if (print.rtl == NULL) + { + rtems_printf (print.printer, "error: cannot lock the linker\n"); + return 1; + } + rtems_rtl_chain_iterate (&print.rtl->objects, rtems_rtl_obj_print_iterator, &print); + rtems_rtl_unlock (); return 0; } -static int -rtems_rtl_shell_sym (rtems_rtl_data* rtl, int argc, char *argv[]) +int +rtems_rtl_shell_sym (const rtems_printer* printer, int argc, char* argv[]) { - rtems_rtl_obj_print print; - print.rtl = rtl; + rtems_rtl_obj_print print = { 0 }; + if (!rtems_rtl_check_opts (printer, "buo", argc, argv)) + return 1; + print.printer = printer; print.indent = 1; - print.sep1 = true; print.oname = true; print.names = false; + print.stats = false; print.memory_map = false; - print.symbols = true; + print.symbols = !rtems_rtl_parse_opt ('u', argc, argv);; print.dependencies = false; - print.base = rtems_rtl_base_arg (argc, argv); - rtems_rtl_chain_iterate (&rtl->objects, - rtems_rtl_obj_print_iterator, - &print); - printf ("Unresolved:\n"); - rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_printer, &print); + print.base = rtems_rtl_parse_opt ('b', argc, argv); + print.re_name = rtems_rtl_parse_arg ('o', NULL, argc, argv);; + print.re_symbol = rtems_rtl_parse_arg (' ', "ou", argc, argv); + print.rtl = rtems_rtl_lock (); + if (print.rtl == NULL) + { + rtems_printf (print.printer, "error: cannot lock the linker\n"); + return 1; + } + if (print.symbols) + { + rtems_rtl_chain_iterate (&print.rtl->objects, + rtems_rtl_obj_print_iterator, + &print); + } + if (rtems_rtl_parse_opt ('u', argc, argv)) + { + rtems_printf (printer, "Unresolved:\n"); + rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_printer, &print); + } + rtems_rtl_unlock (); return 0; } -static int -rtems_rtl_shell_object (rtems_rtl_data* rtl, int argc, char *argv[]) +int +rtems_rtl_shell_object (const rtems_printer* printer, int argc, char* argv[]) { + size_t arg; + + --argc; + ++argv; + + for (arg = 0; arg < argc; ++arg) + { + if (argv[arg][0] == '-') + { + switch (argv[arg][1]) + { + case 'h': + case '?': + rtems_printf (printer, "obj commands:\n"); + rtems_printf (printer, " load \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 char* arg) +rtems_rtl_shell_usage (const rtems_printer* printer, const char* arg) { - printf ("%s: Runtime Linker\n", arg); - printf (" %s [-hl] \n", arg); - printf (" where:\n"); - printf (" command: A n RTL command. See -l for a list plus help.\n"); - printf (" -h: This help\n"); - printf (" -l: The command list.\n"); + rtems_printf (printer, "%s: Runtime Linker\n", arg); + rtems_printf (printer, " %s [-hl] \n", arg); + rtems_printf (printer, " where:\n"); + rtems_printf (printer, " command: A n RTL command. See -l for a list plus help.\n"); + rtems_printf (printer, " -h: This help\n"); + rtems_printf (printer, " -l: The command list.\n"); } int @@ -358,11 +1139,20 @@ rtems_rtl_shell_command (int argc, char* argv[]) { "sym", rtems_rtl_shell_sym, "\tDisplay the symbols, sym [], sym -o []" }, { "obj", rtems_rtl_shell_object, - "\tDisplay the object details, obj " } + "\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]" } }; - int arg; - int t; + rtems_printer printer; + int arg; + int t; + + rtems_print_printer_printf (&printer); for (arg = 1; arg < argc; arg++) { @@ -372,23 +1162,24 @@ rtems_rtl_shell_command (int argc, char* argv[]) switch (argv[arg][1]) { case 'h': - rtems_rtl_shell_usage (argv[0]); + rtems_rtl_shell_usage (&printer, argv[0]); return 0; case 'l': - printf ("%s: commands are:\n", argv[0]); + rtems_printf (&printer, "%s: commands are:\n", argv[0]); for (t = 0; t < (sizeof (table) / sizeof (const rtems_rtl_shell_cmd)); ++t) - printf (" %s\t%s\n", table[t].name, table[t].help); + rtems_printf (&printer, " %s\t%s\n", table[t].name, table[t].help); return 0; default: - printf ("error: unknown option: %s\n", argv[arg]); + rtems_printf (&printer, "error: unknown option: %s\n", argv[arg]); return 1; } } if ((argc - arg) < 1) - printf ("error: you need to provide a command, try %s -h\n", argv[0]); + rtems_printf (&printer, "error: you need to provide a command, try %s -h\n", + argv[0]); else { for (t = 0; @@ -396,20 +1187,9 @@ rtems_rtl_shell_command (int argc, char* argv[]) ++t) { if (strncmp (argv[arg], table[t].name, strlen (argv[arg])) == 0) - { - rtems_rtl_data* rtl = rtems_rtl_lock (); - int r; - if (!rtl) - { - printf ("error: cannot lock the linker\n"); - return 1; - } - r = table[t].handler (rtl, argc - 1, argv + 1); - rtems_rtl_unlock (); - return r; - } + return table[t].handler (&printer, argc - 1, argv + 1); } - printf ("error: command not found: %s (try -h)\n", argv[arg]); + rtems_printf (&printer, "error: command not found: %s (try -h)\n", argv[arg]); } return 1; diff --git a/cpukit/libdl/rtl-trace.c b/cpukit/libdl/rtl-trace.c index e09ec06758..2793baa7cb 100644 --- a/cpukit/libdl/rtl-trace.c +++ b/cpukit/libdl/rtl-trace.c @@ -54,7 +54,9 @@ rtems_rtl_trace_clear_mask (rtems_rtl_trace_mask mask) } int -rtems_rtl_trace_shell_command (int argc, char *argv[]) +rtems_rtl_trace_shell_command (const rtems_printer* printer, + int argc, + char* argv[]) { const char* table[] = { @@ -71,7 +73,9 @@ rtems_rtl_trace_shell_command (int argc, char *argv[]) "unresolved", "cache", "archives", - "dependency" + "archive-syms", + "dependency", + "bit-alloc" }; rtems_rtl_trace_mask set_value = 0; @@ -87,15 +91,15 @@ rtems_rtl_trace_shell_command (int argc, char *argv[]) switch (argv[arg][1]) { case 'h': - printf ("usage: %s [-hl] [set/clear] [flags]\n", argv[0]); + rtems_printf (printer, "usage: %s [-hl] [set/clear] [flags]\n", argv[0]); return 0; case 'l': - printf ("%s: valid flags to set or clear are:\n", argv[0]); + rtems_printf (printer, "%s: valid flags to set or clear are:\n", argv[0]); for (t = 0; t < (sizeof (table) / sizeof (const char*)); t++) - printf (" %s\n", table[t]); + rtems_printf (printer, " %s\n", table[t]); return 0; default: - printf ("error: unknown option\n"); + rtems_printf (printer, "error: unknown option\n"); return 1; } } -- cgit v1.2.3