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