1 /* @(#)avoffset.c	1.39 21/04/28 Copyright 1987, 1995-2021 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)avoffset.c	1.39 21/04/28 Copyright 1987, 1995-2021 J. Schilling";
6 #endif
7 /*
8  * This program is a tool to generate the file "avoffset.h".
9  * It is used by functions that trace the stack to get to the top of the stack.
10  *
11  * It generates two defines:
12  *	AV_OFFSET	- offset of argv relative to the main() frame pointer
13  *	FP_INDIR	- number of stack frames above main()
14  *			  before encountering a NULL pointer.
15  *
16  *	Copyright (c) 1987, 1995-2021 J. Schilling
17  */
18 /*
19  * The contents of this file are subject to the terms of the
20  * Common Development and Distribution License, Version 1.0 only
21  * (the "License").  You may not use this file except in compliance
22  * with the License.
23  *
24  * See the file CDDL.Schily.txt in this distribution for details.
25  * A copy of the CDDL is also available via the Internet at
26  * http://www.opensource.org/licenses/cddl1.txt
27  *
28  * When distributing Covered Code, include this CDDL HEADER in each
29  * file and include the License file CDDL.Schily.txt from this distribution.
30  */
31 
32 #include <schily/stdio.h>
33 #include <schily/standard.h>
34 #include <schily/schily.h>
35 #include <schily/stdlib.h>
36 #include <schily/signal.h>
37 
38 #ifdef	HAVE_SCANSTACK
39 #	include <schily/stkframe.h>
40 #endif
41 
42 LOCAL	RETSIGTYPE	handler 	__PR((int signo));
43 EXPORT	int		main		__PR((int ac, char **av));
44 LOCAL	int		stack_direction	__PR((long *lp));
45 
46 LOCAL	RETSIGTYPE
handler(signo)47 handler(signo)
48 	int	signo;
49 {
50 	fprintf(stderr, "Warning: Cannot scan stack on this environment.\n");
51 	fprintf(stderr, "This is not an error, we just disable stack scannig.\n");
52 
53 	printf("\n#endif	/* __AVOFFSET_H */\n");
54 	fflush(stdout);
55 	exit(0);
56 }
57 
58 
59 int
main(ac,av)60 main(ac, av)
61 	int	ac;
62 	char	**av;
63 {
64 	int		stdir;
65 #ifdef	HAVE_SCANSTACK
66 	volatile struct frame *fp;
67 	register int	i = 0;
68 	register int	o = 0;
69 
70 	/*
71 	 * As the SCO OpenServer C-Compiler has a bug that may cause
72 	 * the first function call to getfp() been done before the
73 	 * new stack frame is created, we call getfp() twice.
74 	 */
75 	(void) getfp();
76 	fp = (struct frame *)getfp();
77 #endif
78 
79 #ifdef	SIGBUS
80 	signal(SIGBUS, handler);
81 #endif
82 	signal(SIGSEGV, handler);
83 #ifdef	SIGILL
84 	signal(SIGILL, handler);	/* For gcc -m64/sparc on FreeBSD */
85 #endif
86 
87 	printf("/*\n");
88 	printf(" * This file has been generated automatically\n");
89 	printf(" * by %s\n", sccsid);
90 	printf(" * do not edit by hand.\n");
91 	printf(" *\n");
92 	printf(" * This file includes definitions for AV_OFFSET and FP_INDIR.\n");
93 	printf(" * FP_INDIR is the number of fp chain elements above 'main'.\n");
94 	printf(" * AV_OFFSET is the offset of &av[0] relative to the frame pointer in 'main'.\n");
95 	printf(" *\n");
96 	printf(" * If getav0() does not work on a specific architecture\n");
97 	printf(" * the program which generated this include file may dump core.\n");
98 	printf(" * In this case, the generated include file does not include\n");
99 	printf(" * definitions for AV_OFFSET and FP_INDIR but ends after this comment.\n");
100 	printf(" * If AV_OFFSET or FP_INDIR are missing in this file, all programs\n");
101 	printf(" * which use the definitions are automatically disabled.\n");
102 	printf(" */\n");
103 	printf("#ifndef	__AVOFFSET_H\n");
104 	printf("#define	__AVOFFSET_H\n\n");
105 
106 	stdir = stack_direction(0);
107 	printf("#define	STACK_DIRECTION	%d\n", stdir);
108 	fflush(stdout);
109 
110 #ifdef	HAVE_SCANSTACK
111 	/*
112 	 * Note: Scanning the stack to look for argc/argv
113 	 *	 works only in the main thread.
114 	 *
115 	 * llvm-gcc-4.2 has a bug and creates an endless loop if we call:
116 	 *	while (fp->fr_savfp) {
117 	 * We now try to limit this to 1000 loops in hope that the bug
118 	 * does not affect the new code extended as well.
119 	 */
120 	while (i <= 1000 && fp->fr_savfp) {
121 		/*
122 		 * Workaround for the still buggy clang...
123 		 * clang version 4.0.0 on ARM64 FreeBSD has become worse.
124 		 * If we do not have the strange write() call, this loop
125 		 * becomes an endless loop and the last line in the loop
126 		 * is never touched.
127 		 */
128 		write(-1, "", 0);
129 		if (fp->fr_savpc == 0)
130 			break;
131 
132 		fp = (struct frame *)fp->fr_savfp;
133 
134 		i++;
135 	}
136 	/*
137 	 * Do not add any printf()'s before this line to allow avoffset
138 	 * to abort without printing more than the comment above.
139 	 */
140 	fp = (struct frame *)getfp();
141 	o = ((char *)av) - ((char *)fp);
142 	if ((o % sizeof (char *)) != 0) {
143 		fprintf(stderr, "AV_OFFSET value (%d) not a multiple of pointer size.\n", o);
144 		fprintf(stderr, "Disabling scanning the stack.\n");
145 
146 		printf("\n#endif	/* __AVOFFSET_H */\n");
147 		exit(0);
148 	}
149 	if (o < -1000 || o > 1000) {
150 		fprintf(stderr, "AV_OFFSET value (%d) does not look reasonable.\n", o);
151 		fprintf(stderr, "Disabling scanning the stack.\n");
152 
153 		printf("\n#endif	/* __AVOFFSET_H */\n");
154 		exit(0);
155 	}
156 	if (i > 1000) {
157 		fprintf(stderr, "FP_INDIR value (%d) does not look reasonable.\n", i);
158 		fprintf(stderr, "Disabling scanning the stack.\n");
159 
160 		printf("\n#endif	/* __AVOFFSET_H */\n");
161 		exit(0);
162 	}
163 	printf("#define	AV_OFFSET	%d\n", o);
164 	printf("#define	FP_INDIR	%d\n", i);
165 #endif
166 	printf("\n#endif	/* __AVOFFSET_H */\n");
167 	fflush(stdout);
168 	exit(0);
169 	return (0);	/* keep lint happy */
170 }
171 
172 #ifndef	__NO_INL__
173 #if	__clang__ || (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 2)
174 #define	__NO_INL__	__attribute__((noinline))
175 #else
176 #define	__NO_INL__
177 #endif
178 #endif
179 
180 LOCAL __NO_INL__ int
stack_direction(lp)181 stack_direction(lp)
182 	long	*lp;
183 {
184 	auto long	*dummy[4];
185 	int		i;
186 
187 	for (i = 0; i < 4; i++)
188 		dummy[i] = lp;
189 
190 	if (lp == 0) {
191 		return (stack_direction((long *)dummy));
192 	} else {
193 		if ((long *)dummy == lp)
194 			return (0);
195 		return (((long *)dummy > lp) ? 1 : -1);
196 	}
197 }
198 
199 #ifdef	HAVE_SCANSTACK
200 #define	IS_AVOFFSET
201 #include "getfp.c"
202 #endif
203