1*6881a400Schristos /* Everything about vfork catchpoints, for GDB. 2*6881a400Schristos 3*6881a400Schristos Copyright (C) 1986-2023 Free Software Foundation, Inc. 4*6881a400Schristos 5*6881a400Schristos This file is part of GDB. 6*6881a400Schristos 7*6881a400Schristos This program is free software; you can redistribute it and/or modify 8*6881a400Schristos it under the terms of the GNU General Public License as published by 9*6881a400Schristos the Free Software Foundation; either version 3 of the License, or 10*6881a400Schristos (at your option) any later version. 11*6881a400Schristos 12*6881a400Schristos This program is distributed in the hope that it will be useful, 13*6881a400Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 14*6881a400Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*6881a400Schristos GNU General Public License for more details. 16*6881a400Schristos 17*6881a400Schristos You should have received a copy of the GNU General Public License 18*6881a400Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19*6881a400Schristos 20*6881a400Schristos #include "defs.h" 21*6881a400Schristos 22*6881a400Schristos #include "annotate.h" 23*6881a400Schristos #include "arch-utils.h" 24*6881a400Schristos #include "breakpoint.h" 25*6881a400Schristos #include "cli/cli-decode.h" 26*6881a400Schristos #include "inferior.h" 27*6881a400Schristos #include "mi/mi-common.h" 28*6881a400Schristos #include "target.h" 29*6881a400Schristos #include "valprint.h" 30*6881a400Schristos 31*6881a400Schristos /* An instance of this type is used to represent a fork or vfork 32*6881a400Schristos catchpoint. A breakpoint is really of this type iff its ops pointer points 33*6881a400Schristos to CATCH_FORK_BREAKPOINT_OPS. */ 34*6881a400Schristos 35*6881a400Schristos struct fork_catchpoint : public catchpoint 36*6881a400Schristos { 37*6881a400Schristos fork_catchpoint (struct gdbarch *gdbarch, bool temp, 38*6881a400Schristos const char *cond_string, bool is_vfork_) 39*6881a400Schristos : catchpoint (gdbarch, temp, cond_string), 40*6881a400Schristos is_vfork (is_vfork_) 41*6881a400Schristos { 42*6881a400Schristos } 43*6881a400Schristos 44*6881a400Schristos int insert_location (struct bp_location *) override; 45*6881a400Schristos int remove_location (struct bp_location *, 46*6881a400Schristos enum remove_bp_reason reason) override; 47*6881a400Schristos int breakpoint_hit (const struct bp_location *bl, 48*6881a400Schristos const address_space *aspace, 49*6881a400Schristos CORE_ADDR bp_addr, 50*6881a400Schristos const target_waitstatus &ws) override; 51*6881a400Schristos enum print_stop_action print_it (const bpstat *bs) const override; 52*6881a400Schristos bool print_one (bp_location **) const override; 53*6881a400Schristos void print_mention () const override; 54*6881a400Schristos void print_recreate (struct ui_file *fp) const override; 55*6881a400Schristos 56*6881a400Schristos /* True if the breakpoint is for vfork, false for fork. */ 57*6881a400Schristos bool is_vfork; 58*6881a400Schristos 59*6881a400Schristos /* Process id of a child process whose forking triggered this 60*6881a400Schristos catchpoint. This field is only valid immediately after this 61*6881a400Schristos catchpoint has triggered. */ 62*6881a400Schristos ptid_t forked_inferior_pid = null_ptid; 63*6881a400Schristos }; 64*6881a400Schristos 65*6881a400Schristos /* Implement the "insert" method for fork catchpoints. */ 66*6881a400Schristos 67*6881a400Schristos int 68*6881a400Schristos fork_catchpoint::insert_location (struct bp_location *bl) 69*6881a400Schristos { 70*6881a400Schristos if (is_vfork) 71*6881a400Schristos return target_insert_vfork_catchpoint (inferior_ptid.pid ()); 72*6881a400Schristos else 73*6881a400Schristos return target_insert_fork_catchpoint (inferior_ptid.pid ()); 74*6881a400Schristos } 75*6881a400Schristos 76*6881a400Schristos /* Implement the "remove" method for fork catchpoints. */ 77*6881a400Schristos 78*6881a400Schristos int 79*6881a400Schristos fork_catchpoint::remove_location (struct bp_location *bl, 80*6881a400Schristos enum remove_bp_reason reason) 81*6881a400Schristos { 82*6881a400Schristos if (is_vfork) 83*6881a400Schristos return target_remove_vfork_catchpoint (inferior_ptid.pid ()); 84*6881a400Schristos else 85*6881a400Schristos return target_remove_fork_catchpoint (inferior_ptid.pid ()); 86*6881a400Schristos } 87*6881a400Schristos 88*6881a400Schristos /* Implement the "breakpoint_hit" method for fork catchpoints. */ 89*6881a400Schristos 90*6881a400Schristos int 91*6881a400Schristos fork_catchpoint::breakpoint_hit (const struct bp_location *bl, 92*6881a400Schristos const address_space *aspace, 93*6881a400Schristos CORE_ADDR bp_addr, 94*6881a400Schristos const target_waitstatus &ws) 95*6881a400Schristos { 96*6881a400Schristos if (ws.kind () != (is_vfork 97*6881a400Schristos ? TARGET_WAITKIND_VFORKED 98*6881a400Schristos : TARGET_WAITKIND_FORKED)) 99*6881a400Schristos return 0; 100*6881a400Schristos 101*6881a400Schristos forked_inferior_pid = ws.child_ptid (); 102*6881a400Schristos return 1; 103*6881a400Schristos } 104*6881a400Schristos 105*6881a400Schristos /* Implement the "print_it" method for fork catchpoints. */ 106*6881a400Schristos 107*6881a400Schristos enum print_stop_action 108*6881a400Schristos fork_catchpoint::print_it (const bpstat *bs) const 109*6881a400Schristos { 110*6881a400Schristos struct ui_out *uiout = current_uiout; 111*6881a400Schristos 112*6881a400Schristos annotate_catchpoint (number); 113*6881a400Schristos maybe_print_thread_hit_breakpoint (uiout); 114*6881a400Schristos if (disposition == disp_del) 115*6881a400Schristos uiout->text ("Temporary catchpoint "); 116*6881a400Schristos else 117*6881a400Schristos uiout->text ("Catchpoint "); 118*6881a400Schristos if (uiout->is_mi_like_p ()) 119*6881a400Schristos { 120*6881a400Schristos uiout->field_string ("reason", 121*6881a400Schristos async_reason_lookup (is_vfork 122*6881a400Schristos ? EXEC_ASYNC_VFORK 123*6881a400Schristos : EXEC_ASYNC_FORK)); 124*6881a400Schristos uiout->field_string ("disp", bpdisp_text (disposition)); 125*6881a400Schristos } 126*6881a400Schristos uiout->field_signed ("bkptno", number); 127*6881a400Schristos if (is_vfork) 128*6881a400Schristos uiout->text (" (vforked process "); 129*6881a400Schristos else 130*6881a400Schristos uiout->text (" (forked process "); 131*6881a400Schristos uiout->field_signed ("newpid", forked_inferior_pid.pid ()); 132*6881a400Schristos uiout->text ("), "); 133*6881a400Schristos return PRINT_SRC_AND_LOC; 134*6881a400Schristos } 135*6881a400Schristos 136*6881a400Schristos /* Implement the "print_one" method for fork catchpoints. */ 137*6881a400Schristos 138*6881a400Schristos bool 139*6881a400Schristos fork_catchpoint::print_one (bp_location **last_loc) const 140*6881a400Schristos { 141*6881a400Schristos struct value_print_options opts; 142*6881a400Schristos struct ui_out *uiout = current_uiout; 143*6881a400Schristos 144*6881a400Schristos get_user_print_options (&opts); 145*6881a400Schristos 146*6881a400Schristos /* Field 4, the address, is omitted (which makes the columns not 147*6881a400Schristos line up too nicely with the headers, but the effect is relatively 148*6881a400Schristos readable). */ 149*6881a400Schristos if (opts.addressprint) 150*6881a400Schristos uiout->field_skip ("addr"); 151*6881a400Schristos annotate_field (5); 152*6881a400Schristos const char *name = is_vfork ? "vfork" : "fork"; 153*6881a400Schristos uiout->text (name); 154*6881a400Schristos if (forked_inferior_pid != null_ptid) 155*6881a400Schristos { 156*6881a400Schristos uiout->text (", process "); 157*6881a400Schristos uiout->field_signed ("what", forked_inferior_pid.pid ()); 158*6881a400Schristos uiout->spaces (1); 159*6881a400Schristos } 160*6881a400Schristos 161*6881a400Schristos if (uiout->is_mi_like_p ()) 162*6881a400Schristos uiout->field_string ("catch-type", name); 163*6881a400Schristos 164*6881a400Schristos return true; 165*6881a400Schristos } 166*6881a400Schristos 167*6881a400Schristos /* Implement the "print_mention" method for fork catchpoints. */ 168*6881a400Schristos 169*6881a400Schristos void 170*6881a400Schristos fork_catchpoint::print_mention () const 171*6881a400Schristos { 172*6881a400Schristos gdb_printf (_("Catchpoint %d (%s)"), number, 173*6881a400Schristos is_vfork ? "vfork" : "fork"); 174*6881a400Schristos } 175*6881a400Schristos 176*6881a400Schristos /* Implement the "print_recreate" method for fork catchpoints. */ 177*6881a400Schristos 178*6881a400Schristos void 179*6881a400Schristos fork_catchpoint::print_recreate (struct ui_file *fp) const 180*6881a400Schristos { 181*6881a400Schristos gdb_printf (fp, "catch %s", is_vfork ? "vfork" : "fork"); 182*6881a400Schristos print_recreate_thread (fp); 183*6881a400Schristos } 184*6881a400Schristos 185*6881a400Schristos static void 186*6881a400Schristos create_fork_vfork_event_catchpoint (struct gdbarch *gdbarch, 187*6881a400Schristos bool temp, const char *cond_string, 188*6881a400Schristos bool is_vfork) 189*6881a400Schristos { 190*6881a400Schristos std::unique_ptr<fork_catchpoint> c 191*6881a400Schristos (new fork_catchpoint (gdbarch, temp, cond_string, is_vfork)); 192*6881a400Schristos 193*6881a400Schristos install_breakpoint (0, std::move (c), 1); 194*6881a400Schristos } 195*6881a400Schristos 196*6881a400Schristos enum catch_fork_kind 197*6881a400Schristos { 198*6881a400Schristos catch_fork_temporary, catch_vfork_temporary, 199*6881a400Schristos catch_fork_permanent, catch_vfork_permanent 200*6881a400Schristos }; 201*6881a400Schristos 202*6881a400Schristos static void 203*6881a400Schristos catch_fork_command_1 (const char *arg, int from_tty, 204*6881a400Schristos struct cmd_list_element *command) 205*6881a400Schristos { 206*6881a400Schristos struct gdbarch *gdbarch = get_current_arch (); 207*6881a400Schristos const char *cond_string = NULL; 208*6881a400Schristos catch_fork_kind fork_kind; 209*6881a400Schristos 210*6881a400Schristos fork_kind = (catch_fork_kind) (uintptr_t) command->context (); 211*6881a400Schristos bool temp = (fork_kind == catch_fork_temporary 212*6881a400Schristos || fork_kind == catch_vfork_temporary); 213*6881a400Schristos 214*6881a400Schristos if (!arg) 215*6881a400Schristos arg = ""; 216*6881a400Schristos arg = skip_spaces (arg); 217*6881a400Schristos 218*6881a400Schristos /* The allowed syntax is: 219*6881a400Schristos catch [v]fork 220*6881a400Schristos catch [v]fork if <cond> 221*6881a400Schristos 222*6881a400Schristos First, check if there's an if clause. */ 223*6881a400Schristos cond_string = ep_parse_optional_if_clause (&arg); 224*6881a400Schristos 225*6881a400Schristos if ((*arg != '\0') && !isspace (*arg)) 226*6881a400Schristos error (_("Junk at end of arguments.")); 227*6881a400Schristos 228*6881a400Schristos /* If this target supports it, create a fork or vfork catchpoint 229*6881a400Schristos and enable reporting of such events. */ 230*6881a400Schristos switch (fork_kind) 231*6881a400Schristos { 232*6881a400Schristos case catch_fork_temporary: 233*6881a400Schristos case catch_fork_permanent: 234*6881a400Schristos create_fork_vfork_event_catchpoint (gdbarch, temp, cond_string, false); 235*6881a400Schristos break; 236*6881a400Schristos case catch_vfork_temporary: 237*6881a400Schristos case catch_vfork_permanent: 238*6881a400Schristos create_fork_vfork_event_catchpoint (gdbarch, temp, cond_string, true); 239*6881a400Schristos break; 240*6881a400Schristos default: 241*6881a400Schristos error (_("unsupported or unknown fork kind; cannot catch it")); 242*6881a400Schristos break; 243*6881a400Schristos } 244*6881a400Schristos } 245*6881a400Schristos 246*6881a400Schristos void _initialize_break_catch_fork (); 247*6881a400Schristos void 248*6881a400Schristos _initialize_break_catch_fork () 249*6881a400Schristos { 250*6881a400Schristos add_catch_command ("fork", _("Catch calls to fork."), 251*6881a400Schristos catch_fork_command_1, 252*6881a400Schristos NULL, 253*6881a400Schristos (void *) (uintptr_t) catch_fork_permanent, 254*6881a400Schristos (void *) (uintptr_t) catch_fork_temporary); 255*6881a400Schristos add_catch_command ("vfork", _("Catch calls to vfork."), 256*6881a400Schristos catch_fork_command_1, 257*6881a400Schristos NULL, 258*6881a400Schristos (void *) (uintptr_t) catch_vfork_permanent, 259*6881a400Schristos (void *) (uintptr_t) catch_vfork_temporary); 260*6881a400Schristos } 261