split out the page dirtying to its own file.
[trinity.git] / log.c
blobd52f0936a7652f72be3411ee505509c52fd6547c
1 #include <errno.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <stdarg.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include "params.h" // logging, monochrome, quiet_level
9 #include "shm.h"
10 #include "pids.h"
11 #include "log.h"
12 #include "arch.h" //PAGE_MASK
13 #include "maps.h" //pages
14 #include "syscall.h" //syscalls
15 #include "tables.h"
16 #include "trinity.h"
18 #define BUFSIZE 1024
20 static FILE *mainlogfile;
21 static bool logfiles_opened = FALSE;
23 void open_logfiles(void)
25 unsigned int i;
26 char *logfilename;
28 logfilename = malloc(64);
29 sprintf(logfilename, "trinity.log");
30 unlink(logfilename);
31 mainlogfile = fopen(logfilename, "a");
32 if (!mainlogfile) {
33 outputerr("## couldn't open logfile %s\n", logfilename);
34 exit(EXIT_FAILURE);
37 for_each_pidslot(i) {
38 sprintf(logfilename, "trinity-child%u.log", i);
39 unlink(logfilename);
40 shm->logfiles[i] = fopen(logfilename, "a");
41 if (!shm->logfiles[i]) {
42 outputerr("## couldn't open logfile %s\n", logfilename);
43 exit(EXIT_FAILURE);
46 free(logfilename);
47 logfiles_opened = TRUE;
50 void close_logfiles(void)
52 unsigned int i;
54 for_each_pidslot(i)
55 if (shm->logfiles[i] != NULL)
56 fclose(shm->logfiles[i]);
59 static FILE * find_logfile_handle(void)
61 pid_t pid;
62 int i;
64 pid = getpid();
65 if (pid == initpid)
66 return mainlogfile;
68 if (pid == shm->mainpid)
69 return mainlogfile;
71 if (pid == watchdog_pid)
72 return mainlogfile;
74 i = find_pid_slot(pid);
75 if (i != PIDSLOT_NOT_FOUND)
76 return shm->logfiles[i];
77 else {
78 /* try one more time. FIXME: This is awful. */
79 unsigned int j;
81 sleep(1);
82 i = find_pid_slot(pid);
83 if (i != PIDSLOT_NOT_FOUND)
84 return shm->logfiles[i];
86 outputerr("## Couldn't find logfile for pid %d\n", pid);
87 dump_pid_slots();
88 outputerr("## Logfiles for pids: ");
89 for_each_pidslot(j)
90 outputerr("%p ", shm->logfiles[j]);
91 outputerr("\n");
93 return NULL;
96 unsigned int highest_logfile(void)
98 FILE *file;
99 int ret;
101 if (logging == FALSE)
102 return 0;
104 file = shm->logfiles[max_children - 1];
105 ret = fileno(file);
107 return ret;
110 void synclogs(void)
112 unsigned int i;
113 int fd;
115 if (logging == FALSE)
116 return;
118 for_each_pidslot(i) {
119 int ret;
121 ret = fflush(shm->logfiles[i]);
122 if (ret == EOF) {
123 outputerr("## logfile flushing failed! %s\n", strerror(errno));
124 continue;
127 fd = fileno(shm->logfiles[i]);
128 if (fd != -1) {
129 ret = fsync(fd);
130 if (ret != 0)
131 outputerr("## fsyncing logfile %d failed. %s\n", i, strerror(errno));
135 (void)fflush(mainlogfile);
136 fsync(fileno(mainlogfile));
139 static void output_arg(unsigned int argnum, struct syscallentry *entry, FILE *fd, bool mono, int childno)
141 enum argtype type = 0;
142 const char *name = NULL;
143 unsigned long reg = 0;
145 switch (argnum) {
146 case 1: type = entry->arg1type;
147 name = entry->arg1name;
148 reg = shm->syscall[childno].a1;
149 break;
150 case 2: type = entry->arg2type;
151 name = entry->arg2name;
152 reg = shm->syscall[childno].a2;
153 break;
154 case 3: type = entry->arg3type;
155 name = entry->arg3name;
156 reg = shm->syscall[childno].a3;
157 break;
158 case 4: type = entry->arg4type;
159 name = entry->arg4name;
160 reg = shm->syscall[childno].a4;
161 break;
162 case 5: type = entry->arg5type;
163 name = entry->arg5name;
164 reg = shm->syscall[childno].a5;
165 break;
166 case 6: type = entry->arg6type;
167 name = entry->arg6name;
168 reg = shm->syscall[childno].a6;
169 break;
172 if (argnum != 1) {
173 CRESETFD
174 fprintf(fd, ", ");
177 fprintf(fd, "%s=", name);
179 switch (type) {
180 case ARG_PATHNAME:
181 fprintf(fd, "\"%s\"", (char *) reg);
182 break;
183 case ARG_PID:
184 case ARG_FD:
185 CRESETFD
186 fprintf(fd, "%ld", (long) reg);
187 break;
188 case ARG_MODE_T:
189 CRESETFD
190 fprintf(fd, "%o", (mode_t) reg);
191 break;
193 case ARG_ADDRESS:
194 case ARG_NON_NULL_ADDRESS:
195 case ARG_IOVEC:
196 case ARG_SOCKADDR:
197 fprintf(fd, "0x%lx", reg);
198 break;
200 case ARG_MMAP:
201 /* Although generic sanitise has set this to a map struct,
202 * common_set_mmap_ptr_len() will subsequently set it to the ->ptr
203 * in the per syscall ->sanitise routine. */
204 fprintf(fd, "%p", (void *) reg);
205 break;
207 case ARG_RANDPAGE:
208 fprintf(fd, "0x%lx [page_rand]", reg);
209 break;
211 case ARG_OP:
212 case ARG_LIST:
213 fprintf(fd, "0x%lx", reg);
214 break;
216 case ARG_UNDEFINED:
217 case ARG_LEN:
218 case ARG_RANGE:
219 case ARG_CPU:
220 case ARG_RANDOM_LONG:
221 case ARG_IOVECLEN:
222 case ARG_SOCKADDRLEN:
223 if (((long) reg < -16384) || ((long) reg > 16384)) {
224 /* Print everything outside -16384 and 16384 as hex. */
225 fprintf(fd, "0x%lx", reg);
226 } else {
227 /* Print everything else as signed decimal. */
228 fprintf(fd, "%ld", (long) reg);
230 CRESETFD
231 break;
234 if ((reg & PAGE_MASK) == (unsigned long) page_zeros)
235 fprintf(fd, "[page_zeros]");
236 if ((reg & PAGE_MASK) == (unsigned long) page_rand)
237 fprintf(fd, "[page_rand]");
238 if ((reg & PAGE_MASK) == (unsigned long) page_0xff)
239 fprintf(fd, "[page_0xff]");
240 if ((reg & PAGE_MASK) == (unsigned long) page_allocs)
241 fprintf(fd, "[page_allocs]");
243 if (entry->decode != NULL) {
244 char *str;
246 str = entry->decode(argnum, childno);
247 if (str != NULL) {
248 fprintf(fd, "%s", str);
249 free(str);
254 static FILE *robust_find_logfile_handle(void)
256 FILE *handle = NULL;
258 if ((logging == TRUE) && (logfiles_opened)) {
259 handle = find_logfile_handle();
260 if (!handle) {
261 unsigned int j;
263 outputerr("## child logfile handle was null logging to main!\n");
264 (void)fflush(stdout);
265 for_each_pidslot(j)
266 shm->logfiles[j] = mainlogfile;
267 sleep(5);
268 handle = find_logfile_handle();
271 return handle;
275 * level defines whether it gets displayed to the screen with printf.
276 * (it always logs).
277 * 0 = everything, even all the registers
278 * 1 = Watchdog prints syscall count
279 * 2 = Just the reseed values
282 void output(unsigned char level, const char *fmt, ...)
284 va_list args;
285 int n;
286 FILE *handle;
287 pid_t pid;
288 char outputbuf[BUFSIZE];
289 char *prefix = NULL;
290 char watchdog_prefix[]="[watchdog]";
291 char init_prefix[]="[init]";
292 char main_prefix[]="[main]";
293 char child_prefix[]="[childNN:1234567890]";
295 if (logging == FALSE && level >= quiet_level)
296 return;
298 /* prefix preparation */
299 pid = getpid();
300 if (pid == watchdog_pid)
301 prefix = watchdog_prefix;
303 if (pid == initpid)
304 prefix = init_prefix;
306 if (pid == shm->mainpid)
307 prefix = main_prefix;
309 if (prefix == NULL) {
310 unsigned int slot;
312 slot = find_pid_slot(pid);
313 sprintf(child_prefix, "[child%u:%u]", slot, pid);
314 prefix = child_prefix;
317 /* formatting output */
318 va_start(args, fmt);
319 n = vsnprintf(outputbuf, sizeof(outputbuf), fmt, args);
320 va_end(args);
321 if (n < 0) {
322 outputerr("## Something went wrong in output() [%d]\n", n);
323 exit(EXIT_FAILURE);
326 /* stdout output if needed */
327 if (quiet_level > level) {
328 printf("%s %s", prefix, outputbuf);
329 (void)fflush(stdout);
332 /* go on with file logs only if enabled */
333 if (logging == FALSE)
334 return;
336 handle = robust_find_logfile_handle();
337 if (!handle)
338 return;
340 /* If we've specified monochrome, we can just dump the buffer into
341 * the logfile as is, because there shouldn't be any ANSI codes
342 * in the buffer to be stripped out. */
343 if (monochrome == FALSE) {
344 char monobuf[BUFSIZE];
345 unsigned int len, i, j;
347 /* copy buffer, sans ANSI codes */
348 len = strlen(outputbuf);
349 for (i = 0, j = 0; (i < len) && (i + 2 < BUFSIZE) && (j < BUFSIZE); i++) {
350 if (outputbuf[i] == '\e') {
351 if (outputbuf[i + 2] == '1')
352 i += 6; // ANSI_COLOUR
353 else
354 i += 3; // ANSI_RESET
355 } else {
356 monobuf[j] = outputbuf[i];
357 j++;
360 monobuf[j] = '\0';
361 fprintf(handle, "%s %s", prefix, monobuf);
362 } else {
363 fprintf(handle, "%s %s", prefix, outputbuf);
366 (void)fflush(handle);
370 * Used as a way to consolidated all printf calls if someones one to redirect it to somewhere else.
371 * note: this function ignores quiet_level since it main purpose is error output.
373 void outputerr(const char *fmt, ...)
375 va_list args;
377 va_start(args, fmt);
378 vfprintf(stderr, fmt, args);
379 va_end(args);
382 void outputstd(const char *fmt, ...)
384 va_list args;
386 va_start(args, fmt);
387 vfprintf(stdout, fmt, args);
388 va_end(args);
391 static void output_syscall_prefix_to_fd(const unsigned int childno, const pid_t pid, const unsigned int syscallnr, FILE *fd, bool mono)
393 struct syscallentry *entry;
394 unsigned int i;
396 entry = syscalls[syscallnr].entry;
398 fprintf(fd, "[child%u:%u] [%lu] %s", childno, pid, shm->child_syscall_count[childno],
399 (shm->syscall[childno].do32bit == TRUE) ? "[32BIT] " : "");
401 if (syscallnr > max_nr_syscalls)
402 fprintf(fd, "%u", syscallnr);
403 else
404 fprintf(fd, "%s", entry->name);
406 CRESETFD
407 fprintf(fd, "(");
409 for (i = 1; i < entry->num_args + 1; i++)
410 output_arg(i, entry, fd, mono, childno);
412 CRESETFD
413 fprintf(fd, ") ");
414 fflush(fd);
417 /* This function is always called from a fuzzing child. */
418 void output_syscall_prefix(const unsigned int childno, const unsigned int syscallnr)
420 FILE *log_handle;
421 pid_t pid;
423 /* Exit if should not continue at all. */
424 if (logging == FALSE && quiet_level < MAX_LOGLEVEL)
425 return;
426 pid = getpid();
428 /* Find the log file handle */
429 log_handle = robust_find_logfile_handle();
431 /* do not output any ascii control symbols to files */
432 if ((logging == TRUE) && (log_handle != NULL))
433 output_syscall_prefix_to_fd(childno, pid, syscallnr, log_handle, TRUE);
435 /* Output to stdout only if -q param is not specified */
436 if (quiet_level == MAX_LOGLEVEL)
437 output_syscall_prefix_to_fd(childno, pid, syscallnr, stdout, monochrome);
440 static void output_syscall_postfix_err(unsigned long ret, int errno_saved, FILE *fd, bool mono)
442 REDFD
443 fprintf(fd, "= %ld (%s)", (long) ret, strerror(errno_saved));
444 CRESETFD
445 fprintf(fd, "\n");
446 fflush(fd);
449 static void output_syscall_postfix_success(unsigned long ret, FILE *fd, bool mono)
451 GREENFD
452 if ((unsigned long)ret > 10000)
453 fprintf(fd, "= 0x%lx", ret);
454 else
455 fprintf(fd, "= %ld", (long) ret);
456 CRESETFD
457 fprintf(fd, "\n");
458 fflush(fd);
461 void output_syscall_postfix(unsigned long ret, int errno_saved, bool err)
463 FILE *log_handle;
465 /* Exit if should not continue at all. */
466 if (logging == FALSE && quiet_level < MAX_LOGLEVEL)
467 return;
469 /* Find the log file handle */
470 log_handle = robust_find_logfile_handle();
472 if (err) {
473 if ((logging == TRUE) && (log_handle != NULL))
474 output_syscall_postfix_err(ret, errno_saved, log_handle, TRUE);
475 if (quiet_level == MAX_LOGLEVEL)
476 output_syscall_postfix_err(ret, errno_saved, stdout, monochrome);
477 } else {
478 if ((logging == TRUE) && (log_handle != NULL))
479 output_syscall_postfix_success(ret, log_handle, TRUE);
480 if (quiet_level == MAX_LOGLEVEL)
481 output_syscall_postfix_success(ret, stdout, monochrome);
485 void debugf(const char *fmt, ...)
487 va_list args;
489 if (debug == TRUE) {
490 va_start(args, fmt);
491 vprintf(fmt, args);
492 va_end(args);