gdb, gdbserver: make target_waitstatus safe
[binutils-gdb.git] / gdb / target / waitstatus.h
1 /* Target waitstatus definitions and prototypes.
2
3 Copyright (C) 1990-2021 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 #ifndef TARGET_WAITSTATUS_H
21 #define TARGET_WAITSTATUS_H
22
23 #include "gdbsupport/gdb_signals.h"
24
25 /* Stuff for target_wait. */
26
27 /* Generally, what has the program done? */
28 enum target_waitkind
29 {
30 /* The program has exited. The exit status is in value.integer. */
31 TARGET_WAITKIND_EXITED,
32
33 /* The program has stopped with a signal. Which signal is in
34 value.sig. */
35 TARGET_WAITKIND_STOPPED,
36
37 /* The program has terminated with a signal. Which signal is in
38 value.sig. */
39 TARGET_WAITKIND_SIGNALLED,
40
41 /* The program is letting us know that it dynamically loaded
42 something (e.g. it called load(2) on AIX). */
43 TARGET_WAITKIND_LOADED,
44
45 /* The program has forked. A "related" process' PTID is in
46 value.related_pid. I.e., if the child forks, value.related_pid
47 is the parent's ID. */
48 TARGET_WAITKIND_FORKED,
49
50 /* The program has vforked. A "related" process's PTID is in
51 value.related_pid. */
52 TARGET_WAITKIND_VFORKED,
53
54 /* The program has exec'ed a new executable file. The new file's
55 pathname is pointed to by value.execd_pathname. */
56 TARGET_WAITKIND_EXECD,
57
58 /* The program had previously vforked, and now the child is done
59 with the shared memory region, because it exec'ed or exited.
60 Note that the event is reported to the vfork parent. This is
61 only used if GDB did not stay attached to the vfork child,
62 otherwise, a TARGET_WAITKIND_EXECD or
63 TARGET_WAITKIND_EXIT|SIGNALLED event associated with the child
64 has the same effect. */
65 TARGET_WAITKIND_VFORK_DONE,
66
67 /* The program has entered or returned from a system call. On
68 HP-UX, this is used in the hardware watchpoint implementation.
69 The syscall's unique integer ID number is in
70 value.syscall_id. */
71 TARGET_WAITKIND_SYSCALL_ENTRY,
72 TARGET_WAITKIND_SYSCALL_RETURN,
73
74 /* Nothing happened, but we stopped anyway. This perhaps should
75 be handled within target_wait, but I'm not sure target_wait
76 should be resuming the inferior. */
77 TARGET_WAITKIND_SPURIOUS,
78
79 /* An event has occured, but we should wait again.
80 Remote_async_wait() returns this when there is an event
81 on the inferior, but the rest of the world is not interested in
82 it. The inferior has not stopped, but has just sent some output
83 to the console, for instance. In this case, we want to go back
84 to the event loop and wait there for another event from the
85 inferior, rather than being stuck in the remote_async_wait()
86 function. This way the event loop is responsive to other events,
87 like for instance the user typing. */
88 TARGET_WAITKIND_IGNORE,
89
90 /* The target has run out of history information,
91 and cannot run backward any further. */
92 TARGET_WAITKIND_NO_HISTORY,
93
94 /* There are no resumed children left in the program. */
95 TARGET_WAITKIND_NO_RESUMED,
96
97 /* The thread was created. */
98 TARGET_WAITKIND_THREAD_CREATED,
99
100 /* The thread has exited. The exit status is in value.integer. */
101 TARGET_WAITKIND_THREAD_EXITED,
102 };
103
104 struct target_waitstatus
105 {
106 /* Default constructor. */
107 target_waitstatus () = default;
108
109 /* Copy constructor. */
110
111 target_waitstatus (const target_waitstatus &other)
112 {
113 m_kind = other.m_kind;
114 m_value = other.m_value;
115
116 if (m_kind == TARGET_WAITKIND_EXECD)
117 m_value.execd_pathname = xstrdup (m_value.execd_pathname);
118 }
119
120 /* Move constructor. */
121
122 target_waitstatus (target_waitstatus &&other)
123 {
124 m_kind = other.m_kind;
125 m_value = other.m_value;
126
127 if (m_kind == TARGET_WAITKIND_EXECD)
128 other.m_value.execd_pathname = nullptr;
129
130 other.reset ();
131 }
132
133 /* Copy assignment operator. */
134
135 target_waitstatus &operator= (const target_waitstatus &rhs)
136 {
137 this->reset ();
138 m_kind = rhs.m_kind;
139 m_value = rhs.m_value;
140
141 if (m_kind == TARGET_WAITKIND_EXECD)
142 m_value.execd_pathname = xstrdup (m_value.execd_pathname);
143
144 return *this;
145 }
146
147 /* Move assignment operator. */
148
149 target_waitstatus &operator= (target_waitstatus &&rhs)
150 {
151 this->reset ();
152 m_kind = rhs.m_kind;
153 m_value = rhs.m_value;
154
155 if (m_kind == TARGET_WAITKIND_EXECD)
156 rhs.m_value.execd_pathname = nullptr;
157
158 rhs.reset ();
159
160 return *this;
161 }
162
163 /* Destructor. */
164
165 ~target_waitstatus ()
166 {
167 this->reset ();
168 }
169
170 /* Setters: set the wait status kind plus any associated data. */
171
172 void set_exited (int exit_status)
173 {
174 this->reset ();
175 m_kind = TARGET_WAITKIND_EXITED;
176 m_value.exit_status = exit_status;
177 }
178
179 void set_stopped (gdb_signal sig)
180 {
181 this->reset ();
182 m_kind = TARGET_WAITKIND_STOPPED;
183 m_value.sig = sig;
184 }
185
186 void set_signalled (gdb_signal sig)
187 {
188 this->reset ();
189 m_kind = TARGET_WAITKIND_SIGNALLED;
190 m_value.sig = sig;
191 }
192
193 void set_loaded ()
194 {
195 this->reset ();
196 m_kind = TARGET_WAITKIND_LOADED;
197 }
198
199 void set_forked (ptid_t child_ptid)
200 {
201 this->reset ();
202 m_kind = TARGET_WAITKIND_FORKED;
203 m_value.child_ptid = child_ptid;
204 }
205
206 void set_vforked (ptid_t child_ptid)
207 {
208 this->reset ();
209 m_kind = TARGET_WAITKIND_VFORKED;
210 m_value.child_ptid = child_ptid;
211 }
212
213 void set_execd (gdb::unique_xmalloc_ptr<char> execd_pathname)
214 {
215 this->reset ();
216 m_kind = TARGET_WAITKIND_EXECD;
217 m_value.execd_pathname = execd_pathname.release ();
218 }
219
220 void set_vfork_done ()
221 {
222 this->reset ();
223 m_kind = TARGET_WAITKIND_VFORK_DONE;
224 }
225
226 void set_syscall_entry (int syscall_number)
227 {
228 this->reset ();
229 m_kind = TARGET_WAITKIND_SYSCALL_ENTRY;
230 m_value.syscall_number = syscall_number;
231 }
232
233 void set_syscall_return (int syscall_number)
234 {
235 this->reset ();
236 m_kind = TARGET_WAITKIND_SYSCALL_RETURN;
237 m_value.syscall_number = syscall_number;
238 }
239
240 void set_spurious ()
241 {
242 this->reset ();
243 m_kind = TARGET_WAITKIND_SPURIOUS;
244 }
245
246 void set_ignore ()
247 {
248 this->reset ();
249 m_kind = TARGET_WAITKIND_IGNORE;
250 }
251
252 void set_no_history ()
253 {
254 this->reset ();
255 m_kind = TARGET_WAITKIND_NO_HISTORY;
256 }
257
258 void set_no_resumed ()
259 {
260 this->reset ();
261 m_kind = TARGET_WAITKIND_NO_RESUMED;
262 }
263
264 void set_thread_created ()
265 {
266 this->reset ();
267 m_kind = TARGET_WAITKIND_THREAD_CREATED;
268 }
269
270 void set_thread_exited (int exit_status)
271 {
272 this->reset ();
273 m_kind = TARGET_WAITKIND_THREAD_EXITED;
274 m_value.exit_status = exit_status;
275 }
276
277 /* Get the kind of this wait status. */
278
279 target_waitkind kind () const
280 {
281 return m_kind;
282 }
283
284 /* Getters for the associated data.
285
286 Getters can only be used if the wait status is of the appropriate kind.
287 See the setters above or the assertions below to know which data is
288 associated to which kind. */
289
290 int exit_status () const
291 {
292 gdb_assert (m_kind == TARGET_WAITKIND_EXITED
293 || m_kind == TARGET_WAITKIND_THREAD_EXITED);
294 return m_value.exit_status;
295 }
296
297 gdb_signal sig () const
298 {
299 gdb_assert (m_kind == TARGET_WAITKIND_STOPPED
300 || m_kind == TARGET_WAITKIND_SIGNALLED);
301 return m_value.sig;
302 }
303
304 ptid_t child_ptid () const
305 {
306 gdb_assert (m_kind == TARGET_WAITKIND_FORKED
307 || m_kind == TARGET_WAITKIND_VFORKED);
308 return m_value.child_ptid;
309 }
310
311 const char *execd_pathname () const
312 {
313 gdb_assert (m_kind == TARGET_WAITKIND_EXECD);
314 return m_value.execd_pathname;
315 }
316
317 int syscall_number () const
318 {
319 gdb_assert (m_kind == TARGET_WAITKIND_SYSCALL_ENTRY
320 || m_kind == TARGET_WAITKIND_SYSCALL_RETURN);
321 return m_value.syscall_number;
322 }
323
324 private:
325 /* Reset the wait status to its original state. */
326 void reset ()
327 {
328 if (m_kind == TARGET_WAITKIND_EXECD)
329 xfree (m_value.execd_pathname);
330
331 m_kind = TARGET_WAITKIND_IGNORE;
332 }
333
334 target_waitkind m_kind = TARGET_WAITKIND_IGNORE;
335
336 /* Additional information about the event. */
337 union
338 {
339 /* Exit status */
340 int exit_status;
341 /* Signal number */
342 enum gdb_signal sig;
343 /* Forked child pid */
344 ptid_t child_ptid;
345 /* execd pathname */
346 char *execd_pathname;
347 /* Syscall number */
348 int syscall_number;
349 } m_value;
350 };
351
352 /* Extended reasons that can explain why a target/thread stopped for a
353 trap signal. */
354
355 enum target_stop_reason
356 {
357 /* Either not stopped, or stopped for a reason that doesn't require
358 special tracking. */
359 TARGET_STOPPED_BY_NO_REASON,
360
361 /* Stopped by a software breakpoint. */
362 TARGET_STOPPED_BY_SW_BREAKPOINT,
363
364 /* Stopped by a hardware breakpoint. */
365 TARGET_STOPPED_BY_HW_BREAKPOINT,
366
367 /* Stopped by a watchpoint. */
368 TARGET_STOPPED_BY_WATCHPOINT,
369
370 /* Stopped by a single step finishing. */
371 TARGET_STOPPED_BY_SINGLE_STEP
372 };
373
374 /* Prototypes */
375
376 /* Return a pretty printed form of target_waitstatus. */
377 std::string target_waitstatus_to_string (const struct target_waitstatus *);
378
379 #endif /* TARGET_WAITSTATUS_H */