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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Routines used to read stabs data from a file, and to build a tdata structure 30 * based on the interesting parts of that data. 31 */ 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <fcntl.h> 36 #include <unistd.h> 37 #include <assert.h> 38 #include <string.h> 39 #include <libgen.h> 40 #include <errno.h> 41 #include <sys/types.h> 42 #include <sys/param.h> 43 44 #include "ctftools.h" 45 #include "list.h" 46 #include "stack.h" 47 #include "memory.h" 48 #include "traverse.h" 49 50 const char *curhdr; 51 52 /* 53 * The stabs generator will sometimes reference types before they've been 54 * defined. If this is the case, a TYPEDEF_UNRES tdesc will be generated. 55 * Note that this is different from a forward declaration, in which the 56 * stab is defined, but is defined as something that doesn't exist yet. 57 * When we have read all of the stabs from the file, we can go back and 58 * fix up all of the unresolved types. We should be able to fix all of them. 59 */ 60 /*ARGSUSED2*/ 61 static int 62 resolve_tou_node(tdesc_t *node, tdesc_t **nodep, void *private) 63 { 64 tdesc_t *new; 65 66 debug(3, "Trying to resolve %s (%d)\n", tdesc_name(node), node->t_id); 67 new = lookup(node->t_id); 68 69 if (new == NULL) { 70 terminate("Couldn't resolve type %d\n", node->t_id); 71 } 72 73 debug(3, " Resolving to %d\n", new->t_id); 74 75 *nodep = new; 76 77 return (1); 78 } 79 80 /*ARGSUSED*/ 81 static int 82 resolve_fwd_node(tdesc_t *node, tdesc_t **nodep, void *private) 83 { 84 tdesc_t *new = lookupname(node->t_name); 85 86 debug(3, "Trying to unforward %s (%d)\n", tdesc_name(node), node->t_id); 87 88 if (!new || (new->t_type != STRUCT && new->t_type != UNION)) 89 return (0); 90 91 debug(3, " Unforwarded to %d\n", new->t_id); 92 93 *nodep = new; 94 95 return (1); 96 } 97 98 static tdtrav_cb_f resolve_cbs[] = { 99 NULL, 100 NULL, /* intrinsic */ 101 NULL, /* pointer */ 102 NULL, /* array */ 103 NULL, /* function */ 104 NULL, /* struct */ 105 NULL, /* union */ 106 NULL, /* enum */ 107 resolve_fwd_node, /* forward */ 108 NULL, /* typedef */ 109 resolve_tou_node, /* typedef unres */ 110 NULL, /* volatile */ 111 NULL, /* const */ 112 NULL, /* restrict */ 113 }; 114 115 static void 116 resolve_nodes(tdata_t *td) 117 { 118 debug(2, "Resolving unresolved stabs\n"); 119 120 (void) iitraverse_hash(td->td_iihash, &td->td_curvgen, resolve_cbs, 121 NULL, NULL, td); 122 } 123 124 static char * 125 concat(char *s1, char *s2, int s2strip) 126 { 127 int savelen = strlen(s2) - s2strip; 128 int newlen = (s1 ? strlen(s1) : 0) + savelen + 1; 129 char *out; 130 131 out = xrealloc(s1, newlen); 132 if (s1) 133 strncpy(out + strlen(out), s2, savelen); 134 else 135 strncpy(out, s2, savelen); 136 137 out[newlen - 1] = '\0'; 138 139 return (out); 140 } 141 142 /* 143 * N_FUN stabs come with their arguments in promoted form. In order to get the 144 * actual arguments, we need to wait for the N_PSYM stabs that will come towards 145 * the end of the function. These routines free the arguments (fnarg_free) we 146 * got from the N_FUN stab and add (fnarg_add) the ones from the N_PSYM stabs. 147 */ 148 static void 149 fnarg_add(iidesc_t *curfun, iidesc_t *arg) 150 { 151 curfun->ii_nargs++; 152 153 if (curfun->ii_nargs == 1) 154 curfun->ii_args = xmalloc(sizeof (tdesc_t *) * FUNCARG_DEF); 155 else if (curfun->ii_nargs > FUNCARG_DEF) { 156 curfun->ii_args = xrealloc(curfun->ii_args, 157 sizeof (tdesc_t *) * curfun->ii_nargs); 158 } 159 160 curfun->ii_args[curfun->ii_nargs - 1] = arg->ii_dtype; 161 arg->ii_dtype = NULL; 162 } 163 164 static void 165 fnarg_free(iidesc_t *ii) 166 { 167 ii->ii_nargs = 0; 168 free(ii->ii_args); 169 ii->ii_args = NULL; 170 } 171 172 /* 173 * Read the stabs from the stab ELF section, and turn them into a tdesc tree, 174 * assembled under an iidesc list. 175 */ 176 int 177 stabs_read(tdata_t *td, Elf *elf, const char *filename) 178 { 179 Elf_Scn *scn; 180 Elf_Data *data; 181 stab_t *stab; 182 stk_t *file_stack; 183 iidesc_t *iidescp; 184 iidesc_t *curfun = NULL; 185 char curpath[MAXPATHLEN]; 186 char *curfile = NULL; 187 char *str; 188 char *fstr = NULL, *ofstr = NULL; 189 int stabidx, stabstridx; 190 int nstabs, rc, i; 191 int scope = 0; 192 193 if (!((stabidx = findelfsecidx(elf, ".stab.excl")) >= 0 && 194 (stabstridx = findelfsecidx(elf, ".stab.exclstr")) >= 0) && 195 !((stabidx = findelfsecidx(elf, ".stab")) >= 0 && 196 (stabstridx = findelfsecidx(elf, ".stabstr")) >= 0)) { 197 errno = ENOENT; 198 return (-1); 199 } 200 201 file_stack = stack_new(free); 202 203 stack_push(file_stack, (void *)filename); 204 curhdr = filename; 205 206 debug(3, "Found stabs in %d, strings in %d\n", stabidx, stabstridx); 207 208 scn = elf_getscn(elf, stabidx); 209 data = elf_rawdata(scn, NULL); 210 nstabs = data->d_size / sizeof (stab_t); 211 212 parse_init(td); 213 for (i = 0; i < nstabs; i++) { 214 stab = &((stab_t *)data->d_buf)[i]; 215 216 /* We don't want any local definitions */ 217 if (stab->n_type == N_LBRAC) { 218 scope++; 219 debug(3, "stab %d: opening scope (%d)\n", i + 1, scope); 220 continue; 221 } else if (stab->n_type == N_RBRAC) { 222 scope--; 223 debug(3, "stab %d: closing scope (%d)\n", i + 1, scope); 224 continue; 225 } else if (stab->n_type == N_EINCL) { 226 /* 227 * There's a bug in the 5.2 (Taz) compilers that causes 228 * them to emit an extra N_EINCL if there's no actual 229 * text in the file being compiled. To work around this 230 * bug, we explicitly check to make sure we're not 231 * trying to pop a stack that only has the outer scope 232 * on it. 233 */ 234 if (stack_level(file_stack) != 1) { 235 str = (char *)stack_pop(file_stack); 236 free(str); 237 curhdr = (char *)stack_peek(file_stack); 238 } 239 } 240 241 /* We only care about a subset of the stabs */ 242 if (!(stab->n_type == N_FUN || stab->n_type == N_GSYM || 243 stab->n_type == N_LCSYM || stab->n_type == N_LSYM || 244 stab->n_type == N_PSYM || stab->n_type == N_ROSYM || 245 stab->n_type == N_RSYM || 246 stab->n_type == N_STSYM || stab->n_type == N_BINCL || 247 stab->n_type == N_SO || stab->n_type == N_OPT)) 248 continue; 249 250 if ((str = elf_strptr(elf, stabstridx, 251 (size_t)stab->n_strx)) == NULL) { 252 terminate("Can't find string at %u for stab %d\n", 253 stab->n_strx, i); 254 } 255 256 if (stab->n_type == N_BINCL) { 257 curhdr = xstrdup(str); 258 stack_push(file_stack, (void *)curhdr); 259 continue; 260 } else if (stab->n_type == N_SO) { 261 if (str[strlen(str) - 1] != '/') { 262 strcpy(curpath, str); 263 curfile = basename(curpath); 264 } 265 continue; 266 } else if (stab->n_type == N_OPT) { 267 if (strcmp(str, "gcc2_compiled.") == 0) { 268 terminate("GCC-generated stabs are " 269 "unsupported. Use DWARF instead.\n"); 270 } 271 continue; 272 } 273 274 if (str[strlen(str) - 1] == '\\') { 275 int offset = 1; 276 /* 277 * There's a bug in the compilers that causes them to 278 * generate \ for continuations with just -g (this is 279 * ok), and \\ for continuations with -g -O (this is 280 * broken). This bug is "fixed" in the 6.2 compilers 281 * via the elimination of continuation stabs. 282 */ 283 if (str[strlen(str) - 2] == '\\') 284 offset = 2; 285 fstr = concat(fstr, str, offset); 286 continue; 287 } else 288 fstr = concat(fstr, str, 0); 289 290 debug(3, "%4d: .stabs \"%s\", %#x, %d, %hd, %d (from %s)\n", i, 291 fstr, stab->n_type, 0, stab->n_desc, 292 stab->n_value, curhdr); 293 294 if (debug_level >= 3) 295 check_hash(); 296 297 /* 298 * Sometimes the compiler stutters, and emits the same stab 299 * twice. This is bad for the parser, which will attempt to 300 * redefine the type IDs indicated in the stabs. This is 301 * compiler bug 4433511. 302 */ 303 if (ofstr && strcmp(fstr, ofstr) == 0) { 304 debug(3, "Stutter stab\n"); 305 free(fstr); 306 fstr = NULL; 307 continue; 308 } 309 310 if (ofstr) 311 free(ofstr); 312 ofstr = fstr; 313 314 iidescp = NULL; 315 if ((rc = parse_stab(stab, fstr, &iidescp)) < 0) 316 terminate("Couldn't parse stab \"%s\" (file %s)\n", 317 str, curhdr); 318 if (rc == 0) 319 goto parse_loop_end; 320 321 /* Make sure the scope tracking is working correctly */ 322 assert(stab->n_type != N_FUN || (iidescp->ii_type != II_GFUN && 323 iidescp->ii_type != II_SFUN) || scope == 0); 324 325 /* 326 * The only things we care about that are in local scope are 327 * the N_PSYM stabs. 328 */ 329 if (scope && stab->n_type != N_PSYM) { 330 if (iidescp) 331 iidesc_free(iidescp, NULL); 332 goto parse_loop_end; 333 } 334 335 switch (iidescp->ii_type) { 336 case II_SFUN: 337 iidescp->ii_owner = xstrdup(curfile); 338 /*FALLTHROUGH*/ 339 case II_GFUN: 340 curfun = iidescp; 341 fnarg_free(iidescp); 342 iidesc_add(td->td_iihash, iidescp); 343 break; 344 345 case II_SVAR: 346 iidescp->ii_owner = xstrdup(curfile); 347 /*FALLTHROUGH*/ 348 case II_GVAR: 349 case II_TYPE: 350 case II_SOU: 351 iidesc_add(td->td_iihash, iidescp); 352 break; 353 354 case II_PSYM: 355 fnarg_add(curfun, iidescp); 356 iidesc_free(iidescp, NULL); 357 break; 358 default: 359 terminate("Unknown iidesc type %d\n", iidescp->ii_type); 360 } 361 362 parse_loop_end: 363 fstr = NULL; 364 } 365 366 if (ofstr) 367 free(ofstr); 368 369 resolve_nodes(td); 370 resolve_typed_bitfields(); 371 parse_finish(td); 372 373 cvt_fixbugs(td); 374 375 return (0); 376 } 377