10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*436Sdmick * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * In this mode, we generate header files containg various #defines which can 310Sstevel@tonic-gate * be used to access members of various structures, and to walk through arrays. 320Sstevel@tonic-gate * The input template specifies the structures and members for whom #defines 330Sstevel@tonic-gate * are to be generated. 340Sstevel@tonic-gate * 350Sstevel@tonic-gate * The template has the following elements 360Sstevel@tonic-gate * 370Sstevel@tonic-gate * 1. Given the name of a structure or union, #defines can be generated that 380Sstevel@tonic-gate * describe the type. If requested, #defines that give the size and the 390Sstevel@tonic-gate * log2 (shift) of the structure will be generated. The latter can only 400Sstevel@tonic-gate * be requested for structures whose size is a power of two. 410Sstevel@tonic-gate * 420Sstevel@tonic-gate * Per-member #defines are also generated. The value of these defines will 430Sstevel@tonic-gate * be the offsets necessary to access the members they describe. By 440Sstevel@tonic-gate * default, the name of the #define will be the name of the member, in upper 450Sstevel@tonic-gate * case, but a user-supplied version can be used instead. If the member is 460Sstevel@tonic-gate * an array, an extra #define will be generated that will give the increment 470Sstevel@tonic-gate * needed to access individual array elements. The name of the increment 480Sstevel@tonic-gate * #define will be identical to that of the member #define, but with an 490Sstevel@tonic-gate * "_INCR" suffix. 500Sstevel@tonic-gate * 510Sstevel@tonic-gate * 2. Literal cpp directives 520Sstevel@tonic-gate * 530Sstevel@tonic-gate * Lines beginning with "\#" are copied directly to the output file. 540Sstevel@tonic-gate * 550Sstevel@tonic-gate * 3. Comments 560Sstevel@tonic-gate * 570Sstevel@tonic-gate * Lines beginning with backslashes (excluding the literal cpp directives 580Sstevel@tonic-gate * described above) are ignored. 590Sstevel@tonic-gate * 600Sstevel@tonic-gate * Example input: 610Sstevel@tonic-gate * 620Sstevel@tonic-gate * \ Dump the `foo' structure, creating a size #define called FOO_SIZE, and a 630Sstevel@tonic-gate * \ shift #define called FOO_SHIFT. `foo' has one member called `mem'. 640Sstevel@tonic-gate * foo FOO_SIZE FOO_SHIFT 650Sstevel@tonic-gate * 660Sstevel@tonic-gate * \ Dump the `a' and `b' members of the `bar' structure. the offset 670Sstevel@tonic-gate * \ #defines for these members should be `FRED' and `BOB', respectively. 680Sstevel@tonic-gate * \ Both members are of type `char' 690Sstevel@tonic-gate * bar 700Sstevel@tonic-gate * a FRED 710Sstevel@tonic-gate * b BOB 720Sstevel@tonic-gate * 730Sstevel@tonic-gate * Example output: 740Sstevel@tonic-gate * 750Sstevel@tonic-gate * #define FOO_SIZE 0x4 760Sstevel@tonic-gate * #define FOO_SHIFT 0x2 770Sstevel@tonic-gate * #define FRED 0x0 780Sstevel@tonic-gate * #define FRED_INCR 0x1 790Sstevel@tonic-gate * #define BOB 0x4 800Sstevel@tonic-gate */ 810Sstevel@tonic-gate 820Sstevel@tonic-gate #include <string.h> 830Sstevel@tonic-gate #include <stdio.h> 840Sstevel@tonic-gate #include <stdlib.h> 850Sstevel@tonic-gate #include <ctype.h> 860Sstevel@tonic-gate #include <sys/types.h> 870Sstevel@tonic-gate 880Sstevel@tonic-gate #include "ctf_headers.h" 890Sstevel@tonic-gate #include "utils.h" 900Sstevel@tonic-gate #include "ctfstabs.h" 910Sstevel@tonic-gate 920Sstevel@tonic-gate static int 930Sstevel@tonic-gate ga_parse_tokens(char *line, int max, char ***wret) 940Sstevel@tonic-gate { 950Sstevel@tonic-gate char *c = line; 960Sstevel@tonic-gate char *word; 970Sstevel@tonic-gate int n; 980Sstevel@tonic-gate 990Sstevel@tonic-gate while (isspace(*c)) 1000Sstevel@tonic-gate c++; 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate for (n = 1, word = strtok(line, " \t"); word != NULL; 1030Sstevel@tonic-gate word = strtok(NULL, " \t"), n++) { 1040Sstevel@tonic-gate if (n > max) 1050Sstevel@tonic-gate return (-1); 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate *(wret[n - 1]) = word; 1080Sstevel@tonic-gate } 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate return (n - 1); 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate static int 1140Sstevel@tonic-gate ga_parse_common(char *line, int min, int max, char **w1, char **w2, char **w3) 1150Sstevel@tonic-gate { 1160Sstevel@tonic-gate char **wret[3]; 1170Sstevel@tonic-gate int nread; 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate wret[0] = w1; 1200Sstevel@tonic-gate wret[1] = w2; 1210Sstevel@tonic-gate wret[2] = w3; 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate if ((nread = ga_parse_tokens(line, max, wret)) < min) 1240Sstevel@tonic-gate return (-1); 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate if (nread < 3 && wret[2] != NULL) 1270Sstevel@tonic-gate *wret[2] = (char *)NULL; 1280Sstevel@tonic-gate if (nread < 2 && wret[1] != NULL) 1290Sstevel@tonic-gate *wret[1] = (char *)NULL; 1300Sstevel@tonic-gate if (nread < 1 && wret[0] != NULL) 1310Sstevel@tonic-gate *wret[0] = (char *)NULL; 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate return (nread); 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate /* 1370Sstevel@tonic-gate * Valid format: typename [sizedefname [shiftdefname]] 1380Sstevel@tonic-gate */ 1390Sstevel@tonic-gate static int 1400Sstevel@tonic-gate ga_parse_name(char *line, char **cnp, char **szdp, char **shdp) 1410Sstevel@tonic-gate { 1420Sstevel@tonic-gate return (ga_parse_common(line, 1, 3, cnp, szdp, shdp)); 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate /* 1460Sstevel@tonic-gate * Valid format: memname [offdefname] 1470Sstevel@tonic-gate */ 1480Sstevel@tonic-gate static int 1490Sstevel@tonic-gate ga_parse_member(char *line, char **mnp, char **offp) 1500Sstevel@tonic-gate { 1510Sstevel@tonic-gate return (ga_parse_common(line, 1, 2, mnp, offp, NULL)); 1520Sstevel@tonic-gate } 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate /* 1550Sstevel@tonic-gate * Used to begin a new structure/union block, and to print the optional size 1560Sstevel@tonic-gate * and optional shift constants. 1570Sstevel@tonic-gate */ 1580Sstevel@tonic-gate static int 1590Sstevel@tonic-gate ga_process_name(char *line) 1600Sstevel@tonic-gate { 1610Sstevel@tonic-gate char *curname, *sizedef, *shdef; 1620Sstevel@tonic-gate ctf_id_t curtype; 1630Sstevel@tonic-gate ssize_t sz, shift; 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate if (ga_parse_name(line, &curname, &sizedef, &shdef) < 0) 1660Sstevel@tonic-gate return (parse_warn("Couldn't parse name")); 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate if ((curtype = find_type(curname)) == CTF_ERR) 1690Sstevel@tonic-gate return (parse_warn("Couldn't find type %s", curname)); 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate if (sizedef != NULL) { 1720Sstevel@tonic-gate if ((sz = ctf_type_size(ctf, curtype)) < 0) { 1730Sstevel@tonic-gate return (parse_warn("Couldn't get size for type %s", 1740Sstevel@tonic-gate curname)); 1750Sstevel@tonic-gate } else if (sz == 0) { 1760Sstevel@tonic-gate return (parse_warn("Invalid type size 0 for %s", 1770Sstevel@tonic-gate curname)); 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate (void) fprintf(out, "#define\t%s\t0x%x\n", sizedef, sz); 1810Sstevel@tonic-gate } 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate if (shdef != NULL) { 1840Sstevel@tonic-gate ssize_t tsz; 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate for (shift = -1, tsz = sz; tsz > 0; tsz >>= 1, shift++); 1870Sstevel@tonic-gate if (shift < 0 || 1 << shift != sz) { 1880Sstevel@tonic-gate return (parse_warn("Can't make shift #define: %s size " 1890Sstevel@tonic-gate "(%d) isn't a power of 2", curname, sz)); 1900Sstevel@tonic-gate } 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate (void) fprintf(out, "#define\t%s\t0x%x\n", shdef, shift); 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate return (curtype); 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate /* 1990Sstevel@tonic-gate * ga_process_member() and ga_member_cb() are used to print the offset and 2000Sstevel@tonic-gate * possibly array increment values for a given structure member. A specific 2010Sstevel@tonic-gate * member is requested via ga_process_member(), and ga_member_cb() is used 2020Sstevel@tonic-gate * to iterate through the members of the current structure type, looking for 2030Sstevel@tonic-gate * that member. This is not the most efficient way to do things, but the 2040Sstevel@tonic-gate * lists involved are generally short. 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate typedef struct ga_member_cb_data { 2070Sstevel@tonic-gate char *gmcb_memname; 2080Sstevel@tonic-gate char *gmcb_submem; 2090Sstevel@tonic-gate char *gmcb_offdef; 2100Sstevel@tonic-gate size_t gmcb_off; 2110Sstevel@tonic-gate } ga_member_cb_data_t; 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate static int ga_member_find(ctf_id_t, ga_member_cb_data_t *); 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate static int 2160Sstevel@tonic-gate ga_member_cb(const char *name, ctf_id_t type, ulong_t off, void *arg) 2170Sstevel@tonic-gate { 2180Sstevel@tonic-gate ga_member_cb_data_t *md = arg; 2190Sstevel@tonic-gate ctf_arinfo_t arinfo; 2200Sstevel@tonic-gate char *label; 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate if (strcmp(name, md->gmcb_memname) != 0) 2230Sstevel@tonic-gate return (0); 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate md->gmcb_off += off / 8; /* off is in bits */ 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate if (md->gmcb_submem != NULL) { 2280Sstevel@tonic-gate /* 2290Sstevel@tonic-gate * The user requested foo.bar. We've found foo, and now need to 2300Sstevel@tonic-gate * recurse down to bar. 2310Sstevel@tonic-gate */ 2320Sstevel@tonic-gate ga_member_cb_data_t smd; 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate smd.gmcb_memname = md->gmcb_submem; 2350Sstevel@tonic-gate smd.gmcb_submem = NULL; 2360Sstevel@tonic-gate smd.gmcb_offdef = md->gmcb_offdef; 2370Sstevel@tonic-gate smd.gmcb_off = md->gmcb_off; 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate return (ga_member_find(type, &smd)); 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate if (md->gmcb_offdef == NULL) { 2430Sstevel@tonic-gate int i; 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate label = md->gmcb_memname; 2460Sstevel@tonic-gate for (i = 0; i < strlen(label); i++) 2470Sstevel@tonic-gate label[i] = toupper(label[i]); 2480Sstevel@tonic-gate } else 2490Sstevel@tonic-gate label = md->gmcb_offdef; 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate /* offsets are in bits - we need bytes */ 2520Sstevel@tonic-gate (void) fprintf(out, "#define\t%s\t0x%lx\n", label, 2530Sstevel@tonic-gate (ulong_t)md->gmcb_off); 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate if ((type = ctf_type_resolve(ctf, type)) == CTF_ERR) 2560Sstevel@tonic-gate return (parse_warn("Couldn't resolve type %s", name)); 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate if (ctf_array_info(ctf, type, &arinfo) == 0) { 2590Sstevel@tonic-gate ssize_t sz; 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate if ((sz = ctf_type_size(ctf, arinfo.ctr_contents)) < 0) 2620Sstevel@tonic-gate return (parse_warn("Couldn't get array elem size")); 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate (void) fprintf(out, "#define\t%s_INCR\t0x%x\n", label, sz); 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate return (1); 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate static int 2710Sstevel@tonic-gate ga_member_find(ctf_id_t curtype, ga_member_cb_data_t *md) 2720Sstevel@tonic-gate { 2730Sstevel@tonic-gate char *c; 2740Sstevel@tonic-gate int rc; 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate if ((c = strchr(md->gmcb_memname, '.')) != NULL) 2770Sstevel@tonic-gate *c++ = NULL; 2780Sstevel@tonic-gate md->gmcb_submem = c; 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate if ((rc = ctf_member_iter(ctf, curtype, ga_member_cb, md)) == 0) { 2810Sstevel@tonic-gate return (parse_warn("Couldn't find member named %s", 2820Sstevel@tonic-gate md->gmcb_memname)); 2830Sstevel@tonic-gate } else if (rc != 1) 2840Sstevel@tonic-gate return (parse_warn("Can't parse")); 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate return (1); 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate static int 2900Sstevel@tonic-gate ga_process_member(ctf_id_t curtype, char *line) 2910Sstevel@tonic-gate { 2920Sstevel@tonic-gate ga_member_cb_data_t md = { 0 }; 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate if (ga_parse_member(line, &md.gmcb_memname, &md.gmcb_offdef) < 0) 2950Sstevel@tonic-gate return (parse_warn("Couldn't parse member")); 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate return (ga_member_find(curtype, &md)); 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate static int 3010Sstevel@tonic-gate ga_process_line(char *line) 3020Sstevel@tonic-gate { 3030Sstevel@tonic-gate static int curtype = -1; 3040Sstevel@tonic-gate int nblank = 0; 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate if (strlen(line) == 0) { 3070Sstevel@tonic-gate curtype = -1; 3080Sstevel@tonic-gate if (nblank++ == 1) 3090Sstevel@tonic-gate (void) fprintf(out, "\n"); 3100Sstevel@tonic-gate return (1); 3110Sstevel@tonic-gate } else 3120Sstevel@tonic-gate nblank = 0; 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate if (line[0] == '\\') { 3150Sstevel@tonic-gate if (line[1] == '#') { 3160Sstevel@tonic-gate /* dump, verbatim, lines that begin with "\#" */ 3170Sstevel@tonic-gate (void) fprintf(out, "%s\n", line + 1); 3180Sstevel@tonic-gate } 3190Sstevel@tonic-gate return (1); 320*436Sdmick 3210Sstevel@tonic-gate } else if (line[0] == '#') { 322*436Sdmick /* 323*436Sdmick * This is a comment of some sort; is it a line number 324*436Sdmick * comment? Those look like '# 53 "filename.c"'. GCC 325*436Sdmick * sometimes inserts them and removes all other vertical 326*436Sdmick * whitespace, so they should be treated as a "type 327*436Sdmick * terminator" like a blank line is. 328*436Sdmick */ 329*436Sdmick if (isdigit(line[2])) { 330*436Sdmick /* line number, terminate type */ 331*436Sdmick curtype = -1; 332*436Sdmick } 3330Sstevel@tonic-gate return (1); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate if (curtype == -1) 3360Sstevel@tonic-gate return ((curtype = ga_process_name(line))); 3370Sstevel@tonic-gate else 3380Sstevel@tonic-gate return (ga_process_member(curtype, line)); 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate proc_ops_t ga_ops = { 3420Sstevel@tonic-gate NULL, 3430Sstevel@tonic-gate ga_process_line, 3440Sstevel@tonic-gate NULL 3450Sstevel@tonic-gate }; 346