/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 (c) 1997-1999 by Sun Microsystems, Inc. * All rights reserved. */ #include #include #include #include #include "parser.h" #include "trace.h" #include "util.h" #include "symtab.h" #include "errlog.h" /* Types */ enum kind_t { PRIMITIVE = 0, COMPOSITE, VARARG }; struct entry_t { char *e_name; int e_valid; int e_line; char *e_file; int e_kind; /* PRIMITIVE, COMPOSITE... */ char *e_type; /* where kind == PRIMITIVE */ /* base type, ie. char if e_type is char */ char *e_basetype; int e_levels; /* levels of indirection */ char *e_attribute; /* kind == COMPOSITE or VARARG. */ char *e_assertion; /* reserved for kind == VARARG. */ char *e_comment; /* reserved for per-element comments. */ int e_pre_uses; int e_post_uses; }; typedef struct entry_head_t { int used; int n_entries; ENTRY entry[1]; /* Actually entry[n_entries]. */ } EHEAD; static struct symtab_t { ENTRY *Function; EHEAD *Args; EHEAD *Varargs; EHEAD *Globals; ENTRY *Errval; /* Includes */ table_t *Includes; /* Bindings */ ENTRY *Exception; /* Types */ table_t *Print_Types; /* Error-message information. */ int Line; char Filename[MAXLINE]; /* Trace additions */ char Prototype[MAXLINE]; char Formals[MAXLINE]; char Actuals[MAXLINE]; char Cast[MAXLINE]; int Nonreturn; int Skip; /* Adl additions */ /* various assertions, one hopes */ } Symtab; /* File Globals. */ static EHEAD *create_entry_table(int); static EHEAD *add_entry_table(EHEAD *, char *, int, char *, int, char *, char *, int, char *, int, int); static ENTRY *get_entry_table(EHEAD *, int); static EHEAD *free_entry_table(EHEAD *); static void clear_entries(EHEAD *, int, int); static ENTRY *allocate_entry(ENTRY *, char *, int, char *, int, char *, char *, int, char *, int, int); static ENTRY *set_entry(ENTRY *, char *, int, char *, int, char *, char *, int, char *, int, int); static ENTRY *free_entry(ENTRY *); static void symtab_clear_varargs(void); static void symtab_clear_globals(void); static void symtab_clear_print_types(void); static void symtab_set_nonreturn(int); static table_t *symtab_free_print_types(table_t *); /* * symtab_new_function -- clear counts, variables for a new function. */ void symtab_new_function(const int line, const char *file) { errlog(BEGIN, "symtab_new_function() {"); Symtab.Line = line; /* Set, don't clear. */ symtab_set_filename(file); symtab_clear_function(); symtab_clear_varargs(); symtab_clear_globals(); symtab_clear_errval(); symtab_clear_exception(); symtab_clear_print_types(); symtab_set_nonreturn(NO); symtab_set_skip(NO); errlog(END, "}"); } /* * symtab_clear_function -- clear function-prototype-derived * values. Called on each prototype line and at beginning * of interface. */ void symtab_clear_function(void) { errlog(BEGIN, "symtab_clear_function() {"); Symtab.Function = free_entry(Symtab.Function); Symtab.Args = free_entry_table(Symtab.Args); Symtab.Prototype[0] = '\0'; Symtab.Formals[0] = '\0'; Symtab.Actuals[0] = '\0'; Symtab.Cast[0] = '\0'; errlog(END, "}"); } /* * symtab_clear_varargs -- called only at end */ static void symtab_clear_varargs(void) { errlog(BEGIN, "symtab_clear_varargs() {"); Symtab.Varargs = free_entry_table(Symtab.Varargs); errlog(END, "}"); } /* * symtab_clear_includes -- clear only at end of file (union++) */ void symtab_clear_includes(void) { errlog(BEGIN, "symtab_clear_includes() {"); Symtab.Includes = free_string_table(Symtab.Includes); errlog(END, "}"); } static void symtab_clear_globals(void) { errlog(BEGIN, "symtab_clear_globals() {"); Symtab.Globals = free_entry_table(Symtab.Globals); errlog(END, "}"); } void symtab_clear_errval(void) { errlog(BEGIN, "symtab_clear_errval() {"); Symtab.Errval = free_entry(Symtab.Errval); errlog(END, "}"); } void symtab_clear_exception(void) { errlog(BEGIN, "symtab_clear_exception() {"); Symtab.Exception = free_entry(Symtab.Exception); errlog(END, "}"); } static void symtab_clear_print_types(void) { errlog(BEGIN, "symtab_clear_print_types() {"); Symtab.Print_Types = symtab_free_print_types(Symtab.Print_Types); errlog(END, "}"); } /* Generated by m4 -- character string values */ void symtab_set_prototype(char *p) { errlog(BEGIN, "symtab_set_prototype(void) {"); (void) strncpy(Symtab.Prototype, p, sizeof (Symtab.Prototype)); Symtab.Prototype[sizeof (Symtab.Prototype)-1] = '\0'; errlog(END, "}"); } char * symtab_get_prototype(void) { errlog(BEGIN, "symtab_get_prototype() {"); errlog(END, "}"); return (Symtab.Prototype); } void symtab_set_formals(char *p) { errlog(BEGIN, "symtab_set_formals() {"); errlog(VERBOSE, "p = %s", p); (void) strncpy(Symtab.Formals, p, sizeof (Symtab.Formals)); Symtab.Formals[sizeof (Symtab.Formals)-1] = '\0'; errlog(END, "}"); } char * symtab_get_formals(void) { errlog(BEGIN, "symtab_get_formals() {"); errlog(END, "}"); return (Symtab.Formals); } void symtab_set_actuals(char *p) { errlog(BEGIN, "symtab_set_actuals() {"); errlog(END, "}"); errlog(VERBOSE, "p = %s", p); (void) strncpy(Symtab.Actuals, p, sizeof (Symtab.Actuals)); Symtab.Actuals[sizeof (Symtab.Actuals)-1] = '\0'; } char * symtab_get_actuals(void) { errlog(BEGIN, "symtab_get_actuals() {"); errlog(END, "}"); return (Symtab.Actuals); } void symtab_set_cast(char *p) { errlog(BEGIN, "symtab_set_cast() {"); errlog(END, "}"); (void) strncpy(Symtab.Cast, p, sizeof (Symtab.Cast)); Symtab.Cast[sizeof (Symtab.Cast)-1] = '\0'; } char * symtab_get_cast(void) { errlog(BEGIN, "symtab_get_cast() {"); errlog(END, "}"); return (Symtab.Cast); } void symtab_set_filename(const char *p) { errlog(BEGIN, "symtab_set_filename() {"); errlog(END, "}"); (void) strncpy(Symtab.Filename, p, sizeof (Symtab.Filename)); Symtab.Filename[sizeof (Symtab.Filename)-1] = '\0'; } char * symtab_get_filename(void) { errlog(BEGIN, "symtab_get_filename() {"); errlog(END, "}"); return (Symtab.Filename); } /* Generated by m4 -- int values */ static void symtab_set_nonreturn(int val) { errlog(BEGIN, "symtab_set_nonreturn() {"); errlog(END, "}"); Symtab.Nonreturn = val; } int symtab_get_nonreturn(void) { errlog(BEGIN, "symtab_get_nonreturn() {"); errlog(END, "}"); return (Symtab.Nonreturn); } void symtab_set_line(int val) { errlog(BEGIN, "symtab_set_line() {"); errlog(END, "}"); Symtab.Line = val; } int symtab_get_line(void) { errlog(BEGIN, "symtab_get_line() {"); errlog(END, "}"); return (Symtab.Line); } void symtab_set_skip(int value) { errlog(BEGIN, "symtab_set_skip() {"); errlog(END, "}"); Symtab.Skip = value; } int symtab_get_skip(void) { errlog(BEGIN, "symtab_get_skip() {"); errlog(END, "}"); return (Symtab.Skip); } /* * Manually written access functions for ENTRY * variables. */ void symtab_set_function(char *name, int line, char *file, char *type, char *basetype, int levels) { errlog(BEGIN, "symtab_set_function() {"); Symtab.Function = allocate_entry(Symtab.Function, name, line, file, PRIMITIVE, type, basetype, levels, "", -1, -1); errlog(END, "}"); } ENTRY * symtab_get_function(void) { errlog(BEGIN, "symtab_get_function() {"); errlog(END, "}"); if (Symtab.Function == NULL) return (NULL); else return ((Symtab.Function->e_valid)? Symtab.Function: NULL); } void symtab_set_exception(char *value, int line, char *file) { errlog(BEGIN, "symtab_set_exception() {"); Symtab.Exception = allocate_entry(Symtab.Exception, value, line, file, COMPOSITE, "", "", 0, "", -1, -1); errlog(END, "}"); } ENTRY * symtab_get_exception(void) { errlog(BEGIN, "symtab_get_exception() {"); errlog(END, "}"); if (Symtab.Exception == NULL) return (NULL); else return ((Symtab.Exception->e_valid)? Symtab.Exception: NULL); } void symtab_set_errval(char *name, int line, char *file, char *type, char *basetype, int levels) { errlog(BEGIN, "symtab_set_errval() {"); Symtab.Errval = allocate_entry(Symtab.Errval, name, line, file, PRIMITIVE, type, basetype, levels, "", -1, -1); errlog(END, "}"); } ENTRY * symtab_get_errval(void) { errlog(BEGIN, "symtab_get_errval() {"); errlog(END, "}"); if (Symtab.Errval == NULL) return (NULL); else return ((Symtab.Errval->e_valid)? Symtab.Errval: NULL); } /* * Manually written access function for tables of ENTRYs */ void symtab_add_args(char *name, int line, char *file, char *type, char *basetype, int levels) { errlog(BEGIN, "symtab_add_args() {"); if (Symtab.Args == NULL) { Symtab.Args = create_entry_table(10); } Symtab.Args = add_entry_table(Symtab.Args, name, line, file, PRIMITIVE, type, basetype, levels, "", -1, -1); errlog(END, "}"); } static int curr_arg; ENTRY * symtab_get_first_arg(void) { errlog(BEGIN, "symtab_get_first_arg() {"); errlog(END, "}"); curr_arg = 1; return (get_entry_table(Symtab.Args, 0)); } ENTRY * symtab_get_next_arg(void) { errlog(BEGIN, "symtab_get_next_arg() {"); errlog(END, "}"); return (get_entry_table(Symtab.Args, curr_arg++)); } ENTRY * symtab_get_last_arg(void) { errlog(BEGIN, "symtab_get_last_arg() {"); errlog(END, "}"); return (get_entry_table(Symtab.Args, Symtab.Args->used)); } void symtab_add_varargs(char *name, int line, char *file, char *type, char *print) { errlog(BEGIN, "symtab_add_varargs() {"); if (Symtab.Varargs == NULL) { Symtab.Varargs = create_entry_table(10); } Symtab.Varargs = add_entry_table(Symtab.Varargs, name, line, file, PRIMITIVE, type, print, 0, "", -1, -1); errlog(END, "}"); } static int curr_vararg; ENTRY * symtab_get_first_vararg(void) { errlog(BEGIN, "symtab_get_first_vararg() {"); errlog(END, "}"); curr_vararg = 1; return (get_entry_table(Symtab.Varargs, 0)); } ENTRY * symtab_get_next_vararg(void) { errlog(BEGIN, "symtab_get_next_vararg() {"); errlog(END, "}"); return (get_entry_table(Symtab.Varargs, curr_vararg++)); } void symtab_add_globals(char *name, int line, char *file, char *type, char *basetype, int levels) { errlog(BEGIN, "symtab_add_globals() {"); if (Symtab.Globals == NULL) { Symtab.Globals = create_entry_table(10); } Symtab.Globals = add_entry_table(Symtab.Globals, name, line, file, PRIMITIVE, type, basetype, levels, "", -1, -1); errlog(END, "}"); } static int curr_global; ENTRY * symtab_get_first_global(void) { errlog(BEGIN, "symtab_get_first_global() {"); errlog(END, "}"); curr_global = 1; return (get_entry_table(Symtab.Globals, 0)); } ENTRY * symtab_get_next_global(void) { errlog(BEGIN, "symtab_get_next_global() {"); errlog(END, "}"); return (get_entry_table(Symtab.Globals, curr_global++)); } /* * manually written functions for accessing tables of strings */ /* * symtab_add_print_types -- add only non-void print types (due to * parser errors in collect.c, yuck). Also note trick compare... * TBD : common code in db, symtab needs to be * pulled out, as they're getting out of sync. */ void symtab_add_print_types(char *print_type, char *c_type) { char buffer[MAXLINE]; errlog(BEGIN, "symtab_add_print_types() {"); #ifdef notdef if (strcmp(print_type, "void") == 0 || *print_type == NULL) { errlog(END, "}"); return; } #endif (void) snprintf(buffer, sizeof (buffer), "%s, %s", print_type, c_type); if (Symtab.Print_Types == NULL) { Symtab.Print_Types = create_string_table(50); } if (in_string_table(Symtab.Print_Types, print_type) == NO) { Symtab.Print_Types = add_string_table(Symtab.Print_Types, &buffer[0]); } errlog(END, "}"); } static table_t * symtab_free_print_types(table_t *t) { errlog(BEGIN, "symtab_free_print_types() {"); errlog(END, "}"); return (free_string_table(t)); } static int curr_print_type; char * symtab_get_first_print_type(void) { errlog(BEGIN, "symtab_get_first_print_type() {"); errlog(END, "}"); curr_print_type = 1; return (get_string_table(Symtab.Print_Types, 0)); } char * symtab_get_next_print_type(void) { errlog(BEGIN, "symtab_get_next_print_type() {"); errlog(END, "}"); return (get_string_table(Symtab.Print_Types, curr_print_type++)); } void symtab_add_includes(char *value) { errlog(BEGIN, "symtab_add_includes() {"); if (Symtab.Includes == NULL) { Symtab.Includes = create_string_table(50); } if (in_string_table(Symtab.Includes, value) == NO) { Symtab.Includes = add_string_table(Symtab.Includes, value); } errlog(END, "}"); } static int curr_include; char * symtab_get_first_include(void) { errlog(BEGIN, "symtab_get_first_include() {"); errlog(END, "}"); curr_include = 1; return (get_string_table(Symtab.Includes, 0)); } char * symtab_get_next_include(void) { errlog(BEGIN, "symtab_get_next_include() {"); errlog(END, "}"); return (get_string_table(Symtab.Includes, curr_include++)); } void symtab_sort_includes(void) { errlog(BEGIN, "symtab_sort_includes() {"); sort_string_table(Symtab.Includes); errlog(END, "}"); } /* * ENTRYs -- access functions to contents of an entry. */ char * name_of(ENTRY *e) { return (e->e_name); } int validity_of(ENTRY *e) { if (e == NULL) return (NO); else return (e->e_valid); } int line_of(ENTRY *e) { return (e->e_line); } char * file_of(ENTRY *e) { return (e->e_file); } /* * x_type_of -- return (type with an extension: an embedded %s where * the name goes. */ char * x_type_of(ENTRY *e) { if (e != NULL && (e->e_kind == PRIMITIVE || e->e_kind == VARARG)) return (e->e_type); else return (NULL); } /* * type_of -- return (just the type, with the %s removed. This is the common * case, and its also the slowest... TBD. */ char * type_of(ENTRY *e) { static char buffer[MAXLINE]; char *p, *q; if (e != NULL && (e->e_kind == PRIMITIVE || e->e_kind == VARARG)) { p = e->e_type; q = &buffer[0]; while (*p != '\0') { if (*p == '%') { p += 2; } else { *q++ = *p++; } } *q = '\0'; return (strtrim(&buffer[0])); } else return (NULL); } char * basetype_of(ENTRY *e) { if (e != NULL && (e->e_kind == PRIMITIVE || e->e_kind == VARARG)) return (e->e_basetype); else return (NULL); } int levels_of(ENTRY *e) { if (e != NULL && (e->e_kind == PRIMITIVE || e->e_kind == VARARG)) return (e->e_levels); else return (0); } char * inverse_of(ENTRY *e) { if (e != NULL && e->e_kind == COMPOSITE) return (e->e_attribute); else return (NULL); } char * selector_of(ENTRY *e) { if (e != NULL && e->e_kind == VARARG) return (e->e_attribute); else return (NULL); } int preuses_of(ENTRY *e) { if (e) return (e->e_pre_uses); else return (-1); } int postuses_of(ENTRY *e) { if (e) return (e->e_post_uses); else return (-1); } /* * allocate_entry -- make a parameter list into a complete * ENTRY struct, allocated dynamically. */ /* ARGSUSED -- lint bug */ static ENTRY * allocate_entry(ENTRY *e, char *name, int line, char *file, int kind, char *type, char *basetype, int levels, char *attribute, int npre, int npost) { errlog(BEGIN, "allocate_entry() {"); if (e == NULL) { if ((e = (ENTRY *)calloc(1, sizeof (ENTRY))) == NULL) { errlog(FATAL, "can't allocate space for an ENTRY"); } } errlog(END, "}"); return (set_entry(e, name, line, file, kind, type, basetype, levels, attribute, npre, npost)); } /* * set_entry -- set a passed-in entry, using * passed parameters, to values suitable for a * symtab entry */ static ENTRY * set_entry(ENTRY *e, char *name, int line, char *file, int kind, char *type, char *basetype, int levels, char *attribute, int npre, int npost) { errlog(BEGIN, "set_entry() {"); if (e == NULL) { errlog(FATAL, "programmer error: passed a NULL ENTRY"); } e->e_name = strset(e->e_name, name); e->e_valid = YES; e->e_line = line, e->e_file = strset(e->e_file, file); e->e_kind = kind; switch (kind) { case PRIMITIVE: e->e_type = strset(e->e_type, type); e->e_basetype = strset(e->e_basetype, basetype); e->e_levels = levels; break; case COMPOSITE: e->e_attribute = strset(e->e_attribute, attribute); break; case VARARG: e->e_attribute = strset(e->e_attribute, attribute); break; default: errlog(FATAL, "programmer error: impossible kind of ENTRY"); } e->e_pre_uses = npre; e->e_post_uses = npost; errlog(END, "}"); return (e); } /* * free_entry -- really just mark an entry as invalid */ static ENTRY * free_entry(ENTRY *e) { if (e != NULL) e->e_valid = NO; return (e); } /* * ENTRY tables. */ #define ENTRY_INCREMENT 10 static EHEAD * create_entry_table(int n) { EHEAD *p; errlog(BEGIN, "create_entry_table() {"); if ((p = (EHEAD *)calloc(1, sizeof (EHEAD)+(n*sizeof (ENTRY)))) == NULL) { errlog(FATAL, "can't allocate space for an ENTRY table"); } p->used = -1; p->n_entries = n; errlog(END, "}"); return (p); } static EHEAD * add_entry_table(EHEAD *t, char *name, int line, char *file, int kind, char *type, char *basetype, int levels, char *attribute, int npre, int npost) { EHEAD *t2; errlog(BEGIN, "add_entry_table() {"); if (t == NULL) { errlog(FATAL, "programmer error: tried to add to NULL EHEAD"); } t->used++; if (t->used >= t->n_entries) { if ((t2 = (EHEAD *)realloc(t, sizeof (EHEAD)+(sizeof (ENTRY)* (t->n_entries+ENTRY_INCREMENT)))) == NULL) { errlog(FATAL, "out of memory extending an EHEAD"); } t = t2; clear_entries(t, t->n_entries, (t->n_entries+ENTRY_INCREMENT)); t->n_entries += ENTRY_INCREMENT; } (void) set_entry(&t->entry[t->used], name, line, file, kind, type, basetype, levels, attribute, npre, npost); errlog(END, "}"); return (t); } static ENTRY * get_entry_table(EHEAD *t, int index) { if (t == NULL) { return (NULL); } else if (index > t->used) { return (NULL); } else { return (&(t->entry[index])); } } static EHEAD * free_entry_table(EHEAD *t) { if (t != NULL) t->used = -1; return (t); } static void clear_entries(EHEAD *t, int start, int end) { int i; for (i = start; i < end; i++) { (void) memset(&t->entry[i], 0, sizeof (ENTRY)); } }