summaryrefslogtreecommitdiffstats
path: root/cpukit/libmisc/monitor/mon-monitor.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libmisc/monitor/mon-monitor.c')
-rw-r--r--cpukit/libmisc/monitor/mon-monitor.c529
1 files changed, 529 insertions, 0 deletions
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;
+ }
+}