GDB (API)
|
00001 /* Everything about signal catchpoints, for GDB. 00002 00003 Copyright (C) 2011-2013 Free Software Foundation, Inc. 00004 00005 This file is part of GDB. 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00019 00020 #include "defs.h" 00021 #include "arch-utils.h" 00022 #include <ctype.h> 00023 #include "breakpoint.h" 00024 #include "gdbcmd.h" 00025 #include "inferior.h" 00026 #include "annotate.h" 00027 #include "valprint.h" 00028 #include "cli/cli-utils.h" 00029 #include "completer.h" 00030 #include "gdb_obstack.h" 00031 00032 #define INTERNAL_SIGNAL(x) ((x) == GDB_SIGNAL_TRAP || (x) == GDB_SIGNAL_INT) 00033 00034 typedef enum gdb_signal gdb_signal_type; 00035 00036 DEF_VEC_I (gdb_signal_type); 00037 00038 /* An instance of this type is used to represent a signal catchpoint. 00039 It includes a "struct breakpoint" as a kind of base class; users 00040 downcast to "struct breakpoint *" when needed. A breakpoint is 00041 really of this type iff its ops pointer points to 00042 SIGNAL_CATCHPOINT_OPS. */ 00043 00044 struct signal_catchpoint 00045 { 00046 /* The base class. */ 00047 00048 struct breakpoint base; 00049 00050 /* Signal numbers used for the 'catch signal' feature. If no signal 00051 has been specified for filtering, its value is NULL. Otherwise, 00052 it holds a list of all signals to be caught. */ 00053 00054 VEC (gdb_signal_type) *signals_to_be_caught; 00055 00056 /* If SIGNALS_TO_BE_CAUGHT is NULL, then all "ordinary" signals are 00057 caught. If CATCH_ALL is non-zero, then internal signals are 00058 caught as well. If SIGNALS_TO_BE_CAUGHT is non-NULL, then this 00059 field is ignored. */ 00060 00061 int catch_all; 00062 }; 00063 00064 /* The breakpoint_ops structure to be used in signal catchpoints. */ 00065 00066 static struct breakpoint_ops signal_catchpoint_ops; 00067 00068 /* Count of each signal. */ 00069 00070 static unsigned int *signal_catch_counts; 00071 00072 00073 00074 /* A convenience wrapper for gdb_signal_to_name that returns the 00075 integer value if the name is not known. */ 00076 00077 static const char * 00078 signal_to_name_or_int (enum gdb_signal sig) 00079 { 00080 const char *result = gdb_signal_to_name (sig); 00081 00082 if (strcmp (result, "?") == 0) 00083 result = plongest (sig); 00084 00085 return result; 00086 } 00087 00088 00089 00090 /* Implement the "dtor" breakpoint_ops method for signal 00091 catchpoints. */ 00092 00093 static void 00094 signal_catchpoint_dtor (struct breakpoint *b) 00095 { 00096 struct signal_catchpoint *c = (struct signal_catchpoint *) b; 00097 00098 VEC_free (gdb_signal_type, c->signals_to_be_caught); 00099 00100 base_breakpoint_ops.dtor (b); 00101 } 00102 00103 /* Implement the "insert_location" breakpoint_ops method for signal 00104 catchpoints. */ 00105 00106 static int 00107 signal_catchpoint_insert_location (struct bp_location *bl) 00108 { 00109 struct signal_catchpoint *c = (void *) bl->owner; 00110 int i; 00111 00112 if (c->signals_to_be_caught != NULL) 00113 { 00114 gdb_signal_type iter; 00115 00116 for (i = 0; 00117 VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter); 00118 i++) 00119 ++signal_catch_counts[iter]; 00120 } 00121 else 00122 { 00123 for (i = 0; i < GDB_SIGNAL_LAST; ++i) 00124 { 00125 if (c->catch_all || !INTERNAL_SIGNAL (i)) 00126 ++signal_catch_counts[i]; 00127 } 00128 } 00129 00130 signal_catch_update (signal_catch_counts); 00131 00132 return 0; 00133 } 00134 00135 /* Implement the "remove_location" breakpoint_ops method for signal 00136 catchpoints. */ 00137 00138 static int 00139 signal_catchpoint_remove_location (struct bp_location *bl) 00140 { 00141 struct signal_catchpoint *c = (void *) bl->owner; 00142 int i; 00143 00144 if (c->signals_to_be_caught != NULL) 00145 { 00146 gdb_signal_type iter; 00147 00148 for (i = 0; 00149 VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter); 00150 i++) 00151 { 00152 gdb_assert (signal_catch_counts[iter] > 0); 00153 --signal_catch_counts[iter]; 00154 } 00155 } 00156 else 00157 { 00158 for (i = 0; i < GDB_SIGNAL_LAST; ++i) 00159 { 00160 if (c->catch_all || !INTERNAL_SIGNAL (i)) 00161 { 00162 gdb_assert (signal_catch_counts[i] > 0); 00163 --signal_catch_counts[i]; 00164 } 00165 } 00166 } 00167 00168 signal_catch_update (signal_catch_counts); 00169 00170 return 0; 00171 } 00172 00173 /* Implement the "breakpoint_hit" breakpoint_ops method for signal 00174 catchpoints. */ 00175 00176 static int 00177 signal_catchpoint_breakpoint_hit (const struct bp_location *bl, 00178 struct address_space *aspace, 00179 CORE_ADDR bp_addr, 00180 const struct target_waitstatus *ws) 00181 { 00182 const struct signal_catchpoint *c = (void *) bl->owner; 00183 gdb_signal_type signal_number; 00184 00185 if (ws->kind != TARGET_WAITKIND_STOPPED) 00186 return 0; 00187 00188 signal_number = ws->value.sig; 00189 00190 /* If we are catching specific signals in this breakpoint, then we 00191 must guarantee that the called signal is the same signal we are 00192 catching. */ 00193 if (c->signals_to_be_caught) 00194 { 00195 int i; 00196 gdb_signal_type iter; 00197 00198 for (i = 0; 00199 VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter); 00200 i++) 00201 if (signal_number == iter) 00202 return 1; 00203 /* Not the same. */ 00204 gdb_assert (!iter); 00205 return 0; 00206 } 00207 else 00208 return c->catch_all || !INTERNAL_SIGNAL (signal_number); 00209 } 00210 00211 /* Implement the "print_it" breakpoint_ops method for signal 00212 catchpoints. */ 00213 00214 static enum print_stop_action 00215 signal_catchpoint_print_it (bpstat bs) 00216 { 00217 struct breakpoint *b = bs->breakpoint_at; 00218 ptid_t ptid; 00219 struct target_waitstatus last; 00220 const char *signal_name; 00221 00222 get_last_target_status (&ptid, &last); 00223 00224 signal_name = signal_to_name_or_int (last.value.sig); 00225 00226 annotate_catchpoint (b->number); 00227 00228 printf_filtered (_("\nCatchpoint %d (signal %s), "), b->number, signal_name); 00229 00230 return PRINT_SRC_AND_LOC; 00231 } 00232 00233 /* Implement the "print_one" breakpoint_ops method for signal 00234 catchpoints. */ 00235 00236 static void 00237 signal_catchpoint_print_one (struct breakpoint *b, 00238 struct bp_location **last_loc) 00239 { 00240 struct signal_catchpoint *c = (void *) b; 00241 struct value_print_options opts; 00242 struct ui_out *uiout = current_uiout; 00243 00244 get_user_print_options (&opts); 00245 00246 /* Field 4, the address, is omitted (which makes the columns 00247 not line up too nicely with the headers, but the effect 00248 is relatively readable). */ 00249 if (opts.addressprint) 00250 ui_out_field_skip (uiout, "addr"); 00251 annotate_field (5); 00252 00253 if (c->signals_to_be_caught 00254 && VEC_length (gdb_signal_type, c->signals_to_be_caught) > 1) 00255 ui_out_text (uiout, "signals \""); 00256 else 00257 ui_out_text (uiout, "signal \""); 00258 00259 if (c->signals_to_be_caught) 00260 { 00261 int i; 00262 gdb_signal_type iter; 00263 struct obstack text; 00264 struct cleanup *cleanup; 00265 00266 obstack_init (&text); 00267 cleanup = make_cleanup_obstack_free (&text); 00268 00269 for (i = 0; 00270 VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter); 00271 i++) 00272 { 00273 const char *name = signal_to_name_or_int (iter); 00274 00275 if (i > 0) 00276 obstack_grow (&text, " ", 1); 00277 obstack_grow (&text, name, strlen (name)); 00278 } 00279 obstack_grow (&text, "", 1); 00280 ui_out_field_string (uiout, "what", obstack_base (&text)); 00281 do_cleanups (cleanup); 00282 } 00283 else 00284 ui_out_field_string (uiout, "what", 00285 c->catch_all ? "<any signal>" : "<standard signals>"); 00286 ui_out_text (uiout, "\" "); 00287 00288 if (ui_out_is_mi_like_p (uiout)) 00289 ui_out_field_string (uiout, "catch-type", "signal"); 00290 } 00291 00292 /* Implement the "print_mention" breakpoint_ops method for signal 00293 catchpoints. */ 00294 00295 static void 00296 signal_catchpoint_print_mention (struct breakpoint *b) 00297 { 00298 struct signal_catchpoint *c = (void *) b; 00299 00300 if (c->signals_to_be_caught) 00301 { 00302 int i; 00303 gdb_signal_type iter; 00304 00305 if (VEC_length (gdb_signal_type, c->signals_to_be_caught) > 1) 00306 printf_filtered (_("Catchpoint %d (signals"), b->number); 00307 else 00308 printf_filtered (_("Catchpoint %d (signal"), b->number); 00309 00310 for (i = 0; 00311 VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter); 00312 i++) 00313 { 00314 const char *name = signal_to_name_or_int (iter); 00315 00316 printf_filtered (" %s", name); 00317 } 00318 printf_filtered (")"); 00319 } 00320 else if (c->catch_all) 00321 printf_filtered (_("Catchpoint %d (any signal)"), b->number); 00322 else 00323 printf_filtered (_("Catchpoint %d (standard signals)"), b->number); 00324 } 00325 00326 /* Implement the "print_recreate" breakpoint_ops method for signal 00327 catchpoints. */ 00328 00329 static void 00330 signal_catchpoint_print_recreate (struct breakpoint *b, struct ui_file *fp) 00331 { 00332 struct signal_catchpoint *c = (void *) b; 00333 00334 fprintf_unfiltered (fp, "catch signal"); 00335 00336 if (c->signals_to_be_caught) 00337 { 00338 int i; 00339 gdb_signal_type iter; 00340 00341 for (i = 0; 00342 VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter); 00343 i++) 00344 fprintf_unfiltered (fp, " %s", signal_to_name_or_int (iter)); 00345 } 00346 else if (c->catch_all) 00347 fprintf_unfiltered (fp, " all"); 00348 } 00349 00350 /* Implement the "explains_signal" breakpoint_ops method for signal 00351 catchpoints. */ 00352 00353 static enum bpstat_signal_value 00354 signal_catchpoint_explains_signal (struct breakpoint *b, enum gdb_signal sig) 00355 { 00356 return BPSTAT_SIGNAL_PASS; 00357 } 00358 00359 /* Create a new signal catchpoint. TEMPFLAG is true if this should be 00360 a temporary catchpoint. FILTER is the list of signals to catch; it 00361 can be NULL, meaning all signals. CATCH_ALL is a flag indicating 00362 whether signals used internally by gdb should be caught; it is only 00363 valid if FILTER is NULL. If FILTER is NULL and CATCH_ALL is zero, 00364 then internal signals like SIGTRAP are not caught. */ 00365 00366 static void 00367 create_signal_catchpoint (int tempflag, VEC (gdb_signal_type) *filter, 00368 int catch_all) 00369 { 00370 struct signal_catchpoint *c; 00371 struct gdbarch *gdbarch = get_current_arch (); 00372 00373 c = XNEW (struct signal_catchpoint); 00374 init_catchpoint (&c->base, gdbarch, tempflag, NULL, &signal_catchpoint_ops); 00375 c->signals_to_be_caught = filter; 00376 c->catch_all = catch_all; 00377 00378 install_breakpoint (0, &c->base, 1); 00379 } 00380 00381 00382 /* Splits the argument using space as delimiter. Returns an xmalloc'd 00383 filter list, or NULL if no filtering is required. */ 00384 00385 static VEC (gdb_signal_type) * 00386 catch_signal_split_args (char *arg, int *catch_all) 00387 { 00388 VEC (gdb_signal_type) *result = NULL; 00389 struct cleanup *cleanup = make_cleanup (VEC_cleanup (gdb_signal_type), 00390 &result); 00391 int first = 1; 00392 00393 while (*arg != '\0') 00394 { 00395 int num; 00396 gdb_signal_type signal_number; 00397 char *one_arg, *endptr; 00398 struct cleanup *inner_cleanup; 00399 00400 one_arg = extract_arg (&arg); 00401 if (one_arg == NULL) 00402 break; 00403 inner_cleanup = make_cleanup (xfree, one_arg); 00404 00405 /* Check for the special flag "all". */ 00406 if (strcmp (one_arg, "all") == 0) 00407 { 00408 arg = skip_spaces (arg); 00409 if (*arg != '\0' || !first) 00410 error (_("'all' cannot be caught with other signals")); 00411 *catch_all = 1; 00412 gdb_assert (result == NULL); 00413 do_cleanups (inner_cleanup); 00414 discard_cleanups (cleanup); 00415 return NULL; 00416 } 00417 00418 first = 0; 00419 00420 /* Check if the user provided a signal name or a number. */ 00421 num = (int) strtol (one_arg, &endptr, 0); 00422 if (*endptr == '\0') 00423 signal_number = gdb_signal_from_command (num); 00424 else 00425 { 00426 signal_number = gdb_signal_from_name (one_arg); 00427 if (signal_number == GDB_SIGNAL_UNKNOWN) 00428 error (_("Unknown signal name '%s'."), one_arg); 00429 } 00430 00431 VEC_safe_push (gdb_signal_type, result, signal_number); 00432 do_cleanups (inner_cleanup); 00433 } 00434 00435 discard_cleanups (cleanup); 00436 return result; 00437 } 00438 00439 /* Implement the "catch signal" command. */ 00440 00441 static void 00442 catch_signal_command (char *arg, int from_tty, 00443 struct cmd_list_element *command) 00444 { 00445 int tempflag, catch_all = 0; 00446 VEC (gdb_signal_type) *filter; 00447 00448 tempflag = get_cmd_context (command) == CATCH_TEMPORARY; 00449 00450 arg = skip_spaces (arg); 00451 00452 /* The allowed syntax is: 00453 catch signal 00454 catch signal <name | number> [<name | number> ... <name | number>] 00455 00456 Let's check if there's a signal name. */ 00457 00458 if (arg != NULL) 00459 filter = catch_signal_split_args (arg, &catch_all); 00460 else 00461 filter = NULL; 00462 00463 create_signal_catchpoint (tempflag, filter, catch_all); 00464 } 00465 00466 static void 00467 initialize_signal_catchpoint_ops (void) 00468 { 00469 struct breakpoint_ops *ops; 00470 00471 initialize_breakpoint_ops (); 00472 00473 ops = &signal_catchpoint_ops; 00474 *ops = base_breakpoint_ops; 00475 ops->dtor = signal_catchpoint_dtor; 00476 ops->insert_location = signal_catchpoint_insert_location; 00477 ops->remove_location = signal_catchpoint_remove_location; 00478 ops->breakpoint_hit = signal_catchpoint_breakpoint_hit; 00479 ops->print_it = signal_catchpoint_print_it; 00480 ops->print_one = signal_catchpoint_print_one; 00481 ops->print_mention = signal_catchpoint_print_mention; 00482 ops->print_recreate = signal_catchpoint_print_recreate; 00483 ops->explains_signal = signal_catchpoint_explains_signal; 00484 } 00485 00486 initialize_file_ftype _initialize_break_catch_sig; 00487 00488 void 00489 _initialize_break_catch_sig (void) 00490 { 00491 initialize_signal_catchpoint_ops (); 00492 00493 signal_catch_counts = XCNEWVEC (unsigned int, GDB_SIGNAL_LAST); 00494 00495 add_catch_command ("signal", _("\ 00496 Catch signals by their names and/or numbers.\n\ 00497 Usage: catch signal [[NAME|NUMBER] [NAME|NUMBER]...|all]\n\ 00498 Arguments say which signals to catch. If no arguments\n\ 00499 are given, every \"normal\" signal will be caught.\n\ 00500 The argument \"all\" means to also catch signals used by GDB.\n\ 00501 Arguments, if given, should be one or more signal names\n\ 00502 (if your system supports that), or signal numbers."), 00503 catch_signal_command, 00504 signal_completer, 00505 CATCH_PERMANENT, 00506 CATCH_TEMPORARY); 00507 }