xref: /minix3/minix/usr.bin/trace/call.c (revision 0b98e8aad89f2bd4ba80b523d73cf29e9dd82ce1)
1 
2 #include "inc.h"
3 
4 #include <minix/com.h>
5 #include <minix/callnr.h>
6 #include <minix/endpoint.h>
7 
8 static const struct calls *call_table[] = {
9 	&pm_calls,
10 	&vfs_calls,
11 	&rs_calls,
12 	&vm_calls,
13 	&ipc_calls,
14 };
15 
16 /*
17  * Find a call handler for the given endpoint, call number pair.  Return NULL
18  * if no call handler for this call exists.
19  */
20 static const struct call_handler *
21 find_handler(endpoint_t endpt, int call_nr)
22 {
23 	int i, index;
24 
25 	for (i = 0; i < COUNT(call_table); i++) {
26 		if (call_table[i]->endpt != ANY &&
27 		    call_table[i]->endpt != endpt)
28 			continue;
29 
30 		if (call_nr < call_table[i]->base)
31 			continue;
32 
33 		index = call_nr - call_table[i]->base;
34 
35 		if (index >= call_table[i]->count)
36 			continue;
37 
38 		if (call_table[i]->map[index].outfunc == NULL)
39 			continue;
40 
41 		return &call_table[i]->map[index];
42 	}
43 
44 	return NULL;
45 }
46 
47 /*
48  * Print an endpoint.
49  */
50 void
51 put_endpoint(struct trace_proc * proc, const char * name, endpoint_t endpt)
52 {
53 	const char *text = NULL;
54 
55 	if (!valuesonly) {
56 		switch (endpt) {
57 		TEXT(ASYNCM);
58 		TEXT(IDLE);
59 		TEXT(CLOCK);
60 		TEXT(SYSTEM);
61 		TEXT(KERNEL);
62 		TEXT(PM_PROC_NR);
63 		TEXT(VFS_PROC_NR);
64 		TEXT(RS_PROC_NR);
65 		TEXT(MEM_PROC_NR);
66 		TEXT(SCHED_PROC_NR);
67 		TEXT(TTY_PROC_NR);
68 		TEXT(DS_PROC_NR);
69 		TEXT(VM_PROC_NR);
70 		TEXT(PFS_PROC_NR);
71 		TEXT(ANY);
72 		TEXT(NONE);
73 		TEXT(SELF);
74 		}
75 	}
76 
77 	if (text != NULL)
78 		put_field(proc, name, text);
79 	else
80 		put_value(proc, name, "%d", endpt);
81 }
82 
83 /*
84  * Print a message structure.  The source field will be printed only if the
85  * PF_ALT flag is given.
86  */
87 static void
88 put_message(struct trace_proc * proc, const char * name, int flags,
89 	vir_bytes addr)
90 {
91 	message m;
92 
93 	if (!put_open_struct(proc, name, flags, addr, &m, sizeof(m)))
94 		return;
95 
96 	if (flags & PF_ALT)
97 		put_endpoint(proc, "m_source", m.m_source);
98 
99 	put_value(proc, "m_type", "%x", m.m_type);
100 
101 	put_close_struct(proc, FALSE /*all*/);
102 }
103 
104 /*
105  * Print the call's equals sign, which also implies that the parameters part of
106  * the call has been fully printed and the corresponding closing parenthesis
107  * may have to be printed, if it has not been printed already.
108  */
109 void
110 put_equals(struct trace_proc * proc)
111 {
112 
113 	/*
114 	 * Do not allow multiple equals signs on a single line.  This check is
115 	 * protection against badly written handlers.  It does not work for the
116 	 * no-return type, but such calls are rare and less error prone anyway.
117 	 */
118 	assert((proc->call_flags & (CF_DONE | CF_NORETURN)) != CF_DONE);
119 
120 	/*
121 	 * We allow (and in fact force) handlers to call put_equals in order to
122 	 * indicate that the call's parameters block has ended, so we must end
123 	 * the block here, if we hadn't done so before.
124 	 */
125 	if (!(proc->call_flags & CF_DONE)) {
126 		put_close(proc, ") ");
127 
128 		proc->call_flags |= CF_DONE;
129 	}
130 
131 	put_align(proc);
132 	put_text(proc, "= ");
133 
134 	format_set_sep(proc, NULL);
135 }
136 
137 /*
138  * Print the primary result of a call, after the equals sign.  It is always
139  * possible that this is an IPC-level or other low-level error, in which case
140  * this takes precedence, which is why this function must be called to print
141  * the result if the call failed in any way at all; it may or may not be used
142  * if the call succeeded.  For regular call results, default MINIX3/POSIX
143  * semantics are used: if the return value is negative, the actual call failed
144  * with -1 and the negative return value is the call's error code.  The caller
145  * may consider other cases a failure (e.g., waitpid() returning 0), but
146  * negative return values *not* signifying an error are currently not supported
147  * since they are not present in MINIX3.
148  */
149 void
150 put_result(struct trace_proc * proc)
151 {
152 	const char *errname;
153 	int value;
154 
155 	/* This call should always be preceded by a put_equals call. */
156 	assert(proc->call_flags & CF_DONE);
157 
158 	/*
159 	 * If we failed to copy in the result register or message, print a
160 	 * basic error and nothing else.
161 	 */
162 	if (proc->call_flags & (CF_REG_ERR | CF_MSG_ERR)) {
163 		put_text(proc, "<fault>");
164 
165 		return;
166 	}
167 
168 	/*
169 	 * If we are printing a system call rather than an IPC call, and an
170 	 * error occurred at the IPC level, prefix the output with "<ipc>" to
171 	 * indicate the IPC failure.  If we are printing an IPC call, an IPC-
172 	 * level result is implied, so we do not print this.
173 	 */
174 	if (proc->call_handler != NULL && (proc->call_flags & CF_IPC_ERR))
175 		put_text(proc, "<ipc> ");
176 
177 	value = proc->call_result;
178 
179 	if (value >= 0)
180 		put_fmt(proc, "%d", value);
181 	else if (!valuesonly && (errname = get_error_name(-value)) != NULL)
182 		put_fmt(proc, "-1 [%s]", errname);
183 	else
184 		put_fmt(proc, "-1 [%d]", -value);
185 
186 	format_set_sep(proc, " ");
187 }
188 
189 /*
190  * The default enter-call (out) printer, which prints no parameters and is thus
191  * immediately done with printing parameters.
192  */
193 int
194 default_out(struct trace_proc * __unused proc, const message * __unused m_out)
195 {
196 
197 	return CT_DONE;
198 }
199 
200 /*
201  * The default leave-call (in) printer, which simply prints the call result,
202  * possibly preceded by an equals sign if none was printed yet.  For obvious
203  * reasons, if the handler's out printer returned CT_NOTDONE, this default
204  * printer must not be used.
205  */
206 void
207 default_in(struct trace_proc * proc, const message * __unused m_out,
208 	const message * __unused m_in, int __unused failed)
209 {
210 
211 	if ((proc->call_flags & (CF_DONE | CF_NORETURN)) != CF_DONE)
212 		put_equals(proc);
213 	put_result(proc);
214 }
215 
216 /*
217  * Prepare a sendrec call, by copying in the request message, determining
218  * whether it is one of the calls that the tracing engine should know about,
219  * searching for a handler for the call, and returning a name for the call.
220  */
221 static const char *
222 sendrec_prepare(struct trace_proc * proc, endpoint_t endpt, vir_bytes addr,
223 	int * trace_class)
224 {
225 	const char *name;
226 	int r;
227 
228 	r = mem_get_data(proc->pid, addr, &proc->m_out, sizeof(proc->m_out));
229 
230 	if (r == 0) {
231 		if (endpt == PM_PROC_NR) {
232 			if (proc->m_out.m_type == PM_EXEC)
233 				*trace_class = TC_EXEC;
234 			else if (proc->m_out.m_type == PM_SIGRETURN)
235 				*trace_class = TC_SIGRET;
236 		}
237 
238 		proc->call_handler = find_handler(endpt, proc->m_out.m_type);
239 	} else
240 		proc->call_handler = NULL;
241 
242 	if (proc->call_handler != NULL) {
243 		if (proc->call_handler->namefunc != NULL)
244 			name = proc->call_handler->namefunc(&proc->m_out);
245 		else
246 			name = proc->call_handler->name;
247 
248 		assert(name != NULL);
249 	} else
250 		name = "ipc_sendrec";
251 
252 	return name;
253 }
254 
255 /*
256  * Print the outgoing (request) part of a sendrec call.  If we found a call
257  * handler for the call, let the handler generate output.  Otherwise, print the
258  * sendrec call at the kernel IPC level.  Return the resulting call flags.
259  */
260 static unsigned int
261 sendrec_out(struct trace_proc * proc, endpoint_t endpt, vir_bytes addr)
262 {
263 
264 	if (proc->call_handler != NULL) {
265 		return proc->call_handler->outfunc(proc, &proc->m_out);
266 	} else {
267 		put_endpoint(proc, "src_dest", endpt);
268 		/*
269 		 * We have already copied in the message, but if we used m_out
270 		 * and PF_LOCADDR here, a copy failure would cause "&.." to be
271 		 * printed rather than the actual message address.
272 		 */
273 		put_message(proc, "m_ptr", 0, addr);
274 
275 		return CT_DONE;
276 	}
277 }
278 
279 /*
280  * Print the incoming (reply) part of a sendrec call.  Copy in the reply
281  * message, determine whether the call is considered to have failed, and let
282  * the call handler do the rest.  If no call handler was found, print an
283  * IPC-level result.
284  */
285 static void
286 sendrec_in(struct trace_proc * proc, int failed)
287 {
288 	message m_in;
289 
290 	if (failed) {
291 		/* The call failed at the IPC level. */
292 		memset(&m_in, 0, sizeof(m_in)); /* not supposed to be used */
293 		assert(proc->call_flags & CF_IPC_ERR);
294 	} else if (mem_get_data(proc->pid, proc->m_addr, &m_in,
295 	    sizeof(m_in)) != 0) {
296 		/* The reply message is somehow unavailable to us. */
297 		memset(&m_in, 0, sizeof(m_in)); /* not supposed to be used */
298 		proc->call_result = EGENERIC; /* not supposed to be used */
299 		proc->call_flags |= CF_MSG_ERR;
300 		failed = PF_FAILED;
301 	} else {
302 		/* The result is for the actual call. */
303 		proc->call_result = m_in.m_type;
304 		failed = (proc->call_result < 0) ? PF_FAILED : 0;
305 	}
306 
307 	if (proc->call_handler != NULL)
308 		proc->call_handler->infunc(proc, &proc->m_out, &m_in, failed);
309 	else
310 		put_result(proc);
311 }
312 
313 /*
314  * Perform preparations for printing a system call.  Return two things: the
315  * name to use for the call, and the trace class of the call.
316  * special treatment).
317  */
318 static const char *
319 call_prepare(struct trace_proc * proc, reg_t reg[3], int * trace_class)
320 {
321 
322 	switch (proc->call_type) {
323 	case SENDREC:
324 		return sendrec_prepare(proc, (endpoint_t)reg[1],
325 		    (vir_bytes)reg[2], trace_class);
326 
327 	case SEND:
328 		return "ipc_send";
329 
330 	case SENDNB:
331 		return "ipc_sendnb";
332 
333 	case RECEIVE:
334 		return "ipc_receive";
335 
336 	case NOTIFY:
337 		return "ipc_notify";
338 
339 	case SENDA:
340 		return "ipc_senda";
341 
342 	case MINIX_KERNINFO:
343 		return "minix_kerninfo";
344 
345 	default:
346 		/*
347 		 * It would be nice to include the call number here, but we
348 		 * must return a string that will last until the entire call is
349 		 * finished.  Adding another buffer to the trace_proc structure
350 		 * is an option, but it seems overkill..
351 		 */
352 		return "ipc_unknown";
353 	}
354 }
355 
356 /*
357  * Print the outgoing (request) part of a system call.  Return the resulting
358  * call flags.
359  */
360 static unsigned int
361 call_out(struct trace_proc * proc, reg_t reg[3])
362 {
363 
364 	switch (proc->call_type) {
365 	case SENDREC:
366 		proc->m_addr = (vir_bytes)reg[2];
367 
368 		return sendrec_out(proc, (endpoint_t)reg[1],
369 		    (vir_bytes)reg[2]);
370 
371 	case SEND:
372 	case SENDNB:
373 		put_endpoint(proc, "dest", (endpoint_t)reg[1]);
374 		put_message(proc, "m_ptr", 0, (vir_bytes)reg[2]);
375 
376 		return CT_DONE;
377 
378 	case RECEIVE:
379 		proc->m_addr = (vir_bytes)reg[2];
380 
381 		put_endpoint(proc, "src", (endpoint_t)reg[1]);
382 
383 		return CT_NOTDONE;
384 
385 	case NOTIFY:
386 		put_endpoint(proc, "dest", (endpoint_t)reg[1]);
387 
388 		return CT_DONE;
389 
390 	case SENDA:
391 		put_ptr(proc, "table", (vir_bytes)reg[2]);
392 		put_value(proc, "count", "%zu", (size_t)reg[1]);
393 
394 		return CT_DONE;
395 
396 	case MINIX_KERNINFO:
397 	default:
398 		return CT_DONE;
399 	}
400 }
401 
402 /*
403  * Print the incoming (reply) part of a call.
404  */
405 static void
406 call_in(struct trace_proc * proc, int failed)
407 {
408 
409 	switch (proc->call_type) {
410 	case SENDREC:
411 		sendrec_in(proc, failed);
412 
413 		break;
414 
415 	case RECEIVE:
416 		/* Print the source as well. */
417 		put_message(proc, "m_ptr", failed | PF_ALT, proc->m_addr);
418 		put_equals(proc);
419 		put_result(proc);
420 
421 		break;
422 
423 	case MINIX_KERNINFO:
424 		/*
425 		 * We do not have a platform-independent means to access the
426 		 * secondary IPC return value, so we cannot print the receive
427 		 * status or minix_kerninfo address.
428 		 */
429 		/* FALLTHROUGH */
430 	default:
431 		put_result(proc);
432 
433 		break;
434 	}
435 }
436 
437 /*
438  * Determine whether to skip printing the given call, based on its name.
439  */
440 static int
441 call_hide(const char * __unused name)
442 {
443 
444 	/*
445 	 * TODO: add support for such filtering, with an strace-like -e command
446 	 * line option.  For now, we filter nothing, although calls may still
447 	 * be hidden as the result of a register retrieval error.
448 	 */
449 	return FALSE;
450 }
451 
452 /*
453  * The given process entered a system call.  Return the trace class of the
454  * call: TC_EXEC for an execve() call, TC_SIGRET for a sigreturn() call, or
455  * TC_NORMAL for a call that requires no exceptions in the trace engine.
456  */
457 int
458 call_enter(struct trace_proc * proc, int show_stack)
459 {
460 	const char *name;
461 	reg_t reg[3];
462 	int trace_class, type;
463 
464 	/* Get the IPC-level type and parameters of the system call. */
465 	if (kernel_get_syscall(proc->pid, reg) < 0) {
466 		/*
467 		 * If obtaining the details of the system call failed, even
468 		 * though we know the process is stopped on a system call, we
469 		 * are going to assume that the process got killed somehow.
470 		 * Thus, the best we can do is ignore the system call entirely,
471 		 * and hope that the next thing we hear about this process is
472 		 * its termination.  At worst, we ignore a serious error..
473 		 */
474 		proc->call_flags = CF_HIDE;
475 
476 		return FALSE;
477 	}
478 
479 	/*
480 	 * Obtain the call name that is to be used for this call, and decide
481 	 * whether we want to print this call at all.
482 	 */
483 	proc->call_type = (int)reg[0];
484 	trace_class = TC_NORMAL;
485 
486 	name = call_prepare(proc, reg, &trace_class);
487 
488 	proc->call_name = name;
489 
490 	if (call_hide(name)) {
491 		proc->call_flags = CF_HIDE;
492 
493 		return trace_class;
494 	}
495 
496 	/* Only print a stack trace if we are printing the call itself. */
497 	if (show_stack)
498 		kernel_put_stacktrace(proc);
499 
500 	/*
501 	 * Start a new line, start recording, and print the call name and
502 	 * opening parenthesis.
503 	 */
504 	put_newline();
505 
506 	format_reset(proc);
507 
508 	record_start(proc);
509 
510 	put_text(proc, name);
511 	put_open(proc, NULL, PF_NONAME, "(", ", ");
512 
513 	/*
514 	 * Print the outgoing part of the call, that is, some or all of its
515 	 * parameters.  This call returns flags indicating how far printing
516 	 * got, and may be one of the following combinations:
517 	 * - CT_NOTDONE (0) if printing parameters is not yet complete; after
518 	 *   the call split, the in handler must print the rest itself;
519 	 * - CT_DONE (CF_DONE) if printing parameters is complete, and we
520 	 *   should now print the closing parenthesis and equals sign;
521 	 * - CT_NORETURN (CF_DONE|CF_NORETURN) if printing parameters is
522 	 *   complete, but we should not print the equals sign, because the
523 	 *   call is expected not to return (the no-return call type).
524 	 */
525 	type = call_out(proc, reg);
526 	assert(type == CT_NOTDONE || type == CT_DONE || type == CT_NORETURN);
527 
528 	/*
529 	 * Print whatever the handler told us to print for now.
530 	 */
531 	if (type & CF_DONE) {
532 		if (type & CF_NORETURN) {
533 			put_close(proc, ")");
534 
535 			put_space(proc);
536 
537 			proc->call_flags |= type;
538 		} else {
539 			/*
540 			 * The equals sign is printed implicitly for the
541 			 * CT_DONE type only.  For CT_NORETURN and CT_NOTDONE,
542 			 * the "in" handler has to do it explicitly.
543 			 */
544 			put_equals(proc);
545 		}
546 	} else {
547 		/*
548 		 * If at least one parameter was printed, print the separator
549 		 * now.  We know that another parameter will follow (otherwise
550 		 * the caller would have returned CT_DONE), and this way the
551 		 * output looks better.
552 		 */
553 		format_push_sep(proc);
554 	}
555 
556 	/*
557 	 * We are now at the call split; further printing will be done once the
558 	 * call returns, through call_leave.  Stop recording; if the call gets
559 	 * suspended and later resumed, we should replay everything up to here.
560 	 */
561 #if DEBUG
562 	put_text(proc, "|"); /* warning, this may push a space */
563 #endif
564 
565 	record_stop(proc);
566 
567 	output_flush();
568 
569 	return trace_class;
570 }
571 
572 /*
573  * The given process left a system call, or if skip is set, the leave phase of
574  * the current system call should be ended.
575  */
576 void
577 call_leave(struct trace_proc * proc, int skip)
578 {
579 	reg_t retreg;
580 	int hide, failed;
581 
582 	/* If the call is skipped, it must be a no-return type call. */
583 	assert(!skip || (proc->call_flags & (CF_NORETURN | CF_HIDE)));
584 
585 	/*
586 	 * Start by replaying the current call, if necessary.  If the call was
587 	 * suspended and we are about to print the "in" part, this is obviously
588 	 * needed.  If the call is hidden, replaying will be a no-op, since
589 	 * nothing was recorded for this call.  The special case is a skipped
590 	 * call (which, as established above, must be a no-return call, e.g.
591 	 * exec), for which replaying has the effect that if the call was
592 	 * previously suspended, it will now be replayed, without suspension:
593 	 *
594 	 *       2| execve("./test", ["./test"], [..(12)]) <..>
595 	 *       3| sigsuspend([]) = <..>
596 	 * [A]   2| execve("./test", ["./test"], [..(12)])
597 	 *       2| ---
598 	 *       2| Tracing test (pid 2)
599 	 *
600 	 * The [A] line is the result of replaying the skipped call.
601 	 */
602 	call_replay(proc);
603 
604 	hide = (proc->call_flags & CF_HIDE);
605 
606 	if (!hide && !skip) {
607 		/* Get the IPC-level result of the call. */
608 		if (kernel_get_retreg(proc->pid, &retreg) < 0) {
609 			/* This should never happen.  Deal with it anyway. */
610 			proc->call_flags |= CF_REG_ERR;
611 			failed = PF_FAILED;
612 		} else if ((proc->call_result = (int)retreg) < 0) {
613 			proc->call_flags |= CF_IPC_ERR;
614 			failed = PF_FAILED;
615 		} else
616 			failed = 0;
617 
618 		/*
619 		 * Print the incoming part of the call, that is, possibly some
620 		 * or all of its parameters and the call's closing parenthesis
621 		 * (if CT_NOTDONE), and the equals sign (if not CT_DONE), then
622 		 * the call result.
623 		 */
624 		call_in(proc, failed);
625 	}
626 
627 	if (!hide) {
628 		/*
629 		 * The call is complete now, so clear the recording.  This also
630 		 * implies that no suspension marker will be printed anymore.
631 		 */
632 		record_clear(proc);
633 
634 		put_newline();
635 	}
636 
637 	/*
638 	 * For calls not of the no-return type, an equals sign must have been
639 	 * printed by now.  This is protection against badly written handlers.
640 	 */
641 	assert(proc->call_flags & CF_DONE);
642 
643 	proc->call_name = NULL;
644 	proc->call_flags = 0;
645 }
646 
647 /*
648  * Replay the recorded text, if any, for the enter phase of the given process.
649  * If there is no recorded text, start a new line anyway.
650  */
651 void
652 call_replay(struct trace_proc * proc)
653 {
654 
655 	/*
656 	 * We get TRUE if the recorded call should be replayed, but the
657 	 * recorded text for the call did not fit in the recording buffer.
658 	 * In that case, we have to come up with a replacement text for the
659 	 * call up to the call split.
660 	 */
661 	if (record_replay(proc) == TRUE) {
662 		/*
663 		 * We basically place a "<..>" suspension marker in the
664 		 * parameters part of the call, and use its call name and flags
665 		 * for the rest.  There is a trailing space in all cases.
666 		 */
667 		put_fmt(proc, "%s(<..>%s", proc->call_name,
668 		    !(proc->call_flags & CF_DONE) ? "," :
669 		    ((proc->call_flags & CF_NORETURN) ? ")" : ") ="));
670 		put_space(proc);
671 	}
672 }
673 
674 /*
675  * Return the human-readable name of the call currently being made by the given
676  * process.  The process is guaranteed to be in a call, although the call may
677  * be hidden.  Under no circumstances may this function return a NULL pointer.
678  */
679 const char *
680 call_name(struct trace_proc * proc)
681 {
682 
683 	assert(proc->call_name != NULL);
684 
685 	return proc->call_name;
686 }
687