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