GDB (API)
/home/stan/gdb/src/gdb/break-catch-sig.c
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines