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