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