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