17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5e824d57fSjohnlev * Common Development and Distribution License (the "License"). 6e824d57fSjohnlev * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22e824d57fSjohnlev * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * In this mode, we generate header files containg various #defines which can 287c478bd9Sstevel@tonic-gate * be used to access members of various structures, and to walk through arrays. 297c478bd9Sstevel@tonic-gate * The input template specifies the structures and members for whom #defines 307c478bd9Sstevel@tonic-gate * are to be generated. 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * The template has the following elements 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * 1. Given the name of a structure or union, #defines can be generated that 357c478bd9Sstevel@tonic-gate * describe the type. If requested, #defines that give the size and the 367c478bd9Sstevel@tonic-gate * log2 (shift) of the structure will be generated. The latter can only 377c478bd9Sstevel@tonic-gate * be requested for structures whose size is a power of two. 387c478bd9Sstevel@tonic-gate * 397c478bd9Sstevel@tonic-gate * Per-member #defines are also generated. The value of these defines will 407c478bd9Sstevel@tonic-gate * be the offsets necessary to access the members they describe. By 417c478bd9Sstevel@tonic-gate * default, the name of the #define will be the name of the member, in upper 427c478bd9Sstevel@tonic-gate * case, but a user-supplied version can be used instead. If the member is 437c478bd9Sstevel@tonic-gate * an array, an extra #define will be generated that will give the increment 447c478bd9Sstevel@tonic-gate * needed to access individual array elements. The name of the increment 457c478bd9Sstevel@tonic-gate * #define will be identical to that of the member #define, but with an 467c478bd9Sstevel@tonic-gate * "_INCR" suffix. 477c478bd9Sstevel@tonic-gate * 487c478bd9Sstevel@tonic-gate * 2. Literal cpp directives 497c478bd9Sstevel@tonic-gate * 507c478bd9Sstevel@tonic-gate * Lines beginning with "\#" are copied directly to the output file. 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * 3. Comments 537c478bd9Sstevel@tonic-gate * 547c478bd9Sstevel@tonic-gate * Lines beginning with backslashes (excluding the literal cpp directives 557c478bd9Sstevel@tonic-gate * described above) are ignored. 567c478bd9Sstevel@tonic-gate * 577c478bd9Sstevel@tonic-gate * Example input: 587c478bd9Sstevel@tonic-gate * 597c478bd9Sstevel@tonic-gate * \ Dump the `foo' structure, creating a size #define called FOO_SIZE, and a 607c478bd9Sstevel@tonic-gate * \ shift #define called FOO_SHIFT. `foo' has one member called `mem'. 617c478bd9Sstevel@tonic-gate * foo FOO_SIZE FOO_SHIFT 627c478bd9Sstevel@tonic-gate * 637c478bd9Sstevel@tonic-gate * \ Dump the `a' and `b' members of the `bar' structure. the offset 647c478bd9Sstevel@tonic-gate * \ #defines for these members should be `FRED' and `BOB', respectively. 657c478bd9Sstevel@tonic-gate * \ Both members are of type `char' 667c478bd9Sstevel@tonic-gate * bar 677c478bd9Sstevel@tonic-gate * a FRED 687c478bd9Sstevel@tonic-gate * b BOB 697c478bd9Sstevel@tonic-gate * 707c478bd9Sstevel@tonic-gate * Example output: 717c478bd9Sstevel@tonic-gate * 727c478bd9Sstevel@tonic-gate * #define FOO_SIZE 0x4 737c478bd9Sstevel@tonic-gate * #define FOO_SHIFT 0x2 747c478bd9Sstevel@tonic-gate * #define FRED 0x0 757c478bd9Sstevel@tonic-gate * #define FRED_INCR 0x1 767c478bd9Sstevel@tonic-gate * #define BOB 0x4 777c478bd9Sstevel@tonic-gate */ 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate #include <string.h> 807c478bd9Sstevel@tonic-gate #include <stdio.h> 817c478bd9Sstevel@tonic-gate #include <stdlib.h> 827c478bd9Sstevel@tonic-gate #include <ctype.h> 837c478bd9Sstevel@tonic-gate #include <sys/types.h> 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate #include "ctf_headers.h" 867c478bd9Sstevel@tonic-gate #include "utils.h" 877c478bd9Sstevel@tonic-gate #include "ctfstabs.h" 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate static int 907c478bd9Sstevel@tonic-gate ga_parse_tokens(char *line, int max, char ***wret) 917c478bd9Sstevel@tonic-gate { 927c478bd9Sstevel@tonic-gate char *c = line; 937c478bd9Sstevel@tonic-gate char *word; 947c478bd9Sstevel@tonic-gate int n; 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate while (isspace(*c)) 977c478bd9Sstevel@tonic-gate c++; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate for (n = 1, word = strtok(line, " \t"); word != NULL; 1007c478bd9Sstevel@tonic-gate word = strtok(NULL, " \t"), n++) { 1017c478bd9Sstevel@tonic-gate if (n > max) 1027c478bd9Sstevel@tonic-gate return (-1); 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate *(wret[n - 1]) = word; 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate return (n - 1); 1087c478bd9Sstevel@tonic-gate } 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate static int 1117c478bd9Sstevel@tonic-gate ga_parse_common(char *line, int min, int max, char **w1, char **w2, char **w3) 1127c478bd9Sstevel@tonic-gate { 1137c478bd9Sstevel@tonic-gate char **wret[3]; 1147c478bd9Sstevel@tonic-gate int nread; 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate wret[0] = w1; 1177c478bd9Sstevel@tonic-gate wret[1] = w2; 1187c478bd9Sstevel@tonic-gate wret[2] = w3; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate if ((nread = ga_parse_tokens(line, max, wret)) < min) 1217c478bd9Sstevel@tonic-gate return (-1); 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate if (nread < 3 && wret[2] != NULL) 1247c478bd9Sstevel@tonic-gate *wret[2] = (char *)NULL; 1257c478bd9Sstevel@tonic-gate if (nread < 2 && wret[1] != NULL) 1267c478bd9Sstevel@tonic-gate *wret[1] = (char *)NULL; 1277c478bd9Sstevel@tonic-gate if (nread < 1 && wret[0] != NULL) 1287c478bd9Sstevel@tonic-gate *wret[0] = (char *)NULL; 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate return (nread); 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate /* 1347c478bd9Sstevel@tonic-gate * Valid format: typename [sizedefname [shiftdefname]] 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate static int 1377c478bd9Sstevel@tonic-gate ga_parse_name(char *line, char **cnp, char **szdp, char **shdp) 1387c478bd9Sstevel@tonic-gate { 1397c478bd9Sstevel@tonic-gate return (ga_parse_common(line, 1, 3, cnp, szdp, shdp)); 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate /* 1437c478bd9Sstevel@tonic-gate * Valid format: memname [offdefname] 1447c478bd9Sstevel@tonic-gate */ 1457c478bd9Sstevel@tonic-gate static int 1467c478bd9Sstevel@tonic-gate ga_parse_member(char *line, char **mnp, char **offp) 1477c478bd9Sstevel@tonic-gate { 1487c478bd9Sstevel@tonic-gate return (ga_parse_common(line, 1, 2, mnp, offp, NULL)); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate /* 1527c478bd9Sstevel@tonic-gate * Used to begin a new structure/union block, and to print the optional size 1537c478bd9Sstevel@tonic-gate * and optional shift constants. 1547c478bd9Sstevel@tonic-gate */ 1557c478bd9Sstevel@tonic-gate static int 1567c478bd9Sstevel@tonic-gate ga_process_name(char *line) 1577c478bd9Sstevel@tonic-gate { 1587c478bd9Sstevel@tonic-gate char *curname, *sizedef, *shdef; 1597c478bd9Sstevel@tonic-gate ctf_id_t curtype; 1607c478bd9Sstevel@tonic-gate ssize_t sz, shift; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate if (ga_parse_name(line, &curname, &sizedef, &shdef) < 0) 1637c478bd9Sstevel@tonic-gate return (parse_warn("Couldn't parse name")); 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate if ((curtype = find_type(curname)) == CTF_ERR) 1667c478bd9Sstevel@tonic-gate return (parse_warn("Couldn't find type %s", curname)); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate if (sizedef != NULL) { 1697c478bd9Sstevel@tonic-gate if ((sz = ctf_type_size(ctf, curtype)) < 0) { 1707c478bd9Sstevel@tonic-gate return (parse_warn("Couldn't get size for type %s", 1717c478bd9Sstevel@tonic-gate curname)); 1727c478bd9Sstevel@tonic-gate } else if (sz == 0) { 1737c478bd9Sstevel@tonic-gate return (parse_warn("Invalid type size 0 for %s", 1747c478bd9Sstevel@tonic-gate curname)); 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate (void) fprintf(out, "#define\t%s\t0x%x\n", sizedef, sz); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate if (shdef != NULL) { 1817c478bd9Sstevel@tonic-gate ssize_t tsz; 1827c478bd9Sstevel@tonic-gate 183*ad0b1ea5SRichard PALO for (shift = -1, tsz = sz; tsz > 0; tsz >>= 1, shift++) 184*ad0b1ea5SRichard PALO ; 1857c478bd9Sstevel@tonic-gate if (shift < 0 || 1 << shift != sz) { 1867c478bd9Sstevel@tonic-gate return (parse_warn("Can't make shift #define: %s size " 1877c478bd9Sstevel@tonic-gate "(%d) isn't a power of 2", curname, sz)); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate (void) fprintf(out, "#define\t%s\t0x%x\n", shdef, shift); 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate return (curtype); 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /* 1977c478bd9Sstevel@tonic-gate * ga_process_member() and ga_member_cb() are used to print the offset and 1987c478bd9Sstevel@tonic-gate * possibly array increment values for a given structure member. A specific 1997c478bd9Sstevel@tonic-gate * member is requested via ga_process_member(), and ga_member_cb() is used 2007c478bd9Sstevel@tonic-gate * to iterate through the members of the current structure type, looking for 2017c478bd9Sstevel@tonic-gate * that member. This is not the most efficient way to do things, but the 2027c478bd9Sstevel@tonic-gate * lists involved are generally short. 2037c478bd9Sstevel@tonic-gate */ 2047c478bd9Sstevel@tonic-gate typedef struct ga_member_cb_data { 2057c478bd9Sstevel@tonic-gate char *gmcb_memname; 2067c478bd9Sstevel@tonic-gate char *gmcb_submem; 2077c478bd9Sstevel@tonic-gate char *gmcb_offdef; 2087c478bd9Sstevel@tonic-gate size_t gmcb_off; 2097c478bd9Sstevel@tonic-gate } ga_member_cb_data_t; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate static int ga_member_find(ctf_id_t, ga_member_cb_data_t *); 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate static int 2147c478bd9Sstevel@tonic-gate ga_member_cb(const char *name, ctf_id_t type, ulong_t off, void *arg) 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate ga_member_cb_data_t *md = arg; 2177c478bd9Sstevel@tonic-gate ctf_arinfo_t arinfo; 2187c478bd9Sstevel@tonic-gate char *label; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate if (strcmp(name, md->gmcb_memname) != 0) 2217c478bd9Sstevel@tonic-gate return (0); 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate md->gmcb_off += off / 8; /* off is in bits */ 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate if (md->gmcb_submem != NULL) { 2267c478bd9Sstevel@tonic-gate /* 2277c478bd9Sstevel@tonic-gate * The user requested foo.bar. We've found foo, and now need to 2287c478bd9Sstevel@tonic-gate * recurse down to bar. 2297c478bd9Sstevel@tonic-gate */ 2307c478bd9Sstevel@tonic-gate ga_member_cb_data_t smd; 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate smd.gmcb_memname = md->gmcb_submem; 2337c478bd9Sstevel@tonic-gate smd.gmcb_submem = NULL; 2347c478bd9Sstevel@tonic-gate smd.gmcb_offdef = md->gmcb_offdef; 2357c478bd9Sstevel@tonic-gate smd.gmcb_off = md->gmcb_off; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate return (ga_member_find(type, &smd)); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (md->gmcb_offdef == NULL) { 2417c478bd9Sstevel@tonic-gate int i; 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate label = md->gmcb_memname; 2447c478bd9Sstevel@tonic-gate for (i = 0; i < strlen(label); i++) 2457c478bd9Sstevel@tonic-gate label[i] = toupper(label[i]); 2467c478bd9Sstevel@tonic-gate } else 2477c478bd9Sstevel@tonic-gate label = md->gmcb_offdef; 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* offsets are in bits - we need bytes */ 2507c478bd9Sstevel@tonic-gate (void) fprintf(out, "#define\t%s\t0x%lx\n", label, 2517c478bd9Sstevel@tonic-gate (ulong_t)md->gmcb_off); 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate if ((type = ctf_type_resolve(ctf, type)) == CTF_ERR) 2547c478bd9Sstevel@tonic-gate return (parse_warn("Couldn't resolve type %s", name)); 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate if (ctf_array_info(ctf, type, &arinfo) == 0) { 2577c478bd9Sstevel@tonic-gate ssize_t sz; 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate if ((sz = ctf_type_size(ctf, arinfo.ctr_contents)) < 0) 2607c478bd9Sstevel@tonic-gate return (parse_warn("Couldn't get array elem size")); 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate (void) fprintf(out, "#define\t%s_INCR\t0x%x\n", label, sz); 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate return (1); 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate static int 2697c478bd9Sstevel@tonic-gate ga_member_find(ctf_id_t curtype, ga_member_cb_data_t *md) 2707c478bd9Sstevel@tonic-gate { 2717c478bd9Sstevel@tonic-gate char *c; 2727c478bd9Sstevel@tonic-gate int rc; 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate if ((c = strchr(md->gmcb_memname, '.')) != NULL) 275*ad0b1ea5SRichard PALO *c++ = '\0'; 2767c478bd9Sstevel@tonic-gate md->gmcb_submem = c; 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate if ((rc = ctf_member_iter(ctf, curtype, ga_member_cb, md)) == 0) { 2797c478bd9Sstevel@tonic-gate return (parse_warn("Couldn't find member named %s", 2807c478bd9Sstevel@tonic-gate md->gmcb_memname)); 2817c478bd9Sstevel@tonic-gate } else if (rc != 1) 2827c478bd9Sstevel@tonic-gate return (parse_warn("Can't parse")); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate return (1); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate static int 2887c478bd9Sstevel@tonic-gate ga_process_member(ctf_id_t curtype, char *line) 2897c478bd9Sstevel@tonic-gate { 2907c478bd9Sstevel@tonic-gate ga_member_cb_data_t md = { 0 }; 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate if (ga_parse_member(line, &md.gmcb_memname, &md.gmcb_offdef) < 0) 2937c478bd9Sstevel@tonic-gate return (parse_warn("Couldn't parse member")); 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate return (ga_member_find(curtype, &md)); 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate static int 2997c478bd9Sstevel@tonic-gate ga_process_line(char *line) 3007c478bd9Sstevel@tonic-gate { 3017c478bd9Sstevel@tonic-gate static int curtype = -1; 302e824d57fSjohnlev static int blanks = 0; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate if (strlen(line) == 0) { 305e824d57fSjohnlev blanks++; 3067c478bd9Sstevel@tonic-gate return (1); 307e824d57fSjohnlev } else if (blanks) { 308e824d57fSjohnlev if (!isspace(line[0])) 309e824d57fSjohnlev curtype = -1; 310e824d57fSjohnlev blanks = 0; 311e824d57fSjohnlev } 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate if (line[0] == '\\') { 3147c478bd9Sstevel@tonic-gate if (line[1] == '#') { 3157c478bd9Sstevel@tonic-gate /* dump, verbatim, lines that begin with "\#" */ 3167c478bd9Sstevel@tonic-gate (void) fprintf(out, "%s\n", line + 1); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate return (1); 31989518a1cSdmick 3207c478bd9Sstevel@tonic-gate } else if (line[0] == '#') { 32189518a1cSdmick /* 32289518a1cSdmick * This is a comment of some sort; is it a line number 32389518a1cSdmick * comment? Those look like '# 53 "filename.c"'. GCC 32489518a1cSdmick * sometimes inserts them and removes all other vertical 32589518a1cSdmick * whitespace, so they should be treated as a "type 32689518a1cSdmick * terminator" like a blank line is. 32789518a1cSdmick */ 32889518a1cSdmick if (isdigit(line[2])) { 32989518a1cSdmick /* line number, terminate type */ 33089518a1cSdmick curtype = -1; 33189518a1cSdmick } 3327c478bd9Sstevel@tonic-gate return (1); 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate if (curtype == -1) 3357c478bd9Sstevel@tonic-gate return ((curtype = ga_process_name(line))); 3367c478bd9Sstevel@tonic-gate else 3377c478bd9Sstevel@tonic-gate return (ga_process_member(curtype, line)); 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate proc_ops_t ga_ops = { 3417c478bd9Sstevel@tonic-gate NULL, 3427c478bd9Sstevel@tonic-gate ga_process_line, 3437c478bd9Sstevel@tonic-gate NULL 3447c478bd9Sstevel@tonic-gate }; 345