diff options
Diffstat (limited to 'cpukit/libmisc/monitor/mon-monitor.c')
-rw-r--r-- | cpukit/libmisc/monitor/mon-monitor.c | 529 |
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; + } +} |