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