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 2003 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 * This program has two modes. 31 * 32 * In the first, or genassym, mode, it generates a header file containing 33 * #define'd values for offsets and other information about requested 34 * structures and arrays. This header file can then be used by assembly 35 * source files to access those structures without having to hard-code the 36 * offsets. The offsets and values in the header file are derived from the 37 * CTF data in a provided object file. 38 * 39 * The second mode creates forthdebug macros for specified structures and 40 * members from an object file. The macros are created using the CTF data in 41 * the object file. 42 * 43 * Forthdebug macros and offsets header files are generated using the same 44 * tool for historical reasons. 45 * 46 * The input and output files, and their interaction with the tool are 47 * shown below: 48 * 49 * --------------- ----------- cc -c -g ------------------ 50 * |#includes | -----> |#includes| ------------> |object file with| 51 * |mode-specific| ----------- ctfconvert | CTF data | 52 * | directives| ------------------ 53 * --------------- | 54 * | | obj_file 55 * | V 56 * | ------------ ---------- 57 * \-------------> |directives| ---------------> |ctfstabs| 58 * ------------ input_template ---------- 59 * | 60 * V 61 * --------------- 62 * Mode-specific input and output formats are |mode-specific| 63 * described in forth.c and genassym.c | output | 64 * --------------- 65 */ 66 67 #include <stdio.h> 68 #include <stdlib.h> 69 #include <stdarg.h> 70 #include <errno.h> 71 #include <fcntl.h> 72 #include <unistd.h> 73 #include <libgen.h> 74 #include <string.h> 75 #include <ctype.h> 76 #include <sys/types.h> 77 #include <sys/stat.h> 78 79 #include "ctf_headers.h" 80 #include "utils.h" 81 #include "memory.h" 82 #include "ctfstabs.h" 83 84 #define WORD_LEN 256 85 86 static int lineno; 87 88 FILE *out; 89 ctf_file_t *ctf; 90 91 static void 92 usage(void) 93 { 94 (void) fprintf(stderr, "Usage: %s -t genassym [-m model] " 95 "[-i input_template] [-o output] obj_file\n", getpname()); 96 (void) fprintf(stderr, " %s -t forth [-m model] " 97 "[-i input_template] [-o output] obj_file\n", getpname()); 98 exit(2); 99 } 100 101 /*PRINTFLIKE1*/ 102 int 103 parse_warn(char *format, ...) 104 { 105 va_list alist; 106 107 (void) fprintf(stderr, "%s: Line %d: ", getpname(), lineno); 108 109 va_start(alist, format); 110 (void) vfprintf(stderr, format, alist); 111 va_end(alist); 112 113 (void) fprintf(stderr, "\n"); 114 115 return (-1); 116 } 117 118 #define READLINE_BUF_INCR 2 119 120 /* 121 * Read a line of input into a statically-allocated buffer. If the line 122 * is larger than the buffer, the buffer will be dynamically resized. 123 * Subsequent calls will overwrite the buffer. 124 */ 125 static char * 126 readline(FILE *fp) 127 { 128 static char *buf, *bptr; 129 static int buflen; 130 131 if (buflen == 0) { 132 buf = xmalloc(READLINE_BUF_INCR); 133 buflen = READLINE_BUF_INCR; 134 } 135 136 bptr = buf; 137 for (;;) { 138 size_t len, off; 139 140 if (fgets(bptr, buflen - (size_t)(bptr - buf), fp) == NULL) 141 return (NULL); 142 143 len = strlen(bptr); 144 145 if (bptr[len - 1] == '\n') 146 return (buf); 147 148 off = (size_t)((bptr + len) - buf); 149 buflen += READLINE_BUF_INCR; 150 buf = xrealloc(buf, buflen); 151 bptr = buf + off; 152 } 153 } 154 155 /* 156 * We're only given a type name. Even if it's a struct or a union, we 157 * still only get the struct or union name. We therefore iterate through 158 * the possible prefixes, trying to find the right type. 159 */ 160 ctf_id_t 161 find_type(char *name) 162 { 163 char fullname[WORD_LEN]; 164 ctf_id_t id; 165 166 if ((id = ctf_lookup_by_name(ctf, name)) != CTF_ERR) 167 return (id); 168 169 (void) snprintf(fullname, WORD_LEN, "struct %s", name); 170 if ((id = ctf_lookup_by_name(ctf, fullname)) != CTF_ERR) 171 return (id); 172 173 (void) snprintf(fullname, WORD_LEN, "union %s", name); 174 if ((id = ctf_lookup_by_name(ctf, fullname)) != CTF_ERR) 175 return (id); 176 177 (void) snprintf(fullname, WORD_LEN, "enum %s", name); 178 if ((id = ctf_lookup_by_name(ctf, fullname)) != CTF_ERR) 179 return (id); 180 181 return (CTF_ERR); 182 } 183 184 static int 185 process_ifile(FILE *tmpl, proc_ops_t *ops) 186 { 187 char *line; 188 int skipping; 189 size_t len; 190 int err = 0; 191 192 for (lineno = skipping = 0; (line = readline(tmpl)) != NULL; lineno++) { 193 len = strlen(line) - 1; 194 line[len] = '\0'; 195 196 if (len == 0) 197 skipping = 0; 198 199 if (skipping == 1) 200 continue; 201 202 if (ops->po_line(line) < 0) { 203 (void) parse_warn("Error found: skipping to the next " 204 "blank line"); 205 err++; 206 skipping = 1; 207 continue; 208 } 209 } 210 211 return (err > 0 ? -1 : 0); 212 } 213 214 static char * 215 get_model(ctf_file_t *ctf) 216 { 217 ssize_t lsz; 218 ctf_id_t lid; 219 220 /* Neither of these should fail */ 221 if ((lid = ctf_lookup_by_name(ctf, "long")) == CTF_ERR || 222 (lsz = ctf_type_size(ctf, lid)) == CTF_ERR) 223 die("Couldn't get size of long in object file"); 224 225 if (lsz == 8) 226 return ("lp64"); 227 else if (lsz == 4) 228 return ("ilp32"); 229 else 230 die("Unexpected size of long: %d bytes\n", lsz); 231 232 return (NULL); 233 } 234 235 int 236 main(int argc, char **argv) 237 { 238 char *model = NULL, *objfile = NULL, *outfile = NULL, *tmplfile = NULL; 239 proc_ops_t *ops = &ga_ops; 240 FILE *tmpl; 241 int ctferr, c; 242 243 while ((c = getopt(argc, argv, "i:m:o:t:")) != EOF) { 244 switch (c) { 245 case 'i': 246 tmplfile = optarg; 247 break; 248 case 'm': 249 model = optarg; 250 break; 251 case 't': 252 if (strcmp(optarg, "genassym") == 0) 253 ops = &ga_ops; 254 else if (strcmp(optarg, "forth") == 0) 255 ops = &fth_ops; 256 else 257 usage(); 258 break; 259 260 case 'o': 261 outfile = optarg; 262 break; 263 default: 264 usage(); 265 } 266 } 267 268 if (argc - optind != 1) 269 usage(); 270 objfile = argv[optind]; 271 272 if (tmplfile == NULL || strcmp(tmplfile, "-") == 0) 273 tmpl = stdin; 274 else if ((tmpl = fopen(tmplfile, "r")) == NULL) 275 die("Couldn't open template file %s", tmplfile); 276 277 /* 278 * this can fail if ENOENT or if there's no CTF data in the file. 279 */ 280 if ((ctf = ctf_open(objfile, &ctferr)) == NULL) { 281 die("Couldn't open object file %s: %s\n", objfile, 282 ctf_errmsg(ctferr)); 283 } 284 285 if (model == NULL) 286 model = get_model(ctf); 287 else if (strcmp(model, get_model(ctf)) != 0) 288 die("Model argument %s doesn't match the object file\n", model); 289 290 if (outfile == NULL || strcmp(outfile, "-") == 0) 291 out = stdout; 292 else if ((out = fopen(outfile, "w")) == NULL) 293 die("Couldn't open output file %s for writing", outfile); 294 295 if ((ops->po_init != NULL && ops->po_init(model) < 0) || 296 (process_ifile(tmpl, ops) < 0) || 297 (ops->po_fini != NULL && ops->po_fini() < 0)) { 298 (void) fclose(out); 299 (void) unlink(outfile); 300 return (1); 301 } 302 303 return (0); 304 } 305