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