1 /*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993-1996 Rick Sladkey <jrs@world.std.com>
5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 2002-2004 Roland McGrath <roland@redhat.com>
7 * Copyright (c) 2004 Ulrich Drepper <drepper@redhat.com>
8 * Copyright (c) 2009-2013 Denys Vlasenko <dvlasenk@redhat.com>
9 * Copyright (c) 2014-2015 Dmitry V. Levin <ldv@strace.io>
10 * Copyright (c) 2014-2022 The strace developers.
11 * All rights reserved.
12 *
13 * SPDX-License-Identifier: LGPL-2.1-or-later
14 */
15
16 #include "defs.h"
17 #include "ptrace.h"
18
19 #include "wait.h"
20
21 #include "xlat/wait4_options.h"
22 #include "xlat/ptrace_events.h"
23
24 static int
25 printstatus(int status)
26 {
27 int exited = 0;
28
29 /*
30 * Here is a tricky presentation problem. This solution
31 * is still not entirely satisfactory but since there
32 * are no wait status constructors it will have to do.
33 */
34 tprint_indirect_begin();
35 tprint_flags_begin();
36 if (WIFSTOPPED(status)) {
37 int sig = WSTOPSIG(status);
38 tprintf_string("{WIFSTOPPED(s) && WSTOPSIG(s) == %s%s}",
39 sprintsigname(sig & 0x7f),
40 sig & 0x80 ? " | 0x80" : "");
41 status &= ~W_STOPCODE(sig);
42 } else if (WIFSIGNALED(status)) {
43 tprintf_string("{WIFSIGNALED(s) && WTERMSIG(s) == %s%s}",
44 sprintsigname(WTERMSIG(status)),
45 WCOREDUMP(status) ? " && WCOREDUMP(s)" : "");
46 status &= ~(W_EXITCODE(0, WTERMSIG(status)) | WCOREFLAG);
47 } else if (WIFEXITED(status)) {
48 tprintf_string("{WIFEXITED(s) && WEXITSTATUS(s) == %d}",
49 WEXITSTATUS(status));
50 exited = 1;
51 status &= ~W_EXITCODE(WEXITSTATUS(status), 0);
52 }
53 #ifdef WIFCONTINUED
54 else if (WIFCONTINUED(status)) {
55 tprints_string("{WIFCONTINUED(s)}");
56 status &= ~W_CONTINUED;
57 }
58 #endif
59 else {
60 PRINT_VAL_X(status);
61 tprint_flags_end();
62 tprint_indirect_end();
63 return 0;
64 }
65
66 if (status) {
67 unsigned int event = (unsigned int) status >> 16;
68 if (event) {
69 tprint_flags_or();
70 tprint_shift_begin();
71 printxval(ptrace_events, event, "PTRACE_EVENT_???");
72 tprint_shift();
73 PRINT_VAL_U(16);
74 tprint_shift_end();
75 status &= 0xffff;
76 }
77 if (status) {
78 tprint_flags_or();
79 PRINT_VAL_X(status);
80 }
81 }
82 tprint_flags_end();
83 tprint_indirect_end();
84
85 return exited;
86 }
87
88 static int
89 printwaitn(struct tcb *const tcp,
90 void (*const print_rusage)(struct tcb *, kernel_ulong_t))
91 {
92 if (entering(tcp)) {
93 /* pid */
94 printpid_tgid_pgid(tcp, tcp->u_arg[0]);
95 tprint_arg_next();
96 } else {
97 int status;
98
99 /* status */
100 if (tcp->u_rval == 0)
101 printaddr(tcp->u_arg[1]);
102 else if (!umove_or_printaddr(tcp, tcp->u_arg[1], &status))
103 printstatus(status);
104 tprint_arg_next();
105
106 /* options */
107 printflags(wait4_options, tcp->u_arg[2], "W???");
108 if (print_rusage) {
109 tprint_arg_next();
110
111 /* usage */
112 if (tcp->u_rval > 0)
113 print_rusage(tcp, tcp->u_arg[3]);
114 else
115 printaddr(tcp->u_arg[3]);
116 }
117 }
118 return RVAL_TGID;
119 }
120
121 SYS_FUNC(waitpid)
122 {
123 return printwaitn(tcp, NULL);
124 }
125
126 #if HAVE_ARCH_TIME32_SYSCALLS || HAVE_ARCH_OLD_TIME64_SYSCALLS
127 SYS_FUNC(wait4)
128 {
129 return printwaitn(tcp, printrusage);
130 }
131 #endif
132
133 #ifdef ALPHA
134 SYS_FUNC(osf_wait4)
135 {
136 return printwaitn(tcp, printrusage32);
137 }
138 #endif
139
140 #include "xlat/waitid_types.h"
141
142 SYS_FUNC(waitid)
143 {
144 unsigned int idtype = (unsigned int) tcp->u_arg[0];
145 int id = tcp->u_arg[1];
146
147 if (entering(tcp)) {
148 /* idtype */
149 printxval(waitid_types, idtype, "P_???");
150 tprint_arg_next();
151
152 switch (idtype) {
153 case P_PID:
154 printpid(tcp, id, PT_TGID);
155 break;
156 case P_PIDFD:
157 printfd(tcp, id);
158 break;
159 case P_PGID:
160 printpid(tcp, id, PT_PGID);
161 break;
162 default:
163 PRINT_VAL_D(id);
164 break;
165 }
166 tprint_arg_next();
167 } else {
168 /* siginfo */
169 printsiginfo_at(tcp, tcp->u_arg[2]);
170 tprint_arg_next();
171
172 /* options */
173 printflags(wait4_options, tcp->u_arg[3], "W???");
174 tprint_arg_next();
175
176 /* usage */
177 printrusage(tcp, tcp->u_arg[4]);
178 }
179 return 0;
180 }