Home | History | Annotate | Line # | Download | only in gdb
      1 /* Everything about load/unload 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 "mi/mi-common.h"
     26 #include "progspace.h"
     27 #include "solist.h"
     28 #include "target.h"
     29 #include "valprint.h"
     30 
     31 /* An instance of this type is used to represent an solib catchpoint.
     32    A breakpoint is really of this type iff its ops pointer points to
     33    CATCH_SOLIB_BREAKPOINT_OPS.  */
     34 
     35 struct solib_catchpoint : public catchpoint
     36 {
     37   solib_catchpoint (struct gdbarch *gdbarch, bool temp,
     38 		    const char *cond_string,
     39 		    bool is_load_, const char *arg)
     40     : catchpoint (gdbarch, temp, cond_string),
     41       is_load (is_load_),
     42       regex (arg == nullptr ? nullptr : make_unique_xstrdup (arg)),
     43       compiled (arg == nullptr
     44 		? nullptr
     45 		: new compiled_regex (arg, REG_NOSUB, _("Invalid regexp")))
     46   {
     47   }
     48 
     49   int insert_location (struct bp_location *) override;
     50   int remove_location (struct bp_location *,
     51 		       enum remove_bp_reason reason) override;
     52   int breakpoint_hit (const struct bp_location *bl,
     53 		      const address_space *aspace,
     54 		      CORE_ADDR bp_addr,
     55 		      const target_waitstatus &ws) override;
     56   void check_status (struct bpstat *bs) override;
     57   enum print_stop_action print_it (const bpstat *bs) const override;
     58   bool print_one (const bp_location **) const override;
     59   void print_mention () const override;
     60   void print_recreate (struct ui_file *fp) const override;
     61 
     62   /* True for "catch load", false for "catch unload".  */
     63   bool is_load;
     64 
     65   /* Regular expression to match, if any.  COMPILED is only valid when
     66      REGEX is non-NULL.  */
     67   gdb::unique_xmalloc_ptr<char> regex;
     68   std::unique_ptr<compiled_regex> compiled;
     69 };
     70 
     71 int
     72 solib_catchpoint::insert_location (struct bp_location *ignore)
     73 {
     74   return 0;
     75 }
     76 
     77 int
     78 solib_catchpoint::remove_location (struct bp_location *ignore,
     79 				   enum remove_bp_reason reason)
     80 {
     81   return 0;
     82 }
     83 
     84 int
     85 solib_catchpoint::breakpoint_hit (const struct bp_location *bl,
     86 				  const address_space *aspace,
     87 				  CORE_ADDR bp_addr,
     88 				  const target_waitstatus &ws)
     89 {
     90   if (ws.kind () == TARGET_WAITKIND_LOADED)
     91     return 1;
     92 
     93   for (breakpoint &other : all_breakpoints ())
     94     {
     95       if (&other == bl->owner)
     96 	continue;
     97 
     98       if (other.type != bp_shlib_event)
     99 	continue;
    100 
    101       if (pspace != NULL && other.pspace != pspace)
    102 	continue;
    103 
    104       for (bp_location &other_bl : other.locations ())
    105 	{
    106 	  if (other.breakpoint_hit (&other_bl, aspace, bp_addr, ws))
    107 	    return 1;
    108 	}
    109     }
    110 
    111   return 0;
    112 }
    113 
    114 void
    115 solib_catchpoint::check_status (struct bpstat *bs)
    116 {
    117   if (is_load)
    118     {
    119       for (solib *iter : current_program_space->added_solibs)
    120 	{
    121 	  if (!regex
    122 	      || compiled->exec (iter->so_name.c_str (), 0, nullptr, 0) == 0)
    123 	    return;
    124 	}
    125     }
    126   else
    127     {
    128       for (const std::string &iter : current_program_space->deleted_solibs)
    129 	{
    130 	  if (!regex
    131 	      || compiled->exec (iter.c_str (), 0, NULL, 0) == 0)
    132 	    return;
    133 	}
    134     }
    135 
    136   bs->stop = false;
    137   bs->print_it = print_it_noop;
    138 }
    139 
    140 enum print_stop_action
    141 solib_catchpoint::print_it (const bpstat *bs) const
    142 {
    143   struct ui_out *uiout = current_uiout;
    144 
    145   annotate_catchpoint (this->number);
    146   maybe_print_thread_hit_breakpoint (uiout);
    147   if (this->disposition == disp_del)
    148     uiout->text ("Temporary catchpoint ");
    149   else
    150     uiout->text ("Catchpoint ");
    151   uiout->field_signed ("bkptno", this->number);
    152   uiout->text ("\n");
    153   if (uiout->is_mi_like_p ())
    154     uiout->field_string ("disp", bpdisp_text (this->disposition));
    155   print_solib_event (true);
    156   return PRINT_SRC_AND_LOC;
    157 }
    158 
    159 bool
    160 solib_catchpoint::print_one (const bp_location **locs) const
    161 {
    162   struct value_print_options opts;
    163   struct ui_out *uiout = current_uiout;
    164 
    165   get_user_print_options (&opts);
    166   /* Field 4, the address, is omitted (which makes the columns not
    167      line up too nicely with the headers, but the effect is relatively
    168      readable).  */
    169   if (opts.addressprint)
    170     {
    171       annotate_field (4);
    172       uiout->field_skip ("addr");
    173     }
    174 
    175   std::string msg;
    176   annotate_field (5);
    177   if (is_load)
    178     {
    179       if (regex)
    180 	msg = string_printf (_("load of library matching %s"),
    181 			     regex.get ());
    182       else
    183 	msg = _("load of library");
    184     }
    185   else
    186     {
    187       if (regex)
    188 	msg = string_printf (_("unload of library matching %s"),
    189 			     regex.get ());
    190       else
    191 	msg = _("unload of library");
    192     }
    193   uiout->field_string ("what", msg);
    194 
    195   if (uiout->is_mi_like_p ())
    196     uiout->field_string ("catch-type", is_load ? "load" : "unload");
    197 
    198   return true;
    199 }
    200 
    201 void
    202 solib_catchpoint::print_mention () const
    203 {
    204   gdb_printf (_("Catchpoint %d (%s)"), number,
    205 	      is_load ? "load" : "unload");
    206 }
    207 
    208 void
    209 solib_catchpoint::print_recreate (struct ui_file *fp) const
    210 {
    211   gdb_printf (fp, "%s %s",
    212 	      disposition == disp_del ? "tcatch" : "catch",
    213 	      is_load ? "load" : "unload");
    214   if (regex)
    215     gdb_printf (fp, " %s", regex.get ());
    216   gdb_printf (fp, "\n");
    217 }
    218 
    219 /* See breakpoint.h.  */
    220 
    221 void
    222 add_solib_catchpoint (const char *arg, bool is_load, bool is_temp, bool enabled)
    223 {
    224   struct gdbarch *gdbarch = get_current_arch ();
    225 
    226   if (!arg)
    227     arg = "";
    228   arg = skip_spaces (arg);
    229   if (*arg == '\0')
    230     arg = nullptr;
    231 
    232   auto c = std::make_unique<solib_catchpoint> (gdbarch, is_temp, nullptr,
    233 					       is_load, arg);
    234 
    235   c->enable_state = enabled ? bp_enabled : bp_disabled;
    236 
    237   install_breakpoint (0, std::move (c), 1);
    238 }
    239 
    240 /* A helper function that does all the work for "catch load" and
    241    "catch unload".  */
    242 
    243 static void
    244 catch_load_or_unload (const char *arg, int from_tty, int is_load,
    245 		      struct cmd_list_element *command)
    246 {
    247   const int enabled = 1;
    248   bool temp = command->context () == CATCH_TEMPORARY;
    249 
    250   add_solib_catchpoint (arg, is_load, temp, enabled);
    251 }
    252 
    253 static void
    254 catch_load_command_1 (const char *arg, int from_tty,
    255 		      struct cmd_list_element *command)
    256 {
    257   catch_load_or_unload (arg, from_tty, 1, command);
    258 }
    259 
    260 static void
    261 catch_unload_command_1 (const char *arg, int from_tty,
    262 			struct cmd_list_element *command)
    263 {
    264   catch_load_or_unload (arg, from_tty, 0, command);
    265 }
    266 
    267 void _initialize_break_catch_load ();
    268 void
    269 _initialize_break_catch_load ()
    270 {
    271   add_catch_command ("load", _("Catch loads of shared libraries.\n\
    272 Usage: catch load [REGEX]\n\
    273 If REGEX is given, only stop for libraries matching the regular expression."),
    274 		     catch_load_command_1,
    275 		     NULL,
    276 		     CATCH_PERMANENT,
    277 		     CATCH_TEMPORARY);
    278   add_catch_command ("unload", _("Catch unloads of shared libraries.\n\
    279 Usage: catch unload [REGEX]\n\
    280 If REGEX is given, only stop for libraries matching the regular expression."),
    281 		     catch_unload_command_1,
    282 		     NULL,
    283 		     CATCH_PERMANENT,
    284 		     CATCH_TEMPORARY);
    285 }
    286