Home | History | Annotate | Line # | Download | only in mi
mi-cmd-break.c revision 1.11
      1 /* MI Command Set - breakpoint and watchpoint commands.
      2    Copyright (C) 2000-2024 Free Software Foundation, Inc.
      3    Contributed by Cygnus Solutions (a Red Hat company).
      4 
      5    This file is part of GDB.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 #include "arch-utils.h"
     21 #include "mi-cmds.h"
     22 #include "ui-out.h"
     23 #include "mi-out.h"
     24 #include "breakpoint.h"
     25 #include "mi-getopt.h"
     26 #include "observable.h"
     27 #include "mi-main.h"
     28 #include "mi-cmd-break.h"
     29 #include "language.h"
     30 #include "location.h"
     31 #include "linespec.h"
     32 #include "gdbsupport/gdb_obstack.h"
     33 #include <ctype.h>
     34 #include "tracepoint.h"
     35 
     36 enum
     37   {
     38     FROM_TTY = 0
     39   };
     40 
     41 /* True if MI breakpoint observers have been registered.  */
     42 
     43 static int mi_breakpoint_observers_installed;
     44 
     45 /* Control whether breakpoint_notify may act.  */
     46 
     47 static int mi_can_breakpoint_notify;
     48 
     49 /* Output a single breakpoint, when allowed.  */
     50 
     51 static void
     52 breakpoint_notify (struct breakpoint *b)
     53 {
     54   if (mi_can_breakpoint_notify)
     55     {
     56       try
     57 	{
     58 	  print_breakpoint (b);
     59 	}
     60       catch (const gdb_exception_error &ex)
     61 	{
     62 	  exception_print (gdb_stderr, ex);
     63 	}
     64     }
     65 }
     66 
     67 enum bp_type
     68   {
     69     REG_BP,
     70     HW_BP,
     71     REGEXP_BP
     72   };
     73 
     74 /* Arrange for all new breakpoints and catchpoints to be reported to
     75    CURRENT_UIOUT until the destructor of the returned scoped_restore
     76    is run.
     77 
     78    Note that MI output will be probably invalid if more than one
     79    breakpoint is created inside one MI command.  */
     80 
     81 scoped_restore_tmpl<int>
     82 setup_breakpoint_reporting (void)
     83 {
     84   if (! mi_breakpoint_observers_installed)
     85     {
     86       gdb::observers::breakpoint_created.attach (breakpoint_notify,
     87 						 "mi-cmd-break");
     88       mi_breakpoint_observers_installed = 1;
     89     }
     90 
     91   return make_scoped_restore (&mi_can_breakpoint_notify, 1);
     92 }
     93 
     94 
     95 /* Convert arguments in ARGV to a string suitable for parsing by
     96    dprintf like "FORMAT",ARG,ARG... and return it.  */
     97 
     98 static std::string
     99 mi_argv_to_format (const char *const *argv, int argc)
    100 {
    101   int i;
    102   std::string result;
    103 
    104   /* Convert ARGV[0] to format string and save to FORMAT.  */
    105   result += '\"';
    106   for (i = 0; argv[0][i] != '\0'; i++)
    107     {
    108       switch (argv[0][i])
    109 	{
    110 	case '\\':
    111 	  result += "\\\\";
    112 	  break;
    113 	case '\a':
    114 	  result += "\\a";
    115 	  break;
    116 	case '\b':
    117 	  result += "\\b";
    118 	  break;
    119 	case '\f':
    120 	  result += "\\f";
    121 	  break;
    122 	case '\n':
    123 	  result += "\\n";
    124 	  break;
    125 	case '\r':
    126 	  result += "\\r";
    127 	  break;
    128 	case '\t':
    129 	  result += "\\t";
    130 	  break;
    131 	case '\v':
    132 	  result += "\\v";
    133 	  break;
    134 	case '"':
    135 	  result += "\\\"";
    136 	  break;
    137 	default:
    138 	  if (isprint (argv[0][i]))
    139 	    result += argv[0][i];
    140 	  else
    141 	    {
    142 	      char tmp[5];
    143 
    144 	      xsnprintf (tmp, sizeof (tmp), "\\%o",
    145 			 (unsigned char) argv[0][i]);
    146 	      result += tmp;
    147 	    }
    148 	  break;
    149 	}
    150     }
    151   result += '\"';
    152 
    153   /* Append other arguments.  */
    154   for (i = 1; i < argc; i++)
    155     {
    156       result += ',';
    157       result += argv[i];
    158     }
    159 
    160   return result;
    161 }
    162 
    163 /* Insert breakpoint.
    164    If dprintf is true, it will insert dprintf.
    165    If not, it will insert other type breakpoint.  */
    166 
    167 static void
    168 mi_cmd_break_insert_1 (int dprintf, const char *command,
    169 		       const char *const *argv, int argc)
    170 {
    171   const char *address = NULL;
    172   int hardware = 0;
    173   int temp_p = 0;
    174   int thread = -1;
    175   int thread_group = -1;
    176   int ignore_count = 0;
    177   const char *condition = NULL;
    178   int pending = 0;
    179   int enabled = 1;
    180   int tracepoint = 0;
    181   symbol_name_match_type match_type = symbol_name_match_type::WILD;
    182   enum bptype type_wanted;
    183   location_spec_up locspec;
    184   const struct breakpoint_ops *ops;
    185   int is_explicit = 0;
    186   std::unique_ptr<explicit_location_spec> explicit_loc
    187     (new explicit_location_spec ());
    188   std::string extra_string;
    189   bool force_condition = false;
    190 
    191   enum opt
    192     {
    193       HARDWARE_OPT, TEMP_OPT, CONDITION_OPT,
    194       IGNORE_COUNT_OPT, THREAD_OPT, THREAD_GROUP_OPT,
    195       PENDING_OPT, DISABLE_OPT,
    196       TRACEPOINT_OPT,
    197       FORCE_CONDITION_OPT,
    198       QUALIFIED_OPT,
    199       EXPLICIT_SOURCE_OPT, EXPLICIT_FUNC_OPT,
    200       EXPLICIT_LABEL_OPT, EXPLICIT_LINE_OPT
    201     };
    202   static const struct mi_opt opts[] =
    203   {
    204     {"h", HARDWARE_OPT, 0},
    205     {"t", TEMP_OPT, 0},
    206     {"c", CONDITION_OPT, 1},
    207     {"i", IGNORE_COUNT_OPT, 1},
    208     {"p", THREAD_OPT, 1},
    209     {"g", THREAD_GROUP_OPT, 1},
    210     {"f", PENDING_OPT, 0},
    211     {"d", DISABLE_OPT, 0},
    212     {"a", TRACEPOINT_OPT, 0},
    213     {"-force-condition", FORCE_CONDITION_OPT, 0},
    214     {"-qualified", QUALIFIED_OPT, 0},
    215     {"-source" , EXPLICIT_SOURCE_OPT, 1},
    216     {"-function", EXPLICIT_FUNC_OPT, 1},
    217     {"-label", EXPLICIT_LABEL_OPT, 1},
    218     {"-line", EXPLICIT_LINE_OPT, 1},
    219     { 0, 0, 0 }
    220   };
    221 
    222   /* Parse arguments. It could be -r or -h or -t, <location> or ``--''
    223      to denote the end of the option list. */
    224   int oind = 0;
    225   const char *oarg;
    226 
    227   while (1)
    228     {
    229       int opt = mi_getopt ("-break-insert", argc, argv,
    230 			   opts, &oind, &oarg);
    231       if (opt < 0)
    232 	break;
    233       switch ((enum opt) opt)
    234 	{
    235 	case TEMP_OPT:
    236 	  temp_p = 1;
    237 	  break;
    238 	case HARDWARE_OPT:
    239 	  hardware = 1;
    240 	  break;
    241 	case CONDITION_OPT:
    242 	  condition = oarg;
    243 	  break;
    244 	case IGNORE_COUNT_OPT:
    245 	  ignore_count = atol (oarg);
    246 	  break;
    247 	case THREAD_OPT:
    248 	  thread = atol (oarg);
    249 	  if (!valid_global_thread_id (thread))
    250 	    error (_("Unknown thread %d."), thread);
    251 	  break;
    252 	case THREAD_GROUP_OPT:
    253 	  thread_group = mi_parse_thread_group_id (oarg);
    254 	  break;
    255 	case PENDING_OPT:
    256 	  pending = 1;
    257 	  break;
    258 	case DISABLE_OPT:
    259 	  enabled = 0;
    260 	  break;
    261 	case TRACEPOINT_OPT:
    262 	  tracepoint = 1;
    263 	  break;
    264 	case QUALIFIED_OPT:
    265 	  match_type = symbol_name_match_type::FULL;
    266 	  break;
    267 	case EXPLICIT_SOURCE_OPT:
    268 	  is_explicit = 1;
    269 	  explicit_loc->source_filename = make_unique_xstrdup (oarg);
    270 	  break;
    271 	case EXPLICIT_FUNC_OPT:
    272 	  is_explicit = 1;
    273 	  explicit_loc->function_name = make_unique_xstrdup (oarg);
    274 	  break;
    275 	case EXPLICIT_LABEL_OPT:
    276 	  is_explicit = 1;
    277 	  explicit_loc->label_name = make_unique_xstrdup (oarg);
    278 	  break;
    279 	case EXPLICIT_LINE_OPT:
    280 	  is_explicit = 1;
    281 	  explicit_loc->line_offset = linespec_parse_line_offset (oarg);
    282 	  break;
    283 	case FORCE_CONDITION_OPT:
    284 	  force_condition = true;
    285 	  break;
    286 	}
    287     }
    288 
    289   if (oind >= argc && !is_explicit)
    290     error (_("-%s-insert: Missing <location>"),
    291 	   dprintf ? "dprintf" : "break");
    292   if (dprintf)
    293     {
    294       int format_num = is_explicit ? oind : oind + 1;
    295 
    296       if (hardware || tracepoint)
    297 	error (_("-dprintf-insert: does not support -h or -a"));
    298       if (format_num >= argc)
    299 	error (_("-dprintf-insert: Missing <format>"));
    300 
    301       extra_string = mi_argv_to_format (argv + format_num, argc - format_num);
    302       address = argv[oind];
    303     }
    304   else
    305     {
    306       if (is_explicit)
    307 	{
    308 	  if (oind < argc)
    309 	    error (_("-break-insert: Garbage following explicit location"));
    310 	}
    311       else
    312 	{
    313 	  if (oind < argc - 1)
    314 	    error (_("-break-insert: Garbage following <location>"));
    315 	  address = argv[oind];
    316 	}
    317     }
    318 
    319   /* Now we have what we need, let's insert the breakpoint!  */
    320   scoped_restore restore_breakpoint_reporting = setup_breakpoint_reporting ();
    321 
    322   if (tracepoint)
    323     {
    324       /* Note that to request a fast tracepoint, the client uses the
    325 	 "hardware" flag, although there's nothing of hardware related to
    326 	 fast tracepoints -- one can implement slow tracepoints with
    327 	 hardware breakpoints, but fast tracepoints are always software.
    328 	 "fast" is a misnomer, actually, "jump" would be more appropriate.
    329 	 A simulator or an emulator could conceivably implement fast
    330 	 regular non-jump based tracepoints.  */
    331       type_wanted = hardware ? bp_fast_tracepoint : bp_tracepoint;
    332       ops = breakpoint_ops_for_location_spec (nullptr, true);
    333     }
    334   else if (dprintf)
    335     {
    336       type_wanted = bp_dprintf;
    337       ops = &code_breakpoint_ops;
    338     }
    339   else
    340     {
    341       type_wanted = hardware ? bp_hardware_breakpoint : bp_breakpoint;
    342       ops = &code_breakpoint_ops;
    343     }
    344 
    345   if (is_explicit)
    346     {
    347       /* Error check -- we must have one of the other
    348 	 parameters specified.  */
    349       if (explicit_loc->source_filename != NULL
    350 	  && explicit_loc->function_name == NULL
    351 	  && explicit_loc->label_name == NULL
    352 	  && explicit_loc->line_offset.sign == LINE_OFFSET_UNKNOWN)
    353 	error (_("-%s-insert: --source option requires --function, --label,"
    354 		 " or --line"), dprintf ? "dprintf" : "break");
    355 
    356       explicit_loc->func_name_match_type = match_type;
    357 
    358       locspec = std::move (explicit_loc);
    359     }
    360   else
    361     {
    362       locspec = string_to_location_spec_basic (&address, current_language,
    363 					       match_type);
    364       if (*address)
    365 	error (_("Garbage '%s' at end of location"), address);
    366     }
    367 
    368   create_breakpoint (get_current_arch (), locspec.get (), condition,
    369 		     thread, thread_group,
    370 		     extra_string.c_str (),
    371 		     force_condition,
    372 		     0 /* condition and thread are valid.  */,
    373 		     temp_p, type_wanted,
    374 		     ignore_count,
    375 		     pending ? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE,
    376 		     ops, 0, enabled, 0, 0);
    377 }
    378 
    379 /* Implements the -break-insert command.
    380    See the MI manual for the list of possible options.  */
    381 
    382 void
    383 mi_cmd_break_insert (const char *command, const char *const *argv, int argc)
    384 {
    385   mi_cmd_break_insert_1 (0, command, argv, argc);
    386 }
    387 
    388 /* Implements the -dprintf-insert command.
    389    See the MI manual for the list of possible options.  */
    390 
    391 void
    392 mi_cmd_dprintf_insert (const char *command, const char *const *argv, int argc)
    393 {
    394   mi_cmd_break_insert_1 (1, command, argv, argc);
    395 }
    396 
    397 /* Implements the -break-condition command.
    398    See the MI manual for the list of options.  */
    399 
    400 void
    401 mi_cmd_break_condition (const char *command, const char *const *argv,
    402 			int argc)
    403 {
    404   enum option
    405     {
    406       FORCE_CONDITION_OPT,
    407     };
    408 
    409   static const struct mi_opt opts[] =
    410   {
    411     {"-force", FORCE_CONDITION_OPT, 0},
    412     { 0, 0, 0 }
    413   };
    414 
    415   /* Parse arguments.  */
    416   int oind = 0;
    417   const char *oarg;
    418   bool force_condition = false;
    419 
    420   while (true)
    421     {
    422       int opt = mi_getopt ("-break-condition", argc, argv,
    423 			   opts, &oind, &oarg);
    424       if (opt < 0)
    425 	break;
    426 
    427       switch (opt)
    428 	{
    429 	case FORCE_CONDITION_OPT:
    430 	  force_condition = true;
    431 	  break;
    432 	}
    433     }
    434 
    435   /* There must be at least one more arg: a bpnum.  */
    436   if (oind >= argc)
    437     error (_("-break-condition: Missing the <number> argument"));
    438 
    439   int bpnum = atoi (argv[oind]);
    440 
    441   /* The rest form the condition expr.  */
    442   std::string expr = "";
    443   for (int i = oind + 1; i < argc; ++i)
    444     {
    445       expr += argv[i];
    446       if (i + 1 < argc)
    447 	expr += " ";
    448     }
    449 
    450   set_breakpoint_condition (bpnum, expr.c_str (), 0 /* from_tty */,
    451 			    force_condition);
    452 }
    453 
    454 enum wp_type
    455 {
    456   REG_WP,
    457   READ_WP,
    458   ACCESS_WP
    459 };
    460 
    461 void
    462 mi_cmd_break_passcount (const char *command, const char *const *argv,
    463 			int argc)
    464 {
    465   int n;
    466   int p;
    467   struct tracepoint *t;
    468 
    469   if (argc != 2)
    470     error (_("Usage: tracepoint-number passcount"));
    471 
    472   n = atoi (argv[0]);
    473   p = atoi (argv[1]);
    474   t = get_tracepoint (n);
    475 
    476   if (t)
    477     {
    478       t->pass_count = p;
    479       notify_breakpoint_modified (t);
    480     }
    481   else
    482     {
    483       error (_("Could not find tracepoint %d"), n);
    484     }
    485 }
    486 
    487 /* Insert a watchpoint. The type of watchpoint is specified by the
    488    first argument:
    489    -break-watch <expr> --> insert a regular wp.
    490    -break-watch -r <expr> --> insert a read watchpoint.
    491    -break-watch -a <expr> --> insert an access wp.  */
    492 
    493 void
    494 mi_cmd_break_watch (const char *command, const char *const *argv, int argc)
    495 {
    496   const char *expr = NULL;
    497   enum wp_type type = REG_WP;
    498   enum opt
    499     {
    500       READ_OPT, ACCESS_OPT
    501     };
    502   static const struct mi_opt opts[] =
    503   {
    504     {"r", READ_OPT, 0},
    505     {"a", ACCESS_OPT, 0},
    506     { 0, 0, 0 }
    507   };
    508 
    509   /* Parse arguments. */
    510   int oind = 0;
    511   const char *oarg;
    512 
    513   while (1)
    514     {
    515       int opt = mi_getopt ("-break-watch", argc, argv,
    516 			   opts, &oind, &oarg);
    517 
    518       if (opt < 0)
    519 	break;
    520       switch ((enum opt) opt)
    521 	{
    522 	case READ_OPT:
    523 	  type = READ_WP;
    524 	  break;
    525 	case ACCESS_OPT:
    526 	  type = ACCESS_WP;
    527 	  break;
    528 	}
    529     }
    530   if (oind >= argc)
    531     error (_("-break-watch: Missing <expression>"));
    532   if (oind < argc - 1)
    533     error (_("-break-watch: Garbage following <expression>"));
    534   expr = argv[oind];
    535 
    536   /* Now we have what we need, let's insert the watchpoint!  */
    537   switch (type)
    538     {
    539     case REG_WP:
    540       watch_command_wrapper (expr, FROM_TTY, false);
    541       break;
    542     case READ_WP:
    543       rwatch_command_wrapper (expr, FROM_TTY, false);
    544       break;
    545     case ACCESS_WP:
    546       awatch_command_wrapper (expr, FROM_TTY, false);
    547       break;
    548     default:
    549       error (_("-break-watch: Unknown watchpoint type."));
    550     }
    551 }
    552 
    553 void
    554 mi_cmd_break_commands (const char *command, const char *const *argv, int argc)
    555 {
    556   counted_command_line break_command;
    557   char *endptr;
    558   int bnum;
    559   struct breakpoint *b;
    560 
    561   if (argc < 1)
    562     error (_("USAGE: %s <BKPT> [<COMMAND> [<COMMAND>...]]"), command);
    563 
    564   bnum = strtol (argv[0], &endptr, 0);
    565   if (endptr == argv[0])
    566     error (_("breakpoint number argument \"%s\" is not a number."),
    567 	   argv[0]);
    568   else if (*endptr != '\0')
    569     error (_("junk at the end of breakpoint number argument \"%s\"."),
    570 	   argv[0]);
    571 
    572   b = get_breakpoint (bnum);
    573   if (b == NULL)
    574     error (_("breakpoint %d not found."), bnum);
    575 
    576   int count = 1;
    577   auto reader
    578     = [&] (std::string &buffer)
    579       {
    580 	const char *result = nullptr;
    581 	if (count < argc)
    582 	  result = argv[count++];
    583 	return result;
    584       };
    585 
    586   if (is_tracepoint (b))
    587     {
    588       tracepoint *t = gdb::checked_static_cast<tracepoint *> (b);
    589       break_command = read_command_lines_1 (reader, 1,
    590 					    [=] (const char *line)
    591 					    {
    592 					      validate_actionline (line, t);
    593 					    });
    594     }
    595   else
    596     break_command = read_command_lines_1 (reader, 1, 0);
    597 
    598   breakpoint_set_commands (b, std::move (break_command));
    599 }
    600 
    601