xref: /illumos-gate/usr/src/tools/ctf/stabs/common/fth_struct.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 2003 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  * Used to dump structures and unions in forth mode.
31  *
32  * structures and unions are a bit more complicated than enums.  To make things
33  * just that much more interesting, we have to dump the members in reverse
34  * order, which is nice.  But wait!  It gets better!  For compatibility reasons,
35  * we need to dump the members in reverse-offset order, even if member-specific
36  * mode was used to request the members in something other than that order.
37  *
38  * The header op prints the macro header and saves the type being printed.
39  *
40  * In member-specific mode, the member op will be invoked for each structure
41  * or union member.  The member op adds the member name, format, type ID,
42  * and offset to a list, sorted in reverse order by offset.
43  *
44  * The trailer op is called when the structure or enum is complete.  If no
45  * members were specifically requested, then the trailer iterates through all
46  * of the members of the structure, pretending they were.  Each member is thus
47  * added, in reverse-offset order, to the list used in specific-member mode.
48  * Either way, we then proceed through the list, dumping each member out with
49  * fth_print_member.  Structure and union members are printed out differently,
50  * depending on member type, as follows:
51  *
52  *  Integer:
53  *	Normal integers: ' <format> <offset> <type>-field <name>
54  *	  <format> defaults to ".d" for enums, ".x" for others
55  *	  <offset> is the member offset, in bytes.
56  *	  <type> is "byte", "short", "long", or "ext" for 8-, 16-, 32-, and
57  *	    64-bit integers, respectively.
58  *	  <name> is the name of the member being printed
59  *
60  *	Bitfields:	 ' <format> <shift> <mask> <offset> bits-field <name>
61  *	  <format> defaults to ".x"
62  *	  <shift> is the number of times to right-shift the masked value
63  *	  <mask> use to extract the bit-field value from the read value
64  *	  <offset> is the member offset, in bytes
65  *	  <name> is the name of the member being printed
66  *
67  *  Float:		Ignored
68  *
69  *  Pointer:		 ' <format> <offset> ptr-field <name>
70  *	  <format> defaults to .x
71  *	  <offset> is in bytes
72  *	  <name> is the name of the member being printed
73  *
74  *  Array:
75  *	Arrays have a content-type-specific prefix, followed by an array
76  *	suffix.  The resulting line looks like this if the array contents
77  *	type is an integer, a pointer, or an enum:
78  *
79  *			 ' <fldc> ' <fmt> <sz> <elsz> <off> array-field <name>
80  *
81  *	The following is printed for array contents that are arrays:
82  *
83  *			 ' noop ' .x <sz> <elsz> <off> array-field <name>
84  *
85  *	The following is printed for array contents that are structs:
86  *
87  *			 ' noop ' <fmt> <sz> <elsz> <off> array-field <name>
88  *
89  *	  <fldc> is "c@", "w@", "l@", or "x@", depending on whether array
90  *	    elements are 8, 16, 32 or 64 bits wide.
91  *	  <fmt> defaults to ".x"
92  *	  <sz> is the size of the array, in bytes
93  *	  <elsz> is the size of the array elements
94  *	  <off> is the member offset, in bytes
95  *	  <name> is the nam eof the member being printed
96  *
97  *  Struct/Union:	 ' <format> <offset> struct-field <name>
98  *	  <format> defaults to ".x"
99  *	  <offset> is the member offset, in bytes
100  *	  <name> is the name of the member being printed
101  */
102 
103 #include <stdio.h>
104 #include <stdlib.h>
105 #include <string.h>
106 
107 #include "ctf_headers.h"
108 #include "forth.h"
109 #include "list.h"
110 #include "memory.h"
111 
112 static ctf_id_t	fth_str_curtid;
113 static list_t	*fth_str_curmems;
114 
115 /*
116  * Node type for the member-storage list (fth_str_curmems) built by
117  * fth_struct_members()
118  */
119 typedef struct fth_str_mem {
120 	char		*fsm_memname;
121 	char		*fsm_format;
122 	ctf_id_t	fsm_tid;
123 	ulong_t		fsm_off;
124 } fth_str_mem_t;
125 
126 typedef struct fth_struct_members_data {
127 	char		*fsmd_strname;
128 	char		*fsmd_memfilter;
129 	char		*fsmd_format;
130 	int		fsmd_matched;
131 } fth_struct_members_data_t;
132 
133 static int fth_print_member(fth_str_mem_t *, int);
134 
135 /* Comparison routined used to insert members into the fth_str_curmems list */
136 static int
137 fth_struct_memcmp(void *m1, void *m2)
138 {
139 	fth_str_mem_t *mem1 = m1, *mem2 = m2;
140 
141 	if (mem1->fsm_off < mem2->fsm_off)
142 		return (1);
143 	else if (mem1->fsm_off > mem2->fsm_off)
144 		return (-1);
145 	else
146 		return (0);
147 }
148 
149 static void
150 fth_free_str_mem(fth_str_mem_t *mem)
151 {
152 	free(mem->fsm_memname);
153 	if (mem->fsm_format)
154 		free(mem->fsm_format);
155 	free(mem);
156 }
157 
158 static int
159 fth_struct_header(ctf_id_t tid)
160 {
161 	ssize_t sz;
162 
163 	fth_str_curtid = tid;
164 	fth_str_curmems = NULL;
165 
166 	if ((sz = ctf_type_size(ctf, fth_str_curtid)) == CTF_ERR)
167 		return (parse_warn("Can't get size for %s", fth_curtype));
168 
169 	(void) fprintf(out, "\n");
170 	(void) fprintf(out, "vocabulary %s-words\n", fth_curtype);
171 	(void) fprintf(out, "h# %x constant %s-sz\n", sz, fth_curtype);
172 	(void) fprintf(out, "%x ' %s-words c-struct .%s\n", sz, fth_curtype,
173 	    fth_curtype);
174 	(void) fprintf(out, "also %s-words definitions\n\n", fth_curtype);
175 
176 	return (0);
177 }
178 
179 /* Print the array prefix for integer and pointer members */
180 static int
181 fth_print_level(uint_t bits, char *format)
182 {
183 	if ((bits & (bits - 1)) != 0 ||(bits % 8) != 0 || bits > 64) {
184 		return (parse_warn("Unexpected bit size %d in %s",
185 		    bits, fth_curtype));
186 	}
187 
188 	(void) fprintf(out, "' %c@ ' %s", " cw l   x"[bits / 8], format);
189 
190 	return (0);
191 }
192 
193 /*
194  * Return the format to be used to print the member.  If one of the builtin
195  * formats "d" or "x" were specified, return ".d" or ".x", respectively.
196  * Otherwise, use the user-provided format as is, or use the default if none
197  * was provided.
198  */
199 static char *
200 fth_convert_format(char *format, char *def)
201 {
202 	static char dot[3] = ".";
203 
204 	if (format == NULL)
205 		return (def);
206 	else if (strlen(format) == 1) {
207 		dot[1] = *format;
208 		return (dot);
209 	} else
210 		return (format);
211 }
212 
213 static int
214 fth_print_integer(const char *memname, ulong_t off, uint_t bits, char *format,
215     int level)
216 {
217 	format = fth_convert_format(format, ".x");
218 
219 	if (bits > 64) {
220 		return (parse_warn("%s.%s is too large (>8 bytes)",
221 		    fth_curtype, memname));
222 	}
223 
224 	if (level != 0)
225 		return (fth_print_level(bits, format));
226 
227 	if ((bits % NBBY) != 0 || (bits & (bits - 1)) != 0) {
228 		/* bit field */
229 		uint_t offset, shift, mask;
230 
231 		offset = (off / 32) * 4;
232 		shift = 32 - ((off % 32) + bits);
233 		mask = ((1 << bits) - 1) << shift;
234 
235 		(void) fprintf(out, "' %s %x %x %x bits-field %s\n",
236 		    format, shift, mask, offset, memname);
237 
238 	} else {
239 		char *type[] = {
240 			NULL, "byte", "short", NULL, "long",
241 			NULL, NULL, NULL, "ext"
242 		};
243 
244 		(void) fprintf(out, "' %s %lx %s-field %s\n", format, off / 8,
245 		    type[bits / 8], memname);
246 	}
247 
248 	return (0);
249 }
250 
251 static int
252 fth_print_pointer(const char *memname, ulong_t off, uint_t bits, char *format,
253     int level)
254 {
255 	format = fth_convert_format(format, ".x");
256 
257 	if (level != 0)
258 		return (fth_print_level(bits, format));
259 
260 	(void) fprintf(out, "' %s %lx ptr-field %s\n", format, off / 8,
261 	    memname);
262 
263 	return (0);
264 }
265 
266 static int
267 fth_print_struct(char *memname, ulong_t off, char *format,
268     int level)
269 {
270 	format = fth_convert_format(format, ".x");
271 
272 	if (level != 0)
273 		(void) fprintf(out, "' noop ' %s", format);
274 	else {
275 		(void) fprintf(out, "' %s %lx struct-field %s\n", format,
276 		    off / 8, memname);
277 	}
278 
279 	return (0);
280 }
281 
282 static int
283 fth_print_enum(char *memname, ulong_t off, char *format,
284     int level)
285 {
286 	format = fth_convert_format(format, ".d");
287 
288 	if (level != 0)
289 		(void) fprintf(out, "' l@ ' %s", format);
290 	else {
291 		(void) fprintf(out, "' %s %lx long-field %s\n", format, off / 8,
292 		    memname);
293 	}
294 
295 	return (0);
296 }
297 
298 static int
299 fth_print_array(char *memname, ctf_id_t tid, ulong_t off, ssize_t sz,
300     char *format, int level)
301 {
302 	if (level != 0)
303 		(void) fprintf(out, "' noop ' .x");
304 	else {
305 		fth_str_mem_t mem;
306 		ctf_arinfo_t ar;
307 
308 		/*
309 		 * print the prefix for the array contents type, then print
310 		 * the array macro
311 		 */
312 
313 		if (ctf_array_info(ctf, tid, &ar) == CTF_ERR) {
314 			return (parse_warn("Can't read array in %s.%s",
315 			    fth_curtype, memname));
316 		}
317 
318 		mem.fsm_memname = memname;
319 		mem.fsm_format = format;
320 		mem.fsm_tid = ar.ctr_contents;
321 		mem.fsm_off = off;
322 
323 		if (fth_print_member(&mem, level + 1) < 0)
324 			return (-1);
325 
326 		(void) fprintf(out, " %x %x %lx array-field %s\n", sz,
327 		    (sz / ar.ctr_nelems), off / 8, memname);
328 	}
329 
330 	return (0);
331 }
332 
333 /* dump a structure or union member */
334 static int
335 fth_print_member(fth_str_mem_t *mem, int level)
336 {
337 	ctf_encoding_t e;
338 	ctf_id_t tid;
339 	int kind;
340 	ssize_t sz;
341 
342 	if ((tid = ctf_type_resolve(ctf, mem->fsm_tid)) == CTF_ERR) {
343 		return (parse_warn("Can't resolve %s.%s", fth_curtype,
344 		    mem->fsm_memname));
345 	}
346 
347 	if ((kind = ctf_type_kind(ctf, tid)) == CTF_ERR) {
348 		return (parse_warn("Can't get kind for %s.%s",
349 		    fth_curtype, mem->fsm_memname));
350 	}
351 
352 	if ((sz = ctf_type_size(ctf, tid)) == CTF_ERR) {
353 		return (parse_warn("Can't get size for %s.%s",
354 		    fth_curtype, mem->fsm_memname));
355 	}
356 
357 	switch (kind) {
358 	case CTF_K_INTEGER:
359 		if (ctf_type_encoding(ctf, tid, &e) == CTF_ERR)
360 			return (parse_warn("Can't get encoding for %ld", tid));
361 
362 		return (fth_print_integer(mem->fsm_memname, mem->fsm_off,
363 		    e.cte_bits, mem->fsm_format, level));
364 
365 	case CTF_K_FLOAT:
366 		(void) parse_warn("Ignoring floating point member %s.%s",
367 		    fth_curtype, mem->fsm_memname);
368 		return (0);
369 
370 	case CTF_K_POINTER:
371 		return (fth_print_pointer(mem->fsm_memname, mem->fsm_off,
372 		    sz * 8, mem->fsm_format, level));
373 
374 	case CTF_K_ARRAY:
375 		return (fth_print_array(mem->fsm_memname, tid, mem->fsm_off, sz,
376 		    mem->fsm_format, level));
377 
378 	case CTF_K_STRUCT:
379 	case CTF_K_UNION:
380 		return (fth_print_struct(mem->fsm_memname, mem->fsm_off,
381 		    mem->fsm_format, level));
382 
383 	case CTF_K_ENUM:
384 		return (fth_print_enum(mem->fsm_memname, mem->fsm_off,
385 		    mem->fsm_format, level));
386 
387 	case CTF_K_FORWARD:
388 		return (parse_warn("Type %ld in %s.%s is undefined", tid,
389 		    fth_curtype, mem->fsm_memname));
390 
391 	default:
392 		return (parse_warn("Unexpected kind %d for %s.%s", kind,
393 		    fth_curtype, mem->fsm_memname));
394 	}
395 }
396 
397 /*
398  * Add a member to list of members to be printed (fth_str_curmems).  If
399  * fsmd_memfilter is non-null, only add this member if its name matches that
400  * in the filter.
401  */
402 static int
403 fth_struct_members_cb(const char *memname, ctf_id_t tid, ulong_t off, void *arg)
404 {
405 	fth_struct_members_data_t *fsmd = arg;
406 	fth_str_mem_t *mem;
407 
408 	if (fsmd->fsmd_memfilter != NULL && strcmp(fsmd->fsmd_memfilter,
409 	    memname) != 0)
410 		return (0);
411 
412 	fsmd->fsmd_matched = 1;
413 
414 	mem = xcalloc(sizeof (fth_str_mem_t));
415 	mem->fsm_memname = xstrdup(memname);
416 	if (fsmd->fsmd_format)
417 		mem->fsm_format = xstrdup(fsmd->fsmd_format);
418 	mem->fsm_tid = tid;
419 	mem->fsm_off = off;
420 
421 	slist_add(&fth_str_curmems, mem, fth_struct_memcmp);
422 
423 	return (0);
424 }
425 
426 /*
427  * If memfilter is non-null, iterate through the members of this type, causing
428  * every member to be added to the list.  Otherwise, use the iterator and
429  * the callback to add only the specified member.
430  */
431 static int
432 fth_struct_members(char *memfilter, char *format)
433 {
434 	fth_struct_members_data_t fsmd;
435 
436 	fsmd.fsmd_strname = fth_curtype;
437 	fsmd.fsmd_memfilter = memfilter;
438 	fsmd.fsmd_format = format;
439 	fsmd.fsmd_matched = 0;
440 
441 	if (ctf_member_iter(ctf, fth_str_curtid, fth_struct_members_cb,
442 	    &fsmd) != 0)
443 		return (-1);
444 
445 	if (memfilter != NULL && fsmd.fsmd_matched == 0) {
446 		return (parse_warn("Invalid member %s.%s", fth_curtype,
447 		    memfilter));
448 	}
449 
450 	return (0);
451 }
452 
453 static int
454 fth_struct_trailer(void)
455 {
456 	if (list_count(fth_str_curmems) == 0) {
457 		if (fth_struct_members(NULL, NULL) < 0)
458 			return (-1);
459 	}
460 
461 	while (!list_empty(fth_str_curmems)) {
462 		fth_str_mem_t *mem = list_remove(&fth_str_curmems,
463 		    list_first(fth_str_curmems), NULL, NULL);
464 
465 		if (fth_print_member(mem, 0) < 0)
466 			return (-1);
467 
468 		fth_free_str_mem(mem);
469 	}
470 
471 	(void) fprintf(out, "\n");
472 	(void) fprintf(out, "kdbg-words definitions\n");
473 	(void) fprintf(out, "previous\n");
474 	(void) fprintf(out, "\n");
475 	(void) fprintf(out, "\\ end %s section\n", fth_curtype);
476 	(void) fprintf(out, "\n");
477 
478 	return (0);
479 }
480 
481 fth_type_ops_t fth_struct_ops = {
482 	fth_struct_header,
483 	fth_struct_members,
484 	fth_struct_trailer
485 };
486