|
|
1.1 ! root 1: /* ! 2: * db/db6.c ! 3: * A debugger. ! 4: * Symbol handling. ! 5: */ ! 6: ! 7: #include <canon.h> ! 8: #include "db.h" ! 9: ! 10: /* ! 11: * In earlier versions of db, a SYM included an id hash, a type and a symbol ! 12: * table index, but not did not include the symbol id[] itself. ! 13: * This allowed db to handle lots of symbols in a small address space, ! 14: * but each symbol lookup required reading the symbol again from ! 15: * the symbol table in the program file (i.e. from the disk). ! 16: * Since memory is no longer as critical an issue, now db stores the id[] ! 17: * as part of the SYM and symbol lookup does not need to access the file. ! 18: */ ! 19: ! 20: /* ! 21: * Given a value 'm' in segment 's', find the closest symbol below. ! 22: * Return a pointer to the symbol, or NULL if none. ! 23: * In COFF, with a flat address space, the segment can be ignored. ! 24: * In l.out, where the same address can represent a code or a data item, ! 25: * it had better not be ignored. ! 26: */ ! 27: SYM * ! 28: findsym(s, addr) int s; ADDR_T addr; ! 29: { ! 30: register int n; ! 31: register SYM *hp, *sp; ! 32: ! 33: dbprintf(("findsym(%d, %lX):\n", s, addr)); ! 34: sp = (SYM *)NULL; ! 35: if (sfp == (FILE *)NULL) ! 36: return sp; /* no symbols */ ! 37: for (n = 0; n < NHASH; n++) { /* search all hash buckets */ ! 38: for (hp = symhash[n]; hp != (SYM *)NULL; hp = hp->s_next) { ! 39: ! 40: dbprintf(("findsym: (%d, %lX) id=%s @ (%d, %lX)\n", s, addr, hp->s_id, hp->s_segn, hp->s_addr)); ! 41: if (IS_LOUT && hp->s_segn != s) ! 42: continue; /* segment mismatch */ ! 43: ! 44: /* If below and better than previous best guess... */ ! 45: if (hp->s_addr <= addr ! 46: && (sp==(SYM *)NULL || hp->s_addr > sp->s_addr)) { ! 47: sp = hp; /* best so far */ ! 48: dbprintf((" best so far: %s addr=%lX s=%d\n", sp->s_id, sp->s_addr, sp->s_segn)); ! 49: if (sp->s_addr == addr) ! 50: return sp; /* gotcha! */ ! 51: } ! 52: } ! 53: } ! 54: return sp; /* NULL or best guess */ ! 55: } ! 56: ! 57: /* ! 58: * Hash a symbol name. ! 59: * The '_' character has no effect on the hash, so "foo" and "foo_" hash ! 60: * to the same value; this is convenient for l.out symbol lookup, ! 61: * where is_symbol() understands "foo" to mean "foo_" if there is no "foo". ! 62: */ ! 63: int ! 64: hash(id) register char *id; ! 65: { ! 66: register int c, h; ! 67: ! 68: for (h = 0; (c = *id++) != 0; ) ! 69: if (c != '_') ! 70: h += c; ! 71: return h % NHASH; ! 72: } ! 73: ! 74: /* ! 75: * See if the given symbol is a special symbol "d", "i" or "u". ! 76: */ ! 77: int ! 78: is_special(sp) register SYM *sp; ! 79: { ! 80: register int s; ! 81: ! 82: if (sp->s_id[1] != '\0') ! 83: return 0; ! 84: switch (sp->s_id[0]) { ! 85: case 'd': s = DSEG; break; ! 86: case 'i': s = ISEG; break; ! 87: case 'u': s = USEG; break; ! 88: default: return 0; ! 89: } ! 90: sp->s_addr = 0; ! 91: sp->s_segn = s; ! 92: return 1; ! 93: } ! 94: ! 95: /* ! 96: * Find the value of a symbol. ! 97: * Return 1 on success, 0 on failure. ! 98: * For l.out, "foo" matches "foo_" if "foo" is not found. ! 99: */ ! 100: int ! 101: is_symbol(sp) SYM *sp; ! 102: { ! 103: register char *cp; ! 104: register SYM *hp; ! 105: register int len; ! 106: ! 107: dbprintf(("is_symbol(%s): ")); ! 108: cp = sp->s_id; ! 109: for (hp = symhash[hash(cp)]; hp != (SYM *)NULL; hp = hp->s_next) { ! 110: if (strcmp(cp, hp->s_id) == 0) { ! 111: dbprintf(("addr=%lX segn=%d\n", hp->s_addr, hp->s_segn)); ! 112: sp->s_addr = hp->s_addr; ! 113: sp->s_segn = hp->s_segn; ! 114: return 1; ! 115: } ! 116: } ! 117: ! 118: /* The symbol was not found. If l.out, try again with trailing '_'. */ ! 119: if (IS_LOUT) { ! 120: len = strlen(cp); ! 121: for (hp = symhash[hash(cp)]; hp != (SYM *)NULL; hp = hp->s_next) { ! 122: if (strncmp(cp, hp->s_id, len) == 0 ! 123: && hp->s_id[len] == '_' ! 124: && hp->s_id[len+1] == '\0') { ! 125: dbprintf(("(%s) addr=%lX segn=%d\n", hp->s_id, hp->s_addr, hp->s_segn)); ! 126: sp->s_addr = hp->s_addr; ! 127: sp->s_segn = hp->s_segn; ! 128: return 1; ! 129: } ! 130: } ! 131: } ! 132: dbprintf((" is_symbol(): %s not found\n", cp)); ! 133: return 0; ! 134: } ! 135: ! 136: /* ! 137: * Allocate a new SYM with the given id, address and segment. ! 138: * Initialize it and link it into the hash chain. ! 139: * db.h declares char s_id[1], but the nalloc() call below ! 140: * leaves room for the actual id char s_id[len+1]. ! 141: */ ! 142: void ! 143: new_sym(id, addr, s) char *id; ADDR_T addr; int s; ! 144: { ! 145: register int len, h; ! 146: register SYM *sp; ! 147: ! 148: h = hash(id); ! 149: len = strlen(id); /* len+1 is s_id len with NUL */ ! 150: dbprintf(("new_sym(%s, %x, %lX) len=%d hash=%x\n", id, type, addr, len, h)); ! 151: sp = (SYM *)nalloc(sizeof(SYM) + len, "symbol"); ! 152: sp->s_next = symhash[h]; ! 153: symhash[h] = sp; ! 154: sp->s_addr = addr; ! 155: sp->s_segn = s; ! 156: strcpy(sp->s_id, id); ! 157: } ! 158: ! 159: /* ! 160: * Read COFF symbols. ! 161: */ ! 162: int ! 163: read_coff_sym() ! 164: { ! 165: SYMENT coffsym; ! 166: long n; ! 167: register int len, segn; ! 168: char *strtab; ! 169: SCNHDR *shp; ! 170: ! 171: dbprintf(("read_coff_sym()\n")); ! 172: ! 173: /* Read the COFF string table. */ ! 174: strtab = read_strtab(); ! 175: ! 176: /* Read the COFF section headers. */ ! 177: len = coff_hdr.f_nscns * sizeof(SCNHDR); ! 178: shp = (SCNHDR *)nalloc(len, "COFF section headers"); ! 179: if (fseek(sfp, (long)(sizeof(FILEHDR) + coff_hdr.f_opthdr), SEEK_SET) == -1 ! 180: || fread(shp, len, 1, sfp) != 1) ! 181: return printe("Cannot read section headers"); ! 182: ! 183: /* Read symbols. */ ! 184: if (fseek(sfp, (long)coff_hdr.f_symptr, SEEK_SET) == -1) ! 185: return printe("COFF symbol seek failed"); ! 186: for (nsyms = 0, n = coff_hdr.f_nsyms; n--; ) { ! 187: /* Read a COFF symbol. */ ! 188: if (fread(&coffsym, sizeof(SYMENT), 1, sfp) != 1) ! 189: return printe("Cannot read COFF symbol"); ! 190: switch (coffsym.n_sclass) { ! 191: case C_EXT: ! 192: case C_EXTDEF: ! 193: break; ! 194: default: ! 195: continue; ! 196: } ! 197: /* Ignore undefined and absolute symbols. */ ! 198: if (coffsym.n_scnum == N_UNDEF || coffsym.n_scnum == N_ABS) ! 199: continue; ! 200: ! 201: switch((int)shp[coffsym.n_scnum-1].s_flags) { ! 202: case STYP_TEXT: segn = ISEG; break; ! 203: case STYP_DATA: ! 204: case STYP_BSS: segn = DSEG; break; ! 205: default: ! 206: panic("Unallowed section flags 0x%lX for symbol in section %d", ! 207: shp[coffsym.n_scnum-1].s_flags, coffsym.n_scnum-1); ! 208: } ! 209: ++nsyms; ! 210: new_sym(symName(&coffsym, strtab), coffsym.n_value, segn); ! 211: } ! 212: dbprintf(("COFF nsyms=%d\n", nsyms)); ! 213: if (strtab != NULL) ! 214: nfree(strtab); ! 215: nfree(shp); ! 216: return 1; ! 217: } ! 218: ! 219: /* ! 220: * Read l.out symbols. ! 221: */ ! 222: int ! 223: read_lout_sym(symseek) long symseek; ! 224: { ! 225: register int n, segn; ! 226: struct ldsym lds; ! 227: char id[NCPLN+1]; ! 228: ! 229: if (fseek(sfp, symseek, SEEK_SET) == -1) ! 230: return printr("Cannot seek to l.out symbols"); ! 231: for (n = nsyms; n--; ) { ! 232: /* Read an l.out symbol. */ ! 233: if (fread(&lds, sizeof(struct ldsym), 1, sfp) != 1) ! 234: return printr("Cannot read l.out symbol"); ! 235: canint(lds.ls_type); ! 236: switch(lds.ls_type & LR_SEG) { ! 237: case L_ABS: ! 238: case L_SHRI: ! 239: case L_PRVI: ! 240: case L_BSSI: ! 241: segn = ISEG; ! 242: break; ! 243: case L_SHRD: ! 244: case L_PRVD: ! 245: case L_BSSD: ! 246: segn = DSEG; ! 247: break; ! 248: default: ! 249: dbprintf(("Unexpected l.out segment %d\n", lds.ls_type & LR_SEG)); ! 250: continue; ! 251: } ! 252: canvaddr(lds.ls_addr); ! 253: strncpy(id, lds.ls_id, NCPLN); ! 254: id[NCPLN] = '\0'; ! 255: new_sym(id, (ADDR_T)lds.ls_addr, segn); ! 256: } ! 257: dbprintf(("l.out nsyms=%d\n", nsyms)); ! 258: return 1; ! 259: } ! 260: ! 261: /* ! 262: * Read the COFF string table. ! 263: * Return a pointer to the allocated table, or NULL if empty. ! 264: */ ! 265: char * ! 266: read_strtab() ! 267: { ! 268: register unsigned int len; ! 269: int llen; ! 270: char *strtab; ! 271: ! 272: dbprintf(("read_strtab()\n")); ! 273: len = llen = sizeof(SYMENT) * coff_hdr.f_nsyms; ! 274: if (len == 0) ! 275: return NULL; /* no symbols */ ! 276: if (llen != len) ! 277: panic("COFF symbol table too big"); ! 278: ! 279: /* Seek to strtab length. */ ! 280: if (fseek(sfp, coff_hdr.f_symptr+len, SEEK_SET) == -1 ! 281: || fread(&llen, sizeof(llen), 1, sfp) != 1) ! 282: llen = 0; ! 283: if (llen == 0) ! 284: return NULL; /* no string table */ ! 285: len = llen -= 4; ! 286: if (len != llen) ! 287: panic("COFF string table too big"); ! 288: strtab = nalloc((int)len, "COFF string table"); ! 289: if (fread(strtab, len, 1, sfp) != 1) { ! 290: printe("Cannot read symbol string table"); ! 291: return NULL; ! 292: } ! 293: return strtab; ! 294: } ! 295: ! 296: /* ! 297: * Given a COFF symbol table entry, return its NUL-terminated name. ! 298: */ ! 299: char * ! 300: symName(sym, strtab) SYMENT *sym; char *strtab; ! 301: { ! 302: static char work[SYMNMLEN+1]; ! 303: ! 304: if (sym->n_zeroes == 0) ! 305: return strtab + sym->n_offset - 4; /* name in string table */ ! 306: ! 307: /* Copy name from n_name to make sure it's NUL-terminated. */ ! 308: memcpy(work, sym->n_name, SYMNMLEN); ! 309: work[SYMNMLEN] = '\0'; ! 310: return work; ! 311: } ! 312: ! 313: /* ! 314: * Read a symbol and return its value in the given 'VAL' structure. ! 315: * The symbol name can contain alphanumeric characters and '_'; ! 316: * a leading '%' indicates a register name. ! 317: */ ! 318: int ! 319: symval(vp) VAL *vp; ! 320: { ! 321: register int c; ! 322: register char *cp; ! 323: int regf; ! 324: static SYM *sp; ! 325: static int sym_len = 128; ! 326: ! 327: /* Allocate a SYM first time through. */ ! 328: if (sp == (SYM *)NULL) ! 329: sp = (SYM *)nalloc(sizeof(SYM)+sym_len+1, "symbol id buffer"); ! 330: ! 331: /* Read the symbol name into the SYM id[] buffer. */ ! 332: for (regf = 0, cp = sp->s_id; ; cp++) { ! 333: c = getn(); ! 334: /* Allow leading '%' to indicate register name. */ ! 335: if (cp==sp->s_id && c=='%') { ! 336: c = getn(); ! 337: ++regf; ! 338: } ! 339: if (!isascii(c) || (!isalnum(c) && c!= '_')) ! 340: break; ! 341: if (cp == &sp->s_id[sym_len]) { ! 342: register SYM *sp2; ! 343: ! 344: /* Grow the symbol id buffer when required. */ ! 345: sp2 = (SYM *)nalloc(sizeof(SYM)+sym_len+sym_len+1, "symbol id buffer"); ! 346: strncpy(sp2->s_id, sp->s_id, sym_len); ! 347: cp = &sp2->s_id[sym_len]; ! 348: sym_len += sym_len; ! 349: nfree(sp); ! 350: sp = sp2; ! 351: } ! 352: *cp = c; ! 353: } ! 354: *cp = '\0'; ! 355: ungetn(c); ! 356: if (regf) { ! 357: if (is_reg(sp) == 0) ! 358: return printe("Register not found"); ! 359: } else if (!is_special(sp) && !is_symbol(sp) && !is_reg(sp)) ! 360: return printe("Symbol not found"); ! 361: ! 362: /* Copy the value and segment to vp. */ ! 363: vp->v_nval = (long)sp->s_addr; ! 364: vp->v_segn = sp->s_segn; ! 365: vp->v_flag = VSEGN; ! 366: return 1; ! 367: } ! 368: ! 369: /* end of db/db6.c */ ! 370:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.