hllsym.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,855 行 · 第 1/5 页

C
1,855
字号
    case 12:
        hash_base = cde->lfo + hdr->cbSymbol + hdr->cbSymHash + sizeof( *hdr );
        p = VMBlock( ii, hash_base, sizeof( unsigned_16 ) );
        if( p == NULL ) return( SR_FAIL );
        num_segs = *(unsigned_16 *)p;
        hash_base += 2 * sizeof( unsigned_16 );
        best.base = 0;
        best.off = *best_off;
        i = 0;
        for( ;; ) {
            if( i >= num_segs ) break;
            chk.mach.segment = i + 1;
            chk.mach.offset = 0;
            MapLogical( ii, &chk );
            if( DCSameAddrSpace( chk, a ) != DS_OK ) goto next_seg;
            p = VMBlock( ii, hash_base + i * sizeof( unsigned_32 ), sizeof( unsigned_32 ) );
            if( p == NULL ) return( SR_FAIL );
            curr.base = *(unsigned_32 *)p;
            base = hash_base + num_segs * sizeof( unsigned_32 );
            p = VMBlock( ii, base + i * sizeof( unsigned_32 ), sizeof( unsigned_32 ) );
            if( p == NULL ) return( SR_FAIL );
            offset_count = *(unsigned_32 *)p;
            if( offset_count == 0 ) goto next_seg;
            curr.base += base + num_segs * sizeof( unsigned_32 );
            //NYI: offsets are sorted, so we can binary search this sucker
            count = 0;
            for( ;; ) {
                if( count >= offset_count ) break;
                p = VMBlock( ii, curr.base + sizeof( unsigned_32 ), sizeof( unsigned_32 ) );
                if( p == NULL ) return( SR_FAIL );
                new_off = *(unsigned_32 *)p + chk.mach.offset;
                if( new_off >= a.mach.offset ) break;
                curr.off = new_off;
                curr.base += 2 * sizeof( unsigned_32 );
                ++count;
            }
            if( new_off == a.mach.offset ) {
                best.base = curr.base;
                best.off  = new_off;
                break;
            }
            if( count != 0
             && curr.off < a.mach.offset
             && (curr.off > best.off || best.base == 0 && best.off ==  0) ) {
                best.base = curr.base - 2 * sizeof( unsigned_32 );
                best.off = curr.off;
            }
next_seg:
            ++i;
        }
        if( best.base == 0 ) return( SR_NONE );
        p = VMBlock( ii, best.base, sizeof( unsigned_32 ) );
        if( p == NULL ) return( SR_FAIL );
        if( SymFillIn( ii, is, *(unsigned_32 *)p + cde->lfo + sizeof( *hdr ) ) != DS_OK ) {
            return( SR_FAIL );
        }
        *best_off = best.off;
        return( (best.off == a.mach.offset) ? SR_EXACT : SR_CLOSEST );
    default:
        //NYI: what to do when don't have hash function? */
        return( SR_NONE );
    }
}

static unsigned long CalcHash( char *name, unsigned len )
{
    unsigned_32         end;
    unsigned_32         sum;
    unsigned            i;

#define B_toupper( b )  ((b) & 0xdf)
#define D_toupper( d )  ((d) & 0xdfdfdfdf)

    end = 0;
    for( i = len & 0x3; i != 0; --i ) {
        end |= B_toupper( name[ len - 1 ] );
        end <<= 8;
        len -= 1;
    }
    len /= 4;
    sum = 0;
    for( i = 0; i < len; ++i ) {
        sum ^= D_toupper( *(unsigned_32 *)name );
        sum = _lrotl( sum, 4 );
        name += 4;
    }
    return( sum ^ end );
}

typedef search_result   SEARCH_CREATOR( imp_image_handle *, s_all *, imp_sym_handle *, void * );

static search_result TableSearchForName( imp_image_handle *ii,
                int case_sense, char *li_name, unsigned li_len,
                unsigned long hash, imp_sym_handle *is,
                SEARCH_CREATOR *create, void *d, unsigned tbl_type )
{
    cv_directory_entry          *cde;
    cv_sst_global_pub_header    *hdr;
    void                        *p;
    unsigned                    i;
    unsigned                    hash_buckets;
    virt_mem                    hash_base;
    virt_mem                    base;
    virt_mem                    sym_base;
    unsigned long               count;
    char                        *name;
    unsigned                    name_len;
    s_all                       *sp;
    search_result               sr;

    cde = FindDirEntry( ii, MH_GBL, tbl_type );
    if( cde == NULL ) return( SR_NONE );
    hdr = VMBlock( ii, cde->lfo, sizeof( *hdr ) );
    if( hdr == NULL ) return( SR_FAIL );
    switch( hdr->symhash ) {
    case 10:
        hash_base = cde->lfo + hdr->cbSymbol + sizeof( *hdr );
        p = VMBlock( ii, hash_base, sizeof( unsigned_16 ) );
        if( p == NULL ) return( SR_FAIL );
        hash_buckets = *(unsigned_16 *)p;
        i = hash % hash_buckets;
        hash_base += 2 * sizeof( unsigned_16 );
        p = VMBlock( ii, hash_base + i * sizeof( unsigned_32 ), sizeof( unsigned_32 ) );
        if( p == NULL ) return( SR_FAIL );
        sym_base = *(unsigned_32 *)p;
        base = hash_base + hash_buckets * sizeof( unsigned_32 );
        p = VMBlock( ii, base + i * sizeof( unsigned_32 ), sizeof( unsigned_32 ) );
        if( p == NULL ) return( SR_FAIL );
        sym_base += base + hash_buckets * sizeof( unsigned_32 );
        sr = SR_NONE;
        for( count = *(unsigned_32 *)p; count != 0; sym_base += 2*sizeof(unsigned_32), --count ) {
            p = VMBlock( ii, sym_base, 2 * sizeof( unsigned_32 ) );
            if( p == NULL ) return( SR_FAIL );
            if( ((unsigned_32 *)p)[1] != hash ) continue;
            if( SymFillIn( ii, is, *(unsigned_32 *)p + cde->lfo + sizeof( *hdr ) ) != DS_OK ) {
                return( SR_FAIL );
            }
            if( SymGetName( ii, is, &name, &name_len, &sp ) != DS_OK ) {
                return( SR_FAIL );
            }
            if( name_len != li_len ) continue;
            if( case_sense ) {
                if( memcmp( li_name, name, name_len ) != 0 ) continue;
            } else {
                if( memicmp( li_name, name, name_len ) != 0 ) continue;
            }
            /* Got one! */
            switch( create( ii, sp, is, d ) ) {
            case SR_FAIL:
                return( SR_FAIL );
            case SR_CLOSEST:
                /* means we found one, but keep on going */
                sr = SR_EXACT;
                break;
            case SR_EXACT:
                return( SR_EXACT );
            }
        }
        return( sr );
    default:
        //NYI: What to do if don't have hash table
        return( SR_NONE );
    }
}

struct match_data {
    unsigned    idx;
};

static search_result MatchSym( imp_image_handle *ii, s_all *p,
                        imp_sym_handle *is, void *d )
{
    struct match_data   *md = d;

    is = is;
    if( md->idx != SymTypeIdx( ii, p ) ) return( SR_NONE );
    return( SR_EXACT );
}

dip_status SymFindMatchingSym( imp_image_handle *ii,
                char *name, unsigned len, unsigned idx, imp_sym_handle *is )
{
    unsigned long       hash;
    search_result       sr;
    struct match_data   data;

    data.idx = idx;
    hash = CalcHash( name, len );
    sr = TableSearchForName( ii, 1, name, len, hash, is, MatchSym, &data,
                sstStaticSym );
    switch( sr ) {
    case SR_FAIL:       return( DS_ERR|DS_FAIL );
    case SR_EXACT:      return( DS_OK );
    }
    sr = TableSearchForName( ii, 1, name, len, hash, is, MatchSym, &data,
                sstGlobalSym );
    switch( sr ) {
    case SR_FAIL:       return( DS_ERR|DS_FAIL );
    case SR_EXACT:      return( DS_OK );
    }
    return( DS_FAIL );
}

static walk_result TableWalkSym( imp_image_handle *ii, imp_sym_handle *is,
                        IMP_SYM_WKR *wk, void *d, unsigned tbl_type )
{
    cv_directory_entry          *cde;
    cv_sst_global_pub_header    *hdr;
    virt_mem                    base;
    virt_mem                    end;
    unsigned                    skip;
    s_all                       *p;
    walk_result                 wr;
    search_result               sr;
    address                     addr;
    imp_sym_handle              dummy;
    addr_off                    dummy_off;

    is->im = MH_GBL;
    cde = FindDirEntry( ii, MH_GBL, tbl_type );
    if( cde == NULL ) return( WR_CONTINUE );
    hdr = VMBlock( ii, cde->lfo, sizeof( *hdr ) );
    if( hdr == NULL ) return( WR_FAIL );
    base = cde->lfo + sizeof( *hdr );
    end = base + hdr->cbSymbol;
    while( base < end ) {
        p = VMRecord( ii, base );
        skip = p->common.length + sizeof( p->common.length );
        switch( p->common.code ) {
        case S_ALIGN:
        case S_PROCREF:
        case S_DATAREF:
            /* not interested */
            break;
        case S_PUB16:
        case S_PUB32:
            if( p->common.code == S_PUB16 ) {
                addr.mach.offset = p->pub16.f.offset;
                addr.mach.segment = p->pub16.f.segment;
            } else {
                addr.mach.offset = p->pub32.f.offset;
                addr.mach.segment = p->pub32.f.segment;
            }
            MapLogical( ii, &addr );
            dummy_off = 0;
            sr = TableSearchForAddr( ii, addr, &dummy, &dummy_off, sstGlobalSym );
            if( sr == SR_FAIL ) return( WR_FAIL );
            if( sr == SR_EXACT ) break;
            /* fall through */
        default:
            if( SymFillIn( ii, is, base ) != DS_OK ) return( WR_FAIL );
            wr = wk( ii, SWI_SYMBOL, is, d );
            if( wr != WR_CONTINUE ) return( wr );
            break;

        }
        base += skip;
    }
    return( WR_CONTINUE );
}

struct glue_info {
    IMP_SYM_WKR         *wk;
    void                *d;
    imp_sym_handle      *is;
};

static walk_result WalkGlue( imp_image_handle *ii, sym_walk_info swi,
                                imp_sym_handle *is, void *d )
{
    struct glue_info *gd = d;

    if( is == NULL ) return( gd->wk( ii, swi, NULL, gd->d ) );
    *gd->is = *is;
    return( gd->wk( ii, swi, gd->is, gd->d ) );
}

static walk_result WalkAModule( imp_image_handle *ii,
                                hll_debug_dir *hdd, void *d )
{
    if( hdd->subsection != hll_sstModules ) return( WR_CONTINUE );
    return( ScopeWalkFile( ii, hdd->iMod, WalkGlue, d ) );
}

walk_result     DoWalkSymList( imp_image_handle *ii,
                symbol_source ss, void *source, IMP_SYM_WKR *wk,
                imp_sym_handle *is, void *d )
{
    struct glue_info    glue;
    imp_mod_handle      im;
    scope_block         *sc_block;
    s_all               *p;
    scope_info          sc_info;
    dip_status          ds;
    walk_result         wr;
    imp_type_handle     it;

    glue.wk = wk;
    glue.is = is;
    glue.d  = d;
    switch( ss ) {
    case SS_MODULE:
        im = *(imp_mod_handle *)source;
        if( im == (imp_mod_handle)NO_MOD ) {
            wr = WalkDirList( ii, &WalkAModule, &glue );
            if( wr != WR_CONTINUE ) return( wr );
            im = MH_GBL;
        }
        if( im == MH_GBL ) {
            wr = TableWalkSym( ii, is, wk, d, sstGlobalSym );
            if( wr != WR_CONTINUE ) return( wr );
            return( TableWalkSym( ii, is, wk, d, sstGlobalPub ) );
        }
        return( ScopeWalkFile( ii, im, WalkGlue, &glue ) );
    case SS_SCOPED:
        if( ImpAddrMod( ii, *(address *)source, &im ) == SR_NONE ) {
            return( WR_CONTINUE );
        }
        return( ScopeWalkAll( ii, im, *(address *)source, &WalkGlue, &glue ) );
    case SS_BLOCK:
        sc_block = source;
        if( ImpAddrMod( ii, sc_block->start, &im ) == SR_NONE ) {
            return( WR_CONTINUE );
        }
        sc_info.cde = FindDirEntry( ii, im, sstAlignSym );
        if( sc_info.cde == NULL ) return( WR_FAIL );
        ds = ScopeFillIn( ii, sc_block->unique & SCOPE_UNIQUE_MASK,
                                &sc_info, &p );
        if( ds & DS_ERR ) return( WR_FAIL );
        if( ds != DS_OK ) return( WR_CONTINUE );
        if( sc_block->unique & SCOPE_CLASS_FLAG ) {
            /* Walk the member function class scope */
            ds = TypeIndexFillIn( ii, SymTypeIdx( ii, p ), &it );
            if( ds & DS_ERR ) return( WR_FAIL );
            if( ds != DS_OK ) return( WR_CONTINUE );
            ds = TypeMemberFuncInfo( ii, &it, &it, NULL, NULL );
            if( ds & DS_ERR ) return( WR_FAIL );
            if( ds != DS_OK ) return( WR_CONTINUE );
            return( TypeSymWalkList( ii, &it, wk, is, d ) );
        } else {
            return( ScopeWalkOne( ii, &sc_info, WalkGlue, &glue ) );
        }
    case SS_TYPE:
        return( TypeSymWalkList( ii, (imp_type_handle *)source, wk, is, d ) );
    }
    return( WR_FAIL );
}

walk_result     DIPENTRY DIPImpWalkSymList( imp_image_handle *ii,
                symbol_source ss, void *source, IMP_SYM_WKR *wk,
                imp_sym_handle *is, void *d )
{
    return( DoWalkSymList( ii, ss, source, wk, is, d ) );
}

walk_result DIPENTRY DIPImpWalkSymListEx( imp_image_handle *ii, symbol_source ss,
                void *source, IMP_SYM_WKR *wk, imp_sym_handle *is,
                location_context *lc, void *d )
{
    lc=lc;
    return( DoWalkSymList( ii, ss, source, wk, is, d ) );
}


imp_mod_handle  DIPENTRY DIPImpSymMod( imp_image_handle *ii,
                        imp_sym_handle *is )
{
    ii = ii;
    return( is->im );
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?