]>
Commit | Line | Data |
---|---|---|
de8e4cb3 TT |
1 | /* Everything about exec catchpoints, for GDB. |
2 | ||
1d506c26 | 3 | Copyright (C) 1986-2024 Free Software Foundation, Inc. |
de8e4cb3 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 | /* Exec catchpoints. */ | |
32 | ||
33 | /* An instance of this type is used to represent an exec catchpoint. | |
34 | A breakpoint is really of this type iff its ops pointer points to | |
35 | CATCH_EXEC_BREAKPOINT_OPS. */ | |
36 | ||
fed1c982 | 37 | struct exec_catchpoint : public catchpoint |
de8e4cb3 | 38 | { |
fed1c982 TT |
39 | exec_catchpoint (struct gdbarch *gdbarch, bool temp, const char *cond_string) |
40 | : catchpoint (gdbarch, temp, cond_string) | |
73063f51 TT |
41 | { |
42 | } | |
43 | ||
021443b5 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; |
5e632eca | 52 | bool print_one (const bp_location **) const override; |
b713485d | 53 | void print_mention () const override; |
4d1ae558 | 54 | void print_recreate (struct ui_file *fp) const override; |
021443b5 | 55 | |
de8e4cb3 TT |
56 | /* Filename of a program whose exec triggered this catchpoint. |
57 | This field is only valid immediately after this catchpoint has | |
58 | triggered. */ | |
59 | gdb::unique_xmalloc_ptr<char> exec_pathname; | |
60 | }; | |
61 | ||
021443b5 TT |
62 | int |
63 | exec_catchpoint::insert_location (struct bp_location *bl) | |
de8e4cb3 TT |
64 | { |
65 | return target_insert_exec_catchpoint (inferior_ptid.pid ()); | |
66 | } | |
67 | ||
021443b5 TT |
68 | int |
69 | exec_catchpoint::remove_location (struct bp_location *bl, | |
70 | enum remove_bp_reason reason) | |
de8e4cb3 TT |
71 | { |
72 | return target_remove_exec_catchpoint (inferior_ptid.pid ()); | |
73 | } | |
74 | ||
021443b5 TT |
75 | int |
76 | exec_catchpoint::breakpoint_hit (const struct bp_location *bl, | |
77 | const address_space *aspace, | |
78 | CORE_ADDR bp_addr, | |
79 | const target_waitstatus &ws) | |
de8e4cb3 | 80 | { |
de8e4cb3 TT |
81 | if (ws.kind () != TARGET_WAITKIND_EXECD) |
82 | return 0; | |
83 | ||
021443b5 | 84 | exec_pathname = make_unique_xstrdup (ws.execd_pathname ()); |
de8e4cb3 TT |
85 | return 1; |
86 | } | |
87 | ||
021443b5 | 88 | enum print_stop_action |
7bd86313 | 89 | exec_catchpoint::print_it (const bpstat *bs) const |
de8e4cb3 TT |
90 | { |
91 | struct ui_out *uiout = current_uiout; | |
de8e4cb3 | 92 | |
021443b5 | 93 | annotate_catchpoint (number); |
de8e4cb3 | 94 | maybe_print_thread_hit_breakpoint (uiout); |
021443b5 | 95 | if (disposition == disp_del) |
de8e4cb3 TT |
96 | uiout->text ("Temporary catchpoint "); |
97 | else | |
98 | uiout->text ("Catchpoint "); | |
99 | if (uiout->is_mi_like_p ()) | |
100 | { | |
101 | uiout->field_string ("reason", async_reason_lookup (EXEC_ASYNC_EXEC)); | |
021443b5 | 102 | uiout->field_string ("disp", bpdisp_text (disposition)); |
de8e4cb3 | 103 | } |
021443b5 | 104 | uiout->field_signed ("bkptno", number); |
de8e4cb3 | 105 | uiout->text (" (exec'd "); |
021443b5 | 106 | uiout->field_string ("new-exec", exec_pathname.get ()); |
de8e4cb3 TT |
107 | uiout->text ("), "); |
108 | ||
109 | return PRINT_SRC_AND_LOC; | |
110 | } | |
111 | ||
021443b5 | 112 | bool |
5e632eca | 113 | exec_catchpoint::print_one (const bp_location **last_loc) const |
de8e4cb3 | 114 | { |
de8e4cb3 TT |
115 | struct value_print_options opts; |
116 | struct ui_out *uiout = current_uiout; | |
117 | ||
118 | get_user_print_options (&opts); | |
119 | ||
120 | /* Field 4, the address, is omitted (which makes the columns | |
121 | not line up too nicely with the headers, but the effect | |
122 | is relatively readable). */ | |
123 | if (opts.addressprint) | |
124 | uiout->field_skip ("addr"); | |
125 | annotate_field (5); | |
126 | uiout->text ("exec"); | |
021443b5 | 127 | if (exec_pathname != NULL) |
de8e4cb3 TT |
128 | { |
129 | uiout->text (", program \""); | |
021443b5 | 130 | uiout->field_string ("what", exec_pathname.get ()); |
de8e4cb3 TT |
131 | uiout->text ("\" "); |
132 | } | |
133 | ||
134 | if (uiout->is_mi_like_p ()) | |
135 | uiout->field_string ("catch-type", "exec"); | |
c01e038b TT |
136 | |
137 | return true; | |
de8e4cb3 TT |
138 | } |
139 | ||
021443b5 | 140 | void |
b713485d | 141 | exec_catchpoint::print_mention () const |
de8e4cb3 | 142 | { |
021443b5 | 143 | gdb_printf (_("Catchpoint %d (exec)"), number); |
de8e4cb3 TT |
144 | } |
145 | ||
021443b5 | 146 | /* Implement the "print_recreate" method for exec catchpoints. */ |
de8e4cb3 | 147 | |
021443b5 | 148 | void |
4d1ae558 | 149 | exec_catchpoint::print_recreate (struct ui_file *fp) const |
de8e4cb3 | 150 | { |
6cb06a8c | 151 | gdb_printf (fp, "catch exec"); |
04d0163c | 152 | print_recreate_thread (fp); |
de8e4cb3 TT |
153 | } |
154 | ||
de8e4cb3 TT |
155 | /* This function attempts to parse an optional "if <cond>" clause |
156 | from the arg string. If one is not found, it returns NULL. | |
157 | ||
158 | Else, it returns a pointer to the condition string. (It does not | |
159 | attempt to evaluate the string against a particular block.) And, | |
160 | it updates arg to point to the first character following the parsed | |
161 | if clause in the arg string. */ | |
162 | ||
163 | const char * | |
164 | ep_parse_optional_if_clause (const char **arg) | |
165 | { | |
166 | const char *cond_string; | |
167 | ||
168 | if (((*arg)[0] != 'i') || ((*arg)[1] != 'f') || !isspace ((*arg)[2])) | |
169 | return NULL; | |
170 | ||
171 | /* Skip the "if" keyword. */ | |
172 | (*arg) += 2; | |
173 | ||
174 | /* Skip any extra leading whitespace, and record the start of the | |
175 | condition string. */ | |
176 | *arg = skip_spaces (*arg); | |
177 | cond_string = *arg; | |
178 | ||
179 | /* Assume that the condition occupies the remainder of the arg | |
180 | string. */ | |
181 | (*arg) += strlen (cond_string); | |
182 | ||
183 | return cond_string; | |
184 | } | |
185 | ||
186 | /* Commands to deal with catching events, such as signals, exceptions, | |
187 | process start/exit, etc. */ | |
188 | ||
189 | static void | |
190 | catch_exec_command_1 (const char *arg, int from_tty, | |
191 | struct cmd_list_element *command) | |
192 | { | |
193 | struct gdbarch *gdbarch = get_current_arch (); | |
194 | const char *cond_string = NULL; | |
195 | bool temp = command->context () == CATCH_TEMPORARY; | |
196 | ||
197 | if (!arg) | |
198 | arg = ""; | |
199 | arg = skip_spaces (arg); | |
200 | ||
201 | /* The allowed syntax is: | |
202 | catch exec | |
203 | catch exec if <cond> | |
204 | ||
205 | First, check if there's an if clause. */ | |
206 | cond_string = ep_parse_optional_if_clause (&arg); | |
207 | ||
208 | if ((*arg != '\0') && !isspace (*arg)) | |
209 | error (_("Junk at end of arguments.")); | |
210 | ||
fed1c982 TT |
211 | std::unique_ptr<exec_catchpoint> c |
212 | (new exec_catchpoint (gdbarch, temp, cond_string)); | |
de8e4cb3 TT |
213 | |
214 | install_breakpoint (0, std::move (c), 1); | |
215 | } | |
216 | ||
de8e4cb3 TT |
217 | void _initialize_break_catch_exec (); |
218 | void | |
219 | _initialize_break_catch_exec () | |
220 | { | |
de8e4cb3 TT |
221 | add_catch_command ("exec", _("Catch calls to exec."), |
222 | catch_exec_command_1, | |
223 | NULL, | |
224 | CATCH_PERMANENT, | |
225 | CATCH_TEMPORARY); | |
226 | } |