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
breakpoint_notify(struct breakpoint * b)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>
setup_breakpoint_reporting(void)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
mi_argv_to_format(const char * const * argv,int argc)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
mi_cmd_break_insert_1(int dprintf,const char * command,const char * const * argv,int argc)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
mi_cmd_break_insert(const char * command,const char * const * argv,int argc)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
mi_cmd_dprintf_insert(const char * command,const char * const * argv,int argc)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
mi_cmd_break_condition(const char * command,const char * const * argv,int argc)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
mi_cmd_break_passcount(const char * command,const char * const * argv,int argc)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
mi_cmd_break_watch(const char * command,const char * const * argv,int argc)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
mi_cmd_break_commands(const char * command,const char * const * argv,int argc)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