1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1997-1999 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <limits.h>
31 #include "parser.h"
32 #include "trace.h"
33 #include "util.h"
34 #include "db.h"
35 #include "symtab.h"
36 #include "io.h"
37 #include "printfuncs.h"
38 #include "errlog.h"
39 
40 static int	 prepare_printf_part(ENTRY *, char *, char *, int);
41 static char	 *space_to_uscore(char const *);
42 
43 static char	arglist[_POSIX_ARG_MAX];
44 
45 /*
46  * generate_printf -- make the cleanest possible printf for the
47  *	parameters, in a relatively terse apptrace/dbx-like format,
48  *	ending in ") = ", or ) if its a void function we're doing.
49  */
50 void
generate_printf(ENTRY * f)51 generate_printf(ENTRY *f)
52 {
53 	ENTRY	*e;
54 	char	*p, *name;
55 	int	l, n;
56 
57 	errlog(BEGIN, "generate_printf");
58 	(void) fprintf(Bodyfp, "    fprintf(ABISTREAM, \"");
59 	p = &arglist[0];
60 	l = (int)sizeof (arglist);
61 	*p = '\0';
62 	for (e = symtab_get_first_arg(); e != NULL; e = symtab_get_next_arg()) {
63 		errlog(TRACING, "arglist = '%s'", arglist);
64 
65 		if (is_void(e)) {
66 			/* This placeholder means there are no real args. */
67 			break;
68 		}
69 		/* Insert punctuation. */
70 		if (p != &arglist[0]) {
71 			(void) fprintf(Bodyfp, ", ");
72 		}
73 		if (*(name =  name_of(e)) == '\0') {
74 			/* It's a varargs indicator instead */
75 			(void) fprintf(Bodyfp, "...");
76 		} else {
77 			(void) fprintf(Bodyfp, "%s = ", name);
78 			n = prepare_printf_part(e, name, p, l);
79 			l -= n;
80 			p += n;
81 			*(p+1) = '\0';
82 		}
83 	}
84 
85 	if (is_void(f) || symtab_get_nonreturn() == YES) {
86 		/* It is a function returning void, or a function */
87 		/* which doesn't return. Close off args. */
88 		(void) fprintf(Bodyfp, ")\"");
89 	} else {
90 		/* Make some more printf for the return type. */
91 		(void) fprintf(Bodyfp, ") = ");
92 		(void) prepare_printf_part(f, "_return", p, l);
93 		(void) fprintf(Bodyfp, "\"");
94 
95 	}
96 	(void) fprintf(Bodyfp, "%s);\n", arglist);
97 	errlog(END, "}");
98 }
99 
100 
101 /*
102  * prepare_printf_part -- do one element of a printf/argument string,
103  *	for printing non-verbose parameter lists
104  */
105 static int
prepare_printf_part(ENTRY * e,char * name,char * place,int size)106 prepare_printf_part(ENTRY *e, char *name, char *place, int size)
107 {
108 	char	*bt;
109 	int	li;
110 
111 	errlog(BEGIN, "prepare_printf_part() {");
112 	errlog(TRACING, "name = '%s'", name);
113 
114 	bt = basetype_of(e);
115 	li = levels_of(e);
116 
117 	if (li == 1 && (strcmp(bt, "char") == 0)) {
118 		/* It's a string, print the beginning of it. */
119 		(void) fputs("\\\"%.*s\\\"", Bodyfp);
120 		size = snprintf(place, size,
121 		    /*CSTYLED*/
122 		    ",\n\tabi_strpsz, (%s) ? %s : nilstr",
123 		    name, name);
124 	} else {
125 		/* Just print a hex value */
126 		(void) fprintf(Bodyfp, "%s", "0x%p");
127 		size = snprintf(place, size, ", \n\t%s", name);
128 	}
129 
130 	errlog(TRACING, "place='%s'\n", place);
131 	errlog(END, "}");
132 	return (size);
133 
134 }
135 
136 
137 /*
138  * generate_printfunc_calls -- generate print commands for primitive types
139  *	and calls to print functions for composite types, cleanly.
140  *	Needs to know about base types of primitives, difference
141  *	between primitives and composite types: TBD.
142  */
143 void
generate_printfunc_calls(ENTRY * f)144 generate_printfunc_calls(ENTRY *f)
145 {
146 	ENTRY	*e;
147 	char	*name;
148 	char	*pf_str_name;
149 	int	li;
150 	char	*format;
151 
152 	errlog(BEGIN, "generate_printfunc_calls() {");
153 	for (e = symtab_get_first_arg(); e != NULL; e = symtab_get_next_arg()) {
154 		if (is_void(e)) {
155 			break;
156 		}
157 		if (*(name = name_of(e)) == '\0') {
158 			(void) fprintf(Bodyfp, "        fputs(\"  ...\\n\", "
159 				"ABISTREAM);\n");
160 		}
161 		errlog(TRACING, "name = '%s'\n", name);
162 		(void) fprintf(Bodyfp,
163 		    "        fprintf(ABISTREAM, \"  %s = \");\n",
164 		    name);
165 
166 		pf_str_name = space_to_uscore(basetype_of(e));
167 
168 		/*
169 		 * If we're dealing with a scalar (non-pointer) then
170 		 * we need to call the printer with a &
171 		 */
172 		li = levels_of(e);
173 		if (li)
174 			format = "\tspf_prtype(ABISTREAM, pf_%s_str, %d, "
175 			    "(void const *)%s);\n";
176 		else
177 			format = "\tspf_prtype(ABISTREAM, pf_%s_str, %d, "
178 			    "(void const *)&%s);\n";
179 
180 		(void) fprintf(Bodyfp, format, pf_str_name, li, name);
181 
182 		free(pf_str_name);
183 	}
184 
185 	if (is_void(f)) {
186 		/*EMPTY*/;
187 	} else {
188 		pf_str_name = space_to_uscore(basetype_of(f));
189 
190 		li = levels_of(f);
191 		if (li)
192 			format = "\tspf_prtype(ABISTREAM, pf_%s_str, %d, "
193 			    "(void const *)_return);\n";
194 		else
195 			format = "\tspf_prtype(ABISTREAM, pf_%s_str, %d, "
196 			    "(void const *)&_return);\n";
197 
198 		(void) fputs("        fputs(retstr, ABISTREAM);\n", Bodyfp);
199 		(void) fprintf(Bodyfp, format, pf_str_name, li);
200 
201 		free(pf_str_name);
202 	}
203 
204 	errlog(END, "}");
205 }
206 
207 
208 /*
209  * Print Function Pointers -- definition, declaration and initialization.
210  *	Use is above...
211  */
212 
213 /*
214  * generate_print_definitions -- generate variable definitions and
215  *	initialize them to NULL.
216  *      These will be set non-null by a lazy evaluation in the
217  *	main.c file if and only if the print function will be used.
218  *	All print functions which can be called must be defined.
219  */
220 void
generate_print_definitions(FILE * fp)221 generate_print_definitions(FILE *fp)
222 {
223 	char	*print_type,
224 		*c_type,
225 		*pf_str_name;
226 
227 	errlog(BEGIN, "generate_print_definitions() {");
228 	for (print_type = db_get_first_print_type();
229 		print_type != NULL;
230 			print_type = db_get_next_print_type()) {
231 		c_type = strchr(print_type, ','); /* Safe by construction. */
232 		*c_type++ = '\0';
233 		errlog(TRACING,  "print_type=%s\n", print_type);
234 
235 		pf_str_name = space_to_uscore(print_type);
236 
237 		(void) fprintf(fp,
238 		    "char const *pf_%s_str = \"%s\";\n",
239 		    pf_str_name, print_type);
240 
241 		free(pf_str_name);
242 
243 		*--c_type = ',';
244 	}
245 
246 	errlog(END, "}");
247 }
248 
249 /*
250  * generate_print_declarations -- generate variable declarations
251  *	for the strings that'll be used as arguments to the type
252  *	printing function.
253  */
254 void
generate_print_declarations(FILE * fp)255 generate_print_declarations(FILE *fp)
256 {
257 	char	*print_type,
258 		*c_type,
259 		*pf_str_name;
260 
261 	errlog(BEGIN, "generate_print_declarations() {");
262 	for (print_type = symtab_get_first_print_type();
263 	    print_type != NULL;
264 	    print_type = symtab_get_next_print_type()) {
265 
266 		errlog(TRACING,  "print_type, c_type=%s\n", print_type);
267 
268 		c_type = strchr(print_type, ','); /* Safe by construction. */
269 		*c_type++ = '\0';
270 
271 		pf_str_name = space_to_uscore(print_type);
272 
273 		(void) fprintf(fp, "extern char const *pf_%s_str;\n",
274 		    pf_str_name);
275 
276 		free(pf_str_name);
277 
278 		*--c_type = ',';
279 	}
280 
281 	errlog(END, "}");
282 }
283 
284 /*
285  * is_void -- see if a type is void.
286  */
287 int
is_void(ENTRY * e)288 is_void(ENTRY *e)
289 {
290 	if ((e != NULL) &&
291 	    levels_of(e) == 0 && (strcmp(basetype_of(e), "void") == 0))
292 		return (1);
293 	else
294 		return (0);
295 }
296 
297 static char *
space_to_uscore(char const * str)298 space_to_uscore(char const *str)
299 {
300 	char *strp, *p;
301 
302 	strp = strdup(str);
303 
304 	assert(strp != NULL, "strdup failed");
305 
306 	for (p = strp; *p != '\0'; p++)
307 		if (*p == ' ')
308 			*p = '_';
309 
310 	return (strp);
311 }
312