8 * The maximum number of bytes that may be buffered before writing the buffered
9 * output to the underlying file. This is a performance optimization only.
10 * Writing more than this number of bytes at once will be handled correctly.
12 #define OUTPUT_BUFSZ 512
15 static char out_buf
[OUTPUT_BUFSZ
];
19 static pid_t last_pid
; /* not a trace_proc pointer; it could become invalid! */
20 static unsigned int line_off
;
21 static unsigned int prefix_off
;
23 static int print_susp
;
27 * Initialize the output channel. Called before any other output functions,
28 * but after a child process (to be traced) has already been spawned. If the
29 * given file string is not NULL, it is the path to a file that is to be used
30 * to write output to. If it is NULL, output is written to standard error.
33 output_init(const char * file
)
36 /* Initialize state. */
48 * Ignore signals resulting from writing to a closed pipe. We can
49 * handle write errors properly ourselves. Setting O_NOSIGPIPE is an
50 * alternative, but that would affect other processes writing to the
51 * same file object, even after we have terminated.
53 signal(SIGPIPE
, SIG_IGN
);
55 /* Initialize the output file descriptor. */
57 /* No output file given? Use standard error. */
58 out_fd
= STDERR_FILENO
;
63 * Use a restrictive mask for the output file. Traces may
64 * contain sensitive information (for security and otherwise),
65 * and the user might not always be careful about the location
68 /* The file descriptor is not closed explicitly. */
69 out_fd
= open(file
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_APPEND
,
72 return (out_fd
< 0) ? -1 : 0;
77 * Write the given data to the given file descriptor, taking into account the
78 * possibility of partial writes and write errors.
81 write_fd(int fd
, const char *buf
, size_t len
)
85 /* If we got a write error before, do not try to write more. */
89 /* Write all output, in chunks if we have to. */
91 r
= write(fd
, buf
, len
);
94 * A write error (and that includes EOF) causes the program to
95 * terminate with an error code. For obvious reasons we cannot
96 * print an error about this. Do not even report to standard
97 * error if the output was redirected, because that may mess
98 * with the actual programs being run right now.
111 * Return TRUE iff an output error occurred and the program should terminate.
121 * Print the given null-terminated string to the output channel. Return the
122 * number of characters printed, for alignment purposes. In the future, this
123 * number may end up being different from the number of bytes given to print,
124 * due to multibyte encoding or colors or whatnot.
127 output_write(const char * text
)
133 if (out_len
+ len
> sizeof(out_buf
)) {
134 write_fd(out_fd
, out_buf
, out_len
);
138 /* Write large buffers right away. */
139 if (len
> sizeof(out_buf
)) {
140 write_fd(out_fd
, text
, len
);
146 memcpy(&out_buf
[out_len
], text
, len
);
154 * Flush any pending output to the output channel.
161 write_fd(out_fd
, out_buf
, out_len
);
168 * Print a PID prefix for the given process, or an info prefix if no process
169 * (NULL) is given. Prefixes are only relevant when multiple processes are
170 * traced. As long as there are multiple processes, each line is prefixed with
171 * the PID of the process. As soon as the number of processes has been reduced
172 * back to one, one more line is prefixed with the PID of the remaining process
173 * (with a "'" instead of a "|") to help the user identify which process is
174 * left. In addition, whenever a preempted call is about to be resumed, a "*"
175 * is printed instead of a space, so as to show that it is a continuation of a
176 * previous line. An example of all these cases:
179 * 3| Tracing test (pid 3)
182 * 2| waitpid(-1, <..>
183 * INFO| This is an example info line.
184 * 3|*read(0, "", 1024) = 0
186 * 3| Process exited normally with code 1
187 * 2'*waitpid(-1, W_EXITED(1), 0) = 3
189 * Process exited normally with code 0
192 put_prefix(struct trace_proc
* proc
, int resuming
)
197 assert(line_off
== 0);
199 count
= proc_count();
201 /* TODO: add a command line option for always printing the pid. */
202 if (print_pid
|| count
> 1 || proc
== NULL
) {
204 * TODO: we currently rely on the highest PID having at most
205 * five digits, but this will eventually change. There are
206 * several ways to deal with that, but none are great.
209 snprintf(prefix
, sizeof(prefix
), "%5s| ", "INFO");
211 snprintf(prefix
, sizeof(prefix
), "%5d%c%c",
212 proc
->pid
, (count
> 1) ? '|' : '\'',
213 resuming
? '*' : ' ');
215 prefix_off
= line_off
= output_write(prefix
);
217 last_pid
= (proc
!= NULL
? proc
->pid
: 0);
224 /* Remember whether the next line should get prefixed regardless. */
225 print_pid
= (count
> 1 || proc
== NULL
);
229 * Add a string to the end of the text recording for the given process.
230 * This is used only to record the call-enter output of system calls.
233 record_add(struct trace_proc
* proc
, const char * text
)
237 assert(proc
->recording
);
239 /* If the recording buffer is already full, do not record more. */
240 if (proc
->outlen
== sizeof(proc
->outbuf
))
245 /* If nonempty, the recording buffer is always null terminated. */
246 if (len
< sizeof(proc
->outbuf
) - proc
->outlen
- 1) {
247 strcpy(&proc
->outbuf
[proc
->outlen
], text
);
251 proc
->outlen
= sizeof(proc
->outbuf
); /* buffer exhausted */
255 * Start recording text for the given process. Since this marks the start of
256 * a call, remember to print a preemption marker when the call gets preempted.
259 record_start(struct trace_proc
* proc
)
262 proc
->recording
= TRUE
;
268 * Stop recording text for the given process.
271 record_stop(struct trace_proc
* proc
)
274 proc
->recording
= FALSE
;
278 * Clear recorded text for the given process. Since this also marks the end of
279 * the entire call, no longer print a supension marker before the next newline.
282 record_clear(struct trace_proc
* proc
)
285 assert(!proc
->recording
);
288 if (proc
->pid
== last_pid
)
293 * Replay the record for the given process on a new line, if the current line
294 * does not already have output for this process. If it does, do nothing.
295 * If the process has no recorded output, just start a new line. Return TRUE
296 * iff the caller must print its own replay text due to a recording overflow.
299 record_replay(struct trace_proc
* proc
)
303 assert(!proc
->recording
);
306 * If there is output on the current line, and it is for the current
307 * process, we must assume that it is the original, recorded text, and
308 * thus, we should do nothing. If output on the current line is for
309 * another process, we must force a new line before replaying.
312 if (proc
->pid
== last_pid
)
319 * If there is nothing to replay, do nothing further. This case may
320 * occur when printing signals, in which case the caller still expects
321 * a new line to be started. This line must not be prefixed with a
322 * "resuming" marker though--after all, nothing is being resumed here.
324 if (proc
->outlen
== 0)
328 * If there is text to replay, then this does mean we are in effect
329 * resuming the recorded call, even if it is just to print a signal.
330 * Thus, we must print a prefix that shows the call is being resumed.
331 * Similarly, unless the recording is cleared before a newline, we must
332 * suspend the line again, too.
334 put_prefix(proc
, TRUE
/*resuming*/);
339 * If the recording buffer was exhausted during recording, the caller
340 * must generate the replay text instead.
342 if (proc
->outlen
== sizeof(proc
->outbuf
))
346 * Replay the recording. If it ends with a space, turn it into a soft
347 * space, because the recording may be followed immediately by a
348 * newline; an example of this is the exit() exception.
350 space
= proc
->outbuf
[proc
->outlen
- 1] == ' ';
352 proc
->outbuf
[proc
->outlen
- 1] = 0;
354 put_text(proc
, proc
->outbuf
);
359 /* Restore the space, in case another replay takes place. */
360 proc
->outbuf
[proc
->outlen
- 1] = ' ';
367 * Start a new line, and adjust the local state accordingly. If nothing has
368 * been printed on the current line yet, this function is a no-op. Otherwise,
369 * the output so far may have to be marked as preempted with the "<..>"
381 (void)output_write(" ");
383 (void)output_write("<..>");
387 (void)output_write("|");
390 (void)output_write("\n");
400 * Print a string as part of the output associated with a process. If the
401 * current line contains output for another process, a newline will be printed
402 * first. If the current line contains output for the same process, then the
403 * text will simply continue on the same line. If the current line is empty,
404 * a process PID prefix may have to be printed first. Either way, after this
405 * operation, the current line will contain text for the given process. If
406 * requested, the text may also be recorded for the process, for later replay.
407 * As an exception, proc may be NULL when printing general information lines.
410 put_text(struct trace_proc
* proc
, const char * text
)
413 if (line_off
> 0 && (proc
== NULL
|| proc
->pid
!= last_pid
)) {
415 * The current line has not been terminated with a newline yet.
416 * Start a new line. Note that this means that for lines not
417 * associated to a process, the whole line must be printed at
418 * once. This can be fixed but is currently not an issue.
423 /* See if we must add a prefix at the start of the line. */
425 put_prefix(proc
, FALSE
/*resuming*/);
427 /* If needed, record the given text. */
428 if (proc
!= NULL
&& proc
->recording
)
429 record_add(proc
, text
);
432 * If we delayed printing a space, print one now. This is never part
433 * of text that must be saved. In fact, we support these soft spaces
434 * for exactly one case; see put_space() for details.
437 line_off
+= output_write(" ");
442 /* Finally, print the actual text. */
443 line_off
+= output_write(text
);
445 last_pid
= (proc
!= NULL
) ? proc
->pid
: 0;
449 * Add a space to the output for the given process, but only if and once more
450 * text is printed for the process afterwards. The aim is to ensure that no
451 * lines ever end with a space, to prevent needless line wrapping on terminals.
452 * The space may have to be remembered for the current line (for preemption,
453 * which does not have a process pointer to work with) as well as recorded for
454 * later replay, if recording is enabled. Consider the following example:
456 * [A] 3| execve(..) <..>
457 * 2| getpid(0) = 2 (ppid=1)
458 * [B] 3| execve(..) = -1 [ENOENT]
459 * [A] 3| exit(1) <..>
460 * 2| getpid(0) = 2 (ppid=1)
462 * 3| Process exited normally with code 1
464 * On the [A] lines, the space between the call's closing parenthesis and the
465 * "<..>" preemption marker is the result of add_space being set to TRUE; on
466 * the [B] line, the space between the closing parenthesis and the equals sign
467 * is the result of the space being recorded.
470 put_space(struct trace_proc
* proc
)
473 /* This call must only be used after output for the given process. */
474 assert(last_pid
== proc
->pid
);
476 /* In case the call does not get preempted. */
479 /* In case the call does get preempted. */
481 record_add(proc
, " ");
485 * Indent the remainders of the text on the line for this process, such that
486 * similar remainders are similarly aligned. In particular, the remainder is
487 * the equals sign of a call, and everything after it. Of course, alignment
488 * can only be used if the call has not already printed beyond the alignment
489 * position. Also, the prefix must not be counted toward the alignment, as it
490 * is possible that a line without prefix may be preempted and later continued
491 * with prefix. All things considered, the result would look like this:
493 * getuid() = 1 (euid=1)
494 * setuid(0) = -1 [EPERM]
495 * write(2, "Permission denied\n", 18) = 18
497 * 3| Tracing test (pid 3)
500 * 3| Process exited normally with code 0
501 * 2' waitpid(-1, W_EXITED(0), 0) = 3
504 void put_align(struct trace_proc
* __unused proc
)
508 * TODO: add actual support for this. The following code works,
509 * although not so efficiently. The difficulty is the default
510 * configuration and corresponding options.
512 while (line_off - prefix_off < 20)