| 1 | /* Skipping uninteresting files and functions while stepping. |
| 2 | |
| 3 | Copyright (C) 2011-2012 Free Software Foundation, Inc. |
| 4 | |
| 5 | This program is free software; you can redistribute it and/or modify |
| 6 | it under the terms of the GNU General Public License as published by |
| 7 | the Free Software Foundation; either version 3 of the License, or |
| 8 | (at your option) any later version. |
| 9 | |
| 10 | This program is distributed in the hope that it will be useful, |
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | GNU General Public License for more details. |
| 14 | |
| 15 | You should have received a copy of the GNU General Public License |
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| 17 | |
| 18 | #include "defs.h" |
| 19 | #include "skip.h" |
| 20 | #include "value.h" |
| 21 | #include "valprint.h" |
| 22 | #include "ui-out.h" |
| 23 | #include "gdb_string.h" |
| 24 | #include "symtab.h" |
| 25 | #include "gdbcmd.h" |
| 26 | #include "command.h" |
| 27 | #include "completer.h" |
| 28 | #include "stack.h" |
| 29 | #include "cli/cli-utils.h" |
| 30 | #include "arch-utils.h" |
| 31 | #include "linespec.h" |
| 32 | #include "objfiles.h" |
| 33 | #include "exceptions.h" |
| 34 | #include "breakpoint.h" /* for get_sal_arch () */ |
| 35 | |
| 36 | struct skiplist_entry |
| 37 | { |
| 38 | int number; |
| 39 | |
| 40 | /* NULL if this isn't a skiplist entry for an entire file. |
| 41 | The skiplist entry owns this pointer. */ |
| 42 | char *filename; |
| 43 | |
| 44 | /* The name of the marked-for-skip function, if this is a skiplist |
| 45 | entry for a function. Note that this might be non-null even if |
| 46 | the pc is 0 if the entry is pending a shared library load. |
| 47 | |
| 48 | The skiplist entry owns this pointer. */ |
| 49 | char *function_name; |
| 50 | |
| 51 | /* 0 if this is a skiplist entry for an entire file, or if this |
| 52 | entry will be on a function, pending a shared library load. */ |
| 53 | CORE_ADDR pc; |
| 54 | |
| 55 | /* Architecture we used to create the skiplist entry. May be null |
| 56 | if the entry is pending a shared library load. */ |
| 57 | struct gdbarch *gdbarch; |
| 58 | |
| 59 | int enabled; |
| 60 | int pending; |
| 61 | |
| 62 | struct skiplist_entry *next; |
| 63 | }; |
| 64 | |
| 65 | static void skip_function_command (char *arg, int from_tty); |
| 66 | static void skip_file_command (char *arg, int from_tty); |
| 67 | static void skip_info (char *arg, int from_tty); |
| 68 | |
| 69 | static void add_skiplist_entry (struct skiplist_entry *e); |
| 70 | static void skip_function_pc (CORE_ADDR pc, const char *name, |
| 71 | struct gdbarch *arch, |
| 72 | int pending); |
| 73 | |
| 74 | static struct skiplist_entry *skiplist_entry_chain; |
| 75 | static int skiplist_entry_count; |
| 76 | |
| 77 | #define ALL_SKIPLIST_ENTRIES(E) \ |
| 78 | for (E = skiplist_entry_chain; E; E = E->next) |
| 79 | |
| 80 | #define ALL_SKIPLIST_ENTRIES_SAFE(E,TMP) \ |
| 81 | for (E = skiplist_entry_chain; \ |
| 82 | E ? (TMP = E->next, 1) : 0; \ |
| 83 | E = TMP) |
| 84 | |
| 85 | static void |
| 86 | skip_file_command (char *arg, int from_tty) |
| 87 | { |
| 88 | struct skiplist_entry *e; |
| 89 | struct symtab *symtab; |
| 90 | int pending = 0; |
| 91 | char *filename = 0; |
| 92 | |
| 93 | /* If no argument was given, try to default to the last |
| 94 | displayed codepoint. */ |
| 95 | if (arg == 0) |
| 96 | { |
| 97 | symtab = get_last_displayed_symtab (); |
| 98 | if (symtab == 0) |
| 99 | error (_("No default file now.")); |
| 100 | else |
| 101 | filename = symtab->filename; |
| 102 | } |
| 103 | else |
| 104 | { |
| 105 | symtab = lookup_symtab (arg); |
| 106 | if (symtab == 0) |
| 107 | { |
| 108 | fprintf_filtered (gdb_stderr, _("No source file named %s.\n"), arg); |
| 109 | if (!nquery (_("\ |
| 110 | Ignore file pending future shared library load? "))) |
| 111 | return; |
| 112 | |
| 113 | pending = 1; |
| 114 | filename = arg; |
| 115 | } |
| 116 | else |
| 117 | filename = symtab->filename; |
| 118 | } |
| 119 | |
| 120 | e = XZALLOC (struct skiplist_entry); |
| 121 | e->filename = xstrdup (filename); |
| 122 | e->enabled = 1; |
| 123 | e->pending = pending; |
| 124 | if (symtab != 0) |
| 125 | e->gdbarch = get_objfile_arch (symtab->objfile); |
| 126 | |
| 127 | add_skiplist_entry (e); |
| 128 | |
| 129 | printf_filtered (_("File %s will be skipped when stepping.\n"), filename); |
| 130 | } |
| 131 | |
| 132 | static void |
| 133 | skip_function_command (char *arg, int from_tty) |
| 134 | { |
| 135 | CORE_ADDR func_pc; |
| 136 | const char *name = NULL; |
| 137 | |
| 138 | /* Default to the current function if no argument is given. */ |
| 139 | if (arg == 0) |
| 140 | { |
| 141 | CORE_ADDR pc; |
| 142 | if (!last_displayed_sal_is_valid ()) |
| 143 | error (_("No default function now.")); |
| 144 | |
| 145 | pc = get_last_displayed_addr (); |
| 146 | if (!find_pc_partial_function (pc, &name, &func_pc, 0)) |
| 147 | { |
| 148 | error (_("No function found containing current program point %s."), |
| 149 | paddress (get_current_arch (), pc)); |
| 150 | } |
| 151 | skip_function_pc (func_pc, name, get_current_arch (), 0); |
| 152 | } |
| 153 | else |
| 154 | { |
| 155 | /* Decode arg. We set funfirstline=1 so decode_line_1 will give us the |
| 156 | first line of the function specified, if it can, and so that we'll |
| 157 | reject variable names and the like. */ |
| 158 | char *orig_arg = arg; /* decode_line_1 modifies the arg pointer. */ |
| 159 | volatile struct gdb_exception decode_exception; |
| 160 | struct symtabs_and_lines sals = { 0 }; |
| 161 | |
| 162 | TRY_CATCH (decode_exception, RETURN_MASK_ERROR) |
| 163 | { |
| 164 | sals = decode_line_1 (&arg, DECODE_LINE_FUNFIRSTLINE, 0, 0); |
| 165 | } |
| 166 | |
| 167 | if (decode_exception.reason < 0) |
| 168 | { |
| 169 | if (decode_exception.error != NOT_FOUND_ERROR) |
| 170 | throw_exception (decode_exception); |
| 171 | |
| 172 | fprintf_filtered (gdb_stderr, |
| 173 | _("No function found named %s.\n"), orig_arg); |
| 174 | |
| 175 | if (nquery (_("\ |
| 176 | Ignore function pending future shared library load? "))) |
| 177 | { |
| 178 | /* Add the pending skiplist entry. */ |
| 179 | skip_function_pc (0, orig_arg, 0, 1); |
| 180 | } |
| 181 | |
| 182 | return; |
| 183 | } |
| 184 | |
| 185 | if (sals.nelts > 1) |
| 186 | error (_("Specify just one function at a time.")); |
| 187 | if (strlen (arg) != 0) |
| 188 | error (_("Junk at end of arguments.")); |
| 189 | |
| 190 | /* The pc decode_line_1 gives us is the first line of the function, |
| 191 | but we actually want the line before that. The call to |
| 192 | find_pc_partial_function gets us the value we actually want. */ |
| 193 | { |
| 194 | struct symtab_and_line sal = sals.sals[0]; |
| 195 | CORE_ADDR pc = sal.pc; |
| 196 | CORE_ADDR func_start = 0; |
| 197 | struct gdbarch *arch = get_sal_arch (sal); |
| 198 | |
| 199 | if (!find_pc_partial_function (pc, &name, &func_start, 0)) |
| 200 | { |
| 201 | error (_("No function found containing program point %s."), |
| 202 | paddress (arch, pc)); |
| 203 | } |
| 204 | |
| 205 | skip_function_pc (func_start, name, arch, 0); |
| 206 | } |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | static void |
| 211 | skip_info (char *arg, int from_tty) |
| 212 | { |
| 213 | struct skiplist_entry *e; |
| 214 | int num_printable_entries = 0; |
| 215 | int address_width = 10; |
| 216 | struct value_print_options opts; |
| 217 | struct cleanup *tbl_chain; |
| 218 | |
| 219 | get_user_print_options (&opts); |
| 220 | |
| 221 | /* Count the number of rows in the table and see if we need space for a |
| 222 | 64-bit address anywhere. */ |
| 223 | ALL_SKIPLIST_ENTRIES (e) |
| 224 | if (arg == 0 || number_is_in_list (arg, e->number)) |
| 225 | { |
| 226 | num_printable_entries++; |
| 227 | if (e->gdbarch && gdbarch_addr_bit (e->gdbarch) > 32) |
| 228 | address_width = 18; |
| 229 | } |
| 230 | |
| 231 | if (num_printable_entries == 0) |
| 232 | { |
| 233 | if (arg == 0) |
| 234 | ui_out_message (current_uiout, 0, _("\ |
| 235 | Not skipping any files or functions.\n")); |
| 236 | else |
| 237 | ui_out_message (current_uiout, 0, |
| 238 | _("No skiplist entries found with number %s.\n"), arg); |
| 239 | |
| 240 | return; |
| 241 | } |
| 242 | |
| 243 | if (opts.addressprint) |
| 244 | tbl_chain = make_cleanup_ui_out_table_begin_end (current_uiout, 5, |
| 245 | num_printable_entries, |
| 246 | "SkiplistTable"); |
| 247 | else |
| 248 | tbl_chain |
| 249 | = make_cleanup_ui_out_table_begin_end (current_uiout, 4, |
| 250 | num_printable_entries, |
| 251 | "SkiplistTable"); |
| 252 | |
| 253 | ui_out_table_header (current_uiout, 7, ui_left, "number", "Num"); /* 1 */ |
| 254 | ui_out_table_header (current_uiout, 14, ui_left, "type", "Type"); /* 2 */ |
| 255 | ui_out_table_header (current_uiout, 3, ui_left, "enabled", "Enb"); /* 3 */ |
| 256 | if (opts.addressprint) |
| 257 | { |
| 258 | ui_out_table_header (current_uiout, address_width, ui_left, |
| 259 | "addr", "Address"); /* 4 */ |
| 260 | } |
| 261 | ui_out_table_header (current_uiout, 40, ui_noalign, "what", "What"); /* 5 */ |
| 262 | ui_out_table_body (current_uiout); |
| 263 | |
| 264 | ALL_SKIPLIST_ENTRIES (e) |
| 265 | { |
| 266 | struct cleanup *entry_chain; |
| 267 | |
| 268 | QUIT; |
| 269 | if (arg != 0 && !number_is_in_list (arg, e->number)) |
| 270 | continue; |
| 271 | |
| 272 | entry_chain = make_cleanup_ui_out_tuple_begin_end (current_uiout, |
| 273 | "blklst-entry"); |
| 274 | ui_out_field_int (current_uiout, "number", e->number); /* 1 */ |
| 275 | |
| 276 | if (e->function_name != 0) |
| 277 | ui_out_field_string (current_uiout, "type", "function"); /* 2 */ |
| 278 | else if (e->filename != 0) |
| 279 | ui_out_field_string (current_uiout, "type", "file"); /* 2 */ |
| 280 | else |
| 281 | internal_error (__FILE__, __LINE__, _("\ |
| 282 | Skiplist entry should have either a filename or a function name.")); |
| 283 | |
| 284 | if (e->enabled) |
| 285 | ui_out_field_string (current_uiout, "enabled", "y"); /* 3 */ |
| 286 | else |
| 287 | ui_out_field_string (current_uiout, "enabled", "n"); /* 3 */ |
| 288 | |
| 289 | if (opts.addressprint) |
| 290 | { |
| 291 | if (e->pc != 0) |
| 292 | ui_out_field_core_addr (current_uiout, "addr", |
| 293 | e->gdbarch, e->pc); /* 4 */ |
| 294 | else |
| 295 | ui_out_field_string (current_uiout, "addr", ""); /* 4 */ |
| 296 | } |
| 297 | |
| 298 | if (!e->pending && e->function_name != 0) |
| 299 | { |
| 300 | struct symbol *sym; |
| 301 | |
| 302 | gdb_assert (e->pc != 0); |
| 303 | sym = find_pc_function (e->pc); |
| 304 | if (sym) |
| 305 | ui_out_field_fmt (current_uiout, "what", "%s at %s:%d", |
| 306 | sym->ginfo.name, |
| 307 | sym->symtab->filename, |
| 308 | sym->line); |
| 309 | else |
| 310 | ui_out_field_string (current_uiout, "what", "?"); |
| 311 | } |
| 312 | else if (e->pending && e->function_name != 0) |
| 313 | { |
| 314 | ui_out_field_fmt (current_uiout, "what", "%s (PENDING)", |
| 315 | e->function_name); |
| 316 | } |
| 317 | else if (!e->pending && e->filename != 0) |
| 318 | ui_out_field_string (current_uiout, "what", e->filename); |
| 319 | else if (e->pending && e->filename != 0) |
| 320 | ui_out_field_fmt (current_uiout, "what", "%s (PENDING)", |
| 321 | e->filename); |
| 322 | |
| 323 | ui_out_text (current_uiout, "\n"); |
| 324 | do_cleanups (entry_chain); |
| 325 | } |
| 326 | |
| 327 | do_cleanups (tbl_chain); |
| 328 | } |
| 329 | |
| 330 | static void |
| 331 | skip_enable_command (char *arg, int from_tty) |
| 332 | { |
| 333 | struct skiplist_entry *e; |
| 334 | int found = 0; |
| 335 | |
| 336 | ALL_SKIPLIST_ENTRIES (e) |
| 337 | if (arg == 0 || number_is_in_list (arg, e->number)) |
| 338 | { |
| 339 | e->enabled = 1; |
| 340 | found = 1; |
| 341 | } |
| 342 | |
| 343 | if (!found) |
| 344 | error (_("No skiplist entries found with number %s."), arg); |
| 345 | } |
| 346 | |
| 347 | static void |
| 348 | skip_disable_command (char *arg, int from_tty) |
| 349 | { |
| 350 | struct skiplist_entry *e; |
| 351 | int found = 0; |
| 352 | |
| 353 | ALL_SKIPLIST_ENTRIES (e) |
| 354 | if (arg == 0 || number_is_in_list (arg, e->number)) |
| 355 | { |
| 356 | e->enabled = 0; |
| 357 | found = 1; |
| 358 | } |
| 359 | |
| 360 | if (!found) |
| 361 | error (_("No skiplist entries found with number %s."), arg); |
| 362 | } |
| 363 | |
| 364 | static void |
| 365 | skip_delete_command (char *arg, int from_tty) |
| 366 | { |
| 367 | struct skiplist_entry *e, *temp, *b_prev; |
| 368 | int found = 0; |
| 369 | |
| 370 | b_prev = 0; |
| 371 | ALL_SKIPLIST_ENTRIES_SAFE (e, temp) |
| 372 | if (arg == 0 || number_is_in_list (arg, e->number)) |
| 373 | { |
| 374 | if (b_prev != 0) |
| 375 | b_prev->next = e->next; |
| 376 | else |
| 377 | skiplist_entry_chain = e->next; |
| 378 | |
| 379 | xfree (e->function_name); |
| 380 | xfree (e->filename); |
| 381 | xfree (e); |
| 382 | found = 1; |
| 383 | } |
| 384 | else |
| 385 | { |
| 386 | b_prev = e; |
| 387 | } |
| 388 | |
| 389 | if (!found) |
| 390 | error (_("No skiplist entries found with number %s."), arg); |
| 391 | } |
| 392 | |
| 393 | /* Create a skiplist entry for the given pc corresponding to the given |
| 394 | function name and add it to the list. */ |
| 395 | |
| 396 | static void |
| 397 | skip_function_pc (CORE_ADDR pc, const char *name, struct gdbarch *arch, |
| 398 | int pending) |
| 399 | { |
| 400 | struct skiplist_entry *e = XZALLOC (struct skiplist_entry); |
| 401 | |
| 402 | e->pc = pc; |
| 403 | e->gdbarch = arch; |
| 404 | e->enabled = 1; |
| 405 | e->pending = pending; |
| 406 | e->function_name = xstrdup (name); |
| 407 | |
| 408 | add_skiplist_entry (e); |
| 409 | |
| 410 | if (!pending) |
| 411 | printf_filtered (_("Function %s at %s will be skipped when stepping.\n"), |
| 412 | name, paddress (get_current_arch (), pc)); |
| 413 | else |
| 414 | printf_filtered (_("Function %s will be skipped when stepping, " |
| 415 | "pending shared library load.\n"), |
| 416 | name); |
| 417 | } |
| 418 | |
| 419 | /* Add the given skiplist entry to our list, and set the entry's number. */ |
| 420 | |
| 421 | static void |
| 422 | add_skiplist_entry (struct skiplist_entry *e) |
| 423 | { |
| 424 | struct skiplist_entry *e1; |
| 425 | |
| 426 | e->number = ++skiplist_entry_count; |
| 427 | |
| 428 | /* Add to the end of the chain so that the list of |
| 429 | skiplist entries will be in numerical order. */ |
| 430 | |
| 431 | e1 = skiplist_entry_chain; |
| 432 | if (e1 == 0) |
| 433 | skiplist_entry_chain = e; |
| 434 | else |
| 435 | { |
| 436 | while (e1->next) |
| 437 | e1 = e1->next; |
| 438 | e1->next = e; |
| 439 | } |
| 440 | } |
| 441 | |
| 442 | /* Does the given pc correspond to the beginning of a skipped function? */ |
| 443 | |
| 444 | int |
| 445 | function_pc_is_marked_for_skip (CORE_ADDR pc) |
| 446 | { |
| 447 | int searched_for_sal = 0; |
| 448 | struct symtab_and_line sal; |
| 449 | char *filename = NULL; |
| 450 | struct skiplist_entry *e; |
| 451 | |
| 452 | ALL_SKIPLIST_ENTRIES (e) |
| 453 | { |
| 454 | if (!e->enabled || e->pending) |
| 455 | continue; |
| 456 | |
| 457 | /* Does the pc we're stepping into match e's stored pc? */ |
| 458 | if (e->pc != 0 && pc == e->pc) |
| 459 | return 1; |
| 460 | |
| 461 | if (e->filename != 0) |
| 462 | { |
| 463 | /* Get the filename corresponding to this pc, if we haven't |
| 464 | * yet. */ |
| 465 | if (!searched_for_sal) |
| 466 | { |
| 467 | sal = find_pc_line (pc, 0); |
| 468 | if (sal.symtab != 0) |
| 469 | filename = sal.symtab->filename; |
| 470 | searched_for_sal = 1; |
| 471 | } |
| 472 | if (filename != 0 && strcmp (filename, e->filename) == 0) |
| 473 | return 1; |
| 474 | } |
| 475 | } |
| 476 | |
| 477 | return 0; |
| 478 | } |
| 479 | |
| 480 | /* Re-set the skip list after symbols have been re-loaded. */ |
| 481 | void |
| 482 | skip_re_set (void) |
| 483 | { |
| 484 | struct skiplist_entry *e; |
| 485 | |
| 486 | ALL_SKIPLIST_ENTRIES (e) |
| 487 | { |
| 488 | if (e->filename != 0) |
| 489 | { |
| 490 | /* If it's an entry telling us to skip a file, but the entry is |
| 491 | currently pending a solib load, let's see if we now know |
| 492 | about the file. */ |
| 493 | struct symtab *symtab = lookup_symtab (e->filename); |
| 494 | if (symtab != 0) |
| 495 | { |
| 496 | xfree (e->filename); |
| 497 | e->filename = xstrdup (symtab->filename); |
| 498 | e->gdbarch = get_objfile_arch (symtab->objfile); |
| 499 | e->pending = 0; |
| 500 | } |
| 501 | else |
| 502 | { |
| 503 | e->pending = 1; |
| 504 | } |
| 505 | } |
| 506 | else if (e->function_name != 0) |
| 507 | { |
| 508 | char *func_name = e->function_name; |
| 509 | struct symtabs_and_lines sals = { 0 }; |
| 510 | volatile struct gdb_exception decode_exception; |
| 511 | |
| 512 | TRY_CATCH (decode_exception, RETURN_MASK_ERROR) |
| 513 | { |
| 514 | sals = decode_line_1 (&func_name, DECODE_LINE_FUNFIRSTLINE, 0, 0); |
| 515 | } |
| 516 | |
| 517 | if (decode_exception.reason >= 0 |
| 518 | && sals.nelts == 1 && strlen (func_name) == 0) |
| 519 | { |
| 520 | struct symtab_and_line sal = sals.sals[0]; |
| 521 | CORE_ADDR pc = sal.pc; |
| 522 | CORE_ADDR func_start = 0; |
| 523 | struct gdbarch *arch = get_sal_arch (sal); |
| 524 | const char *func_name; |
| 525 | |
| 526 | if (find_pc_partial_function (pc, &func_name, &func_start, 0)) |
| 527 | { |
| 528 | e->pending = 0; |
| 529 | e->function_name = xstrdup (func_name); |
| 530 | e->pc = func_start; |
| 531 | e->gdbarch = arch; |
| 532 | } |
| 533 | } |
| 534 | else |
| 535 | { |
| 536 | e->pending = 1; |
| 537 | } |
| 538 | } |
| 539 | } |
| 540 | } |
| 541 | |
| 542 | /* Provide a prototype to silence -Wmissing-prototypes. */ |
| 543 | extern initialize_file_ftype _initialize_step_skip; |
| 544 | |
| 545 | void |
| 546 | _initialize_step_skip (void) |
| 547 | { |
| 548 | static struct cmd_list_element *skiplist = NULL; |
| 549 | struct cmd_list_element *c; |
| 550 | |
| 551 | skiplist_entry_chain = 0; |
| 552 | skiplist_entry_count = 0; |
| 553 | |
| 554 | add_prefix_cmd ("skip", class_breakpoint, skip_function_command, _("\ |
| 555 | Ignore a function while stepping.\n\ |
| 556 | Usage: skip [FUNCTION NAME]\n\ |
| 557 | If no function name is given, ignore the current function."), |
| 558 | &skiplist, "skip ", 1, &cmdlist); |
| 559 | |
| 560 | c = add_cmd ("file", class_breakpoint, skip_file_command, _("\ |
| 561 | Ignore a file while stepping.\n\ |
| 562 | Usage: skip file [FILENAME]\n\ |
| 563 | If no filename is given, ignore the current file."), |
| 564 | &skiplist); |
| 565 | set_cmd_completer (c, filename_completer); |
| 566 | |
| 567 | c = add_cmd ("function", class_breakpoint, skip_function_command, _("\ |
| 568 | Ignore a function while stepping.\n\ |
| 569 | Usage: skip function [FUNCTION NAME]\n\ |
| 570 | If no function name is given, skip the current function."), |
| 571 | &skiplist); |
| 572 | set_cmd_completer (c, location_completer); |
| 573 | |
| 574 | add_cmd ("enable", class_breakpoint, skip_enable_command, _("\ |
| 575 | Enable skip entries. You can specify numbers (e.g. \"skip enable 1 3\"), \ |
| 576 | ranges (e.g. \"skip enable 4-8\"), or both (e.g. \"skip enable 1 3 4-8\").\n\n\ |
| 577 | If you don't specify any numbers or ranges, we'll enable all skip entries.\n\n\ |
| 578 | Usage: skip enable [NUMBERS AND/OR RANGES]"), |
| 579 | &skiplist); |
| 580 | |
| 581 | add_cmd ("disable", class_breakpoint, skip_disable_command, _("\ |
| 582 | Disable skip entries. You can specify numbers (e.g. \"skip disable 1 3\"), \ |
| 583 | ranges (e.g. \"skip disable 4-8\"), or both (e.g. \"skip disable 1 3 4-8\").\n\n\ |
| 584 | If you don't specify any numbers or ranges, we'll disable all skip entries.\n\n\ |
| 585 | Usage: skip disable [NUMBERS AND/OR RANGES]"), |
| 586 | &skiplist); |
| 587 | |
| 588 | add_cmd ("delete", class_breakpoint, skip_delete_command, _("\ |
| 589 | Delete skip entries. You can specify numbers (e.g. \"skip delete 1 3\"), \ |
| 590 | ranges (e.g. \"skip delete 4-8\"), or both (e.g. \"skip delete 1 3 4-8\").\n\n\ |
| 591 | If you don't specify any numbers or ranges, we'll delete all skip entries.\n\n\ |
| 592 | Usage: skip delete [NUMBERS AND/OR RANGES]"), |
| 593 | &skiplist); |
| 594 | |
| 595 | add_info ("skip", skip_info, _("\ |
| 596 | Display the status of skips. You can specify numbers (e.g. \"skip info 1 3\"), \ |
| 597 | ranges (e.g. \"skip info 4-8\"), or both (e.g. \"skip info 1 3 4-8\").\n\n\ |
| 598 | If you don't specify any numbers or ranges, we'll show all skips.\n\n\ |
| 599 | Usage: skip info [NUMBERS AND/OR RANGES]\n\ |
| 600 | The \"Type\" column indicates one of:\n\ |
| 601 | \tfile - ignored file\n\ |
| 602 | \tfunction - ignored function")); |
| 603 | } |