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