/* $Id$ */ /* Symbol table reader */ { #include #include #include #include "position.h" #include "file.h" #include "type.h" #include "symbol.h" #include "scope.h" #include "class.h" #include "idf.h" #include "rd.h" #include "misc.h" extern char *strchr(); extern long str2long(); extern double atof(); static char *DbPtr; /* current pointer in db string */ static int AllowName; /* set if NAME legal at this point */ static long ival; static double fval; static char *strval; static int last_index[2]; static struct outname *currnam; static int saw_code; static struct literal *get_literal_space(); static struct fields *get_field_space(); static end_field(); static char *string_val(); } %start DbParser, debugger_string; %prefix DBS; %lexical DBSlex; %onerror DBSonerror; %token INTEGER, REAL, STRING, NAME; debugger_string { register p_symbol s; char *str; p_type tmp = 0; int upb = 0; } : name(&str) [ /* constant name */ { s = NewSymbol(str, CurrentScope, CONST, currnam); } 'c' const_name(s) | /* type name */ { s = NewSymbol(str, CurrentScope, TYPE, currnam); } 't' type_name(&(s->sy_type), s) { if (! s->sy_type->ty_sym) s->sy_type->ty_sym = s; if ((s->sy_type->ty_class == T_ENUM || s->sy_type->ty_class == T_SUBRANGE) && currnam->on_desc != 0) { s->sy_type->ty_size = currnam->on_desc; } } | /* tag name (only C?) */ { s = NewSymbol(str, CurrentScope, TAG, currnam); } 'T' type_name(&(s->sy_type), s) { if (! s->sy_type->ty_sym) s->sy_type->ty_sym = s; if (s->sy_type->ty_class != T_CROSS) { resolve_cross(s->sy_type); } } | /* end scope */ 'E' INTEGER { close_scope(); } | /* module begin */ { s = NewSymbol(str, CurrentScope, MODULE, currnam); } 'M' INTEGER { open_scope(s, 1); s->sy_name.nm_scope = CurrentScope; CurrentScope->sc_start = currnam->on_valu; CurrentScope->sc_proclevel = currnam->on_desc; add_scope_addr(CurrentScope); } | /* external procedure */ { s = NewSymbol(str, FileScope, PROC, currnam); } 'P' routine(s) | /* private procedure */ { s = NewSymbol(str, CurrentScope, PROC, currnam); } 'Q' routine(s) | /* external function */ { s = NewSymbol(str, FileScope, FUNCTION, currnam); } 'F' function(s) | /* private function */ { s = NewSymbol(str, CurrentScope, FUNCTION, currnam); } 'f' function(s) | /* global variable, external */ /* maybe we already know it; but we need the type information anyway for other types. */ { s = Lookup(findidf(str), FileScope, VAR); if (s) { tmp = s->sy_type; s->sy_type = 0; } else s = NewSymbol(str, FileScope, VAR, currnam); } 'G' type(&(s->sy_type), (int *) 0, s) { if (tmp) s->sy_type = tmp; } | /* static variable */ { s = NewSymbol(str, CurrentScope, VAR, currnam); } 'S' type(&(s->sy_type), (int *) 0, s) | /* static variable, local scope */ { s = NewSymbol(str, CurrentScope, VAR, currnam); } 'V' type(&(s->sy_type), (int *) 0, s) | /* register variable */ { s = NewSymbol(str, CurrentScope, REGVAR, currnam); } 'r' type(&(s->sy_type), (int *) 0, s) | /* value parameter */ { s = NewSymbol(str, CurrentScope, LOCVAR, currnam); } 'p' type(&(s->sy_type), (int *) 0, s) { add_param_type('p', s); } | /* value parameter but address passed */ { s = NewSymbol(str, CurrentScope, VARPAR, currnam); } 'i' type(&(s->sy_type), (int *) 0, s) { add_param_type('i', s); } | /* variable parameter */ { s = NewSymbol(str, CurrentScope, VARPAR, currnam); } 'v' type(&(s->sy_type), (int *) 0, s) { add_param_type('v', s); } | /* local variable */ { s = NewSymbol(str, CurrentScope, LOCVAR, currnam); } type_name(&(s->sy_type), s) | /* lower or upper bound of array descriptor */ [ 'A' { upb = LBOUND; } | 'Z' { upb = UBOUND; } ] [ ['p' | ] { s = NewSymbol(str, CurrentScope, LOCVAR, currnam); if (upb == UBOUND) add_param_type('Z', s); } | [ 'V' | 'S' ] { s = NewSymbol(str, CurrentScope, VAR, currnam); } ] type_name(&(s->sy_type), s) { p_symbol s1 = new_symbol(); *s1 = *s; s->sy_class = upb; s->sy_descr = s1; } | /* function result in Pascal; ignore ??? */ { s = NewSymbol(str, CurrentScope, LOCVAR, currnam); } 'X' type_name(&(s->sy_type), s) ] ';'? ; name(char **s;) : /* anything up to a ':' */ NAME { *s = strval; } ; const_name(p_symbol cst;) { int type_index[2]; long iconst; register char *p; } : '=' [ /* 'b' integer_const(&(cst->sy_const.co_ival)) /* boolean */ /* | */ 'c' integer_const(&(cst->sy_const.co_ival)) /* character */ { cst->sy_type = char_type; } | 'i' integer_const(&(cst->sy_const.co_ival)) /* integer */ { cst->sy_type = long_type; } | 'r' real_const(&(cst->sy_const.co_rval)) /* real */ { cst->sy_type = double_type; } | 's' string_const /* string */ { cst->sy_const.co_sval = string_val(strval); cst->sy_type = string_type; } | 'e' type_index(type_index) ',' integer_const(&(cst->sy_const.co_ival)) /* enumeration constant; * enumeration type, value */ { cst->sy_type = *tp_lookup(type_index); } | 'S' type_index(type_index) { cst->sy_type = *tp_lookup(type_index); cst->sy_const.co_setval = p = Malloc((unsigned) cst->sy_type->ty_size); } [ ',' integer_const(&iconst) { *p++ = iconst; } ]+ /* set constant: * settype, values of the bytes * in the set. */ ] ; integer_const(long *iconst;) { int sign = 0; } : [ '+' | '-' { sign = 1; } ]? INTEGER { *iconst = sign ? -ival : ival; } ; real_const(double *f;) { int sign = 0; } : [ '+' | '-' { sign = 1; } ]? REAL { *f = sign ? fval : -fval; } ; string_const : STRING /* has SINGLE quotes! */ ; type_name(p_type *t; p_symbol sy;) { int type_index[2]; p_type *p; } : type_index(type_index) { p = tp_lookup(type_index); } [ { if (*p && (*p)->ty_class != 0 && (*p)->ty_class != T_CROSS) { error("Redefining (%d,%d) %d", type_index[0], type_index[1], (*p)->ty_class); } } '=' type(p, type_index, sy) | { if (*t && ! *p) *p = *t; else if (*t) **t = **p; } ] { if (*p == 0) *p = new_type(); *t = *p; } ; type_index(int *type_index;) : [ INTEGER { type_index[0] = 0; type_index[1] = ival; } | '(' INTEGER { type_index[0] = ival; } ',' INTEGER { type_index[1] = ival; } ')' ] { last_index[0] = type_index[0]; last_index[1] = type_index[1]; } ; function(p_symbol p;) : { p->sy_type = new_type(); p->sy_type->ty_class = T_PROCEDURE; p->sy_type->ty_size = pointer_size; } type(&(p->sy_type->ty_retval), (int *) 0, (p_symbol) 0) { if (CurrentScope != FileScope && saw_code) { /* if saw_code is not set, it is a nested procedure */ close_scope(); } saw_code = 0; open_scope(p, 1); p->sy_name.nm_scope = CurrentScope; CurrentScope->sc_start = currnam->on_valu; add_scope_addr(CurrentScope); CurrentScope->sc_proclevel = currnam->on_desc; } ; routine(p_symbol p;) : { p->sy_type = new_type(); p->sy_type->ty_class = T_PROCEDURE; p->sy_type->ty_size = pointer_size; if (CurrentScope != FileScope && saw_code) { /* if saw_code is not set, it is a nested procedure */ close_scope(); } saw_code = 0; open_scope(p, 1); p->sy_name.nm_scope = CurrentScope; CurrentScope->sc_start = currnam->on_valu; add_scope_addr(CurrentScope); CurrentScope->sc_proclevel = currnam->on_desc; } INTEGER ';' type(&(p->sy_type->ty_retval), (int *) 0, (p_symbol) 0) ; type(p_type *ptp; int *type_index; p_symbol sy;) { register p_type tp = *ptp ? *ptp : new_type(); p_type t1 = 0, t2 = 0; long ic1, ic2; int A_used = 0; int tclass; int tp_index[2]; char *str; } : [ /* type cross reference */ /* these are used in C for references to a struct, union or * enum that has not been declared (yet) */ 'x' [ 's' /* struct */ { tclass = T_STRUCT; } | 'u' /* union */ { tclass = T_UNION; } | 'e' /* enum */ { tclass = T_ENUM; } ] { AllowName = 1; } name(&str) { sy = Lookfromscope(str2idf(str,0),TAG,CurrentScope); if (sy && (sy->sy_type->ty_class == tclass || sy->sy_type->ty_class == T_CROSS)) { if (tp != *ptp) free_type(tp); tp = sy->sy_type; } else { tp->ty_class = T_CROSS; tp->ty_size = tclass; sy = NewSymbol(str, CurrentScope, TAG, (struct outname *) 0); sy->sy_type = tp; } } | /* subrange */ /* the integer_const's represent the lower and the upper bound. * A subrange type defined as subrange of itself is an integer type. * If the second integer_const == 0, but the first is not, we * have a floating point type with size equal to the first * integer_const. * Upperbound -1 means unsigned int or unsigned long. */ 'r' type_index(tp_index) ';' [ 'A' integer_const(&ic1) { A_used = 1; } | integer_const(&ic1) ] ';' [ 'A' integer_const(&ic2) { A_used |= 2; } | integer_const(&ic2) | 'Z' integer_const(&ic2) { A_used |= 0200; } ] { if (tp != *ptp) free_type(tp); tp = subrange_type(A_used, tp_index, ic1, ic2, type_index); } | /* array; first type is bound type, next type * is element type */ 'a' type(&t1, (int *) 0, (p_symbol) 0) ';' type(&t2, (int *) 0, (p_symbol) 0) { if (tp != *ptp) free_type(tp); tp = array_type(t1, t2); } | /* structure type */ 's' { tp->ty_class = T_STRUCT; } structure_type(tp, sy) | /* union type */ 'u' { tp->ty_class = T_UNION; } structure_type(tp, sy) | /* enumeration type */ 'e' { tp->ty_class = T_ENUM; } enum_type(tp) | /* pointer type */ '*' { tp->ty_class = T_POINTER; tp->ty_size = pointer_size; } type(&(tp->ty_ptrto), (int *) 0, (p_symbol) 0) | /* function type */ 'f' { tp->ty_class = T_PROCEDURE; tp->ty_size = pointer_size; } type(&(tp->ty_retval), (int *) 0, (p_symbol) 0) /* [ %prefer ',' param_list(tp) | ] */ | /* procedure type */ 'Q' { tp->ty_class = T_PROCEDURE; tp->ty_size = pointer_size; } type(&(tp->ty_retval), (int *) 0, (p_symbol) 0) ',' param_list(tp) | /* another procedure type */ 'p' { tp->ty_class = T_PROCEDURE; tp->ty_size = pointer_size; tp->ty_retval = void_type; } param_list(tp) | /* set type */ /* the first integer_const represents the size in bytes, * the second one represents the low bound */ 'S' { tp->ty_class = T_SET; } type(&(tp->ty_setbase), (int *) 0, (p_symbol) 0) ';' [ integer_const(&(tp->ty_size)) ';' integer_const(&(tp->ty_setlow)) ';' | { set_bounds(tp); } ] | /* file type of Pascal */ 'L' { tp->ty_class = T_FILE; } type(&(tp->ty_fileof), (int *) 0, (p_symbol) 0) | type_name(ptp, (p_symbol) 0) { if (type_index && (*ptp)->ty_class == 0 && type_index[0] == last_index[0] && type_index[1] == last_index[1]) { **ptp = *void_type; if (*ptp != tp) free_type(tp); } tp = *ptp; } ] { if (*ptp && *ptp != tp) **ptp = *tp; else *ptp = tp; } ; structure_type(register p_type tp; p_symbol sy;) { register struct fields *fldp; char *str; } : integer_const(&(tp->ty_size)) /* size in bytes */ { open_scope(sy, 0); if (sy) sy->sy_name.nm_scope = CurrentScope; } [ name(&str) { fldp = get_field_space(tp, str); } type(&(fldp->fld_type), (int *) 0, (p_symbol) 0) ',' integer_const(&(fldp->fld_pos)) ',' /* offset in bits */ integer_const(&(fldp->fld_bitsize)) ';' /* size in bits */ ]* ';' { end_field(tp); close_scope(); } ; enum_type(register p_type tp;) { register struct literal *litp; long maxval = 0; register p_symbol s; } : [ { litp = get_literal_space(tp); } name(&(litp->lit_name)) integer_const(&(litp->lit_val)) ',' { if (maxval < litp->lit_val) maxval = litp->lit_val; AllowName = 1; s = NewSymbol(litp->lit_name, CurrentScope, CONST, (struct outname *) 0); s->sy_const.co_ival = litp->lit_val; s->sy_type = tp; } ]* ';' { end_literal(tp, maxval); } ; param_list(p_type t;) { register struct param *p; long iconst; } : integer_const(&iconst) ';' /* number of parameters */ { t->ty_nparams = iconst; t->ty_params = p = (struct param *) Malloc((unsigned)(t->ty_nparams * sizeof(struct param))); } [ [ 'p' { p->par_kind = 'p'; } | 'v' { p->par_kind = 'v'; } | 'i' { p->par_kind = 'i'; } ] { p->par_type = 0; } type(&(p->par_type), (int *) 0, (p_symbol) 0) ';' { p->par_off = t->ty_nbparams; t->ty_nbparams += param_size(p->par_type, p->par_kind); p++; } ]* ; { static char *db_string; static char *DbOldPtr; static struct outname * DbString(n) struct outname *n; { currnam = n; DbPtr = n->on_mptr; db_string = DbPtr; AllowName = 1; DbParser(); return currnam; } /*ARGSUSED*/ DBSmessage(n) { fatal("error in symbol table string \"%s\", DbPtr = \"%s\", DbOldPtr = \"%s\"", db_string, DbPtr, DbOldPtr); } DBSonerror(tk, p) int *p; { DbPtr = DbOldPtr; /* ??? if (DBSsymb < 0) { while (*p && *p != ';') p++; if (*p) DbPtr = ";"; return; } */ if (! tk) { while (*p && *p != NAME) p++; if (*p) { AllowName = 1; } } else if (tk == NAME) AllowName = 1; } DBSlex() { register char *cp = DbPtr; int allow_name = AllowName; register int c; AllowName = 0; DbOldPtr = cp; c = *cp; if (c == '\\' && *(cp+1) == '\0') { currnam++; cp = currnam->on_mptr; DbOldPtr = cp; c = *cp; } if (! c) { DbPtr = cp; return -1; } if ((! allow_name && is_token(c)) || c == ';') { DbPtr = cp+1; return c; } if (is_dig(c)) { int retval = INTEGER; while (++cp, is_dig(*cp)) /* nothing */; c = *cp; if (c == '.') { retval = REAL; while (++cp, is_dig(*cp)) /* nothing */; c = *cp; } if (c == 'e' || c == 'E') { char *oldcp = cp; cp++; c = *cp; if (c == '-' || c == '+') { cp++; c = *cp; } if (is_dig(c)) { retval = REAL; while (++cp, is_dig(*cp)) /* nothing */; } else cp = oldcp; } c = *cp; *cp = 0; if (retval == INTEGER) { ival = str2long(DbOldPtr, 10); } else { fval = atof(DbOldPtr); } *cp = c; DbPtr = cp; return retval; } if (c == '\'') { cp++; strval = cp; while ((c = *cp) && c != '\'') { if (c == '\\') cp++; /* backslash escapes next character */ if (!(c = *cp)) break; /* but not a null byte */ cp++; } if (! c) DBSmessage(0); /* no return */ *cp = 0; DbPtr = cp + 1; return STRING; } strval = cp; while ((c = *cp) && c != ':' && c != ',') cp++; DbPtr = *cp ? cp+1 : cp; *cp = 0; return NAME; } static struct fields * get_field_space(tp, s) register p_type tp; char *s; { register struct fields *p; p_symbol sy; if (! (tp->ty_nfields & 07)) { tp->ty_fields = (struct fields *) Realloc((char *) tp->ty_fields, (tp->ty_nfields+8)*sizeof(struct fields)); } p = &tp->ty_fields[tp->ty_nfields++]; p->fld_name = s; p->fld_type = 0; sy = NewSymbol(s, CurrentScope, FIELD, currnam); sy->sy_field = p; return p; } static end_field(tp) register p_type tp; { tp->ty_fields = (struct fields *) Realloc((char *) tp->ty_fields, tp->ty_nfields * sizeof(struct fields)); } static struct literal * get_literal_space(tp) register p_type tp; { if (! (tp->ty_nenums & 07)) { tp->ty_literals = (struct literal *) Realloc((char *) tp->ty_literals, (tp->ty_nenums+8)*sizeof(struct literal)); } return &tp->ty_literals[tp->ty_nenums++]; } static char * string_val(s) char *s; { register char *ns = s, *os = s; register unsigned int i = 1; for (;;) { if (!*os) break; i++; if (*os == '\\') { os++; *ns++ = *os++; } else *ns++ = *os++; } *ns = '\0'; return Salloc(s, i); } static char *AckStrings; /* ACK a.out string table */ static struct outname *AckNames; /* ACK a.out symbol table entries */ static unsigned int NAckNames; /* Number of ACK symbol table entries */ static struct outname *EndAckNames; /* &AckNames[NAckNames] */ /* Read the symbol table from file 'f', which is supposed to be an ACK a.out format file. Offer db strings to the db string parser. */ int DbRead(f) char *f; { struct outhead h; register struct outname *n; register struct outname *line_file = 0; long OffsetStrings; int lbrac_required = 0; int needs_newscope = 0; int lbrac_level = 0; /* Open file, read header, and check magic word */ if (! rd_open(f)) { fatal("%s: could not open", f); } rd_ohead(&h); if (BADMAGIC(h) && h.oh_magic != O_CONVERTED) { fatal("%s: not an object file", f); } /* Allocate space for name table and read it */ AckNames = (struct outname *) Malloc((unsigned)(sizeof(struct outname) * h.oh_nname)); AckStrings = Malloc((unsigned) h.oh_nchar); rd_name(AckNames, h.oh_nname); rd_string(AckStrings, h.oh_nchar); /* Adjust file offsets in name table to point at strings */ OffsetStrings = OFF_CHAR(h); NAckNames = h.oh_nname; EndAckNames = &AckNames[h.oh_nname]; for (n = EndAckNames; --n >= AckNames;) { if (n->on_foff) { if ((unsigned)(n->on_foff - OffsetStrings) >= h.oh_nchar) { fatal("%s: error in object file", f); } n->on_mptr = AckStrings + (n->on_foff - OffsetStrings); } else n->on_mptr = 0; } /* Offer strings to the db string parser if they contain a ':'. Also offer filename-line number information to add_position_addr(). Here, the order may be important. */ for (n = &AckNames[0]; n < EndAckNames; n++) { int tp = n->on_type >> 8; register p_symbol sym; if (tp & (S_STB >> 8)) { switch(tp) { #ifdef N_BINCL case N_BINCL: n->on_valu = (long) line_file; line_file = n; break; case N_EINCL: if (line_file) { line_file = (struct outname *) line_file->on_valu; } break; #endif case N_SO: if (n->on_mptr[strlen(n->on_mptr)-1] == '/') { /* another N_SO follows ... */ break; } clean_tp_tab(); while (CurrentScope != PervasiveScope) { close_scope(); } saw_code = 0; sym = add_file(n->on_mptr); if (! listfile) newfile(sym->sy_idf); open_scope(sym, 0); sym->sy_file->f_scope = CurrentScope; FileScope = CurrentScope; CurrentScope->sc_start = n->on_valu; /* fall through */ case N_SOL: if (line_file) n->on_valu = line_file->on_valu; line_file = n; break; case N_MAIN: if (! FileScope) fatal("No file scope"); newfile(FileScope->sc_definedby->sy_idf); break; case N_SLINE: assert(line_file); if (CurrentScope->sc_start) { register p_scope sc = get_scope_from_addr(n->on_valu); if (sc) CurrentScope = sc; } else if (! saw_code) { CurrentScope->sc_start = n->on_valu; add_scope_addr(CurrentScope); } if (!CurrentScope->sc_bp_opp || CurrentScope->sc_bp_lineno > n->on_desc) { CurrentScope->sc_bp_opp = n->on_valu; CurrentScope->sc_bp_lineno = n->on_desc; } saw_code = 1; add_position_addr(line_file->on_mptr, n); break; case N_LBRAC: /* block, desc = nesting level */ if (lbrac_level && ! lbrac_required) { open_scope((p_symbol) 0, 0); saw_code = 0; } else { /* Sun-4 ld does not relocate LBRAC values, so we cannot use it register p_scope sc = get_scope_from_addr(n->on_valu); if (!sc || sc->sc_bp_opp) { } else CurrentScope = sc; */ } lbrac_level++; needs_newscope = 1; break; #ifdef N_SCOPE case N_SCOPE: if (n->on_mptr && strchr(n->on_mptr, ':')) { n = DbString(n); } break; #endif case N_RBRAC: /* end block, desc = nesting level */ if (CurrentScope != FileScope) close_scope(); needs_newscope = 1; if (--lbrac_level == 0) needs_newscope = 0; saw_code = 0; break; case N_FUN: /* function, value = address */ case N_GSYM: /* global variable */ case N_STSYM: /* data, static, value = address */ case N_LCSYM: /* bss, static, value = address */ case N_RSYM: /* register var, value = reg number */ case N_SSYM: /* struct/union el, value = offset */ case N_PSYM: /* parameter, value = offset from AP */ case N_LSYM: /* local sym, value = offset from FP */ if (needs_newscope) { open_scope((p_symbol) 0, 0); saw_code = 0; needs_newscope = 0; lbrac_required = 1; } if (n->on_mptr && strchr(n->on_mptr, ':')) { n = DbString(n); } break; default: /* if (n->on_mptr && (n->on_type&S_TYP) >= S_MIN) { struct idf *id = str2idf(n->on_mptr, 0); sym = new_symbol(); sym->sy_next = id->id_def; id->id_def = sym; sym->sy_class = SYMENTRY; sym->sy_onam = *n; sym->sy_idf = id; } */ break; } } } close_scope(); add_position_addr((char *) 0, (struct outname *) 0); clean_tp_tab(); rd_close(); return (h.oh_magic == O_CONVERTED); } }