forked from Imagelibrary/rtems
1192 lines
29 KiB
C
1192 lines
29 KiB
C
/*
|
|
------------------------------------------------------------------------
|
|
|
|
Copyright 2002, 2015 Chris Johns <chrisj@rtems.org>
|
|
All rights reserved.
|
|
|
|
COPYRIGHT (c) 2014.
|
|
On-Line Applications Research Corporation (OAR).
|
|
|
|
The license and distribution terms for this file may be
|
|
found in the file LICENSE in this distribution.
|
|
|
|
This software with is provided ``as is'' and with NO WARRANTY.
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
RTEMS Performance Monitoring and Measurement Framework.
|
|
|
|
This is the Target Interface Command Line Interface. You need
|
|
start the RTEMS monitor.
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
|
|
#include <rtems.h>
|
|
#include <rtems/capture-cli.h>
|
|
#include <rtems/captureimpl.h>
|
|
#include <rtems/monitor.h>
|
|
#include <rtems/cpuuse.h>
|
|
#
|
|
#define RC_UNUSED RTEMS_UNUSED
|
|
|
|
#define RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS (20)
|
|
|
|
/*
|
|
* Counter used to count the number of active tasks.
|
|
*/
|
|
static int rtems_capture_cli_task_count = 0;
|
|
|
|
/*
|
|
* The user capture timestamper.
|
|
*/
|
|
static rtems_capture_timestamp capture_timestamp;
|
|
|
|
/*
|
|
* rtems_capture_cli_open
|
|
*
|
|
* This function opens the capture engine. We need the size of the
|
|
* capture buffer.
|
|
*/
|
|
|
|
static const char* open_usage = "usage: copen [-i] size\n";
|
|
|
|
static void
|
|
rtems_capture_cli_open (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
uint32_t size = 0;
|
|
bool enable = false;
|
|
rtems_status_code sc;
|
|
int arg;
|
|
|
|
if (argc <= 1)
|
|
{
|
|
fprintf (stdout, open_usage);
|
|
return;
|
|
}
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
if (argv[arg][1] == 'i')
|
|
enable = true;
|
|
else
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
size = strtoul (argv[arg], 0, 0);
|
|
|
|
if (size < 100)
|
|
{
|
|
fprintf (stdout, "error: size must be greater than or equal to 100\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
sc = rtems_capture_open (size, capture_timestamp);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: open failed: %s\n", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "capture engine opened.\n");
|
|
|
|
if (!enable)
|
|
return;
|
|
|
|
sc = rtems_capture_control (enable);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: open enable failed: %s\n", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "capture engine enabled.\n");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_close
|
|
*
|
|
* This function closes the capture engine.
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_close (int argc RC_UNUSED,
|
|
char** argv RC_UNUSED,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_capture_close ();
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: close failed: %s\n", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "capture engine closed.\n");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_enable
|
|
*
|
|
* This function enables the capture engine.
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_enable (int argc RC_UNUSED,
|
|
char** argv RC_UNUSED,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_capture_control (true);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: enable failed: %s\n", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "capture engine enabled.\n");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_disable
|
|
*
|
|
* This function disables the capture engine.
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_disable (int argc RC_UNUSED,
|
|
char** argv RC_UNUSED,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_capture_control (false);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: disable failed: %s\n", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "capture engine disabled.\n");
|
|
}
|
|
|
|
static void
|
|
rtems_capture_cli_print_task (rtems_tcb *tcb)
|
|
{
|
|
rtems_task_priority ceiling = rtems_capture_watch_get_ceiling ();
|
|
rtems_task_priority floor = rtems_capture_watch_get_floor ();
|
|
rtems_task_priority priority;
|
|
int length;
|
|
|
|
priority = rtems_capture_task_real_priority (tcb);
|
|
|
|
fprintf (stdout, " ");
|
|
rtems_monitor_dump_id (rtems_capture_task_id (tcb));
|
|
fprintf (stdout, " ");
|
|
rtems_monitor_dump_name (rtems_capture_task_id (tcb));
|
|
fprintf (stdout, " ");
|
|
rtems_monitor_dump_priority (rtems_capture_task_start_priority (tcb));
|
|
fprintf (stdout, " ");
|
|
rtems_monitor_dump_priority (rtems_capture_task_real_priority (tcb));
|
|
fprintf (stdout, " ");
|
|
rtems_monitor_dump_priority (rtems_capture_task_curr_priority (tcb));
|
|
fprintf (stdout, " ");
|
|
length = rtems_monitor_dump_state (rtems_capture_task_state (tcb));
|
|
fprintf (stdout, "%*c", 14 - length, ' ');
|
|
fprintf (stdout, " %c%c",
|
|
'a',
|
|
rtems_capture_task_flags (tcb) & RTEMS_CAPTURE_TRACED ? 't' : '-');
|
|
|
|
if ((floor > ceiling) && (ceiling > priority))
|
|
fprintf (stdout, "--");
|
|
else
|
|
{
|
|
uint32_t flags = rtems_capture_task_control_flags (tcb);
|
|
fprintf (stdout, "%c%c",
|
|
rtems_capture_task_control (tcb) ?
|
|
(flags & RTEMS_CAPTURE_WATCH ? 'w' : '+') : '-',
|
|
rtems_capture_watch_global_on () ? 'g' : '-');
|
|
}
|
|
fprintf (stdout, "\n");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_count_tasks
|
|
*
|
|
* This function is called for each tcb and counts the
|
|
* number of tasks.
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_count_tasks (rtems_tcb *tcb)
|
|
{
|
|
rtems_capture_cli_task_count++;
|
|
}
|
|
|
|
|
|
/*
|
|
* rtems_capture_cli_task_list
|
|
*
|
|
* This function lists the tasks the capture engine knows about.
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_task_list (int argc RC_UNUSED,
|
|
char** argv RC_UNUSED,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_capture_time_t uptime;
|
|
|
|
rtems_capture_time (&uptime);
|
|
|
|
rtems_capture_cli_task_count = 0;
|
|
rtems_iterate_over_all_threads (rtems_capture_cli_count_tasks);
|
|
|
|
fprintf (stdout, "uptime: ");
|
|
rtems_capture_print_timestamp (uptime);
|
|
fprintf (stdout, "\ntotal %i\n", rtems_capture_cli_task_count);
|
|
rtems_iterate_over_all_threads (rtems_capture_cli_print_task);
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_watch_list
|
|
*
|
|
* This function lists the controls in the capture engine.
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_watch_list (int argc RC_UNUSED,
|
|
char** argv RC_UNUSED,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_capture_print_watch_list();
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_get_name_id
|
|
*
|
|
* This function checks arguments for a name or an id.
|
|
*/
|
|
|
|
static bool
|
|
rtems_capture_cli_get_name_id (char* arg,
|
|
bool* valid_name,
|
|
bool* valid_id,
|
|
rtems_name* name,
|
|
rtems_id* id)
|
|
{
|
|
size_t l;
|
|
size_t i;
|
|
|
|
if (*valid_name && *valid_id)
|
|
{
|
|
fprintf (stdout, "error: too many arguments\n");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* See if the arg is all hex digits.
|
|
*/
|
|
|
|
l = strlen (arg);
|
|
|
|
for (i = 0; i < l; i++)
|
|
if (!isxdigit ((unsigned char)arg[i]))
|
|
break;
|
|
|
|
if (i == l)
|
|
{
|
|
*id = strtoul (arg, 0, 16);
|
|
*valid_id = true;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* This is a bit of hack but it should work on all platforms
|
|
* as it is what the score does with names.
|
|
*
|
|
* @warning The extra assigns play with the byte order so do not
|
|
* remove unless the score has been updated.
|
|
*/
|
|
rtems_name rname;
|
|
|
|
rname = rtems_build_name(arg[0], arg[1], arg[2], arg[3]);
|
|
*name = rname;
|
|
*valid_name = true;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_watch_add
|
|
*
|
|
* This function is a monitor command that add a watch to the capture
|
|
* engine.
|
|
*/
|
|
|
|
static char const * watch_add_usage = "usage: cwadd [task name] [id]\n";
|
|
|
|
static void
|
|
rtems_capture_cli_watch_add (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
int arg;
|
|
rtems_name name = 0;
|
|
rtems_id id = 0;
|
|
bool valid_name = false;
|
|
bool valid_id = false;
|
|
|
|
if (argc <= 1)
|
|
{
|
|
fprintf (stdout, watch_add_usage);
|
|
return;
|
|
}
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
|
|
&name, &id))
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!valid_name && !valid_id)
|
|
{
|
|
fprintf (stdout, "error: no valid name or task id located\n");
|
|
return;
|
|
}
|
|
|
|
sc = rtems_capture_watch_add (name, id);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout,
|
|
"error: watch add failed: %s\n", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "watch added.\n");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_watch_del
|
|
*
|
|
* This function is a monitor command that deletes a watch from the capture
|
|
* engine.
|
|
*/
|
|
|
|
static char const * watch_del_usage = "usage: cwdel [task name] [id]\n";
|
|
|
|
static void
|
|
rtems_capture_cli_watch_del (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
int arg;
|
|
rtems_name name = 0;
|
|
rtems_id id = 0;
|
|
bool valid_name = false;
|
|
bool valid_id = false;
|
|
|
|
if (argc <= 1)
|
|
{
|
|
fprintf (stdout, watch_del_usage);
|
|
return;
|
|
}
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
|
|
&name, &id))
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!valid_name && !valid_id)
|
|
{
|
|
fprintf (stdout, "error: no valid name or task id located\n");
|
|
return;
|
|
}
|
|
|
|
sc = rtems_capture_watch_del (name, id);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: watch delete failed: %s\n",
|
|
rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "watch delete.\n");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_watch_control
|
|
*
|
|
* This function is a monitor command that controls a watch.
|
|
*/
|
|
|
|
static char const * watch_control_usage = "usage: cwctl [task name] [id] on/off\n";
|
|
|
|
static void
|
|
rtems_capture_cli_watch_control (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
int arg;
|
|
rtems_name name = 0;
|
|
rtems_id id = 0;
|
|
bool valid_name = false;
|
|
bool valid_id = false;
|
|
bool enable = false;
|
|
|
|
if (argc <= 2)
|
|
{
|
|
fprintf (stdout, watch_control_usage);
|
|
return;
|
|
}
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
if (strcmp (argv[arg], "on") == 0)
|
|
enable = true;
|
|
else if (strcmp (argv[arg], "off") == 0)
|
|
enable = false;
|
|
else if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name,
|
|
&valid_id, &name, &id))
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!valid_name && !valid_id)
|
|
{
|
|
fprintf (stdout, "error: no valid name or task id located\n");
|
|
return;
|
|
}
|
|
|
|
sc = rtems_capture_watch_ctrl (name, id, enable);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: watch control failed: %s\n",
|
|
rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "watch %s.\n", enable ? "enabled" : "disabled");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_watch_global
|
|
*
|
|
* This function is a monitor command that sets a global watch.
|
|
*/
|
|
|
|
static char const * watch_global_usage = "usage: cwglob on/off\n";
|
|
|
|
static void
|
|
rtems_capture_cli_watch_global (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
int arg;
|
|
bool enable = false;
|
|
|
|
if (argc <= 1)
|
|
{
|
|
fprintf (stdout, watch_global_usage);
|
|
return;
|
|
}
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
if (strcmp (argv[arg], "on") == 0)
|
|
enable = true;
|
|
else if (strcmp (argv[arg], "off") == 0)
|
|
enable = false;
|
|
}
|
|
}
|
|
|
|
sc = rtems_capture_watch_global (enable);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: global watch failed: %s\n",
|
|
rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "global watch %s.\n", enable ? "enabled" : "disabled");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_watch_ceiling
|
|
*
|
|
* This function is a monitor command that sets watch ceiling.
|
|
*/
|
|
|
|
static char const * watch_ceiling_usage = "usage: cwceil priority\n";
|
|
|
|
static void
|
|
rtems_capture_cli_watch_ceiling (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
int arg;
|
|
rtems_task_priority priority = 0;
|
|
|
|
if (argc <= 1)
|
|
{
|
|
fprintf (stdout, watch_ceiling_usage);
|
|
return;
|
|
}
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
priority = strtoul (argv[arg], 0, 0);
|
|
}
|
|
}
|
|
|
|
sc = rtems_capture_watch_ceiling (priority);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: watch ceiling failed: %s\n",
|
|
rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "watch ceiling is %" PRId32 ".\n", priority);
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_watch_floor
|
|
*
|
|
* This function is a monitor command that sets watch floor.
|
|
*/
|
|
|
|
static char const * watch_floor_usage = "usage: cwfloor priority\n";
|
|
|
|
static void
|
|
rtems_capture_cli_watch_floor (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
int arg;
|
|
rtems_task_priority priority = 0;
|
|
|
|
if (argc <= 1)
|
|
{
|
|
fprintf (stdout, watch_floor_usage);
|
|
return;
|
|
}
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
priority = strtoul (argv[arg], 0, 0);
|
|
}
|
|
}
|
|
|
|
sc = rtems_capture_watch_floor (priority);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: watch floor failed: %s\n",
|
|
rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "watch floor is %" PRId32 ".\n", priority);
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_trigger_worker
|
|
*
|
|
* This function is a monitor command that sets or clears a trigger.
|
|
*/
|
|
|
|
static char const *trigger_set_usage =
|
|
"usage: %s [-?] type [to name/id] [from] [from name/id]\n";
|
|
|
|
static char const *trigger_set_types =
|
|
" You can say 'type TASK' or 'type TO from FROM'\n" \
|
|
" where TASK is the task the event is happening to\n" \
|
|
" or you can say the event TO this task FROM this task.\n" \
|
|
" No type defaults to 'switch'.\n" \
|
|
" switch : context switch TASK or FROM or FROM->TO\n" \
|
|
" create : create TASK, or create TO from FROM\n" \
|
|
" start : start TASK, or start TO from FROM\n" \
|
|
" restart : restart TASK, or restart TO from FROM\n" \
|
|
" delete : delete TASK or delete TO from FROM\n" \
|
|
" begin : begin TASK\n" \
|
|
" exitted : exitted TASK\n";
|
|
|
|
/*
|
|
* Structure to handle the parsing of the trigger command line.
|
|
*/
|
|
typedef struct rtems_capture_cli_triggers_s
|
|
{
|
|
char const * name;
|
|
rtems_capture_trigger_t type;
|
|
int to_only;
|
|
} rtems_capture_cli_triggers_t;
|
|
|
|
static rtems_capture_cli_triggers_t rtems_capture_cli_triggers[] =
|
|
{
|
|
{ "switch", rtems_capture_switch, 0 }, /* must be first */
|
|
{ "create", rtems_capture_create, 0 },
|
|
{ "start", rtems_capture_start, 0 },
|
|
{ "restart", rtems_capture_restart, 0 },
|
|
{ "delete", rtems_capture_delete, 0 },
|
|
{ "begin", rtems_capture_begin, 1 },
|
|
{ "exitted", rtems_capture_exitted, 1 }
|
|
};
|
|
|
|
typedef enum rtems_capture_cli_trig_state_e
|
|
{
|
|
trig_type,
|
|
trig_to,
|
|
trig_from_from,
|
|
trig_from
|
|
} rtems_capture_cli_trig_state_t;
|
|
|
|
#define RTEMS_CAPTURE_CLI_TRIGGERS_NUM \
|
|
(sizeof (rtems_capture_cli_triggers) / sizeof (rtems_capture_cli_triggers_t))
|
|
|
|
static void
|
|
rtems_capture_cli_trigger_worker (int set, int argc, char** argv)
|
|
{
|
|
rtems_status_code sc;
|
|
int arg;
|
|
int trigger = 0; /* switch */
|
|
rtems_capture_trigger_mode_t trigger_mode = rtems_capture_from_any;
|
|
bool trigger_set = false;
|
|
bool is_from = false;
|
|
bool is_to = false;
|
|
rtems_name name = 0;
|
|
rtems_id id = 0;
|
|
bool valid_name = false;
|
|
bool valid_id = false;
|
|
rtems_name from_name = 0;
|
|
rtems_id from_id = 0;
|
|
bool from_valid_name = false;
|
|
bool from_valid_id = false;
|
|
rtems_name to_name = 0;
|
|
rtems_id to_id = 0;
|
|
bool to_valid_name = false;
|
|
bool to_valid_id = false;
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
switch (argv[arg][1])
|
|
{
|
|
case '?':
|
|
fprintf (stdout, trigger_set_usage, set ? "ctset" : "ctclear");
|
|
fprintf (stdout, trigger_set_types);
|
|
return;
|
|
default:
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!trigger_set)
|
|
{
|
|
bool found = false;
|
|
int t;
|
|
|
|
for (t = 0; t < RTEMS_CAPTURE_CLI_TRIGGERS_NUM; t++)
|
|
if (strcmp (argv[arg], rtems_capture_cli_triggers[t].name) == 0)
|
|
{
|
|
trigger = t;
|
|
found = true;
|
|
break;
|
|
}
|
|
|
|
trigger_set = true;
|
|
|
|
/*
|
|
* If a trigger was not found assume the default and
|
|
* assume the parameter is a task name or id.
|
|
*/
|
|
if (found)
|
|
continue;
|
|
}
|
|
|
|
if (strcmp (arg[argv], "from") == 0)
|
|
{
|
|
if (from_valid_name || from_valid_id)
|
|
fprintf (stdout, "warning: extra 'from' ignored\n");
|
|
|
|
is_from = true;
|
|
continue;
|
|
}
|
|
|
|
if (strcmp (arg[argv], "to") == 0)
|
|
{
|
|
if (to_valid_name || from_valid_id)
|
|
fprintf (stdout, "warning: extra 'to' ignored\n");
|
|
|
|
is_to = true;
|
|
continue;
|
|
}
|
|
|
|
if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
|
|
&name, &id))
|
|
return;
|
|
|
|
if (valid_name)
|
|
{
|
|
if (!is_from && !is_to)
|
|
is_to = true;
|
|
|
|
if (is_from)
|
|
{
|
|
if (!from_valid_name && !from_valid_id)
|
|
{
|
|
from_valid_name = true;
|
|
from_name = name;
|
|
}
|
|
else
|
|
fprintf (stdout, "warning: extra name arguments ignored\n");
|
|
}
|
|
else if (!to_valid_name && !to_valid_id)
|
|
{
|
|
to_valid_name = true;
|
|
to_name = name;
|
|
}
|
|
else
|
|
fprintf (stdout, "warning: extra name arguments ignored\n");
|
|
}
|
|
|
|
if (valid_id)
|
|
{
|
|
if (!is_from && !is_to)
|
|
is_to = true;
|
|
|
|
if (is_from)
|
|
{
|
|
if (!from_valid_name && !from_valid_id)
|
|
{
|
|
from_valid_id = true;
|
|
from_id = id;
|
|
}
|
|
else
|
|
fprintf (stdout, "warning: extra id arguments ignored\n");
|
|
}
|
|
else if (!to_valid_name && !to_valid_id)
|
|
{
|
|
to_valid_id = true;
|
|
to_id = id;
|
|
}
|
|
else
|
|
fprintf (stdout, "warning: extra id arguments ignored\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_from && rtems_capture_cli_triggers[trigger].to_only)
|
|
{
|
|
fprintf (stdout, "error: a %s trigger can be a TO trigger\n",
|
|
rtems_capture_cli_triggers[trigger].name);
|
|
return;
|
|
}
|
|
|
|
if (!to_valid_name && !to_valid_id && !from_valid_name && !from_valid_id)
|
|
{
|
|
fprintf (stdout, trigger_set_usage, set ? "ctset" : "ctclear");
|
|
return;
|
|
}
|
|
|
|
if (!is_from && !to_valid_name && !to_valid_id)
|
|
{
|
|
fprintf (stdout, "error: a %s trigger needs a TO name or id\n",
|
|
rtems_capture_cli_triggers[trigger].name);
|
|
return;
|
|
}
|
|
|
|
if (is_from && !from_valid_name && !from_valid_id)
|
|
{
|
|
fprintf (stdout, "error: a %s trigger needs a FROM name or id\n",
|
|
rtems_capture_cli_triggers[trigger].name);
|
|
return;
|
|
}
|
|
|
|
if ((from_valid_name || from_valid_id) && (to_valid_name || to_valid_id))
|
|
trigger_mode = rtems_capture_from_to;
|
|
else if (from_valid_name || from_valid_id)
|
|
trigger_mode = rtems_capture_to_any;
|
|
else if (to_valid_name || to_valid_id)
|
|
trigger_mode = rtems_capture_from_any;
|
|
|
|
if (set)
|
|
sc = rtems_capture_set_trigger (from_name, from_id, to_name, to_id,
|
|
trigger_mode,
|
|
rtems_capture_cli_triggers[trigger].type);
|
|
else
|
|
sc = rtems_capture_clear_trigger (from_name, from_id, to_name, to_id,
|
|
trigger_mode,
|
|
rtems_capture_cli_triggers[trigger].type);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: %sing the trigger failed: %s\n",
|
|
set ? "sett" : "clear", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "trigger %s.\n", set ? "set" : "cleared");
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_trigger_set
|
|
*
|
|
* This function is a monitor command that sets a trigger.
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_trigger_set (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_capture_cli_trigger_worker (1, argc, argv);
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_trigger_clear
|
|
*
|
|
* This function is a monitor command that clears a trigger.
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_trigger_clear (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_capture_cli_trigger_worker (0, argc, argv);
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_trace_records
|
|
*
|
|
* This function is a monitor command that dumps trace records.
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_trace_records (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
bool csv = false;
|
|
static int dump_total = 22;
|
|
int arg;
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
if (argv[arg][1] == 'c')
|
|
csv = true;
|
|
else
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
else
|
|
{
|
|
size_t i;
|
|
size_t l;
|
|
|
|
l = strlen (argv[arg]);
|
|
|
|
for (i = 0; i < l; i++)
|
|
if (!isdigit ((unsigned char)argv[arg][i]))
|
|
{
|
|
fprintf (stdout, "error: not a number\n");
|
|
return;
|
|
}
|
|
|
|
dump_total = strtoul (argv[arg], 0, 0);
|
|
}
|
|
}
|
|
|
|
rtems_capture_print_trace_records( dump_total, csv );
|
|
}
|
|
|
|
/*
|
|
* rtems_capture_cli_flush
|
|
*
|
|
* This function is a monitor command that flushes and primes the capture
|
|
* engine.
|
|
*/
|
|
|
|
static void
|
|
rtems_capture_cli_flush (int argc,
|
|
char** argv,
|
|
const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
|
|
bool verbose RC_UNUSED)
|
|
{
|
|
rtems_status_code sc;
|
|
bool prime = true;
|
|
int arg;
|
|
|
|
for (arg = 1; arg < argc; arg++)
|
|
{
|
|
if (argv[arg][0] == '-')
|
|
{
|
|
if (argv[arg][1] == 'n')
|
|
prime = false;
|
|
else
|
|
fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
|
|
}
|
|
}
|
|
|
|
sc = rtems_capture_flush (prime);
|
|
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
fprintf (stdout, "error: flush failed: %s\n", rtems_status_text (sc));
|
|
return;
|
|
}
|
|
|
|
fprintf (stdout, "trace buffer flushed and %s.\n",
|
|
prime ? "primed" : "not primed");
|
|
}
|
|
|
|
static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
|
|
{
|
|
{
|
|
"copen",
|
|
"usage: copen [-i] size\n",
|
|
0,
|
|
rtems_capture_cli_open,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cclose",
|
|
"usage: cclose\n",
|
|
0,
|
|
rtems_capture_cli_close,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cenable",
|
|
"usage: cenable\n",
|
|
0,
|
|
rtems_capture_cli_enable,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cdisable",
|
|
"usage: cdisable\n",
|
|
0,
|
|
rtems_capture_cli_disable,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"ctlist",
|
|
"usage: ctlist \n",
|
|
0,
|
|
rtems_capture_cli_task_list,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cwlist",
|
|
"usage: cwlist\n",
|
|
0,
|
|
rtems_capture_cli_watch_list,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cwadd",
|
|
"usage: cwadd [task name] [id]\n",
|
|
0,
|
|
rtems_capture_cli_watch_add,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cwdel",
|
|
"usage: cwdel [task name] [id]\n",
|
|
0,
|
|
rtems_capture_cli_watch_del,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cwctl",
|
|
"usage: cwctl [task name] [id] on/off\n",
|
|
0,
|
|
rtems_capture_cli_watch_control,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cwglob",
|
|
"usage: cwglob on/off\n",
|
|
0,
|
|
rtems_capture_cli_watch_global,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cwceil",
|
|
"usage: cwceil priority\n",
|
|
0,
|
|
rtems_capture_cli_watch_ceiling,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cwfloor",
|
|
"usage: cwfloor priority\n",
|
|
0,
|
|
rtems_capture_cli_watch_floor,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"ctrace",
|
|
"usage: ctrace [-c] [-r records]\n",
|
|
0,
|
|
rtems_capture_cli_trace_records,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"ctset",
|
|
"usage: ctset -h\n",
|
|
0,
|
|
rtems_capture_cli_trigger_set,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"ctclear",
|
|
"usage: ctclear -?\n",
|
|
0,
|
|
rtems_capture_cli_trigger_clear,
|
|
{ 0 },
|
|
0
|
|
},
|
|
{
|
|
"cflush",
|
|
"usage: cflush [-n]\n",
|
|
0,
|
|
rtems_capture_cli_flush,
|
|
{ 0 },
|
|
0
|
|
}
|
|
};
|
|
|
|
/*
|
|
* rtems_capture_cli_init
|
|
*
|
|
* This function initialises the command line interface to the capture
|
|
* engine.
|
|
*/
|
|
|
|
rtems_status_code
|
|
rtems_capture_cli_init (rtems_capture_timestamp timestamp)
|
|
{
|
|
size_t cmd;
|
|
|
|
capture_timestamp = timestamp;
|
|
|
|
for (cmd = 0;
|
|
cmd < sizeof (rtems_capture_cli_cmds) / sizeof (rtems_monitor_command_entry_t);
|
|
cmd++)
|
|
rtems_monitor_insert_cmd (&rtems_capture_cli_cmds[cmd]);
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|