diff options
author | Wez Furlong <wez@netevil.org> | 2011-04-03 14:37:41 -0400 |
---|---|---|
committer | Wez Furlong <wez@netevil.org> | 2011-04-03 14:37:41 -0400 |
commit | 253acb864d82ab0406d6a6bcecd09e502c64b140 (patch) | |
tree | 115e5562e80acc02e7329053f258cf1c0e3e1e38 /cvt/stabs.c | |
download | ctf-253acb864d82ab0406d6a6bcecd09e502c64b140.tar.gz |
Pull in the CTF sources from the FreeBSD 8.2 tree; arrange for them
to build under autoconf.
Diffstat (limited to 'cvt/stabs.c')
-rw-r--r-- | cvt/stabs.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/cvt/stabs.c b/cvt/stabs.c new file mode 100644 index 0000000..86a106f --- /dev/null +++ b/cvt/stabs.c @@ -0,0 +1,371 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines used to read stabs data from a file, and to build a tdata structure + * based on the interesting parts of that data. + */ + +#include "libctf/ctf_impl.h" +#include "ctftools.h" +#include "common/list.h" +#include "stack.h" +#include "memory.h" +#include "traverse.h" + +char *curhdr; + +/* + * The stabs generator will sometimes reference types before they've been + * defined. If this is the case, a TYPEDEF_UNRES tdesc will be generated. + * Note that this is different from a forward declaration, in which the + * stab is defined, but is defined as something that doesn't exist yet. + * When we have read all of the stabs from the file, we can go back and + * fix up all of the unresolved types. We should be able to fix all of them. + */ +/*ARGSUSED2*/ +static int +resolve_tou_node(tdesc_t *node, tdesc_t **nodep, void *private __unused) +{ + tdesc_t *new; + + debug(3, "Trying to resolve %s (%d)\n", tdesc_name(node), node->t_id); + new = lookup(node->t_id); + + if (new == NULL) { + terminate("Couldn't resolve type %d\n", node->t_id); + } + + debug(3, " Resolving to %d\n", new->t_id); + + *nodep = new; + + return (1); +} + +/*ARGSUSED*/ +static int +resolve_fwd_node(tdesc_t *node, tdesc_t **nodep, void *private __unused) +{ + tdesc_t *new = lookupname(node->t_name); + + debug(3, "Trying to unforward %s (%d)\n", tdesc_name(node), node->t_id); + + if (!new || (new->t_type != STRUCT && new->t_type != UNION)) + return (0); + + debug(3, " Unforwarded to %d\n", new->t_id); + + *nodep = new; + + return (1); +} + +static tdtrav_cb_f resolve_cbs[] = { + NULL, + NULL, /* intrinsic */ + NULL, /* pointer */ + NULL, /* array */ + NULL, /* function */ + NULL, /* struct */ + NULL, /* union */ + NULL, /* enum */ + resolve_fwd_node, /* forward */ + NULL, /* typedef */ + resolve_tou_node, /* typedef unres */ + NULL, /* volatile */ + NULL, /* const */ + NULL, /* restrict */ +}; + +static void +resolve_nodes(tdata_t *td) +{ + debug(2, "Resolving unresolved stabs\n"); + + (void) iitraverse_hash(td->td_iihash, &td->td_curvgen, resolve_cbs, + NULL, NULL, td); +} + +static char * +concat(char *s1, char *s2, int s2strip) +{ + int savelen = strlen(s2) - s2strip; + int newlen = (s1 ? strlen(s1) : 0) + savelen + 1; + char *out; + + out = xrealloc(s1, newlen); + if (s1) + strncpy(out + strlen(out), s2, savelen); + else + strncpy(out, s2, savelen); + + out[newlen - 1] = '\0'; + + return (out); +} + +/* + * N_FUN stabs come with their arguments in promoted form. In order to get the + * actual arguments, we need to wait for the N_PSYM stabs that will come towards + * the end of the function. These routines free the arguments (fnarg_free) we + * got from the N_FUN stab and add (fnarg_add) the ones from the N_PSYM stabs. + */ +static void +fnarg_add(iidesc_t *curfun, iidesc_t *arg) +{ + curfun->ii_nargs++; + + if (curfun->ii_nargs == 1) + curfun->ii_args = xmalloc(sizeof (tdesc_t *) * FUNCARG_DEF); + else if (curfun->ii_nargs > FUNCARG_DEF) { + curfun->ii_args = xrealloc(curfun->ii_args, + sizeof (tdesc_t *) * curfun->ii_nargs); + } + + curfun->ii_args[curfun->ii_nargs - 1] = arg->ii_dtype; + arg->ii_dtype = NULL; +} + +static void +fnarg_free(iidesc_t *ii) +{ + ii->ii_nargs = 0; + free(ii->ii_args); + ii->ii_args = NULL; +} + +/* + * Read the stabs from the stab ELF section, and turn them into a tdesc tree, + * assembled under an iidesc list. + */ +int +stabs_read(tdata_t *td, Elf *elf, char *file) +{ + Elf_Scn *scn; + Elf_Data *data; + stab_t *stab; + stk_t *file_stack; + iidesc_t *iidescp; + iidesc_t *curfun = NULL; + char curpath[MAXPATHLEN]; + char *curfile = NULL; + char *str; + char *fstr = NULL, *ofstr = NULL; + int stabidx, stabstridx; + int nstabs, rc, i; + int scope = 0; + + if (!((stabidx = findelfsecidx(elf, file, ".stab.excl")) >= 0 && + (stabstridx = findelfsecidx(elf, file, ".stab.exclstr")) >= 0) && + !((stabidx = findelfsecidx(elf, file, ".stab")) >= 0 && + (stabstridx = findelfsecidx(elf, file, ".stabstr")) >= 0)) { + errno = ENOENT; + return (-1); + } + + file_stack = stack_new(free); + + stack_push(file_stack, file); + curhdr = file; + + debug(3, "Found stabs in %d, strings in %d\n", stabidx, stabstridx); + + scn = elf_getscn(elf, stabidx); + data = elf_rawdata(scn, NULL); + nstabs = data->d_size / sizeof (stab_t); + + parse_init(td); + for (i = 0; i < nstabs; i++) { + stab = &((stab_t *)data->d_buf)[i]; + + /* We don't want any local definitions */ + if (stab->n_type == N_LBRAC) { + scope++; + debug(3, "stab %d: opening scope (%d)\n", i + 1, scope); + continue; + } else if (stab->n_type == N_RBRAC) { + scope--; + debug(3, "stab %d: closing scope (%d)\n", i + 1, scope); + continue; + } else if (stab->n_type == N_EINCL) { + /* + * There's a bug in the 5.2 (Taz) compilers that causes + * them to emit an extra N_EINCL if there's no actual + * text in the file being compiled. To work around this + * bug, we explicitly check to make sure we're not + * trying to pop a stack that only has the outer scope + * on it. + */ + if (stack_level(file_stack) != 1) { + str = (char *)stack_pop(file_stack); + free(str); + curhdr = (char *)stack_peek(file_stack); + } + } + + /* We only care about a subset of the stabs */ + if (!(stab->n_type == N_FUN || stab->n_type == N_GSYM || + stab->n_type == N_LCSYM || stab->n_type == N_LSYM || + stab->n_type == N_PSYM || stab->n_type == N_ROSYM || + stab->n_type == N_RSYM || + stab->n_type == N_STSYM || stab->n_type == N_BINCL || + stab->n_type == N_SO || stab->n_type == N_OPT)) + continue; + + if ((str = elf_strptr(elf, stabstridx, + (size_t)stab->n_strx)) == NULL) { + terminate("%s: Can't find string at %u for stab %d\n", + file, stab->n_strx, i); + } + + if (stab->n_type == N_BINCL) { + curhdr = xstrdup(str); + stack_push(file_stack, curhdr); + continue; + } else if (stab->n_type == N_SO) { + if (str[strlen(str) - 1] != '/') { + strcpy(curpath, str); + curfile = basename(curpath); + } + continue; + } else if (stab->n_type == N_OPT) { + if (strcmp(str, "gcc2_compiled.") == 0) { + terminate("%s: GCC-generated stabs are " + "unsupported. Use DWARF instead.\n", file); + } + continue; + } + + if (str[strlen(str) - 1] == '\\') { + int offset = 1; + /* + * There's a bug in the compilers that causes them to + * generate \ for continuations with just -g (this is + * ok), and \\ for continuations with -g -O (this is + * broken). This bug is "fixed" in the 6.2 compilers + * via the elimination of continuation stabs. + */ + if (str[strlen(str) - 2] == '\\') + offset = 2; + fstr = concat(fstr, str, offset); + continue; + } else + fstr = concat(fstr, str, 0); + + debug(3, "%4d: .stabs \"%s\", %#x, %d, %hd, %d (from %s)\n", i, + fstr, stab->n_type, 0, stab->n_desc, + stab->n_value, curhdr); + + if (debug_level >= 3) + check_hash(); + + /* + * Sometimes the compiler stutters, and emits the same stab + * twice. This is bad for the parser, which will attempt to + * redefine the type IDs indicated in the stabs. This is + * compiler bug 4433511. + */ + if (ofstr && strcmp(fstr, ofstr) == 0) { + debug(3, "Stutter stab\n"); + free(fstr); + fstr = NULL; + continue; + } + + if (ofstr) + free(ofstr); + ofstr = fstr; + + iidescp = NULL; + + if ((rc = parse_stab(stab, fstr, &iidescp)) < 0) { + terminate("%s: Couldn't parse stab \"%s\" " + "(source file %s)\n", file, str, curhdr); + } + + if (rc == 0) + goto parse_loop_end; + + /* Make sure the scope tracking is working correctly */ + assert(stab->n_type != N_FUN || (iidescp->ii_type != II_GFUN && + iidescp->ii_type != II_SFUN) || scope == 0); + + /* + * The only things we care about that are in local scope are + * the N_PSYM stabs. + */ + if (scope && stab->n_type != N_PSYM) { + if (iidescp) + iidesc_free(iidescp, NULL); + goto parse_loop_end; + } + + switch (iidescp->ii_type) { + case II_SFUN: + iidescp->ii_owner = xstrdup(curfile); + /*FALLTHROUGH*/ + case II_GFUN: + curfun = iidescp; + fnarg_free(iidescp); + iidesc_add(td->td_iihash, iidescp); + break; + + case II_SVAR: + iidescp->ii_owner = xstrdup(curfile); + /*FALLTHROUGH*/ + case II_GVAR: + case II_TYPE: + case II_SOU: + iidesc_add(td->td_iihash, iidescp); + break; + + case II_PSYM: + fnarg_add(curfun, iidescp); + iidesc_free(iidescp, NULL); + break; + default: + aborterr("invalid ii_type %d for stab type %d", + iidescp->ii_type, stab->n_type); + } + +parse_loop_end: + fstr = NULL; + } + + if (ofstr) + free(ofstr); + + resolve_nodes(td); + resolve_typed_bitfields(); + parse_finish(td); + + cvt_fixstabs(td); + cvt_fixups(td, elf_ptrsz(elf)); + + return (0); +} |