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 /* 28 * In this mode, we generate forthdebug macros as requested by the input 29 * template, the format of which is given below. 30 * 31 * These templates have the following elements: 32 * 33 * 1. Macro creation 34 * 35 * Given the name of a structure, union, or enum type, a forthdebug macro 36 * is created that will dump the members of the type. The type can be 37 * specified as a standalone structure, union, or enum, or it can be 38 * described relative to another structure or union as "type.member". 39 * 40 * By default, all struct members, union members, or enum values, as 41 * appropriate, will be printed. An alternate form allows specific members 42 * of struct or union types to be printed. Both forms must be followed by a 43 * blank line. In the specific-member case, an optional format specifier can 44 * be provided that will be used to dump the contents of the member. 45 * Builtins `d' and `x' can be used to dump the member in decimal or 46 * hexadecimal, respectively. Alternatively, a custom formatter can be 47 * specified. 48 * 49 * 2. Model-specific sections 50 * 51 * `model_start' / `model_end' pairs function as an #ifdef for the ctfstabs 52 * tool. They take, as an argument, either `ilp32' or `lp64'. If a 64-bit 53 * macro is being generated (if a 64-bit object file is being used), lines 54 * between `lp64' model pairs will be processed, but lines between `ilp32' 55 * pairs will be omitted. The reverse is true for 32-bit macros. 56 * 57 * 3. Literal sections 58 * 59 * Portions of the input template file enclosed within `forth_start' / 60 * `forth_end' pairs and between `verbatim_begin' / `verbatim_end' pairs 61 * will be copied as-is to the output file. 62 * 63 * 4. Comments 64 * 65 * Lines beginning with backslashes are ignored. 66 * 67 * Example: 68 * 69 * \ dump the `foo' structure 70 * foo 71 * 72 * \ dump the `a' and `b' members of the `bar' structure. dump member `b' 73 * \ in hexadecimal 74 * bar 75 * a 76 * b x 77 * 78 * \ dump the `big' member of the `baz' structure in 64-bit macros, and 79 * \ the `small' member in 32-bit macros. 80 * baz 81 * model_start lp64 82 * big 83 * model_end 84 * model_start ilp32 85 * small 86 * model_end 87 * 88 * \ copy `literal 1' and `literal 2' to the output file 89 * verbatim_begin 90 * literal 1 91 * verbatim_end 92 * forth_start 93 * literal 2 94 * forth_end 95 * 96 * For a more complex example, see common.fdbg. 97 */ 98 99 #include <stdio.h> 100 #include <stdlib.h> 101 #include <string.h> 102 #include <ctype.h> 103 104 #include "ctf_headers.h" 105 #include "ctfstabs.h" 106 #include "forth.h" 107 #include "utils.h" 108 #include "memory.h" 109 110 char *fth_curtype; /* name of the type being processed */ 111 static fth_type_ops_t *fth_type_ops; /* see forth.h */ 112 113 static char *fth_model; /* the current macro type - for model_start */ 114 static int fth_ignoring; /* in a non-matching model_start/end pair */ 115 static int fth_copying; /* in a verbatim_* or forth_* pair */ 116 117 static int 118 fth_init(char *model) 119 { 120 fth_model = model; 121 122 return (0); 123 } 124 125 /*ARGSUSED*/ 126 static int 127 fth_null_header(ctf_id_t tid) 128 { 129 return (0); 130 } 131 132 /*ARGSUSED*/ 133 static int 134 fth_null_members(char *memfilter, char *format) 135 { 136 return (0); 137 } 138 139 static int 140 fth_null_trailer(void) 141 { 142 return (0); 143 } 144 145 static fth_type_ops_t fth_null_ops = { 146 fth_null_header, 147 fth_null_members, 148 fth_null_trailer 149 }; 150 151 /*ARGSUSED2*/ 152 static int 153 find_member_cb(const char *memname, ctf_id_t tid, ulong_t off, void *arg) 154 { 155 char *memtofind = arg; 156 157 if (strcmp(memname, memtofind) == 0) 158 return (tid); 159 160 return (0); 161 } 162 163 /* find the tid of a specified member */ 164 static ctf_id_t 165 find_member(ctf_id_t tid, char *memname) 166 { 167 return (ctf_member_iter(ctf, tid, find_member_cb, memname)); 168 } 169 170 /* 171 * Begin a macro. 172 * 173 * Once we figure out the type of the thing that we're supposed to dump (struct, 174 * union, or enum), we select the proper type-specific ops-vector for dumping. 175 */ 176 static int 177 fth_section_init(char *fullname) 178 { 179 ctf_id_t ltid = 0, tid; 180 char *curtype, *lpart, *part, *npart; 181 int lkind = 0, kind; 182 183 curtype = xstrdup(fullname); 184 lpart = NULL; 185 part = strtok(fullname, "."); 186 187 /* 188 * First figure out what sort of type we're looking at. Life would be 189 * simple if we were only going to get type names, but it's not - we 190 * could also get `type.member'. In that case, we need to figure out 191 * (and dump) the type of `member' instead. 192 */ 193 for (;;) { 194 if (lpart == NULL) { 195 /* First part - the struct name */ 196 if ((tid = find_type(part)) == CTF_ERR || 197 (tid = ctf_type_resolve(ctf, tid)) == CTF_ERR || 198 (kind = ctf_type_kind(ctf, tid)) == CTF_ERR) { 199 free(curtype); 200 return (parse_warn("Couldn't find %s: %s", 201 part, ctf_errmsg(ctf_errno(ctf)))); 202 } 203 } else { 204 /* Second (or more) part - the member name */ 205 if (lkind != CTF_K_STRUCT && lkind != CTF_K_UNION) { 206 free(curtype); 207 return (parse_warn("%s isn't a struct/union", 208 lpart)); 209 } 210 211 if ((tid = find_member(ltid, part)) <= 0) { 212 free(curtype); 213 return (parse_warn("%s isn't a member of %s", 214 part, lpart)); 215 } 216 217 if ((kind = ctf_type_kind(ctf, tid)) == CTF_ERR) { 218 free(curtype); 219 return (parse_warn("Can't get kind for %s", 220 part)); 221 } 222 } 223 224 /* 225 * Stop if there aren't any more parts. We use `npart' here 226 * because we don't want to clobber part - we need it later. 227 */ 228 if ((npart = strtok(NULL, ".")) == NULL) 229 break; 230 231 lpart = part; 232 ltid = tid; 233 lkind = kind; 234 235 part = npart; 236 } 237 238 /* 239 * Pick the right ops vector for dumping. 240 */ 241 switch (kind) { 242 case CTF_K_STRUCT: 243 case CTF_K_UNION: 244 fth_type_ops = &fth_struct_ops; 245 break; 246 247 case CTF_K_ENUM: 248 fth_type_ops = &fth_enum_ops; 249 break; 250 251 default: 252 fth_type_ops = &fth_null_ops; 253 free(curtype); 254 return (parse_warn("%s isn't a struct, union, or enum", part)); 255 } 256 257 fth_curtype = curtype; 258 259 return (fth_type_ops->fto_header(tid)); 260 } 261 262 static int 263 fth_section_add_member(char *name, char *format) 264 { 265 if (fth_curtype == NULL) 266 return (fth_section_init(name)); 267 268 if (fth_type_ops->fto_members(name, format) < 0) 269 return (-1); 270 271 return (0); 272 } 273 274 static int 275 fth_section_end(void) 276 { 277 if (fth_curtype == NULL) 278 return (0); 279 280 if (fth_type_ops->fto_trailer() < 0) 281 return (-1); 282 283 free(fth_curtype); 284 fth_curtype = NULL; 285 286 return (0); 287 } 288 289 static int 290 fth_process_line(char *line) 291 { 292 char *format = NULL; 293 char *word, *name, *c; 294 int nblank = 0; 295 int n; 296 297 if (strlen(line) == 0) { 298 if (fth_section_end() < 0) 299 return (-1); 300 301 if (fth_copying == 1 || nblank++ == 1) 302 (void) fprintf(out, "\n"); 303 return (0); 304 } else 305 nblank = 0; 306 307 /* skip comments */ 308 if (line[0] == '\\') 309 return (0); 310 311 if (strcmp(line, "model_end") == 0) { 312 fth_ignoring = 0; 313 return (0); 314 } 315 316 if (fth_ignoring == 1) 317 return (0); 318 319 word = "model_start "; 320 if (strncmp(line, word, strlen(word)) == 0) { 321 for (c = line + strlen(word); isspace(*c); c++); 322 if (strlen(c) == strlen(fth_model) && 323 strncmp(c, fth_model, strlen(fth_model)) == 0) 324 /* EMPTY - match */; 325 else 326 fth_ignoring = 1; 327 return (0); 328 } 329 330 if (strcmp(line, "verbatim_end") == 0 || 331 strcmp(line, "forth_end") == 0) { 332 char *start = (strcmp(line, "verbatim_end") == 0 ? 333 "verbatim_begin" : "forth_start"); 334 335 if (fth_copying == 0) { 336 (void) parse_warn("Found %s without matching %s", 337 line, start); 338 if (fth_curtype != NULL) 339 (void) fth_section_end(); 340 return (-1); 341 } 342 fth_copying = 0; 343 return (0); 344 } 345 346 if (fth_copying == 1) { 347 (void) fprintf(out, "%s\n", line); 348 return (0); 349 } 350 351 if (strcmp(line, "verbatim_begin") == 0 || 352 strcmp(line, "forth_start") == 0) { 353 if (fth_curtype != NULL) { 354 (void) parse_warn("Expected blank line between %s " 355 "macro and %s", fth_curtype, line); 356 return (fth_section_end()); 357 } 358 359 fth_copying = 1; 360 return (0); 361 } 362 363 for (n = 1, word = strtok(line, " \t"); word != NULL; 364 word = strtok(NULL, " \t"), n++) { 365 if (n == 1) 366 name = word; 367 else if (n == 2) 368 format = word; 369 else 370 (void) parse_warn("Too many words"); 371 } 372 373 return (fth_section_add_member(name, format)); 374 } 375 376 static int 377 fth_fini(void) 378 { 379 return (fth_section_end()); 380 } 381 382 proc_ops_t fth_ops = { 383 fth_init, 384 fth_process_line, 385 fth_fini 386 }; 387