]>
Commit | Line | Data |
---|---|---|
2f9ee862 TT |
1 | /* Everything about load/unload catchpoints, for GDB. |
2 | ||
3 | Copyright (C) 1986-2022 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 | ||
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; |
a67bcaba | 59 | bool print_one (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 | ||
94 | for (breakpoint *other : all_breakpoints ()) | |
95 | { | |
96 | if (other == bl->owner) | |
97 | continue; | |
98 | ||
99 | if (other->type != bp_shlib_event) | |
100 | continue; | |
101 | ||
89e57567 | 102 | if (pspace != NULL && other->pspace != pspace) |
2f9ee862 TT |
103 | continue; |
104 | ||
105 | for (bp_location *other_bl : other->locations ()) | |
106 | { | |
c47614fe | 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 TT |
119 | { |
120 | for (so_list *iter : current_program_space->added_solibs) | |
121 | { | |
89e57567 TT |
122 | if (!regex |
123 | || compiled->exec (iter->so_name, 0, NULL, 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 | ||
137 | bs->stop = 0; | |
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 TT |
143 | { |
144 | struct breakpoint *b = bs->breakpoint_at; | |
145 | struct ui_out *uiout = current_uiout; | |
146 | ||
147 | annotate_catchpoint (b->number); | |
148 | maybe_print_thread_hit_breakpoint (uiout); | |
149 | if (b->disposition == disp_del) | |
150 | uiout->text ("Temporary catchpoint "); | |
151 | else | |
152 | uiout->text ("Catchpoint "); | |
153 | uiout->field_signed ("bkptno", b->number); | |
154 | uiout->text ("\n"); | |
155 | if (uiout->is_mi_like_p ()) | |
156 | uiout->field_string ("disp", bpdisp_text (b->disposition)); | |
4e9e993a | 157 | print_solib_event (true); |
2f9ee862 TT |
158 | return PRINT_SRC_AND_LOC; |
159 | } | |
160 | ||
89e57567 | 161 | bool |
a67bcaba | 162 | solib_catchpoint::print_one (bp_location **locs) const |
2f9ee862 | 163 | { |
2f9ee862 TT |
164 | struct value_print_options opts; |
165 | struct ui_out *uiout = current_uiout; | |
166 | ||
167 | get_user_print_options (&opts); | |
168 | /* Field 4, the address, is omitted (which makes the columns not | |
169 | line up too nicely with the headers, but the effect is relatively | |
170 | readable). */ | |
171 | if (opts.addressprint) | |
172 | { | |
173 | annotate_field (4); | |
174 | uiout->field_skip ("addr"); | |
175 | } | |
176 | ||
177 | std::string msg; | |
178 | annotate_field (5); | |
89e57567 | 179 | if (is_load) |
2f9ee862 | 180 | { |
89e57567 | 181 | if (regex) |
2f9ee862 | 182 | msg = string_printf (_("load of library matching %s"), |
89e57567 | 183 | regex.get ()); |
2f9ee862 TT |
184 | else |
185 | msg = _("load of library"); | |
186 | } | |
187 | else | |
188 | { | |
89e57567 | 189 | if (regex) |
2f9ee862 | 190 | msg = string_printf (_("unload of library matching %s"), |
89e57567 | 191 | regex.get ()); |
2f9ee862 TT |
192 | else |
193 | msg = _("unload of library"); | |
194 | } | |
195 | uiout->field_string ("what", msg); | |
196 | ||
197 | if (uiout->is_mi_like_p ()) | |
89e57567 | 198 | uiout->field_string ("catch-type", is_load ? "load" : "unload"); |
c01e038b TT |
199 | |
200 | return true; | |
2f9ee862 TT |
201 | } |
202 | ||
89e57567 | 203 | void |
b713485d | 204 | solib_catchpoint::print_mention () const |
2f9ee862 | 205 | { |
89e57567 TT |
206 | gdb_printf (_("Catchpoint %d (%s)"), number, |
207 | is_load ? "load" : "unload"); | |
2f9ee862 TT |
208 | } |
209 | ||
89e57567 | 210 | void |
4d1ae558 | 211 | solib_catchpoint::print_recreate (struct ui_file *fp) const |
2f9ee862 | 212 | { |
2f9ee862 | 213 | gdb_printf (fp, "%s %s", |
89e57567 TT |
214 | disposition == disp_del ? "tcatch" : "catch", |
215 | is_load ? "load" : "unload"); | |
216 | if (regex) | |
217 | gdb_printf (fp, " %s", regex.get ()); | |
2f9ee862 TT |
218 | gdb_printf (fp, "\n"); |
219 | } | |
220 | ||
2f9ee862 TT |
221 | /* See breakpoint.h. */ |
222 | ||
223 | void | |
224 | add_solib_catchpoint (const char *arg, bool is_load, bool is_temp, bool enabled) | |
225 | { | |
226 | struct gdbarch *gdbarch = get_current_arch (); | |
227 | ||
228 | if (!arg) | |
229 | arg = ""; | |
230 | arg = skip_spaces (arg); | |
4874f776 TT |
231 | if (*arg == '\0') |
232 | arg = nullptr; | |
2f9ee862 | 233 | |
fed1c982 TT |
234 | std::unique_ptr<solib_catchpoint> c (new solib_catchpoint (gdbarch, is_temp, |
235 | nullptr, | |
73063f51 | 236 | is_load, arg)); |
2f9ee862 | 237 | |
2f9ee862 TT |
238 | c->enable_state = enabled ? bp_enabled : bp_disabled; |
239 | ||
240 | install_breakpoint (0, std::move (c), 1); | |
241 | } | |
242 | ||
243 | /* A helper function that does all the work for "catch load" and | |
244 | "catch unload". */ | |
245 | ||
246 | static void | |
247 | catch_load_or_unload (const char *arg, int from_tty, int is_load, | |
248 | struct cmd_list_element *command) | |
249 | { | |
250 | const int enabled = 1; | |
251 | bool temp = command->context () == CATCH_TEMPORARY; | |
252 | ||
253 | add_solib_catchpoint (arg, is_load, temp, enabled); | |
254 | } | |
255 | ||
256 | static void | |
257 | catch_load_command_1 (const char *arg, int from_tty, | |
258 | struct cmd_list_element *command) | |
259 | { | |
260 | catch_load_or_unload (arg, from_tty, 1, command); | |
261 | } | |
262 | ||
263 | static void | |
264 | catch_unload_command_1 (const char *arg, int from_tty, | |
265 | struct cmd_list_element *command) | |
266 | { | |
267 | catch_load_or_unload (arg, from_tty, 0, command); | |
268 | } | |
269 | ||
2f9ee862 TT |
270 | void _initialize_break_catch_load (); |
271 | void | |
272 | _initialize_break_catch_load () | |
273 | { | |
2f9ee862 TT |
274 | add_catch_command ("load", _("Catch loads of shared libraries.\n\ |
275 | Usage: catch load [REGEX]\n\ | |
276 | If REGEX is given, only stop for libraries matching the regular expression."), | |
277 | catch_load_command_1, | |
278 | NULL, | |
279 | CATCH_PERMANENT, | |
280 | CATCH_TEMPORARY); | |
281 | add_catch_command ("unload", _("Catch unloads of shared libraries.\n\ | |
282 | Usage: catch unload [REGEX]\n\ | |
283 | If REGEX is given, only stop for libraries matching the regular expression."), | |
284 | catch_unload_command_1, | |
285 | NULL, | |
286 | CATCH_PERMANENT, | |
287 | CATCH_TEMPORARY); | |
288 | } |