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