1 /*
2 * Copyright 2023-2024, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include <OS.h>
8 #include <poll.h>
9
10 #include <event_queue_defs.h>
11
12 #include "strace.h"
13 #include "Syscall.h"
14 #include "Context.h"
15 #include "MemoryReader.h"
16 #include "TypeHandler.h"
17
18
19 // #pragma mark - enums & flags handlers
20
21
22 struct enum_info {
23 unsigned int index;
24 const char *name;
25 };
26
27 #define ENUM_INFO_ENTRY(name) \
28 { name, #name }
29
30
31 #define FLAG_INFO_ENTRY(name) \
32 { name, #name }
33
34
35 static const FlagsTypeHandler::FlagInfo kPollFlagInfos[] = {
36 FLAG_INFO_ENTRY(POLLIN),
37 FLAG_INFO_ENTRY(POLLOUT),
38 FLAG_INFO_ENTRY(POLLRDBAND),
39 FLAG_INFO_ENTRY(POLLWRBAND),
40 FLAG_INFO_ENTRY(POLLPRI),
41
42 FLAG_INFO_ENTRY(POLLERR),
43 FLAG_INFO_ENTRY(POLLHUP),
44 FLAG_INFO_ENTRY(POLLNVAL),
45
46 { 0, NULL }
47 };
48
49
50 static const FlagsTypeHandler::FlagInfo kEventFlagInfos[] = {
51 FLAG_INFO_ENTRY(B_EVENT_READ),
52 FLAG_INFO_ENTRY(B_EVENT_WRITE),
53 FLAG_INFO_ENTRY(B_EVENT_ERROR),
54 FLAG_INFO_ENTRY(B_EVENT_PRIORITY_READ),
55 FLAG_INFO_ENTRY(B_EVENT_PRIORITY_WRITE),
56 FLAG_INFO_ENTRY(B_EVENT_HIGH_PRIORITY_READ),
57 FLAG_INFO_ENTRY(B_EVENT_HIGH_PRIORITY_WRITE),
58 FLAG_INFO_ENTRY(B_EVENT_DISCONNECTED),
59 FLAG_INFO_ENTRY(B_EVENT_INVALID),
60
61 /* event queue only */
62 FLAG_INFO_ENTRY(B_EVENT_LEVEL_TRIGGERED),
63 FLAG_INFO_ENTRY(B_EVENT_ONE_SHOT),
64
65 { 0, NULL }
66 };
67
68
69 static const char* kObjectTypes[] = {
70 "fd",
71 "sem",
72 "port",
73 "thread",
74 };
75
76
77 static FlagsTypeHandler::FlagsList kPollFlags;
78 static FlagsTypeHandler sPollFlagsHandler(kPollFlags);
79 static FlagsTypeHandler::FlagsList kEventFlags;
80 static FlagsTypeHandler sEventFlagsHandler(kEventFlags);
81
82
83 // #pragma mark - specialized type handlers
84
85
86 static string
read_fdset(Context & context,void * data)87 read_fdset(Context &context, void *data)
88 {
89 // default FD_SETSIZE is 1024
90 unsigned long tmp[1024 / (sizeof(unsigned long) * 8)];
91 int32 bytesRead;
92
93 status_t err = context.Reader().Read(data, &tmp, sizeof(tmp), bytesRead);
94 if (err != B_OK)
95 return context.FormatPointer(data);
96
97 /* implicitly align to unsigned long lower boundary */
98 int count = bytesRead / sizeof(unsigned long);
99 int added = 0;
100
101 string r;
102 r.reserve(16);
103
104 r = "[";
105
106 for (int i = 0; i < count && added < 8; i++) {
107 for (int j = 0;
108 j < (int)(sizeof(unsigned long) * 8) && added < 8; j++) {
109 if (tmp[i] & (1UL << j)) {
110 if (added > 0)
111 r += " ";
112 unsigned int fd = i * sizeof(unsigned long) * 8 + j;
113 r += context.FormatUnsigned(fd);
114 added++;
115 }
116 }
117 }
118
119 if (added >= 8)
120 r += " ...";
121
122 r += "]";
123
124 return r;
125 }
126
127
128 template<>
129 string
GetParameterValue(Context & context,Parameter *,const void * address)130 TypeHandlerImpl<fd_set *>::GetParameterValue(Context &context, Parameter *,
131 const void *address)
132 {
133 void *data = *(void **)address;
134 if (data != NULL && context.GetContents(Context::SIMPLE_STRUCTS))
135 return read_fdset(context, data);
136 return context.FormatPointer(data);
137 }
138
139
140 template<>
141 string
GetReturnValue(Context & context,uint64 value)142 TypeHandlerImpl<fd_set *>::GetReturnValue(Context &context, uint64 value)
143 {
144 return context.FormatPointer((void *)value);
145 }
146
147
148 static string
read_pollfd(Context & context,void * data)149 read_pollfd(Context &context, void *data)
150 {
151 nfds_t numfds = context.ReadValue<nfds_t>(context.GetSibling(1));
152 if ((int64)numfds <= 0)
153 return string();
154
155 pollfd tmp[numfds];
156 int32 bytesRead;
157
158 status_t err = context.Reader().Read(data, &tmp, sizeof(tmp), bytesRead);
159 if (err != B_OK)
160 return context.FormatPointer(data);
161
162 string r;
163 r.reserve(16);
164
165 r = "[";
166
167 int added = 0;
168 for (nfds_t i = 0; i < numfds && added < 8; i++) {
169 if ((tmp[i].fd == -1 || tmp[i].revents == 0)
170 && context.GetContents(Context::OUTPUT_VALUES)) {
171 continue;
172 }
173 if (added > 0)
174 r += ", ";
175 r += "{fd=" + context.FormatSigned(tmp[i].fd);
176 if (tmp[i].fd != -1 && context.GetContents(Context::INPUT_VALUES)) {
177 r += ", events=";
178 r += sPollFlagsHandler.RenderValue(context, tmp[i].events);
179 }
180 if (context.GetContents(Context::OUTPUT_VALUES)) {
181 r += ", revents=";
182 r += sPollFlagsHandler.RenderValue(context, tmp[i].revents);
183 }
184 added++;
185 r += "}";
186 }
187
188 if (added >= 8)
189 r += " ...";
190
191 r += "]";
192 return r;
193 }
194
195
196 template<>
197 string
GetParameterValue(Context & context,Parameter *,const void * address)198 TypeHandlerImpl<pollfd *>::GetParameterValue(Context &context, Parameter *,
199 const void *address)
200 {
201 void *data = *(void **)address;
202 if (data != NULL && context.GetContents(Context::SIMPLE_STRUCTS))
203 return read_pollfd(context, data);
204 return context.FormatPointer(data);
205 }
206
207
208 template<>
209 string
GetReturnValue(Context & context,uint64 value)210 TypeHandlerImpl<pollfd *>::GetReturnValue(Context &context, uint64 value)
211 {
212 return context.FormatPointer((void *)value);
213 }
214
215
216 static string
read_object_wait_infos(Context & context,Parameter * param,void * data)217 read_object_wait_infos(Context &context, Parameter *param, void *data)
218 {
219 int numInfos = context.ReadValue<int>(context.GetNextSibling(param));
220 if (numInfos <= 0)
221 return string();
222
223 object_wait_info tmp[numInfos];
224 int32 bytesRead;
225
226 status_t err = context.Reader().Read(data, &tmp, sizeof(tmp), bytesRead);
227 if (err != B_OK)
228 return context.FormatPointer(data);
229
230 string r;
231 r.reserve(16);
232
233 r = "[";
234
235 for (int i = 0; i < numInfos; i++) {
236 if (i > 0)
237 r += ", ";
238 if (i >= 8) {
239 r += "...";
240 break;
241 }
242
243 r += "{";
244 r += (tmp[i].type < sizeof(kObjectTypes)) ?
245 kObjectTypes[tmp[i].type] : context.FormatUnsigned(tmp[i].type);
246 r += "=";
247 r += context.FormatSigned(tmp[i].object);
248
249 r += ", events=";
250 r += sEventFlagsHandler.RenderValue(context, tmp[i].events);
251 r += "}";
252 }
253
254 r += "]";
255 return r;
256 }
257
258
259 template<>
260 string
GetParameterValue(Context & context,Parameter * param,const void * address)261 TypeHandlerImpl<object_wait_info *>::GetParameterValue(Context &context, Parameter *param,
262 const void *address)
263 {
264 void *data = *(void **)address;
265 if (data != NULL && context.GetContents(Context::SIMPLE_STRUCTS))
266 return read_object_wait_infos(context, param, data);
267 return context.FormatPointer(data);
268 }
269
270
271 template<>
272 string
GetReturnValue(Context & context,uint64 value)273 TypeHandlerImpl<object_wait_info *>::GetReturnValue(Context &context, uint64 value)
274 {
275 return context.FormatPointer((void *)value);
276 }
277
278
279 static string
read_event_wait_infos(Context & context,Parameter * param,void * data)280 read_event_wait_infos(Context &context, Parameter *param, void *data)
281 {
282 int numInfos = 0;
283 if (param->Out())
284 numInfos = context.GetReturnValue();
285 else
286 numInfos = context.ReadValue<int>(context.GetNextSibling(param));
287 if (numInfos <= 0)
288 return context.FormatPointer(data);
289
290 event_wait_info tmp[numInfos];
291 int32 bytesRead;
292
293 status_t err = context.Reader().Read(data, &tmp, sizeof(tmp), bytesRead);
294 if (err != B_OK)
295 return context.FormatPointer(data);
296
297 string r;
298 r.reserve(16);
299
300 r = "[";
301
302 for (int i = 0; i < numInfos; i++) {
303 if (i > 0)
304 r += ", ";
305 if (i >= 8) {
306 r += "...";
307 break;
308 }
309
310 r += "{";
311 r += (tmp[i].type < sizeof(kObjectTypes)) ?
312 kObjectTypes[tmp[i].type] : context.FormatUnsigned(tmp[i].type);
313 r += "=";
314 r += context.FormatSigned(tmp[i].object);
315
316 r += ", events=";
317 if (tmp[i].events == -1)
318 r += "-1";
319 else if (tmp[i].events < 0)
320 r += strerror(tmp[i].events);
321 else
322 r += sEventFlagsHandler.RenderValue(context, tmp[i].events);
323
324 if (tmp[i].user_data != NULL) {
325 r += ", user_data=";
326 r += context.FormatPointer(tmp[i].user_data);
327 }
328 r += "}";
329 }
330
331 r += "]";
332 return r;
333 }
334
335
336 template<>
337 string
GetParameterValue(Context & context,Parameter * param,const void * address)338 TypeHandlerImpl<event_wait_info *>::GetParameterValue(Context &context, Parameter *param,
339 const void *address)
340 {
341 void *data = *(void **)address;
342 if (data != NULL && context.GetContents(Context::SIMPLE_STRUCTS))
343 return read_event_wait_infos(context, param, data);
344 return context.FormatPointer(data);
345 }
346
347
348 template<>
349 string
GetReturnValue(Context & context,uint64 value)350 TypeHandlerImpl<event_wait_info *>::GetReturnValue(Context &context, uint64 value)
351 {
352 return context.FormatPointer((void *)value);
353 }
354
355
DEFINE_TYPE(fdset_ptr,fd_set *)356 DEFINE_TYPE(fdset_ptr, fd_set *)
357 DEFINE_TYPE(pollfd_ptr, pollfd *)
358 DEFINE_TYPE(object_wait_infos_ptr, object_wait_info *)
359 DEFINE_TYPE(event_wait_infos_ptr, event_wait_info *)
360
361
362 // #pragma mark - patch function
363
364
365 void
366 patch_events()
367 {
368 for (int i = 0; kPollFlagInfos[i].name != NULL; i++)
369 kPollFlags.push_back(kPollFlagInfos[i]);
370 for (int i = 0; kEventFlagInfos[i].name != NULL; i++)
371 kEventFlags.push_back(kEventFlagInfos[i]);
372
373 Syscall *poll = get_syscall("_kern_poll");
374 poll->ParameterAt(0)->SetInOut(true);
375
376 Syscall *select = get_syscall("_kern_select");
377 select->ParameterAt(1)->SetInOut(true);
378 select->ParameterAt(2)->SetInOut(true);
379 select->ParameterAt(3)->SetInOut(true);
380
381 Syscall *wait_for_objects = get_syscall("_kern_wait_for_objects");
382 wait_for_objects->ParameterAt(0)->SetInOut(true);
383
384 Syscall *event_queue_select = get_syscall("_kern_event_queue_select");
385 event_queue_select->ParameterAt(1)->SetInOut(true);
386
387 Syscall *event_queue_wait = get_syscall("_kern_event_queue_wait");
388 event_queue_wait->ParameterAt(1)->SetOut(true);
389
390 Syscall *wait_for_child = get_syscall("_kern_wait_for_child");
391 wait_for_child->ParameterAt(2)->SetOut(true);
392 wait_for_child->ParameterAt(3)->SetOut(true);
393
394 Syscall *wait_for_thread = get_syscall("_kern_wait_for_thread");
395 wait_for_thread->ParameterAt(1)->SetOut(true);
396
397 Syscall *wait_for_thread_etc = get_syscall("_kern_wait_for_thread_etc");
398 wait_for_thread_etc->ParameterAt(3)->SetOut(true);
399 }
400