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