Annotation of lucent/sys/src/libmach/sym.c, revision 1.1

1.1     ! root        1: #include <u.h>
        !             2: #include <libc.h>
        !             3: #include <bio.h>
        !             4: #include <mach.h>
        !             5: 
        !             6: #define        HUGEINT 0x7fffffff
        !             7: #define        NNAME   20              /* a relic of the past */
        !             8: 
        !             9: typedef        struct txtsym Txtsym;
        !            10: typedef        struct file File;
        !            11: typedef        struct hist Hist;
        !            12: 
        !            13: struct txtsym {                                /* Text Symbol table */
        !            14:        int     n;                      /* number of local vars */
        !            15:        Sym     **locals;               /* array of ptrs to autos */
        !            16:        Sym     *sym;                   /* function symbol entry */
        !            17: };
        !            18: 
        !            19: struct hist {          /* Stack of include files & #line directives */
        !            20:        char    *name;                  /* Assumes names Null terminated in file */
        !            21:        long    line;                   /* line # where it was included */
        !            22:        long    offset;                 /* line # of #line directive */
        !            23: };
        !            24: 
        !            25: struct file {                          /* Per input file header to history stack */
        !            26:        long            addr;           /* address of first text sym */
        !            27:        union {
        !            28:                Txtsym          *txt;   /* first text symbol */
        !            29:                Sym             *sym;   /* only during initilization */
        !            30:        };
        !            31:        int             n;              /* size of history stack */
        !            32:        Hist            *hist;          /* history stack */
        !            33: };
        !            34: 
        !            35: static int     debug = 0;
        !            36: 
        !            37: static Sym     **autos;                /* Base of auto variables */
        !            38: static File    *files;                 /* Base of file arena */
        !            39: static int     fmax;                   /* largest file path index */
        !            40: static Sym     **fnames;               /* file names path component table */
        !            41: static Sym     **globals;              /* globals by addr table */
        !            42: static Hist    *hist;                  /* base of history stack */
        !            43: static int     isbuilt;                /* internal table init flag */
        !            44: static long    nauto;                  /* number of automatics */
        !            45: static long    nfiles;                 /* number of files */
        !            46: static long    nglob;                  /* number of globals */
        !            47: static long    nhist;                  /* number of history stack entries */
        !            48: static long    nsym;                   /* number of symbols */
        !            49: static int     ntxt;                   /* number of text symbols */
        !            50: static uchar   *pcline;                /* start of pc-line state table */
        !            51: static uchar   *pclineend;             /* end of pc-line table */
        !            52: static uchar   *spoff;                 /* start of pc-sp state table */
        !            53: static uchar   *spoffend;              /* end of pc-sp offset table */
        !            54: static Sym     *symbols;               /* symbol table */
        !            55: static Txtsym  *txt;                   /* Base of text symbol table */
        !            56: static long    txtstart;               /* start of text segment */
        !            57: static long    txtend;                 /* end of text segment */
        !            58: 
        !            59: static void    cleansyms(void);
        !            60: static int     decodename(Biobuf*, Sym*);
        !            61: static short   *encfname(char *);
        !            62: static Hist    *fline(char *, int, long, Hist *);
        !            63: static void    fillsym(Sym *, Symbol *);
        !            64: static int     findglobal(char *, Symbol *);
        !            65: static int     findlocvar(Symbol *, char *, Symbol *);
        !            66: static int     findtext(char *, Symbol *);
        !            67: static int     hcomp(Hist *, short *);
        !            68: static int     hline(File *, short *, ulong *);
        !            69: static void    printhist(char *, Hist *, int);
        !            70: static int     buildtbls(void);
        !            71: static int     symcomp(void *, void *);
        !            72: static int     symerrmsg(int, char*);
        !            73: static int     txtcomp(void *, void *);
        !            74: static int     filecomp(void *, void *);
        !            75: 
        !            76: /*
        !            77:  *     initialize the symbol tables
        !            78:  */
        !            79: int
        !            80: syminit(int fd, Fhdr *fp)
        !            81: {
        !            82:        Sym *p;
        !            83:        int i, size;
        !            84:        Biobuf b;
        !            85: 
        !            86:        if(fp->symsz == 0)
        !            87:                return 0;
        !            88:        if(fp->type == FNONE)
        !            89:                return 0;
        !            90: 
        !            91:        cleansyms();
        !            92:        textseg(fp->txtaddr, fp);
        !            93:                /* minimum symbol record size = 4+1+2 bytes */
        !            94:        symbols = malloc((fp->symsz/(4+1+2)+1)*sizeof(Sym));
        !            95:        if(symbols == 0) {
        !            96:                werrstr("can't malloc %d bytes", fp->symsz);
        !            97:                return -1;
        !            98:        }
        !            99: 
        !           100:        Binit(&b, fd, OREAD);
        !           101:        Bseek(&b, fp->symoff, 0);
        !           102:        nsym = 0;
        !           103:        size = 0;
        !           104:        for(p = symbols; size < fp->symsz; p++, nsym++) {
        !           105:                if(Bread(&b, &p->value, sizeof(p->value)) != sizeof(p->value))
        !           106:                        return symerrmsg(sizeof(p->value), "symbol");
        !           107:                p->value = beswal(p->value);
        !           108:                if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type))
        !           109:                        return symerrmsg(sizeof(p->value), "symbol");
        !           110: 
        !           111:                i = decodename(&b, p);
        !           112:                if(i < 0)
        !           113:                        return -1;
        !           114:                size += i+sizeof(p->value)+sizeof(p->type);
        !           115: 
        !           116:                /* count global & auto vars, text symbols, and file names */
        !           117:                switch (p->type) {
        !           118:                case 'l':
        !           119:                case 'L':
        !           120:                case 't':
        !           121:                case 'T':
        !           122:                        ntxt++;
        !           123:                        break;
        !           124:                case 'd':
        !           125:                case 'D':
        !           126:                case 'b':
        !           127:                case 'B':
        !           128:                        nglob++;
        !           129:                        break;
        !           130:                case 'f':
        !           131:                        if(strcmp(p->name, ".frame") == 0) {
        !           132:                                p->type = 'm';
        !           133:                                nauto++;
        !           134:                        }
        !           135:                        else if(p->value > fmax)
        !           136:                                fmax = p->value;        /* highest path index */
        !           137:                        break;
        !           138:                case 'a':
        !           139:                case 'p':
        !           140:                case 'm':
        !           141:                        nauto++;
        !           142:                        break;
        !           143:                case 'z':
        !           144:                        if(p->value == 1) {             /* one extra per file */
        !           145:                                nhist++;
        !           146:                                nfiles++;
        !           147:                        }
        !           148:                        nhist++;
        !           149:                        break;
        !           150:                default:
        !           151:                        break;
        !           152:                }
        !           153:        }
        !           154:        if (debug)
        !           155:                print("NG: %d NT: %d NF: %d\n", nglob, ntxt, fmax);
        !           156:        if (fp->sppcsz) {                       /* pc-sp offset table */
        !           157:                spoff = (uchar *)malloc(fp->sppcsz);
        !           158:                if(spoff == 0) {
        !           159:                        werrstr("can't malloc %d bytes", fp->sppcsz);
        !           160:                        return -1;
        !           161:                }
        !           162:                Bseek(&b, fp->sppcoff, 0);
        !           163:                i = Bread(&b, spoff, fp->sppcsz);
        !           164:                if(i != fp->sppcsz){
        !           165:                        spoff = 0;
        !           166:                        return symerrmsg(fp->sppcsz, "sp-pc");
        !           167:                }
        !           168:                spoffend = spoff+fp->sppcsz;
        !           169:        }
        !           170:        if (fp->lnpcsz) {                       /* pc-line number table */
        !           171:                pcline = (uchar *)malloc(fp->lnpcsz);
        !           172:                if(pcline == 0) {
        !           173:                        werrstr("can't malloc %d bytes", fp->lnpcsz);
        !           174:                        return -1;
        !           175:                }
        !           176:                Bseek(&b, fp->lnpcoff, 0);
        !           177:                i = Bread(&b, pcline, fp->lnpcsz);
        !           178:                if(i != fp->lnpcsz){
        !           179:                        pcline = 0;
        !           180:                        return symerrmsg(fp->lnpcsz, "pc-line");
        !           181:                }
        !           182:                pclineend = pcline+fp->lnpcsz;
        !           183:        }
        !           184:        return nsym;
        !           185: }
        !           186: 
        !           187: static int
        !           188: symerrmsg(int n, char *table)
        !           189: {
        !           190:        werrstr("can't read %d bytes of %s table", n, table);
        !           191:        return -1;
        !           192: }
        !           193: 
        !           194: static int
        !           195: decodename(Biobuf *bp, Sym *p)
        !           196: {
        !           197:        char *cp;
        !           198:        int c1, c2;
        !           199:        int n;
        !           200: 
        !           201:        if((p->type & 0x80) == 0) {             /* old-style, fixed length names */
        !           202:                p->name = malloc(NNAME);
        !           203:                if(p->name == 0) {
        !           204:                        werrstr("can't malloc %d bytes", NNAME);
        !           205:                        return -1;
        !           206:                }
        !           207:                if(Bread(bp, p->name, NNAME) != NNAME)
        !           208:                        return symerrmsg(NNAME, "symbol");
        !           209:                Bseek(bp, 3, 1);
        !           210:                return NNAME+3;
        !           211:        }
        !           212: 
        !           213:        p->type &= ~0x80;
        !           214:        if(p->type == 'z' || p->type == 'Z') {
        !           215:                n = Bseek(bp, 0, 1);
        !           216:                if(Bgetc(bp) < 0) {
        !           217:                        werrstr("can't read symbol name");
        !           218:                        return -1;
        !           219:                }
        !           220:                for(;;) {
        !           221:                        c1 = Bgetc(bp);
        !           222:                        c2 = Bgetc(bp);
        !           223:                        if(c1 < 0 || c2 < 0) {
        !           224:                                werrstr("can't read symbol name");
        !           225:                                return -1;
        !           226:                        }
        !           227:                        if(c1 == 0 && c2 == 0)
        !           228:                                break;
        !           229:                }
        !           230:                n = Bseek(bp, 0, 1)-n;
        !           231:                p->name = malloc(n);
        !           232:                if(p->name == 0) {
        !           233:                        werrstr("can't malloc %d bytes", n);
        !           234:                        return -1;
        !           235:                }
        !           236:                Bseek(bp, -n, 1);
        !           237:                if(Bread(bp, p->name, n) != n) {
        !           238:                        werrstr("can't read %d bytes of symbol name", n);
        !           239:                        return -1;
        !           240:                }
        !           241:        } else {
        !           242:                cp = Brdline(bp, '\0');
        !           243:                if(cp == 0) {
        !           244:                        werrstr("can't read symbol name");
        !           245:                        return -1;
        !           246:                }
        !           247:                n = Blinelen(bp);
        !           248:                p->name = malloc(n);
        !           249:                if(p->name == 0) {
        !           250:                        werrstr("can't malloc %d bytes", n);
        !           251:                        return -1;
        !           252:                }
        !           253:                strcpy(p->name, cp);
        !           254:        }
        !           255:        return n;
        !           256: }
        !           257: /*
        !           258:  *     free any previously loaded symbol tables
        !           259:  */
        !           260: static void
        !           261: cleansyms(void)
        !           262: {
        !           263:        if(globals)
        !           264:                free(globals);
        !           265:        globals = 0;
        !           266:        nglob = 0;
        !           267:        if(txt)
        !           268:                free(txt);
        !           269:        txt = 0;
        !           270:        ntxt = 0;
        !           271:        if(fnames)
        !           272:                free(fnames);
        !           273:        fnames = 0;
        !           274:        fmax = 0;
        !           275: 
        !           276:        if(files)
        !           277:                free(files);
        !           278:        files = 0;
        !           279:        nfiles = 0;
        !           280:        if(hist)
        !           281:                free(hist);
        !           282:        hist = 0;
        !           283:        nhist = 0;
        !           284:        if(autos)
        !           285:                free(autos);
        !           286:        autos = 0;
        !           287:        nauto = 0;
        !           288:        isbuilt = 0;
        !           289:        if(symbols)
        !           290:                free(symbols);
        !           291:        symbols = 0;
        !           292:        nsym = 0;
        !           293:        if(spoff)
        !           294:                free(spoff);
        !           295:        spoff = 0;
        !           296:        if(pcline)
        !           297:                free(pcline);
        !           298:        pcline = 0;
        !           299: }
        !           300: /*
        !           301:  *     delimit the text segment
        !           302:  */
        !           303: void
        !           304: textseg(ulong base, Fhdr *fp)
        !           305: {
        !           306:        txtstart = base;
        !           307:        txtend = base+fp->txtsz;
        !           308: }
        !           309: /*
        !           310:  *     symbase: return base and size of raw symbol table
        !           311:  *             (special hack for high access rate operations)
        !           312:  */
        !           313: Sym *
        !           314: symbase(long *n)
        !           315: {
        !           316:        *n = nsym;
        !           317:        return symbols;
        !           318: }
        !           319: /*
        !           320:  *     Get the ith symbol table entry
        !           321:  */
        !           322: Sym *
        !           323: getsym(int index)
        !           324: {
        !           325:        if(index < nsym)
        !           326:                return &symbols[index];
        !           327:        return 0;
        !           328: }
        !           329: 
        !           330: /*
        !           331:  *     initialize internal symbol tables
        !           332:  */
        !           333: static int
        !           334: buildtbls(void)
        !           335: {
        !           336:        int i, j, nh, ng, nt;
        !           337:        File *f;
        !           338:        Txtsym *tp;
        !           339:        Hist *hp;
        !           340:        Sym *p, **ap;
        !           341: 
        !           342:        if(isbuilt)
        !           343:                return 1;
        !           344:        isbuilt = 1;
        !           345:                        /* allocate the tables */
        !           346:        if(nglob) {
        !           347:                globals = malloc(nglob*sizeof(*globals));
        !           348:                if(!globals) {
        !           349:                        werrstr("can't malloc global symbol table");
        !           350:                        return 0;
        !           351:                }
        !           352:        }
        !           353:        if(ntxt) {
        !           354:                txt = malloc(ntxt*sizeof(*txt));
        !           355:                if (!txt) {
        !           356:                        werrstr("can't malloc text symbol table");
        !           357:                        return 0;
        !           358:                }
        !           359:        }
        !           360:        fmax++;
        !           361:        fnames = malloc(fmax*sizeof(*fnames));
        !           362:        if (!fnames) {
        !           363:                werrstr("can't malloc file name table");
        !           364:                return 0;
        !           365:        }
        !           366:        memset(fnames, 0, fmax*sizeof(*fnames));
        !           367:        files = malloc(nfiles*sizeof(*files));
        !           368:        if(!files) {
        !           369:                werrstr("can't malloc file table");
        !           370:                return 0;
        !           371:        }
        !           372:        hist = malloc(nhist*sizeof(Hist));
        !           373:        if(hist == 0) {
        !           374:                werrstr("can't malloc history stack");
        !           375:                return 0;
        !           376:        }
        !           377:        autos = malloc(nauto*sizeof(Sym*));
        !           378:        if(autos == 0) {
        !           379:                werrstr("can't malloc auto symbol table");
        !           380:                return 0;
        !           381:        }
        !           382:                /* load the tables */
        !           383:        ng = nt = nh = 0;
        !           384:        f = 0;
        !           385:        tp = 0;
        !           386:        i = nsym;
        !           387:        hp = hist;
        !           388:        ap = autos;
        !           389:        for(p = symbols; i-- > 0; p++) {
        !           390:                switch(p->type) {
        !           391:                case 'D':
        !           392:                case 'd':
        !           393:                case 'B':
        !           394:                case 'b':
        !           395:                        if(debug)
        !           396:                                print("Global: %s %lux\n", p->name, p->value);
        !           397:                        globals[ng++] = p;
        !           398:                        break;
        !           399:                case 'z':
        !           400:                        if(p->value == 1) {             /* New file */
        !           401:                                if(f) {
        !           402:                                        f->n = nh;
        !           403:                                        f->hist[nh].name = 0;   /* one extra */
        !           404:                                        hp += nh+1;
        !           405:                                        f++;
        !           406:                                }
        !           407:                                else f = files;
        !           408:                                f->hist = hp;
        !           409:                                f->sym = 0;
        !           410:                                f->addr = 0;
        !           411:                                nh = 0;
        !           412:                        }
        !           413:                                /* alloc one slot extra as terminator */
        !           414:                        f->hist[nh].name = p->name;
        !           415:                        f->hist[nh].line = p->value;
        !           416:                        f->hist[nh].offset = 0;
        !           417:                        if(debug)
        !           418:                                printhist("-> ", &f->hist[nh], 1);
        !           419:                        nh++;
        !           420:                        break;
        !           421:                case 'Z':
        !           422:                        if(f && nh > 0)
        !           423:                                f->hist[nh-1].offset = p->value;
        !           424:                        break;
        !           425:                case 'T':
        !           426:                case 't':       /* Text: terminate history if first in file */
        !           427:                case 'L':
        !           428:                case 'l':
        !           429:                        tp = &txt[nt++];
        !           430:                        tp->n = 0;
        !           431:                        tp->sym = p;
        !           432:                        tp->locals = ap;
        !           433:                        if(debug)
        !           434:                                print("TEXT: %s at %lux\n", p->name, p->value);
        !           435:                        if(f && !f->sym) {                      /* first  */
        !           436:                                f->sym = p;
        !           437:                                f->addr = p->value;
        !           438:                        }
        !           439:                        break;
        !           440:                case 'a':
        !           441:                case 'p':
        !           442:                case 'm':               /* Local Vars */
        !           443:                        if(!tp)
        !           444:                                print("Warning: Free floating local var");
        !           445:                        else {
        !           446:                                if(debug)
        !           447:                                        print("Local: %s %lux\n", p->name, p->value);
        !           448:                                tp->locals[tp->n] = p;
        !           449:                                tp->n++;
        !           450:                                ap++;
        !           451:                        }
        !           452:                        break;
        !           453:                case 'f':               /* File names */
        !           454:                        if(debug)
        !           455:                                print("Fname: %s\n", p->name);
        !           456:                        fnames[p->value] = p;
        !           457:                        break;
        !           458:                default:
        !           459:                        break;
        !           460:                }
        !           461:        }
        !           462:                /* sort global and text tables into ascending address order */
        !           463:        qsort(globals, nglob, sizeof(Sym*), symcomp);
        !           464:        qsort(txt, ntxt, sizeof(Txtsym), txtcomp);
        !           465:        qsort(files, nfiles, sizeof(File), filecomp);
        !           466:        tp = txt;
        !           467:        for(i = 0, f = files; i < nfiles; i++, f++) {
        !           468:                for(j = 0; j < ntxt; j++) {
        !           469:                        if(f->sym == tp->sym) {
        !           470:                                if(debug) {
        !           471:                                        print("LINK: %s to", f->sym->name);
        !           472:                                        printhist("... ", f->hist, 1);
        !           473:                                }
        !           474:                                f->txt = tp++;
        !           475:                                break;
        !           476:                        }
        !           477:                        if(++tp >= txt+ntxt)    /* wrap around */
        !           478:                                tp = txt;
        !           479:                }
        !           480:        }
        !           481:        return 1;
        !           482: }
        !           483: 
        !           484: /*
        !           485:  * find symbol function.var by name.
        !           486:  *     fn != 0 && var != 0     => look for fn in text, var in data
        !           487:  *     fn != 0 && var == 0     => look for fn in text
        !           488:  *     fn == 0 && var != 0     => look for var first in text then in data space.
        !           489:  */
        !           490: int
        !           491: lookup(char *fn, char *var, Symbol *s)
        !           492: {
        !           493:        int found;
        !           494: 
        !           495:        if(buildtbls() == 0)
        !           496:                return 0;
        !           497:        if(fn) {
        !           498:                found = findtext(fn, s);
        !           499:                if(var == 0)            /* case 2: fn not in text */
        !           500:                        return found;
        !           501:                else if(!found)         /* case 1: fn not found */
        !           502:                        return 0;
        !           503:        } else if(var) {
        !           504:                found = findtext(var, s);
        !           505:                if(found)
        !           506:                        return 1;       /* case 3: var found in text */
        !           507:        } else return 0;                /* case 4: fn & var == zero */
        !           508: 
        !           509:        if(found)
        !           510:                return findlocal(s, var, s);    /* case 1: fn found */
        !           511:        return findglobal(var, s);              /* case 3: var not found */
        !           512: 
        !           513: }
        !           514: /*
        !           515:  * find a function by name
        !           516:  */
        !           517: static int
        !           518: findtext(char *name, Symbol *s)
        !           519: {
        !           520:        int i;
        !           521: 
        !           522:        for(i = 0; i < ntxt; i++) {
        !           523:                if(strcmp(txt[i].sym->name, name) == 0) {
        !           524:                        fillsym(txt[i].sym, s);
        !           525:                        s->handle = (void *) &txt[i];
        !           526:                        return 1;
        !           527:                }
        !           528:        }
        !           529:        return 0;
        !           530: }
        !           531: /*
        !           532:  * find global variable by name
        !           533:  */
        !           534: static int
        !           535: findglobal(char *name, Symbol *s)
        !           536: {
        !           537:        int i;
        !           538: 
        !           539:        for(i = 0; i < nglob; i++) {
        !           540:                if(strcmp(globals[i]->name, name) == 0) {
        !           541:                        fillsym(globals[i], s);
        !           542:                        return 1;
        !           543:                }
        !           544:        }
        !           545:        return 0;
        !           546: }
        !           547: /*
        !           548:  *     find the local variable by name within a given function
        !           549:  */
        !           550: int
        !           551: findlocal(Symbol *s1, char *name, Symbol *s2)
        !           552: {
        !           553:        if(s1 == 0)
        !           554:                return 0;
        !           555:        if(buildtbls() == 0)
        !           556:                return 0;
        !           557:        return findlocvar(s1, name, s2);
        !           558: }
        !           559: /*
        !           560:  *     find the local variable by name within a given function
        !           561:  *             (internal function - does no parameter validation)
        !           562:  */
        !           563: static int
        !           564: findlocvar(Symbol *s1, char *name, Symbol *s2)
        !           565: {
        !           566:        Txtsym *tp;
        !           567:        int i;
        !           568: 
        !           569:        tp = (Txtsym *)s1->handle;
        !           570:        if(tp && tp->locals) {
        !           571:                for(i = 0; i < tp->n; i++)
        !           572:                        if (strcmp(tp->locals[i]->name, name) == 0) {
        !           573:                                fillsym(tp->locals[i], s2);
        !           574:                                s2->handle = (void *)tp;
        !           575:                                return 1;
        !           576:                        }
        !           577:        }
        !           578:        return 0;
        !           579: }
        !           580: /*
        !           581:  *     Get ith text symbol
        !           582:  */
        !           583: int
        !           584: textsym(Symbol *s, int index)
        !           585: {
        !           586: 
        !           587:        if(buildtbls() == 0)
        !           588:                return 0;
        !           589:        if(index >= ntxt)
        !           590:                return 0;
        !           591:        fillsym(txt[index].sym, s);
        !           592:        s->handle = (void *)&txt[index];
        !           593:        return 1;
        !           594: }
        !           595: /*     
        !           596:  *     Get ith file name
        !           597:  */
        !           598: int
        !           599: filesym(int index, char *buf, int n)
        !           600: {
        !           601:        Hist *hp;
        !           602: 
        !           603:        if(buildtbls() == 0)
        !           604:                return 0;
        !           605:        if(index >= nfiles)
        !           606:                return 0;
        !           607:        hp = files[index].hist;
        !           608:        if(!hp || !hp->name)
        !           609:                return 0;
        !           610:        return fileelem(fnames, (uchar*)hp->name, buf, n);
        !           611: }
        !           612: /*
        !           613:  *     Lookup name of local variable located at an offset into the frame.
        !           614:  *     The type selects either a parameter or automatic.
        !           615:  */
        !           616: int
        !           617: getauto(Symbol *s1, int off, int type, Symbol *s2)
        !           618: {
        !           619:        Txtsym *tp;
        !           620:        Sym *p;
        !           621:        int i, t;
        !           622: 
        !           623:        if(s1 == 0)
        !           624:                return 0;
        !           625:        if(type == CPARAM)
        !           626:                t = 'p';
        !           627:        else if(type == CAUTO)
        !           628:                t = 'a';
        !           629:        else
        !           630:                return 0;
        !           631:        if(buildtbls() == 0)
        !           632:                return 0;
        !           633:        tp = (Txtsym *)s1->handle;
        !           634:        if(tp == 0)
        !           635:                return 0;
        !           636:        for(i = 0; i < tp->n; i++) {
        !           637:                p = tp->locals[i];
        !           638:                if(p->type == t && p->value == off) {
        !           639:                        fillsym(p, s2);
        !           640:                        s2->handle = s1->handle;
        !           641:                        return 1;
        !           642:                }
        !           643:        }
        !           644:        return 0;
        !           645: }
        !           646: 
        !           647: /*
        !           648:  * Find text symbol containing addr; binary search assumes text array is sorted by addr
        !           649:  */
        !           650: static int
        !           651: srchtext(long addr)
        !           652: {
        !           653:        ulong val;
        !           654:        int top, bot, mid;
        !           655:        Sym *sp;
        !           656: 
        !           657:        val = addr;
        !           658:        bot = 0;
        !           659:        top = ntxt;
        !           660:        for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
        !           661:                sp = txt[mid].sym;
        !           662:                if(val < (ulong)sp->value)
        !           663:                        top = mid;
        !           664:                else if(mid != ntxt-1 && val >= (ulong)txt[mid+1].sym->value)
        !           665:                        bot = mid;
        !           666:                else
        !           667:                        return mid;
        !           668:        }
        !           669:        return -1;
        !           670: }
        !           671: 
        !           672: /*
        !           673:  * Find data symbol containing addr; binary search assumes data array is sorted by addr
        !           674:  */
        !           675: static
        !           676: int srchdata(long addr)
        !           677: {
        !           678:        ulong val;
        !           679:        int top, bot, mid;
        !           680:        Sym *sp;
        !           681: 
        !           682:        bot = 0;
        !           683:        top = nglob;
        !           684:        val = addr;
        !           685:        for(mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
        !           686:                sp = globals[mid];
        !           687:                if(val < (ulong)sp->value)
        !           688:                        top = mid;
        !           689:                else if(mid < nglob-1 && val >= (ulong)globals[mid+1]->value)
        !           690:                        bot = mid;
        !           691:                else
        !           692:                        return mid;
        !           693:        }
        !           694:        return -1;
        !           695: }
        !           696: /*
        !           697:  * Find symbol containing val in specified search space
        !           698:  * There is a special case when a value falls beyond the end
        !           699:  * of the text segment; if the search space is CTEXT, that value
        !           700:  * (usually etext) is returned.  If the search space is CANY, symbols in the
        !           701:  * data space are searched for a match.
        !           702:  */
        !           703: int
        !           704: findsym(long w, int type, Symbol *s)
        !           705: {
        !           706:        int i;
        !           707: 
        !           708:        if(buildtbls() == 0)
        !           709:                return 0;
        !           710: 
        !           711:        if(type == CTEXT || type == CANY) {
        !           712:                i = srchtext(w);
        !           713:                if(i >= 0) {
        !           714:                        if(type == CTEXT || i != ntxt-1) {
        !           715:                                fillsym(txt[i].sym, s);
        !           716:                                s->handle = (void *) &txt[i];
        !           717:                                return 1;
        !           718:                        }
        !           719:                }
        !           720:        }
        !           721:        if(type == CDATA || type == CANY) {
        !           722:                i = srchdata(w);
        !           723:                if(i >= 0) {
        !           724:                        fillsym(globals[i], s);
        !           725:                        return 1;
        !           726:                }
        !           727:        }
        !           728:        return 0;
        !           729: }
        !           730: 
        !           731: /*
        !           732:  *     Find the start and end address of the function containing addr
        !           733:  */
        !           734: int
        !           735: fnbound(long addr, ulong *bounds)
        !           736: {
        !           737:        int i;
        !           738: 
        !           739:        if(buildtbls() == 0)
        !           740:                return 0;
        !           741: 
        !           742:        i = srchtext(addr);
        !           743:        if(0 <= i && i < ntxt-1) {
        !           744:                bounds[0] = txt[i].sym->value;
        !           745:                bounds[1] = txt[i+1].sym->value;
        !           746:                return 1;
        !           747:        }
        !           748:        return 0;
        !           749: }
        !           750: 
        !           751: /*
        !           752:  * get the ith local symbol for a function
        !           753:  * the input symbol table is reverse ordered, so we reverse
        !           754:  * accesses here to maintain approx. parameter ordering in a stack trace.
        !           755:  */
        !           756: int
        !           757: localsym(Symbol *s, int index)
        !           758: {
        !           759:        Txtsym *tp;
        !           760: 
        !           761:        if(s == 0)
        !           762:                return 0;
        !           763:        if(buildtbls() == 0)
        !           764:                return 0;
        !           765: 
        !           766:        tp = (Txtsym *)s->handle;
        !           767:        if(tp && tp->locals && index < tp->n) {
        !           768:                fillsym(tp->locals[tp->n-index-1], s);  /* reverse */
        !           769:                s->handle = (void *)tp;
        !           770:                return 1;
        !           771:        }
        !           772:        return 0;
        !           773: }
        !           774: /*
        !           775:  * get the ith global symbol
        !           776:  */
        !           777: int
        !           778: globalsym(Symbol *s, int index)
        !           779: {
        !           780:        if(s == 0)
        !           781:                return 0;
        !           782:        if(buildtbls() == 0)
        !           783:                return 0;
        !           784: 
        !           785:        if(index < nglob) {
        !           786:                fillsym(globals[index], s);
        !           787:                return 1;
        !           788:        }
        !           789:        return 0;
        !           790: }
        !           791: /*
        !           792:  *     find the pc given a file name and line offset into it.
        !           793:  */
        !           794: long
        !           795: file2pc(char *file, ulong line)
        !           796: {
        !           797:        File *fp;
        !           798:        int i;
        !           799:        long pc;
        !           800:        ulong start, end;
        !           801:        short *name;
        !           802: 
        !           803:        if(buildtbls() == 0 || files == 0)
        !           804:                return -1;
        !           805:        name = encfname(file);
        !           806:        if(name == 0) {                 /* encode the file name */
        !           807:                werrstr("file %s not found", file);
        !           808:                return -1;
        !           809:        } 
        !           810:                /* find this history stack */
        !           811:        for(i = 0, fp = files; i < nfiles; i++, fp++)
        !           812:                if (hline(fp, name, &line))
        !           813:                        break;
        !           814:        free(name);
        !           815:        if(i >= nfiles) {
        !           816:                werrstr("line %d in file %s not found", line, file);
        !           817:                return -1;
        !           818:        }
        !           819:        start = fp->addr;               /* first text addr this file */
        !           820:        if(i < nfiles-1)
        !           821:                end = (fp+1)->addr;     /* first text addr next file */
        !           822:        else
        !           823:                end = 0;                /* last file in load module */
        !           824:        /*
        !           825:         * At this point, line contains the offset into the file.
        !           826:         * run the state machine to locate the pc closest to that value.
        !           827:         */
        !           828:        if(debug)
        !           829:                print("find pc for %d - between: %lux and %lux\n", line, start, end);
        !           830:        pc = line2addr(line, start, end);
        !           831:        if(pc == -1) {
        !           832:                werrstr("line %d not in file %s", line, file);
        !           833:                return -1;
        !           834:        }
        !           835:        return pc;
        !           836: }
        !           837: /*
        !           838:  *     search for a path component index
        !           839:  */
        !           840: static int
        !           841: pathcomp(char *s, int n)
        !           842: {
        !           843:        int i;
        !           844: 
        !           845:        for(i = 0; i <= fmax; i++)
        !           846:                if(fnames[i] && strncmp(s, fnames[i]->name, n) == 0)
        !           847:                        return i;
        !           848:        return -1;
        !           849: }
        !           850: /*
        !           851:  *     Encode a char file name as a sequence of short indices
        !           852:  *     into the file name dictionary.
        !           853:  */
        !           854: static short*
        !           855: encfname(char *file)
        !           856: {
        !           857:        int i, j;
        !           858:        char *cp, *cp2;
        !           859:        short *dest;
        !           860: 
        !           861:        if(*file == '/')        /* always check first '/' */
        !           862:                cp2 = file+1;
        !           863:        else {
        !           864:                cp2 = strchr(file, '/');
        !           865:                if(!cp2)
        !           866:                        cp2 = strchr(file, 0);
        !           867:        }
        !           868:        cp = file;
        !           869:        dest = 0;
        !           870:        for(i = 0; *cp; i++) {
        !           871:                j = pathcomp(cp, cp2-cp);
        !           872:                if(j < 0)
        !           873:                        return 0;       /* not found */
        !           874:                dest = realloc(dest, (i+1)*sizeof(short));
        !           875:                dest[i] = j;
        !           876:                cp = cp2;
        !           877:                while(*cp == '/')       /* skip embedded '/'s */
        !           878:                        cp++;
        !           879:                cp2 = strchr(cp, '/');
        !           880:                if(!cp2)
        !           881:                        cp2 = strchr(cp, 0);
        !           882:        }
        !           883:        dest = realloc(dest, (i+1)*sizeof(short));
        !           884:        dest[i] = 0;
        !           885:        return dest;
        !           886: }
        !           887: /*
        !           888:  *     Search a history stack for a matching file name accumulating
        !           889:  *     the size of intervening files in the stack.
        !           890:  */
        !           891: static int
        !           892: hline(File *fp, short *name, ulong *line)
        !           893: {
        !           894:        Hist *hp;
        !           895:        int offset, depth;
        !           896:        long ln;
        !           897: 
        !           898:        for(hp = fp->hist; hp->name; hp++)              /* find name in stack */
        !           899:                if(hp->name[1] || hp->name[2]) {
        !           900:                        if(hcomp(hp, name))
        !           901:                                break;
        !           902:                }
        !           903:        if(!hp->name)           /* match not found */
        !           904:                return 0;
        !           905:        if(debug)
        !           906:                printhist("hline found ... ", hp, 1);
        !           907:        /*
        !           908:         * unwind the stack until empty or we hit an entry beyond our line
        !           909:         */
        !           910:        ln = *line;
        !           911:        offset = hp->line-1;
        !           912:        depth = 1;
        !           913:        for(hp++; depth && hp->name; hp++) {
        !           914:                if(debug)
        !           915:                        printhist("hline inspect ... ", hp, 1);
        !           916:                if(hp->name[1] || hp->name[2]) {
        !           917:                        if(hp->offset){                 /* Z record */
        !           918:                                offset = 0;
        !           919:                                if(hcomp(hp, name)) {
        !           920:                                        if(*line <= hp->offset)
        !           921:                                                break;
        !           922:                                        ln = *line+hp->line-hp->offset;
        !           923:                                        depth = 1;      /* implicit pop */
        !           924:                                } else
        !           925:                                        depth = 2;      /* implicit push */
        !           926:                        } else if(depth == 1 && ln < hp->line-offset)
        !           927:                                        break;          /* Beyond our line */
        !           928:                        else if(depth++ == 1)           /* push */
        !           929:                                offset -= hp->line;
        !           930:                } else if(--depth == 1)         /* pop */
        !           931:                        offset += hp->line;     
        !           932:        }
        !           933:        *line = ln+offset;
        !           934:        return 1;
        !           935: }
        !           936: /*
        !           937:  *     compare two encoded file names
        !           938:  */
        !           939: static int
        !           940: hcomp(Hist *hp, short *sp)
        !           941: {
        !           942:        uchar *cp;
        !           943:        int i, j;
        !           944:        short *s;
        !           945: 
        !           946:        cp = (uchar *)hp->name;
        !           947:        s = sp;
        !           948:        if (*s == 0)
        !           949:                return 0;
        !           950:        for (i = 1; j = (cp[i]<<8)|cp[i+1]; i += 2) {
        !           951:                if(j == 0)
        !           952:                        break;
        !           953:                if(*s == j)
        !           954:                        s++;
        !           955:                else
        !           956:                        s = sp;
        !           957:        }
        !           958:        return *s == 0;
        !           959: }
        !           960: /*
        !           961:  *     Convert a pc to a "file:line {file:line}" string.
        !           962:  */
        !           963: int
        !           964: fileline(char *str, int n, ulong dot)
        !           965: {
        !           966:        long line;
        !           967:        int top, bot, mid;
        !           968:        File *f;
        !           969: 
        !           970:        *str = 0;
        !           971:        if(buildtbls() == 0)
        !           972:                return 0;
        !           973: 
        !           974:                /* binary search assumes file list is sorted by addr */
        !           975:        bot = 0;
        !           976:        top = nfiles;
        !           977:        for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
        !           978:                f = &files[mid];
        !           979:                if(dot < f->addr)
        !           980:                        top = mid;
        !           981:                else if(mid < nfiles-1 && dot >= (f+1)->addr)
        !           982:                        bot = mid;
        !           983:                else {
        !           984:                        line = pc2line(dot);
        !           985:                        if(line > 0 && fline(str, n, line, f->hist))
        !           986:                                return 1;
        !           987:                        break;
        !           988:                }
        !           989:        }
        !           990:        return 0;
        !           991: }
        !           992: 
        !           993: /*
        !           994:  *     Convert a line number within a composite file to relative line
        !           995:  *     number in a source file.  A composite file is the source
        !           996:  *     file with included files inserted in line.
        !           997:  */
        !           998: static Hist *
        !           999: fline(char *str, int n, long line, Hist *base)
        !          1000: {
        !          1001:        Hist *start;                    /* start of current level */
        !          1002:        Hist *h;                        /* current entry */
        !          1003:        int delta;                      /* sum of size of files this level */
        !          1004:        int k;
        !          1005: 
        !          1006:        start = base;
        !          1007:        h = base;
        !          1008:        delta = h->line;
        !          1009:        while(h && h->name && line > h->line) {
        !          1010:                if(h->name[1] || h->name[2]) {
        !          1011:                        if(h->offset != 0) {    /* #line Directive */
        !          1012:                                delta = h->line-h->offset+1;
        !          1013:                                start = h;
        !          1014:                                base = h++;
        !          1015:                        } else {                /* beginning of File */
        !          1016:                                if(start == base)
        !          1017:                                        start = h++;
        !          1018:                                else {
        !          1019:                                        h = fline(str, n, line, start);
        !          1020:                                        if(!h)
        !          1021:                                                break;
        !          1022:                                }
        !          1023:                        }
        !          1024:                } else {
        !          1025:                        if(start == base)       /* end of recursion level */
        !          1026:                                return h;
        !          1027:                        else {                  /* end of included file */
        !          1028:                                delta += h->line-start->line;
        !          1029:                                h++;
        !          1030:                                start = base;
        !          1031:                        }
        !          1032:                }
        !          1033:        }
        !          1034:        if(!h)
        !          1035:                return 0;
        !          1036:        if(start != base)
        !          1037:                line = line-start->line+1;
        !          1038:        else
        !          1039:                line = line-delta+1;
        !          1040:        if(!h->name)
        !          1041:                strncpy(str, "<eof>", n);
        !          1042:        else {
        !          1043:                k = fileelem(fnames, (uchar*)start->name, str, n);
        !          1044:                if(k+8 < n)
        !          1045:                        sprint(str+k, ":%ld", line);
        !          1046:        }
        !          1047: /**********Remove comments for complete back-trace of include sequence
        !          1048:  *     if(start != base) {
        !          1049:  *             k = strlen(str);
        !          1050:  *             if(k+2 < n) {
        !          1051:  *                     str[k++] = ' ';
        !          1052:  *                     str[k++] = '{';
        !          1053:  *             }
        !          1054:  *             k += fileelem(fnames, (uchar*) base->name, str+k, n-k);
        !          1055:  *             if(k+10 < n)
        !          1056:  *                     sprint(str+k, ":%ld}", start->line-delta);
        !          1057:  *     }
        !          1058:  ********************/
        !          1059:        return h;
        !          1060: }
        !          1061: /*
        !          1062:  *     convert an encoded file name to a string.
        !          1063:  */
        !          1064: int
        !          1065: fileelem(Sym **fp, uchar *cp, char *buf, int n)
        !          1066: {
        !          1067:        int i, j;
        !          1068:        char *c, *bp, *end;
        !          1069: 
        !          1070:        bp = buf;
        !          1071:        end = buf+n-1;
        !          1072:        for(i = 1; j = (cp[i]<<8)|cp[i+1]; i+=2){
        !          1073:                c = fp[j]->name;
        !          1074:                if(bp != buf && bp[-1] != '/' && bp < end)
        !          1075:                        *bp++ = '/';
        !          1076:                while(bp < end && *c)
        !          1077:                        *bp++ = *c++;
        !          1078:        }
        !          1079:        *bp = 0;
        !          1080:        return bp-buf;
        !          1081: }
        !          1082: /*
        !          1083:  *     compare the values of two symbol table entries.
        !          1084:  */
        !          1085: static int
        !          1086: symcomp(void *a, void *b)
        !          1087: {
        !          1088:        return (*(Sym**)a)->value - (*(Sym**)b)->value;
        !          1089: }
        !          1090: /*
        !          1091:  *     compare the values of the symbols referenced by two text table entries
        !          1092:  */
        !          1093: static int
        !          1094: txtcomp(void *a, void *b)
        !          1095: {
        !          1096:        return ((Txtsym*)a)->sym->value - ((Txtsym*)b)->sym->value;
        !          1097: }
        !          1098: /*
        !          1099:  *     compare the values of the symbols referenced by two file table entries
        !          1100:  */
        !          1101: static int
        !          1102: filecomp(void *a, void *b)
        !          1103: {
        !          1104:        return ((File*)a)->addr - ((File*)b)->addr;
        !          1105: }
        !          1106: /*
        !          1107:  *     fill an interface Symbol structure from a symbol table entry
        !          1108:  */
        !          1109: static void
        !          1110: fillsym(Sym *sp, Symbol *s)
        !          1111: {
        !          1112:        s->type = sp->type;
        !          1113:        s->value = sp->value;
        !          1114:        s->name = sp->name;
        !          1115:        switch(sp->type) {
        !          1116:        case 'b':
        !          1117:        case 'B':
        !          1118:        case 'D':
        !          1119:        case 'd':
        !          1120:                s->class = CDATA;
        !          1121:                break;
        !          1122:        case 't':
        !          1123:        case 'T':
        !          1124:        case 'l':
        !          1125:        case 'L':
        !          1126:                s->class = CTEXT;
        !          1127:                break;
        !          1128:        case 'a':
        !          1129:                s->class = CAUTO;
        !          1130:                break;
        !          1131:        case 'p':
        !          1132:                s->class = CPARAM;
        !          1133:                break;
        !          1134:        case 'm':
        !          1135:                s->class = CSTAB;
        !          1136:                break;
        !          1137:        default:
        !          1138:                s->class = CNONE;
        !          1139:                break;
        !          1140:        }
        !          1141:        s->handle = 0;
        !          1142: }
        !          1143: /*
        !          1144:  *     find the stack frame, given the pc
        !          1145:  */
        !          1146: long
        !          1147: pc2sp(ulong pc)
        !          1148: {
        !          1149:        uchar *c;
        !          1150:        uchar u;
        !          1151:        ulong currpc;
        !          1152:        long currsp;
        !          1153: 
        !          1154:        if(spoff == 0)
        !          1155:                return -1;
        !          1156:        currsp = 0;
        !          1157:        currpc = txtstart - mach->pcquant;
        !          1158: 
        !          1159:        if(pc<currpc || pc>txtend)
        !          1160:                return -1;
        !          1161:        for(c = spoff; c < spoffend; c++) {
        !          1162:                if (currpc >= pc)
        !          1163:                        return currsp;
        !          1164:                u = *c;
        !          1165:                if (u == 0) {
        !          1166:                        currsp += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
        !          1167:                        c += 4;
        !          1168:                }
        !          1169:                else if (u < 65)
        !          1170:                        currsp += 4*u;
        !          1171:                else if (u < 129)
        !          1172:                        currsp -= 4*(u-64);
        !          1173:                else 
        !          1174:                        currpc += mach->pcquant*(u-129);
        !          1175:                currpc += mach->pcquant;
        !          1176:        }
        !          1177:        return -1;
        !          1178: }
        !          1179: /*
        !          1180:  *     find the source file line number for a given value of the pc
        !          1181:  */
        !          1182: long
        !          1183: pc2line(ulong pc)
        !          1184: {
        !          1185:        uchar *c;
        !          1186:        uchar u;
        !          1187:        ulong currpc;
        !          1188:        long currline;
        !          1189: 
        !          1190:        if(pcline == 0)
        !          1191:                return -1;
        !          1192:        currline = 0;
        !          1193:        currpc = txtstart-mach->pcquant;
        !          1194:        if(pc<currpc || pc>txtend)
        !          1195:                return -1;
        !          1196: 
        !          1197:        for(c = pcline; c < pclineend; c++) {
        !          1198:                if(currpc >= pc)
        !          1199:                        return currline;
        !          1200:                u = *c;
        !          1201:                if(u == 0) {
        !          1202:                        currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
        !          1203:                        c += 4;
        !          1204:                }
        !          1205:                else if(u < 65)
        !          1206:                        currline += u;
        !          1207:                else if(u < 129)
        !          1208:                        currline -= (u-64);
        !          1209:                else 
        !          1210:                        currpc += mach->pcquant*(u-129);
        !          1211:                currpc += mach->pcquant;
        !          1212:        }
        !          1213:        return -1;
        !          1214: }
        !          1215: /*
        !          1216:  *     find the pc associated with a line number
        !          1217:  *     basepc and endpc are text addresses bounding the search.
        !          1218:  *     if endpc == 0, the end of the table is used (i.e., no upper bound).
        !          1219:  *     usually, basepc and endpc contain the first text address in
        !          1220:  *     a file and the first text address in the following file, respectively.
        !          1221:  */
        !          1222: long
        !          1223: line2addr(ulong line, ulong basepc, ulong endpc)
        !          1224: {
        !          1225:        uchar *c;
        !          1226:        uchar u;
        !          1227:        ulong currpc;
        !          1228:        long currline;
        !          1229:        long delta, d;
        !          1230:        long pc, found;
        !          1231: 
        !          1232:        if(pcline == 0 || line == 0)
        !          1233:                return -1;
        !          1234: 
        !          1235:        currline = 0;
        !          1236:        currpc = txtstart-mach->pcquant;
        !          1237:        pc = -1;
        !          1238:        found = 0;
        !          1239:        delta = HUGEINT;
        !          1240: 
        !          1241:        for(c = pcline; c < pclineend; c++) {
        !          1242:                if(endpc && currpc >= endpc)    /* end of file of interest */
        !          1243:                        break;
        !          1244:                if(currpc >= basepc) {          /* proper file */
        !          1245:                        if(currline >= line) {
        !          1246:                                d = currline-line;
        !          1247:                                found = 1;
        !          1248:                        } else
        !          1249:                                d = line-currline;
        !          1250:                        if(d < delta) {
        !          1251:                                delta = d;
        !          1252:                                pc = currpc;
        !          1253:                        }
        !          1254:                }
        !          1255:                u = *c;
        !          1256:                if(u == 0) {
        !          1257:                        currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
        !          1258:                        c += 4;
        !          1259:                }
        !          1260:                else if(u < 65)
        !          1261:                        currline += u;
        !          1262:                else if(u < 129)
        !          1263:                        currline -= (u-64);
        !          1264:                else 
        !          1265:                        currpc += mach->pcquant*(u-129);
        !          1266:                currpc += mach->pcquant;
        !          1267:        }
        !          1268:        if(found)
        !          1269:                return pc;
        !          1270:        return -1;
        !          1271: }
        !          1272: /*
        !          1273:  *     Print a history stack (debug). if count is 0, prints the whole stack
        !          1274:  */
        !          1275: void
        !          1276: printhist(char *msg, Hist *hp, int count)
        !          1277: {
        !          1278:        int i;
        !          1279:        uchar *cp;
        !          1280:        char buf[128];
        !          1281: 
        !          1282:        i = 0;
        !          1283:        while(hp->name) {
        !          1284:                if(count && ++i > count)
        !          1285:                        break;
        !          1286:                print("%s Line: %x (%d)  Offset: %x (%d)  Name: ", msg,
        !          1287:                        hp->line, hp->line, hp->offset, hp->offset);
        !          1288:                for(cp = (uchar *)hp->name+1; (*cp<<8)|cp[1]; cp += 2) {
        !          1289:                        if (cp != (uchar *)hp->name+1)
        !          1290:                                print("/");
        !          1291:                        print("%x", (*cp<<8)|cp[1]);
        !          1292:                }
        !          1293:                fileelem(fnames, (uchar *) hp->name, buf, sizeof(buf));
        !          1294:                print(" (%s)\n", buf);
        !          1295:                hp++;
        !          1296:        }
        !          1297: }
        !          1298: 
        !          1299: #ifdef DEBUG
        !          1300: /*
        !          1301:  *     print the history stack for a file. (debug only)
        !          1302:  *     if (name == 0) => print all history stacks.
        !          1303:  */
        !          1304: void
        !          1305: dumphist(char *name)
        !          1306: {
        !          1307:        int i;
        !          1308:        File *f;
        !          1309:        short *fname;
        !          1310: 
        !          1311:        if(buildtbls() == 0)
        !          1312:                return;
        !          1313:        if(name)
        !          1314:                fname = encfname(name);
        !          1315:        for(i = 0, f = files; i < nfiles; i++, f++)
        !          1316:                if(fname == 0 || hcomp(f->hist, fname))
        !          1317:                        printhist("> ", f->hist, f->n);
        !          1318: 
        !          1319:        if(fname)
        !          1320:                free(fname);
        !          1321: }
        !          1322: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.