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
fth_init(char * model)120 fth_init(char *model)
121 {
122 fth_model = model;
123
124 return (0);
125 }
126
127 /*ARGSUSED*/
128 static int
fth_null_header(ctf_id_t tid)129 fth_null_header(ctf_id_t tid)
130 {
131 return (0);
132 }
133
134 /*ARGSUSED*/
135 static int
fth_null_members(char * memfilter,char * format)136 fth_null_members(char *memfilter, char *format)
137 {
138 return (0);
139 }
140
141 static int
fth_null_trailer(void)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
find_member_cb(const char * memname,ctf_id_t tid,ulong_t off,void * arg)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
find_member(ctf_id_t tid,char * memname)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
fth_section_init(char * fullname)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
fth_section_add_member(char * name,char * format)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
fth_section_end(void)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
fth_process_line(char * line)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
fth_fini(void)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