Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:18

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @brief RTEMS Performance Monitoring and Measurement Framework.
0007  *
0008  * This is the Target Interface Command Line Interface. You need
0009  * start the RTEMS monitor.
0010  */
0011 
0012 /*
0013  * Copyright 2002, 2015 Chris Johns <chrisj@rtems.org>.
0014  * All rights reserved.
0015  *
0016  * COPYRIGHT (c) 2014.
0017  * On-Line Applications Research Corporation (OAR).
0018  *
0019  * Redistribution and use in source and binary forms, with or without
0020  * modification, are permitted provided that the following conditions
0021  * are met:
0022  * 1. Redistributions of source code must retain the above copyright
0023  *    notice, this list of conditions and the following disclaimer.
0024  * 2. Redistributions in binary form must reproduce the above copyright
0025  *    notice, this list of conditions and the following disclaimer in the
0026  *    documentation and/or other materials provided with the distribution.
0027  *
0028  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0029  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0030  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0031  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0032  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0033  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0034  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0035  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0036  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0037  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0038  * POSSIBILITY OF SUCH DAMAGE.
0039  */
0040 
0041 #ifdef HAVE_CONFIG_H
0042 #include "config.h"
0043 #endif
0044 
0045 #include <ctype.h>
0046 #include <stdlib.h>
0047 #include <stdio.h>
0048 #include <string.h>
0049 #include <inttypes.h>
0050 
0051 #include <rtems.h>
0052 #include <rtems/capture-cli.h>
0053 #include <rtems/captureimpl.h>
0054 #include <rtems/monitor.h>
0055 #include <rtems/cpuuse.h>
0056 #
0057 #define RC_UNUSED RTEMS_UNUSED
0058 
0059 #define RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS (20)
0060 
0061 /*
0062  * The user capture timestamper.
0063  */
0064 static rtems_capture_timestamp capture_timestamp;
0065 
0066 /*
0067  * rtems_capture_cli_open
0068  *
0069  * This function opens the capture engine. We need the size of the
0070  * capture buffer.
0071  */
0072 
0073 static const char* open_usage = "usage: copen [-i] size\n";
0074 
0075 static void
0076 rtems_capture_cli_open (int                                argc,
0077                         char**                             argv,
0078                         const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0079                         bool                               verbose RC_UNUSED)
0080 {
0081   uint32_t          size = 0;
0082   bool              enable = false;
0083   rtems_status_code sc;
0084   int               arg;
0085 
0086   if (argc <= 1)
0087   {
0088     fprintf (stdout, open_usage);
0089     return;
0090   }
0091 
0092   for (arg = 1; arg < argc; arg++)
0093   {
0094     if (argv[arg][0] == '-')
0095     {
0096       if (argv[arg][1] == 'i')
0097         enable = true;
0098       else
0099         fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
0100     }
0101     else
0102     {
0103       size = strtoul (argv[arg], 0, 0);
0104 
0105       if (size < 100)
0106       {
0107         fprintf (stdout, "error: size must be greater than or equal to 100\n");
0108         return;
0109       }
0110     }
0111   }
0112 
0113   sc = rtems_capture_open (size, capture_timestamp);
0114 
0115   if (sc != RTEMS_SUCCESSFUL)
0116   {
0117     fprintf (stdout, "error: open failed: %s\n", rtems_status_text (sc));
0118     return;
0119   }
0120 
0121   fprintf (stdout, "capture engine opened.\n");
0122 
0123   if (!enable)
0124     return;
0125 
0126   sc = rtems_capture_set_control (enable);
0127 
0128   if (sc != RTEMS_SUCCESSFUL)
0129   {
0130     fprintf (stdout, "error: open enable failed: %s\n", rtems_status_text (sc));
0131     return;
0132   }
0133 
0134   fprintf (stdout, "capture engine enabled.\n");
0135 }
0136 
0137 /*
0138  * rtems_capture_cli_close
0139  *
0140  * This function closes the capture engine.
0141  */
0142 
0143 static void
0144 rtems_capture_cli_close (int                                argc RC_UNUSED,
0145                          char**                             argv RC_UNUSED,
0146                          const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0147                          bool                               verbose RC_UNUSED)
0148 {
0149   rtems_status_code sc;
0150 
0151   sc = rtems_capture_close ();
0152 
0153   if (sc != RTEMS_SUCCESSFUL)
0154   {
0155     fprintf (stdout, "error: close failed: %s\n", rtems_status_text (sc));
0156     return;
0157   }
0158 
0159   fprintf (stdout, "capture engine closed.\n");
0160 }
0161 
0162 /*
0163  * rtems_capture_cli_enable
0164  *
0165  * This function enables the capture engine.
0166  */
0167 
0168 static void
0169 rtems_capture_cli_enable (int                                argc RC_UNUSED,
0170                           char**                             argv RC_UNUSED,
0171                           const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0172                           bool                               verbose RC_UNUSED)
0173 {
0174   rtems_status_code sc;
0175 
0176   sc = rtems_capture_set_control (true);
0177 
0178   if (sc != RTEMS_SUCCESSFUL)
0179   {
0180     fprintf (stdout, "error: enable failed: %s\n", rtems_status_text (sc));
0181     return;
0182   }
0183 
0184   fprintf (stdout, "capture engine enabled.\n");
0185 }
0186 
0187 /*
0188  * rtems_capture_cli_disable
0189  *
0190  * This function disables the capture engine.
0191  */
0192 
0193 static void
0194 rtems_capture_cli_disable (int                                argc RC_UNUSED,
0195                            char**                             argv RC_UNUSED,
0196                            const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0197                            bool                               verbose RC_UNUSED)
0198 {
0199   rtems_status_code sc;
0200 
0201   sc = rtems_capture_set_control (false);
0202 
0203   if (sc != RTEMS_SUCCESSFUL)
0204   {
0205     fprintf (stdout, "error: disable failed: %s\n", rtems_status_text (sc));
0206     return;
0207   }
0208 
0209   fprintf (stdout, "capture engine disabled.\n");
0210 }
0211 
0212 static bool
0213 rtems_capture_cli_print_task (rtems_tcb *tcb, void *arg)
0214 {
0215   rtems_task_priority   ceiling = rtems_capture_watch_get_ceiling ();
0216   rtems_task_priority   floor = rtems_capture_watch_get_floor ();
0217   rtems_task_priority   priority;
0218   int                   length;
0219   uint32_t              flags = rtems_capture_task_control_flags (tcb);
0220 
0221   priority = rtems_capture_task_real_priority (tcb);
0222 
0223   fprintf (stdout, " ");
0224   rtems_monitor_dump_id (rtems_capture_task_id (tcb));
0225   fprintf (stdout, " ");
0226   if (rtems_capture_task_api (rtems_capture_task_id (tcb)) != OBJECTS_POSIX_API)
0227   {
0228     rtems_monitor_dump_name (rtems_capture_task_id (tcb));
0229     fprintf (stdout, " ");
0230   }
0231   else
0232   {
0233     fprintf (stdout, "     ");
0234   }
0235   rtems_monitor_dump_priority (rtems_capture_task_start_priority (tcb));
0236   fprintf (stdout, " ");
0237   rtems_monitor_dump_priority (rtems_capture_task_real_priority (tcb));
0238   fprintf (stdout, " ");
0239   rtems_monitor_dump_priority (rtems_capture_task_curr_priority (tcb));
0240   fprintf (stdout, " ");
0241   length = rtems_monitor_dump_state (rtems_capture_task_state (tcb));
0242   fprintf (stdout, "%*c", 14 - length, ' ');
0243   fprintf (stdout, " %c%c",
0244            'a',
0245            flags & RTEMS_CAPTURE_TRACED ? 't' : '-');
0246 
0247   if ((floor > ceiling) && (ceiling > priority))
0248     fprintf (stdout, "--");
0249   else
0250   {
0251     fprintf (stdout, "%c%c",
0252              rtems_capture_task_control (tcb) ?
0253              (flags & RTEMS_CAPTURE_WATCH ? 'w' : '+') : '-',
0254              rtems_capture_watch_global_on () ? 'g' : '-');
0255   }
0256   fprintf (stdout, "\n");
0257   return false;
0258 }
0259 
0260 /*
0261  * rtems_capture_cli_count_tasks
0262  *
0263  * This function is called for each tcb and counts the
0264  * number of tasks.
0265  */
0266 
0267 static bool
0268 rtems_capture_cli_count_tasks (rtems_tcb *tcb, void *arg)
0269 {
0270   uint32_t *task_count = arg;
0271   ++(*task_count);
0272   return false;
0273 }
0274 
0275 
0276 /*
0277  * rtems_capture_cli_task_list
0278  *
0279  * This function lists the tasks the capture engine knows about.
0280  */
0281 
0282 static void
0283 rtems_capture_cli_task_list (int                                argc RC_UNUSED,
0284                              char**                             argv RC_UNUSED,
0285                              const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0286                              bool                               verbose RC_UNUSED)
0287 {
0288   rtems_capture_time uptime;
0289   uint32_t           task_count;
0290 
0291   rtems_capture_get_time (&uptime);
0292 
0293   task_count = 0;
0294   rtems_task_iterate (rtems_capture_cli_count_tasks, &task_count);
0295 
0296   fprintf (stdout, "uptime: ");
0297   rtems_capture_print_timestamp (uptime);
0298   fprintf (stdout, "\ntotal %" PRIu32 "\n", task_count);
0299   rtems_task_iterate (rtems_capture_cli_print_task, NULL);
0300 }
0301 
0302 /*
0303  * rtems_capture_cli_watch_list
0304  *
0305  * This function lists the controls in the capture engine.
0306  */
0307 
0308 static void
0309 rtems_capture_cli_watch_list (int                                argc RC_UNUSED,
0310                               char**                             argv RC_UNUSED,
0311                               const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0312                               bool                               verbose RC_UNUSED)
0313 {
0314   rtems_capture_print_watch_list();
0315 }
0316 
0317 /*
0318  * rtems_capture_cli_get_name_id
0319  *
0320  * This function checks arguments for a name or an id.
0321  */
0322 
0323 static bool
0324 rtems_capture_cli_get_name_id (char*       arg,
0325                                bool*       valid_name,
0326                                bool*       valid_id,
0327                                rtems_name* name,
0328                                rtems_id*   id)
0329 {
0330   size_t l;
0331   size_t i;
0332 
0333   if (*valid_name && *valid_id)
0334   {
0335     fprintf (stdout, "error: too many arguments\n");
0336     return 0;
0337   }
0338 
0339   /*
0340    * See if the arg is all hex digits.
0341    */
0342 
0343   l = strlen (arg);
0344 
0345   for (i = 0; i < l; i++)
0346     if (!isxdigit ((unsigned char)arg[i]))
0347       break;
0348 
0349   if (i == l)
0350   {
0351     *id = strtoul (arg, 0, 16);
0352     *valid_id = true;
0353   }
0354   else
0355   {
0356     /*
0357      * This is a bit of hack but it should work on all platforms
0358      * as it is what the score does with names.
0359      *
0360      * @warning The extra assigns play with the byte order so do not
0361      *          remove unless the score has been updated.
0362      */
0363     rtems_name   rname;
0364 
0365     rname = rtems_build_name(arg[0], arg[1], arg[2], arg[3]);
0366     *name = rname;
0367     *valid_name = true;
0368   }
0369 
0370   return 1;
0371 }
0372 
0373 /*
0374  * rtems_capture_cli_watch_add
0375  *
0376  * This function is a monitor command that add a watch to the capture
0377  * engine.
0378  */
0379 
0380 static char const * watch_add_usage = "usage: cwadd [task name] [id]\n";
0381 
0382 static void
0383 rtems_capture_cli_watch_add (int                                argc,
0384                              char**                             argv,
0385                              const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0386                              bool                               verbose RC_UNUSED)
0387 {
0388   rtems_status_code sc;
0389   int               arg;
0390   rtems_name        name = 0;
0391   rtems_id          id = 0;
0392   bool              valid_name = false;
0393   bool              valid_id = false;
0394 
0395   if (argc <= 1)
0396   {
0397     fprintf (stdout, watch_add_usage);
0398     return;
0399   }
0400 
0401   for (arg = 1; arg < argc; arg++)
0402   {
0403     if (argv[arg][0] == '-')
0404     {
0405       fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
0406     }
0407     else
0408     {
0409       if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
0410                                           &name, &id))
0411         return;
0412     }
0413   }
0414 
0415   if (!valid_name && !valid_id)
0416   {
0417     fprintf (stdout, "error: no valid name or task id located\n");
0418     return;
0419   }
0420 
0421   sc = rtems_capture_watch_add (name, id);
0422 
0423   if (sc != RTEMS_SUCCESSFUL)
0424   {
0425     fprintf (stdout,
0426              "error: watch add failed: %s\n", rtems_status_text (sc));
0427     return;
0428   }
0429 
0430   fprintf (stdout, "watch added.\n");
0431 }
0432 
0433 /*
0434  * rtems_capture_cli_watch_del
0435  *
0436  * This function is a monitor command that deletes a watch from the capture
0437  * engine.
0438  */
0439 
0440 static char const * watch_del_usage = "usage: cwdel [task name] [id]\n";
0441 
0442 static void
0443 rtems_capture_cli_watch_del (int                                argc,
0444                              char**                             argv,
0445                              const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0446                              bool                               verbose RC_UNUSED)
0447 {
0448   rtems_status_code sc;
0449   int               arg;
0450   rtems_name        name = 0;
0451   rtems_id          id = 0;
0452   bool              valid_name = false;
0453   bool              valid_id = false;
0454 
0455   if (argc <= 1)
0456   {
0457     fprintf (stdout, watch_del_usage);
0458     return;
0459   }
0460 
0461   for (arg = 1; arg < argc; arg++)
0462   {
0463     if (argv[arg][0] == '-')
0464     {
0465       fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
0466     }
0467     else
0468     {
0469       if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
0470                                           &name, &id))
0471         return;
0472     }
0473   }
0474 
0475   if (!valid_name && !valid_id)
0476   {
0477     fprintf (stdout, "error: no valid name or task id located\n");
0478     return;
0479   }
0480 
0481   sc = rtems_capture_watch_del (name, id);
0482 
0483   if (sc != RTEMS_SUCCESSFUL)
0484   {
0485     fprintf (stdout, "error: watch delete failed: %s\n",
0486              rtems_status_text (sc));
0487     return;
0488   }
0489 
0490   fprintf (stdout, "watch delete.\n");
0491 }
0492 
0493 /*
0494  * rtems_capture_cli_watch_control
0495  *
0496  * This function is a monitor command that controls a watch.
0497  */
0498 
0499 static char const * watch_control_usage = "usage: cwctl [task name] [id] on/off\n";
0500 
0501 static void
0502 rtems_capture_cli_watch_control (int                                argc,
0503                                  char**                             argv,
0504                                  const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0505                                  bool                               verbose RC_UNUSED)
0506 {
0507   rtems_status_code sc;
0508   int               arg;
0509   rtems_name        name = 0;
0510   rtems_id          id = 0;
0511   bool              valid_name = false;
0512   bool              valid_id = false;
0513   bool              enable = false;
0514 
0515   if (argc <= 2)
0516   {
0517     fprintf (stdout, watch_control_usage);
0518     return;
0519   }
0520 
0521   for (arg = 1; arg < argc; arg++)
0522   {
0523     if (argv[arg][0] == '-')
0524     {
0525       fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
0526     }
0527     else
0528     {
0529       if (strcmp (argv[arg], "on") == 0)
0530         enable = true;
0531       else if (strcmp (argv[arg], "off") == 0)
0532         enable = false;
0533       else if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name,
0534                                                &valid_id, &name, &id))
0535         return;
0536     }
0537   }
0538 
0539   if (!valid_name && !valid_id)
0540   {
0541     fprintf (stdout, "error: no valid name or task id located\n");
0542     return;
0543   }
0544 
0545   sc = rtems_capture_watch_ctrl (name, id, enable);
0546 
0547   if (sc != RTEMS_SUCCESSFUL)
0548   {
0549     fprintf (stdout, "error: watch control failed: %s\n",
0550              rtems_status_text (sc));
0551     return;
0552   }
0553 
0554   fprintf (stdout, "watch %s.\n", enable ? "enabled" : "disabled");
0555 }
0556 
0557 /*
0558  * rtems_capture_cli_watch_global
0559  *
0560  * This function is a monitor command that sets a global watch.
0561  */
0562 
0563 static char const * watch_global_usage = "usage: cwglob on/off\n";
0564 
0565 static void
0566 rtems_capture_cli_watch_global (int                                argc,
0567                                 char**                             argv,
0568                                 const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0569                                 bool                               verbose RC_UNUSED)
0570 {
0571   rtems_status_code sc;
0572   int               arg;
0573   bool              enable = false;
0574 
0575   if (argc <= 1)
0576   {
0577     fprintf (stdout, watch_global_usage);
0578     return;
0579   }
0580 
0581   for (arg = 1; arg < argc; arg++)
0582   {
0583     if (argv[arg][0] == '-')
0584     {
0585       fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
0586     }
0587     else
0588     {
0589       if (strcmp (argv[arg], "on") == 0)
0590         enable = true;
0591       else if (strcmp (argv[arg], "off") == 0)
0592         enable = false;
0593     }
0594   }
0595 
0596   sc = rtems_capture_watch_global (enable);
0597 
0598   if (sc != RTEMS_SUCCESSFUL)
0599   {
0600     fprintf (stdout, "error: global watch failed: %s\n",
0601              rtems_status_text (sc));
0602     return;
0603   }
0604 
0605   fprintf (stdout, "global watch %s.\n", enable ? "enabled" : "disabled");
0606 }
0607 
0608 /*
0609  * rtems_capture_cli_watch_ceiling
0610  *
0611  * This function is a monitor command that sets watch ceiling.
0612  */
0613 
0614 static char const * watch_ceiling_usage = "usage: cwceil priority\n";
0615 
0616 static void
0617 rtems_capture_cli_watch_ceiling (int                                argc,
0618                                  char**                             argv,
0619                                  const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0620                                  bool                               verbose RC_UNUSED)
0621 {
0622   rtems_status_code   sc;
0623   int                 arg;
0624   rtems_task_priority priority = 0;
0625 
0626   if (argc <= 1)
0627   {
0628     fprintf (stdout, watch_ceiling_usage);
0629     return;
0630   }
0631 
0632   for (arg = 1; arg < argc; arg++)
0633   {
0634     if (argv[arg][0] == '-')
0635     {
0636       fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
0637     }
0638     else
0639     {
0640       priority = strtoul (argv[arg], 0, 0);
0641     }
0642   }
0643 
0644   sc = rtems_capture_watch_ceiling (priority);
0645 
0646   if (sc != RTEMS_SUCCESSFUL)
0647   {
0648     fprintf (stdout, "error: watch ceiling failed: %s\n",
0649              rtems_status_text (sc));
0650     return;
0651   }
0652 
0653   fprintf (stdout, "watch ceiling is %" PRId32 ".\n", priority);
0654 }
0655 
0656 /*
0657  * rtems_capture_cli_watch_floor
0658  *
0659  * This function is a monitor command that sets watch floor.
0660  */
0661 
0662 static char const * watch_floor_usage = "usage: cwfloor priority\n";
0663 
0664 static void
0665 rtems_capture_cli_watch_floor (int                                argc,
0666                                char**                             argv,
0667                                const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0668                                bool                               verbose RC_UNUSED)
0669 {
0670   rtems_status_code   sc;
0671   int                 arg;
0672   rtems_task_priority priority = 0;
0673 
0674   if (argc <= 1)
0675   {
0676     fprintf (stdout, watch_floor_usage);
0677     return;
0678   }
0679 
0680   for (arg = 1; arg < argc; arg++)
0681   {
0682     if (argv[arg][0] == '-')
0683     {
0684       fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
0685     }
0686     else
0687     {
0688       priority = strtoul (argv[arg], 0, 0);
0689     }
0690   }
0691 
0692   sc = rtems_capture_watch_floor (priority);
0693 
0694   if (sc != RTEMS_SUCCESSFUL)
0695   {
0696     fprintf (stdout, "error: watch floor failed: %s\n",
0697              rtems_status_text (sc));
0698     return;
0699   }
0700 
0701   fprintf (stdout, "watch floor is %" PRId32 ".\n", priority);
0702 }
0703 
0704 /*
0705  * rtems_capture_cli_trigger_worker
0706  *
0707  * This function is a monitor command that sets or clears a trigger.
0708  */
0709 
0710 static char const *trigger_set_usage =
0711       "usage: %s [-?] type [to name/id] [from] [from name/id]\n";
0712 
0713 static char const *trigger_set_types =
0714       "  You can say 'type TASK' or 'type TO from FROM'\n" \
0715       "  where TASK is the task the event is happening to\n" \
0716       "  or you can say the event TO this task FROM this task.\n" \
0717       "  No type defaults to 'switch'.\n" \
0718       "   switch  : context switch TASK or FROM or FROM->TO\n" \
0719       "   create  : create TASK, or create TO from FROM\n" \
0720       "   start   : start TASK, or start TO from FROM\n" \
0721       "   restart : restart TASK, or restart TO from FROM\n" \
0722       "   delete  : delete TASK or delete TO from FROM\n" \
0723       "   begin   : begin TASK\n" \
0724       "   exitted : exitted TASK\n";
0725 
0726 /*
0727  * Structure to handle the parsing of the trigger command line.
0728  */
0729 typedef struct rtems_capture_cli_triggers
0730 {
0731   char const *          name;
0732   rtems_capture_trigger type;
0733   int                   to_only;
0734 } rtems_capture_cli_triggers;
0735 
0736 static const rtems_capture_cli_triggers rtems_capture_cli_trigger[] =
0737 {
0738   { "switch",  rtems_capture_switch,  0 }, /* must be first */
0739   { "create",  rtems_capture_create,  0 },
0740   { "start",   rtems_capture_start,   0 },
0741   { "restart", rtems_capture_restart, 0 },
0742   { "delete",  rtems_capture_delete,  0 },
0743   { "begin",   rtems_capture_begin,   1 },
0744   { "exitted", rtems_capture_exitted, 1 }
0745 };
0746 
0747 typedef enum rtems_capture_cli_trig_state
0748 {
0749   trig_type,
0750   trig_to,
0751   trig_from_from,
0752   trig_from
0753 } rtems_capture_cli_trig_state;
0754 
0755 #define RTEMS_CAPTURE_CLI_TRIGGERS_NUM \
0756   (sizeof (rtems_capture_cli_trigger) / sizeof (rtems_capture_cli_triggers))
0757 
0758 static void
0759 rtems_capture_cli_trigger_worker (int set, int argc, char** argv)
0760 {
0761   rtems_status_code          sc;
0762   int                        arg;
0763   int                        trigger = 0; /* switch */
0764   rtems_capture_trigger_mode trigger_mode = rtems_capture_from_any;
0765   bool                       trigger_set = false;
0766   bool                       is_from = false;
0767   bool                       is_to = false;
0768   rtems_name                 name = 0;
0769   rtems_id                   id = 0;
0770   bool                       valid_name = false;
0771   bool                       valid_id = false;
0772   rtems_name                 from_name = 0;
0773   rtems_id                   from_id = 0;
0774   bool                       from_valid_name = false;
0775   bool                       from_valid_id = false;
0776   rtems_name                 to_name = 0;
0777   rtems_id                   to_id = 0;
0778   bool                       to_valid_name = false;
0779   bool                       to_valid_id = false;
0780 
0781   for (arg = 1; arg < argc; arg++)
0782   {
0783     if (argv[arg][0] == '-')
0784     {
0785       switch (argv[arg][1])
0786       {
0787         case '?':
0788           fprintf (stdout, trigger_set_usage, set ? "ctset" : "ctclear");
0789           fprintf (stdout, trigger_set_types);
0790           return;
0791         default:
0792           fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
0793           break;
0794       }
0795     }
0796     else
0797     {
0798       if (!trigger_set)
0799       {
0800         bool found = false;
0801         int  t;
0802 
0803         for (t = 0; t < RTEMS_CAPTURE_CLI_TRIGGERS_NUM; t++)
0804           if (strcmp (argv[arg], rtems_capture_cli_trigger[t].name) == 0)
0805           {
0806             trigger = t;
0807             found = true;
0808             break;
0809           }
0810 
0811         trigger_set = true;
0812 
0813         /*
0814          * If a trigger was not found assume the default and
0815          * assume the parameter is a task name or id.
0816          */
0817         if (found)
0818           continue;
0819       }
0820 
0821       if (strcmp (argv[arg], "from") == 0)
0822       {
0823         if (from_valid_name || from_valid_id)
0824           fprintf (stdout, "warning: extra 'from' ignored\n");
0825 
0826         is_from = true;
0827         continue;
0828       }
0829 
0830       if (strcmp (argv[arg], "to") == 0)
0831       {
0832         if (to_valid_name || from_valid_id)
0833           fprintf (stdout, "warning: extra 'to' ignored\n");
0834 
0835         is_to = true;
0836         continue;
0837       }
0838 
0839       if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
0840                                           &name, &id))
0841         return;
0842 
0843       if (valid_name)
0844       {
0845         if (!is_from && !is_to)
0846           is_to = true;
0847 
0848         if (is_from)
0849         {
0850           if (!from_valid_name && !from_valid_id)
0851           {
0852             from_valid_name = true;
0853             from_name       = name;
0854           }
0855           else
0856             fprintf (stdout, "warning: extra name arguments ignored\n");
0857         }
0858         else if (!to_valid_name && !to_valid_id)
0859         {
0860           to_valid_name = true;
0861           to_name       = name;
0862         }
0863         else
0864           fprintf (stdout, "warning: extra name arguments ignored\n");
0865       }
0866 
0867       if (valid_id)
0868       {
0869         if (!is_from && !is_to)
0870           is_to = true;
0871 
0872         if (is_from)
0873         {
0874           if (!from_valid_name && !from_valid_id)
0875           {
0876             from_valid_id = true;
0877             from_id       = id;
0878           }
0879           else
0880             fprintf (stdout, "warning: extra id arguments ignored\n");
0881         }
0882         else if (!to_valid_name && !to_valid_id)
0883         {
0884           to_valid_id = true;
0885           to_id       = id;
0886         }
0887         else
0888           fprintf (stdout, "warning: extra id arguments ignored\n");
0889       }
0890     }
0891   }
0892 
0893   if (is_from && rtems_capture_cli_trigger[trigger].to_only)
0894   {
0895     fprintf (stdout, "error: a %s trigger can be a TO trigger\n",
0896              rtems_capture_cli_trigger[trigger].name);
0897     return;
0898   }
0899 
0900   if (!to_valid_name && !to_valid_id && !from_valid_name && !from_valid_id)
0901   {
0902     fprintf (stdout, trigger_set_usage, set ? "ctset" : "ctclear");
0903     return;
0904   }
0905 
0906   if (!is_from && !to_valid_name && !to_valid_id)
0907   {
0908     fprintf (stdout, "error: a %s trigger needs a TO name or id\n",
0909              rtems_capture_cli_trigger[trigger].name);
0910     return;
0911   }
0912 
0913   if (is_from && !from_valid_name && !from_valid_id)
0914   {
0915     fprintf (stdout, "error: a %s trigger needs a FROM name or id\n",
0916              rtems_capture_cli_trigger[trigger].name);
0917     return;
0918   }
0919 
0920   if ((from_valid_name || from_valid_id) && (to_valid_name || to_valid_id))
0921     trigger_mode = rtems_capture_from_to;
0922   else if (from_valid_name || from_valid_id)
0923     trigger_mode = rtems_capture_to_any;
0924   else if (to_valid_name || to_valid_id)
0925     trigger_mode = rtems_capture_from_any;
0926 
0927   if (set)
0928     sc = rtems_capture_set_trigger (from_name, from_id, to_name, to_id,
0929                                     trigger_mode,
0930                                     rtems_capture_cli_trigger[trigger].type);
0931   else
0932     sc = rtems_capture_clear_trigger (from_name, from_id, to_name, to_id,
0933                                       trigger_mode,
0934                                       rtems_capture_cli_trigger[trigger].type);
0935 
0936   if (sc != RTEMS_SUCCESSFUL)
0937   {
0938     fprintf (stdout, "error: %sing the trigger failed: %s\n",
0939              set ? "sett" : "clear", rtems_status_text (sc));
0940     return;
0941   }
0942 
0943   fprintf (stdout, "trigger %s.\n", set ? "set" : "cleared");
0944 }
0945 
0946 /*
0947  * rtems_capture_cli_trigger_set
0948  *
0949  * This function is a monitor command that sets a trigger.
0950  */
0951 
0952 static void
0953 rtems_capture_cli_trigger_set (int                                argc,
0954                                char**                             argv,
0955                                const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0956                                bool                               verbose RC_UNUSED)
0957 {
0958   rtems_capture_cli_trigger_worker (1, argc, argv);
0959 }
0960 
0961 /*
0962  * rtems_capture_cli_trigger_clear
0963  *
0964  * This function is a monitor command that clears a trigger.
0965  */
0966 
0967 static void
0968 rtems_capture_cli_trigger_clear (int                                argc,
0969                                  char**                             argv,
0970                                  const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0971                                  bool                               verbose RC_UNUSED)
0972 {
0973   rtems_capture_cli_trigger_worker (0, argc, argv);
0974 }
0975 
0976 /*
0977  * rtems_capture_cli_trace_records
0978  *
0979  * This function is a monitor command that dumps trace records.
0980  */
0981 
0982 static void
0983 rtems_capture_cli_trace_records (int                                argc,
0984                                  char**                             argv,
0985                                  const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
0986                                  bool                               verbose RC_UNUSED)
0987 {
0988   bool                    csv = false;
0989   static int              dump_total = 22;
0990   int                     arg;
0991 
0992   for (arg = 1; arg < argc; arg++)
0993   {
0994     if (argv[arg][0] == '-')
0995     {
0996       if (argv[arg][1] == 'c')
0997         csv = true;
0998       else
0999         fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
1000     }
1001     else
1002     {
1003       size_t i;
1004       size_t l;
1005 
1006       l = strlen (argv[arg]);
1007 
1008       for (i = 0; i < l; i++)
1009         if (!isdigit ((unsigned char)argv[arg][i]))
1010         {
1011           fprintf (stdout, "error: not a number\n");
1012           return;
1013         }
1014 
1015       dump_total = strtoul (argv[arg], 0, 0);
1016     }
1017   }
1018 
1019   rtems_capture_print_trace_records( dump_total, csv );
1020 }
1021 
1022 /*
1023  * rtems_capture_cli_flush
1024  *
1025  * This function is a monitor command that flushes and primes the capture
1026  * engine.
1027  */
1028 
1029 static void
1030 rtems_capture_cli_flush (int                                argc,
1031                          char**                             argv,
1032                          const rtems_monitor_command_arg_t* command_arg RC_UNUSED,
1033                          bool                               verbose RC_UNUSED)
1034 {
1035   rtems_status_code sc;
1036   bool              prime = true;
1037   int               arg;
1038 
1039   for (arg = 1; arg < argc; arg++)
1040   {
1041     if (argv[arg][0] == '-')
1042     {
1043       if (argv[arg][1] == 'n')
1044         prime = false;
1045       else
1046         fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
1047     }
1048   }
1049 
1050   sc = rtems_capture_flush (prime);
1051 
1052   if (sc != RTEMS_SUCCESSFUL)
1053   {
1054     fprintf (stdout, "error: flush failed: %s\n", rtems_status_text (sc));
1055     return;
1056   }
1057 
1058   fprintf (stdout, "trace buffer flushed and %s.\n",
1059            prime ? "primed" : "not primed");
1060 }
1061 
1062 static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
1063 {
1064   {
1065     "copen",
1066     "usage: copen [-i] size",
1067     0,
1068     rtems_capture_cli_open,
1069     { 0 },
1070     0
1071   },
1072   {
1073     "cclose",
1074     "usage: cclose",
1075     0,
1076     rtems_capture_cli_close,
1077     { 0 },
1078     0
1079   },
1080   {
1081     "cenable",
1082     "usage: cenable",
1083     0,
1084     rtems_capture_cli_enable,
1085     { 0 },
1086     0
1087   },
1088   {
1089     "cdisable",
1090     "usage: cdisable",
1091     0,
1092     rtems_capture_cli_disable,
1093     { 0 },
1094     0
1095   },
1096   {
1097     "ctlist",
1098     "usage: ctlist",
1099     0,
1100      rtems_capture_cli_task_list,
1101     { 0 },
1102     0
1103   },
1104   {
1105     "cwlist",
1106     "usage: cwlist",
1107     0,
1108     rtems_capture_cli_watch_list,
1109     { 0 },
1110     0
1111   },
1112   {
1113     "cwadd",
1114     "usage: cwadd [task name] [id]",
1115     0,
1116     rtems_capture_cli_watch_add,
1117     { 0 },
1118     0
1119   },
1120   {
1121     "cwdel",
1122     "usage: cwdel [task name] [id]",
1123     0,
1124     rtems_capture_cli_watch_del,
1125     { 0 },
1126     0
1127   },
1128   {
1129     "cwctl",
1130     "usage: cwctl [task name] [id] on/off",
1131     0,
1132     rtems_capture_cli_watch_control,
1133     { 0 },
1134     0
1135   },
1136   {
1137     "cwglob",
1138     "usage: cwglob on/off",
1139     0,
1140     rtems_capture_cli_watch_global,
1141     { 0 },
1142     0
1143   },
1144   {
1145     "cwceil",
1146     "usage: cwceil priority",
1147     0,
1148     rtems_capture_cli_watch_ceiling,
1149     { 0 },
1150     0
1151   },
1152   {
1153     "cwfloor",
1154     "usage: cwfloor priority",
1155     0,
1156     rtems_capture_cli_watch_floor,
1157     { 0 },
1158     0
1159   },
1160   {
1161     "ctrace",
1162     "usage: ctrace [-c] [-r records]",
1163     0,
1164     rtems_capture_cli_trace_records,
1165     { 0 },
1166     0
1167   },
1168   {
1169     "ctset",
1170     "usage: ctset -h",
1171     0,
1172     rtems_capture_cli_trigger_set,
1173     { 0 },
1174     0
1175   },
1176   {
1177     "ctclear",
1178     "usage: ctclear -?",
1179     0,
1180     rtems_capture_cli_trigger_clear,
1181     { 0 },
1182     0
1183   },
1184   {
1185     "cflush",
1186     "usage: cflush [-n]",
1187     0,
1188     rtems_capture_cli_flush,
1189     { 0 },
1190     0
1191   }
1192 };
1193 
1194 /*
1195  * rtems_capture_cli_init
1196  *
1197  * This function initialises the command line interface to the capture
1198  * engine.
1199  */
1200 
1201 rtems_status_code
1202 rtems_capture_cli_init (rtems_capture_timestamp timestamp)
1203 {
1204   size_t cmd;
1205 
1206   capture_timestamp = timestamp;
1207 
1208   for (cmd = 0;
1209        cmd < sizeof (rtems_capture_cli_cmds) / sizeof (rtems_monitor_command_entry_t);
1210        cmd++)
1211     rtems_monitor_insert_cmd (&rtems_capture_cli_cmds[cmd]);
1212 
1213   return RTEMS_SUCCESSFUL;
1214 }