mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-05 15:15:44 +00:00
392 lines
10 KiB
C
392 lines
10 KiB
C
/*
|
|
* COPYRIGHT (c) 2012 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.
|
|
*/
|
|
|
|
#if HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <inttypes.h>
|
|
|
|
/*
|
|
* Flag the targets where off_t is 32 bits. This is not a compiler type
|
|
* so we can't rely on prerdefines.
|
|
*/
|
|
#if defined(__moxie__)
|
|
#define PRIdoff_t PRIo32
|
|
#else
|
|
#define PRIdoff_t PRIo64
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <rtems/rtl/rtl.h>
|
|
#include "rtl-chain-iterator.h"
|
|
#include "rtl-shell.h"
|
|
#include "rtl-trace.h"
|
|
|
|
/**
|
|
* The type of the shell handlers we have.
|
|
*/
|
|
typedef int (*rtems_rtl_shell_handler_t) (rtems_rtl_data_t* rtl, 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_t handler; /**< The sub-command's handler. */
|
|
const char* help; /**< The sub-command's help. */
|
|
} rtems_rtl_shell_cmd_t;
|
|
|
|
/**
|
|
* 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_t;
|
|
|
|
/**
|
|
* Object summary iterator.
|
|
*/
|
|
static bool
|
|
rtems_rtl_obj_summary_iterator (rtems_chain_node* node, void* data)
|
|
{
|
|
rtems_rtl_obj_summary_t* summary = data;
|
|
rtems_rtl_obj_t* obj = (rtems_rtl_obj_t*) 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_t* 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 (rtems_rtl_data_t* rtl, int argc, char *argv[])
|
|
{
|
|
rtems_rtl_obj_summary_t summary;
|
|
size_t total_memory;
|
|
|
|
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_t)) +
|
|
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));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Object print data.
|
|
*/
|
|
typedef struct
|
|
{
|
|
rtems_rtl_data_t* rtl; /**< The RTL data. */
|
|
int indent; /**< Spaces to indent. */
|
|
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 base; /**< Include the base object file. */
|
|
} rtems_rtl_obj_print_t;
|
|
|
|
/**
|
|
* Return the different between 2 void*.
|
|
*/
|
|
static size_t
|
|
rtems_rtl_delta_voids (void* higher, void* lower)
|
|
{
|
|
char* ch = higher;
|
|
char* cl = lower;
|
|
return ch - cl;
|
|
}
|
|
|
|
/**
|
|
* Parse an argument.
|
|
*/
|
|
static bool
|
|
rtems_rtl_parse_arg (const char* opt, int argc, char *argv[])
|
|
{
|
|
int arg;
|
|
for (arg = 0; arg < argc; ++arg)
|
|
if (strncmp (opt, argv[arg], 2) == 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* See if -b for base is set.
|
|
*/
|
|
static bool
|
|
rtems_rtl_base_arg (int argc, char *argv[])
|
|
{
|
|
return rtems_rtl_parse_arg ("-b", argc, argv);
|
|
}
|
|
|
|
/**
|
|
* See if -s for base is set.
|
|
*/
|
|
static bool
|
|
rtems_rtl_symbols_arg (int argc, char *argv[])
|
|
{
|
|
return rtems_rtl_parse_arg ("-s", argc, argv);
|
|
}
|
|
|
|
/**
|
|
* Object printer.
|
|
*/
|
|
static bool
|
|
rtems_rtl_obj_printer (rtems_rtl_obj_print_t* print, rtems_rtl_obj_t* obj)
|
|
{
|
|
char flags_str[33];
|
|
|
|
/*
|
|
* Skip the base module unless asked to show it.
|
|
*/
|
|
if (!print->base && (obj == print->rtl->base))
|
|
return true;
|
|
|
|
if (print->oname)
|
|
{
|
|
printf ("%-*cobject name : %s\n",
|
|
print->indent, ' ', rtems_rtl_obj_oname (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));
|
|
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);
|
|
}
|
|
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, rtems_rtl_delta_voids (obj->const_base, obj->text_base));
|
|
printf ("%-*cconst base : %p (%zi)\n", print->indent, ' ',
|
|
obj->const_base, rtems_rtl_delta_voids (obj->data_base, obj->const_base));
|
|
printf ("%-*cdata base : %p (%zi)\n", print->indent, ' ',
|
|
obj->data_base, rtems_rtl_delta_voids (obj->bss_base, obj->data_base));
|
|
printf ("%-*cbss base : %p (%zi)\n", print->indent, ' ',
|
|
obj->bss_base, obj->bss_size);
|
|
}
|
|
printf ("%-*cunresolved : %lu\n", print->indent, ' ', obj->unresolved);
|
|
printf ("%-*csymbols : %zi\n", print->indent, ' ', obj->global_syms);
|
|
printf ("%-*csymbol memory : %zi\n", print->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);
|
|
}
|
|
printf ("\n");
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Object unresolved symbols printer.
|
|
*/
|
|
static bool
|
|
rtems_rtl_unresolved_printer (rtems_rtl_unresolv_rec_t* rec,
|
|
void* data)
|
|
{
|
|
rtems_rtl_obj_print_t* print = (rtems_rtl_obj_print_t*) data;
|
|
if (rec->type == rtems_rtl_unresolved_name)
|
|
printf ("%-*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_t* print = data;
|
|
rtems_rtl_obj_t* obj = (rtems_rtl_obj_t*) node;
|
|
return rtems_rtl_obj_printer (print, obj);
|
|
}
|
|
|
|
static int
|
|
rtems_rtl_shell_list (rtems_rtl_data_t* rtl, int argc, char *argv[])
|
|
{
|
|
rtems_rtl_obj_print_t print;
|
|
print.rtl = rtl;
|
|
print.indent = 1;
|
|
print.oname = true;
|
|
print.names = true;
|
|
print.memory_map = true;
|
|
print.symbols = rtems_rtl_symbols_arg (argc, argv);
|
|
print.base = false;
|
|
rtems_rtl_chain_iterate (&rtl->objects,
|
|
rtems_rtl_obj_print_iterator,
|
|
&print);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
rtems_rtl_shell_sym (rtems_rtl_data_t* rtl, int argc, char *argv[])
|
|
{
|
|
rtems_rtl_obj_print_t print;
|
|
print.rtl = rtl;
|
|
print.indent = 1;
|
|
print.oname = true;
|
|
print.names = false;
|
|
print.memory_map = false;
|
|
print.symbols = true;
|
|
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_interate (rtems_rtl_unresolved_printer, &print);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
rtems_rtl_shell_object (rtems_rtl_data_t* rtl, int argc, char *argv[])
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
rtems_rtl_shell_usage (const char* arg)
|
|
{
|
|
printf ("%s: Runtime Linker\n", arg);
|
|
printf (" %s [-hl] <command>\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");
|
|
}
|
|
|
|
int
|
|
rtems_rtl_shell_command (int argc, char* argv[])
|
|
{
|
|
const rtems_rtl_shell_cmd_t 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>" }
|
|
};
|
|
|
|
int arg;
|
|
int t;
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] != '-')
|
|
break;
|
|
|
|
switch (argv[arg][1])
|
|
{
|
|
case 'h':
|
|
rtems_rtl_shell_usage (argv[0]);
|
|
return 0;
|
|
case 'l':
|
|
printf ("%s: commands are:\n", argv[0]);
|
|
for (t = 0;
|
|
t < (sizeof (table) / sizeof (const rtems_rtl_shell_cmd_t));
|
|
++t)
|
|
printf (" %s\t%s\n", table[t].name, table[t].help);
|
|
return 0;
|
|
default:
|
|
printf ("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]);
|
|
else
|
|
{
|
|
for (t = 0;
|
|
t < (sizeof (table) / sizeof (const rtems_rtl_shell_cmd_t));
|
|
++t)
|
|
{
|
|
if (strncmp (argv[arg], table[t].name, strlen (argv[arg])) == 0)
|
|
{
|
|
rtems_rtl_data_t* rtl = rtems_rtl_data ();
|
|
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;
|
|
}
|
|
}
|
|
printf ("error: command not found: %s (try -h)\n", argv[arg]);
|
|
}
|
|
|
|
return 1;
|
|
}
|