diff options
Diffstat (limited to 'cpukit/libmisc/monitor')
22 files changed, 5054 insertions, 0 deletions
diff --git a/cpukit/libmisc/monitor/README b/cpukit/libmisc/monitor/README new file mode 100644 index 0000000000..d5a73da140 --- /dev/null +++ b/cpukit/libmisc/monitor/README @@ -0,0 +1,97 @@ +# +# $Id$ +# + +monitor task + +The monitor task is an optional task that knows about RTEMS +data structures and can print out information about them. +It is a work-in-progress and needs many more commands, but +is useful now. + +The monitor works best when it is the highest priority task, +so all your other tasks should ideally be at some priority +greater than 1. + +To use the monitor: +------------------- + + #include <rtems/monitor.h> + + ... + + rtems_monitor_init(0); + + The parameter to rtems_monitor_init() tells the monitor whether + to suspend itself on startup. A value of 0 causes the monitor + to immediately enter command mode; a non-zero value causes the + monitor to suspend itself after creation and wait for explicit + wakeup. + + + rtems_monitor_wakeup(); + + wakes up a suspended monitor and causes it to reenter command mode. + +Monitor commands +---------------- + + The monitor prompt is 'rtems> '. + Can abbreviate commands to "uniquity" + There is a 'help' command. Here is the output from various + help commands: + + Commands (may be abbreviated) + + help -- get this message or command specific help + task -- show task information + queue -- show message queue information + symbol -- show entries from symbol table + pause -- pause monitor for a specified number of ticks + fatal -- invoke a fatal RTEMS error + + task [id [id ...] ] + display information about the specified tasks. + Default is to display information about all tasks on this node + + queue [id [id ... ] ] + display information about the specified message queues + Default is to display information about all queues on this node + + symbol [ symbolname [symbolname ... ] ] + display value associated with specified symbol. + Defaults to displaying all known symbols. + + pause [ticks] + monitor goes to "sleep" for specified ticks (default is 1) + monitor will resume at end of period or if explicitly awakened + + fatal [status] + Invoke 'rtems_fatal_error_occurred' with 'status' + (default is RTEMS_INTERNAL_ERROR) + + continue + put the monitor to sleep waiting for an explicit wakeup from the + program running. + + +Sample output from 'task' command +--------------------------------- + + rtems> task + ID NAME PRIO STAT MODES EVENTS WAITID WAITARG NOTES + ------------------------------------------------------------------------ + 00010001 UI1 2 READY P:T:nA NONE15: 0x40606348 + 00010002 RMON 1 READY nP NONE15: 0x40604110 + + 'RMON' is the monitor itself, so we have 1 "user" task. + Its modes are P:T:nA which translate to: + + preemptable + timesliced + no ASRS + + It has no events. + It has a notepad value for notepad 15 which is 0x40606348 + (this is the libc thread state) + diff --git a/cpukit/libmisc/monitor/mon-command.c b/cpukit/libmisc/monitor/mon-command.c new file mode 100644 index 0000000000..b16c8f06c0 --- /dev/null +++ b/cpukit/libmisc/monitor/mon-command.c @@ -0,0 +1,244 @@ +/** + * @file + * + * @brief Command support routines for RTEMS monitor. + */ + +/* + * $Id$ + * + * 2001-01-30 KJO (vac4050@cae597.rsc.raytheon.com): + * Fixed rtems_monitor_command_lookup() to accept partial + * commands to uniqeness. Added support for setting + * the monitor prompt via an environment variable: + * RTEMS_MONITOR_PROMPT + * + * CCJ: 26-3-2000, adding command history and command line + * editing. This code is donated from My Right Boot and not + * covered by GPL, only the RTEMS license. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <stdio.h> + +#include <rtems.h> +#include <rtems/monitor.h> + +static void +rtems_monitor_show_help ( + const rtems_monitor_command_entry_t *help_cmd, + int max_cmd_len +) +{ +#define MAX_HELP_LINE_LENGTH (75 - max_cmd_len - 2) + + if (help_cmd && help_cmd->command) + { + const char *help = help_cmd->usage; + int help_len = strlen (help); + int spaces = max_cmd_len - strlen (help_cmd->command); + int show_this_line = 0; + int line_one = 1; + int c; + + fprintf(stdout,"%s", help_cmd->command); + + if (help_len == 0) + { + fprintf(stdout," - No help associated.\n"); + return; + } + + while (help_len) + { + fprintf(stdout,"%*c", spaces, ' '); + + if (line_one) + fprintf(stdout," - "); + + spaces = max_cmd_len + 2; + line_one = 0; + + /* + * See if greater then the line length if so, work back + * from the end for a space, tab or lf or cr. + */ + + if (help_len > MAX_HELP_LINE_LENGTH) + { + for (show_this_line = MAX_HELP_LINE_LENGTH - 1; + show_this_line; + show_this_line--) + if ((help[show_this_line] == ' ') || + (help[show_this_line] == '\n') || + (help[show_this_line] == '\r')) + break; + + /* + * If show_this_line is 0, it is a very long word !! + */ + + if (show_this_line == 0) + show_this_line = MAX_HELP_LINE_LENGTH - 1; + } + else + show_this_line = help_len; + + for (c = 0; c < show_this_line; c++) + if ((help[c] == '\r') || (help[c] == '\n')) + show_this_line = c; + else + putchar (help[c]); + + fprintf(stdout,"\n"); + + help += show_this_line; + help_len -= show_this_line; + + /* + * Move past the line feeds or what ever else is being skipped. + */ + + while (help_len) + { + if ((*help != '\r') && (*help != '\n')) + break; + + if (*help != ' ') + { + help++; + help_len--; + break; + } + help++; + help_len--; + } + } + } +} + +void +rtems_monitor_command_usage( + const rtems_monitor_command_entry_t *table, + const char *command_name +) +{ + const rtems_monitor_command_entry_t *command = table; + int max_cmd_len = 0; + + /* if first entry in table is a usage, then print it out */ + + if (command_name && (*command_name != '\0')) + { + command = rtems_monitor_command_lookup (command_name); + + if (command) + rtems_monitor_show_help (command, strlen (command_name)); + else + fprintf(stdout,"Unrecognised command; try just 'help'\n"); + return; + } + + /* + * Find the largest command size. + */ + + while (command) + { + int len = command->command ? strlen (command->command) : 0 ; + + if (len > max_cmd_len) + max_cmd_len = len; + + command = command->next; + } + + max_cmd_len++; + + command = table; + + /* + * Now some nice formatting for the help. + */ + + while (command) + { + rtems_monitor_show_help (command, max_cmd_len); + command = command->next; + } +} + + +void rtems_monitor_help_cmd( + int argc, + char **argv, + const rtems_monitor_command_arg_t *command_arg, + bool verbose __attribute__((unused)) +) +{ + int arg; + const rtems_monitor_command_entry_t *command = + command_arg->monitor_command_entry; + + if (argc == 1) + rtems_monitor_command_usage(command, 0); + else + { + for (arg = 1; argv[arg]; arg++) + rtems_monitor_command_usage(command, argv[arg]); + } +} + +typedef struct { + const char *name; + size_t length; + const rtems_monitor_command_entry_t *match; +} rtems_monitor_command_lookup_entry; + +static bool rtems_monitor_command_lookup_routine( + const rtems_monitor_command_entry_t *e, + void *arg +) +{ + rtems_monitor_command_lookup_entry *le = + (rtems_monitor_command_lookup_entry *) arg; + + /* Check name */ + if (strncmp(e->command, le->name, le->length) == 0) { + /* Check for ambiguity */ + if (le->match == NULL) { + le->match = e; + } else { + return false; + } + } + + return true; +} + +/** + * @brief Looks for a command with the name @a name in the list of registered + * commands. + * + * The parameter @a name must not be NULL. + * + * Returns the corresponding command entry or NULL if no command is found. + */ +const rtems_monitor_command_entry_t *rtems_monitor_command_lookup( + const char *name +) +{ + rtems_monitor_command_lookup_entry e = { + .name = name, + .length = strlen( name), + .match = NULL + }; + + rtems_monitor_command_iterate(rtems_monitor_command_lookup_routine, &e); + + return e.match; +} diff --git a/cpukit/libmisc/monitor/mon-config.c b/cpukit/libmisc/monitor/mon-config.c new file mode 100644 index 0000000000..b067db7e2f --- /dev/null +++ b/cpukit/libmisc/monitor/mon-config.c @@ -0,0 +1,136 @@ +/* + * RTEMS Config display support + * + * TODO + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ +#include <rtems.h> +#include <rtems/monitor.h> + +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> /* strtoul() */ + +#define DATACOL 15 +#define CONTCOL DATACOL /* continued col */ + +/* + * Fill in entire monitor config table + * for sending to a remote monitor or printing on the local system + */ + +void +rtems_monitor_config_canonical( + rtems_monitor_config_t *canonical_config, + void *config_void +) +{ + rtems_configuration_table *c = (rtems_configuration_table *) config_void; + rtems_api_configuration_table *r = &Configuration_RTEMS_API; + + canonical_config->work_space_start = c->work_space_start; + canonical_config->work_space_size = c->work_space_size; + canonical_config->maximum_tasks = r->maximum_tasks; + canonical_config->maximum_timers = r->maximum_timers; + canonical_config->maximum_semaphores = r->maximum_semaphores; + canonical_config->maximum_message_queues = r->maximum_message_queues; + canonical_config->maximum_partitions = r->maximum_partitions; + canonical_config->maximum_regions = r->maximum_regions; + canonical_config->maximum_ports = r->maximum_ports; + canonical_config->maximum_periods = r->maximum_periods; + canonical_config->maximum_extensions = c->maximum_extensions; + canonical_config->microseconds_per_tick = c->microseconds_per_tick; + canonical_config->ticks_per_timeslice = c->ticks_per_timeslice; + canonical_config->number_of_initialization_tasks = r->number_of_initialization_tasks; +} + +/* + * This is easy, since there is only 1 (altho we could get them from + * other nodes...) + */ + +void * +rtems_monitor_config_next( + void *object_info __attribute__((unused)), + rtems_monitor_config_t *canonical_config __attribute__((unused)), + rtems_id *next_id +) +{ + rtems_configuration_table *c = &Configuration; + int n = rtems_object_id_get_index(*next_id); + + if (n >= 1) + goto failed; + + _Thread_Disable_dispatch(); + + *next_id += 1; + return (void *) c; + +failed: + *next_id = RTEMS_OBJECT_ID_FINAL; + return 0; +} + + +void +rtems_monitor_config_dump_header( + bool verbose __attribute__((unused)) +) +{ + fprintf(stdout,"\ +INITIAL (startup) Configuration Info\n"); +/*23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 +0 1 2 3 4 5 6 7 */ + rtems_monitor_separator(); +} + + +int +rtems_monitor_config_dump( + rtems_monitor_config_t *monitor_config, + bool verbose __attribute__((unused)) +) +{ + int length = 0; + + length = 0; + length += fprintf(stdout,"WORKSPACE"); + length += rtems_monitor_pad(DATACOL, length); + length += fprintf(stdout,"start: %p; size: 0x%" PRIx32 "\n", + monitor_config->work_space_start, + monitor_config->work_space_size); + + length = 0; + length += fprintf(stdout,"TIME"); + length += rtems_monitor_pad(DATACOL, length); + length += fprintf(stdout,"usec/tick: %" PRId32 "; tick/timeslice: %" PRId32 "; tick/sec: %" PRId32 "\n", + monitor_config->microseconds_per_tick, + monitor_config->ticks_per_timeslice, + 1000000 / monitor_config->microseconds_per_tick); + + length = 0; + length += fprintf(stdout,"MAXIMUMS"); + length += rtems_monitor_pad(DATACOL, length); + length += fprintf(stdout,"tasks: %" PRId32 "; timers: %" PRId32 "; sems: %" PRId32 "; que's: %" PRId32 "; ext's: %" PRId32 "\n", + monitor_config->maximum_tasks, + monitor_config->maximum_timers, + monitor_config->maximum_semaphores, + monitor_config->maximum_message_queues, + monitor_config->maximum_extensions); + length = 0; + length += rtems_monitor_pad(CONTCOL, length); + length += fprintf(stdout,"partitions: %" PRId32 "; regions: %" PRId32 "; ports: %" PRId32 "; periods: %" PRId32 "\n", + monitor_config->maximum_partitions, + monitor_config->maximum_regions, + monitor_config->maximum_ports, + monitor_config->maximum_periods); + return length; +} diff --git a/cpukit/libmisc/monitor/mon-driver.c b/cpukit/libmisc/monitor/mon-driver.c new file mode 100644 index 0000000000..c5c2c468b9 --- /dev/null +++ b/cpukit/libmisc/monitor/mon-driver.c @@ -0,0 +1,144 @@ +/* + * RTEMS monitor IO (device drivers) support + * + * There are 2 "driver" things the monitor knows about. + * + * 1. Regular RTEMS drivers. + * This is a table indexed by major device number and + * containing driver entry points only. + * + * 2. Driver name table. + * A separate table of names for drivers. + * The table converts driver names to a major number + * as index into the driver table and a minor number + * for an argument to driver. + * + * Drivers are displayed with 'driver' command. + * Names are displayed with 'name' command. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ +#include <rtems.h> + +#include <rtems/monitor.h> + +#include <stdio.h> +#include <stdlib.h> /* strtoul() */ +#include <inttypes.h> + +#define DATACOL 15 +#define CONTCOL DATACOL /* continued col */ + + +void +rtems_monitor_driver_canonical( + rtems_monitor_driver_t *canonical_driver, + void *driver_void +) +{ + rtems_driver_address_table *d = (rtems_driver_address_table *) driver_void; + + rtems_monitor_symbol_canonical_by_value(&canonical_driver->initialization, + (void *) d->initialization_entry); + + rtems_monitor_symbol_canonical_by_value(&canonical_driver->open, + (void *) d->open_entry); + rtems_monitor_symbol_canonical_by_value(&canonical_driver->close, + (void *) d->close_entry); + rtems_monitor_symbol_canonical_by_value(&canonical_driver->read, + (void *) d->read_entry); + rtems_monitor_symbol_canonical_by_value(&canonical_driver->write, + (void *) d->write_entry); + rtems_monitor_symbol_canonical_by_value(&canonical_driver->control, + (void *) d->control_entry); +} + + +void * +rtems_monitor_driver_next( + void *object_info __attribute__((unused)), + rtems_monitor_driver_t *canonical_driver, + rtems_id *next_id +) +{ + rtems_configuration_table *c = &Configuration; + uint32_t n = rtems_object_id_get_index(*next_id); + + if (n >= c->number_of_device_drivers) + goto failed; + + _Thread_Disable_dispatch(); + + /* + * dummy up a fake id and name for this item + */ + + canonical_driver->id = n; + canonical_driver->name = rtems_build_name('-', '-', '-', '-'); + + *next_id += 1; + return (void *) (c->Device_driver_table + n); + +failed: + *next_id = RTEMS_OBJECT_ID_FINAL; + return 0; +} + + +void +rtems_monitor_driver_dump_header( + bool verbose __attribute__((unused)) +) +{ + fprintf(stdout,"\ + Major Entry points\n"); +/*23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 +0 1 2 3 4 5 6 7 */ + rtems_monitor_separator(); +} + +void +rtems_monitor_driver_dump( + rtems_monitor_driver_t *monitor_driver, + bool verbose +) +{ + uint32_t length = 0; + +#if defined(RTEMS_USE_16_BIT_OBJECT) + length += fprintf(stdout," %" PRId16 "", monitor_driver->id); +#else + length += fprintf(stdout," %" PRId32 "", monitor_driver->id); +#endif + length += rtems_monitor_pad(13, length); + length += fprintf(stdout,"init: "); + length += rtems_monitor_symbol_dump(&monitor_driver->initialization, verbose); + length += fprintf(stdout,"; control: "); + length += rtems_monitor_symbol_dump(&monitor_driver->control, verbose); + length += fprintf(stdout,"\n"); + length = 0; + + length += rtems_monitor_pad(13, length); + + length += fprintf(stdout,"open: "); + length += rtems_monitor_symbol_dump(&monitor_driver->open, verbose); + length += fprintf(stdout,"; close: "); + length += rtems_monitor_symbol_dump(&monitor_driver->close, verbose); + length += fprintf(stdout,"\n"); + length = 0; + + length += rtems_monitor_pad(13, length); + + length += fprintf(stdout,"read: "); + length += rtems_monitor_symbol_dump(&monitor_driver->read, verbose); + length += fprintf(stdout,"; write: "); + length += rtems_monitor_symbol_dump(&monitor_driver->write, verbose); + length += fprintf(stdout,"\n"); + length = 0; +} diff --git a/cpukit/libmisc/monitor/mon-editor.c b/cpukit/libmisc/monitor/mon-editor.c new file mode 100644 index 0000000000..1104b50185 --- /dev/null +++ b/cpukit/libmisc/monitor/mon-editor.c @@ -0,0 +1,643 @@ +/** + * @file + * + * @brief Command line editor for RTEMS monitor. + */ + +/* + * $Id$ + * + * 2001-01-30 KJO (vac4050@cae597.rsc.raytheon.com): + * Fixed rtems_monitor_command_lookup() to accept partial + * commands to uniqeness. Added support for setting + * the monitor prompt via an environment variable: + * RTEMS_MONITOR_PROMPT + * + * CCJ: 26-3-2000, adding command history and command line + * editing. This code is donated from My Right Boot and not + * covered by GPL, only the RTEMS license. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> + +#include <rtems/monitor.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <inttypes.h> +#include <termios.h> +#include <unistd.h> + +#ifndef MONITOR_PROMPT +#define MONITOR_PROMPT "rtems" /* will have '> ' appended */ +#endif + +/* + * Some key labels to define special keys. + */ + +#define KEYS_EXTENDED (0x8000) +#define KEYS_NORMAL_MASK (0x00ff) +#define KEYS_INS (0) +#define KEYS_DEL (1) +#define KEYS_UARROW (2) +#define KEYS_DARROW (3) +#define KEYS_LARROW (4) +#define KEYS_RARROW (5) +#define KEYS_HOME (6) +#define KEYS_END (7) +#define KEYS_F1 (8) +#define KEYS_F2 (9) +#define KEYS_F3 (10) +#define KEYS_F4 (11) +#define KEYS_F5 (12) +#define KEYS_F6 (13) +#define KEYS_F7 (14) +#define KEYS_F8 (15) +#define KEYS_F9 (16) +#define KEYS_F10 (17) + +#define RTEMS_COMMAND_BUFFER_SIZE (75) + +static char monitor_prompt[32]; +static char buffer[RTEMS_COMMAND_BUFFER_SIZE]; +static int pos; +static int logged_in; + +/* + * History data. + */ + +#define RTEMS_COMMAND_HISTORIES (20) + +static char history_buffer[RTEMS_COMMAND_HISTORIES][RTEMS_COMMAND_BUFFER_SIZE]; +static int history_pos[RTEMS_COMMAND_HISTORIES]; +static int history; +static int history_next; + +/* + * Translation tables. Not sure if this is the best way to + * handle this, how-ever I wish to avoid the overhead of + * including a more complete and standard environment such + * as ncurses. + */ + +struct translation_table +{ + char expecting; + const struct translation_table *branch; + unsigned int key; +}; + +static const struct translation_table trans_two[] = +{ + { '~', 0, KEYS_INS }, + { 0, 0, 0 } +}; + +static const struct translation_table trans_three[] = +{ + { '~', 0, KEYS_DEL }, + { 0, 0, 0 } +}; + +static const struct translation_table trans_tab_csi[] = +{ + { '2', trans_two, 0 }, + { '3', trans_three, 0 }, + { 'A', 0, KEYS_UARROW }, + { 'B', 0, KEYS_DARROW }, + { 'D', 0, KEYS_LARROW }, + { 'C', 0, KEYS_RARROW }, + { 'F', 0, KEYS_END }, + { 'H', 0, KEYS_HOME }, + { 0, 0, 0 } +}; + +static const struct translation_table trans_tab_O[] = +{ + { '1', 0, KEYS_F1 }, + { '2', 0, KEYS_F2 }, + { '3', 0, KEYS_F3 }, + { '4', 0, KEYS_F4 }, + { '5', 0, KEYS_F5 }, + { '6', 0, KEYS_F6 }, + { '7', 0, KEYS_F7 }, + { '8', 0, KEYS_F8 }, + { '9', 0, KEYS_F9 }, + { ':', 0, KEYS_F10 }, + { 'P', 0, KEYS_F1 }, + { 'Q', 0, KEYS_F2 }, + { 'R', 0, KEYS_F3 }, + { 'S', 0, KEYS_F4 }, + { 'T', 0, KEYS_F5 }, + { 'U', 0, KEYS_F6 }, + { 'V', 0, KEYS_F7 }, + { 'W', 0, KEYS_F8 }, + { 'X', 0, KEYS_F9 }, + { 'Y', 0, KEYS_F10 }, + { 0, 0, 0 } +}; + +static const struct translation_table trans_tab[] = +{ + { '[', trans_tab_csi, 0 }, /* CSI command sequences */ + { 'O', trans_tab_O, 0 }, /* O are the fuction keys */ + { 0, 0, 0 } +}; + +/* + * Perform a basic translation for some ANSI/VT100 key codes. + * This code could do with a timeout on the ESC as it is + * now lost from the input stream. It is not* used by the + * line editor below so considiered not worth the effort. + */ + +static unsigned int +rtems_monitor_getchar (void) +{ + const struct translation_table *translation = 0; + for (;;) + { + char c = getchar (); + if (c == 27) + translation = trans_tab; + else + { + /* + * If no translation happing just pass through + * and return the key. + */ + if (translation) + { + /* + * Scan the current table for the key, and if found + * see if this key is a fork. If so follow it and + * wait else return the extended key. + */ + int index = 0; + int branched = 0; + while ((translation[index].expecting != '\0') || + (translation[index].key != '\0')) + { + if (translation[index].expecting == c) + { + /* + * A branch is take if more keys are to come. + */ + if (translation[index].branch == 0) + return KEYS_EXTENDED | translation[index].key; + else + { + translation = translation[index].branch; + branched = 1; + break; + } + } + index++; + } + /* + * Who knows what these keys are, just drop them. + */ + if (!branched) + translation = 0; + } + else + return c; + } + } +} + +/* + * The line editor with history. + */ + +static int +rtems_monitor_line_editor ( + char *command +) +{ + int repeating = 0; + + memset (buffer, 0, RTEMS_COMMAND_BUFFER_SIZE); + history = history_next; + pos = 0; + + if (!logged_in) + fprintf(stdout,"\nMonitor ready, press enter to login.\n\n"); + else + fprintf(stdout,"%s $ ", monitor_prompt); + + while (1) + { + unsigned int extended_key; + char c; + + fflush (stdout); + + extended_key = rtems_monitor_getchar (); + c = extended_key & KEYS_NORMAL_MASK; + + /* + * Make the extended_key usable as a boolean. + */ + extended_key &= ~KEYS_NORMAL_MASK; + + if (!extended_key && !logged_in) + { + if (c == '\n') + { + logged_in = 1; + /* + * The prompt has changed from `>' to `$' to help know + * which version of the monitor code people are using. + */ + fprintf(stdout,"%s $ ", monitor_prompt); + } + } + else + { + if (extended_key) + { + switch (c) + { + case KEYS_END: + fprintf(stdout,buffer + pos); + pos = (int) strlen (buffer); + break; + + case KEYS_HOME: + fprintf(stdout,"\r%s $ ", monitor_prompt); + pos = 0; + break; + + case KEYS_LARROW: + if (pos > 0) + { + pos--; + putchar ('\b'); + } + break; + + case KEYS_RARROW: + if ((pos < RTEMS_COMMAND_BUFFER_SIZE) && (buffer[pos] != '\0')) + { + putchar (buffer[pos]); + pos++; + } + break; + + case KEYS_UARROW: + /* + * If we are moving up the histories then we need to save the working + * buffer. + */ + if (history) + { + int end; + int bs; + if (history == history_next) + { + memcpy (history_buffer[history_next], buffer, + RTEMS_COMMAND_BUFFER_SIZE); + history_pos[history_next] = pos; + } + history--; + memcpy (buffer, history_buffer[history], + RTEMS_COMMAND_BUFFER_SIZE); + pos = history_pos[history]; + fprintf(stdout,"\r%*c", RTEMS_COMMAND_BUFFER_SIZE, ' '); + fprintf(stdout,"\r%s $ %s", monitor_prompt, buffer); + end = (int) strlen (buffer); + for (bs = 0; bs < (end - pos); bs++) + putchar ('\b'); + } + break; + + case KEYS_DARROW: + if (history < history_next) + { + int end; + int bs; + history++; + memcpy (buffer, history_buffer[history], + RTEMS_COMMAND_BUFFER_SIZE); + pos = history_pos[history]; + fprintf(stdout,"\r%*c", RTEMS_COMMAND_BUFFER_SIZE, ' '); + fprintf(stdout,"\r%s $ %s", monitor_prompt, buffer); + end = (int) strlen (buffer); + for (bs = 0; bs < (end - pos); bs++) + putchar ('\b'); + } + break; + + case KEYS_DEL: + if (buffer[pos] != '\0') + { + int end; + int bs; + strcpy (&buffer[pos], &buffer[pos + 1]); + fprintf(stdout,"\r%s $ %s", monitor_prompt, buffer); + end = (int) strlen (buffer); + for (bs = 0; bs < (end - pos); bs++) + putchar ('\b'); + } + break; + } + } + else + { + switch (c) + { + case '\b': + case '\x7e': + case '\x7f': + if (pos > 0) + { + int bs; + pos--; + strcpy (buffer + pos, buffer + pos + 1); + fprintf(stdout,"\b%s \b", buffer + pos); + for (bs = 0; bs < ((int) strlen (buffer) - pos); bs++) + putchar ('\b'); + } + break; + + case '\n': + /* + * Process the command. + */ + fprintf(stdout,"\n"); + repeating = 1; + /* + * Only process the history if we have a command and + *a history. + */ + if (strlen (buffer)) + { + if (history_next && (history == history_next)) + { + /* + * Do not place the last command into the history + *if the same. + */ + if (strcmp (history_buffer[history_next - 1], buffer)) + repeating = 0; + } + else + repeating = 0; + } + if (!repeating) + { + memcpy (history_buffer[history_next], buffer, + RTEMS_COMMAND_BUFFER_SIZE); + history_pos[history_next] = pos; + if (history_next < (RTEMS_COMMAND_HISTORIES - 1)) + history_next++; + else + { + memmove (history_buffer[0], history_buffer[1], + RTEMS_COMMAND_BUFFER_SIZE * (RTEMS_COMMAND_HISTORIES - 1)); + memmove (&history_pos[0], &history_pos[1], + sizeof (history_pos[0]) * (RTEMS_COMMAND_HISTORIES - 1)); + } + } + else + { +#ifdef ENABLE_ENTER_REPEATS + if (history_next) + memcpy (buffer, history_buffer[history_next - 1], + RTEMS_COMMAND_BUFFER_SIZE); +#endif + } + memmove (command, buffer, RTEMS_COMMAND_BUFFER_SIZE); + return repeating; + break; + + default: + if ((pos < (RTEMS_COMMAND_BUFFER_SIZE - 1)) && + (c >= ' ') && (c <= 'z')) + { + int end; + end = strlen (buffer); + if ((pos < end) && (end < RTEMS_COMMAND_BUFFER_SIZE)) + { + int ch, bs; + for (ch = end; ch > pos; ch--) + buffer[ch] = buffer[ch - 1]; + fprintf(stdout,buffer + pos); + for (bs = 0; bs < (end - pos + 1); bs++) + putchar ('\b'); + } + buffer[pos++] = c; + if (pos > end) + buffer[pos] = '\0'; + putchar (c); + } + break; + } + } + } + } +} + +/* + * make_argv(cp): token-count + * Break up the command line in 'cp' into global argv[] and argc (return + * value). + */ + +int +rtems_monitor_make_argv( + char *cp, + int *argc_p, + char **argv) +{ + int argc = 0; + + while ((cp = strtok(cp, " \t\n\r"))) + { + argv[argc++] = cp; + cp = (char *) NULL; + } + argv[argc] = (char *) NULL; /* end of argv */ + + return *argc_p = argc; +} + + +/* + * Read and break up a monitor command + * + * We have to loop on the gets call, since it will return NULL under UNIX + * RTEMS when we get a signal (eg: SIGALRM). + */ + +int +rtems_monitor_command_read(char *command, + int *argc, + char **argv) +{ + char *env_prompt; + + env_prompt = getenv("RTEMS_MONITOR_PROMPT"); + + /* + * put node number in the prompt if we are multiprocessing + */ +#if defined(RTEMS_MULTIPROCESSING) + if (!rtems_configuration_get_user_multiprocessing_table ()) + sprintf (monitor_prompt, "%s", + (env_prompt == NULL) ? MONITOR_PROMPT: env_prompt); + else /* .... */ +#endif + if (rtems_monitor_default_node != rtems_monitor_node) + sprintf (monitor_prompt, "%" PRId32 "-%s-%" PRId32 "", rtems_monitor_node, + (env_prompt == NULL) ? MONITOR_PROMPT : env_prompt, + rtems_monitor_default_node); + else + sprintf (monitor_prompt, "%" PRId32 "-%s", rtems_monitor_node, + (env_prompt == NULL) ? MONITOR_PROMPT : env_prompt); + + rtems_monitor_line_editor (command); + + return rtems_monitor_make_argv (command, argc, argv); +} + +/* + * Main monitor command loop + */ + +void +rtems_monitor_task( + rtems_task_argument monitor_flags +) +{ + rtems_tcb *debugee = 0; + rtems_context *rp; +#if (CPU_HARDWARE_FP == TRUE) || (CPU_SOFTWARE_FP == TRUE) + rtems_context_fp *fp; +#endif + char command_buffer[513]; + int argc; + char *argv[64]; + bool verbose = false; + struct termios term; + + /* + * Make the stdin stream characte not line based. + */ + + if (tcgetattr (STDIN_FILENO, &term) < 0) + { + fprintf(stdout,"rtems-monitor: cannot get terminal attributes.\n"); + } + else + { + /* + * No echo, no canonical processing. + */ + + term.c_lflag &= ~(ECHO | ICANON | IEXTEN); + + /* + * No sigint on BREAK, CR-to-NL off, input parity off, + * don't strip 8th bit on input, output flow control off + */ + + term.c_lflag &= ~(INPCK | ISTRIP | IXON); + term.c_cc[VMIN] = 1; + term.c_cc[VTIME] = 0; + + if (tcsetattr (STDIN_FILENO, TCSANOW, &term) < 0) + { + fprintf(stdout,"cannot set terminal attributes\n"); + } + } + + if (!(monitor_flags & RTEMS_MONITOR_NOSYMLOAD)) { + rtems_monitor_symbols_loadup(); + } + + if (monitor_flags & RTEMS_MONITOR_SUSPEND) + (void) rtems_monitor_suspend(RTEMS_NO_TIMEOUT); + + for (;;) + { + const rtems_monitor_command_entry_t *command; + + debugee = _Thread_Executing; + rp = &debugee->Registers; +#if (CPU_HARDWARE_FP == TRUE) || (CPU_SOFTWARE_FP == TRUE) + fp = debugee->fp_context; /* possibly 0 */ +#endif + + if (0 == rtems_monitor_command_read(command_buffer, &argc, argv)) + continue; + if (argc < 1 + || (command = rtems_monitor_command_lookup(argv [0])) == 0) { + /* no command */ + fprintf(stdout,"Unrecognised command; try 'help'\n"); + continue; + } + + command->command_function(argc, argv, &command->command_arg, verbose); + + fflush(stdout); + } +} + + +void +rtems_monitor_kill(void) +{ + if (rtems_monitor_task_id) + rtems_task_delete(rtems_monitor_task_id); + rtems_monitor_task_id = 0; + + rtems_monitor_server_kill(); +} + +void +rtems_monitor_init( + uint32_t monitor_flags +) +{ + rtems_status_code status; + + rtems_monitor_kill(); + + status = rtems_task_create(RTEMS_MONITOR_NAME, + 1, + RTEMS_MINIMUM_STACK_SIZE * 2, + RTEMS_INTERRUPT_LEVEL(0), + RTEMS_DEFAULT_ATTRIBUTES, + &rtems_monitor_task_id); + if (status != RTEMS_SUCCESSFUL) + { + rtems_error(status, "could not create monitor task"); + return; + } + + rtems_monitor_node = rtems_object_id_get_node(rtems_monitor_task_id); + rtems_monitor_default_node = rtems_monitor_node; + + rtems_monitor_server_init(monitor_flags); + + if (!(monitor_flags & RTEMS_MONITOR_NOTASK)) { + /* + * Start the monitor task itself + */ + status = rtems_task_start( + rtems_monitor_task_id, rtems_monitor_task, monitor_flags); + if (status != RTEMS_SUCCESSFUL) { + rtems_error(status, "could not start monitor"); + return; + } + } +} diff --git a/cpukit/libmisc/monitor/mon-extension.c b/cpukit/libmisc/monitor/mon-extension.c new file mode 100644 index 0000000000..c6a9f72040 --- /dev/null +++ b/cpukit/libmisc/monitor/mon-extension.c @@ -0,0 +1,102 @@ +/* + * RTEMS Monitor extension support + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/monitor.h> + +#include <stdio.h> + +void +rtems_monitor_extension_canonical( + rtems_monitor_extension_t *canonical_extension, + void *extension_void +) +{ + Extension_Control *rtems_extension = (Extension_Control *) extension_void; + rtems_extensions_table *e = &rtems_extension->Extension.Callouts; + + rtems_monitor_symbol_canonical_by_value(&canonical_extension->e_create, + (void *) e->thread_create); + + rtems_monitor_symbol_canonical_by_value(&canonical_extension->e_start, + (void *) e->thread_start); + rtems_monitor_symbol_canonical_by_value(&canonical_extension->e_restart, + (void *) e->thread_restart); + rtems_monitor_symbol_canonical_by_value(&canonical_extension->e_delete, + (void *) e->thread_delete); + rtems_monitor_symbol_canonical_by_value(&canonical_extension->e_tswitch, + (void *) e->thread_switch); + rtems_monitor_symbol_canonical_by_value(&canonical_extension->e_begin, + (void *) e->thread_begin); + rtems_monitor_symbol_canonical_by_value(&canonical_extension->e_exitted, + (void *) e->thread_exitted); + rtems_monitor_symbol_canonical_by_value(&canonical_extension->e_fatal, + (void *) e->fatal); +} + +void +rtems_monitor_extension_dump_header( + bool verbose __attribute__((unused)) +) +{ + fprintf(stdout,"\ + ID NAME\n"); +/*23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 +0 1 2 3 4 5 6 7 */ + + rtems_monitor_separator(); +} + + +/* + * Dump out the canonical form + */ + +void +rtems_monitor_extension_dump( + rtems_monitor_extension_t *monitor_extension, + bool verbose +) +{ + uint32_t length = 0; + + length += rtems_monitor_dump_id(monitor_extension->id); + length += rtems_monitor_pad(11, length); + length += rtems_monitor_dump_name(monitor_extension->id); + + length += rtems_monitor_pad(18, length); + length += fprintf(stdout,"create: "); + length += rtems_monitor_symbol_dump(&monitor_extension->e_create, verbose); + length += fprintf(stdout,"; start: "); + length += rtems_monitor_symbol_dump(&monitor_extension->e_start, verbose); + length += fprintf(stdout,"; restart: "); + length += rtems_monitor_symbol_dump(&monitor_extension->e_restart, verbose); + length += fprintf(stdout,"\n"); + length = 0; + + length += rtems_monitor_pad(18, length); + length += fprintf(stdout,"delete: "); + length += rtems_monitor_symbol_dump(&monitor_extension->e_delete, verbose); + length += fprintf(stdout,"; switch: "); + length += rtems_monitor_symbol_dump(&monitor_extension->e_tswitch, verbose); + length += fprintf(stdout,"; begin: "); + length += rtems_monitor_symbol_dump(&monitor_extension->e_begin, verbose); + length += fprintf(stdout,"\n"); + length = 0; + + length += rtems_monitor_pad(18, length); + length += fprintf(stdout,"exitted: "); + length += rtems_monitor_symbol_dump(&monitor_extension->e_exitted, verbose); + length += fprintf(stdout,"; fatal: "); + length += rtems_monitor_symbol_dump(&monitor_extension->e_fatal, verbose); + length += fprintf(stdout,"\n"); + length = 0; + fprintf(stdout,"\n"); +} diff --git a/cpukit/libmisc/monitor/mon-itask.c b/cpukit/libmisc/monitor/mon-itask.c new file mode 100644 index 0000000000..6dab51a768 --- /dev/null +++ b/cpukit/libmisc/monitor/mon-itask.c @@ -0,0 +1,121 @@ +/* + * RTEMS Monitor init task support + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ +#include <rtems.h> +#include <rtems/monitor.h> + +#include <inttypes.h> +#include <stdio.h> + +/* + * As above, but just for init tasks + */ +void +rtems_monitor_init_task_canonical( + rtems_monitor_init_task_t *canonical_itask, + void *itask_void +) +{ + rtems_initialization_tasks_table *rtems_itask = itask_void; + + rtems_monitor_symbol_canonical_by_value(&canonical_itask->entry, + (void *) rtems_itask->entry_point); + + canonical_itask->argument = rtems_itask->argument; + canonical_itask->stack_size = rtems_itask->stack_size; + canonical_itask->priority = rtems_itask->initial_priority; + canonical_itask->modes = rtems_itask->mode_set; + canonical_itask->attributes = rtems_itask->attribute_set; +} + +void * +rtems_monitor_init_task_next( + void *object_info __attribute__((unused)), + rtems_monitor_init_task_t *canonical_init_task, + rtems_id *next_id +) +{ + rtems_initialization_tasks_table *itask; + uint32_t n = rtems_object_id_get_index(*next_id); + + if (n >= Configuration_RTEMS_API.number_of_initialization_tasks) + goto failed; + + _Thread_Disable_dispatch(); + + itask = Configuration_RTEMS_API.User_initialization_tasks_table + n; + + /* + * dummy up a fake id and name for this item + */ + + canonical_init_task->id = n; + canonical_init_task->name = itask->name; + + *next_id += 1; + return (void *) itask; + +failed: + *next_id = RTEMS_OBJECT_ID_FINAL; + return 0; +} + + +void +rtems_monitor_init_task_dump_header( + bool verbose __attribute__((unused)) +) +{ + fprintf(stdout,"\ + # NAME ENTRY ARGUMENT PRIO MODES ATTRIBUTES STACK SIZE\n"); +/*23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 +0 1 2 3 4 5 6 7 */ + rtems_monitor_separator(); +} + +/* + */ + +void +rtems_monitor_init_task_dump( + rtems_monitor_init_task_t *monitor_itask, + bool verbose +) +{ + int length = 0; + + length += rtems_monitor_dump_decimal(monitor_itask->id); + + length += rtems_monitor_pad(7, length); + length += rtems_monitor_dump_name(monitor_itask->id); + + length += rtems_monitor_pad(14, length); + length += rtems_monitor_symbol_dump(&monitor_itask->entry, verbose); + + length += rtems_monitor_pad(25, length); + length += fprintf(stdout,"%" PRId32 " [0x%" PRIx32 "]", + monitor_itask->argument, monitor_itask->argument); + + length += rtems_monitor_pad(39, length); + length += rtems_monitor_dump_priority(monitor_itask->priority); + + length += rtems_monitor_pad(46, length); + length += rtems_monitor_dump_modes(monitor_itask->modes); + + length += rtems_monitor_pad(54, length); + length += rtems_monitor_dump_attributes(monitor_itask->attributes); + + length += rtems_monitor_pad(66, length); + length += fprintf(stdout,"%" PRId32 " [0x%" PRIx32 "]", + monitor_itask->stack_size, monitor_itask->stack_size); + + fprintf(stdout,"\n"); +} diff --git a/cpukit/libmisc/monitor/mon-manager.c b/cpukit/libmisc/monitor/mon-manager.c new file mode 100644 index 0000000000..9e71addfae --- /dev/null +++ b/cpukit/libmisc/monitor/mon-manager.c @@ -0,0 +1,55 @@ +/* + * RTEMS Monitor "manager" support. + * Used to traverse object (chain) lists and print them out. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/monitor.h> + +#include <stdio.h> + +/* + * "next" routine for all objects that are RTEMS manager objects + */ + +void * +rtems_monitor_manager_next( + void *table_void, + void *canonical, + rtems_id *next_id +) +{ + Objects_Information *table = table_void; + rtems_monitor_generic_t *copy; + Objects_Control *object = 0; + Objects_Locations location; + + /* + * When we are called, it must be local + */ + +#if defined(RTEMS_MULTIPROCESSING) + if ( ! _Objects_Is_local_id(*next_id) ) + goto done; +#endif + + object = _Objects_Get_next(table, *next_id, &location, next_id); + + if (object) + { + copy = (rtems_monitor_generic_t *) canonical; + copy->id = object->id; + copy->name = object->name.name_u32; + } + +#if defined(RTEMS_MULTIPROCESSING) +done: +#endif + return object; +} diff --git a/cpukit/libmisc/monitor/mon-monitor.c b/cpukit/libmisc/monitor/mon-monitor.c new file mode 100644 index 0000000000..88f3d49eb3 --- /dev/null +++ b/cpukit/libmisc/monitor/mon-monitor.c @@ -0,0 +1,529 @@ +/* + * RTEMS monitor main body + * + * TODO: + * add stuff to RTEMS api + * rtems_get_name(id) + * rtems_get_type(id) + * rtems_build_id(node, type, num) + * Add a command to dump out info about an arbitrary id when + * types are added to id's + * rtems> id idnum + * idnum: node n, object: whatever, id: whatever + * allow id's to be specified as n:t:id, where 'n:t' is optional + * should have a separate monitor FILE stream (ala the debugger) + * remote request/response stuff should be cleaned up + * maybe we can use real rpc?? + * 'info' command to print out: + * interrupt stack location, direction and size + * floating point config stuff + * interrupt config stuff + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <rtems/monitor.h> + +/* set by trap handler */ +extern rtems_tcb *debugger_interrupted_task; +extern rtems_context *debugger_interrupted_task_context; +extern uint32_t debugger_trap; + +/* + * Various id's for the monitor + * They need to be public variables for access by other agencies + * such as debugger and remote servers' + */ + +rtems_id rtems_monitor_task_id; + +uint32_t rtems_monitor_node; /* our node number */ +uint32_t rtems_monitor_default_node; /* current default for commands */ + +/* + * The rtems symbol table + */ + +rtems_symbol_table_t *rtems_monitor_symbols; + +/* + * The top-level commands + */ + +static const rtems_monitor_command_entry_t rtems_monitor_commands[] = { + { "config", + "Show the system configuration.", + 0, + rtems_monitor_object_cmd, + { RTEMS_MONITOR_OBJECT_CONFIG }, + &rtems_monitor_commands[1], + }, + { "itask", + "List init tasks for the system", + 0, + rtems_monitor_object_cmd, + { RTEMS_MONITOR_OBJECT_INIT_TASK }, + &rtems_monitor_commands[2], + }, + { "mpci", + "Show the MPCI system configuration, if configured.", + 0, + rtems_monitor_object_cmd, + { RTEMS_MONITOR_OBJECT_MPCI }, + &rtems_monitor_commands[3], + }, + { "pause", + "Monitor goes to \"sleep\" for specified ticks (default is 1). " + "Monitor will resume at end of period or if explicitly awakened\n" + " pause [ticks]", + 0, + rtems_monitor_pause_cmd, + { 0 }, + &rtems_monitor_commands[4], + }, + { "continue", + "Put the monitor to sleep waiting for an explicit wakeup from the " + "program running.\n", + 0, + rtems_monitor_continue_cmd, + { 0 }, + &rtems_monitor_commands[5], + }, + { "go", + "Alias for 'continue'", + 0, + rtems_monitor_continue_cmd, + { 0 }, + &rtems_monitor_commands[6], + }, + { "symbol", + "Display value associated with specified symbol. " + "Defaults to displaying all known symbols.\n" + " symbol [ symbolname [symbolname ... ] ]", + 0, + rtems_monitor_symbol_cmd, + { .symbol_table = &rtems_monitor_symbols }, + &rtems_monitor_commands[7], + }, + { "extension", + "Display information about specified extensions. " + "Default is to display information about all extensions on this node.\n" + " extension [id [id ...] ]", + 0, + rtems_monitor_object_cmd, + { RTEMS_MONITOR_OBJECT_EXTENSION }, + &rtems_monitor_commands[8], + }, + { "task", + "Display information about the specified tasks. " + "Default is to display information about all tasks on this node.\n" + " task [id [id ...] ]", + 0, + rtems_monitor_object_cmd, + { RTEMS_MONITOR_OBJECT_TASK }, + &rtems_monitor_commands[9], + }, + { "queue", + "Display information about the specified message queues. " + "Default is to display information about all queues on this node.\n" + " queue [id [id ... ] ]", + 0, + rtems_monitor_object_cmd, + { RTEMS_MONITOR_OBJECT_QUEUE }, + &rtems_monitor_commands[10], + }, + { "sema", + "sema [id [id ... ] ]\n" + " display information about the specified semaphores\n" + " Default is to display information about all semaphores on this node\n" + , + 0, + rtems_monitor_object_cmd, + { RTEMS_MONITOR_OBJECT_SEMAPHORE }, + &rtems_monitor_commands[11], + }, + { "region", + "region [id [id ... ] ]\n" + " display information about the specified regions\n" + " Default is to display information about all regions on this node\n" + , + 0, + rtems_monitor_object_cmd, + { RTEMS_MONITOR_OBJECT_REGION }, + &rtems_monitor_commands[12], + }, + { "part", + "part [id [id ... ] ]\n" + " display information about the specified partitions\n" + " Default is to display information about all partitions on this node\n" + , + 0, + rtems_monitor_object_cmd, + { RTEMS_MONITOR_OBJECT_PARTITION }, + &rtems_monitor_commands[13], + }, + { "object", + "Display information about specified RTEMS objects. " + "Object id's must include 'type' information. " + "(which may normally be defaulted)\n" + " object [id [id ...] ]", + 0, + rtems_monitor_object_cmd, + { RTEMS_MONITOR_OBJECT_INVALID }, + &rtems_monitor_commands[14], + }, + { "driver", + "Display the RTEMS device driver table.\n" + " driver [ major [ major ... ] ]", + 0, + rtems_monitor_object_cmd, + { RTEMS_MONITOR_OBJECT_DRIVER }, + &rtems_monitor_commands[15], + }, + { "dname", + "Displays information about named drivers.\n", + 0, + rtems_monitor_object_cmd, + { RTEMS_MONITOR_OBJECT_DNAME }, + &rtems_monitor_commands[16], + }, + { "exit", + "Invoke 'rtems_fatal_error_occurred' with 'status' " + "(default is RTEMS_SUCCESSFUL)\n" + " exit [status]", + 0, + rtems_monitor_fatal_cmd, + { .status_code = RTEMS_SUCCESSFUL }, + &rtems_monitor_commands[17], + }, + { "fatal", + "'exit' with fatal error; default error is RTEMS_TASK_EXITTED\n" + " fatal [status]", + 0, + rtems_monitor_fatal_cmd, + { .status_code = RTEMS_TASK_EXITTED }, /* exit value */ + &rtems_monitor_commands[18], + }, + { "quit", + "Alias for 'exit'\n", + 0, + rtems_monitor_fatal_cmd, + { .status_code = RTEMS_SUCCESSFUL }, /* exit value */ + &rtems_monitor_commands[19], + }, + { "reset", + "(SW)Resets the System.", + 0, + rtems_monitor_reset_cmd, + { 0 }, + &rtems_monitor_commands[20], + }, +#if defined(RTEMS_MULTIPROCESSING) + { "node", + "Specify default node number for commands that take id's.\n" + " node [ node number ]", + 0, + rtems_monitor_node_cmd, + { 0 }, + &rtems_monitor_commands[21], + }, + #define RTEMS_MONITOR_POSIX_NEXT 22 +#else + #define RTEMS_MONITOR_POSIX_NEXT 21 +#endif +#ifdef RTEMS_POSIX_API + { "pthread", + "Display information about the specified pthreads. " + "Default is to display information about all pthreads on this node.\n" + " pthread [id [id ...] ]", + 0, + rtems_monitor_object_cmd, + { RTEMS_MONITOR_OBJECT_PTHREAD }, + &rtems_monitor_commands[RTEMS_MONITOR_POSIX_NEXT], + }, + #define RTEMS_MONITOR_DEBUGGER_NEXT (RTEMS_MONITOR_POSIX_NEXT + 1) +#else + #define RTEMS_MONITOR_DEBUGGER_NEXT RTEMS_MONITOR_POSIX_NEXT +#endif +#ifdef CPU_INVOKE_DEBUGGER + { "debugger", + "Enter the debugger, if possible. " + "A continue from the debugger will return to the monitor.\n", + 0, + rtems_monitor_debugger_cmd, + { 0 }, + &rtems_monitor_commands[RTEMS_MONITOR_DEBUGGER_NEXT], + }, +#endif + { "help", + "Provide information about commands. " + "Default is show basic command summary.\n" + "help [ command [ command ] ]", + 0, + rtems_monitor_help_cmd, + { .monitor_command_entry = rtems_monitor_commands }, + NULL + } +}; + +/* + * All registered commands. + */ + +static const rtems_monitor_command_entry_t *rtems_monitor_registered_commands = + &rtems_monitor_commands [0]; + + +rtems_status_code +rtems_monitor_suspend(rtems_interval timeout) +{ + rtems_event_set event_set; + rtems_status_code status; + + status = rtems_event_receive(MONITOR_WAKEUP_EVENT, + RTEMS_DEFAULT_OPTIONS, + timeout, + &event_set); + return status; +} + +void __attribute__((weak)) +rtems_monitor_reset_cmd( + int argc, + char **argv, + const rtems_monitor_command_arg_t* command_arg, + bool verbose +) +{ + +} + +void +rtems_monitor_wakeup(void) +{ + rtems_status_code status; + + status = rtems_event_send(rtems_monitor_task_id, MONITOR_WAKEUP_EVENT); +} + +void rtems_monitor_debugger_cmd( + int argc __attribute__((unused)), + char **argv __attribute__((unused)), + const rtems_monitor_command_arg_t *command_arg __attribute__((unused)), + bool verbose __attribute__((unused)) +) +{ +#ifdef CPU_INVOKE_DEBUGGER + CPU_INVOKE_DEBUGGER; +#endif +} + +void rtems_monitor_pause_cmd( + int argc, + char **argv, + const rtems_monitor_command_arg_t *command_arg __attribute__((unused)), + bool verbose __attribute__((unused)) +) +{ + if (argc == 1) + rtems_monitor_suspend(1); + else + rtems_monitor_suspend(strtoul(argv[1], 0, 0)); +} + +void rtems_monitor_fatal_cmd( + int argc, + char **argv, + const rtems_monitor_command_arg_t *command_arg, + bool verbose __attribute__((unused)) +) +{ + if (argc == 1) + rtems_fatal_error_occurred(command_arg->status_code); + else + rtems_fatal_error_occurred(strtoul(argv[1], 0, 0)); +} + +void rtems_monitor_continue_cmd( + int argc __attribute__((unused)), + char **argv __attribute__((unused)), + const rtems_monitor_command_arg_t *command_arg __attribute__((unused)), + bool verbose __attribute__((unused)) +) +{ + rtems_monitor_suspend(RTEMS_NO_TIMEOUT); +} + +#if defined(RTEMS_MULTIPROCESSING) +void rtems_monitor_node_cmd( + int argc, + char **argv, + const rtems_monitor_command_arg_t *command_arg __attribute__((unused)), + bool verbose __attribute__((unused)) +) +{ + uint32_t new_node = rtems_monitor_default_node; + + switch (argc) { + case 1: /* no node, just set back to ours */ + new_node = rtems_monitor_node; + break; + + case 2: + new_node = strtoul(argv[1], 0, 0); + break; + + default: + fprintf(stdout,"invalid syntax, try 'help node'\n"); + break; + } + + if ((new_node >= 1) && + _Configuration_MP_table && + (new_node <= _Configuration_MP_table->maximum_nodes)) + rtems_monitor_default_node = new_node; +} +#endif + + +/* + * Function: rtems_monitor_symbols_loadup + * + * Description: + * Create and load the monitor's symbol table. + * We are reading the output format of 'gnm' which looks like this: + * + * 400a7068 ? _Rate_monotonic_Information + * 400a708c ? _Thread_Dispatch_disable_level + * 400a7090 ? _Configuration_Table + * + * We ignore the type field. + * + * Side Effects: + * Creates and fills in 'rtems_monitor_symbols' table + * + * TODO + * there should be a BSP #define or something like that + * to do this; Assuming stdio is crazy. + * Someday this should know BFD + * Maybe we could get objcopy to just copy the symbol areas + * and copy that down. + * + */ + +void +rtems_monitor_symbols_loadup(void) +{ + FILE *fp; + char buffer[128]; + + if (rtems_monitor_symbols) + rtems_symbol_table_destroy(rtems_monitor_symbols); + + rtems_monitor_symbols = rtems_symbol_table_create(); + if (rtems_monitor_symbols == 0) + return; + + fp = fopen("symbols", "r"); + + if (fp == 0) + return; + + while (fgets(buffer, sizeof(buffer) - 1, fp)) + { + char *symbol; + char *value; + char *ignored_type; + + value = strtok(buffer, " \t\n"); + ignored_type = strtok(0, " \t\n"); + symbol = strtok(0, " \t\n"); + + if (symbol && ignored_type && value) + { + rtems_symbol_t *sp; + sp = rtems_symbol_create(rtems_monitor_symbols, + symbol, + (uint32_t) strtoul(value, 0, 16)); + if (sp == 0) + { + fprintf(stdout,"could not define symbol '%s'\n", symbol); + goto done; + } + } + else + { + fprintf(stdout,"parsing error on '%s'\n", buffer); + goto done; + } + } + +done: + fclose(fp); + return; +} + +/* + * User registered commands. + */ + +int +rtems_monitor_insert_cmd ( + rtems_monitor_command_entry_t *command +) +{ + const rtems_monitor_command_entry_t *e = rtems_monitor_registered_commands; + + /* Reject empty commands */ + if (command->command == NULL) { + return 0; + } + + /* Reject command if already present */ + while (e->next != NULL) { + if (e->command != NULL && strcmp(command->command, e->command) == 0) { + return 0; + } + e = e->next; + } + + /* Prepend new command */ + command->next = rtems_monitor_registered_commands; + rtems_monitor_registered_commands = command; + + return 1; +} + +/** + * @brief Iterates through all registerd commands. + * + * For each command the interation routine @a routine is called with the + * command entry and the user provided argument @a arg. It is guaranteed that + * the command name and function are not NULL. + */ +void rtems_monitor_command_iterate( + rtems_monitor_per_command_routine routine, + void *arg +) +{ + const rtems_monitor_command_entry_t *e = rtems_monitor_registered_commands; + + while (e != NULL) { + if (e->command != NULL && e->command_function != NULL) { + if (!routine(e, arg)) { + break; + } + } + e = e->next; + } +} diff --git a/cpukit/libmisc/monitor/mon-mpci.c b/cpukit/libmisc/monitor/mon-mpci.c new file mode 100644 index 0000000000..ab77431241 --- /dev/null +++ b/cpukit/libmisc/monitor/mon-mpci.c @@ -0,0 +1,163 @@ +/* + * RTEMS MPCI Config display support + * + * TODO + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ +#include <rtems.h> +#include <rtems/monitor.h> + +#include <stdio.h> +#include <stdlib.h> /* strtoul() */ +#include <inttypes.h> + +#define DATACOL 15 + +/* + * Fill in entire monitor config table + * for sending to a remote monitor or printing on the local system + */ + +void +rtems_monitor_mpci_canonical( + rtems_monitor_mpci_t *canonical_mpci, + void *config_void +) +{ + rtems_configuration_table *c = &Configuration; + rtems_multiprocessing_table *m; + rtems_mpci_table *mt; + + m = c->User_multiprocessing_table; + if (m == 0) + return; + mt = m->User_mpci_table; + + canonical_mpci->node = m->node; + canonical_mpci->maximum_nodes = m->maximum_nodes; + canonical_mpci->maximum_global_objects = m->maximum_global_objects; + canonical_mpci->maximum_proxies = m->maximum_proxies; + + canonical_mpci->default_timeout = mt->default_timeout; + canonical_mpci->maximum_packet_size = mt->maximum_packet_size; + + rtems_monitor_symbol_canonical_by_value(&canonical_mpci->initialization, + (void *) mt->initialization); + + rtems_monitor_symbol_canonical_by_value(&canonical_mpci->get_packet, + (void *) mt->get_packet); + rtems_monitor_symbol_canonical_by_value(&canonical_mpci->return_packet, + (void *) mt->return_packet); + rtems_monitor_symbol_canonical_by_value(&canonical_mpci->send_packet, + (void *) mt->send_packet); + rtems_monitor_symbol_canonical_by_value(&canonical_mpci->receive_packet, + (void *) mt->receive_packet); +} + +/* + * This is easy, since there is only 1 (altho we could get them from + * other nodes...) + */ + +void * +rtems_monitor_mpci_next( + void *object_info, + rtems_monitor_mpci_t *canonical_mpci, + rtems_id *next_id +) +{ + rtems_configuration_table *c = &Configuration; + int n = rtems_object_id_get_index(*next_id); + + if (n >= 1) + goto failed; + + if ( ! c->User_multiprocessing_table) + goto failed; + + _Thread_Disable_dispatch(); + + *next_id += 1; + return (void *) c; + +failed: + *next_id = RTEMS_OBJECT_ID_FINAL; + return 0; +} + + +void +rtems_monitor_mpci_dump_header( + bool verbose +) +{ + fprintf(stdout,"\ + max max max default max\n\ + node nodes globals proxies timeout pktsize\n"); +/*23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 +0 1 2 3 4 5 6 7 */ + + rtems_monitor_separator(); +} + + +void +rtems_monitor_mpci_dump( + rtems_monitor_mpci_t *monitor_mpci, + bool verbose +) +{ + uint32_t length = 0; + + length += rtems_monitor_pad(2, length); + length += fprintf(stdout," %" PRId32 , monitor_mpci->node); + length += rtems_monitor_pad(11, length); + length += fprintf(stdout,"%" PRId32, monitor_mpci->maximum_nodes); + + length += rtems_monitor_pad(18, length); + length += rtems_monitor_dump_decimal(monitor_mpci->maximum_global_objects); + + length += rtems_monitor_pad(28, length); + length += rtems_monitor_dump_decimal(monitor_mpci->maximum_proxies); + + length += rtems_monitor_pad(37, length); + length += rtems_monitor_dump_decimal(monitor_mpci->default_timeout); + + length += rtems_monitor_pad(46, length); + length += rtems_monitor_dump_decimal((uint32_t) monitor_mpci->maximum_packet_size); + + fprintf(stdout,"\n"); + length = 0; + length += rtems_monitor_pad(DATACOL, length); + + length += fprintf(stdout,"init: "); + length += rtems_monitor_symbol_dump(&monitor_mpci->initialization, verbose); + + fprintf(stdout,"\n"); + length = 0; + length += rtems_monitor_pad(DATACOL, length); + + length += fprintf(stdout,"get: "); + length += rtems_monitor_symbol_dump(&monitor_mpci->get_packet, verbose); + length += fprintf(stdout,"; return: "); + length += rtems_monitor_symbol_dump(&monitor_mpci->return_packet, verbose); + + fprintf(stdout,"\n"); + length = 0; + length += rtems_monitor_pad(DATACOL, length); + + length += fprintf(stdout,"send: "); + length += rtems_monitor_symbol_dump(&monitor_mpci->send_packet, verbose); + length += fprintf(stdout,"; receive: "); + length += rtems_monitor_symbol_dump(&monitor_mpci->receive_packet, verbose); + + fprintf(stdout,"\n"); + length = 0; +} diff --git a/cpukit/libmisc/monitor/mon-network.c b/cpukit/libmisc/monitor/mon-network.c new file mode 100644 index 0000000000..52c0cd9852 --- /dev/null +++ b/cpukit/libmisc/monitor/mon-network.c @@ -0,0 +1,342 @@ +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> + +#include <rtems/rtems_bsdnet.h> +#include <sys/socket.h> +#include <net/if.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/sockio.h> +#include <net/route.h> + + +void mon_ifconfig(int argc, char *argv[], + uint32_t command_arg __attribute__((unused)), + bool verbose __attribute__((unused))) +{ + struct sockaddr_in ipaddr; + struct sockaddr_in dstaddr; + struct sockaddr_in netmask; + struct sockaddr_in broadcast; + char *iface; + int f_ip = 0; + int f_ptp = 0; + int f_netmask = 0; + int f_up = 0; + int f_down = 0; + int f_bcast = 0; + int cur_idx; + int rc; + int flags; + + memset(&ipaddr, 0, sizeof(ipaddr)); + memset(&dstaddr, 0, sizeof(dstaddr)); + memset(&netmask, 0, sizeof(netmask)); + memset(&broadcast, 0, sizeof(broadcast)); + + ipaddr.sin_len = sizeof(ipaddr); + ipaddr.sin_family = AF_INET; + + dstaddr.sin_len = sizeof(dstaddr); + dstaddr.sin_family = AF_INET; + + netmask.sin_len = sizeof(netmask); + netmask.sin_family = AF_INET; + + broadcast.sin_len = sizeof(broadcast); + broadcast.sin_family = AF_INET; + + cur_idx = 0; + if (argc <= 1) { + /* display all interfaces */ + iface = NULL; + cur_idx += 1; + } else { + iface = argv[1]; + if (isdigit((unsigned char)*argv[2])) { + if (inet_pton(AF_INET, argv[2], &ipaddr.sin_addr) < 0) { + printf("bad ip address: %s\n", argv[2]); + return; + } + f_ip = 1; + cur_idx += 3; + } else { + cur_idx += 2; + } + } + + if ((f_down !=0) && (f_ip != 0)) { + f_up = 1; + } + + while(argc > cur_idx) { + if (strcmp(argv[cur_idx], "up") == 0) { + f_up = 1; + if (f_down != 0) { + printf("Can't make interface up and down\n"); + } + } else if(strcmp(argv[cur_idx], "down") == 0) { + f_down = 1; + if (f_up != 0) { + printf("Can't make interface up and down\n"); + } + } else if(strcmp(argv[cur_idx], "netmask") == 0) { + if ((cur_idx + 1) >= argc) { + printf("No netmask address\n"); + return; + } + if (inet_pton(AF_INET, argv[cur_idx+1], &netmask.sin_addr) < 0) { + printf("bad netmask: %s\n", argv[cur_idx]); + return; + } + f_netmask = 1; + cur_idx += 1; + } else if(strcmp(argv[cur_idx], "broadcast") == 0) { + if ((cur_idx + 1) >= argc) { + printf("No broadcast address\n"); + return; + } + if (inet_pton(AF_INET, argv[cur_idx+1], &broadcast.sin_addr) < 0) { + printf("bad broadcast: %s\n", argv[cur_idx]); + return; + } + f_bcast = 1; + cur_idx += 1; + } else if(strcmp(argv[cur_idx], "pointopoint") == 0) { + if ((cur_idx + 1) >= argc) { + printf("No pointopoint address\n"); + return; + } + if (inet_pton(AF_INET, argv[cur_idx+1], &dstaddr.sin_addr) < 0) { + printf("bad pointopoint: %s\n", argv[cur_idx]); + return; + } + + f_ptp = 1; + cur_idx += 1; + } else { + printf("Bad parameter: %s\n", argv[cur_idx]); + return; + } + + cur_idx += 1; + } + + printf("ifconfig "); + if (iface != NULL) { + printf("%s ", iface); + if (f_ip != 0) { + char str[256]; + inet_ntop(AF_INET, &ipaddr.sin_addr, str, 256); + printf("%s ", str); + } + + if (f_netmask != 0) { + char str[256]; + inet_ntop(AF_INET, &netmask.sin_addr, str, 256); + printf("netmask %s ", str); + } + + if (f_bcast != 0) { + char str[256]; + inet_ntop(AF_INET, &broadcast.sin_addr, str, 256); + printf("broadcast %s ", str); + } + + if (f_ptp != 0) { + char str[256]; + inet_ntop(AF_INET, &dstaddr.sin_addr, str, 256); + printf("pointopoint %s ", str); + } + + if (f_up != 0) { + printf("up\n"); + } else if (f_down != 0) { + printf("down\n"); + } else { + printf("\n"); + } + } + + if ((iface == NULL) || ((f_ip == 0) && (f_down == 0) && (f_up == 0))) { + rtems_bsdnet_show_if_stats(); + return; + } + + flags = 0; + if (f_netmask) { + rc = rtems_bsdnet_ifconfig(iface, SIOCSIFNETMASK, &netmask); + if (rc < 0) { + printf("Could not set netmask: %s\n", strerror(errno)); + return; + } + } + + if (f_bcast) { + rc = rtems_bsdnet_ifconfig(iface, SIOCSIFBRDADDR, &broadcast); + if (rc < 0) { + printf("Could not set broadcast: %s\n", strerror(errno)); + return; + } + } + + if (f_ptp) { + rc = rtems_bsdnet_ifconfig(iface, SIOCSIFDSTADDR, &dstaddr); + if (rc < 0) { + printf("Could not set destination address: %s\n", strerror(errno)); + return; + } + flags |= IFF_POINTOPOINT; + } + + /* This must come _after_ setting the netmask, broadcast addresses */ + if (f_ip) { + rc = rtems_bsdnet_ifconfig(iface, SIOCSIFADDR, &ipaddr); + if (rc < 0) { + printf("Could not set IP address: %s\n", strerror(errno)); + return; + } + } + + if (f_up != 0) { + flags |= IFF_UP; + } + + if (f_down != 0) { + printf("Warning: taking interfaces down is not supported\n"); + } + + rc = rtems_bsdnet_ifconfig(iface, SIOCSIFFLAGS, &flags); + if (rc < 0) { + printf("Could not set interface flags: %s\n", strerror(errno)); + return; + } +} + + + +void mon_route(int argc, char *argv[], + uint32_t command_arg __attribute__((unused)), + bool verbose __attribute__((unused))) +{ + int cmd; + struct sockaddr_in dst; + struct sockaddr_in gw; + struct sockaddr_in netmask; + int f_host; + int f_gw = 0; + int cur_idx; + int flags; + int rc; + + memset(&dst, 0, sizeof(dst)); + memset(&gw, 0, sizeof(gw)); + memset(&netmask, 0, sizeof(netmask)); + + dst.sin_len = sizeof(dst); + dst.sin_family = AF_INET; + dst.sin_addr.s_addr = inet_addr("0.0.0.0"); + + gw.sin_len = sizeof(gw); + gw.sin_family = AF_INET; + gw.sin_addr.s_addr = inet_addr("0.0.0.0"); + + netmask.sin_len = sizeof(netmask); + netmask.sin_family = AF_INET; + netmask.sin_addr.s_addr = inet_addr("255.255.255.0"); + + if (argc < 2) { + rtems_bsdnet_show_inet_routes(); + return; + } + + if (strcmp(argv[1], "add") == 0) { + cmd = RTM_ADD; + } else if (strcmp(argv[1], "del") == 0) { + cmd = RTM_DELETE; + } else { + printf("invalid command: %s\n", argv[1]); + printf("\tit should be 'add' or 'del'\n"); + return; + } + + if (argc < 3) { + printf("not enough arguments\n"); + return; + } + + if (strcmp(argv[2], "-host") == 0) { + f_host = 1; + } else if (strcmp(argv[2], "-net") == 0) { + f_host = 0; + } else { + printf("Invalid type: %s\n", argv[1]); + printf("\tit should be '-host' or '-net'\n"); + return; + } + + if (argc < 4) { + printf("not enough arguments\n"); + return; + } + + inet_pton(AF_INET, argv[3], &dst.sin_addr); + + cur_idx = 4; + while(cur_idx < argc) { + if (strcmp(argv[cur_idx], "gw") == 0) { + if ((cur_idx +1) >= argc) { + printf("no gateway address\n"); + return; + } + f_gw = 1; + inet_pton(AF_INET, argv[cur_idx + 1], &gw.sin_addr); + cur_idx += 1; + } else if(strcmp(argv[cur_idx], "netmask") == 0) { + if ((cur_idx +1) >= argc) { + printf("no netmask address\n"); + return; + } + f_gw = 1; + inet_pton(AF_INET, argv[cur_idx + 1], &netmask.sin_addr); + cur_idx += 1; + } else { + printf("Unknown argument: %s\n", argv[cur_idx]); + return; + } + cur_idx += 1; + } + + flags = RTF_STATIC; + if (f_gw != 0) { + flags |= RTF_GATEWAY; + } + if (f_host != 0) { + flags |= RTF_HOST; + } + + rc = rtems_bsdnet_rtrequest(cmd, + (struct sockaddr*) &dst, + (struct sockaddr*) &gw, + (struct sockaddr*) &netmask, flags, NULL); + if (rc < 0) { + printf("Error adding route\n"); + } +} diff --git a/cpukit/libmisc/monitor/mon-object.c b/cpukit/libmisc/monitor/mon-object.c new file mode 100644 index 0000000000..96b2a85f8d --- /dev/null +++ b/cpukit/libmisc/monitor/mon-object.c @@ -0,0 +1,423 @@ +/* + * RTEMS Monitor "object" support. + * + * Used to traverse object lists and print them out. + * An object can be an RTEMS object (chain based stuff) or + * a "misc" object such as a device driver. + * + * Each object has its own file in this directory (eg: extension.c) + * That file provides routines to convert a "native" structure + * to its canonical form, print a canonical structure, etc. + * + * TODO: + * should allow for non-numeric id's??? + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ +#include <rtems.h> +#include <rtems/monitor.h> +#if defined(RTEMS_POSIX_API) + #include <rtems/posix/pthread.h> +#endif + +#include <stdio.h> +#include <stdlib.h> /* strtoul() */ +#include <string.h> /* memcpy() */ + +#define NUMELEMS(arr) (sizeof(arr) / sizeof(arr[0])) + +/* + * add: + * next + */ + +static const rtems_monitor_object_info_t rtems_monitor_object_info[] = +{ + { RTEMS_MONITOR_OBJECT_CONFIG, + (void *) 0, + sizeof(rtems_monitor_config_t), + (rtems_monitor_object_next_fn) rtems_monitor_config_next, + (rtems_monitor_object_canonical_fn) rtems_monitor_config_canonical, + (rtems_monitor_object_dump_header_fn) rtems_monitor_config_dump_header, + (rtems_monitor_object_dump_fn) rtems_monitor_config_dump, + }, + { RTEMS_MONITOR_OBJECT_MPCI, + (void *) 0, +#if defined(RTEMS_MULTIPROCESSING) + sizeof(rtems_monitor_mpci_t), + (rtems_monitor_object_next_fn) rtems_monitor_mpci_next, + (rtems_monitor_object_canonical_fn) rtems_monitor_mpci_canonical, + (rtems_monitor_object_dump_header_fn) rtems_monitor_mpci_dump_header, + (rtems_monitor_object_dump_fn) rtems_monitor_mpci_dump, +#else + 0, + (rtems_monitor_object_next_fn) 0, + (rtems_monitor_object_canonical_fn) 0, + (rtems_monitor_object_dump_header_fn) 0, + (rtems_monitor_object_dump_fn) 0, +#endif + }, + { RTEMS_MONITOR_OBJECT_INIT_TASK, + (void *) 0, + sizeof(rtems_monitor_init_task_t), + (rtems_monitor_object_next_fn) rtems_monitor_init_task_next, + (rtems_monitor_object_canonical_fn) rtems_monitor_init_task_canonical, + (rtems_monitor_object_dump_header_fn) rtems_monitor_init_task_dump_header, + (rtems_monitor_object_dump_fn) rtems_monitor_init_task_dump, + }, + { RTEMS_MONITOR_OBJECT_TASK, + (void *) &_RTEMS_tasks_Information, + sizeof(rtems_monitor_task_t), + (rtems_monitor_object_next_fn) rtems_monitor_manager_next, + (rtems_monitor_object_canonical_fn) rtems_monitor_task_canonical, + (rtems_monitor_object_dump_header_fn) rtems_monitor_task_dump_header, + (rtems_monitor_object_dump_fn) rtems_monitor_task_dump, + }, + { RTEMS_MONITOR_OBJECT_QUEUE, + (void *) &_Message_queue_Information, + sizeof(rtems_monitor_queue_t), + (rtems_monitor_object_next_fn) rtems_monitor_manager_next, + (rtems_monitor_object_canonical_fn) rtems_monitor_queue_canonical, + (rtems_monitor_object_dump_header_fn) rtems_monitor_queue_dump_header, + (rtems_monitor_object_dump_fn) rtems_monitor_queue_dump, + }, + { RTEMS_MONITOR_OBJECT_SEMAPHORE, + (void *) &_Semaphore_Information, + sizeof(rtems_monitor_sema_t), + (rtems_monitor_object_next_fn) rtems_monitor_manager_next, + (rtems_monitor_object_canonical_fn) rtems_monitor_sema_canonical, + (rtems_monitor_object_dump_header_fn) rtems_monitor_sema_dump_header, + (rtems_monitor_object_dump_fn) rtems_monitor_sema_dump, + }, + { RTEMS_MONITOR_OBJECT_REGION, + (void *) &_Region_Information, + sizeof(rtems_monitor_region_t), + (rtems_monitor_object_next_fn) rtems_monitor_manager_next, + (rtems_monitor_object_canonical_fn) rtems_monitor_region_canonical, + (rtems_monitor_object_dump_header_fn) rtems_monitor_region_dump_header, + (rtems_monitor_object_dump_fn) rtems_monitor_region_dump, + }, + { RTEMS_MONITOR_OBJECT_PARTITION, + (void *) &_Partition_Information, + sizeof(rtems_monitor_part_t), + (rtems_monitor_object_next_fn) rtems_monitor_manager_next, + (rtems_monitor_object_canonical_fn) rtems_monitor_part_canonical, + (rtems_monitor_object_dump_header_fn) rtems_monitor_part_dump_header, + (rtems_monitor_object_dump_fn) rtems_monitor_part_dump, + }, + { RTEMS_MONITOR_OBJECT_EXTENSION, + (void *) &_Extension_Information, + sizeof(rtems_monitor_extension_t), + (rtems_monitor_object_next_fn) rtems_monitor_manager_next, + (rtems_monitor_object_canonical_fn) rtems_monitor_extension_canonical, + (rtems_monitor_object_dump_header_fn) rtems_monitor_extension_dump_header, + (rtems_monitor_object_dump_fn) rtems_monitor_extension_dump, + }, + { RTEMS_MONITOR_OBJECT_DRIVER, + (void *) 0, + sizeof(rtems_monitor_driver_t), + (rtems_monitor_object_next_fn) rtems_monitor_driver_next, + (rtems_monitor_object_canonical_fn) rtems_monitor_driver_canonical, + (rtems_monitor_object_dump_header_fn) rtems_monitor_driver_dump_header, + (rtems_monitor_object_dump_fn) rtems_monitor_driver_dump, + }, +#if defined(RTEMS_POSIX_API) + { RTEMS_MONITOR_OBJECT_PTHREAD, + (void *) &_POSIX_Threads_Information, + sizeof(rtems_monitor_task_t), + (rtems_monitor_object_next_fn) rtems_monitor_manager_next, + (rtems_monitor_object_canonical_fn) rtems_monitor_task_canonical, + (rtems_monitor_object_dump_header_fn) rtems_monitor_task_dump_header, + (rtems_monitor_object_dump_fn) rtems_monitor_task_dump, + }, +#endif +}; + +/* + * Allow id's to be specified without the node number or + * type for convenience. + */ + +rtems_id +rtems_monitor_id_fixup( + rtems_id id, + uint32_t default_node, + rtems_monitor_object_type_t type +) +{ + uint32_t node; + + node = rtems_object_id_get_node(id); + if (node == 0) + { + if (rtems_object_id_get_class(id) != OBJECTS_CLASSIC_NO_CLASS) + type = rtems_object_id_get_class(id); + + id = rtems_build_id( + OBJECTS_CLASSIC_API, + type, + default_node, + rtems_object_id_get_index(id) + ); + } + return id; +} + + +const rtems_monitor_object_info_t * +rtems_monitor_object_lookup( + rtems_monitor_object_type_t type +) +{ + const rtems_monitor_object_info_t *p; + for (p = &rtems_monitor_object_info[0]; + p < &rtems_monitor_object_info[NUMELEMS(rtems_monitor_object_info)]; + p++) + { + if (p->type == type) + return p; + } + return 0; +} + +rtems_id +rtems_monitor_object_canonical_next_remote( + rtems_monitor_object_type_t type, + rtems_id id, + void *canonical +) +{ + rtems_id next_id; + rtems_status_code status; + rtems_monitor_server_request_t request; + rtems_monitor_server_response_t response; + + /* + * Send request + */ + + request.command = RTEMS_MONITOR_SERVER_CANONICAL; + request.argument0 = (uint32_t) type; + request.argument1 = (uint32_t) id; + + status = rtems_monitor_server_request( + rtems_object_id_get_node(id), &request, &response); + if (status != RTEMS_SUCCESSFUL) + goto failed; + + /* + * process response + */ + + next_id = (rtems_id) response.result0; + if (next_id != RTEMS_OBJECT_ID_FINAL) + (void) memcpy(canonical, &response.payload, response.result1); + + return next_id; + +failed: + return RTEMS_OBJECT_ID_FINAL; + +} + + +rtems_id +rtems_monitor_object_canonical_next( + const rtems_monitor_object_info_t *info, + rtems_id id, + void *canonical +) +{ + rtems_id next_id; + void *raw_item; + +#if defined(RTEMS_MULTIPROCESSING) + if ( ! _Objects_Is_local_id(id) ) { + next_id = rtems_monitor_object_canonical_next_remote( + info->type, + id, + canonical + ); + } else +#endif + { + next_id = id; + + raw_item = (void *) info->next( + info->object_information, + canonical, + &next_id + ); + + if (raw_item) { + info->canonical(canonical, raw_item); + _Thread_Enable_dispatch(); + } + } + return next_id; +} + + +/* + * this is routine server invokes locally to get the type + */ + +rtems_id +rtems_monitor_object_canonical_get( + rtems_monitor_object_type_t type, + rtems_id id, + void *canonical, + size_t *size_p +) +{ + const rtems_monitor_object_info_t *info; + rtems_id next_id; + + *size_p = 0; + + info = rtems_monitor_object_lookup(type); + + if (info == 0) + return RTEMS_OBJECT_ID_FINAL; + + next_id = rtems_monitor_object_canonical_next(info, id, canonical); + *size_p = info->size; + + return next_id; +} + + +void +rtems_monitor_object_dump_1( + const rtems_monitor_object_info_t *info, + rtems_id id, + bool verbose +) +{ + rtems_id next_id; + rtems_monitor_union_t canonical; + + if ((next_id = rtems_monitor_object_canonical_next( + info, + id, + &canonical)) != RTEMS_OBJECT_ID_FINAL) + { + /* + * If the one we actually got is the one we wanted, then + * print it out. + * For ones that have an id field, this works fine, + * for all others, always dump it out. + * + * HACK: the way we determine whether there is an id is a hack. + * + * by the way: the reason we try to not have an id, is that some + * of the canonical structures are almost too big for shared + * memory driver (eg: mpci) + */ + + if ((info->next != rtems_monitor_manager_next) || + (id == canonical.generic.id)) + info->dump(&canonical, verbose); + } +} + +void +rtems_monitor_object_dump_all( + const rtems_monitor_object_info_t *info, + bool verbose +) +{ + rtems_id next_id; + rtems_monitor_union_t canonical; + + next_id = RTEMS_OBJECT_ID_INITIAL(OBJECTS_CLASSIC_API, info->type, rtems_monitor_default_node); + + while ((next_id = rtems_monitor_object_canonical_next( + info, + next_id, + &canonical)) != RTEMS_OBJECT_ID_FINAL) + { + info->dump(&canonical, verbose); + } +} + +void +rtems_monitor_object_cmd( + int argc, + char **argv, + const rtems_monitor_command_arg_t *command_arg, + bool verbose +) +{ + int arg; + const rtems_monitor_object_info_t *info = 0; + rtems_monitor_object_type_t type; + + /* what is the default type? */ + type = command_arg->monitor_object; + + if (argc == 1) + { + if (type == RTEMS_MONITOR_OBJECT_INVALID) + { + fprintf(stdout,"A type must be specified to \"dump all\"\n"); + goto done; + } + + info = rtems_monitor_object_lookup(type); + if (info == 0) + goto not_found; + + if (info->dump_header) + info->dump_header(verbose); + rtems_monitor_object_dump_all(info, verbose); + } + else + { + uint32_t default_node = rtems_monitor_default_node; + rtems_monitor_object_type_t last_type = RTEMS_MONITOR_OBJECT_INVALID; + rtems_id id; + + for (arg=1; argv[arg]; arg++) + { + id = (rtems_id) strtoul(argv[arg], 0, 16); + id = rtems_monitor_id_fixup(id, default_node, type); + type = (rtems_monitor_object_type_t) rtems_object_id_get_class(id); + + /* + * Allow the item type to change in the middle + * of the command. If the type changes, then + * just dump out a new header and keep on going. + */ + if (type != last_type) + { + info = rtems_monitor_object_lookup(type); + if (info == 0) + goto not_found; + + if (info->dump_header) + info->dump_header(verbose); + } + + if (info == 0) + { +not_found: fprintf(stdout,"Invalid or unsupported type %d\n", type); + goto done; + } + + rtems_monitor_object_dump_1(info, id, verbose); + + default_node = rtems_object_id_get_node(id); + + last_type = type; + } + } +done: + return; +} diff --git a/cpukit/libmisc/monitor/mon-part.c b/cpukit/libmisc/monitor/mon-part.c new file mode 100644 index 0000000000..72aff6921f --- /dev/null +++ b/cpukit/libmisc/monitor/mon-part.c @@ -0,0 +1,72 @@ +/* + * RTEMS Monitor partition support + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include "monitor.h" +#include <rtems/rtems/attr.inl> +#include <stdio.h> +#include <string.h> /* memcpy() */ + +void +rtems_monitor_part_canonical( + rtems_monitor_part_t *canonical_part, + void *part_void +) +{ + Partition_Control *rtems_part = (Partition_Control *) part_void; + + canonical_part->attribute = rtems_part->attribute_set; + canonical_part->start_addr = rtems_part->starting_address; + canonical_part->length = rtems_part->length; + canonical_part->buf_size = rtems_part->buffer_size; + canonical_part->used_blocks = rtems_part->number_of_used_blocks; +} + + +void +rtems_monitor_part_dump_header( + bool verbose __attribute__((unused)) +) +{ + printf("\ + ID NAME ATTR STARTADDR LENGTH BUF_SIZE USED_BLOCKS\n"); +/*23456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 + 1 2 3 4 5 6 7 */ + + rtems_monitor_separator(); +} + +/* + */ + +void +rtems_monitor_part_dump( + rtems_monitor_part_t *monitor_part, + bool verbose __attribute__((unused)) +) +{ + int length = 0; + + length += rtems_monitor_dump_id(monitor_part->id); + length += rtems_monitor_pad(11, length); + length += rtems_monitor_dump_name(monitor_part->id); + length += rtems_monitor_pad(18, length); + length += rtems_monitor_dump_attributes(monitor_part->attribute); + length += rtems_monitor_pad(30, length); + length += rtems_monitor_dump_addr(monitor_part->start_addr); + length += rtems_monitor_pad(40, length); + length += rtems_monitor_dump_hex(monitor_part->length); + length += rtems_monitor_pad(50, length); + length += rtems_monitor_dump_hex(monitor_part->buf_size); + length += rtems_monitor_pad(60, length); + length += rtems_monitor_dump_hex(monitor_part->used_blocks); + printf("\n"); +} + diff --git a/cpukit/libmisc/monitor/mon-prmisc.c b/cpukit/libmisc/monitor/mon-prmisc.c new file mode 100644 index 0000000000..32ee6711b4 --- /dev/null +++ b/cpukit/libmisc/monitor/mon-prmisc.c @@ -0,0 +1,259 @@ +/* + * Print misc stuff for the monitor dump routines + * Each routine returns the number of characters it output. + * + * TODO: + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/monitor.h> + +#include <rtems/assoc.h> + +#include <stdio.h> +#include <ctype.h> +#include <inttypes.h> + +void +rtems_monitor_separator(void) +{ + fprintf(stdout,"------------------------------------------------------------------------------\n"); +} + +uint32_t +rtems_monitor_pad( + uint32_t destination_column, + uint32_t current_column +) +{ + int pad_length; + + if (destination_column <= current_column) + pad_length = 1; + else + pad_length = destination_column - current_column; + + return fprintf(stdout,"%*s", pad_length, ""); +} + +int +rtems_monitor_dump_decimal(uint32_t num) +{ + return fprintf(stdout,"%4" PRId32, num); +} + +int +rtems_monitor_dump_addr(void *addr) +{ + return fprintf(stdout,"0x%p", addr); +} + +int +rtems_monitor_dump_hex(uint32_t num) +{ + return fprintf(stdout,"0x%" PRIx32, num); +} + +int +rtems_monitor_dump_assoc_bitfield( + const rtems_assoc_t *ap, + const char *separator, + uint32_t value + ) +{ + uint32_t b; + uint32_t length = 0; + const char *name; + + for (b = 1; b; b <<= 1) + if (b & value) + { + if (length) + length += fprintf(stdout,"%s", separator); + + name = rtems_assoc_name_by_local(ap, b); + + if (name) + length += fprintf(stdout,"%s", name); + else + length += fprintf(stdout,"0x%" PRIx32, b); + } + + return length; +} + +int +rtems_monitor_dump_id(rtems_id id) +{ +#if defined(RTEMS_USE_16_BIT_OBJECT) + return fprintf(stdout,"%08" PRIx16, id); +#else + return fprintf(stdout,"%08" PRIx32, id); +#endif +} + +int +rtems_monitor_dump_name(rtems_id id) +{ + char name_buffer[18] = "????"; + + rtems_object_get_name( id, sizeof(name_buffer), name_buffer ); + + return fprintf( stdout, name_buffer ); +} + +int +rtems_monitor_dump_priority(rtems_task_priority priority) +{ + return fprintf(stdout,"%3" PRId32, priority); +} + + +static const rtems_assoc_t rtems_monitor_state_assoc[] = { + { "DORM", STATES_DORMANT, 0 }, + { "SUSP", STATES_SUSPENDED, 0 }, + { "TRANS", STATES_TRANSIENT, 0 }, + { "DELAY", STATES_DELAYING, 0 }, + { "Wtime", STATES_WAITING_FOR_TIME, 0 }, + { "Wbuf", STATES_WAITING_FOR_BUFFER, 0 }, + { "Wseg", STATES_WAITING_FOR_SEGMENT, 0 }, + { "Wmsg" , STATES_WAITING_FOR_MESSAGE, 0 }, + { "Wevnt", STATES_WAITING_FOR_EVENT, 0 }, + { "Wsem", STATES_WAITING_FOR_SEMAPHORE, 0 }, + { "Wmutex", STATES_WAITING_FOR_MUTEX, 0 }, + { "Wcvar", STATES_WAITING_FOR_CONDITION_VARIABLE, 0 }, + { "Wjatx", STATES_WAITING_FOR_JOIN_AT_EXIT, 0 }, + { "Wrpc", STATES_WAITING_FOR_RPC_REPLY, 0 }, + { "WRATE", STATES_WAITING_FOR_PERIOD, 0 }, + { "Wsig", STATES_WAITING_FOR_SIGNAL, 0 }, + { "Wbar", STATES_WAITING_FOR_BARRIER, 0 }, + { "Wrwlk", STATES_WAITING_FOR_RWLOCK, 0 }, + { "Wisig", STATES_INTERRUPTIBLE_BY_SIGNAL, 0 }, + { 0, 0, 0 }, +}; + +int +rtems_monitor_dump_state(States_Control state) +{ + int length = 0; + + if (state == STATES_READY) /* assoc doesn't deal with this as it is 0 */ + length += fprintf(stdout,"READY"); + + length += rtems_monitor_dump_assoc_bitfield(rtems_monitor_state_assoc, + ":", + state); + return length; +} + +static const rtems_assoc_t rtems_monitor_attribute_assoc[] = { + { "GL", RTEMS_GLOBAL, 0 }, + { "PR", RTEMS_PRIORITY, 0 }, + { "FL", RTEMS_FLOATING_POINT, 0 }, + { "BI", RTEMS_BINARY_SEMAPHORE, 0 }, + { "SB", RTEMS_SIMPLE_BINARY_SEMAPHORE, 0 }, + { "IN", RTEMS_INHERIT_PRIORITY, 0 }, + { "CE", RTEMS_PRIORITY_CEILING, 0 }, + { "AR", RTEMS_BARRIER_AUTOMATIC_RELEASE, 0 }, + { "ST", RTEMS_SYSTEM_TASK, 0 }, + { 0, 0, 0 }, +}; + +int +rtems_monitor_dump_attributes(rtems_attribute attributes) +{ + int length = 0; + + if (attributes == RTEMS_DEFAULT_ATTRIBUTES) /* value is 0 */ + length += fprintf(stdout,"DEFAULT"); + + length += rtems_monitor_dump_assoc_bitfield(rtems_monitor_attribute_assoc, + ":", + attributes); + return length; +} + +static const rtems_assoc_t rtems_monitor_modes_assoc[] = { + { "nP", RTEMS_NO_PREEMPT, 0 }, + { "T", RTEMS_TIMESLICE, 0 }, + { "nA", RTEMS_NO_ASR, 0 }, + { 0, 0, 0 }, +}; + +int +rtems_monitor_dump_modes(rtems_mode modes) +{ + uint32_t length = 0; + + if (modes == RTEMS_DEFAULT_MODES) /* value is 0 */ + length += fprintf(stdout,"P:T:nA"); + + length += rtems_monitor_dump_assoc_bitfield(rtems_monitor_modes_assoc, + ":", + modes); + return length; +} + +static const rtems_assoc_t rtems_monitor_events_assoc[] = { + { "0", RTEMS_EVENT_0, 0 }, + { "1", RTEMS_EVENT_1, 0 }, + { "2", RTEMS_EVENT_2, 0 }, + { "3", RTEMS_EVENT_3, 0 }, + { "4", RTEMS_EVENT_4, 0 }, + { "5", RTEMS_EVENT_5, 0 }, + { "6", RTEMS_EVENT_6, 0 }, + { "7", RTEMS_EVENT_7, 0 }, + { "8", RTEMS_EVENT_8, 0 }, + { "9", RTEMS_EVENT_9, 0 }, + { "10", RTEMS_EVENT_10, 0 }, + { "11", RTEMS_EVENT_11, 0 }, + { "12", RTEMS_EVENT_12, 0 }, + { "13", RTEMS_EVENT_13, 0 }, + { "14", RTEMS_EVENT_14, 0 }, + { "15", RTEMS_EVENT_15, 0 }, + { "16", RTEMS_EVENT_16, 0 }, + { "17", RTEMS_EVENT_17, 0 }, + { "18", RTEMS_EVENT_18, 0 }, + { "19", RTEMS_EVENT_19, 0 }, + { "20", RTEMS_EVENT_20, 0 }, + { "21", RTEMS_EVENT_21, 0 }, + { "22", RTEMS_EVENT_22, 0 }, + { "23", RTEMS_EVENT_23, 0 }, + { "24", RTEMS_EVENT_24, 0 }, + { "25", RTEMS_EVENT_25, 0 }, + { "26", RTEMS_EVENT_26, 0 }, + { "27", RTEMS_EVENT_27, 0 }, + { "28", RTEMS_EVENT_28, 0 }, + { "29", RTEMS_EVENT_29, 0 }, + { "30", RTEMS_EVENT_30, 0 }, + { "31", RTEMS_EVENT_31, 0 }, + { 0, 0, 0 }, +}; + +int +rtems_monitor_dump_events(rtems_event_set events) +{ + if (events == EVENT_SETS_NONE_PENDING) /* value is 0 */ + return fprintf(stdout," NONE "); + + return fprintf(stdout,"%08" PRIx32, events); +} + +int +rtems_monitor_dump_notepad(uint32_t *notepad) +{ + int length = 0; + int i; + + for (i=0; i < RTEMS_NUMBER_NOTEPADS; i++) + if (notepad[i]) + length += fprintf(stdout,"%d: 0x%" PRIx32, i, notepad[i]); + + return length; +} diff --git a/cpukit/libmisc/monitor/mon-queue.c b/cpukit/libmisc/monitor/mon-queue.c new file mode 100644 index 0000000000..4237b01780 --- /dev/null +++ b/cpukit/libmisc/monitor/mon-queue.c @@ -0,0 +1,68 @@ +/* + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/monitor.h> + +#include <stdio.h> + +void +rtems_monitor_queue_canonical( + rtems_monitor_queue_t *canonical_queue, + void *queue_void +) +{ + Message_queue_Control *rtems_queue = (Message_queue_Control *) queue_void; + + canonical_queue->attributes = rtems_queue->attribute_set; + canonical_queue->maximum_message_size = rtems_queue->message_queue.maximum_message_size; + canonical_queue->maximum_pending_messages = rtems_queue->message_queue.maximum_pending_messages; + canonical_queue->number_of_pending_messages = rtems_queue->message_queue.number_of_pending_messages; +} + +void +rtems_monitor_queue_dump_header( + bool verbose __attribute__((unused)) +) +{ + fprintf(stdout,"\ + ID NAME ATTRIBUTES PEND MAXPEND MAXSIZE\n"); +/*23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 +0 1 2 3 4 5 6 7 */ + rtems_monitor_separator(); +} + + +/* + * Dump out the "next" queue indicated by 'id'. + * Returns next one to check. + * Returns RTEMS_OBJECT_ID_FINAL when all done + */ + +void +rtems_monitor_queue_dump( + rtems_monitor_queue_t *monitor_queue, + bool verbose __attribute__((unused)) +) +{ + uint32_t length = 0; + + length += rtems_monitor_dump_id(monitor_queue->id); + length += rtems_monitor_pad(11, length); + length += rtems_monitor_dump_name(monitor_queue->id); + length += rtems_monitor_pad(19, length); + length += rtems_monitor_dump_attributes(monitor_queue->attributes); + length += rtems_monitor_pad(31, length); + length += rtems_monitor_dump_decimal(monitor_queue->number_of_pending_messages); + length += rtems_monitor_pad(39, length); + length += rtems_monitor_dump_decimal(monitor_queue->maximum_pending_messages); + length += rtems_monitor_pad(48, length); + length += rtems_monitor_dump_decimal(monitor_queue->maximum_message_size); + + fprintf(stdout,"\n"); +} diff --git a/cpukit/libmisc/monitor/mon-region.c b/cpukit/libmisc/monitor/mon-region.c new file mode 100644 index 0000000000..271cbf82f4 --- /dev/null +++ b/cpukit/libmisc/monitor/mon-region.c @@ -0,0 +1,73 @@ +/* + * RTEMS Monitor region support + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include "monitor.h" +#include <rtems/rtems/attr.inl> +#include <stdio.h> +#include <string.h> /* memcpy() */ + +void +rtems_monitor_region_canonical( + rtems_monitor_region_t *canonical_region, + void *region_void +) +{ + Region_Control *rtems_region = (Region_Control *) region_void; + + canonical_region->attribute = rtems_region->attribute_set; + canonical_region->start_addr = rtems_region->starting_address; + canonical_region->length = rtems_region->length; + canonical_region->page_size = rtems_region->page_size; + canonical_region->max_seg_size = rtems_region->maximum_segment_size; + canonical_region->used_blocks = rtems_region->number_of_used_blocks; +} + + +void +rtems_monitor_region_dump_header( + bool verbose __attribute__((unused)) +) +{ + printf("\ + ID NAME ATTR STARTADDR LENGTH PAGE_SIZE USED_BLOCKS\n"); +/*23456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 + 1 2 3 4 5 6 7 */ + + rtems_monitor_separator(); +} + +/* + */ + +void +rtems_monitor_region_dump( + rtems_monitor_region_t *monitor_region, + bool verbose __attribute__((unused)) +) +{ + int length = 0; + + length += rtems_monitor_dump_id(monitor_region->id); + length += rtems_monitor_pad(11, length); + length += rtems_monitor_dump_name(monitor_region->id); + length += rtems_monitor_pad(18, length); + length += rtems_monitor_dump_attributes(monitor_region->attribute); + length += rtems_monitor_pad(30, length); + length += rtems_monitor_dump_addr(monitor_region->start_addr); + length += rtems_monitor_pad(40, length); + length += rtems_monitor_dump_hex(monitor_region->length); + length += rtems_monitor_pad(50, length); + length += rtems_monitor_dump_hex(monitor_region->page_size); + length += rtems_monitor_pad(60, length); + length += rtems_monitor_dump_hex(monitor_region->used_blocks); + printf("\n"); +} + diff --git a/cpukit/libmisc/monitor/mon-sema.c b/cpukit/libmisc/monitor/mon-sema.c new file mode 100644 index 0000000000..276601c04c --- /dev/null +++ b/cpukit/libmisc/monitor/mon-sema.c @@ -0,0 +1,84 @@ +/* + * RTEMS Monitor semaphore support + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include "monitor.h" +#include <rtems/rtems/attr.inl> +#include <stdio.h> +#include <string.h> /* memcpy() */ + +void +rtems_monitor_sema_canonical( + rtems_monitor_sema_t *canonical_sema, + void *sema_void +) +{ + Semaphore_Control *rtems_sema = (Semaphore_Control *) sema_void; + + canonical_sema->attribute = rtems_sema->attribute_set; + canonical_sema->priority_ceiling = + rtems_sema->Core_control.mutex.Attributes.priority_ceiling; + + canonical_sema->holder_id = + rtems_sema->Core_control.mutex.holder_id; + + if (_Attributes_Is_counting_semaphore(canonical_sema->attribute)) { + /* we have a counting semaphore */ + canonical_sema->cur_count = + rtems_sema->Core_control.semaphore.count; + + canonical_sema->max_count = + rtems_sema->Core_control.semaphore.Attributes.maximum_count; + } + else { + /* we have a binary semaphore (mutex) */ + canonical_sema->cur_count = rtems_sema->Core_control.mutex.lock; + canonical_sema->max_count = 1; /* mutex is either 0 or 1 */ + } +} + + +void +rtems_monitor_sema_dump_header( + bool verbose __attribute__((unused)) +) +{ + printf("\ + ID NAME ATTR PRICEIL CURR_CNT HOLDID \n"); +/*23456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 + 1 2 3 4 5 6 7 */ + + rtems_monitor_separator(); +} + +/* + */ + +void +rtems_monitor_sema_dump( + rtems_monitor_sema_t *monitor_sema, + bool verbose __attribute__((unused)) +) +{ + int length = 0; + + length += rtems_monitor_dump_id(monitor_sema->id); + length += rtems_monitor_pad(11, length); + length += rtems_monitor_dump_name(monitor_sema->id); + length += rtems_monitor_pad(18, length); + length += rtems_monitor_dump_attributes(monitor_sema->attribute); + length += rtems_monitor_pad(30, length); + length += rtems_monitor_dump_priority(monitor_sema->priority_ceiling); + length += rtems_monitor_pad(38, length); + length += rtems_monitor_dump_decimal(monitor_sema->cur_count); + length += rtems_monitor_pad(47, length); + length += rtems_monitor_dump_id(monitor_sema->holder_id); + printf("\n"); +} diff --git a/cpukit/libmisc/monitor/mon-server.c b/cpukit/libmisc/monitor/mon-server.c new file mode 100644 index 0000000000..03bc1932b2 --- /dev/null +++ b/cpukit/libmisc/monitor/mon-server.c @@ -0,0 +1,309 @@ +/* + * RTEMS monitor server (handles requests for info from RTEMS monitors + * running on other nodes) + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include <rtems/monitor.h> + +/* + * Various id's for the server + */ + +rtems_id rtems_monitor_server_task_id; +rtems_id rtems_monitor_server_request_queue_id; /* our server */ +rtems_id *rtems_monitor_server_request_queue_ids; /* all servers */ +rtems_id rtems_monitor_server_response_queue_id; /* our server */ + + +/* + * Send a request to a server task + */ + +rtems_status_code +rtems_monitor_server_request( + uint32_t server_node, + rtems_monitor_server_request_t *request, + rtems_monitor_server_response_t *response +) +{ + rtems_id server_id; + rtems_status_code status; + size_t size; + + /* + * What is id of monitor on target node? + * Look it up if we don't know it yet. + */ + + server_id = rtems_monitor_server_request_queue_ids[server_node]; + if (server_id == 0) + { + status = rtems_message_queue_ident(RTEMS_MONITOR_QUEUE_NAME, + server_node, + &server_id); + if (status != RTEMS_SUCCESSFUL) + { + rtems_error(status, "ident of remote server failed"); + goto done; + } + + rtems_monitor_server_request_queue_ids[server_node] = server_id; + } + + request->return_id = rtems_monitor_server_response_queue_id; + + status = rtems_message_queue_send(server_id, request, sizeof(*request)); + if (status != RTEMS_SUCCESSFUL) + { + rtems_error(status, "monitor server request send failed"); + goto done; + } + + /* + * Await response, if requested + */ + + if (response) + { + status = rtems_message_queue_receive(rtems_monitor_server_response_queue_id, + response, + &size, + RTEMS_WAIT, + 100); + if (status != RTEMS_SUCCESSFUL) + { + rtems_error(status, "server did not respond"); + + /* maybe server task was restarted; look it up again next time */ + rtems_monitor_server_request_queue_ids[server_node] = 0; + + goto done; + } + + if (response->command != RTEMS_MONITOR_SERVER_RESPONSE) + { + status = RTEMS_INCORRECT_STATE; + goto done; + } + } + +done: + return status; +} + + + +/* + * monitor server task + */ + +void +rtems_monitor_server_task( + rtems_task_argument monitor_flags __attribute__((unused)) +) +{ + rtems_monitor_server_request_t request; + rtems_monitor_server_response_t response; + rtems_status_code status; + size_t size; + + for (;;) + { + status = rtems_message_queue_receive( + rtems_monitor_server_request_queue_id, + &request, + &size, + RTEMS_WAIT, + (rtems_interval) 0); + + if (status != RTEMS_SUCCESSFUL) + { + rtems_error(status, "monitor server msg queue receive error"); + goto failed; + } + + if (size != sizeof(request)) + { + rtems_error(0, "monitor server bad size on receive"); + goto failed; + } + + switch (request.command) + { + case RTEMS_MONITOR_SERVER_CANONICAL: + { + rtems_monitor_object_type_t object_type; + rtems_id id; + rtems_id next_id; + + object_type = (rtems_monitor_object_type_t) request.argument0; + id = (rtems_id) request.argument1; + next_id = rtems_monitor_object_canonical_get(object_type, + id, + &response.payload, + &size); + + response.command = RTEMS_MONITOR_SERVER_RESPONSE; + response.result0 = next_id; + response.result1 = size; + +#define SERVER_OVERHEAD (RTEMS_offsetof(rtems_monitor_server_response_t, \ + payload)) + + status = rtems_message_queue_send(request.return_id, + &response, + size + SERVER_OVERHEAD); + if (status != RTEMS_SUCCESSFUL) + { + rtems_error(status, "response send failed"); + goto failed; + } + break; + } + + default: + { + rtems_error(0, "invalid command to monitor server: %d", request.command); + goto failed; + } + } + } + +failed: + rtems_task_delete(RTEMS_SELF); +} + + +/* + * Kill off any old server + * Not sure if this is useful, but it doesn't help + */ + +void +rtems_monitor_server_kill(void) +{ + if (rtems_monitor_server_task_id) + rtems_task_delete(rtems_monitor_server_task_id); + rtems_monitor_server_task_id = 0; + + if (rtems_monitor_server_request_queue_id) + rtems_message_queue_delete(rtems_monitor_server_request_queue_id); + rtems_monitor_server_request_queue_ids = 0; + + if (rtems_monitor_server_response_queue_id) + rtems_message_queue_delete(rtems_monitor_server_response_queue_id); + rtems_monitor_server_response_queue_id = 0; + + if (rtems_monitor_server_request_queue_ids) + free(rtems_monitor_server_request_queue_ids); + rtems_monitor_server_request_queue_ids = 0; +} + + +void +rtems_monitor_server_init( + uint32_t monitor_flags __attribute__((unused)) +) +{ + #if defined(RTEMS_MULTIPROCESSING) + rtems_status_code status; + + if (_System_state_Is_multiprocessing && + (_Configuration_MP_table->maximum_nodes > 1)) + { + uint32_t maximum_nodes = _Configuration_MP_table->maximum_nodes; + + /* + * create the msg que our server will listen + * Since we only get msgs from other RTEMS monitors, we just + * need reserve space for 1 msg from each node. + */ + + status = rtems_message_queue_create( + RTEMS_MONITOR_QUEUE_NAME, + maximum_nodes, + sizeof(rtems_monitor_server_request_t), + RTEMS_GLOBAL, + &rtems_monitor_server_request_queue_id); + + if (status != RTEMS_SUCCESSFUL) + { + rtems_error(status, "could not create monitor server message queue"); + goto done; + } + + /* + * create the msg que our responses will come on + * Since monitor just does one thing at a time, we only need 1 item + * message queue. + */ + + status = rtems_message_queue_create( + RTEMS_MONITOR_RESPONSE_QUEUE_NAME, + 1, /* depth */ + sizeof(rtems_monitor_server_response_t), + RTEMS_GLOBAL, + &rtems_monitor_server_response_queue_id); + + if (status != RTEMS_SUCCESSFUL) + { + rtems_error(status, "could not create monitor response message queue"); + goto done; + } + + /* need an id for queue of each other server we might talk to */ + /* indexed by node, so add 1 to maximum_nodes */ + rtems_monitor_server_request_queue_ids = + (rtems_id *) malloc((maximum_nodes + 1) * sizeof(rtems_id)); + (void) memset(rtems_monitor_server_request_queue_ids, + 0, + (maximum_nodes + 1) * sizeof(rtems_id)); + + rtems_monitor_server_request_queue_ids[rtems_monitor_node] = + rtems_monitor_server_request_queue_id; + + /* + * create the server task + */ + status = rtems_task_create(RTEMS_MONITOR_SERVER_NAME, + 1, + 0 /* default stack */, + RTEMS_INTERRUPT_LEVEL(0), + RTEMS_DEFAULT_ATTRIBUTES, + &rtems_monitor_server_task_id); + if (status != RTEMS_SUCCESSFUL) + { + rtems_error(status, "could not create monitor server task"); + goto done; + } + + /* + * Start the server task + */ + status = rtems_task_start(rtems_monitor_server_task_id, + rtems_monitor_server_task, + monitor_flags); + if (status != RTEMS_SUCCESSFUL) + { + rtems_error(status, "could not start monitor server"); + goto done; + } + } + +done: + #endif + return; +} diff --git a/cpukit/libmisc/monitor/mon-symbols.c b/cpukit/libmisc/monitor/mon-symbols.c new file mode 100644 index 0000000000..38a5716c6f --- /dev/null +++ b/cpukit/libmisc/monitor/mon-symbols.c @@ -0,0 +1,490 @@ +/* + * File: symbols.c + * + * Description: + * Symbol table manager for the RTEMS monitor. + * These routines may be used by other system resources also. + * + * + * TODO: + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif + +#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ +#include <rtems.h> +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> + +#include <rtems/monitor.h> +#include "symbols.h" + + +rtems_symbol_table_t * +rtems_symbol_table_create(void) +{ + rtems_symbol_table_t *table; + + table = (rtems_symbol_table_t *) malloc(sizeof(rtems_symbol_table_t)); + memset((void *) table, 0, sizeof(*table)); + + table->growth_factor = 30; /* 30 percent */ + + return table; +} + +void +rtems_symbol_table_destroy(rtems_symbol_table_t *table) +{ + rtems_symbol_string_block_t *p, *pnext; + + if (table) + { + if (table->addresses) + (void) free(table->addresses); + table->addresses = 0; + p = table->string_buffer_head; + while (p) + { + pnext = p->next; + free(p); + p = pnext; + } + table->string_buffer_head = 0; + table->string_buffer_current = 0; + + free(table); + } +} + +rtems_symbol_t * +rtems_symbol_create( + rtems_symbol_table_t *table, + const char *name, + uint32_t value + ) +{ + size_t symbol_length; + size_t newsize; + rtems_symbol_t *sp; + + symbol_length = strlen(name) + 1; /* include '\000' in length */ + + /* need to grow the table? */ + if (table->next >= table->size) + { + if (table->size == 0) + newsize = 100; + else + newsize = table->size + (table->size / (100 / table->growth_factor)); + + table->addresses = (rtems_symbol_t *) realloc((void *) table->addresses, newsize * sizeof(rtems_symbol_t)); + if (table->addresses == 0) /* blew it; lost orig */ + goto failed; + table->size = newsize; + } + + sp = &table->addresses[table->next]; + sp->value = value; + + /* Have to add it to string pool */ + /* need to grow pool? */ + + if ((table->string_buffer_head == 0) || + (table->strings_next + symbol_length) >= SYMBOL_STRING_BLOCK_SIZE) + { + rtems_symbol_string_block_t *p; + + p = (rtems_symbol_string_block_t *) malloc(sizeof(rtems_symbol_string_block_t)); + if (p == 0) + goto failed; + p->next = 0; + if (table->string_buffer_head == 0) + table->string_buffer_head = p; + else + table->string_buffer_current->next = p; + table->string_buffer_current = p; + + table->strings_next = 0; + } + + sp->name = table->string_buffer_current->buffer + table->strings_next; + (void) strcpy(sp->name, name); + + table->strings_next += symbol_length; + table->sorted = 0; + table->next++; + + return sp; + +/* XXX Not sure what to do here. We've possibly destroyed the initial + symbol table due to realloc failure */ +failed: + return 0; +} + +/* + * Qsort entry point for compare by address + */ + +static int +rtems_symbol_compare(const void *e1, + const void *e2) +{ + rtems_symbol_t *s1, *s2; + s1 = (rtems_symbol_t *) e1; + s2 = (rtems_symbol_t *) e2; + + if (s1->value < s2->value) + return -1; + if (s1->value > s2->value) + return 1; + return 0; +} + + +/* + * Sort the symbol table using qsort + */ + +static void +rtems_symbol_sort(rtems_symbol_table_t *table) +{ + qsort((void *) table->addresses, (size_t) table->next, + sizeof(rtems_symbol_t), rtems_symbol_compare); + table->sorted = 1; +} + + +/* + * Search the symbol table by address + * This code based on CYGNUS newlib bsearch, but changed + * to allow for finding closest symbol <= key + */ + +rtems_symbol_t * +rtems_symbol_value_lookup( + rtems_symbol_table_t *table, + uint32_t value + ) +{ + rtems_symbol_t *sp; + rtems_symbol_t *base; + rtems_symbol_t *best = 0; + uint32_t distance; + uint32_t best_distance = ~0; + uint32_t elements; + + if (table == 0) + table = rtems_monitor_symbols; + + if ((table == 0) || (table->size == 0)) + return 0; + + if (table->sorted == 0) + rtems_symbol_sort(table); + + base = table->addresses; + elements = table->next; + + while (elements) + { + sp = base + (elements / 2); + if (value < sp->value) + elements /= 2; + else if (value > sp->value) + { + distance = value - sp->value; + if (distance < best_distance) + { + best_distance = distance; + best = sp; + } + base = sp + 1; + elements = (elements / 2) - (elements % 2 ? 0 : 1); + } + else + return sp; + } + + if (value == base->value) + return base; + + return best; +} + +/* + * Search the symbol table for the exact matching address. + * If the symbol table has already been sorted, then + * call the regular symbol value lookup, however, it it + * has not yet been sorted, search it sequentially. + * This routine is primarily used for low level symbol + * lookups (eg. from exception handler and interrupt routines) + * where the penality of sorted is not wanted and where + * an exact match is needed such that symbol table order + * is not important. + */ +const rtems_symbol_t * +rtems_symbol_value_lookup_exact( + rtems_symbol_table_t *table, + uint32_t value + ) +{ + uint32_t s; + rtems_symbol_t *sp; + + if (table == 0) + { + table = rtems_monitor_symbols; + if (table == 0) + return NULL; + } + + if (table->sorted) + { + sp = rtems_symbol_value_lookup(table, value); + if ( rtems_symbol_value(sp) == value ) + return sp; + else + return NULL; /* not an exact match */ + } + + for (s = 0, sp = table->addresses; s < table->next; s++, sp++) + { + if ( sp->value == value ) + return sp; + } + + return NULL; + +} + + +/* + * Search the symbol table by string name (case independent) + */ + +rtems_symbol_t * +rtems_symbol_name_lookup( + rtems_symbol_table_t *table, + const char *name + ) +{ + uint32_t s; + rtems_symbol_t *sp; + + if (table == 0) + { + table = rtems_monitor_symbols; + if (table == 0) + return NULL; + } + + for (s = 0, sp = table->addresses; s < table->next; s++, sp++) + { + if ( strcasecmp(sp->name, name) == 0 ) + return sp; + } + + return NULL; +} + +void * +rtems_monitor_symbol_next( + void *object_info, + rtems_monitor_symbol_t *canonical __attribute__((unused)), + rtems_id *next_id +) +{ + rtems_symbol_table_t *table; + uint32_t n = rtems_object_id_get_index(*next_id); + + table = *(rtems_symbol_table_t **) object_info; + if (table == 0) + goto failed; + + if (n >= table->next) + goto failed; + + /* NOTE: symbols do not have id and name fields */ + + if (table->sorted == 0) + rtems_symbol_sort(table); + + _Thread_Disable_dispatch(); + + *next_id += 1; + return (void *) (table->addresses + n); + +failed: + *next_id = RTEMS_OBJECT_ID_FINAL; + return 0; +} + +void +rtems_monitor_symbol_canonical( + rtems_monitor_symbol_t *canonical_symbol, + rtems_symbol_t *sp +) +{ + canonical_symbol->value = sp->value; + canonical_symbol->offset = 0; + strncpy(canonical_symbol->name, sp->name, sizeof(canonical_symbol->name)-1); +} + + +void +rtems_monitor_symbol_canonical_by_name( + rtems_monitor_symbol_t *canonical_symbol, + const char *name +) +{ + rtems_symbol_t *sp; + + sp = rtems_symbol_name_lookup(0, name); + + canonical_symbol->value = sp ? sp->value : 0; + + strncpy(canonical_symbol->name, name, sizeof(canonical_symbol->name) - 1); + canonical_symbol->offset = 0; +} + +void +rtems_monitor_symbol_canonical_by_value( + rtems_monitor_symbol_t *canonical_symbol, + void *value_void_p +) +{ + uintptr_t value = (uintptr_t) value_void_p; + rtems_symbol_t *sp; + + sp = rtems_symbol_value_lookup(0, value); + if (sp) + { + canonical_symbol->value = sp->value; + canonical_symbol->offset = value - sp->value; + strncpy(canonical_symbol->name, sp->name, sizeof(canonical_symbol->name)-1); + } + else + { + canonical_symbol->value = value; + canonical_symbol->offset = 0; + canonical_symbol->name[0] = '\0'; + } +} + + +uint32_t +rtems_monitor_symbol_dump( + rtems_monitor_symbol_t *canonical_symbol, + bool verbose +) +{ + uint32_t length = 0; + + /* + * print the name if it exists AND if value is non-zero + * Ie: don't print some garbage symbol for address 0 + */ + + if (canonical_symbol->name[0] && (canonical_symbol->value != 0)) + { + if (canonical_symbol->offset == 0) + length += fprintf(stdout,"%.*s", + (int) sizeof(canonical_symbol->name), + canonical_symbol->name); + else + length += fprintf(stdout,"<%.*s+0x%" PRIx32 ">", + (int) sizeof(canonical_symbol->name), + canonical_symbol->name, + canonical_symbol->offset); + if (verbose) + length += fprintf(stdout, + " [0x%" PRIx32 "]", canonical_symbol->value); + } + else + length += fprintf(stdout,"[0x%" PRIx32 "]", canonical_symbol->value); + + return length; +} + + +void +rtems_monitor_symbol_dump_all( + rtems_symbol_table_t *table, + bool verbose __attribute__((unused)) +) +{ + uint32_t s; + rtems_symbol_t *sp; + + if (table == 0) + { + table = rtems_monitor_symbols; + if (table == 0) + return; + } + + if (table->sorted == 0) + rtems_symbol_sort(table); + + for (s = 0, sp = table->addresses; s < table->next; s++, sp++) + { + rtems_monitor_symbol_t canonical_symbol; + + rtems_monitor_symbol_canonical(&canonical_symbol, sp); + rtems_monitor_symbol_dump(&canonical_symbol, true); + fprintf(stdout,"\n"); + } +} + + +/* + * 'symbol' command + */ + +void rtems_monitor_symbol_cmd( + int argc, + char **argv, + const rtems_monitor_command_arg_t *command_arg, + bool verbose +) +{ + int arg; + rtems_symbol_table_t *table; + + table = *command_arg->symbol_table; + if (table == 0) + { + table = rtems_monitor_symbols; + if (table == 0) + return; + } + + /* + * Use object command to dump out whole symbol table + */ + if (argc == 1) + rtems_monitor_symbol_dump_all(table, verbose); + else + { + rtems_monitor_symbol_t canonical_symbol; + + for (arg=1; argv[arg]; arg++) + { + rtems_monitor_symbol_canonical_by_name(&canonical_symbol, argv[arg]); + rtems_monitor_symbol_dump(&canonical_symbol, verbose); + fprintf(stdout,"\n"); + } + } +} diff --git a/cpukit/libmisc/monitor/mon-task.c b/cpukit/libmisc/monitor/mon-task.c new file mode 100644 index 0000000000..6007b3f879 --- /dev/null +++ b/cpukit/libmisc/monitor/mon-task.c @@ -0,0 +1,105 @@ +/* + * RTEMS Monitor task support + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/monitor.h> + +#include <stdio.h> +#include <string.h> /* memcpy() */ + +void +rtems_monitor_task_canonical( + rtems_monitor_task_t *canonical_task, + void *thread_void +) +{ + Thread_Control *rtems_thread = (Thread_Control *) thread_void; + RTEMS_API_Control *api; + + api = rtems_thread->API_Extensions[ THREAD_API_RTEMS ]; + + canonical_task->entry = rtems_thread->Start.entry_point; + canonical_task->argument = rtems_thread->Start.numeric_argument; + canonical_task->stack = rtems_thread->Start.Initial_stack.area; + canonical_task->stack_size = rtems_thread->Start.Initial_stack.size; + canonical_task->priority = rtems_thread->current_priority; + canonical_task->state = rtems_thread->current_state; + canonical_task->wait_id = rtems_thread->Wait.id; + canonical_task->events = api->pending_events; + /* + * FIXME: make this optionally cpu_time_executed + */ +#if 0 + canonical_task->ticks = rtems_thread->cpu_time_executed; +#else + canonical_task->ticks = 0; +#endif + +/* XXX modes and attributes only exist in the RTEMS API .. */ +/* XXX not directly in the core thread.. they will have to be derived */ +/* XXX if they are important enough to include anymore. */ + canonical_task->modes = 0; /* XXX FIX ME.... rtems_thread->current_modes; */ + canonical_task->attributes = 0 /* XXX FIX ME rtems_thread->API_Extensions[ THREAD_API_RTEMS ]->attribute_set */; + (void) memcpy(canonical_task->notepad, api ->Notepads, sizeof(canonical_task->notepad)); +/* XXX more to fix */ +/* + (void) memcpy(&canonical_task->wait_args, &rtems_thread->Wait.Extra, sizeof(canonical_task->wait_args)); +*/ +} + + +void +rtems_monitor_task_dump_header( + bool verbose __attribute__((unused)) +) +{ + fprintf(stdout,"\ + ID NAME PRI STATE MODES EVENTS WAITID WAITARG NOTES\n\ +"); +/*23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 +0 1 2 3 4 5 6 7 */ + + rtems_monitor_separator(); +} + +/* + */ + +void +rtems_monitor_task_dump( + rtems_monitor_task_t *monitor_task, + bool verbose __attribute__((unused)) +) +{ + int length = 0; + + length += rtems_monitor_dump_id(monitor_task->id); + length += rtems_monitor_pad(11, length); + length += rtems_monitor_dump_name(monitor_task->id); + length += rtems_monitor_pad(26, length); + length += rtems_monitor_dump_priority(monitor_task->priority); + length += rtems_monitor_pad(29, length); + length += rtems_monitor_dump_state(monitor_task->state); + length += rtems_monitor_pad(37, length); + length += rtems_monitor_dump_modes(monitor_task->modes); + length += rtems_monitor_pad(45, length); + length += rtems_monitor_dump_events(monitor_task->events); + if (monitor_task->wait_id) + { + length += rtems_monitor_pad(54, length); + length += rtems_monitor_dump_id(monitor_task->wait_id); + length += rtems_monitor_pad(63, length); + length += rtems_monitor_dump_hex(monitor_task->wait_args); + } + + length += rtems_monitor_pad(72, length); + length += rtems_monitor_dump_notepad(monitor_task->notepad); + fprintf(stdout,"\n"); +} diff --git a/cpukit/libmisc/monitor/monitor.h b/cpukit/libmisc/monitor/monitor.h new file mode 100644 index 0000000000..84a360b976 --- /dev/null +++ b/cpukit/libmisc/monitor/monitor.h @@ -0,0 +1,531 @@ +/** + * @file rtems/monitor.h + * + * The RTEMS monitor task. + */ + +/* + * $Id$ + */ + +#ifndef __MONITOR_H +#define __MONITOR_H + +#include <rtems/error.h> /* rtems_error() */ +#include <rtems/config.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward decls from symbols.h */ +typedef struct _rtems_symbol_t rtems_symbol_t; +typedef struct _rtems_symbol_table_t rtems_symbol_table_t; + +/* + * Monitor types are derived from rtems object classes + */ + +typedef enum { + RTEMS_MONITOR_OBJECT_INVALID = OBJECTS_CLASSIC_NO_CLASS, + RTEMS_MONITOR_OBJECT_TASK = OBJECTS_RTEMS_TASKS, + RTEMS_MONITOR_OBJECT_EXTENSION = OBJECTS_RTEMS_EXTENSIONS, + RTEMS_MONITOR_OBJECT_QUEUE = OBJECTS_RTEMS_MESSAGE_QUEUES, + RTEMS_MONITOR_OBJECT_SEMAPHORE = OBJECTS_RTEMS_SEMAPHORES, + RTEMS_MONITOR_OBJECT_PARTITION = OBJECTS_RTEMS_PARTITIONS, + RTEMS_MONITOR_OBJECT_REGION = OBJECTS_RTEMS_REGIONS, + RTEMS_MONITOR_OBJECT_PORT = OBJECTS_RTEMS_PORTS, + + /* following monitor objects are not known to RTEMS, but + * we like to have "types" for them anyway */ + + RTEMS_MONITOR_OBJECT_DRIVER = OBJECTS_RTEMS_CLASSES_LAST+1, + RTEMS_MONITOR_OBJECT_DNAME, + RTEMS_MONITOR_OBJECT_CONFIG, + RTEMS_MONITOR_OBJECT_INIT_TASK, + RTEMS_MONITOR_OBJECT_MPCI, + RTEMS_MONITOR_OBJECT_SYMBOL, + #if defined(RTEMS_POSIX_API) + RTEMS_MONITOR_OBJECT_PTHREAD, + #endif +} rtems_monitor_object_type_t; + +/* + * rtems_monitor_init() flags + */ + +#define RTEMS_MONITOR_SUSPEND 0x0001 /* suspend monitor on startup */ +#define RTEMS_MONITOR_GLOBAL 0x0002 /* monitor should be global */ +#define RTEMS_MONITOR_NOTASK 0x0004 /* do not start monitor task */ +#define RTEMS_MONITOR_NOSYMLOAD 0x0008 /* do not load symbols */ +#define RTEMS_MONITOR_WAITQUIT 0x0010 /* wait for monitor task to terminate */ + +/* + * Public interfaces for RTEMS data structures monitor is aware of. + * These are only used by the monitor. + * + * NOTE: + * All the canonical objects that correspond to RTEMS managed "objects" + * must have an identical first portion with 'id' and 'name' fields. + * + * Others do not have that restriction, even tho we would like them to. + * This is because some of the canonical structures are almost too big + * for shared memory driver (eg: mpci) and we are nickel and diming it. + */ + +/* + * Type of a pointer that may be a symbol + */ + +#define MONITOR_SYMBOL_LEN 20 +typedef struct { + char name[MONITOR_SYMBOL_LEN]; + uint32_t value; + uint32_t offset; +} rtems_monitor_symbol_t; + +typedef struct { + rtems_id id; + rtems_name name; + /* end of common portion */ +} rtems_monitor_generic_t; + +/* + * Task + */ +typedef struct { + rtems_id id; + rtems_name name; + /* end of common portion */ + Thread_Entry entry; + Thread_Entry_numeric_type argument; + void *stack; + uint32_t stack_size; + rtems_task_priority priority; + States_Control state; + rtems_event_set events; + rtems_mode modes; + rtems_attribute attributes; + uint32_t notepad[RTEMS_NUMBER_NOTEPADS]; + rtems_id wait_id; + uint32_t wait_args; + uint32_t ticks; +} rtems_monitor_task_t; + +/* + * Init task + */ + +typedef struct { + rtems_id id; /* not really an id */ + rtems_name name; + /* end of common portion */ + rtems_monitor_symbol_t entry; + uint32_t argument; + uint32_t stack_size; + rtems_task_priority priority; + rtems_mode modes; + rtems_attribute attributes; +} rtems_monitor_init_task_t; + + +/* + * Message queue + */ +typedef struct { + rtems_id id; + rtems_name name; + /* end of common portion */ + rtems_attribute attributes; + uint32_t number_of_pending_messages; + uint32_t maximum_pending_messages; + size_t maximum_message_size; +} rtems_monitor_queue_t; + +/* + * Semaphore + */ +typedef struct { + rtems_id id; + rtems_name name; + /* end of common portion */ + rtems_attribute attribute; + rtems_task_priority priority_ceiling; + uint32_t max_count; + uint32_t cur_count; + rtems_id holder_id; +} rtems_monitor_sema_t; + +/* + * Extension + */ +typedef struct { + rtems_id id; + rtems_name name; + /* end of common portion */ + rtems_monitor_symbol_t e_create; + rtems_monitor_symbol_t e_start; + rtems_monitor_symbol_t e_restart; + rtems_monitor_symbol_t e_delete; + rtems_monitor_symbol_t e_tswitch; + rtems_monitor_symbol_t e_begin; + rtems_monitor_symbol_t e_exitted; + rtems_monitor_symbol_t e_fatal; +} rtems_monitor_extension_t; + + /* + * Region + */ +typedef struct { + rtems_id id; + rtems_name name; + /* end of common portion */ + rtems_attribute attribute; + void * start_addr; + uint32_t length; + uint32_t page_size; + uint32_t max_seg_size; + uint32_t used_blocks; +} rtems_monitor_region_t; + +/* + * Partition + */ +typedef struct { + rtems_id id; + rtems_name name; + /* end of common portion */ + rtems_attribute attribute; + void * start_addr; + uint32_t length; + uint32_t buf_size; + uint32_t used_blocks; +} rtems_monitor_part_t; + +/* + * Device driver + */ + +typedef struct { + rtems_id id; /* not really an id (should be tho) */ + rtems_name name; /* ditto */ + /* end of common portion */ + rtems_monitor_symbol_t initialization; /* initialization procedure */ + rtems_monitor_symbol_t open; /* open request procedure */ + rtems_monitor_symbol_t close; /* close request procedure */ + rtems_monitor_symbol_t read; /* read request procedure */ + rtems_monitor_symbol_t write; /* write request procedure */ + rtems_monitor_symbol_t control; /* special functions procedure */ +} rtems_monitor_driver_t; + +/* + * System config + */ + +typedef struct { + void *work_space_start; + uint32_t work_space_size; + uint32_t maximum_tasks; + uint32_t maximum_timers; + uint32_t maximum_semaphores; + uint32_t maximum_message_queues; + uint32_t maximum_partitions; + uint32_t maximum_regions; + uint32_t maximum_ports; + uint32_t maximum_periods; + uint32_t maximum_extensions; + uint32_t microseconds_per_tick; + uint32_t ticks_per_timeslice; + uint32_t number_of_initialization_tasks; +} rtems_monitor_config_t; + +/* + * MPCI config + */ + +#if defined(RTEMS_MULTIPROCESSING) +typedef struct { + uint32_t node; /* local node number */ + uint32_t maximum_nodes; /* maximum # nodes in system */ + uint32_t maximum_global_objects; /* maximum # global objects */ + uint32_t maximum_proxies; /* maximum # proxies */ + + uint32_t default_timeout; /* in ticks */ + size_t maximum_packet_size; + rtems_monitor_symbol_t initialization; + rtems_monitor_symbol_t get_packet; + rtems_monitor_symbol_t return_packet; + rtems_monitor_symbol_t send_packet; + rtems_monitor_symbol_t receive_packet; +} rtems_monitor_mpci_t; +#endif + +/* + * The generic canonical information union + */ + +typedef union { + rtems_monitor_generic_t generic; + rtems_monitor_task_t task; + rtems_monitor_queue_t queue; + rtems_monitor_sema_t sema; + rtems_monitor_extension_t extension; + rtems_monitor_driver_t driver; + rtems_monitor_config_t config; + rtems_monitor_region_t region; + rtems_monitor_part_t part; +#if defined(RTEMS_MULTIPROCESSING) + rtems_monitor_mpci_t mpci; +#endif + rtems_monitor_init_task_t itask; +} rtems_monitor_union_t; + +/* + * Support for talking to other monitors + */ + +/* + * Names of other monitors + */ + +#define RTEMS_MONITOR_NAME (rtems_build_name('R', 'M', 'O', 'N')) +#define RTEMS_MONITOR_SERVER_NAME (rtems_build_name('R', 'M', 'S', 'V')) +#define RTEMS_MONITOR_QUEUE_NAME (rtems_build_name('R', 'M', 'S', 'Q')) +#define RTEMS_MONITOR_RESPONSE_QUEUE_NAME (rtems_build_name('R', 'M', 'R', 'Q')) + +#define RTEMS_MONITOR_SERVER_RESPONSE 0x0001 +#define RTEMS_MONITOR_SERVER_CANONICAL 0x0002 + +typedef struct +{ + uint32_t command; + rtems_id return_id; + uint32_t argument0; + uint32_t argument1; + uint32_t argument2; + uint32_t argument3; + uint32_t argument4; + uint32_t argument5; +} rtems_monitor_server_request_t; + +typedef struct +{ + uint32_t command; + uint32_t result0; + uint32_t result1; + rtems_monitor_union_t payload; +} rtems_monitor_server_response_t; + +extern rtems_id rtems_monitor_task_id; + +extern uint32_t rtems_monitor_node; /* our node number */ +extern uint32_t rtems_monitor_default_node; /* current default for commands */ + +/* + * Monitor command function and table entry + */ + +typedef struct rtems_monitor_command_entry_s rtems_monitor_command_entry_t; +typedef union _rtems_monitor_command_arg_t rtems_monitor_command_arg_t; + +typedef void (*rtems_monitor_command_function_t)( + int argc, + char **argv, + const rtems_monitor_command_arg_t *command_arg, + bool verbose +); + +union _rtems_monitor_command_arg_t { + rtems_monitor_object_type_t monitor_object; + rtems_status_code status_code; + rtems_symbol_table_t **symbol_table; + const rtems_monitor_command_entry_t *monitor_command_entry; +}; + +struct rtems_monitor_command_entry_s { + const char *command; /* command name */ + const char *usage; /* usage string for the command */ + uint32_t arguments_required; /* # of required args */ + rtems_monitor_command_function_t command_function; + /* Some argument for the command */ + rtems_monitor_command_arg_t command_arg; + const rtems_monitor_command_entry_t *next; +}; + + +typedef void *(*rtems_monitor_object_next_fn)(void *, void *, rtems_id *); +typedef void (*rtems_monitor_object_canonical_fn)(void *, void *); +typedef void (*rtems_monitor_object_dump_header_fn)(bool); +typedef void (*rtems_monitor_object_dump_fn)(void *, bool); + +typedef struct { + rtems_monitor_object_type_t type; + void *object_information; + int size; /* of canonical object */ + rtems_monitor_object_next_fn next; + rtems_monitor_object_canonical_fn canonical; + rtems_monitor_object_dump_header_fn dump_header; + rtems_monitor_object_dump_fn dump; +} rtems_monitor_object_info_t; + +typedef bool (*rtems_monitor_per_command_routine)(const rtems_monitor_command_entry_t *, void *); + +/* monitor.c */ +void rtems_monitor_pause_cmd(int, char **, const rtems_monitor_command_arg_t*, bool); +void rtems_monitor_fatal_cmd(int, char **, const rtems_monitor_command_arg_t*, bool); +void rtems_monitor_continue_cmd(int, char **, const rtems_monitor_command_arg_t*, bool); +void rtems_monitor_debugger_cmd(int, char **, const rtems_monitor_command_arg_t*, bool); +void rtems_monitor_reset_cmd(int, char **, const rtems_monitor_command_arg_t*, bool); +void rtems_monitor_node_cmd(int, char **, const rtems_monitor_command_arg_t*, bool); +void rtems_monitor_symbols_loadup(void); +int rtems_monitor_insert_cmd(rtems_monitor_command_entry_t *); +void rtems_monitor_wakeup(void); +void rtems_monitor_command_iterate(rtems_monitor_per_command_routine routine, void *arg); +rtems_status_code rtems_monitor_suspend(rtems_interval timeout); + +/* editor.c */ +void rtems_monitor_kill(void); +void rtems_monitor_init(uint32_t); +void rtems_monitor_task(rtems_task_argument); + +/* server.c */ +void rtems_monitor_server_kill(void); +rtems_status_code rtems_monitor_server_request(uint32_t , rtems_monitor_server_request_t *, rtems_monitor_server_response_t *); +void rtems_monitor_server_task(rtems_task_argument); +void rtems_monitor_server_init(uint32_t ); + +/* command.c */ +int rtems_monitor_make_argv(char *, int *, char **); +int rtems_monitor_command_read(char *, int *, char **); +void rtems_monitor_command_usage(const rtems_monitor_command_entry_t *, const char *); +void rtems_monitor_help_cmd(int, char **, const rtems_monitor_command_arg_t *, bool); +const rtems_monitor_command_entry_t *rtems_monitor_command_lookup(const char *name); + +/* prmisc.c */ +void rtems_monitor_separator(void); +uint32_t rtems_monitor_pad(uint32_t dest_col, uint32_t curr_col); +int rtems_monitor_dump_decimal(uint32_t num); +int rtems_monitor_dump_hex(uint32_t num); +int rtems_monitor_dump_addr(void *addr); +int rtems_monitor_dump_id(rtems_id id); +int rtems_monitor_dump_name(rtems_id id); +int rtems_monitor_dump_priority(rtems_task_priority priority); +int rtems_monitor_dump_state(States_Control state); +int rtems_monitor_dump_modes(rtems_mode modes); +int rtems_monitor_dump_attributes(rtems_attribute attributes); +int rtems_monitor_dump_events(rtems_event_set events); +int rtems_monitor_dump_notepad(uint32_t *notepad); + +/* object.c */ +rtems_id rtems_monitor_id_fixup(rtems_id, uint32_t , rtems_monitor_object_type_t); +const rtems_monitor_object_info_t *rtems_monitor_object_lookup(rtems_monitor_object_type_t type); +rtems_id rtems_monitor_object_canonical_get(rtems_monitor_object_type_t, rtems_id, void *, size_t *size_p); +rtems_id rtems_monitor_object_canonical_next(const rtems_monitor_object_info_t *, rtems_id, void *); +void *rtems_monitor_object_next(void *, void *, rtems_id, rtems_id *); +rtems_id rtems_monitor_object_canonical(rtems_id, void *); +void rtems_monitor_object_cmd(int, char **, const rtems_monitor_command_arg_t*, bool); + +/* manager.c */ +void *rtems_monitor_manager_next(void *, void *, rtems_id *); + +/* config.c */ +void rtems_monitor_config_canonical(rtems_monitor_config_t *, void *); +void *rtems_monitor_config_next(void *, rtems_monitor_config_t *, rtems_id *); +void rtems_monitor_config_dump_header(bool); +int rtems_monitor_config_dump(rtems_monitor_config_t *, bool verbose); + +/* mpci.c */ +#if defined(RTEMS_MULTIPROCESSING) +void rtems_monitor_mpci_canonical(rtems_monitor_mpci_t *, void *); +void *rtems_monitor_mpci_next(void *, rtems_monitor_mpci_t *, rtems_id *); +void rtems_monitor_mpci_dump_header(bool); +void rtems_monitor_mpci_dump(rtems_monitor_mpci_t *, bool verbose); +#endif + +/* itask.c */ +void rtems_monitor_init_task_canonical(rtems_monitor_init_task_t *, void *); +void *rtems_monitor_init_task_next(void *, rtems_monitor_init_task_t *, rtems_id *); +void rtems_monitor_init_task_dump_header(bool); +void rtems_monitor_init_task_dump(rtems_monitor_init_task_t *, bool verbose); + +/* extension.c */ +void rtems_monitor_extension_canonical(rtems_monitor_extension_t *, void *); +void rtems_monitor_extension_dump_header(bool verbose); +void rtems_monitor_extension_dump(rtems_monitor_extension_t *, bool); + +/* task.c */ +void rtems_monitor_task_canonical(rtems_monitor_task_t *, void *); +void rtems_monitor_task_dump_header(bool verbose); +void rtems_monitor_task_dump(rtems_monitor_task_t *, bool); + +/* sema.c */ +void rtems_monitor_sema_canonical(rtems_monitor_sema_t *, void *); +void rtems_monitor_sema_dump_header(bool verbose); +void rtems_monitor_sema_dump(rtems_monitor_sema_t *, bool); + +/* queue.c */ +void rtems_monitor_queue_canonical(rtems_monitor_queue_t *, void *); +void rtems_monitor_queue_dump_header(bool verbose); +void rtems_monitor_queue_dump(rtems_monitor_queue_t *, bool); + +/* region.c */ +void rtems_monitor_region_canonical(rtems_monitor_region_t *, void *); +void rtems_monitor_region_dump_header(bool verbose); +void rtems_monitor_region_dump(rtems_monitor_region_t *, bool); + +/* partition.c */ +void rtems_monitor_part_canonical(rtems_monitor_part_t *, void *); +void rtems_monitor_part_dump_header(bool verbose); +void rtems_monitor_part_dump(rtems_monitor_part_t *, bool); + +/* driver.c */ +void *rtems_monitor_driver_next(void *, rtems_monitor_driver_t *, rtems_id *); +void rtems_monitor_driver_canonical(rtems_monitor_driver_t *, void *); +void rtems_monitor_driver_dump_header(bool); +void rtems_monitor_driver_dump(rtems_monitor_driver_t *, bool); + +/* symbols.c */ +rtems_symbol_table_t *rtems_symbol_table_create(void); +void rtems_symbol_table_destroy(rtems_symbol_table_t *table); + +rtems_symbol_t *rtems_symbol_create(rtems_symbol_table_t *, const char *, uint32_t ); +rtems_symbol_t *rtems_symbol_value_lookup(rtems_symbol_table_t *, uint32_t ); +const rtems_symbol_t *rtems_symbol_value_lookup_exact(rtems_symbol_table_t *, uint32_t ); +rtems_symbol_t *rtems_symbol_name_lookup(rtems_symbol_table_t *, const char *); +void *rtems_monitor_symbol_next(void *object_info, rtems_monitor_symbol_t *, rtems_id *); +void rtems_monitor_symbol_canonical(rtems_monitor_symbol_t *, rtems_symbol_t *); +void rtems_monitor_symbol_canonical_by_name(rtems_monitor_symbol_t *, const char *); +void rtems_monitor_symbol_canonical_by_value(rtems_monitor_symbol_t *, void *); +uint32_t rtems_monitor_symbol_dump(rtems_monitor_symbol_t *, bool); +void rtems_monitor_symbol_cmd(int, char **, const rtems_monitor_command_arg_t*, bool); + +#if defined(RTEMS_NETWORKING) +void mon_ifconfig( + int argc, + char *argv[], + uint32_t command_arg, + bool verbose +); +void mon_route( + int argc, + char *argv[], + uint32_t command_arg, + bool verbose +); +#endif + +/* mon-object.c */ +const rtems_monitor_object_info_t *rtems_monitor_object_lookup( + rtems_monitor_object_type_t type +); + +/* shared data */ +extern rtems_symbol_table_t *rtems_monitor_symbols; + +#define MONITOR_WAKEUP_EVENT RTEMS_EVENT_0 + +#ifdef __cplusplus +} +#endif + +#endif /* ! __MONITOR_H */ diff --git a/cpukit/libmisc/monitor/symbols.h b/cpukit/libmisc/monitor/symbols.h new file mode 100644 index 0000000000..6246379a94 --- /dev/null +++ b/cpukit/libmisc/monitor/symbols.h @@ -0,0 +1,64 @@ +/* + * RTEMS monitor symbol table functions + * + * Description: + * Entry points for symbol table routines. + * + * + * + * TODO: + * + * $Id$ + */ + +#ifndef _INCLUDE_SYMBOLS_H +#define _INCLUDE_SYMBOLS_H + +#include <rtems/monitor.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct _rtems_symbol_t { + uint32_t value; + char *name; +} ; + +#define SYMBOL_STRING_BLOCK_SIZE 4080 +typedef struct rtems_symbol_string_block_s { + struct rtems_symbol_string_block_s *next; + char buffer[SYMBOL_STRING_BLOCK_SIZE]; +} rtems_symbol_string_block_t; + +struct _rtems_symbol_table_t { + + uint32_t sorted; /* are symbols sorted right now? */ + uint32_t growth_factor; /* % to grow by when needed */ + uint32_t next; /* next symbol slot to use when adding */ + uint32_t size; /* max # of symbols */ + + /* + * Symbol list -- sorted by address (when we do a lookup) + */ + + rtems_symbol_t *addresses; /* symbol array by address */ + + /* + * String pool, unsorted, a list of blocks of string data + */ + + rtems_symbol_string_block_t *string_buffer_head; + rtems_symbol_string_block_t *string_buffer_current; + uint32_t strings_next; /* next byte to use in this block */ + +} ; + +#define rtems_symbol_name(sp) ((sp)->name) +#define rtems_symbol_value(sp) ((sp)->value) + +#ifdef __cplusplus +} +#endif + +#endif /* ! _INCLUDE_SYMBOLS_H */ |