1 /* MI Command Set - breakpoint and watchpoint commands. 2 Copyright (C) 2000-2019 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 37 enum 38 { 39 FROM_TTY = 0 40 }; 41 42 /* True if MI breakpoint observers have been registered. */ 43 44 static int mi_breakpoint_observers_installed; 45 46 /* Control whether breakpoint_notify may act. */ 47 48 static int mi_can_breakpoint_notify; 49 50 /* Output a single breakpoint, when allowed. */ 51 52 static void 53 breakpoint_notify (struct breakpoint *b) 54 { 55 if (mi_can_breakpoint_notify) 56 { 57 TRY 58 { 59 print_breakpoint (b); 60 } 61 CATCH (ex, RETURN_MASK_ALL) 62 { 63 exception_print (gdb_stderr, ex); 64 } 65 END_CATCH 66 } 67 } 68 69 enum bp_type 70 { 71 REG_BP, 72 HW_BP, 73 REGEXP_BP 74 }; 75 76 /* Arrange for all new breakpoints and catchpoints to be reported to 77 CURRENT_UIOUT until the destructor of the returned scoped_restore 78 is run. 79 80 Note that MI output will be probably invalid if more than one 81 breakpoint is created inside one MI command. */ 82 83 scoped_restore_tmpl<int> 84 setup_breakpoint_reporting (void) 85 { 86 if (! mi_breakpoint_observers_installed) 87 { 88 gdb::observers::breakpoint_created.attach (breakpoint_notify); 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 99 static std::string 100 mi_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 168 static void 169 mi_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 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 EXPLICIT_SOURCE_OPT, EXPLICIT_FUNC_OPT, 193 EXPLICIT_LABEL_OPT, EXPLICIT_LINE_OPT 194 }; 195 static const struct mi_opt opts[] = 196 { 197 {"h", HARDWARE_OPT, 0}, 198 {"t", TEMP_OPT, 0}, 199 {"c", CONDITION_OPT, 1}, 200 {"i", IGNORE_COUNT_OPT, 1}, 201 {"p", THREAD_OPT, 1}, 202 {"f", PENDING_OPT, 0}, 203 {"d", DISABLE_OPT, 0}, 204 {"a", TRACEPOINT_OPT, 0}, 205 {"-source" , EXPLICIT_SOURCE_OPT, 1}, 206 {"-function", EXPLICIT_FUNC_OPT, 1}, 207 {"-label", EXPLICIT_LABEL_OPT, 1}, 208 {"-line", EXPLICIT_LINE_OPT, 1}, 209 { 0, 0, 0 } 210 }; 211 212 /* Parse arguments. It could be -r or -h or -t, <location> or ``--'' 213 to denote the end of the option list. */ 214 int oind = 0; 215 char *oarg; 216 217 initialize_explicit_location (&explicit_loc); 218 219 while (1) 220 { 221 int opt = mi_getopt ("-break-insert", argc, argv, 222 opts, &oind, &oarg); 223 if (opt < 0) 224 break; 225 switch ((enum opt) opt) 226 { 227 case TEMP_OPT: 228 temp_p = 1; 229 break; 230 case HARDWARE_OPT: 231 hardware = 1; 232 break; 233 case CONDITION_OPT: 234 condition = oarg; 235 break; 236 case IGNORE_COUNT_OPT: 237 ignore_count = atol (oarg); 238 break; 239 case THREAD_OPT: 240 thread = atol (oarg); 241 break; 242 case PENDING_OPT: 243 pending = 1; 244 break; 245 case DISABLE_OPT: 246 enabled = 0; 247 break; 248 case TRACEPOINT_OPT: 249 tracepoint = 1; 250 break; 251 case EXPLICIT_SOURCE_OPT: 252 is_explicit = 1; 253 explicit_loc.source_filename = oarg; 254 break; 255 case EXPLICIT_FUNC_OPT: 256 is_explicit = 1; 257 explicit_loc.function_name = oarg; 258 break; 259 case EXPLICIT_LABEL_OPT: 260 is_explicit = 1; 261 explicit_loc.label_name = oarg; 262 break; 263 case EXPLICIT_LINE_OPT: 264 is_explicit = 1; 265 explicit_loc.line_offset = linespec_parse_line_offset (oarg); 266 break; 267 } 268 } 269 270 if (oind >= argc && !is_explicit) 271 error (_("-%s-insert: Missing <location>"), 272 dprintf ? "dprintf" : "break"); 273 if (dprintf) 274 { 275 int format_num = is_explicit ? oind : oind + 1; 276 277 if (hardware || tracepoint) 278 error (_("-dprintf-insert: does not support -h or -a")); 279 if (format_num >= argc) 280 error (_("-dprintf-insert: Missing <format>")); 281 282 extra_string = mi_argv_to_format (argv + format_num, argc - format_num); 283 address = argv[oind]; 284 } 285 else 286 { 287 if (is_explicit) 288 { 289 if (oind < argc) 290 error (_("-break-insert: Garbage following explicit location")); 291 } 292 else 293 { 294 if (oind < argc - 1) 295 error (_("-break-insert: Garbage following <location>")); 296 address = argv[oind]; 297 } 298 } 299 300 /* Now we have what we need, let's insert the breakpoint! */ 301 scoped_restore restore_breakpoint_reporting = setup_breakpoint_reporting (); 302 303 if (tracepoint) 304 { 305 /* Note that to request a fast tracepoint, the client uses the 306 "hardware" flag, although there's nothing of hardware related to 307 fast tracepoints -- one can implement slow tracepoints with 308 hardware breakpoints, but fast tracepoints are always software. 309 "fast" is a misnomer, actually, "jump" would be more appropriate. 310 A simulator or an emulator could conceivably implement fast 311 regular non-jump based tracepoints. */ 312 type_wanted = hardware ? bp_fast_tracepoint : bp_tracepoint; 313 ops = &tracepoint_breakpoint_ops; 314 } 315 else if (dprintf) 316 { 317 type_wanted = bp_dprintf; 318 ops = &dprintf_breakpoint_ops; 319 } 320 else 321 { 322 type_wanted = hardware ? bp_hardware_breakpoint : bp_breakpoint; 323 ops = &bkpt_breakpoint_ops; 324 } 325 326 if (is_explicit) 327 { 328 /* Error check -- we must have one of the other 329 parameters specified. */ 330 if (explicit_loc.source_filename != NULL 331 && explicit_loc.function_name == NULL 332 && explicit_loc.label_name == NULL 333 && explicit_loc.line_offset.sign == LINE_OFFSET_UNKNOWN) 334 error (_("-%s-insert: --source option requires --function, --label," 335 " or --line"), dprintf ? "dprintf" : "break"); 336 337 location = new_explicit_location (&explicit_loc); 338 } 339 else 340 { 341 location = string_to_event_location_basic (&address, current_language, 342 symbol_name_match_type::WILD); 343 if (*address) 344 error (_("Garbage '%s' at end of location"), address); 345 } 346 347 create_breakpoint (get_current_arch (), location.get (), condition, thread, 348 extra_string.c_str (), 349 0 /* condition and thread are valid. */, 350 temp_p, type_wanted, 351 ignore_count, 352 pending ? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE, 353 ops, 0, enabled, 0, 0); 354 } 355 356 /* Implements the -break-insert command. 357 See the MI manual for the list of possible options. */ 358 359 void 360 mi_cmd_break_insert (const char *command, char **argv, int argc) 361 { 362 mi_cmd_break_insert_1 (0, command, argv, argc); 363 } 364 365 /* Implements the -dprintf-insert command. 366 See the MI manual for the list of possible options. */ 367 368 void 369 mi_cmd_dprintf_insert (const char *command, char **argv, int argc) 370 { 371 mi_cmd_break_insert_1 (1, command, argv, argc); 372 } 373 374 enum wp_type 375 { 376 REG_WP, 377 READ_WP, 378 ACCESS_WP 379 }; 380 381 void 382 mi_cmd_break_passcount (const char *command, char **argv, int argc) 383 { 384 int n; 385 int p; 386 struct tracepoint *t; 387 388 if (argc != 2) 389 error (_("Usage: tracepoint-number passcount")); 390 391 n = atoi (argv[0]); 392 p = atoi (argv[1]); 393 t = get_tracepoint (n); 394 395 if (t) 396 { 397 t->pass_count = p; 398 gdb::observers::breakpoint_modified.notify (t); 399 } 400 else 401 { 402 error (_("Could not find tracepoint %d"), n); 403 } 404 } 405 406 /* Insert a watchpoint. The type of watchpoint is specified by the 407 first argument: 408 -break-watch <expr> --> insert a regular wp. 409 -break-watch -r <expr> --> insert a read watchpoint. 410 -break-watch -a <expr> --> insert an access wp. */ 411 412 void 413 mi_cmd_break_watch (const char *command, char **argv, int argc) 414 { 415 char *expr = NULL; 416 enum wp_type type = REG_WP; 417 enum opt 418 { 419 READ_OPT, ACCESS_OPT 420 }; 421 static const struct mi_opt opts[] = 422 { 423 {"r", READ_OPT, 0}, 424 {"a", ACCESS_OPT, 0}, 425 { 0, 0, 0 } 426 }; 427 428 /* Parse arguments. */ 429 int oind = 0; 430 char *oarg; 431 432 while (1) 433 { 434 int opt = mi_getopt ("-break-watch", argc, argv, 435 opts, &oind, &oarg); 436 437 if (opt < 0) 438 break; 439 switch ((enum opt) opt) 440 { 441 case READ_OPT: 442 type = READ_WP; 443 break; 444 case ACCESS_OPT: 445 type = ACCESS_WP; 446 break; 447 } 448 } 449 if (oind >= argc) 450 error (_("-break-watch: Missing <expression>")); 451 if (oind < argc - 1) 452 error (_("-break-watch: Garbage following <expression>")); 453 expr = argv[oind]; 454 455 /* Now we have what we need, let's insert the watchpoint! */ 456 switch (type) 457 { 458 case REG_WP: 459 watch_command_wrapper (expr, FROM_TTY, 0); 460 break; 461 case READ_WP: 462 rwatch_command_wrapper (expr, FROM_TTY, 0); 463 break; 464 case ACCESS_WP: 465 awatch_command_wrapper (expr, FROM_TTY, 0); 466 break; 467 default: 468 error (_("-break-watch: Unknown watchpoint type.")); 469 } 470 } 471 472 void 473 mi_cmd_break_commands (const char *command, char **argv, int argc) 474 { 475 counted_command_line break_command; 476 char *endptr; 477 int bnum; 478 struct breakpoint *b; 479 480 if (argc < 1) 481 error (_("USAGE: %s <BKPT> [<COMMAND> [<COMMAND>...]]"), command); 482 483 bnum = strtol (argv[0], &endptr, 0); 484 if (endptr == argv[0]) 485 error (_("breakpoint number argument \"%s\" is not a number."), 486 argv[0]); 487 else if (*endptr != '\0') 488 error (_("junk at the end of breakpoint number argument \"%s\"."), 489 argv[0]); 490 491 b = get_breakpoint (bnum); 492 if (b == NULL) 493 error (_("breakpoint %d not found."), bnum); 494 495 int count = 1; 496 auto reader 497 = [&] () 498 { 499 const char *result = nullptr; 500 if (count < argc) 501 result = argv[count++]; 502 return result; 503 }; 504 505 if (is_tracepoint (b)) 506 break_command = read_command_lines_1 (reader, 1, 507 [=] (const char *line) 508 { 509 validate_actionline (line, b); 510 }); 511 else 512 break_command = read_command_lines_1 (reader, 1, 0); 513 514 breakpoint_set_commands (b, std::move (break_command)); 515 } 516 517