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