xref: /haiku/src/bin/debug/strace/events.cpp (revision caed67a8cba83913b9c21ac2b06ebc6bd1cb3111)
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
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
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
142 TypeHandlerImpl<fd_set *>::GetReturnValue(Context &context, uint64 value)
143 {
144 	return context.FormatPointer((void *)value);
145 }
146 
147 
148 static string
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
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
210 TypeHandlerImpl<pollfd *>::GetReturnValue(Context &context, uint64 value)
211 {
212 	return context.FormatPointer((void *)value);
213 }
214 
215 
216 static string
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
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
273 TypeHandlerImpl<object_wait_info *>::GetReturnValue(Context &context, uint64 value)
274 {
275 	return context.FormatPointer((void *)value);
276 }
277 
278 
279 static string
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
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
350 TypeHandlerImpl<event_wait_info *>::GetReturnValue(Context &context, uint64 value)
351 {
352 	return context.FormatPointer((void *)value);
353 }
354 
355 
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