[BACK]Return to db_sym.c CVS log [TXT][DIR] Up to [local] / sys / ddb

Annotation of sys/ddb/db_sym.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: db_sym.c,v 1.32 2006/03/13 06:23:20 jsg Exp $ */
        !             2: /*     $NetBSD: db_sym.c,v 1.24 2000/08/11 22:50:47 tv Exp $   */
        !             3:
        !             4: /*
        !             5:  * Mach Operating System
        !             6:  * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
        !             7:  * All Rights Reserved.
        !             8:  *
        !             9:  * Permission to use, copy, modify and distribute this software and its
        !            10:  * documentation is hereby granted, provided that both the copyright
        !            11:  * notice and this permission notice appear in all copies of the
        !            12:  * software, derivative works or modified versions, and any portions
        !            13:  * thereof, and that both notices appear in supporting documentation.
        !            14:  *
        !            15:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            16:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            17:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            18:  *
        !            19:  * Carnegie Mellon requests users of this software to return to
        !            20:  *
        !            21:  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
        !            22:  *  School of Computer Science
        !            23:  *  Carnegie Mellon University
        !            24:  *  Pittsburgh PA 15213-3890
        !            25:  *
        !            26:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            27:  * the rights to redistribute these changes.
        !            28:  */
        !            29:
        !            30: #include <sys/param.h>
        !            31: #include <sys/proc.h>
        !            32: #include <sys/systm.h>
        !            33:
        !            34: #include <machine/db_machdep.h>
        !            35:
        !            36: #include <ddb/db_lex.h>
        !            37: #include <ddb/db_sym.h>
        !            38: #include <ddb/db_output.h>
        !            39: #include <ddb/db_extern.h>
        !            40: #include <ddb/db_command.h>
        !            41:
        !            42: /*
        !            43:  * Multiple symbol tables
        !            44:  */
        !            45: #ifndef MAXLKMS
        !            46: #define MAXLKMS 20
        !            47: #endif
        !            48:
        !            49: #ifndef MAXNOSYMTABS
        !            50: #define        MAXNOSYMTABS    MAXLKMS+1       /* Room for kernel + LKM's */
        !            51: #endif
        !            52:
        !            53: db_symtab_t    db_symtabs[MAXNOSYMTABS] = {{0,},};
        !            54:
        !            55: db_symtab_t    *db_last_symtab;
        !            56:
        !            57: static db_forall_func_t db_sift;
        !            58:
        !            59: extern char end[];
        !            60:
        !            61: /*
        !            62:  * Put the most picky symbol table formats at the top!
        !            63:  */
        !            64: const db_symformat_t *db_symformats[] = {
        !            65: #ifdef DB_ELF_SYMBOLS
        !            66:        &db_symformat_elf,
        !            67: #endif
        !            68: #ifdef DB_AOUT_SYMBOLS
        !            69:        &db_symformat_aout,
        !            70: #endif
        !            71:        NULL,
        !            72: };
        !            73:
        !            74: const db_symformat_t *db_symformat;
        !            75:
        !            76: boolean_t      X_db_sym_init(int, void *, void *, const char *);
        !            77: db_sym_t       X_db_lookup(db_symtab_t *, char *);
        !            78: db_sym_t       X_db_search_symbol(db_symtab_t *, db_addr_t,
        !            79:                    db_strategy_t, db_expr_t *);
        !            80: void           X_db_symbol_values(db_symtab_t *, db_sym_t, char **,
        !            81:                    db_expr_t *);
        !            82: boolean_t      X_db_line_at_pc(db_symtab_t *, db_sym_t, char **,
        !            83:                    int *, db_expr_t);
        !            84: int            X_db_sym_numargs(db_symtab_t *, db_sym_t, int *,
        !            85:                    char **);
        !            86:
        !            87: /*
        !            88:  * Initialize the kernel debugger by initializing the master symbol
        !            89:  * table.  Note that if initializing the master symbol table fails,
        !            90:  * no other symbol tables can be loaded.
        !            91:  */
        !            92: #if 0
        !            93: void
        !            94: ddb_init(int symsize, void *vss, void *vse)
        !            95: {
        !            96:        const db_symformat_t **symf;
        !            97:        const char *name = "bsd";
        !            98:
        !            99:        if (symsize <= 0) {
        !           100:                printf(" [ no symbols available ]\n");
        !           101:                return;
        !           102:        }
        !           103:
        !           104:        /*
        !           105:         * Do this check now for the master symbol table to avoid printing
        !           106:         * the message N times.
        !           107:         */
        !           108:        if (ALIGNED_POINTER(vss, long) == 0) {
        !           109:                printf("[ %s symbol table has bad start address %p ]\n",
        !           110:                    name, vss);
        !           111:                return;
        !           112:        }
        !           113:
        !           114:        for (symf = db_symformats; *symf != NULL; symf++) {
        !           115:                db_symformat = *symf;
        !           116:                if (X_db_sym_init(symsize, vss, vse, name) == TRUE)
        !           117:                        return;
        !           118:        }
        !           119:
        !           120:        db_symformat = NULL;
        !           121:        printf("[ no symbol table formats found ]\n");
        !           122: }
        !           123: #else
        !           124: void
        !           125: ddb_init(void)
        !           126: {
        !           127:        const db_symformat_t **symf;
        !           128:        const char *name = "bsd";
        !           129:        extern char *esym;
        !           130: #if defined(__sparc64__) || defined(__mips__)
        !           131:        extern char *ssym;
        !           132: #endif
        !           133:        char *xssym, *xesym;
        !           134:
        !           135:        xesym = esym;
        !           136: #if defined(__sparc64__) || defined(__mips__)
        !           137:        xssym = ssym;
        !           138: #else
        !           139:        xssym = (char *)&end;
        !           140: #endif
        !           141:        /*
        !           142:         * Do this check now for the master symbol table to avoid printing
        !           143:         * the message N times.
        !           144:         */
        !           145:        if ((((vaddr_t)xssym) & (sizeof(long) - 1)) != 0) {
        !           146:                printf("[ %s symbol table has bad start address %p ]\n",
        !           147:                    name, xssym);
        !           148:                return;
        !           149:        }
        !           150:
        !           151:        if (xesym != NULL && xesym != xssym)
        !           152:                for (symf = db_symformats; *symf != NULL; symf++) {
        !           153:                        db_symformat = *symf;
        !           154:                        if (X_db_sym_init((vaddr_t)xesym - (vaddr_t)xssym,
        !           155:                            xssym, xesym, name) == TRUE)
        !           156:                        return;
        !           157:                }
        !           158:
        !           159:        db_symformat = NULL;
        !           160:        printf("[ no symbol table formats found ]\n");
        !           161: }
        !           162: #endif
        !           163:
        !           164: /*
        !           165:  * Add symbol table, with given name, to list of symbol tables.
        !           166:  */
        !           167: int
        !           168: db_add_symbol_table(char *start, char *end, const char *name, char *ref)
        !           169: {
        !           170:        int slot;
        !           171:
        !           172:        for (slot = 0; slot < MAXNOSYMTABS; slot++) {
        !           173:                if (db_symtabs[slot].name == NULL)
        !           174:                        break;
        !           175:        }
        !           176:        if (slot >= MAXNOSYMTABS) {
        !           177:                db_printf("No slots left for %s symbol table", name);
        !           178:                return(-1);
        !           179:        }
        !           180:
        !           181:        db_symtabs[slot].start = start;
        !           182:        db_symtabs[slot].end = end;
        !           183:        db_symtabs[slot].name = name;
        !           184:        db_symtabs[slot].private = ref;
        !           185:
        !           186:        return(slot);
        !           187: }
        !           188:
        !           189: /*
        !           190:  * Delete a symbol table. Caller is responsible for freeing storage.
        !           191:  */
        !           192: void
        !           193: db_del_symbol_table(char *name)
        !           194: {
        !           195:        int slot;
        !           196:
        !           197:        for (slot = 0; slot < MAXNOSYMTABS; slot++) {
        !           198:                if (db_symtabs[slot].name &&
        !           199:                    ! strcmp(db_symtabs[slot].name, name))
        !           200:                        break;
        !           201:        }
        !           202:        if (slot >= MAXNOSYMTABS) {
        !           203:                db_printf("Unable to find symbol table slot for %s.", name);
        !           204:                return;
        !           205:        }
        !           206:
        !           207:        db_symtabs[slot].start = 0;
        !           208:        db_symtabs[slot].end = 0;
        !           209:        db_symtabs[slot].name = 0;
        !           210:        db_symtabs[slot].private = 0;
        !           211: }
        !           212:
        !           213: /*
        !           214:  *  db_qualify("vm_map", "bsd") returns "bsd:vm_map".
        !           215:  *
        !           216:  *  Note: return value points to static data whose content is
        !           217:  *  overwritten by each call... but in practice this seems okay.
        !           218:  */
        !           219: char *
        !           220: db_qualify(db_sym_t sym, const char *symtabname)
        !           221: {
        !           222:        char            *symname;
        !           223:        static char     tmp[256];
        !           224:        char    *s;
        !           225:
        !           226:        db_symbol_values(sym, &symname, 0);
        !           227:        s = tmp;
        !           228:        while ((*s++ = *symtabname++) != '\0')
        !           229:                ;
        !           230:        s[-1] = ':';
        !           231:        while ((*s++ = *symname++) != '\0')
        !           232:                ;
        !           233:        return tmp;
        !           234: }
        !           235:
        !           236:
        !           237: boolean_t
        !           238: db_eqname(char *src, char *dst, int c)
        !           239: {
        !           240:        if (!strcmp(src, dst))
        !           241:            return (TRUE);
        !           242:        if (src[0] == c)
        !           243:            return (!strcmp(src+1,dst));
        !           244:        return (FALSE);
        !           245: }
        !           246:
        !           247: boolean_t
        !           248: db_value_of_name(char *name, db_expr_t *valuep)
        !           249: {
        !           250:        db_sym_t        sym;
        !           251:
        !           252:        sym = db_lookup(name);
        !           253:        if (sym == DB_SYM_NULL)
        !           254:            return (FALSE);
        !           255:        db_symbol_values(sym, &name, valuep);
        !           256:        return (TRUE);
        !           257: }
        !           258:
        !           259:
        !           260: /*
        !           261:  * Lookup a symbol.
        !           262:  * If the symbol has a qualifier (e.g., ux:vm_map),
        !           263:  * then only the specified symbol table will be searched;
        !           264:  * otherwise, all symbol tables will be searched.
        !           265:  */
        !           266: db_sym_t
        !           267: db_lookup(char *symstr)
        !           268: {
        !           269:        db_sym_t sp;
        !           270:        int i;
        !           271:        int symtab_start = 0;
        !           272:        int symtab_end = MAXNOSYMTABS;
        !           273:        char *cp;
        !           274:
        !           275:        /*
        !           276:         * Look for, remove, and remember any symbol table specifier.
        !           277:         */
        !           278:        for (cp = symstr; *cp; cp++) {
        !           279:                if (*cp == ':') {
        !           280:                        *cp = '\0';
        !           281:                        for (i = 0; i < MAXNOSYMTABS; i++) {
        !           282:                                if (db_symtabs[i].name &&
        !           283:                                    ! strcmp(symstr, db_symtabs[i].name)) {
        !           284:                                        symtab_start = i;
        !           285:                                        symtab_end = i + 1;
        !           286:                                        break;
        !           287:                                }
        !           288:                        }
        !           289:                        *cp = ':';
        !           290:                        if (i == MAXNOSYMTABS) {
        !           291:                                db_error("invalid symbol table name");
        !           292:                                /*NOTREACHED*/
        !           293:                        }
        !           294:                        symstr = cp+1;
        !           295:                }
        !           296:        }
        !           297:
        !           298:        /*
        !           299:         * Look in the specified set of symbol tables.
        !           300:         * Return on first match.
        !           301:         */
        !           302:        for (i = symtab_start; i < symtab_end; i++) {
        !           303:                if (db_symtabs[i].name &&
        !           304:                    (sp = X_db_lookup(&db_symtabs[i], symstr))) {
        !           305:                        db_last_symtab = &db_symtabs[i];
        !           306:                        return sp;
        !           307:                }
        !           308:        }
        !           309:        return 0;
        !           310: }
        !           311:
        !           312: /* Private structure for passing args to db_sift() from db_sifting(). */
        !           313: struct db_sift_args {
        !           314:        char    *symstr;
        !           315:        int     mode;
        !           316: };
        !           317:
        !           318: /*
        !           319:  * Does the work of db_sifting(), called once for each
        !           320:  * symbol via X_db_forall(), prints out symbols matching
        !           321:  * criteria.
        !           322:  */
        !           323: static void
        !           324: db_sift(db_symtab_t *stab, db_sym_t sym, char *name, char *suffix, int prefix,
        !           325:     void *arg)
        !           326: {
        !           327:        char c, sc;
        !           328:        char *find, *p;
        !           329:        size_t len;
        !           330:        struct db_sift_args *dsa;
        !           331:
        !           332:        dsa = (struct db_sift_args*)arg;
        !           333:
        !           334:        find = dsa->symstr;     /* String we're looking for. */
        !           335:        p = name;               /* String we're searching within. */
        !           336:
        !           337:        /* Matching algorithm cribbed from strstr(), which is not
        !           338:           in the kernel. */
        !           339:        if ((c = *find++) != 0) {
        !           340:                len = strlen(find);
        !           341:                do {
        !           342:                        do {
        !           343:                                if ((sc = *p++) == 0)
        !           344:                                        return;
        !           345:                        } while (sc != c);
        !           346:                } while (strncmp(p, find, len) != 0);
        !           347:        }
        !           348:        if (dsa->mode=='F')     /* ala ls -F */
        !           349:                db_printf("%s%s ", name, suffix);
        !           350:        else
        !           351:                db_printf("%s ", name);
        !           352: }
        !           353:
        !           354: /*
        !           355:  * "Sift" for a partial symbol.
        !           356:  * Named for the Sun OpenPROM command ("sifting").
        !           357:  * If the symbol has a qualifier (e.g., ux:vm_map),
        !           358:  * then only the specified symbol table will be searched;
        !           359:  * otherwise, all symbol tables will be searched..
        !           360:  *
        !           361:  * "mode" is how-to-display, set from modifiers.
        !           362:  */
        !           363: void
        !           364: db_sifting(char *symstr, int mode)
        !           365: {
        !           366:        char *cp;
        !           367:        int i;
        !           368:        int symtab_start = 0;
        !           369:        int symtab_end = MAXNOSYMTABS;
        !           370:        struct db_sift_args dsa;
        !           371:
        !           372:        /*
        !           373:         * Look for, remove, and remember any symbol table specifier.
        !           374:         */
        !           375:        for (cp = symstr; *cp; cp++) {
        !           376:                if (*cp == ':') {
        !           377:                        *cp = '\0';
        !           378:                        for (i = 0; i < MAXNOSYMTABS; i++) {
        !           379:                                if (db_symtabs[i].name &&
        !           380:                                    ! strcmp(symstr, db_symtabs[i].name)) {
        !           381:                                        symtab_start = i;
        !           382:                                        symtab_end = i + 1;
        !           383:                                        break;
        !           384:                                }
        !           385:                        }
        !           386:                        *cp = ':';
        !           387:                        if (i == MAXNOSYMTABS) {
        !           388:                                db_error("invalid symbol table name");
        !           389:                                /*NOTREACHED*/
        !           390:                        }
        !           391:                        symstr = cp+1;
        !           392:                }
        !           393:        }
        !           394:
        !           395:        /* Pass args to db_sift(). */
        !           396:        dsa.symstr = symstr;
        !           397:        dsa.mode = mode;
        !           398:
        !           399:        /*
        !           400:         * Look in the specified set of symbol tables.
        !           401:         */
        !           402:        for (i = symtab_start; i < symtab_end; i++)
        !           403:                if (db_symtabs[i].name) {
        !           404:                        db_printf("Sifting table %s:\n", db_symtabs[i].name);
        !           405:                        X_db_forall(&db_symtabs[i], db_sift, &dsa);
        !           406:                }
        !           407:
        !           408:        return;
        !           409: }
        !           410:
        !           411:
        !           412: /*
        !           413:  * Does this symbol name appear in more than one symbol table?
        !           414:  * Used by db_symbol_values to decide whether to qualify a symbol.
        !           415:  */
        !           416: boolean_t db_qualify_ambiguous_names = FALSE;
        !           417:
        !           418: boolean_t
        !           419: db_symbol_is_ambiguous(db_sym_t sym)
        !           420: {
        !           421:        char            *sym_name;
        !           422:        int     i;
        !           423:        boolean_t       found_once = FALSE;
        !           424:
        !           425:        if (!db_qualify_ambiguous_names)
        !           426:                return FALSE;
        !           427:
        !           428:        db_symbol_values(sym, &sym_name, 0);
        !           429:        for (i = 0; i < MAXNOSYMTABS; i++) {
        !           430:                if (db_symtabs[i].name &&
        !           431:                    X_db_lookup(&db_symtabs[i], sym_name)) {
        !           432:                        if (found_once)
        !           433:                                return TRUE;
        !           434:                        found_once = TRUE;
        !           435:                }
        !           436:        }
        !           437:        return FALSE;
        !           438: }
        !           439:
        !           440: /*
        !           441:  * Find the closest symbol to val, and return its name
        !           442:  * and the difference between val and the symbol found.
        !           443:  */
        !           444: db_sym_t
        !           445: db_search_symbol(db_addr_t val, db_strategy_t strategy, db_expr_t *offp)
        !           446: {
        !           447:        unsigned int    diff;
        !           448:        db_expr_t       newdiff;
        !           449:        int             i;
        !           450:        db_sym_t        ret = DB_SYM_NULL, sym;
        !           451:
        !           452:        newdiff = diff = ~0;
        !           453:        db_last_symtab = 0;
        !           454:        for (i = 0; i < MAXNOSYMTABS; i++) {
        !           455:            if (!db_symtabs[i].name)
        !           456:                continue;
        !           457:            sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff);
        !           458:            if (newdiff < diff) {
        !           459:                db_last_symtab = &db_symtabs[i];
        !           460:                diff = newdiff;
        !           461:                ret = sym;
        !           462:            }
        !           463:        }
        !           464:        *offp = diff;
        !           465:        return ret;
        !           466: }
        !           467:
        !           468: /*
        !           469:  * Return name and value of a symbol
        !           470:  */
        !           471: void
        !           472: db_symbol_values(db_sym_t sym, char **namep, db_expr_t *valuep)
        !           473: {
        !           474:        db_expr_t       value;
        !           475:
        !           476:        if (sym == DB_SYM_NULL) {
        !           477:                *namep = 0;
        !           478:                return;
        !           479:        }
        !           480:
        !           481:        X_db_symbol_values(db_last_symtab, sym, namep, &value);
        !           482:
        !           483:        if (db_symbol_is_ambiguous(sym))
        !           484:                *namep = db_qualify(sym, db_last_symtab->name);
        !           485:        if (valuep)
        !           486:                *valuep = value;
        !           487: }
        !           488:
        !           489:
        !           490: /*
        !           491:  * Print a the closest symbol to value
        !           492:  *
        !           493:  * After matching the symbol according to the given strategy
        !           494:  * we print it in the name+offset format, provided the symbol's
        !           495:  * value is close enough (eg smaller than db_maxoff).
        !           496:  * We also attempt to print [filename:linenum] when applicable
        !           497:  * (eg for procedure names).
        !           498:  *
        !           499:  * If we could not find a reasonable name+offset representation,
        !           500:  * then we just print the value in hex.  Small values might get
        !           501:  * bogus symbol associations, e.g. 3 might get some absolute
        !           502:  * value like _INCLUDE_VERSION or something, therefore we do
        !           503:  * not accept symbols whose value is zero (and use plain hex).
        !           504:  * Also, avoid printing as "end+0x????" which is useless.
        !           505:  * The variable db_lastsym is used instead of "end" in case we
        !           506:  * add support for symbols in loadable driver modules.
        !           507:  */
        !           508: unsigned long  db_lastsym = (unsigned long)end;
        !           509: unsigned int   db_maxoff = 0x10000000;
        !           510:
        !           511:
        !           512: void
        !           513: db_printsym(db_expr_t off, db_strategy_t strategy,
        !           514:     int (*pr)(const char *, ...))
        !           515: {
        !           516:        db_expr_t       d;
        !           517:        char            *filename;
        !           518:        char            *name;
        !           519:        db_expr_t       value;
        !           520:        int             linenum;
        !           521:        db_sym_t        cursym;
        !           522:        char            buf[DB_FORMAT_BUF_SIZE];
        !           523:
        !           524:        if (off <= db_lastsym) {
        !           525:                cursym = db_search_symbol(off, strategy, &d);
        !           526:                db_symbol_values(cursym, &name, &value);
        !           527:                if (name && (d < db_maxoff) && value) {
        !           528:                        (*pr)("%s", name);
        !           529:                        if (d) {
        !           530:                                (*pr)("+%s", db_format(buf, sizeof(buf),
        !           531:                                    d, DB_FORMAT_R, 1, 0));
        !           532:                        }
        !           533:                        if (strategy == DB_STGY_PROC) {
        !           534:                                if (db_line_at_pc(cursym, &filename, &linenum, off))
        !           535:                                        (*pr)(" [%s:%d]", filename, linenum);
        !           536:                        }
        !           537:                        return;
        !           538:                }
        !           539:        }
        !           540:
        !           541:        (*pr)("%s", db_format(buf, sizeof(buf), off, DB_FORMAT_N, 1, 0));
        !           542:        return;
        !           543: }
        !           544:
        !           545:
        !           546: boolean_t
        !           547: db_line_at_pc(db_sym_t sym, char **filename, int *linenum, db_expr_t pc)
        !           548: {
        !           549:        return X_db_line_at_pc(db_last_symtab, sym, filename, linenum, pc);
        !           550: }
        !           551:
        !           552: int
        !           553: db_sym_numargs(db_sym_t sym, int *nargp, char **argnames)
        !           554: {
        !           555:        return X_db_sym_numargs(db_last_symtab, sym, nargp, argnames);
        !           556: }
        !           557:
        !           558: boolean_t
        !           559: X_db_sym_init(int symsize, void *vss, void *vse, const char *name)
        !           560: {
        !           561:
        !           562:        if (db_symformat != NULL)
        !           563:                return ((*db_symformat->sym_init)(symsize, vss, vse, name));
        !           564:        return (FALSE);
        !           565: }
        !           566:
        !           567: db_sym_t
        !           568: X_db_lookup(db_symtab_t *stab, char *symstr)
        !           569: {
        !           570:
        !           571:        if (db_symformat != NULL)
        !           572:                return ((*db_symformat->sym_lookup)(stab, symstr));
        !           573:        return ((db_sym_t)0);
        !           574: }
        !           575:
        !           576: db_sym_t
        !           577: X_db_search_symbol(db_symtab_t *stab, db_addr_t off, db_strategy_t strategy,
        !           578:     db_expr_t *diffp)
        !           579: {
        !           580:
        !           581:        if (db_symformat != NULL)
        !           582:                return ((*db_symformat->sym_search)(stab, off, strategy,
        !           583:                    diffp));
        !           584:        return ((db_sym_t)0);
        !           585: }
        !           586:
        !           587: void
        !           588: X_db_symbol_values(db_symtab_t *stab, db_sym_t sym, char **namep,
        !           589:     db_expr_t *valuep)
        !           590: {
        !           591:
        !           592:        if (db_symformat != NULL)
        !           593:                (*db_symformat->sym_value)(stab, sym, namep, valuep);
        !           594: }
        !           595:
        !           596: boolean_t
        !           597: X_db_line_at_pc(db_symtab_t *stab, db_sym_t cursym, char **filename,
        !           598:     int *linenum, db_expr_t off)
        !           599: {
        !           600:
        !           601:        if (db_symformat != NULL)
        !           602:                return ((*db_symformat->sym_line_at_pc)(stab, cursym,
        !           603:                    filename, linenum, off));
        !           604:        return (FALSE);
        !           605: }
        !           606:
        !           607: boolean_t
        !           608: X_db_sym_numargs(db_symtab_t *stab, db_sym_t cursym, int *nargp,
        !           609:     char **argnamep)
        !           610: {
        !           611:
        !           612:        if (db_symformat != NULL)
        !           613:                return ((*db_symformat->sym_numargs)(stab, cursym, nargp,
        !           614:                    argnamep));
        !           615:        return (FALSE);
        !           616: }
        !           617:
        !           618: void
        !           619: X_db_forall(db_symtab_t *stab, db_forall_func_t db_forall_func, void *arg)
        !           620: {
        !           621:        if (db_symformat != NULL)
        !           622:                (*db_symformat->sym_forall)(stab, db_forall_func, arg);
        !           623: }

CVSweb