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 120 fth_init(char *model) 121 { 122 fth_model = model; 123 124 return (0); 125 } 126 127 /*ARGSUSED*/ 128 static int 129 fth_null_header(ctf_id_t tid) 130 { 131 return (0); 132 } 133 134 /*ARGSUSED*/ 135 static int 136 fth_null_members(char *memfilter, char *format) 137 { 138 return (0); 139 } 140 141 static int 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 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 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 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 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 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 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 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