1 /* Everything about signal catchpoints, for GDB. 2 3 Copyright (C) 2011-2023 Free Software Foundation, Inc. 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 <ctype.h> 23 #include "breakpoint.h" 24 #include "gdbcmd.h" 25 #include "inferior.h" 26 #include "infrun.h" 27 #include "annotate.h" 28 #include "valprint.h" 29 #include "cli/cli-utils.h" 30 #include "completer.h" 31 #include "cli/cli-style.h" 32 #include "cli/cli-decode.h" 33 34 #include <string> 35 36 #define INTERNAL_SIGNAL(x) ((x) == GDB_SIGNAL_TRAP || (x) == GDB_SIGNAL_INT) 37 38 /* An instance of this type is used to represent a signal 39 catchpoint. */ 40 41 struct signal_catchpoint : public catchpoint 42 { 43 signal_catchpoint (struct gdbarch *gdbarch, bool temp, 44 std::vector<gdb_signal> &&sigs, 45 bool catch_all_) 46 : catchpoint (gdbarch, temp, nullptr), 47 signals_to_be_caught (std::move (sigs)), 48 catch_all (catch_all_) 49 { 50 } 51 52 int insert_location (struct bp_location *) override; 53 int remove_location (struct bp_location *, 54 enum remove_bp_reason reason) override; 55 int breakpoint_hit (const struct bp_location *bl, 56 const address_space *aspace, 57 CORE_ADDR bp_addr, 58 const target_waitstatus &ws) override; 59 enum print_stop_action print_it (const bpstat *bs) const override; 60 bool print_one (bp_location **) const override; 61 void print_mention () const override; 62 void print_recreate (struct ui_file *fp) const override; 63 bool explains_signal (enum gdb_signal) override; 64 65 /* Signal numbers used for the 'catch signal' feature. If no signal 66 has been specified for filtering, it is empty. Otherwise, 67 it holds a list of all signals to be caught. */ 68 69 std::vector<gdb_signal> signals_to_be_caught; 70 71 /* If SIGNALS_TO_BE_CAUGHT is empty, then all "ordinary" signals are 72 caught. If CATCH_ALL is true, then internal signals are caught 73 as well. If SIGNALS_TO_BE_CAUGHT is not empty, then this field 74 is ignored. */ 75 76 bool catch_all; 77 }; 78 79 /* Count of each signal. */ 80 81 static unsigned int signal_catch_counts[GDB_SIGNAL_LAST]; 82 83 84 85 /* A convenience wrapper for gdb_signal_to_name that returns the 86 integer value if the name is not known. */ 87 88 static const char * 89 signal_to_name_or_int (enum gdb_signal sig) 90 { 91 const char *result = gdb_signal_to_name (sig); 92 93 if (strcmp (result, "?") == 0) 94 result = plongest (sig); 95 96 return result; 97 } 98 99 100 101 /* Implement the "insert_location" method for signal catchpoints. */ 102 103 int 104 signal_catchpoint::insert_location (struct bp_location *bl) 105 { 106 struct signal_catchpoint *c = (struct signal_catchpoint *) bl->owner; 107 108 if (!c->signals_to_be_caught.empty ()) 109 { 110 for (gdb_signal iter : c->signals_to_be_caught) 111 ++signal_catch_counts[iter]; 112 } 113 else 114 { 115 for (int i = 0; i < GDB_SIGNAL_LAST; ++i) 116 { 117 if (c->catch_all || !INTERNAL_SIGNAL (i)) 118 ++signal_catch_counts[i]; 119 } 120 } 121 122 signal_catch_update (signal_catch_counts); 123 124 return 0; 125 } 126 127 /* Implement the "remove_location" method for signal catchpoints. */ 128 129 int 130 signal_catchpoint::remove_location (struct bp_location *bl, 131 enum remove_bp_reason reason) 132 { 133 struct signal_catchpoint *c = (struct signal_catchpoint *) bl->owner; 134 135 if (!c->signals_to_be_caught.empty ()) 136 { 137 for (gdb_signal iter : c->signals_to_be_caught) 138 { 139 gdb_assert (signal_catch_counts[iter] > 0); 140 --signal_catch_counts[iter]; 141 } 142 } 143 else 144 { 145 for (int i = 0; i < GDB_SIGNAL_LAST; ++i) 146 { 147 if (c->catch_all || !INTERNAL_SIGNAL (i)) 148 { 149 gdb_assert (signal_catch_counts[i] > 0); 150 --signal_catch_counts[i]; 151 } 152 } 153 } 154 155 signal_catch_update (signal_catch_counts); 156 157 return 0; 158 } 159 160 /* Implement the "breakpoint_hit" method for signal catchpoints. */ 161 162 int 163 signal_catchpoint::breakpoint_hit (const struct bp_location *bl, 164 const address_space *aspace, 165 CORE_ADDR bp_addr, 166 const target_waitstatus &ws) 167 { 168 const struct signal_catchpoint *c 169 = (const struct signal_catchpoint *) bl->owner; 170 gdb_signal signal_number; 171 172 if (ws.kind () != TARGET_WAITKIND_STOPPED) 173 return 0; 174 175 signal_number = ws.sig (); 176 177 /* If we are catching specific signals in this breakpoint, then we 178 must guarantee that the called signal is the same signal we are 179 catching. */ 180 if (!c->signals_to_be_caught.empty ()) 181 { 182 for (gdb_signal iter : c->signals_to_be_caught) 183 if (signal_number == iter) 184 return 1; 185 /* Not the same. */ 186 return 0; 187 } 188 else 189 return c->catch_all || !INTERNAL_SIGNAL (signal_number); 190 } 191 192 /* Implement the "print_it" method for signal catchpoints. */ 193 194 enum print_stop_action 195 signal_catchpoint::print_it (const bpstat *bs) const 196 { 197 struct target_waitstatus last; 198 const char *signal_name; 199 struct ui_out *uiout = current_uiout; 200 201 get_last_target_status (nullptr, nullptr, &last); 202 203 signal_name = signal_to_name_or_int (last.sig ()); 204 205 annotate_catchpoint (number); 206 maybe_print_thread_hit_breakpoint (uiout); 207 208 gdb_printf (_("Catchpoint %d (signal %s), "), number, signal_name); 209 210 return PRINT_SRC_AND_LOC; 211 } 212 213 /* Implement the "print_one" method for signal catchpoints. */ 214 215 bool 216 signal_catchpoint::print_one (bp_location **last_loc) const 217 { 218 struct value_print_options opts; 219 struct ui_out *uiout = current_uiout; 220 221 get_user_print_options (&opts); 222 223 /* Field 4, the address, is omitted (which makes the columns 224 not line up too nicely with the headers, but the effect 225 is relatively readable). */ 226 if (opts.addressprint) 227 uiout->field_skip ("addr"); 228 annotate_field (5); 229 230 if (signals_to_be_caught.size () > 1) 231 uiout->text ("signals \""); 232 else 233 uiout->text ("signal \""); 234 235 if (!signals_to_be_caught.empty ()) 236 { 237 std::string text; 238 239 bool first = true; 240 for (gdb_signal iter : signals_to_be_caught) 241 { 242 const char *name = signal_to_name_or_int (iter); 243 244 if (!first) 245 text += " "; 246 first = false; 247 248 text += name; 249 } 250 uiout->field_string ("what", text); 251 } 252 else 253 uiout->field_string ("what", 254 catch_all ? "<any signal>" : "<standard signals>", 255 metadata_style.style ()); 256 uiout->text ("\" "); 257 258 if (uiout->is_mi_like_p ()) 259 uiout->field_string ("catch-type", "signal"); 260 261 return true; 262 } 263 264 /* Implement the "print_mention" method for signal catchpoints. */ 265 266 void 267 signal_catchpoint::print_mention () const 268 { 269 if (!signals_to_be_caught.empty ()) 270 { 271 if (signals_to_be_caught.size () > 1) 272 gdb_printf (_("Catchpoint %d (signals"), number); 273 else 274 gdb_printf (_("Catchpoint %d (signal"), number); 275 276 for (gdb_signal iter : signals_to_be_caught) 277 { 278 const char *name = signal_to_name_or_int (iter); 279 280 gdb_printf (" %s", name); 281 } 282 gdb_printf (")"); 283 } 284 else if (catch_all) 285 gdb_printf (_("Catchpoint %d (any signal)"), number); 286 else 287 gdb_printf (_("Catchpoint %d (standard signals)"), number); 288 } 289 290 /* Implement the "print_recreate" method for signal catchpoints. */ 291 292 void 293 signal_catchpoint::print_recreate (struct ui_file *fp) const 294 { 295 gdb_printf (fp, "catch signal"); 296 297 if (!signals_to_be_caught.empty ()) 298 { 299 for (gdb_signal iter : signals_to_be_caught) 300 gdb_printf (fp, " %s", signal_to_name_or_int (iter)); 301 } 302 else if (catch_all) 303 gdb_printf (fp, " all"); 304 gdb_putc ('\n', fp); 305 } 306 307 /* Implement the "explains_signal" method for signal catchpoints. */ 308 309 bool 310 signal_catchpoint::explains_signal (enum gdb_signal sig) 311 { 312 return true; 313 } 314 315 /* Create a new signal catchpoint. TEMPFLAG is true if this should be 316 a temporary catchpoint. FILTER is the list of signals to catch; it 317 can be empty, meaning all signals. CATCH_ALL is a flag indicating 318 whether signals used internally by gdb should be caught; it is only 319 valid if FILTER is NULL. If FILTER is empty and CATCH_ALL is zero, 320 then internal signals like SIGTRAP are not caught. */ 321 322 static void 323 create_signal_catchpoint (int tempflag, std::vector<gdb_signal> &&filter, 324 bool catch_all) 325 { 326 struct gdbarch *gdbarch = get_current_arch (); 327 328 std::unique_ptr<signal_catchpoint> c 329 (new signal_catchpoint (gdbarch, tempflag, std::move (filter), catch_all)); 330 331 install_breakpoint (0, std::move (c), 1); 332 } 333 334 335 /* Splits the argument using space as delimiter. Returns a filter 336 list, which is empty if no filtering is required. */ 337 338 static std::vector<gdb_signal> 339 catch_signal_split_args (const char *arg, bool *catch_all) 340 { 341 std::vector<gdb_signal> result; 342 bool first = true; 343 344 while (*arg != '\0') 345 { 346 int num; 347 gdb_signal signal_number; 348 char *endptr; 349 350 std::string one_arg = extract_arg (&arg); 351 if (one_arg.empty ()) 352 break; 353 354 /* Check for the special flag "all". */ 355 if (one_arg == "all") 356 { 357 arg = skip_spaces (arg); 358 if (*arg != '\0' || !first) 359 error (_("'all' cannot be caught with other signals")); 360 *catch_all = true; 361 gdb_assert (result.empty ()); 362 return result; 363 } 364 365 first = false; 366 367 /* Check if the user provided a signal name or a number. */ 368 num = (int) strtol (one_arg.c_str (), &endptr, 0); 369 if (*endptr == '\0') 370 signal_number = gdb_signal_from_command (num); 371 else 372 { 373 signal_number = gdb_signal_from_name (one_arg.c_str ()); 374 if (signal_number == GDB_SIGNAL_UNKNOWN) 375 error (_("Unknown signal name '%s'."), one_arg.c_str ()); 376 } 377 378 result.push_back (signal_number); 379 } 380 381 result.shrink_to_fit (); 382 return result; 383 } 384 385 /* Implement the "catch signal" command. */ 386 387 static void 388 catch_signal_command (const char *arg, int from_tty, 389 struct cmd_list_element *command) 390 { 391 int tempflag; 392 bool catch_all = false; 393 std::vector<gdb_signal> filter; 394 395 tempflag = command->context () == CATCH_TEMPORARY; 396 397 arg = skip_spaces (arg); 398 399 /* The allowed syntax is: 400 catch signal 401 catch signal <name | number> [<name | number> ... <name | number>] 402 403 Let's check if there's a signal name. */ 404 405 if (arg != NULL) 406 filter = catch_signal_split_args (arg, &catch_all); 407 408 create_signal_catchpoint (tempflag, std::move (filter), catch_all); 409 } 410 411 void _initialize_break_catch_sig (); 412 void 413 _initialize_break_catch_sig () 414 { 415 add_catch_command ("signal", _("\ 416 Catch signals by their names and/or numbers.\n\ 417 Usage: catch signal [[NAME|NUMBER] [NAME|NUMBER]...|all]\n\ 418 Arguments say which signals to catch. If no arguments\n\ 419 are given, every \"normal\" signal will be caught.\n\ 420 The argument \"all\" means to also catch signals used by GDB.\n\ 421 Arguments, if given, should be one or more signal names\n\ 422 (if your system supports that), or signal numbers."), 423 catch_signal_command, 424 signal_completer, 425 CATCH_PERMANENT, 426 CATCH_TEMPORARY); 427 } 428