1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * In this mode, we generate header files containg various #defines which can 31*0Sstevel@tonic-gate * be used to access members of various structures, and to walk through arrays. 32*0Sstevel@tonic-gate * The input template specifies the structures and members for whom #defines 33*0Sstevel@tonic-gate * are to be generated. 34*0Sstevel@tonic-gate * 35*0Sstevel@tonic-gate * The template has the following elements 36*0Sstevel@tonic-gate * 37*0Sstevel@tonic-gate * 1. Given the name of a structure or union, #defines can be generated that 38*0Sstevel@tonic-gate * describe the type. If requested, #defines that give the size and the 39*0Sstevel@tonic-gate * log2 (shift) of the structure will be generated. The latter can only 40*0Sstevel@tonic-gate * be requested for structures whose size is a power of two. 41*0Sstevel@tonic-gate * 42*0Sstevel@tonic-gate * Per-member #defines are also generated. The value of these defines will 43*0Sstevel@tonic-gate * be the offsets necessary to access the members they describe. By 44*0Sstevel@tonic-gate * default, the name of the #define will be the name of the member, in upper 45*0Sstevel@tonic-gate * case, but a user-supplied version can be used instead. If the member is 46*0Sstevel@tonic-gate * an array, an extra #define will be generated that will give the increment 47*0Sstevel@tonic-gate * needed to access individual array elements. The name of the increment 48*0Sstevel@tonic-gate * #define will be identical to that of the member #define, but with an 49*0Sstevel@tonic-gate * "_INCR" suffix. 50*0Sstevel@tonic-gate * 51*0Sstevel@tonic-gate * 2. Literal cpp directives 52*0Sstevel@tonic-gate * 53*0Sstevel@tonic-gate * Lines beginning with "\#" are copied directly to the output file. 54*0Sstevel@tonic-gate * 55*0Sstevel@tonic-gate * 3. Comments 56*0Sstevel@tonic-gate * 57*0Sstevel@tonic-gate * Lines beginning with backslashes (excluding the literal cpp directives 58*0Sstevel@tonic-gate * described above) are ignored. 59*0Sstevel@tonic-gate * 60*0Sstevel@tonic-gate * Example input: 61*0Sstevel@tonic-gate * 62*0Sstevel@tonic-gate * \ Dump the `foo' structure, creating a size #define called FOO_SIZE, and a 63*0Sstevel@tonic-gate * \ shift #define called FOO_SHIFT. `foo' has one member called `mem'. 64*0Sstevel@tonic-gate * foo FOO_SIZE FOO_SHIFT 65*0Sstevel@tonic-gate * 66*0Sstevel@tonic-gate * \ Dump the `a' and `b' members of the `bar' structure. the offset 67*0Sstevel@tonic-gate * \ #defines for these members should be `FRED' and `BOB', respectively. 68*0Sstevel@tonic-gate * \ Both members are of type `char' 69*0Sstevel@tonic-gate * bar 70*0Sstevel@tonic-gate * a FRED 71*0Sstevel@tonic-gate * b BOB 72*0Sstevel@tonic-gate * 73*0Sstevel@tonic-gate * Example output: 74*0Sstevel@tonic-gate * 75*0Sstevel@tonic-gate * #define FOO_SIZE 0x4 76*0Sstevel@tonic-gate * #define FOO_SHIFT 0x2 77*0Sstevel@tonic-gate * #define FRED 0x0 78*0Sstevel@tonic-gate * #define FRED_INCR 0x1 79*0Sstevel@tonic-gate * #define BOB 0x4 80*0Sstevel@tonic-gate */ 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate #include <string.h> 83*0Sstevel@tonic-gate #include <stdio.h> 84*0Sstevel@tonic-gate #include <stdlib.h> 85*0Sstevel@tonic-gate #include <ctype.h> 86*0Sstevel@tonic-gate #include <sys/types.h> 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate #include "ctf_headers.h" 89*0Sstevel@tonic-gate #include "utils.h" 90*0Sstevel@tonic-gate #include "ctfstabs.h" 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate static int 93*0Sstevel@tonic-gate ga_parse_tokens(char *line, int max, char ***wret) 94*0Sstevel@tonic-gate { 95*0Sstevel@tonic-gate char *c = line; 96*0Sstevel@tonic-gate char *word; 97*0Sstevel@tonic-gate int n; 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate while (isspace(*c)) 100*0Sstevel@tonic-gate c++; 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate for (n = 1, word = strtok(line, " \t"); word != NULL; 103*0Sstevel@tonic-gate word = strtok(NULL, " \t"), n++) { 104*0Sstevel@tonic-gate if (n > max) 105*0Sstevel@tonic-gate return (-1); 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate *(wret[n - 1]) = word; 108*0Sstevel@tonic-gate } 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate return (n - 1); 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate static int 114*0Sstevel@tonic-gate ga_parse_common(char *line, int min, int max, char **w1, char **w2, char **w3) 115*0Sstevel@tonic-gate { 116*0Sstevel@tonic-gate char **wret[3]; 117*0Sstevel@tonic-gate int nread; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate wret[0] = w1; 120*0Sstevel@tonic-gate wret[1] = w2; 121*0Sstevel@tonic-gate wret[2] = w3; 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate if ((nread = ga_parse_tokens(line, max, wret)) < min) 124*0Sstevel@tonic-gate return (-1); 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate if (nread < 3 && wret[2] != NULL) 127*0Sstevel@tonic-gate *wret[2] = (char *)NULL; 128*0Sstevel@tonic-gate if (nread < 2 && wret[1] != NULL) 129*0Sstevel@tonic-gate *wret[1] = (char *)NULL; 130*0Sstevel@tonic-gate if (nread < 1 && wret[0] != NULL) 131*0Sstevel@tonic-gate *wret[0] = (char *)NULL; 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate return (nread); 134*0Sstevel@tonic-gate } 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate /* 137*0Sstevel@tonic-gate * Valid format: typename [sizedefname [shiftdefname]] 138*0Sstevel@tonic-gate */ 139*0Sstevel@tonic-gate static int 140*0Sstevel@tonic-gate ga_parse_name(char *line, char **cnp, char **szdp, char **shdp) 141*0Sstevel@tonic-gate { 142*0Sstevel@tonic-gate return (ga_parse_common(line, 1, 3, cnp, szdp, shdp)); 143*0Sstevel@tonic-gate } 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate /* 146*0Sstevel@tonic-gate * Valid format: memname [offdefname] 147*0Sstevel@tonic-gate */ 148*0Sstevel@tonic-gate static int 149*0Sstevel@tonic-gate ga_parse_member(char *line, char **mnp, char **offp) 150*0Sstevel@tonic-gate { 151*0Sstevel@tonic-gate return (ga_parse_common(line, 1, 2, mnp, offp, NULL)); 152*0Sstevel@tonic-gate } 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate /* 155*0Sstevel@tonic-gate * Used to begin a new structure/union block, and to print the optional size 156*0Sstevel@tonic-gate * and optional shift constants. 157*0Sstevel@tonic-gate */ 158*0Sstevel@tonic-gate static int 159*0Sstevel@tonic-gate ga_process_name(char *line) 160*0Sstevel@tonic-gate { 161*0Sstevel@tonic-gate char *curname, *sizedef, *shdef; 162*0Sstevel@tonic-gate ctf_id_t curtype; 163*0Sstevel@tonic-gate ssize_t sz, shift; 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate if (ga_parse_name(line, &curname, &sizedef, &shdef) < 0) 166*0Sstevel@tonic-gate return (parse_warn("Couldn't parse name")); 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate if ((curtype = find_type(curname)) == CTF_ERR) 169*0Sstevel@tonic-gate return (parse_warn("Couldn't find type %s", curname)); 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate if (sizedef != NULL) { 172*0Sstevel@tonic-gate if ((sz = ctf_type_size(ctf, curtype)) < 0) { 173*0Sstevel@tonic-gate return (parse_warn("Couldn't get size for type %s", 174*0Sstevel@tonic-gate curname)); 175*0Sstevel@tonic-gate } else if (sz == 0) { 176*0Sstevel@tonic-gate return (parse_warn("Invalid type size 0 for %s", 177*0Sstevel@tonic-gate curname)); 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate (void) fprintf(out, "#define\t%s\t0x%x\n", sizedef, sz); 181*0Sstevel@tonic-gate } 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate if (shdef != NULL) { 184*0Sstevel@tonic-gate ssize_t tsz; 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate for (shift = -1, tsz = sz; tsz > 0; tsz >>= 1, shift++); 187*0Sstevel@tonic-gate if (shift < 0 || 1 << shift != sz) { 188*0Sstevel@tonic-gate return (parse_warn("Can't make shift #define: %s size " 189*0Sstevel@tonic-gate "(%d) isn't a power of 2", curname, sz)); 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate (void) fprintf(out, "#define\t%s\t0x%x\n", shdef, shift); 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate return (curtype); 196*0Sstevel@tonic-gate } 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate /* 199*0Sstevel@tonic-gate * ga_process_member() and ga_member_cb() are used to print the offset and 200*0Sstevel@tonic-gate * possibly array increment values for a given structure member. A specific 201*0Sstevel@tonic-gate * member is requested via ga_process_member(), and ga_member_cb() is used 202*0Sstevel@tonic-gate * to iterate through the members of the current structure type, looking for 203*0Sstevel@tonic-gate * that member. This is not the most efficient way to do things, but the 204*0Sstevel@tonic-gate * lists involved are generally short. 205*0Sstevel@tonic-gate */ 206*0Sstevel@tonic-gate typedef struct ga_member_cb_data { 207*0Sstevel@tonic-gate char *gmcb_memname; 208*0Sstevel@tonic-gate char *gmcb_submem; 209*0Sstevel@tonic-gate char *gmcb_offdef; 210*0Sstevel@tonic-gate size_t gmcb_off; 211*0Sstevel@tonic-gate } ga_member_cb_data_t; 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate static int ga_member_find(ctf_id_t, ga_member_cb_data_t *); 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate static int 216*0Sstevel@tonic-gate ga_member_cb(const char *name, ctf_id_t type, ulong_t off, void *arg) 217*0Sstevel@tonic-gate { 218*0Sstevel@tonic-gate ga_member_cb_data_t *md = arg; 219*0Sstevel@tonic-gate ctf_arinfo_t arinfo; 220*0Sstevel@tonic-gate char *label; 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate if (strcmp(name, md->gmcb_memname) != 0) 223*0Sstevel@tonic-gate return (0); 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate md->gmcb_off += off / 8; /* off is in bits */ 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate if (md->gmcb_submem != NULL) { 228*0Sstevel@tonic-gate /* 229*0Sstevel@tonic-gate * The user requested foo.bar. We've found foo, and now need to 230*0Sstevel@tonic-gate * recurse down to bar. 231*0Sstevel@tonic-gate */ 232*0Sstevel@tonic-gate ga_member_cb_data_t smd; 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate smd.gmcb_memname = md->gmcb_submem; 235*0Sstevel@tonic-gate smd.gmcb_submem = NULL; 236*0Sstevel@tonic-gate smd.gmcb_offdef = md->gmcb_offdef; 237*0Sstevel@tonic-gate smd.gmcb_off = md->gmcb_off; 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate return (ga_member_find(type, &smd)); 240*0Sstevel@tonic-gate } 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate if (md->gmcb_offdef == NULL) { 243*0Sstevel@tonic-gate int i; 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate label = md->gmcb_memname; 246*0Sstevel@tonic-gate for (i = 0; i < strlen(label); i++) 247*0Sstevel@tonic-gate label[i] = toupper(label[i]); 248*0Sstevel@tonic-gate } else 249*0Sstevel@tonic-gate label = md->gmcb_offdef; 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate /* offsets are in bits - we need bytes */ 252*0Sstevel@tonic-gate (void) fprintf(out, "#define\t%s\t0x%lx\n", label, 253*0Sstevel@tonic-gate (ulong_t)md->gmcb_off); 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate if ((type = ctf_type_resolve(ctf, type)) == CTF_ERR) 256*0Sstevel@tonic-gate return (parse_warn("Couldn't resolve type %s", name)); 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate if (ctf_array_info(ctf, type, &arinfo) == 0) { 259*0Sstevel@tonic-gate ssize_t sz; 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate if ((sz = ctf_type_size(ctf, arinfo.ctr_contents)) < 0) 262*0Sstevel@tonic-gate return (parse_warn("Couldn't get array elem size")); 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate (void) fprintf(out, "#define\t%s_INCR\t0x%x\n", label, sz); 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate return (1); 268*0Sstevel@tonic-gate } 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate static int 271*0Sstevel@tonic-gate ga_member_find(ctf_id_t curtype, ga_member_cb_data_t *md) 272*0Sstevel@tonic-gate { 273*0Sstevel@tonic-gate char *c; 274*0Sstevel@tonic-gate int rc; 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate if ((c = strchr(md->gmcb_memname, '.')) != NULL) 277*0Sstevel@tonic-gate *c++ = NULL; 278*0Sstevel@tonic-gate md->gmcb_submem = c; 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate if ((rc = ctf_member_iter(ctf, curtype, ga_member_cb, md)) == 0) { 281*0Sstevel@tonic-gate return (parse_warn("Couldn't find member named %s", 282*0Sstevel@tonic-gate md->gmcb_memname)); 283*0Sstevel@tonic-gate } else if (rc != 1) 284*0Sstevel@tonic-gate return (parse_warn("Can't parse")); 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate return (1); 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate static int 290*0Sstevel@tonic-gate ga_process_member(ctf_id_t curtype, char *line) 291*0Sstevel@tonic-gate { 292*0Sstevel@tonic-gate ga_member_cb_data_t md = { 0 }; 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate if (ga_parse_member(line, &md.gmcb_memname, &md.gmcb_offdef) < 0) 295*0Sstevel@tonic-gate return (parse_warn("Couldn't parse member")); 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate return (ga_member_find(curtype, &md)); 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate static int 301*0Sstevel@tonic-gate ga_process_line(char *line) 302*0Sstevel@tonic-gate { 303*0Sstevel@tonic-gate static int curtype = -1; 304*0Sstevel@tonic-gate int nblank = 0; 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate if (strlen(line) == 0) { 307*0Sstevel@tonic-gate curtype = -1; 308*0Sstevel@tonic-gate if (nblank++ == 1) 309*0Sstevel@tonic-gate (void) fprintf(out, "\n"); 310*0Sstevel@tonic-gate return (1); 311*0Sstevel@tonic-gate } else 312*0Sstevel@tonic-gate nblank = 0; 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate if (line[0] == '\\') { 315*0Sstevel@tonic-gate if (line[1] == '#') { 316*0Sstevel@tonic-gate /* dump, verbatim, lines that begin with "\#" */ 317*0Sstevel@tonic-gate (void) fprintf(out, "%s\n", line + 1); 318*0Sstevel@tonic-gate } 319*0Sstevel@tonic-gate return (1); 320*0Sstevel@tonic-gate } else if (line[0] == '#') { 321*0Sstevel@tonic-gate return (1); 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate if (curtype == -1) 325*0Sstevel@tonic-gate return ((curtype = ga_process_name(line))); 326*0Sstevel@tonic-gate else 327*0Sstevel@tonic-gate return (ga_process_member(curtype, line)); 328*0Sstevel@tonic-gate } 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate proc_ops_t ga_ops = { 331*0Sstevel@tonic-gate NULL, 332*0Sstevel@tonic-gate ga_process_line, 333*0Sstevel@tonic-gate NULL 334*0Sstevel@tonic-gate }; 335