]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/mi/mi-cmd-break.c
gdbsupport, gdb: give names to observers
[thirdparty/binutils-gdb.git] / gdb / mi / mi-cmd-break.c
CommitLineData
fb40c209 1/* MI Command Set - breakpoint and watchpoint commands.
3666a048 2 Copyright (C) 2000-2021 Free Software Foundation, Inc.
ab91fdd5 3 Contributed by Cygnus Solutions (a Red Hat company).
fb40c209
AC
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
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
fb40c209
AC
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
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
fb40c209
AC
19
20#include "defs.h"
a6d9a66e 21#include "arch-utils.h"
fb40c209
AC
22#include "mi-cmds.h"
23#include "ui-out.h"
24#include "mi-out.h"
25#include "breakpoint.h"
fb40c209 26#include "mi-getopt.h"
76727919 27#include "observable.h"
8d3788bd 28#include "mi-main.h"
91985142 29#include "mi-cmd-break.h"
f00aae0f
KS
30#include "language.h"
31#include "location.h"
32#include "linespec.h"
c5867ab6
HZ
33#include "gdb_obstack.h"
34#include <ctype.h>
60b3cef2 35#include "tracepoint.h"
fb40c209 36
fb40c209
AC
37enum
38 {
39 FROM_TTY = 0
40 };
41
383f836e
TT
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
2b03b41d 50/* Output a single breakpoint, when allowed. */
fb40c209
AC
51
52static void
8d3788bd 53breakpoint_notify (struct breakpoint *b)
fb40c209 54{
383f836e 55 if (mi_can_breakpoint_notify)
65630365 56 {
a70b8144 57 try
65630365
PA
58 {
59 print_breakpoint (b);
60 }
230d2906 61 catch (const gdb_exception &ex)
65630365
PA
62 {
63 exception_print (gdb_stderr, ex);
64 }
65630365 65 }
fb40c209
AC
66}
67
fb40c209
AC
68enum bp_type
69 {
70 REG_BP,
71 HW_BP,
72 REGEXP_BP
73 };
74
91985142 75/* Arrange for all new breakpoints and catchpoints to be reported to
00f675ff
TT
76 CURRENT_UIOUT until the destructor of the returned scoped_restore
77 is run.
91985142
MG
78
79 Note that MI output will be probably invalid if more than one
80 breakpoint is created inside one MI command. */
81
00f675ff 82scoped_restore_tmpl<int>
91985142
MG
83setup_breakpoint_reporting (void)
84{
91985142
MG
85 if (! mi_breakpoint_observers_installed)
86 {
c90e7d63
SM
87 gdb::observers::breakpoint_created.attach (breakpoint_notify,
88 "mi-cmd-break");
91985142
MG
89 mi_breakpoint_observers_installed = 1;
90 }
91
00f675ff 92 return make_scoped_restore (&mi_can_breakpoint_notify, 1);
91985142
MG
93}
94
95
c5867ab6
HZ
96/* Convert arguments in ARGV to the string in "format",argv,argv...
97 and return it. */
fb40c209 98
784c453a 99static std::string
c5867ab6
HZ
100mi_argv_to_format (char **argv, int argc)
101{
102 int i;
784c453a 103 std::string result;
c5867ab6
HZ
104
105 /* Convert ARGV[OIND + 1] to format string and save to FORMAT. */
784c453a 106 result += '\"';
c5867ab6
HZ
107 for (i = 0; i < strlen (argv[0]); i++)
108 {
109 switch (argv[0][i])
110 {
111 case '\\':
784c453a 112 result += "\\\\";
c5867ab6
HZ
113 break;
114 case '\a':
784c453a 115 result += "\\a";
c5867ab6
HZ
116 break;
117 case '\b':
784c453a 118 result += "\\b";
c5867ab6
HZ
119 break;
120 case '\f':
784c453a 121 result += "\\f";
c5867ab6
HZ
122 break;
123 case '\n':
784c453a 124 result += "\\n";
c5867ab6
HZ
125 break;
126 case '\r':
784c453a 127 result += "\\r";
c5867ab6
HZ
128 break;
129 case '\t':
784c453a 130 result += "\\t";
c5867ab6
HZ
131 break;
132 case '\v':
784c453a 133 result += "\\v";
c5867ab6 134 break;
fa876972 135 case '"':
784c453a 136 result += "\\\"";
fa876972 137 break;
c5867ab6
HZ
138 default:
139 if (isprint (argv[0][i]))
784c453a 140 result += argv[0][i];
c5867ab6
HZ
141 else
142 {
143 char tmp[5];
144
ce70887a
JB
145 xsnprintf (tmp, sizeof (tmp), "\\%o",
146 (unsigned char) argv[0][i]);
784c453a 147 result += tmp;
c5867ab6
HZ
148 }
149 break;
150 }
151 }
784c453a 152 result += '\"';
c5867ab6
HZ
153
154 /* Apply other argv to FORMAT. */
155 for (i = 1; i < argc; i++)
156 {
784c453a
TT
157 result += ',';
158 result += argv[i];
c5867ab6 159 }
c5867ab6 160
784c453a 161 return result;
c5867ab6
HZ
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
9f33b8b7 169mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
fb40c209 170{
f2fc3015 171 const char *address = NULL;
8cdf0e15 172 int hardware = 0;
fb40c209
AC
173 int temp_p = 0;
174 int thread = -1;
175 int ignore_count = 0;
176 char *condition = NULL;
afe8ab22 177 int pending = 0;
41447f92 178 int enabled = 1;
6534d786 179 int tracepoint = 0;
6791b117 180 symbol_name_match_type match_type = symbol_name_match_type::WILD;
0fb4aa4b 181 enum bptype type_wanted;
ffc2605c 182 event_location_up location;
19ca11c5 183 struct breakpoint_ops *ops;
eb8c4e2e 184 int is_explicit = 0;
67994074 185 struct explicit_location explicit_loc;
784c453a 186 std::string extra_string;
41447f92 187
fb40c209
AC
188 enum opt
189 {
8cdf0e15 190 HARDWARE_OPT, TEMP_OPT, CONDITION_OPT,
6534d786
VP
191 IGNORE_COUNT_OPT, THREAD_OPT, PENDING_OPT, DISABLE_OPT,
192 TRACEPOINT_OPT,
6791b117 193 QUALIFIED_OPT,
eb8c4e2e
KS
194 EXPLICIT_SOURCE_OPT, EXPLICIT_FUNC_OPT,
195 EXPLICIT_LABEL_OPT, EXPLICIT_LINE_OPT
fb40c209 196 };
91174723 197 static const struct mi_opt opts[] =
fb40c209
AC
198 {
199 {"h", HARDWARE_OPT, 0},
200 {"t", TEMP_OPT, 0},
201 {"c", CONDITION_OPT, 1},
202 {"i", IGNORE_COUNT_OPT, 1},
203 {"p", THREAD_OPT, 1},
afe8ab22 204 {"f", PENDING_OPT, 0},
41447f92 205 {"d", DISABLE_OPT, 0},
6534d786 206 {"a", TRACEPOINT_OPT, 0},
6791b117 207 {"-qualified", QUALIFIED_OPT, 0},
eb8c4e2e
KS
208 {"-source" , EXPLICIT_SOURCE_OPT, 1},
209 {"-function", EXPLICIT_FUNC_OPT, 1},
210 {"-label", EXPLICIT_LABEL_OPT, 1},
211 {"-line", EXPLICIT_LINE_OPT, 1},
d5d6fca5 212 { 0, 0, 0 }
fb40c209
AC
213 };
214
215 /* Parse arguments. It could be -r or -h or -t, <location> or ``--''
216 to denote the end of the option list. */
f8c000a2
AS
217 int oind = 0;
218 char *oarg;
102040f0 219
67994074 220 initialize_explicit_location (&explicit_loc);
eb8c4e2e 221
fb40c209
AC
222 while (1)
223 {
1b05df00 224 int opt = mi_getopt ("-break-insert", argc, argv,
f8c000a2 225 opts, &oind, &oarg);
fb40c209
AC
226 if (opt < 0)
227 break;
228 switch ((enum opt) opt)
229 {
230 case TEMP_OPT:
231 temp_p = 1;
232 break;
233 case HARDWARE_OPT:
8cdf0e15 234 hardware = 1;
fb40c209 235 break;
fb40c209 236 case CONDITION_OPT:
f8c000a2 237 condition = oarg;
fb40c209
AC
238 break;
239 case IGNORE_COUNT_OPT:
f8c000a2 240 ignore_count = atol (oarg);
fb40c209
AC
241 break;
242 case THREAD_OPT:
f8c000a2 243 thread = atol (oarg);
fb40c209 244 break;
afe8ab22
VP
245 case PENDING_OPT:
246 pending = 1;
247 break;
41447f92
VP
248 case DISABLE_OPT:
249 enabled = 0;
6534d786
VP
250 break;
251 case TRACEPOINT_OPT:
252 tracepoint = 1;
253 break;
6791b117
PA
254 case QUALIFIED_OPT:
255 match_type = symbol_name_match_type::FULL;
256 break;
eb8c4e2e
KS
257 case EXPLICIT_SOURCE_OPT:
258 is_explicit = 1;
67994074 259 explicit_loc.source_filename = oarg;
eb8c4e2e
KS
260 break;
261 case EXPLICIT_FUNC_OPT:
262 is_explicit = 1;
67994074 263 explicit_loc.function_name = oarg;
eb8c4e2e
KS
264 break;
265 case EXPLICIT_LABEL_OPT:
266 is_explicit = 1;
67994074 267 explicit_loc.label_name = oarg;
eb8c4e2e
KS
268 break;
269 case EXPLICIT_LINE_OPT:
270 is_explicit = 1;
67994074 271 explicit_loc.line_offset = linespec_parse_line_offset (oarg);
eb8c4e2e 272 break;
fb40c209
AC
273 }
274 }
275
eb8c4e2e 276 if (oind >= argc && !is_explicit)
c5867ab6
HZ
277 error (_("-%s-insert: Missing <location>"),
278 dprintf ? "dprintf" : "break");
c5867ab6
HZ
279 if (dprintf)
280 {
eb8c4e2e 281 int format_num = is_explicit ? oind : oind + 1;
c5867ab6
HZ
282
283 if (hardware || tracepoint)
284 error (_("-dprintf-insert: does not support -h or -a"));
285 if (format_num >= argc)
286 error (_("-dprintf-insert: Missing <format>"));
287
288 extra_string = mi_argv_to_format (argv + format_num, argc - format_num);
eb8c4e2e 289 address = argv[oind];
c5867ab6
HZ
290 }
291 else
292 {
eb8c4e2e
KS
293 if (is_explicit)
294 {
295 if (oind < argc)
296 error (_("-break-insert: Garbage following explicit location"));
297 }
298 else
299 {
300 if (oind < argc - 1)
301 error (_("-break-insert: Garbage following <location>"));
302 address = argv[oind];
303 }
c5867ab6 304 }
fb40c209 305
2b03b41d 306 /* Now we have what we need, let's insert the breakpoint! */
00f675ff 307 scoped_restore restore_breakpoint_reporting = setup_breakpoint_reporting ();
c5867ab6
HZ
308
309 if (tracepoint)
310 {
311 /* Note that to request a fast tracepoint, the client uses the
312 "hardware" flag, although there's nothing of hardware related to
313 fast tracepoints -- one can implement slow tracepoints with
314 hardware breakpoints, but fast tracepoints are always software.
315 "fast" is a misnomer, actually, "jump" would be more appropriate.
316 A simulator or an emulator could conceivably implement fast
317 regular non-jump based tracepoints. */
318 type_wanted = hardware ? bp_fast_tracepoint : bp_tracepoint;
319 ops = &tracepoint_breakpoint_ops;
320 }
321 else if (dprintf)
322 {
323 type_wanted = bp_dprintf;
324 ops = &dprintf_breakpoint_ops;
325 }
326 else
327 {
328 type_wanted = hardware ? bp_hardware_breakpoint : bp_breakpoint;
329 ops = &bkpt_breakpoint_ops;
330 }
0fb4aa4b 331
eb8c4e2e
KS
332 if (is_explicit)
333 {
334 /* Error check -- we must have one of the other
335 parameters specified. */
67994074
KS
336 if (explicit_loc.source_filename != NULL
337 && explicit_loc.function_name == NULL
338 && explicit_loc.label_name == NULL
339 && explicit_loc.line_offset.sign == LINE_OFFSET_UNKNOWN)
eb8c4e2e
KS
340 error (_("-%s-insert: --source option requires --function, --label,"
341 " or --line"), dprintf ? "dprintf" : "break");
342
6791b117
PA
343 explicit_loc.func_name_match_type = match_type;
344
67994074 345 location = new_explicit_location (&explicit_loc);
eb8c4e2e
KS
346 }
347 else
348 {
a20714ff 349 location = string_to_event_location_basic (&address, current_language,
6791b117 350 match_type);
eb8c4e2e 351 if (*address)
ffc2605c 352 error (_("Garbage '%s' at end of location"), address);
eb8c4e2e 353 }
f00aae0f 354
ffc2605c 355 create_breakpoint (get_current_arch (), location.get (), condition, thread,
784c453a 356 extra_string.c_str (),
10a636cc 357 false,
8cdf0e15 358 0 /* condition and thread are valid. */,
0fb4aa4b 359 temp_p, type_wanted,
8cdf0e15
VP
360 ignore_count,
361 pending ? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE,
19ca11c5 362 ops, 0, enabled, 0, 0);
c5867ab6
HZ
363}
364
365/* Implements the -break-insert command.
366 See the MI manual for the list of possible options. */
8cdf0e15 367
c5867ab6 368void
9f33b8b7 369mi_cmd_break_insert (const char *command, char **argv, int argc)
c5867ab6
HZ
370{
371 mi_cmd_break_insert_1 (0, command, argv, argc);
372}
373
374/* Implements the -dprintf-insert command.
375 See the MI manual for the list of possible options. */
376
377void
9f33b8b7 378mi_cmd_dprintf_insert (const char *command, char **argv, int argc)
c5867ab6
HZ
379{
380 mi_cmd_break_insert_1 (1, command, argv, argc);
fb40c209
AC
381}
382
383enum wp_type
384{
385 REG_WP,
386 READ_WP,
387 ACCESS_WP
388};
389
9b4c786c 390void
9f33b8b7 391mi_cmd_break_passcount (const char *command, char **argv, int argc)
9b4c786c
VP
392{
393 int n;
394 int p;
d9b3f62e 395 struct tracepoint *t;
9b4c786c
VP
396
397 if (argc != 2)
398 error (_("Usage: tracepoint-number passcount"));
399
400 n = atoi (argv[0]);
401 p = atoi (argv[1]);
402 t = get_tracepoint (n);
403
404 if (t)
405 {
406 t->pass_count = p;
76727919 407 gdb::observers::breakpoint_modified.notify (t);
9b4c786c
VP
408 }
409 else
410 {
401a70b8 411 error (_("Could not find tracepoint %d"), n);
9b4c786c
VP
412 }
413}
414
fb40c209
AC
415/* Insert a watchpoint. The type of watchpoint is specified by the
416 first argument:
417 -break-watch <expr> --> insert a regular wp.
418 -break-watch -r <expr> --> insert a read watchpoint.
2b03b41d 419 -break-watch -a <expr> --> insert an access wp. */
fb40c209 420
ce8f13f8 421void
9f33b8b7 422mi_cmd_break_watch (const char *command, char **argv, int argc)
fb40c209
AC
423{
424 char *expr = NULL;
425 enum wp_type type = REG_WP;
426 enum opt
427 {
428 READ_OPT, ACCESS_OPT
429 };
91174723 430 static const struct mi_opt opts[] =
fb40c209
AC
431 {
432 {"r", READ_OPT, 0},
433 {"a", ACCESS_OPT, 0},
d5d6fca5 434 { 0, 0, 0 }
fb40c209
AC
435 };
436
437 /* Parse arguments. */
f8c000a2
AS
438 int oind = 0;
439 char *oarg;
102040f0 440
fb40c209
AC
441 while (1)
442 {
1b05df00 443 int opt = mi_getopt ("-break-watch", argc, argv,
f8c000a2 444 opts, &oind, &oarg);
102040f0 445
fb40c209
AC
446 if (opt < 0)
447 break;
448 switch ((enum opt) opt)
449 {
450 case READ_OPT:
451 type = READ_WP;
452 break;
453 case ACCESS_OPT:
454 type = ACCESS_WP;
455 break;
456 }
457 }
f8c000a2 458 if (oind >= argc)
1b05df00 459 error (_("-break-watch: Missing <expression>"));
f8c000a2 460 if (oind < argc - 1)
1b05df00 461 error (_("-break-watch: Garbage following <expression>"));
f8c000a2 462 expr = argv[oind];
fb40c209 463
2b03b41d 464 /* Now we have what we need, let's insert the watchpoint! */
fb40c209
AC
465 switch (type)
466 {
467 case REG_WP:
2e362716 468 watch_command_wrapper (expr, FROM_TTY, false);
fb40c209
AC
469 break;
470 case READ_WP:
2e362716 471 rwatch_command_wrapper (expr, FROM_TTY, false);
fb40c209
AC
472 break;
473 case ACCESS_WP:
2e362716 474 awatch_command_wrapper (expr, FROM_TTY, false);
fb40c209
AC
475 break;
476 default:
1b05df00 477 error (_("-break-watch: Unknown watchpoint type."));
fb40c209 478 }
fb40c209 479}
48cb2d85 480
48cb2d85 481void
9f33b8b7 482mi_cmd_break_commands (const char *command, char **argv, int argc)
48cb2d85 483{
12973681 484 counted_command_line break_command;
48cb2d85
VP
485 char *endptr;
486 int bnum;
487 struct breakpoint *b;
488
489 if (argc < 1)
9b20d036 490 error (_("USAGE: %s <BKPT> [<COMMAND> [<COMMAND>...]]"), command);
48cb2d85
VP
491
492 bnum = strtol (argv[0], &endptr, 0);
493 if (endptr == argv[0])
9b20d036 494 error (_("breakpoint number argument \"%s\" is not a number."),
48cb2d85
VP
495 argv[0]);
496 else if (*endptr != '\0')
9b20d036 497 error (_("junk at the end of breakpoint number argument \"%s\"."),
48cb2d85
VP
498 argv[0]);
499
500 b = get_breakpoint (bnum);
501 if (b == NULL)
9b20d036 502 error (_("breakpoint %d not found."), bnum);
48cb2d85 503
60b3cef2
TT
504 int count = 1;
505 auto reader
506 = [&] ()
507 {
508 const char *result = nullptr;
509 if (count < argc)
510 result = argv[count++];
511 return result;
512 };
48cb2d85 513
d77f58be 514 if (is_tracepoint (b))
60b3cef2
TT
515 break_command = read_command_lines_1 (reader, 1,
516 [=] (const char *line)
517 {
518 validate_actionline (line, b);
519 });
a7bdde9e 520 else
60b3cef2 521 break_command = read_command_lines_1 (reader, 1, 0);
a7bdde9e 522
93921405 523 breakpoint_set_commands (b, std::move (break_command));
48cb2d85
VP
524}
525