xref: /illumos-gate/usr/src/tools/ctf/stabs/common/forth.c (revision 1f5207b7604fb44407eb4342aff613f7c4508508)
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 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * In this mode, we generate forthdebug macros as requested by the input
31  * template, the format of which is given below.
32  *
33  * These templates have the following elements:
34  *
35  * 1. Macro creation
36  *
37  *    Given the name of a structure, union, or enum type, a forthdebug macro
38  *    is created that will dump the members of the type.  The type can be
39  *    specified as a standalone structure, union, or enum, or it can be
40  *    described relative to another structure or union as "type.member".
41  *
42  *    By default, all struct members, union members, or enum values, as
43  *    appropriate, will be printed.  An alternate form allows specific members
44  *    of struct or union types to be printed.  Both forms must be followed by a
45  *    blank line.  In the specific-member case, an optional format specifier can
46  *    be provided that will be used to dump the contents of the member.
47  *    Builtins `d' and `x' can be used to dump the member in decimal or
48  *    hexadecimal, respectively.  Alternatively, a custom formatter can be
49  *    specified.
50  *
51  * 2. Model-specific sections
52  *
53  *    `model_start' / `model_end' pairs function as an #ifdef for the ctfstabs
54  *    tool.  They take, as an argument, either `ilp32' or `lp64'.  If a 64-bit
55  *    macro is being generated (if a 64-bit object file is being used), lines
56  *    between `lp64' model pairs will be processed, but lines between `ilp32'
57  *    pairs will be omitted.  The reverse is true for 32-bit macros.
58  *
59  * 3. Literal sections
60  *
61  *    Portions of the input template file enclosed within `forth_start' /
62  *    `forth_end' pairs and between `verbatim_begin' / `verbatim_end' pairs
63  *    will be copied as-is to the output file.
64  *
65  * 4. Comments
66  *
67  *    Lines beginning with backslashes are ignored.
68  *
69  * Example:
70  *
71  *    \ dump the `foo' structure
72  *    foo
73  *
74  *    \ dump the `a' and `b' members of the `bar' structure.  dump member `b'
75  *    \ in hexadecimal
76  *    bar
77  *	a
78  *	b	x
79  *
80  *    \ dump the `big' member of the `baz' structure in 64-bit macros, and
81  *    \ the `small' member in 32-bit macros.
82  *    baz
83  *    model_start lp64
84  *	big
85  *    model_end
86  *    model_start ilp32
87  *	small
88  *    model_end
89  *
90  *    \ copy `literal 1' and `literal 2' to the output file
91  *    verbatim_begin
92  *    literal 1
93  *    verbatim_end
94  *    forth_start
95  *    literal 2
96  *    forth_end
97  *
98  * For a more complex example, see common.fdbg.
99  */
100 
101 #include <stdio.h>
102 #include <stdlib.h>
103 #include <string.h>
104 #include <ctype.h>
105 
106 #include "ctf_headers.h"
107 #include "ctfstabs.h"
108 #include "forth.h"
109 #include "utils.h"
110 #include "memory.h"
111 
112 char *fth_curtype;			/* name of the type being processed */
113 static fth_type_ops_t *fth_type_ops;	/* see forth.h */
114 
115 static char *fth_model;		/* the current macro type - for model_start */
116 static int fth_ignoring;	/* in a non-matching model_start/end pair */
117 static int fth_copying;		/* in a verbatim_* or forth_* pair */
118 
119 static int
120 fth_init(char *model)
121 {
122 	fth_model = model;
123 
124 	return (0);
125 }
126 
127 /*ARGSUSED*/
128 static int
129 fth_null_header(ctf_id_t tid)
130 {
131 	return (0);
132 }
133 
134 /*ARGSUSED*/
135 static int
136 fth_null_members(char *memfilter, char *format)
137 {
138 	return (0);
139 }
140 
141 static int
142 fth_null_trailer(void)
143 {
144 	return (0);
145 }
146 
147 static fth_type_ops_t fth_null_ops = {
148 	fth_null_header,
149 	fth_null_members,
150 	fth_null_trailer
151 };
152 
153 /*ARGSUSED2*/
154 static int
155 find_member_cb(const char *memname, ctf_id_t tid, ulong_t off, void *arg)
156 {
157 	char *memtofind = arg;
158 
159 	if (strcmp(memname, memtofind) == 0)
160 		return (tid);
161 
162 	return (0);
163 }
164 
165 /* find the tid of a specified member */
166 static ctf_id_t
167 find_member(ctf_id_t tid, char *memname)
168 {
169 	return (ctf_member_iter(ctf, tid, find_member_cb, memname));
170 }
171 
172 /*
173  * Begin a macro.
174  *
175  * Once we figure out the type of the thing that we're supposed to dump (struct,
176  * union, or enum), we select the proper type-specific ops-vector for dumping.
177  */
178 static int
179 fth_section_init(char *fullname)
180 {
181 	ctf_id_t ltid = 0, tid;
182 	char *curtype, *lpart, *part, *npart;
183 	int lkind = 0, kind;
184 
185 	curtype = xstrdup(fullname);
186 	lpart = NULL;
187 	part = strtok(fullname, ".");
188 
189 	/*
190 	 * First figure out what sort of type we're looking at.  Life would be
191 	 * simple if we were only going to get type names, but it's not - we
192 	 * could also get `type.member'.  In that case, we need to figure out
193 	 * (and dump) the type of `member' instead.
194 	 */
195 	for (;;) {
196 		if (lpart == NULL) {
197 			/* First part - the struct name */
198 			if ((tid = find_type(part)) == CTF_ERR ||
199 			    (tid = ctf_type_resolve(ctf, tid)) == CTF_ERR ||
200 			    (kind = ctf_type_kind(ctf, tid)) == CTF_ERR) {
201 				free(curtype);
202 				return (parse_warn("Couldn't find %s: %s",
203 				    part, ctf_errmsg(ctf_errno(ctf))));
204 			}
205 		} else {
206 			/* Second (or more) part - the member name */
207 			if (lkind != CTF_K_STRUCT && lkind != CTF_K_UNION) {
208 				free(curtype);
209 				return (parse_warn("%s isn't a struct/union",
210 				    lpart));
211 			}
212 
213 			if ((tid = find_member(ltid, part)) <= 0) {
214 				free(curtype);
215 				return (parse_warn("%s isn't a member of %s",
216 				    part, lpart));
217 			}
218 
219 			if ((kind = ctf_type_kind(ctf, tid)) == CTF_ERR) {
220 				free(curtype);
221 				return (parse_warn("Can't get kind for %s",
222 				    part));
223 			}
224 		}
225 
226 		/*
227 		 * Stop if there aren't any more parts.  We use `npart' here
228 		 * because we don't want to clobber part - we need it later.
229 		 */
230 		if ((npart = strtok(NULL, ".")) == NULL)
231 			break;
232 
233 		lpart = part;
234 		ltid = tid;
235 		lkind = kind;
236 
237 		part = npart;
238 	}
239 
240 	/*
241 	 * Pick the right ops vector for dumping.
242 	 */
243 	switch (kind) {
244 	case CTF_K_STRUCT:
245 	case CTF_K_UNION:
246 		fth_type_ops = &fth_struct_ops;
247 		break;
248 
249 	case CTF_K_ENUM:
250 		fth_type_ops = &fth_enum_ops;
251 		break;
252 
253 	default:
254 		fth_type_ops = &fth_null_ops;
255 		free(curtype);
256 		return (parse_warn("%s isn't a struct, union, or enum", part));
257 	}
258 
259 	fth_curtype = curtype;
260 
261 	return (fth_type_ops->fto_header(tid));
262 }
263 
264 static int
265 fth_section_add_member(char *name, char *format)
266 {
267 	if (fth_curtype == NULL)
268 		return (fth_section_init(name));
269 
270 	if (fth_type_ops->fto_members(name, format) < 0)
271 		return (-1);
272 
273 	return (0);
274 }
275 
276 static int
277 fth_section_end(void)
278 {
279 	if (fth_curtype == NULL)
280 		return (0);
281 
282 	if (fth_type_ops->fto_trailer() < 0)
283 		return (-1);
284 
285 	free(fth_curtype);
286 	fth_curtype = NULL;
287 
288 	return (0);
289 }
290 
291 static int
292 fth_process_line(char *line)
293 {
294 	char *format = NULL;
295 	char *word, *name, *c;
296 	int nblank = 0;
297 	int n;
298 
299 	if (strlen(line) == 0) {
300 		if (fth_section_end() < 0)
301 			return (-1);
302 
303 		if (fth_copying == 1 || nblank++ == 1)
304 			(void) fprintf(out, "\n");
305 		return (0);
306 	} else
307 		nblank = 0;
308 
309 	/* skip comments */
310 	if (line[0] == '\\')
311 		return (0);
312 
313 	if (strcmp(line, "model_end") == 0) {
314 		fth_ignoring = 0;
315 		return (0);
316 	}
317 
318 	if (fth_ignoring == 1)
319 		return (0);
320 
321 	word = "model_start ";
322 	if (strncmp(line, word, strlen(word)) == 0) {
323 		for (c = line + strlen(word); isspace(*c); c++);
324 		if (strlen(c) == strlen(fth_model) &&
325 		    strncmp(c, fth_model, strlen(fth_model)) == 0)
326 			/* EMPTY - match */;
327 		else
328 			fth_ignoring = 1;
329 		return (0);
330 	}
331 
332 	if (strcmp(line, "verbatim_end") == 0 ||
333 	    strcmp(line, "forth_end") == 0) {
334 		char *start = (strcmp(line, "verbatim_end") == 0 ?
335 		    "verbatim_begin" : "forth_start");
336 
337 		if (fth_copying == 0) {
338 			(void) parse_warn("Found %s without matching %s",
339 			    line, start);
340 			if (fth_curtype != NULL)
341 				(void) fth_section_end();
342 			return (-1);
343 		}
344 		fth_copying = 0;
345 		return (0);
346 	}
347 
348 	if (fth_copying == 1) {
349 		(void) fprintf(out, "%s\n", line);
350 		return (0);
351 	}
352 
353 	if (strcmp(line, "verbatim_begin") == 0 ||
354 	    strcmp(line, "forth_start") == 0) {
355 		if (fth_curtype != NULL) {
356 			(void) parse_warn("Expected blank line between %s "
357 			    "macro and %s", fth_curtype, line);
358 			return (fth_section_end());
359 		}
360 
361 		fth_copying = 1;
362 		return (0);
363 	}
364 
365 	for (n = 1, word = strtok(line, " \t"); word != NULL;
366 	    word = strtok(NULL, " \t"), n++) {
367 		if (n == 1)
368 			name = word;
369 		else if (n == 2)
370 			format = word;
371 		else
372 			(void) parse_warn("Too many words");
373 	}
374 
375 	return (fth_section_add_member(name, format));
376 }
377 
378 static int
379 fth_fini(void)
380 {
381 	return (fth_section_end());
382 }
383 
384 proc_ops_t fth_ops = {
385 	fth_init,
386 	fth_process_line,
387 	fth_fini
388 };
389