xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/mi/mi-cmd-break.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
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 
37 enum
38   {
39     FROM_TTY = 0
40   };
41 
42 /* True if MI breakpoint observers have been registered.  */
43 
44 static int mi_breakpoint_observers_installed;
45 
46 /* Control whether breakpoint_notify may act.  */
47 
48 static int mi_can_breakpoint_notify;
49 
50 /* Output a single breakpoint, when allowed.  */
51 
52 static void
53 breakpoint_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 
68 enum 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 
82 scoped_restore_tmpl<int>
83 setup_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 
99 static std::string
100 mi_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 
168 static void
169 mi_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 
373 void
374 mi_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 
382 void
383 mi_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 
391 void
392 mi_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 
444 enum wp_type
445 {
446   REG_WP,
447   READ_WP,
448   ACCESS_WP
449 };
450 
451 void
452 mi_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 
482 void
483 mi_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 
542 void
543 mi_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