1*521fa314SDavid van Moolenbroek 2*521fa314SDavid van Moolenbroek #include "inc.h" 3*521fa314SDavid van Moolenbroek 4*521fa314SDavid van Moolenbroek #include <fcntl.h> 5*521fa314SDavid van Moolenbroek #include <unistd.h> 6*521fa314SDavid van Moolenbroek 7*521fa314SDavid van Moolenbroek /* 8*521fa314SDavid van Moolenbroek * The maximum number of bytes that may be buffered before writing the buffered 9*521fa314SDavid van Moolenbroek * output to the underlying file. This is a performance optimization only. 10*521fa314SDavid van Moolenbroek * Writing more than this number of bytes at once will be handled correctly. 11*521fa314SDavid van Moolenbroek */ 12*521fa314SDavid van Moolenbroek #define OUTPUT_BUFSZ 512 13*521fa314SDavid van Moolenbroek 14*521fa314SDavid van Moolenbroek static int out_fd; 15*521fa314SDavid van Moolenbroek static char out_buf[OUTPUT_BUFSZ]; 16*521fa314SDavid van Moolenbroek static int out_len; 17*521fa314SDavid van Moolenbroek static int out_err; 18*521fa314SDavid van Moolenbroek 19*521fa314SDavid van Moolenbroek static pid_t last_pid; /* not a trace_proc pointer; it could become invalid! */ 20*521fa314SDavid van Moolenbroek static unsigned int line_off; 21*521fa314SDavid van Moolenbroek static unsigned int prefix_off; 22*521fa314SDavid van Moolenbroek static int print_pid; 23*521fa314SDavid van Moolenbroek static int print_susp; 24*521fa314SDavid van Moolenbroek static int add_space; 25*521fa314SDavid van Moolenbroek 26*521fa314SDavid van Moolenbroek /* 27*521fa314SDavid van Moolenbroek * Initialize the output channel. Called before any other output functions, 28*521fa314SDavid van Moolenbroek * but after a child process (to be traced) has already been spawned. If the 29*521fa314SDavid van Moolenbroek * given file string is not NULL, it is the path to a file that is to be used 30*521fa314SDavid van Moolenbroek * to write output to. If it is NULL, output is written to standard error. 31*521fa314SDavid van Moolenbroek */ 32*521fa314SDavid van Moolenbroek int 33*521fa314SDavid van Moolenbroek output_init(const char * file) 34*521fa314SDavid van Moolenbroek { 35*521fa314SDavid van Moolenbroek 36*521fa314SDavid van Moolenbroek /* Initialize state. */ 37*521fa314SDavid van Moolenbroek out_len = 0; 38*521fa314SDavid van Moolenbroek out_err = FALSE; 39*521fa314SDavid van Moolenbroek 40*521fa314SDavid van Moolenbroek last_pid = 0; 41*521fa314SDavid van Moolenbroek line_off = 0; 42*521fa314SDavid van Moolenbroek prefix_off = 0; 43*521fa314SDavid van Moolenbroek print_pid = FALSE; 44*521fa314SDavid van Moolenbroek print_susp = FALSE; 45*521fa314SDavid van Moolenbroek add_space = FALSE; 46*521fa314SDavid van Moolenbroek 47*521fa314SDavid van Moolenbroek /* 48*521fa314SDavid van Moolenbroek * Ignore signals resulting from writing to a closed pipe. We can 49*521fa314SDavid van Moolenbroek * handle write errors properly ourselves. Setting O_NOSIGPIPE is an 50*521fa314SDavid van Moolenbroek * alternative, but that would affect other processes writing to the 51*521fa314SDavid van Moolenbroek * same file object, even after we have terminated. 52*521fa314SDavid van Moolenbroek */ 53*521fa314SDavid van Moolenbroek signal(SIGPIPE, SIG_IGN); 54*521fa314SDavid van Moolenbroek 55*521fa314SDavid van Moolenbroek /* Initialize the output file descriptor. */ 56*521fa314SDavid van Moolenbroek if (file == NULL) { 57*521fa314SDavid van Moolenbroek /* No output file given? Use standard error. */ 58*521fa314SDavid van Moolenbroek out_fd = STDERR_FILENO; 59*521fa314SDavid van Moolenbroek 60*521fa314SDavid van Moolenbroek return 0; 61*521fa314SDavid van Moolenbroek } else { 62*521fa314SDavid van Moolenbroek /* 63*521fa314SDavid van Moolenbroek * Use a restrictive mask for the output file. Traces may 64*521fa314SDavid van Moolenbroek * contain sensitive information (for security and otherwise), 65*521fa314SDavid van Moolenbroek * and the user might not always be careful about the location 66*521fa314SDavid van Moolenbroek * of the file. 67*521fa314SDavid van Moolenbroek */ 68*521fa314SDavid van Moolenbroek /* The file descriptor is not closed explicitly. */ 69*521fa314SDavid van Moolenbroek out_fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 70*521fa314SDavid van Moolenbroek 0600); 71*521fa314SDavid van Moolenbroek 72*521fa314SDavid van Moolenbroek return (out_fd < 0) ? -1 : 0; 73*521fa314SDavid van Moolenbroek } 74*521fa314SDavid van Moolenbroek } 75*521fa314SDavid van Moolenbroek 76*521fa314SDavid van Moolenbroek /* 77*521fa314SDavid van Moolenbroek * Write the given data to the given file descriptor, taking into account the 78*521fa314SDavid van Moolenbroek * possibility of partial writes and write errors. 79*521fa314SDavid van Moolenbroek */ 80*521fa314SDavid van Moolenbroek static void 81*521fa314SDavid van Moolenbroek write_fd(int fd, const char *buf, size_t len) 82*521fa314SDavid van Moolenbroek { 83*521fa314SDavid van Moolenbroek ssize_t r; 84*521fa314SDavid van Moolenbroek 85*521fa314SDavid van Moolenbroek /* If we got a write error before, do not try to write more. */ 86*521fa314SDavid van Moolenbroek if (out_err) 87*521fa314SDavid van Moolenbroek return; 88*521fa314SDavid van Moolenbroek 89*521fa314SDavid van Moolenbroek /* Write all output, in chunks if we have to. */ 90*521fa314SDavid van Moolenbroek while (len > 0) { 91*521fa314SDavid van Moolenbroek r = write(fd, buf, len); 92*521fa314SDavid van Moolenbroek 93*521fa314SDavid van Moolenbroek /* 94*521fa314SDavid van Moolenbroek * A write error (and that includes EOF) causes the program to 95*521fa314SDavid van Moolenbroek * terminate with an error code. For obvious reasons we cannot 96*521fa314SDavid van Moolenbroek * print an error about this. Do not even report to standard 97*521fa314SDavid van Moolenbroek * error if the output was redirected, because that may mess 98*521fa314SDavid van Moolenbroek * with the actual programs being run right now. 99*521fa314SDavid van Moolenbroek */ 100*521fa314SDavid van Moolenbroek if (r <= 0) { 101*521fa314SDavid van Moolenbroek out_err = TRUE; 102*521fa314SDavid van Moolenbroek 103*521fa314SDavid van Moolenbroek break; 104*521fa314SDavid van Moolenbroek } 105*521fa314SDavid van Moolenbroek 106*521fa314SDavid van Moolenbroek len -= r; 107*521fa314SDavid van Moolenbroek } 108*521fa314SDavid van Moolenbroek } 109*521fa314SDavid van Moolenbroek 110*521fa314SDavid van Moolenbroek /* 111*521fa314SDavid van Moolenbroek * Return TRUE iff an output error occurred and the program should terminate. 112*521fa314SDavid van Moolenbroek */ 113*521fa314SDavid van Moolenbroek int 114*521fa314SDavid van Moolenbroek output_error(void) 115*521fa314SDavid van Moolenbroek { 116*521fa314SDavid van Moolenbroek 117*521fa314SDavid van Moolenbroek return out_err; 118*521fa314SDavid van Moolenbroek } 119*521fa314SDavid van Moolenbroek 120*521fa314SDavid van Moolenbroek /* 121*521fa314SDavid van Moolenbroek * Print the given null-terminated string to the output channel. Return the 122*521fa314SDavid van Moolenbroek * number of characters printed, for alignment purposes. In the future, this 123*521fa314SDavid van Moolenbroek * number may end up being different from the number of bytes given to print, 124*521fa314SDavid van Moolenbroek * due to multibyte encoding or colors or whatnot. 125*521fa314SDavid van Moolenbroek */ 126*521fa314SDavid van Moolenbroek static unsigned int 127*521fa314SDavid van Moolenbroek output_write(const char * text) 128*521fa314SDavid van Moolenbroek { 129*521fa314SDavid van Moolenbroek size_t len; 130*521fa314SDavid van Moolenbroek 131*521fa314SDavid van Moolenbroek len = strlen(text); 132*521fa314SDavid van Moolenbroek 133*521fa314SDavid van Moolenbroek if (out_len + len > sizeof(out_buf)) { 134*521fa314SDavid van Moolenbroek write_fd(out_fd, out_buf, out_len); 135*521fa314SDavid van Moolenbroek 136*521fa314SDavid van Moolenbroek out_len = 0; 137*521fa314SDavid van Moolenbroek 138*521fa314SDavid van Moolenbroek /* Write large buffers right away. */ 139*521fa314SDavid van Moolenbroek if (len > sizeof(out_buf)) { 140*521fa314SDavid van Moolenbroek write_fd(out_fd, text, len); 141*521fa314SDavid van Moolenbroek 142*521fa314SDavid van Moolenbroek return len; 143*521fa314SDavid van Moolenbroek } 144*521fa314SDavid van Moolenbroek } 145*521fa314SDavid van Moolenbroek 146*521fa314SDavid van Moolenbroek memcpy(&out_buf[out_len], text, len); 147*521fa314SDavid van Moolenbroek 148*521fa314SDavid van Moolenbroek out_len += len; 149*521fa314SDavid van Moolenbroek 150*521fa314SDavid van Moolenbroek return len; 151*521fa314SDavid van Moolenbroek } 152*521fa314SDavid van Moolenbroek 153*521fa314SDavid van Moolenbroek /* 154*521fa314SDavid van Moolenbroek * Flush any pending output to the output channel. 155*521fa314SDavid van Moolenbroek */ 156*521fa314SDavid van Moolenbroek void 157*521fa314SDavid van Moolenbroek output_flush(void) 158*521fa314SDavid van Moolenbroek { 159*521fa314SDavid van Moolenbroek 160*521fa314SDavid van Moolenbroek if (out_len > 0) { 161*521fa314SDavid van Moolenbroek write_fd(out_fd, out_buf, out_len); 162*521fa314SDavid van Moolenbroek 163*521fa314SDavid van Moolenbroek out_len = 0; 164*521fa314SDavid van Moolenbroek } 165*521fa314SDavid van Moolenbroek } 166*521fa314SDavid van Moolenbroek 167*521fa314SDavid van Moolenbroek /* 168*521fa314SDavid van Moolenbroek * Print a PID prefix for the given process, or an info prefix if no process 169*521fa314SDavid van Moolenbroek * (NULL) is given. Prefixes are only relevant when multiple processes are 170*521fa314SDavid van Moolenbroek * traced. As long as there are multiple processes, each line is prefixed with 171*521fa314SDavid van Moolenbroek * the PID of the process. As soon as the number of processes has been reduced 172*521fa314SDavid van Moolenbroek * back to one, one more line is prefixed with the PID of the remaining process 173*521fa314SDavid van Moolenbroek * (with a "'" instead of a "|") to help the user identify which process is 174*521fa314SDavid van Moolenbroek * left. In addition, whenever a preempted call is about to be resumed, a "*" 175*521fa314SDavid van Moolenbroek * is printed instead of a space, so as to show that it is a continuation of a 176*521fa314SDavid van Moolenbroek * previous line. An example of all these cases: 177*521fa314SDavid van Moolenbroek * 178*521fa314SDavid van Moolenbroek * fork() = 3 179*521fa314SDavid van Moolenbroek * 3| Tracing test (pid 3) 180*521fa314SDavid van Moolenbroek * 3| fork() = 0 181*521fa314SDavid van Moolenbroek * 3| read(0, <..> 182*521fa314SDavid van Moolenbroek * 2| waitpid(-1, <..> 183*521fa314SDavid van Moolenbroek * INFO| This is an example info line. 184*521fa314SDavid van Moolenbroek * 3|*read(0, "", 1024) = 0 185*521fa314SDavid van Moolenbroek * 3| exit(1) 186*521fa314SDavid van Moolenbroek * 3| Process exited normally with code 1 187*521fa314SDavid van Moolenbroek * 2'*waitpid(-1, W_EXITED(1), 0) = 3 188*521fa314SDavid van Moolenbroek * exit(0) 189*521fa314SDavid van Moolenbroek * Process exited normally with code 0 190*521fa314SDavid van Moolenbroek */ 191*521fa314SDavid van Moolenbroek static void 192*521fa314SDavid van Moolenbroek put_prefix(struct trace_proc * proc, int resuming) 193*521fa314SDavid van Moolenbroek { 194*521fa314SDavid van Moolenbroek char prefix[32]; 195*521fa314SDavid van Moolenbroek unsigned int count; 196*521fa314SDavid van Moolenbroek 197*521fa314SDavid van Moolenbroek assert(line_off == 0); 198*521fa314SDavid van Moolenbroek 199*521fa314SDavid van Moolenbroek count = proc_count(); 200*521fa314SDavid van Moolenbroek 201*521fa314SDavid van Moolenbroek /* TODO: add a command line option for always printing the pid. */ 202*521fa314SDavid van Moolenbroek if (print_pid || count > 1 || proc == NULL) { 203*521fa314SDavid van Moolenbroek /* 204*521fa314SDavid van Moolenbroek * TODO: we currently rely on the highest PID having at most 205*521fa314SDavid van Moolenbroek * five digits, but this will eventually change. There are 206*521fa314SDavid van Moolenbroek * several ways to deal with that, but none are great. 207*521fa314SDavid van Moolenbroek */ 208*521fa314SDavid van Moolenbroek if (proc == NULL) 209*521fa314SDavid van Moolenbroek snprintf(prefix, sizeof(prefix), "%5s| ", "INFO"); 210*521fa314SDavid van Moolenbroek else 211*521fa314SDavid van Moolenbroek snprintf(prefix, sizeof(prefix), "%5d%c%c", 212*521fa314SDavid van Moolenbroek proc->pid, (count > 1) ? '|' : '\'', 213*521fa314SDavid van Moolenbroek resuming ? '*' : ' '); 214*521fa314SDavid van Moolenbroek 215*521fa314SDavid van Moolenbroek prefix_off = line_off = output_write(prefix); 216*521fa314SDavid van Moolenbroek 217*521fa314SDavid van Moolenbroek last_pid = (proc != NULL ? proc->pid : 0); 218*521fa314SDavid van Moolenbroek } else { 219*521fa314SDavid van Moolenbroek assert(!resuming); 220*521fa314SDavid van Moolenbroek 221*521fa314SDavid van Moolenbroek prefix_off = 0; 222*521fa314SDavid van Moolenbroek } 223*521fa314SDavid van Moolenbroek 224*521fa314SDavid van Moolenbroek /* Remember whether the next line should get prefixed regardless. */ 225*521fa314SDavid van Moolenbroek print_pid = (count > 1 || proc == NULL); 226*521fa314SDavid van Moolenbroek } 227*521fa314SDavid van Moolenbroek 228*521fa314SDavid van Moolenbroek /* 229*521fa314SDavid van Moolenbroek * Add a string to the end of the text recording for the given process. 230*521fa314SDavid van Moolenbroek * This is used only to record the call-enter output of system calls. 231*521fa314SDavid van Moolenbroek */ 232*521fa314SDavid van Moolenbroek static void 233*521fa314SDavid van Moolenbroek record_add(struct trace_proc * proc, const char * text) 234*521fa314SDavid van Moolenbroek { 235*521fa314SDavid van Moolenbroek size_t len; 236*521fa314SDavid van Moolenbroek 237*521fa314SDavid van Moolenbroek assert(proc->recording); 238*521fa314SDavid van Moolenbroek 239*521fa314SDavid van Moolenbroek /* If the recording buffer is already full, do not record more. */ 240*521fa314SDavid van Moolenbroek if (proc->outlen == sizeof(proc->outbuf)) 241*521fa314SDavid van Moolenbroek return; 242*521fa314SDavid van Moolenbroek 243*521fa314SDavid van Moolenbroek len = strlen(text); 244*521fa314SDavid van Moolenbroek 245*521fa314SDavid van Moolenbroek /* If nonempty, the recording buffer is always null terminated. */ 246*521fa314SDavid van Moolenbroek if (len < sizeof(proc->outbuf) - proc->outlen - 1) { 247*521fa314SDavid van Moolenbroek strcpy(&proc->outbuf[proc->outlen], text); 248*521fa314SDavid van Moolenbroek 249*521fa314SDavid van Moolenbroek proc->outlen += len; 250*521fa314SDavid van Moolenbroek } else 251*521fa314SDavid van Moolenbroek proc->outlen = sizeof(proc->outbuf); /* buffer exhausted */ 252*521fa314SDavid van Moolenbroek } 253*521fa314SDavid van Moolenbroek 254*521fa314SDavid van Moolenbroek /* 255*521fa314SDavid van Moolenbroek * Start recording text for the given process. Since this marks the start of 256*521fa314SDavid van Moolenbroek * a call, remember to print a preemption marker when the call gets preempted. 257*521fa314SDavid van Moolenbroek */ 258*521fa314SDavid van Moolenbroek void 259*521fa314SDavid van Moolenbroek record_start(struct trace_proc * proc) 260*521fa314SDavid van Moolenbroek { 261*521fa314SDavid van Moolenbroek 262*521fa314SDavid van Moolenbroek proc->recording = TRUE; 263*521fa314SDavid van Moolenbroek 264*521fa314SDavid van Moolenbroek print_susp = TRUE; 265*521fa314SDavid van Moolenbroek } 266*521fa314SDavid van Moolenbroek 267*521fa314SDavid van Moolenbroek /* 268*521fa314SDavid van Moolenbroek * Stop recording text for the given process. 269*521fa314SDavid van Moolenbroek */ 270*521fa314SDavid van Moolenbroek void 271*521fa314SDavid van Moolenbroek record_stop(struct trace_proc * proc) 272*521fa314SDavid van Moolenbroek { 273*521fa314SDavid van Moolenbroek 274*521fa314SDavid van Moolenbroek proc->recording = FALSE; 275*521fa314SDavid van Moolenbroek } 276*521fa314SDavid van Moolenbroek 277*521fa314SDavid van Moolenbroek /* 278*521fa314SDavid van Moolenbroek * Clear recorded text for the given process. Since this also marks the end of 279*521fa314SDavid van Moolenbroek * the entire call, no longer print a supension marker before the next newline. 280*521fa314SDavid van Moolenbroek */ 281*521fa314SDavid van Moolenbroek void 282*521fa314SDavid van Moolenbroek record_clear(struct trace_proc * proc) 283*521fa314SDavid van Moolenbroek { 284*521fa314SDavid van Moolenbroek 285*521fa314SDavid van Moolenbroek assert(!proc->recording); 286*521fa314SDavid van Moolenbroek proc->outlen = 0; 287*521fa314SDavid van Moolenbroek 288*521fa314SDavid van Moolenbroek if (proc->pid == last_pid) 289*521fa314SDavid van Moolenbroek print_susp = FALSE; 290*521fa314SDavid van Moolenbroek } 291*521fa314SDavid van Moolenbroek 292*521fa314SDavid van Moolenbroek /* 293*521fa314SDavid van Moolenbroek * Replay the record for the given process on a new line, if the current line 294*521fa314SDavid van Moolenbroek * does not already have output for this process. If it does, do nothing. 295*521fa314SDavid van Moolenbroek * If the process has no recorded output, just start a new line. Return TRUE 296*521fa314SDavid van Moolenbroek * iff the caller must print its own replay text due to a recording overflow. 297*521fa314SDavid van Moolenbroek */ 298*521fa314SDavid van Moolenbroek int 299*521fa314SDavid van Moolenbroek record_replay(struct trace_proc * proc) 300*521fa314SDavid van Moolenbroek { 301*521fa314SDavid van Moolenbroek int space; 302*521fa314SDavid van Moolenbroek 303*521fa314SDavid van Moolenbroek assert(!proc->recording); 304*521fa314SDavid van Moolenbroek 305*521fa314SDavid van Moolenbroek /* 306*521fa314SDavid van Moolenbroek * If there is output on the current line, and it is for the current 307*521fa314SDavid van Moolenbroek * process, we must assume that it is the original, recorded text, and 308*521fa314SDavid van Moolenbroek * thus, we should do nothing. If output on the current line is for 309*521fa314SDavid van Moolenbroek * another process, we must force a new line before replaying. 310*521fa314SDavid van Moolenbroek */ 311*521fa314SDavid van Moolenbroek if (line_off > 0) { 312*521fa314SDavid van Moolenbroek if (proc->pid == last_pid) 313*521fa314SDavid van Moolenbroek return FALSE; 314*521fa314SDavid van Moolenbroek 315*521fa314SDavid van Moolenbroek put_newline(); 316*521fa314SDavid van Moolenbroek } 317*521fa314SDavid van Moolenbroek 318*521fa314SDavid van Moolenbroek /* 319*521fa314SDavid van Moolenbroek * If there is nothing to replay, do nothing further. This case may 320*521fa314SDavid van Moolenbroek * occur when printing signals, in which case the caller still expects 321*521fa314SDavid van Moolenbroek * a new line to be started. This line must not be prefixed with a 322*521fa314SDavid van Moolenbroek * "resuming" marker though--after all, nothing is being resumed here. 323*521fa314SDavid van Moolenbroek */ 324*521fa314SDavid van Moolenbroek if (proc->outlen == 0) 325*521fa314SDavid van Moolenbroek return FALSE; 326*521fa314SDavid van Moolenbroek 327*521fa314SDavid van Moolenbroek /* 328*521fa314SDavid van Moolenbroek * If there is text to replay, then this does mean we are in effect 329*521fa314SDavid van Moolenbroek * resuming the recorded call, even if it is just to print a signal. 330*521fa314SDavid van Moolenbroek * Thus, we must print a prefix that shows the call is being resumed. 331*521fa314SDavid van Moolenbroek * Similarly, unless the recording is cleared before a newline, we must 332*521fa314SDavid van Moolenbroek * suspend the line again, too. 333*521fa314SDavid van Moolenbroek */ 334*521fa314SDavid van Moolenbroek put_prefix(proc, TRUE /*resuming*/); 335*521fa314SDavid van Moolenbroek 336*521fa314SDavid van Moolenbroek print_susp = TRUE; 337*521fa314SDavid van Moolenbroek 338*521fa314SDavid van Moolenbroek /* 339*521fa314SDavid van Moolenbroek * If the recording buffer was exhausted during recording, the caller 340*521fa314SDavid van Moolenbroek * must generate the replay text instead. 341*521fa314SDavid van Moolenbroek */ 342*521fa314SDavid van Moolenbroek if (proc->outlen == sizeof(proc->outbuf)) 343*521fa314SDavid van Moolenbroek return TRUE; 344*521fa314SDavid van Moolenbroek 345*521fa314SDavid van Moolenbroek /* 346*521fa314SDavid van Moolenbroek * Replay the recording. If it ends with a space, turn it into a soft 347*521fa314SDavid van Moolenbroek * space, because the recording may be followed immediately by a 348*521fa314SDavid van Moolenbroek * newline; an example of this is the exit() exception. 349*521fa314SDavid van Moolenbroek */ 350*521fa314SDavid van Moolenbroek space = proc->outbuf[proc->outlen - 1] == ' '; 351*521fa314SDavid van Moolenbroek if (space) 352*521fa314SDavid van Moolenbroek proc->outbuf[proc->outlen - 1] = 0; 353*521fa314SDavid van Moolenbroek 354*521fa314SDavid van Moolenbroek put_text(proc, proc->outbuf); 355*521fa314SDavid van Moolenbroek 356*521fa314SDavid van Moolenbroek if (space) { 357*521fa314SDavid van Moolenbroek put_space(proc); 358*521fa314SDavid van Moolenbroek 359*521fa314SDavid van Moolenbroek /* Restore the space, in case another replay takes place. */ 360*521fa314SDavid van Moolenbroek proc->outbuf[proc->outlen - 1] = ' '; 361*521fa314SDavid van Moolenbroek } 362*521fa314SDavid van Moolenbroek 363*521fa314SDavid van Moolenbroek return FALSE; 364*521fa314SDavid van Moolenbroek } 365*521fa314SDavid van Moolenbroek 366*521fa314SDavid van Moolenbroek /* 367*521fa314SDavid van Moolenbroek * Start a new line, and adjust the local state accordingly. If nothing has 368*521fa314SDavid van Moolenbroek * been printed on the current line yet, this function is a no-op. Otherwise, 369*521fa314SDavid van Moolenbroek * the output so far may have to be marked as preempted with the "<..>" 370*521fa314SDavid van Moolenbroek * preemption marker. 371*521fa314SDavid van Moolenbroek */ 372*521fa314SDavid van Moolenbroek void 373*521fa314SDavid van Moolenbroek put_newline(void) 374*521fa314SDavid van Moolenbroek { 375*521fa314SDavid van Moolenbroek 376*521fa314SDavid van Moolenbroek if (line_off == 0) 377*521fa314SDavid van Moolenbroek return; 378*521fa314SDavid van Moolenbroek 379*521fa314SDavid van Moolenbroek if (print_susp) { 380*521fa314SDavid van Moolenbroek if (add_space) 381*521fa314SDavid van Moolenbroek (void)output_write(" "); 382*521fa314SDavid van Moolenbroek 383*521fa314SDavid van Moolenbroek (void)output_write("<..>"); 384*521fa314SDavid van Moolenbroek } 385*521fa314SDavid van Moolenbroek 386*521fa314SDavid van Moolenbroek #if DEBUG 387*521fa314SDavid van Moolenbroek (void)output_write("|"); 388*521fa314SDavid van Moolenbroek #endif 389*521fa314SDavid van Moolenbroek 390*521fa314SDavid van Moolenbroek (void)output_write("\n"); 391*521fa314SDavid van Moolenbroek output_flush(); 392*521fa314SDavid van Moolenbroek 393*521fa314SDavid van Moolenbroek line_off = 0; 394*521fa314SDavid van Moolenbroek add_space = FALSE; 395*521fa314SDavid van Moolenbroek print_susp = FALSE; 396*521fa314SDavid van Moolenbroek last_pid = 0; 397*521fa314SDavid van Moolenbroek } 398*521fa314SDavid van Moolenbroek 399*521fa314SDavid van Moolenbroek /* 400*521fa314SDavid van Moolenbroek * Print a string as part of the output associated with a process. If the 401*521fa314SDavid van Moolenbroek * current line contains output for another process, a newline will be printed 402*521fa314SDavid van Moolenbroek * first. If the current line contains output for the same process, then the 403*521fa314SDavid van Moolenbroek * text will simply continue on the same line. If the current line is empty, 404*521fa314SDavid van Moolenbroek * a process PID prefix may have to be printed first. Either way, after this 405*521fa314SDavid van Moolenbroek * operation, the current line will contain text for the given process. If 406*521fa314SDavid van Moolenbroek * requested, the text may also be recorded for the process, for later replay. 407*521fa314SDavid van Moolenbroek * As an exception, proc may be NULL when printing general information lines. 408*521fa314SDavid van Moolenbroek */ 409*521fa314SDavid van Moolenbroek void 410*521fa314SDavid van Moolenbroek put_text(struct trace_proc * proc, const char * text) 411*521fa314SDavid van Moolenbroek { 412*521fa314SDavid van Moolenbroek 413*521fa314SDavid van Moolenbroek if (line_off > 0 && (proc == NULL || proc->pid != last_pid)) { 414*521fa314SDavid van Moolenbroek /* 415*521fa314SDavid van Moolenbroek * The current line has not been terminated with a newline yet. 416*521fa314SDavid van Moolenbroek * Start a new line. Note that this means that for lines not 417*521fa314SDavid van Moolenbroek * associated to a process, the whole line must be printed at 418*521fa314SDavid van Moolenbroek * once. This can be fixed but is currently not an issue. 419*521fa314SDavid van Moolenbroek */ 420*521fa314SDavid van Moolenbroek put_newline(); 421*521fa314SDavid van Moolenbroek } 422*521fa314SDavid van Moolenbroek 423*521fa314SDavid van Moolenbroek /* See if we must add a prefix at the start of the line. */ 424*521fa314SDavid van Moolenbroek if (line_off == 0) 425*521fa314SDavid van Moolenbroek put_prefix(proc, FALSE /*resuming*/); 426*521fa314SDavid van Moolenbroek 427*521fa314SDavid van Moolenbroek /* If needed, record the given text. */ 428*521fa314SDavid van Moolenbroek if (proc != NULL && proc->recording) 429*521fa314SDavid van Moolenbroek record_add(proc, text); 430*521fa314SDavid van Moolenbroek 431*521fa314SDavid van Moolenbroek /* 432*521fa314SDavid van Moolenbroek * If we delayed printing a space, print one now. This is never part 433*521fa314SDavid van Moolenbroek * of text that must be saved. In fact, we support these soft spaces 434*521fa314SDavid van Moolenbroek * for exactly one case; see put_space() for details. 435*521fa314SDavid van Moolenbroek */ 436*521fa314SDavid van Moolenbroek if (add_space) { 437*521fa314SDavid van Moolenbroek line_off += output_write(" "); 438*521fa314SDavid van Moolenbroek 439*521fa314SDavid van Moolenbroek add_space = FALSE; 440*521fa314SDavid van Moolenbroek } 441*521fa314SDavid van Moolenbroek 442*521fa314SDavid van Moolenbroek /* Finally, print the actual text. */ 443*521fa314SDavid van Moolenbroek line_off += output_write(text); 444*521fa314SDavid van Moolenbroek 445*521fa314SDavid van Moolenbroek last_pid = (proc != NULL) ? proc->pid : 0; 446*521fa314SDavid van Moolenbroek } 447*521fa314SDavid van Moolenbroek 448*521fa314SDavid van Moolenbroek /* 449*521fa314SDavid van Moolenbroek * Add a space to the output for the given process, but only if and once more 450*521fa314SDavid van Moolenbroek * text is printed for the process afterwards. The aim is to ensure that no 451*521fa314SDavid van Moolenbroek * lines ever end with a space, to prevent needless line wrapping on terminals. 452*521fa314SDavid van Moolenbroek * The space may have to be remembered for the current line (for preemption, 453*521fa314SDavid van Moolenbroek * which does not have a process pointer to work with) as well as recorded for 454*521fa314SDavid van Moolenbroek * later replay, if recording is enabled. Consider the following example: 455*521fa314SDavid van Moolenbroek * 456*521fa314SDavid van Moolenbroek * [A] 3| execve(..) <..> 457*521fa314SDavid van Moolenbroek * 2| getpid(0) = 2 (ppid=1) 458*521fa314SDavid van Moolenbroek * [B] 3| execve(..) = -1 [ENOENT] 459*521fa314SDavid van Moolenbroek * [A] 3| exit(1) <..> 460*521fa314SDavid van Moolenbroek * 2| getpid(0) = 2 (ppid=1) 461*521fa314SDavid van Moolenbroek * 3| exit(1) 462*521fa314SDavid van Moolenbroek * 3| Process exited normally with code 1 463*521fa314SDavid van Moolenbroek * 464*521fa314SDavid van Moolenbroek * On the [A] lines, the space between the call's closing parenthesis and the 465*521fa314SDavid van Moolenbroek * "<..>" preemption marker is the result of add_space being set to TRUE; on 466*521fa314SDavid van Moolenbroek * the [B] line, the space between the closing parenthesis and the equals sign 467*521fa314SDavid van Moolenbroek * is the result of the space being recorded. 468*521fa314SDavid van Moolenbroek */ 469*521fa314SDavid van Moolenbroek void 470*521fa314SDavid van Moolenbroek put_space(struct trace_proc * proc) 471*521fa314SDavid van Moolenbroek { 472*521fa314SDavid van Moolenbroek 473*521fa314SDavid van Moolenbroek /* This call must only be used after output for the given process. */ 474*521fa314SDavid van Moolenbroek assert(last_pid == proc->pid); 475*521fa314SDavid van Moolenbroek 476*521fa314SDavid van Moolenbroek /* In case the call does not get preempted. */ 477*521fa314SDavid van Moolenbroek add_space = TRUE; 478*521fa314SDavid van Moolenbroek 479*521fa314SDavid van Moolenbroek /* In case the call does get preempted. */ 480*521fa314SDavid van Moolenbroek if (proc->recording) 481*521fa314SDavid van Moolenbroek record_add(proc, " "); 482*521fa314SDavid van Moolenbroek } 483*521fa314SDavid van Moolenbroek 484*521fa314SDavid van Moolenbroek /* 485*521fa314SDavid van Moolenbroek * Indent the remainders of the text on the line for this process, such that 486*521fa314SDavid van Moolenbroek * similar remainders are similarly aligned. In particular, the remainder is 487*521fa314SDavid van Moolenbroek * the equals sign of a call, and everything after it. Of course, alignment 488*521fa314SDavid van Moolenbroek * can only be used if the call has not already printed beyond the alignment 489*521fa314SDavid van Moolenbroek * position. Also, the prefix must not be counted toward the alignment, as it 490*521fa314SDavid van Moolenbroek * is possible that a line without prefix may be preempted and later continued 491*521fa314SDavid van Moolenbroek * with prefix. All things considered, the result would look like this: 492*521fa314SDavid van Moolenbroek * 493*521fa314SDavid van Moolenbroek * getuid() = 1 (euid=1) 494*521fa314SDavid van Moolenbroek * setuid(0) = -1 [EPERM] 495*521fa314SDavid van Moolenbroek * write(2, "Permission denied\n", 18) = 18 496*521fa314SDavid van Moolenbroek * fork() = 3 497*521fa314SDavid van Moolenbroek * 3| Tracing test (pid 3) 498*521fa314SDavid van Moolenbroek * 3| fork() = 0 499*521fa314SDavid van Moolenbroek * 3| exit(0) 500*521fa314SDavid van Moolenbroek * 3| Process exited normally with code 0 501*521fa314SDavid van Moolenbroek * 2' waitpid(-1, W_EXITED(0), 0) = 3 502*521fa314SDavid van Moolenbroek * 503*521fa314SDavid van Moolenbroek */ 504*521fa314SDavid van Moolenbroek void put_align(struct trace_proc * __unused proc) 505*521fa314SDavid van Moolenbroek { 506*521fa314SDavid van Moolenbroek 507*521fa314SDavid van Moolenbroek /* 508*521fa314SDavid van Moolenbroek * TODO: add actual support for this. The following code works, 509*521fa314SDavid van Moolenbroek * although not so efficiently. The difficulty is the default 510*521fa314SDavid van Moolenbroek * configuration and corresponding options. 511*521fa314SDavid van Moolenbroek 512*521fa314SDavid van Moolenbroek while (line_off - prefix_off < 20) 513*521fa314SDavid van Moolenbroek put_text(proc, " "); 514*521fa314SDavid van Moolenbroek 515*521fa314SDavid van Moolenbroek */ 516*521fa314SDavid van Moolenbroek } 517