1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1989-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Eduardo Krell <ekrell@adexus.cl> *
20 * *
21 ***********************************************************************/
22 #pragma prototyped
23
24 /*
25 * 3d system call trace
26 */
27
28 #define SYSTRACE3D 1
29
30 #include "3d.h"
31
32 #if SYSTRACE3D
33
34 #define SYSCALL syscall3d
35
36 #include "dir_3d.h"
37
38 #ifndef D_FILENO
39 #define D_FILENO(d) (1)
40 #endif
41 #ifndef D_TYPE
42 #define D_TYPE(d) (0)
43 #endif
44
45 #define C_EXIT (MSG_MASK(MSG_exit))
46 #define C_IO (MSG_MASK(MSG_read)|MSG_MASK(MSG_write))
47 #define C_ZERO (MSG_MASK(MSG_pipe))
48
49 typedef union
50 {
51 void* pointer;
52 int number;
53 char* string;
54 char** vector;
55 } ARG;
56
57 static void* dll;
58
59 #if _lib_strerror
60
61 #undef strerror /* otherwise it's _ast_strerror */
62
63 #else
64
65 extern int sys_nerr;
66 extern char* sys_errlist[];
67
68 char*
strerror(int err)69 strerror(int err)
70 {
71 static char msg[28];
72
73 if (err > 0 && err <= sys_nerr)
74 return sys_errlist[err];
75 sfsprintf(msg, sizeof(msg), "Error %d", err);
76 return msg;
77 }
78
79 #endif
80
81 #define MAXBUF 128
82 #define MAXLIN 79
83 #define MAXOUT 2048
84
85 static void
buffer(char ** buf,char * end,register char * s,int n)86 buffer(char** buf, char* end, register char* s, int n)
87 {
88 register char* b;
89 register char* be;
90 register char* se;
91 register int c;
92
93 if (n < 0)
94 bprintf(buf, end, " %p", s);
95 else
96 {
97 b = *buf;
98 be = end;
99 if (be - b > MAXBUF)
100 be = b + MAXBUF;
101 be -= 5;
102 be = be;
103 se = s + n;
104 if (b < be - 1)
105 {
106 *b++ = ' ';
107 *b++ = '"';
108 while (b < be && s < se)
109 {
110 if ((c = *((unsigned char*)s++)) < 040)
111 {
112 *b++ = '\\';
113 switch (c)
114 {
115 case '\007':
116 c = 'a';
117 break;
118 case '\b':
119 c = 'b';
120 break;
121 case '\f':
122 c = 'f';
123 break;
124 case '\n':
125 c = 'n';
126 break;
127 case '\r':
128 c = 'r';
129 break;
130 case '\t':
131 c = 't';
132 break;
133 case '\013':
134 c = 'v';
135 break;
136 case '\033':
137 c = 'E';
138 break;
139 default:
140 if (b < be - 3)
141 {
142 if (n = s < se && c >= '0' && c <= '9')
143 *b++ = '0';
144 if (n || ((c >> 3) & 07))
145 *b++ = '0' + ((c >> 3) & 07);
146 *b++ = '0' + (c & 07);
147 }
148 continue;
149 }
150 if (b < be)
151 *b++ = c;
152 }
153 else if (c < 0177)
154 *b++ = c;
155 else if (c == 0177)
156 {
157 *b++ = '^';
158 if (b >= be)
159 break;
160 *b++ = '?';
161 }
162 else if (b < be - 4)
163 {
164 *b++ = '\\';
165 *b++ = '0' + ((c >> 6) & 03);
166 *b++ = '0' + ((c >> 3) & 07);
167 *b++ = '0' + (c & 07);
168 }
169 }
170 if ((b >= be || s < se) && (be - *buf) >= 4)
171 {
172 b -= 4;
173 *b++ = '"';
174 *b++ = '.';
175 *b++ = '.';
176 *b++ = '.';
177 }
178 else if (b < be)
179 *b++ = '"';
180 }
181 *buf = b;
182 }
183 }
184
185 #if __gnu_linux__
186 #undef _no_exit_exit
187 #endif
188
189 #if _lib_syscall && _sys_syscall
190
191 #include <sys/syscall.h>
192
193 #ifdef SYS_exit
194
195 static void
sys_exit(int code)196 sys_exit(int code)
197 {
198 syscall(SYS_exit, code);
199 }
200
201 #define SYS_EXIT sys_exit
202
203 #endif
204
205 #endif
206
207 /*
208 * initialize the 3d syscall table
209 */
210
211 void
callinit(void)212 callinit(void)
213 {
214 register Systrace_t* cp;
215
216 #if defined(__sgi) && defined(_ABIO32)
217 sys_trace[0].name = "_exit";
218 #endif
219 #if sun && !_sun && _lib_on_exit
220 sys_trace[0].name = "__exit";
221 #endif
222 if (dll = dllnext(RTLD_LAZY))
223 {
224 for (cp = sys_trace; cp < &sys_trace[elementsof(sys_trace)]; cp++)
225 if (!(cp->func = (Sysfunc_t)dlsym(dll, cp->name)) && (*cp->name != '_' || !(cp->func = (Sysfunc_t)dlsym(dll, cp->name + 1)) || !*cp->name++))
226 cp->func = (Sysfunc_t)nosys;
227 #if !defined(SYS_EXIT) && _no_exit_exit
228 state.libexit = (Exitfunc_t)dlsym(dll, "exit");
229 #endif
230 }
231 #ifdef SYS_EXIT
232 sys_trace[0].func = (Sysfunc_t)sys_exit;
233 #endif
234 }
235
236 /*
237 * dump the 3d syscall table
238 */
239
240 void
calldump(char ** b,char * e)241 calldump(char** b, char* e)
242 {
243 register Systrace_t* cp;
244 register int m;
245
246 bprintf(b, e, "\nsystem calls total=%d nosys=%p exit=%p\n\n", elementsof(sys_trace), nosys,
247 #if _no_exit_exit
248 state.libexit
249 #else
250 (Sysfunc_t)0
251 #endif
252 );
253 for (cp = sys_trace; cp < &sys_trace[elementsof(sys_trace)]; cp++)
254 {
255 bprintf(b, e, " %03d%s %03d %12s", cp - sys_trace, (cp - sys_trace) == cp->index ? " " : "*", cp->call, cp->name);
256 for (m = state.trap.size - 1; m >= 0; m--)
257 if (MSG_MASK(cp->call) & state.trap.intercept[m].mask)
258 bprintf(b, e, " %p[%d]", state.trap.intercept[m].call, m);
259 bprintf(b, e, " %p\n", cp->func);
260 }
261 }
262
263 #if _no_exit_exit
264 static int
oksys(void)265 oksys(void)
266 {
267 return 0;
268 }
269
270 void
exit(int code)271 exit(int code)
272 {
273 if (state.libexit)
274 sys_trace[SYS3D_exit].func = (Sysfunc_t)oksys;
275 _exit(code);
276 if (state.libexit)
277 {
278 (*state.libexit)(code);
279 state.libexit = 0;
280 }
281 }
282 #endif
283
284 Sysfunc_t
sysfunc(int call)285 sysfunc(int call)
286 {
287 initialize();
288 return sys_trace[call].func;
289 }
290
291 #if !_var_syscall
292 long
syscall3d(int call,void * a1,void * a2,void * a3,void * a4,void * a5,void * a6)293 syscall3d(int call, void* a1, void* a2, void* a3, void* a4, void* a5, void* a6)
294 {
295 #if 0 /* to convince proto */
296 }
297 #endif
298 #else
299 long
300 syscall3d(int call, ...)
301 {
302 #endif
303 register int n;
304 register long r;
305 register Systrace_t* cp;
306 register ARG* ap;
307 register int ac;
308 int a;
309 int m;
310 int on;
311 char* b;
312 char* e;
313 char* t;
314 char** p;
315 int* ip;
316 ARG arg[7];
317 char buf[MAXOUT];
318 Sysfunc_t func;
319 #if _var_syscall
320 va_list vp;
321 #endif
322
323 initialize();
324 #if _var_syscall
325 va_start(vp, call);
326 #endif
327 cp = sys_trace + call;
328 #if _var_syscall
329 n = cp->args;
330 for (r = 1; r <= elementsof(arg); r++)
331 arg[r].pointer = (r <= n) ? va_arg(vp, void*) : (void*)0;
332 va_end(vp);
333 #else
334 switch (cp->args)
335 {
336 case 6: arg[6].pointer = a6;
337 case 5: arg[5].pointer = a5;
338 case 4: arg[4].pointer = a4;
339 case 3: arg[3].pointer = a3;
340 case 2: arg[2].pointer = a2;
341 case 1: arg[1].pointer = a1;
342 }
343 #endif
344 if (state.kernel || state.trace.pid <= 1 || (on = fsfd(&state.fs[FS_option])) <= 0 || !(state.test & 0100) && !(MSG_MASK(cp->call) & (state.trace.call & ~MSG_MASK(error_info.trace ? 0 : MSG_nop))))
345 on = 0;
346 else
347 {
348 state.kernel++;
349 if (!state.trace.count)
350 {
351 e = (b = buf) + elementsof(buf) - 1;
352 if (state.trace.pid > 2)
353 bprintf(&b, e, "[%d] ", state.trace.pid);
354 bprintf(&b, e, "%s (", cp->name);
355 a = A_INPUT;
356 if (call == SYS3D_write)
357 {
358 if ((m = arg[1].number) == on)
359 a = 0;
360 else if (m == 1 || m == 2)
361 {
362 struct stat st;
363
364 n = errno;
365 if (!fstat(m, &st) && st.st_ino == state.fs[FS_option].st.st_ino && st.st_dev == state.fs[FS_option].st.st_dev)
366 a = 0;
367 errno = n;
368 }
369 }
370 if ((state.test & 020) && call == SYS3D_close) bprintf(&b, e, "%s%s%s", state.file[arg[1].number].reserved ? " [RESERVED]" : "", arg[1].number == TABLE_FD ? " [TABLE]" : "", arg[1].number == state.table.fd ? " [table]" : "");
371 for (ac = 1; ac <= cp->args && (n = cp->type[ac]) >= a; ac++)
372 {
373 ap = &arg[ac];
374 switch (n)
375 {
376 case A_INPUT:
377 if (a)
378 {
379 buffer(&b, e, ap->string, arg[ac + 1].number);
380 break;
381 }
382 /*FALLTHROUGH*/
383 case A_OUTPUT:
384 case A_POINTER:
385 bprintf(&b, e, " %p", ap->number);
386 break;
387 case A_MODE:
388 bprintf(&b, e, " 0%o", ap->number);
389 break;
390 case A_STRING:
391 if (t = ap->string)
392 buffer(&b, e, t, strlen(t));
393 else
394 bprintf(&b, e, " (null)");
395 break;
396 case A_VECTOR:
397 bprintf(&b, e, " [");
398 for (p = ap->vector; *p && p < ap->vector + 8; p++)
399 buffer(&b, e, *p, strlen(*p));
400 if (*p)
401 bprintf(&b, e, "...");
402 bprintf(&b, e, " ]");
403 break;
404 default:
405 bprintf(&b, e, " %d", ap->number);
406 break;
407 }
408 }
409 if (!a)
410 *b++ = '\n';
411 else if (MSG_MASK(cp->call) & C_EXIT)
412 {
413 bprintf(&b, e, " ) = ?\n");
414 state.kernel++;
415 }
416 n = errno;
417 write(on, buf, b - buf);
418 errno = n;
419 }
420 else
421 {
422 if (MSG_MASK(cp->call) & C_EXIT)
423 {
424 e = (b = buf) + elementsof(buf) - 1;
425 *b++ = '\n';
426 if (state.trace.pid > 2)
427 bprintf(&b, e, " [%d] %s\n", state.trace.pid, state.cmd);
428 for (n = 0; n < elementsof(sys_trace); n++)
429 if (sys_trace[n].count)
430 {
431 if (MSG_MASK(sys_trace[n].call) & C_IO)
432 {
433 bprintf(&b, e, " %5d %-10s", sys_trace[n].count, sys_trace[n].name);
434 if (sys_trace[n].megs)
435 bprintf(&b, e, "%5lu.%dm", sys_trace[n].megs, (sys_trace[n].units * 10) >> 20);
436 else
437 bprintf(&b, e, "%5lu.%dk", sys_trace[n].units >> 10, ((sys_trace[n].units & ((1<<10)-1)) * 10) >> 10);
438 }
439 else
440 bprintf(&b, e, " %5d %s", sys_trace[n].count, sys_trace[n].name);
441 if (b < e)
442 *b++ = '\n';
443 }
444 *b++ = '\n';
445 n = errno;
446 write(on, buf, b - buf);
447 errno = n;
448 state.kernel++;
449 }
450 cp->count++;
451 }
452 }
453 for (m = state.trap.size - 1; m >= 0; m--)
454 if (MSG_MASK(cp->call) & state.trap.intercept[m].mask)
455 break;
456 if (m >= 0)
457 {
458 n = state.trap.size;
459 state.trap.size = m;
460 r = (*state.trap.intercept[m].call)(&state.trap.intercept[m], cp->call, call, arg[1].pointer, arg[2].pointer, arg[3].pointer, arg[4].pointer, arg[5].pointer, arg[6].pointer);
461 state.trap.size = n;
462 }
463 else
464 {
465 #if _dynamic_syscall || _static_syscall
466 #if _dynamic_syscall
467 if (dll && cp->func)
468 #else
469 if (dll && cp->func && cp->index < 0)
470 #endif
471 {
472 switch (cp->active++)
473 {
474 case 0:
475 func = cp->func;
476 break;
477 case 1:
478 if (!(func = cp->last))
479 {
480 if (!(cp->last = (Sysfunc_t)dlsym(dll, cp->name)) && (*cp->name != '_' || !(cp->last = (Sysfunc_t)dlsym(dll, cp->name + 1)) || !*cp->name++))
481 cp->last = (Sysfunc_t)nosys;
482 func = cp->last;
483 if (func == cp->func)
484 {
485 /*
486 * longjmp gets you here
487 */
488
489 cp->active = 3;
490 }
491 else if (cp->func != (Sysfunc_t)nosys && func == (Sysfunc_t)nosys)
492 {
493 cp->active = 10;
494 e = (b = buf) + elementsof(buf) - 1;
495 bprintf(&b, e, "3d: %s: system call loop -- cannot determine the real system call\n", cp->name);
496 write(2, buf, b - buf);
497 }
498 }
499 break;
500 case 2:
501 case 3:
502 cp->active = 3;
503 func = cp->func;
504 break;
505 default:
506 cp->active = 10;
507 func = (Sysfunc_t)nosys;
508 break;
509 }
510 r = (*func)(arg[1].pointer, arg[2].pointer, arg[3].pointer, arg[4].pointer, arg[5].pointer, arg[6].pointer);
511 cp->active--;
512 }
513 else
514 #endif
515 #if _lib_syscall
516 if (cp->index >= 0)
517 r = syscall(cp->index, arg[1].pointer, arg[2].pointer, arg[3].pointer, arg[4].pointer, arg[5].pointer, arg[6].pointer);
518 else if (cp->nov >= 0)
519 r = syscall(cp->nov, arg[2].pointer, arg[3].pointer, arg[4].pointer, arg[5].pointer, arg[6].pointer, 0);
520 else
521 #endif
522 {
523 #ifndef ENOSYS
524 #define ENOSYS EINVAL
525 #endif
526 errno = ENOSYS;
527 r = -1;
528 }
529 }
530 #if !_mangle_syscall
531 if (r > 0 && (MSG_MASK(cp->call) & C_ZERO))
532 r = 0;
533 #endif
534 if (on && state.kernel <= 1)
535 {
536 if (!state.trace.count)
537 {
538 if ((m = MAXLIN - (b - buf)) < 0)
539 m = 0;
540 b = buf;
541 for (; ac <= cp->args; ac++)
542 {
543 ap = &arg[ac];
544 switch (n = cp->type[ac])
545 {
546 case A_OUTPUT:
547 switch (call)
548 {
549 case SYS3D_fstat:
550 #ifdef SYS3D_lstat
551 case SYS3D_lstat:
552 #endif
553 case SYS3D_stat:
554 if (!r)
555 {
556 /*UNDENT...*/
557 #ifdef _3D_STAT_VER
558 switch (arg[1].number)
559 {
560 case _3D_STAT_VER:
561 #endif
562 {
563 struct stat* sp = (struct stat*)ap->pointer;
564 bprintf(&b, e, " [ dev=%d ino=%d view=%d mode=0%o nlink=%d uid=%d gid=%d size=%u atime=%u mtime=%u ctime=%u ]", sp->st_dev, sp->st_ino, iview(sp), sp->st_mode, sp->st_nlink, sp->st_uid, sp->st_gid, sp->st_size, sp->st_atime, sp->st_mtime, sp->st_ctime);
565 continue;
566 }
567 #ifdef _3D_STAT_VER
568 #ifdef _3D_STAT64_VER
569 case _3D_STAT64_VER:
570 {
571 struct stat64* sp = (struct stat64*)ap->pointer;
572 bprintf(&b, e, " [ dev=%d ino=%lld view=%d mode=0%o nlink=%d uid=%d gid=%d size=%llu atime=%u mtime=%u ctime=%u ]", sp->st_dev, sp->st_ino, iview(sp), sp->st_mode, sp->st_nlink, sp->st_uid, sp->st_gid, sp->st_size, sp->st_atime, sp->st_mtime, sp->st_ctime);
573 continue;
574 }
575 #endif
576 }
577 #endif
578 }
579 break;
580 #ifdef SYS3D_getdents
581 case SYS3D_getdents:
582 if (r > 0)
583 {
584 struct DIRdirent* dp = (struct DIRdirent*)ap->pointer;
585 struct DIRdirent* de = (struct DIRdirent*)((char*)dp + r);
586
587 bprintf(&b, e, " [");
588 while (dp < de)
589 {
590 #ifdef DIRdirent
591 bprintf(&b, e, " %lu \"%s\"", D_FILENO(dp), dp->d_name);
592 #else
593 bprintf(&b, e, " %02d %lu \"%s\"", D_TYPE(dp), D_FILENO(dp), dp->d_name);
594 #endif
595 dp = (struct DIRdirent*)((char*)dp + dp->d_reclen);
596 }
597 bprintf(&b, e, " ]");
598 continue;
599 }
600 break;
601 #endif
602 case SYS3D_pipe:
603 if (!r)
604 {
605 ip = (int*)ap->pointer;
606 bprintf(&b, e, " [ %d %d ]", ip[0], ip[1]);
607 continue;
608 }
609 break;
610 }
611 /*FALLTHROUGH*/
612 case A_INPUT:
613 if (n == A_OUTPUT && cp->type[n = 0] == A_SIZE || ac < (elementsof(cp->type) - 1) && cp->type[n = ac + 1] == A_SIZE)
614 {
615 buffer(&b, e, ap->string, n ? arg[n].number : r);
616 break;
617 }
618 goto pointer;
619 case A_MODE:
620 bprintf(&b, e, " 0%o", ap->number);
621 break;
622 case A_POINTER:
623 pointer:
624 bprintf(&b, e, " %p", ap->pointer);
625 break;
626 case A_STRING:
627 if (r == -1)
628 goto pointer;
629 buffer(&b, e, ap->string, strlen(ap->string));
630 break;
631 default:
632 bprintf(&b, e, " %d", ap->number);
633 break;
634 }
635 }
636 #if DEBUG_dirent
637 switch (call)
638 {
639 #ifdef SYS3D_readdir
640 #undef DIRdirent
641 case SYS3D_readdir:
642 if (r && (state.test & 0100))
643 {
644 struct DIRdirent* dp = (struct DIRdirent*)pointerof(r);
645
646 bprintf(&b, e, " ) = [ %02d %lu \"%s\" ]", D_TYPE(dp), D_FILENO(dp), dp->d_name);
647 break;
648 }
649 goto number;
650 #endif
651 #ifdef SYS3D_readdir64
652 case SYS3D_readdir64:
653 if (r && (state.test & 0100))
654 {
655 struct dirent64* dp = (struct dirent64*)pointerof(r);
656
657 bprintf(&b, e, " ) = [ %02d %llu \"%s\" ]", D_TYPE(dp), D_FILENO(dp), dp->d_name);
658 break;
659 }
660 goto number;
661 #endif
662 default:
663 number:
664 bprintf(&b, e, "%s) = %d", a ? " " : "\t", r);
665 break;
666 }
667 #else
668 bprintf(&b, e, "%s) = %d", a ? " " : "\t", r);
669 #endif
670 if (r == -1)
671 bprintf(&b, e, " [%s]", strerror(errno));
672 n = errno;
673 t = buf;
674 while ((b - t) >= m)
675 {
676 char* w;
677 char* x;
678 char* z;
679 int c1;
680 int c2;
681
682 x = w = t + m;
683 z = t + m / 2;
684 while (x > z && *x != ' ') x--;
685 if (x <= z)
686 x = w;
687 c1 = *x;
688 *x++ = '\n';
689 c2 = *x;
690 *x++ = '\t';
691 write(on, t, x - t);
692 *--x = c2;
693 if ((*--x = c1) == ' ')
694 x++;
695 t = x;
696 m = MAXLIN - 8;
697 }
698 *b++ = '\n';
699 write(on, t, b - t);
700 errno = n;
701 }
702 else if (r >= 0 && (MSG_MASK(cp->call) & C_IO) && (cp->units += r) >= (1<<20))
703 {
704 cp->megs += cp->units >> 20;
705 cp->units &= ((1<<20)-1);
706 }
707 state.kernel--;
708 }
709 return r;
710 }
711
712 #else
713
714 NoN(syscall)
715
716 #endif
717