1/* MI Command Set - breakpoint and watchpoint commands. 2 Copyright (C) 2000-2020 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 "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_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 the string in "format",argv,argv... 96 and return it. */ 97 98static std::string 99mi_argv_to_format (char **argv, int argc) 100{ 101 int i; 102 std::string result; 103 104 /* Convert ARGV[OIND + 1] to format string and save to FORMAT. */ 105 result += '\"'; 106 for (i = 0; i < strlen (argv[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 /* Apply other argv to FORMAT. */ 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 167static void 168mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc) 169{ 170 const char *address = NULL; 171 int hardware = 0; 172 int temp_p = 0; 173 int thread = -1; 174 int ignore_count = 0; 175 char *condition = NULL; 176 int pending = 0; 177 int enabled = 1; 178 int tracepoint = 0; 179 symbol_name_match_type match_type = symbol_name_match_type::WILD; 180 enum bptype type_wanted; 181 event_location_up location; 182 struct breakpoint_ops *ops; 183 int is_explicit = 0; 184 struct explicit_location explicit_loc; 185 std::string extra_string; 186 187 enum opt 188 { 189 HARDWARE_OPT, TEMP_OPT, CONDITION_OPT, 190 IGNORE_COUNT_OPT, THREAD_OPT, PENDING_OPT, DISABLE_OPT, 191 TRACEPOINT_OPT, 192 QUALIFIED_OPT, 193 EXPLICIT_SOURCE_OPT, EXPLICIT_FUNC_OPT, 194 EXPLICIT_LABEL_OPT, EXPLICIT_LINE_OPT 195 }; 196 static const struct mi_opt opts[] = 197 { 198 {"h", HARDWARE_OPT, 0}, 199 {"t", TEMP_OPT, 0}, 200 {"c", CONDITION_OPT, 1}, 201 {"i", IGNORE_COUNT_OPT, 1}, 202 {"p", THREAD_OPT, 1}, 203 {"f", PENDING_OPT, 0}, 204 {"d", DISABLE_OPT, 0}, 205 {"a", TRACEPOINT_OPT, 0}, 206 {"-qualified", QUALIFIED_OPT, 0}, 207 {"-source" , EXPLICIT_SOURCE_OPT, 1}, 208 {"-function", EXPLICIT_FUNC_OPT, 1}, 209 {"-label", EXPLICIT_LABEL_OPT, 1}, 210 {"-line", EXPLICIT_LINE_OPT, 1}, 211 { 0, 0, 0 } 212 }; 213 214 /* Parse arguments. It could be -r or -h or -t, <location> or ``--'' 215 to denote the end of the option list. */ 216 int oind = 0; 217 char *oarg; 218 219 initialize_explicit_location (&explicit_loc); 220 221 while (1) 222 { 223 int opt = mi_getopt ("-break-insert", argc, argv, 224 opts, &oind, &oarg); 225 if (opt < 0) 226 break; 227 switch ((enum opt) opt) 228 { 229 case TEMP_OPT: 230 temp_p = 1; 231 break; 232 case HARDWARE_OPT: 233 hardware = 1; 234 break; 235 case CONDITION_OPT: 236 condition = oarg; 237 break; 238 case IGNORE_COUNT_OPT: 239 ignore_count = atol (oarg); 240 break; 241 case THREAD_OPT: 242 thread = atol (oarg); 243 break; 244 case PENDING_OPT: 245 pending = 1; 246 break; 247 case DISABLE_OPT: 248 enabled = 0; 249 break; 250 case TRACEPOINT_OPT: 251 tracepoint = 1; 252 break; 253 case QUALIFIED_OPT: 254 match_type = symbol_name_match_type::FULL; 255 break; 256 case EXPLICIT_SOURCE_OPT: 257 is_explicit = 1; 258 explicit_loc.source_filename = oarg; 259 break; 260 case EXPLICIT_FUNC_OPT: 261 is_explicit = 1; 262 explicit_loc.function_name = oarg; 263 break; 264 case EXPLICIT_LABEL_OPT: 265 is_explicit = 1; 266 explicit_loc.label_name = oarg; 267 break; 268 case EXPLICIT_LINE_OPT: 269 is_explicit = 1; 270 explicit_loc.line_offset = linespec_parse_line_offset (oarg); 271 break; 272 } 273 } 274 275 if (oind >= argc && !is_explicit) 276 error (_("-%s-insert: Missing <location>"), 277 dprintf ? "dprintf" : "break"); 278 if (dprintf) 279 { 280 int format_num = is_explicit ? oind : oind + 1; 281 282 if (hardware || tracepoint) 283 error (_("-dprintf-insert: does not support -h or -a")); 284 if (format_num >= argc) 285 error (_("-dprintf-insert: Missing <format>")); 286 287 extra_string = mi_argv_to_format (argv + format_num, argc - format_num); 288 address = argv[oind]; 289 } 290 else 291 { 292 if (is_explicit) 293 { 294 if (oind < argc) 295 error (_("-break-insert: Garbage following explicit location")); 296 } 297 else 298 { 299 if (oind < argc - 1) 300 error (_("-break-insert: Garbage following <location>")); 301 address = argv[oind]; 302 } 303 } 304 305 /* Now we have what we need, let's insert the breakpoint! */ 306 scoped_restore restore_breakpoint_reporting = setup_breakpoint_reporting (); 307 308 if (tracepoint) 309 { 310 /* Note that to request a fast tracepoint, the client uses the 311 "hardware" flag, although there's nothing of hardware related to 312 fast tracepoints -- one can implement slow tracepoints with 313 hardware breakpoints, but fast tracepoints are always software. 314 "fast" is a misnomer, actually, "jump" would be more appropriate. 315 A simulator or an emulator could conceivably implement fast 316 regular non-jump based tracepoints. */ 317 type_wanted = hardware ? bp_fast_tracepoint : bp_tracepoint; 318 ops = &tracepoint_breakpoint_ops; 319 } 320 else if (dprintf) 321 { 322 type_wanted = bp_dprintf; 323 ops = &dprintf_breakpoint_ops; 324 } 325 else 326 { 327 type_wanted = hardware ? bp_hardware_breakpoint : bp_breakpoint; 328 ops = &bkpt_breakpoint_ops; 329 } 330 331 if (is_explicit) 332 { 333 /* Error check -- we must have one of the other 334 parameters specified. */ 335 if (explicit_loc.source_filename != NULL 336 && explicit_loc.function_name == NULL 337 && explicit_loc.label_name == NULL 338 && explicit_loc.line_offset.sign == LINE_OFFSET_UNKNOWN) 339 error (_("-%s-insert: --source option requires --function, --label," 340 " or --line"), dprintf ? "dprintf" : "break"); 341 342 explicit_loc.func_name_match_type = match_type; 343 344 location = new_explicit_location (&explicit_loc); 345 } 346 else 347 { 348 location = string_to_event_location_basic (&address, current_language, 349 match_type); 350 if (*address) 351 error (_("Garbage '%s' at end of location"), address); 352 } 353 354 create_breakpoint (get_current_arch (), location.get (), condition, thread, 355 extra_string.c_str (), 356 0 /* condition and thread are valid. */, 357 temp_p, type_wanted, 358 ignore_count, 359 pending ? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE, 360 ops, 0, enabled, 0, 0); 361} 362 363/* Implements the -break-insert command. 364 See the MI manual for the list of possible options. */ 365 366void 367mi_cmd_break_insert (const char *command, char **argv, int argc) 368{ 369 mi_cmd_break_insert_1 (0, command, argv, argc); 370} 371 372/* Implements the -dprintf-insert command. 373 See the MI manual for the list of possible options. */ 374 375void 376mi_cmd_dprintf_insert (const char *command, char **argv, int argc) 377{ 378 mi_cmd_break_insert_1 (1, command, argv, argc); 379} 380 381enum wp_type 382{ 383 REG_WP, 384 READ_WP, 385 ACCESS_WP 386}; 387 388void 389mi_cmd_break_passcount (const char *command, char **argv, int argc) 390{ 391 int n; 392 int p; 393 struct tracepoint *t; 394 395 if (argc != 2) 396 error (_("Usage: tracepoint-number passcount")); 397 398 n = atoi (argv[0]); 399 p = atoi (argv[1]); 400 t = get_tracepoint (n); 401 402 if (t) 403 { 404 t->pass_count = p; 405 gdb::observers::breakpoint_modified.notify (t); 406 } 407 else 408 { 409 error (_("Could not find tracepoint %d"), n); 410 } 411} 412 413/* Insert a watchpoint. The type of watchpoint is specified by the 414 first argument: 415 -break-watch <expr> --> insert a regular wp. 416 -break-watch -r <expr> --> insert a read watchpoint. 417 -break-watch -a <expr> --> insert an access wp. */ 418 419void 420mi_cmd_break_watch (const char *command, char **argv, int argc) 421{ 422 char *expr = NULL; 423 enum wp_type type = REG_WP; 424 enum opt 425 { 426 READ_OPT, ACCESS_OPT 427 }; 428 static const struct mi_opt opts[] = 429 { 430 {"r", READ_OPT, 0}, 431 {"a", ACCESS_OPT, 0}, 432 { 0, 0, 0 } 433 }; 434 435 /* Parse arguments. */ 436 int oind = 0; 437 char *oarg; 438 439 while (1) 440 { 441 int opt = mi_getopt ("-break-watch", argc, argv, 442 opts, &oind, &oarg); 443 444 if (opt < 0) 445 break; 446 switch ((enum opt) opt) 447 { 448 case READ_OPT: 449 type = READ_WP; 450 break; 451 case ACCESS_OPT: 452 type = ACCESS_WP; 453 break; 454 } 455 } 456 if (oind >= argc) 457 error (_("-break-watch: Missing <expression>")); 458 if (oind < argc - 1) 459 error (_("-break-watch: Garbage following <expression>")); 460 expr = argv[oind]; 461 462 /* Now we have what we need, let's insert the watchpoint! */ 463 switch (type) 464 { 465 case REG_WP: 466 watch_command_wrapper (expr, FROM_TTY, 0); 467 break; 468 case READ_WP: 469 rwatch_command_wrapper (expr, FROM_TTY, 0); 470 break; 471 case ACCESS_WP: 472 awatch_command_wrapper (expr, FROM_TTY, 0); 473 break; 474 default: 475 error (_("-break-watch: Unknown watchpoint type.")); 476 } 477} 478 479void 480mi_cmd_break_commands (const char *command, char **argv, int argc) 481{ 482 counted_command_line break_command; 483 char *endptr; 484 int bnum; 485 struct breakpoint *b; 486 487 if (argc < 1) 488 error (_("USAGE: %s <BKPT> [<COMMAND> [<COMMAND>...]]"), command); 489 490 bnum = strtol (argv[0], &endptr, 0); 491 if (endptr == argv[0]) 492 error (_("breakpoint number argument \"%s\" is not a number."), 493 argv[0]); 494 else if (*endptr != '\0') 495 error (_("junk at the end of breakpoint number argument \"%s\"."), 496 argv[0]); 497 498 b = get_breakpoint (bnum); 499 if (b == NULL) 500 error (_("breakpoint %d not found."), bnum); 501 502 int count = 1; 503 auto reader 504 = [&] () 505 { 506 const char *result = nullptr; 507 if (count < argc) 508 result = argv[count++]; 509 return result; 510 }; 511 512 if (is_tracepoint (b)) 513 break_command = read_command_lines_1 (reader, 1, 514 [=] (const char *line) 515 { 516 validate_actionline (line, b); 517 }); 518 else 519 break_command = read_command_lines_1 (reader, 1, 0); 520 521 breakpoint_set_commands (b, std::move (break_command)); 522} 523 524