/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include <string.h>
#include "dfdip.h"
#include "dfld.h"
#include "dfmod.h"
#include "dfmodinf.h"
#include "dfaddr.h"
#include "dfaddsym.h"
#include "dftype.h"
#include "dfloc.h"
#include "dfscope.h"
#include "dfhash.h"
#include "demangle.h"
#include "dfsym.h"

imp_mod_handle  DIPENTRY DIPImpSymMod( imp_image_handle *ii,
                        imp_sym_handle *is )
{
    /*
        Return the module that the implementation symbol handle comes from.
    */
    imp_mod_handle im;

    ii = ii;
    im = IMX2IM( is->imx );
    return( im );
}

unsigned        DIPENTRY DIPImpSymName( imp_image_handle *ii,
                        imp_sym_handle *is, location_context *lc,
                        symbol_name sn, char *buff, unsigned max )
{
    /*

        SN_SOURCE:
                The name of the symbol as it appears in the source code.

        SN_OBJECT:
                The name of the symbol as it appeared to the linker.

        SN_DEMANGLED:
                C++ names, with full typing (essentially it looks like
                a function prototype). If the symbol is not a C++ symbol
                (not mangled), return zero for the length.

        SN_EXPRESSION:
                Return whatever character string is necessary such that
                when scanned in an expression, the symbol handle can
                be reconstructed.

        SS_BLOCK:
                Not possible. Will never happen.
    */
    char        *name;
    unsigned    len, demangled_len;

    lc = lc;
//TODO: whats lc for
    DRSetDebug( ii->dwarf->handle ); /* must do at each call into dwarf */
    switch( sn ){
    case SN_SOURCE:
    case SN_OBJECT:
        len =  DRGetNameBuff( is->sym, buff, max );
        if( len == 0 ){
            DCStatus( DS_FAIL );
            return( 0 );
        }
        --len;
        if( max != 0 && len > max ){
           buff[max-1] = '\0';
        }
        break;
    case SN_SCOPED:
        len =  DRGetScopedNameBuff( is->sym, buff, max );
        if( len == 0 ){
            DCStatus( DS_FAIL );
            return( 0 );
        }
        --len;
        if( max != 0 && len > max ){
           buff[max-1] = '\0';
        }
        break;
    case SN_DEMANGLED:
        if( ii->mod_map[is->imx].lang == DR_LANG_CPLUSPLUS ){
            name = DRDecoratedName( is->sym, NULL );
            if( name == NULL ){
                DCStatus( DS_FAIL );
                return( 0 );
            }
            len = NameCopy(buff, name, max );
            DCFree( name );
        } else if( buff == NULL ) {
            return( 0 );
        } else {
            len = DRGetNameBuff( is->sym, buff, max );
            if( __is_mangled( buff, len ) ) {
                demangled_len = __demangle_l( buff, len, NULL, 0 );
                if( demangled_len > max ) demangled_len = max;
                name = DCAlloc( demangled_len );
                __demangle_l( buff, len, name, demangled_len );
                strncpy( buff, name, max );
                DCFree( name );
                return( demangled_len );
            } else {
                return( 0 );
            }
        }
        break;
    case SN_EXPRESSION:
        return( 0 );
    }
    return( len );
}

dip_status      DIPENTRY DIPImpSymType( imp_image_handle *ii,
                imp_sym_handle *is, imp_type_handle *it )
{
    dip_status ret;
    /*
        Get the implementation type handle for the type of the
        given symbol.
    */
    ret = DS_FAIL;
    DRSetDebug( ii->dwarf->handle ); /* must do at each call into dwarf */
    if( is->state == DF_NOT ){
        is->stype = DRGetTagType( is->sym );
    }
    switch( is->stype ){
    case DR_TAG_FUNCTION:
    case DR_TAG_CLASS:
    case DR_TAG_ENUM:
        it->type = is->sym;
        break;
    default:
        it->type =  DRGetTypeAT( is->sym );
        break;
    }
    ret = DS_OK;
    it->imx = is->imx;
    if( it->type != NULL ){
        it->state = DF_NOT;
    }else{
        it->state = DF_SET;      // default the type
        it->sub_array = FALSE;
        it->typeinfo.kind = DR_TYPEK_DATA;
        it->typeinfo.size = 0;
        it->typeinfo.mclass = DR_MOD_NONE;
        if( is->stype == DR_TAG_LABEL ){
            it->typeinfo.kind = DR_TYPEK_CODE;
        }

    }
    return( ret );
}

struct mod_wlk{
    imp_image_handle *ii;
    seg_list        *addr_sym;
    im_idx          imx;
    address          a;
    dr_handle        sym;
    search_result    ret;
};

static int AMod( dr_handle sym, void *_d, dr_search_context *cont ) {
/*******************************************************************/
//TODO: no segments, better TAG_label
    struct mod_wlk  *d = _d;
    uint_32         offset;
    uint_32         seg;
    int             ret;
    addrsym_info    info;

    cont = cont;
    ret = TRUE;
    if( DRGetLowPc( sym, &offset) ){
        if( d->ii->mod_map[d->imx].is_segment == FALSE ){
            seg = SEG_FLAT; // if flat hoke segment
        }else{
            EvalSeg( d->ii, sym, &seg );
        }
    }else{
        if( d->ii->mod_map[d->imx].is_segment == FALSE ){
            seg = SEG_FLAT; // if flat hoke segment
        }else{
            EvalSeg( d->ii, sym, &seg );
        }
        ret = EvalSymOffset( d->ii, sym, &offset );
    }
    info.map_offset = offset;
    info.sym = sym;
    info.map_seg = seg;
    AddAddrSym( d->addr_sym, &info );
    return( TRUE );
}

extern seg_list *DFLoadAddrSym( imp_image_handle *ii,
                                im_idx imx  ){
    dr_handle       cu_tag;
    struct mod_wlk  d;
    seg_list        *addr_sym;

    addr_sym = ii->mod_map[imx].addr_sym;
    if( addr_sym->head == NULL ){ /* no cache */
        FiniAddrSym( addr_sym ); /* kill cache */
        DRSetDebug( ii->dwarf->handle ); /* must do at each interface */
        cu_tag = ii->mod_map[imx].cu_tag;
        d.addr_sym = addr_sym;
        d.ii = ii;
        d.imx = imx;
        d.ret = SR_NONE;
        DRWalkModFunc( cu_tag, FALSE, AMod, &d ); /* load cache */
        SortAddrSym( addr_sym );
    }
    return( addr_sym );
}


typedef struct{
    dr_handle   inh;     /* member class handle */
    char       *name;    /* member name         */
    dr_handle   match;   /* handle that matches */
}mem_func_wlk;

static int AMemFuncSym( void *_df, addrsym_info *info ) {
/*******************************************************/
    mem_func_wlk *df = _df;
    int     cont;
    char   buff[256];
    int    len;
    dr_handle contain;

    cont = TRUE;
    contain  = DRGetContaining( info->sym );
    if( contain != NULL ){
        contain = DRSkipTypeChain( contain ); /* PCH typedef link */
        if( contain == df->inh ){
            len =  DRGetNameBuff( info->sym, buff, sizeof(buff) );
            if( strcmp( buff, df->name ) == 0 ){
                cont = FALSE;
                df->match = info->sym;
            }
        }
    }
    return( cont );
}

static dr_handle MemFuncLookUp( imp_image_handle *ii,
                                dr_handle sym,
                                dr_handle inh,
                                im_idx   imx )
{
    mem_func_wlk  df;
    char          buff[256];
    seg_list     *addr_sym;

    DRSetDebug( ii->dwarf->handle ); /* must do at each call into dwarf */
    addr_sym = DFLoadAddrSym( ii, imx );
    DRGetNameBuff( sym, buff, sizeof(buff) );
    df.name = buff;
    df.inh =  inh;
    df.match =  NULL;
    WlkAddrSyms( addr_sym, &AMemFuncSym, &df );
    return( df.match );
}

static  addr_seg GetCodeSeg( imp_image_handle *ii ){
/**************************************************/
    addr_ptr mach;
    mach.segment = SEG_CODE;
    mach.offset = 0;
    DCMapAddr( &mach, ii->dcmap );
    return( mach.segment );
}

dip_status      DIPENTRY DIPImpSymLocation( imp_image_handle *ii,
                imp_sym_handle *is, location_context *lc, location_list *ll )
{
    /*
        Get the location of the given symbol.
    */
    dip_status       ret;
    address          base; /* base segment & offset */
    uint_32          seg;
    dr_handle        sym;

    base = NilAddr;
    DRSetDebug( ii->dwarf->handle ); /* must do at each call into dwarf */
    if( DRGetLowPc( is->sym, &base.mach.offset) ){
        if( ii->mod_map[is->imx].is_segment == FALSE ){
            seg = SEG_CODE; // if flat hoke segment
        }else{
            EvalSeg( ii, is->sym, &seg );
        }
        base.mach.segment = seg;
        DCMapAddr( &base.mach, ii->dcmap );
        LocationCreate( ll, LT_ADDR, &base );
        ret = DS_OK;
    }else{
        switch( is->sclass ){
        case SYM_MEM:
        case SYM_VIRTF:
        {
            dr_bitfield info;
            int b_strt;

            ret = SafeDCItemLocation( lc, CI_OBJECT, ll );
            if( ret != DS_OK ){
                DCStatus( ret );
                return( ret );
            }
            if( is->f.minfo.inh != NULL ){
                DFBaseAdjust( ii, is->f.minfo.root,
                      DRGetTypeAT( is->f.minfo.inh ),lc, &ll->e[0].u.addr );
            }
            ret = EvalLocAdj( ii, lc, is->sym, &ll->e[0].u.addr  );
            if( is->sclass == SYM_VIRTF ){
                ll->e[0].u.addr.mach.segment = GetCodeSeg( ii );
            }else if( DRGetBitFieldInfo( is->sym, &info )  ){
                b_strt = 8*info.byte_size.val.s  -
                 (info.bit_offset.val.s + info.bit_size.val.s);
                LocationAdd( ll, b_strt );
                LocationTrunc( ll, info.bit_size.val.s );
            }
            break;
        }
        case SYM_MEMF:

            if( is->f.minfo.inh == NULL ){
                sym = is->f.minfo.root;
            }else{
                sym = DRGetTypeAT( is->f.minfo.inh ); //get inherited type
            }
            sym = DRSkipTypeChain( sym ); /* PCH typedef link */
            sym =  MemFuncLookUp( ii, is->sym, sym, is->imx );
            if( sym == NULL ){
                base = NilAddr; //for now say it's NULL
                LocationCreate( ll, LT_ADDR, &base );
                ret = DS_OK;
                break;
            }else{
                is->sym = sym;
            }
            DRSetDebug( ii->dwarf->handle ); /* must do at each call into dwarf */
            if( DRGetLowPc( is->sym, &base.mach.offset) ){
                if( ii->mod_map[is->imx].is_segment == FALSE ){
                    seg = SEG_CODE; // if flat hoke segment
                }else{
                    EvalSeg( ii, is->sym, &seg );
                }
                base.mach.segment = seg;
                DCMapAddr( &base.mach, ii->dcmap );
                LocationCreate( ll, LT_ADDR, &base );
                ret = DS_OK;
            }
            break;
        case SYM_MEMVAR:
        case SYM_VAR:
            if( ii->mod_map[is->imx].is_segment == FALSE ){
                if( DRIsFunc( is->sym ) ){
                    seg = SEG_CODE; // if flat hoke segment
                }else{
                    seg = SEG_DATA; // if flat hoke segment
                }
            }else{
                EvalSeg( ii, is->sym, &seg );
            }
            ret = EvalLocation( ii, lc, is->sym, seg, ll );
            break;
        }
    }
    return( ret );
}

dip_status      DIPENTRY DIPImpSymValue( imp_image_handle *ii,
                imp_sym_handle *is, location_context *ic, void *buff )
{
    uint_32     value;
    /*
        Copy the value of a constant symbol into 'buff'. You can get the
        size required by doing a SymType followed by a TypeInfo.
    */
    ii = ii;
    ic = ic;
    if( is->sclass != SYM_ENUM ){
        return( DS_FAIL );
    }
    DRSetDebug( ii->dwarf->handle ); /* must do at each call into dwarf */
    if( !DRConstValAT( is->sym, &value ) ){
        return( DS_FAIL );
    }
    switch( is->f.einfo.size ){
    case 1:
        *(uint_8 *)buff = value;
        break;
    case 2:
        *(uint_16 *)buff = value;
        break;
    case 4:
        *(uint_32 *)buff = value;
        break;
    default:
        return( DS_FAIL );
    }
    return( DS_OK );
}

dip_status      DIPENTRY DIPImpSymInfo( imp_image_handle *ii,
                imp_sym_handle *is, location_context *lc, sym_info *si )
{
    /*
        Get some generic information about a symbol.
    */
    uint_32         num1;
    uint_32         num2;
    dr_ptr          addr_class;

    lc = lc;
    DRSetDebug( ii->dwarf->handle ); /* must do at each call into dwarf */
    if( is->state == DF_NOT ){
        DRSetDebug( ii->dwarf->handle ); /* must do at each interface */
        is->stype = DRGetTagType( is->sym );
        is->acc   = DRGetAccess( is->sym );
        is->isstatic = DRIsFunctionStatic( is->sym );
        is->isartificial = DRIsArtificial( is->sym );
        is->state = DF_SET;
    }
    switch( is->stype ){
    case DR_TAG_FUNCTION:
        if( is->sclass == SYM_MEMF || is->sclass == SYM_VIRTF ){
            si->kind = SK_CODE;  //member functions
        }else{
            si->kind = SK_PROCEDURE;
            if( DRStartScopeAT( is->sym, &num1 ) ){
                si->prolog_size  = num1;
            }else{
                si->prolog_size  = 0;
            }
            if( !DRGetLowPc( is->sym, &num1 ) ){
                num1 = 0;
            }
            if( !DRGetHighPc( is->sym, &num2 ) ){
                num2 = num1;
            }
            si->rtn_size = num2 - num1;
            si->num_parms = GetParmCount( ii, is->sym );
            si->ret_size = 0;
            si->ret_modifier = TM_NONE;
            si->epilog_size = 0;
            si->rtn_calloc  = 0;
            EvalOffset( ii, is->sym, &num1 );
            si->ret_addr_offset = num1;
            addr_class =  DRGetAddrClass( is->sym );
            switch( addr_class ){
            case DR_PTR_far32:
            case DR_PTR_far16:
                si->rtn_far = 1;
                break;
            default:
                si->rtn_far = 0;
            }
        }
        break;
    case DR_TAG_CLASS:
    case DR_TAG_ENUM:
    case DR_TAG_TYPEDEF:
        si->kind = SK_TYPE;
        break;
    case DR_TAG_VARIABLE:
        si->kind = SK_DATA;
        break;
    case DR_TAG_LABEL:
        si->kind = SK_CODE;
        break;
    case DR_TAG_NAMESPACE:
        si->kind = SK_NAMESPACE;
        break;
    default:
        si->kind = SK_NONE;
        break;
    }
    si->is_private = 0;
    si->is_protected = 0;
    si->is_public = 0;
    switch( is->acc ){
    case DR_ACCESS_PUBLIC:
        si->is_public = 1;
        break;
    case DR_ACCESS_PROTECTED:
        si->is_protected = 1;
        break;
    case DR_ACCESS_PRIVATE:
        si->is_private = 1;
        break;
    }
    si->compiler = is->isartificial;
    if( is->isstatic ){
        si->global = 0;
    }else{
        si->global = 1;
    }
    switch( is->sclass ){
    case SYM_MEMVAR:
        si->member = 1;
        si->is_static = 1;
        break;
    case SYM_MEM:
    case SYM_MEMF:
    case SYM_VIRTF:
        si->member = 1;
        si->is_static = 0;
        break;
    default:
        si->member = 0;
        si->is_static = 0;
    }
    return( DS_OK );
}

static int ARet( dr_handle var, int index, void *_var_ptr ) {
/***********************************************************/
    dr_handle  *var_ptr = _var_ptr;
    char name[sizeof(".return")];
    int  cont;
    int  len;

    index = index;
    cont = TRUE;
    if( DRIsArtificial( var ) ){
        len =  DRGetNameBuff( var, name, sizeof(".return") );
        if( len == sizeof(".return") ){
            if( strcmp( name, ".return" ) == 0 ){
                *var_ptr = var;
                cont = FALSE;
            }
        }
    }
    return( cont );
}

extern dr_handle GetRet(  imp_image_handle *ii, dr_handle proc ){
/******************************************************/
// find handle of watcom return sym
    dr_handle ret;

    DRSetDebug( ii->dwarf->handle ); /* must do at each call into dwarf */
    if( DRWalkBlock( proc,  DR_SRCH_var, ARet, &ret ) ){
        ret = NULL;
    }
    return( ret );
}

dip_status      DIPENTRY DIPImpSymParmLocation( imp_image_handle *ii,
                    imp_sym_handle *is, location_context *lc,
                    location_list *ll, unsigned n )
{
    /*
        Get information about where a routine's parameters/return value
        are located.
        If the 'n' parameter is zero, fill in the location list structure
        pointed at by 'll' with the information on the location of the
        function's return value. Otherwise fill it in with the location
        of the n'th parameter.
    */
//TODO: brian only wants regs for now
    dr_handle       parm;
    dip_status      ret;

    DRSetDebug( ii->dwarf->handle ); /* must do at each call into dwarf */
    ret = DS_FAIL;
    if( n > 0 ){
        parm = GetParmN( ii, is->sym, n );
        if( parm != NULL ){
            ret = EvalParmLocation( ii, lc, parm, ll );
        }
    }else if( n == 0 ){
        //TODO: get ret location
        parm = GetRet( ii, is->sym );
        if( parm != NULL ){
            ret = EvalRetLocation( ii, lc, parm, ll );
        }
    }
    return( ret );
}

static int AThis( dr_handle var, int index, void *_var_ptr ) {
/************************************************************/
    dr_handle *var_ptr = _var_ptr;
    char name[sizeof("this")];
    int  ret;
    int  len;

    index = index;
    ret = TRUE;
    len =  DRGetNameBuff( var, name, sizeof("this"));
    if( len == sizeof("this") ){
        if( strcmp( name, "this" ) == 0 ){
            *var_ptr = var;
            ret = FALSE;
        }
    }
    return( ret );
}

static dr_handle GetThis(  imp_image_handle *ii, dr_handle proc ){
/******************************************************/
// return handle of the this parm
    dr_handle ret;

    DRSetDebug( ii->dwarf->handle ); /* must do at each call into dwarf */
    if( DRWalkBlock( proc,  DR_SRCH_parm, AThis, &ret ) ){
        ret = NULL;
    }
    return( ret );
}

dip_status      DIPENTRY DIPImpSymObjType( imp_image_handle *ii,
                    imp_sym_handle *is, imp_type_handle *it, type_info *ti )
{
    dr_handle   dr_this;
    dr_handle   dr_type;
    dr_typeinfo typeinfo;
    dip_status  ret;
    /*
        Fill in the imp_type_handle with the type of the 'this' object
        for a C++ member function.
        If 'ti' is not NULL, fill in the type_info with the kind of 'this'
        pointer that the routine is expecting (near/far, 16/32). If the
        routine is a static member, set ti->kind to TK_NONE.
    */
    dr_this = GetThis( ii, is->sym );
    if( dr_this != NULL ){
        DRSetDebug( ii->dwarf->handle ); /* must do at each call into dwarf */
        dr_type =  DRGetTypeAT( dr_this );
        if( dr_type != NULL ){
            DRGetTypeInfo( dr_type, &typeinfo );
            MapImpTypeInfo( &typeinfo, ti );
            dr_type =  DRSkipTypeChain( dr_type );
            it->type = DRGetTypeAT( dr_type );
            it->state = DF_NOT;
            it->imx = is->imx;
            ret = DS_OK;
        }else{
            ret = DS_FAIL;
        }
    }else{
        ti->kind = TK_NONE;
        ret = DS_FAIL;
    }
    return( ret );
}

dip_status      DIPENTRY DIPImpSymObjLocation( imp_image_handle *ii,
                                imp_sym_handle *is, location_context *lc,
                                 location_list *ll )
{
    /*
        Fill in the location list with the location of the '*this' object
        for a C++ member function. Return DS_FAIL if it's a static member
        function.
     */
    dr_handle       dr_this;
    dr_handle       dr_type;
    dr_typeinfo     typeinfo;
    uint_32         seg;
    address         base; /* base segment & offset */
    location_list   tmp;
    union{
        addr32_off   n16;
        addr48_off   n32;
        addr32_ptr   f16;
        addr48_ptr   f32;
    }obj_ptr;

    dip_status      ret;

    dr_this = GetThis( ii, is->sym );
    if( dr_this != NULL ){
        if( ii->mod_map[is->imx].is_segment == FALSE ){
            seg = SEG_DATA; // if flat hoke segment
        }else{
            EvalSeg( ii, is->sym, &seg );
        }
        ret = EvalLocation( ii, lc, dr_this, seg, &tmp );
        if( ret == DS_OK ){
            dr_type =  DRGetTypeAT( dr_this );
            if( dr_type != NULL ){
                DRGetTypeInfo( dr_type, &typeinfo );
                LocationCreate( ll, LT_INTERNAL, &obj_ptr );
                ret = DCAssignLocation( ll, &tmp, typeinfo.size );
                if( ret == DS_OK ){
                    base = NilAddr;
                    switch( typeinfo.modifier.ptr ){ /* set segment */
                    case DR_PTR_none:
                    case DR_PTR_near16:
                    case DR_PTR_near32:
                        ret = SafeDCItemLocation( lc, CI_DEF_ADDR_SPACE, ll );
                        base = ll->e[0].u.addr; /* set base */
                        break;
                    }
                    switch( typeinfo.modifier.ptr ){
                    case DR_PTR_none:
                        if( typeinfo.size == 4 ){
                            base.mach.offset  = obj_ptr.n32;
                        }else{
                            base.mach.offset  = obj_ptr.n16;
                        }
                        break;
                    case DR_PTR_near16:
                        base.mach.offset  = obj_ptr.n16;
                        break;
                    case DR_PTR_near32:
                        base.mach.offset  = obj_ptr.n32;
                        break;
                    case DR_PTR_far16:
                        base.mach.segment = obj_ptr.f16.segment;
                        base.mach.offset  = obj_ptr.f16.offset;
                        break;
                    case DR_PTR_far32:
                        base.mach.segment = obj_ptr.f32.segment;
                        base.mach.offset  = obj_ptr.f32.offset;
                        break;
                    case DR_PTR_huge16:
                        base.mach.segment = obj_ptr.f16.segment;
                        base.mach.offset  = obj_ptr.f16.offset;
                        break;
                    }
                }
                LocationCreate( ll, LT_ADDR, &base );
            }
        }
    }else{
        ret = DS_FAIL;
    }
    return( ret );
}




search_result   DIPENTRY DIPImpAddrSym( imp_image_handle *ii,
                            imp_mod_handle im, address a, imp_sym_handle *is )
{
    /*
        Search the given module for a symbol who's address is greater than
        or equal to 'addr'. If none is found return SR_NONE. If you find
        a symbol at that address exactly, fill in '*is' and return SR_EXACT.
        Otherwise, fill in '*is' and return SR_CLOSEST.
    */
    im_idx          imx;
    addrsym_info    info;
    search_result   ret;
    seg_list        *addr_sym;

    if( im == 0 ){
        DCStatus( DS_FAIL );
        return( SR_NONE );
    }
    imx = IM2IMX( im );
    addr_sym = DFLoadAddrSym( ii, imx );
    Real2Map( ii->addr_map, &a );
    if( FindAddrSym( addr_sym, &a.mach, &info ) >= 0 ){
           is->sclass = SYM_VAR;
           is->imx = imx;
           is->sym = info.sym;
           is->state = DF_NOT;
           if( info.map_offset == a.mach.offset ){
               ret = SR_EXACT;
           }else{
               ret = SR_CLOSEST;
           }
    }else{
        ret = SR_NONE;
    }
    return( ret );
}

/**********************************/
/* Walk inner and outer blocks   */
/*********************************/

static int InBlk( dr_handle blk, int depth, void *_ctl ) {
/********************************************************/
    scope_ctl        *ctl = _ctl;
    uint_32           lo;
    uint_32           hi;
    scope_node       *new;

    depth = depth;
    lo =0; //quick fix for labels
    hi =0;
    DRGetLowPc( blk, &lo );
    DRGetHighPc( blk, &hi );
    new = AddScope( ctl->edge, lo, hi, blk );
    if( ctl->root == NULL ){
        ctl->root = new;
    }
    ctl->edge = new;
    return( TRUE );
}

static bool IsInScope( scope_ctl  *ctl, address addr ){
/*************************************************/
    bool ret;
    scope_node *root;

    ret = FALSE;
    root = ctl->root;
    if( root != NULL ){
        if( ctl->base.mach.segment == addr.mach.segment ){
            if( root->start <= addr.mach.offset
              && addr.mach.offset <  root->end ){
                ret = TRUE;
           }
        }
    }
    return( ret );
}

static search_result  DFAddrScope( imp_image_handle *ii,
                im_idx imx, address addr, scope_block *scope )
{
    scope_ctl         *ctl;
    scope_node        *node;
    search_result      ret;

    ret = SR_NONE;
    Real2Map( ii->addr_map, &addr );
    ctl =  &ii->scope;
    if( !IsInScope( ctl, addr ) ){
        addrsym_info       info;
        seg_list           *addr_sym;

        addr_sym = DFLoadAddrSym( ii, imx );
        if( FindAddrSym( addr_sym, &addr.mach, &info ) >= 0 ){
            DRSetDebug( ii->dwarf->handle ); /* must do at each interface */
            if( DRIsFunc( info.sym ) ){
                FiniScope( ctl );
                ctl->base = addr;
                ctl->base.mach.offset = info.map_offset;
                ctl->base.mach.segment = info.map_seg;
                DRWalkScope( info.sym, InBlk, ctl );
            }
        }
    }
    if( ctl->root != NULL ){
        node = FindScope( ctl->root, addr.mach.offset );
        if( node != NULL ){
            scope->start = addr;
            scope->start.mach.offset = node->start;
            scope->len = node->end - node->start;
            DCMapAddr( &scope->start.mach, ii->dcmap );
            scope->unique = node->what;
            scope->unique -= ii->mod_map[imx].cu_tag; /* make relative */
            ret = SR_CLOSEST;
        }
    }
    return( ret );
}

search_result   DIPENTRY DIPImpAddrScope( imp_image_handle *ii,
                imp_mod_handle im, address addr, scope_block *scope )
{
    /*
        Find the range of the lexical scope block enclosing 'addr' in
        module 'im'. If there is no such scope, return SR_NONE. Otherwise
        fill in scope->start with the address of the start of the lexical
        block and scope->len with the size of the block. Fill in
        scope->unique with something that uniquely identifies the lexical
        block in question. This is used to disamibiguate between blocks
        that start at the same address and have the same length. The value
        should be chosen so that
                1. It remains valid and consistant across a DIPUnloadInfo
                   and DIPLoadInfo of the same information.
                2. It remains the same whether the scope_block was obtained
                   by DIPImpAddrScope or DIPImpScopeOuter.
        Then return SR_EXACT/SR_CLOSEST as appropriate.
    */
    return( DFAddrScope( ii, IM2IMX( im ), addr, scope ) );
}

static search_result   DFScopeOuter( imp_image_handle *ii,
                im_idx imx, scope_block *in, scope_block *out )
{
    /*
        Given the scope_block pointed to by 'in' in the module 'im', find
        the parent lexical block of it and fill in the scope_block pointed
        to by 'out' with the information. Return SR_EXACT/SR_CLOSEST as
        appropriate. Return SR_NONE if there is no parent block.
        Make sure that the case where 'in' and 'out' point to the same
        address is handled.
    */
    dr_handle           what;
    search_result       ret;
    address             addr;
    scope_ctl         *ctl;
    scope_node        *node;

    ret = SR_NONE;
    addr =  in->start;
    Real2Map( ii->addr_map, &addr );
    ctl = &ii->scope;
    if( !IsInScope( ctl, addr ) ){
        addrsym_info       info;
        seg_list           *addr_sym;

        addr_sym = DFLoadAddrSym( ii, imx );
        if( FindAddrSym( addr_sym, &addr.mach, &info ) >= 0 ){
            DRSetDebug( ii->dwarf->handle ); /* must do at each interface */
            if( DRIsFunc( info.sym ) ){
                FiniScope( ctl );
                ctl->base = addr;
                ctl->base.mach.offset = info.map_offset;
                ctl->base.mach.segment = info.map_seg;
                DRWalkScope( info.sym, InBlk, ctl );
            }
        }
    }
    if( ctl->root != NULL ){
        ret = SR_NONE;
        node = FindScope( ctl->root, addr.mach.offset );
        what = in->unique;
        what += ii->mod_map[imx].cu_tag; /* make absolute */
        while( node != NULL ){
            if( node->what == what ){
                node = node->down;
                break;
            }
            node = node->down;
        }
        if( node != NULL ){
            out->start = addr;
            out->start.mach.offset = node->start;
            out->len = node->end - node->start;
            DCMapAddr( &out->start.mach, ii->dcmap );
            what = node->what;
            what -= ii->mod_map[imx].cu_tag;
            out->unique = what; /* make relative */
            ret = SR_EXACT;
        }
    }
    return( ret );
}

static dr_handle GetContainingClass( dr_handle curr )
{
    dr_tag_type     sc;

    curr = DRGetContaining( curr );
    if( curr != NULL ){
        curr = DRSkipTypeChain( curr ); /* PCH typedef link */
        sc = DRGetTagType( curr );
        if( sc != DR_TAG_CLASS ){
            curr = NULL;
        }
    }
    return( curr );
}

search_result   DIPENTRY DIPImpScopeOuter( imp_image_handle *ii,
                imp_mod_handle im, scope_block *in, scope_block *out )
{
    search_result   ret;
    dr_handle       curr;
    dr_tag_type     sc;
    dr_handle       cu_tag;
    im_idx          imx;

    DRSetDebug( ii->dwarf->handle ); /* must do at each interface */
    imx = IM2IMX( im );
    cu_tag = ii->mod_map[imx].cu_tag;
    curr = in->unique + cu_tag;
    sc = DRGetTagType( curr );
    switch( sc ){
    case DR_TAG_CLASS:
        DCStatus( DS_FAIL );
        ret = SR_NONE;
        break;
    case DR_TAG_FUNCTION:
        curr = GetContainingClass( curr );
        if( curr != NULL ){
            *out = *in;
             out->unique = curr-cu_tag;
             ret = SR_EXACT;
         }else{
            DCStatus( DS_FAIL );
            ret = SR_NONE;
         }
         break;
    default:
        ret = DFScopeOuter( ii, imx, in, out );
    }
    return( ret );

}
/**********************************************/
/* Walk or Search various scopes for symbols  */
/**********************************************/

typedef struct {
    im_idx           imx;
    imp_image_handle *ii;
    void             *d;
    dr_handle        containing;
    dr_srch          what;
    bool             cont;  //continue to next scope
    enum {
        WLK_LOOKUP,
        WLK_WLK,
    }                kind;
}blk_wlk_com;

typedef struct {
    blk_wlk_com    com;
    walk_result     wr;
    IMP_SYM_WKR    *wk;
    imp_sym_handle *is;
}blk_wlk_wlk;

typedef struct {
    blk_wlk_com      com;
    int              (*comp)();
    lookup_item      *li;
    search_result     sr;
    char             *buff;
    unsigned         len;
}blk_wlk_lookup;

typedef union {
    blk_wlk_com    com;
    blk_wlk_wlk    wlk;
    blk_wlk_lookup lookup;
}blk_wlk;

typedef int (*BLKLF)( dr_handle var, int index, void *df );

static dr_srch Dip2DwarfSrch( symbol_type dip ){
    dr_srch ret;

    switch( dip ) {
    case ST_NONE:
    case ST_OPERATOR:
    case ST_DESTRUCTOR:
        ret = DR_SRCH_func_var;
        break;
    case ST_TYPE:
        ret = DR_SRCH_ctypes;
        break;
    case ST_STRUCT_TAG:
    case ST_CLASS_TAG:
    case ST_UNION_TAG:
        ret = DR_SRCH_class;
        break;
    case ST_ENUM_TAG:
        ret = DR_SRCH_enum;
        break;
    }
    return( ret );
}

static int ASym( dr_handle var, int index, void *_df ) {
/******************************************************/
    blk_wlk_wlk *df = _df;
    int     cont;
    imp_sym_handle   *is;
    dr_dbg_handle  saved;

    index = index;
    is = df->is;
    is->sclass = SYM_VAR;
    is->imx = df->com.imx;
    is->sym = var;
    is->state = DF_NOT;
    saved = DRGetDebug();
    df->wr = df->wk( df->com.ii, SWI_SYMBOL, is, df->com.d );
    DRSetDebug( saved );
    cont = TRUE;
    if( df->wr != WR_CONTINUE ){
        cont = FALSE;
    }
    df->com.cont = cont;
    return( cont );
}

static int ASymCont( dr_handle var, int index, void *_df ) {
/**********************************************************/
    blk_wlk_wlk     *df = _df;
    dr_handle       contain;
    int             cont;

    cont = TRUE;
    contain = DRGetContaining( var );
    if( contain != NULL ){
        contain = DRSkipTypeChain( contain ); /* PCH typedef link */
    }
    if( df->com.containing == contain ){
        cont = ASym( var, index, df );
    }
    return( cont );
}

static int AModSym( dr_handle var, int index, void *_df ) {
/*********************************************************/
    blk_wlk_wlk *df = _df;
    int     cont;
    imp_sym_handle   *is;
    dr_tag_type      sc;
    dr_dbg_handle  saved;

    index = index;
    sc = DRGetTagType( var );
    if( sc == DR_TAG_NAMESPACE ){
        DRWalkBlock( var, df->com.what, AModSym, df );
        cont = TRUE;
    }else{
        is = df->is;
        is->sclass = SYM_VAR;
        is->imx = df->com.imx;
        is->sym = var;
        is->state = DF_NOT;
        saved = DRGetDebug();
        df->wr = df->wk( df->com.ii, SWI_SYMBOL, is, df->com.d );
        DRSetDebug( saved );
        cont = TRUE;
    }
    if( df->wr != WR_CONTINUE ){
        cont = FALSE;
    }
    df->com.cont = cont;
    return( cont );
}

static int ASymLookup( dr_handle var, int index, void *_df ) {
/************************************************************/
    blk_wlk_lookup   *df = _df;
    imp_sym_handle   *is;
    int     cont;
    int    len;

    len =  DRGetNameBuff( var, df->buff, df->len );
    if( len == df->len && df->comp(df->buff, df->li->name.start,df->li->name.len)==0 ) {
        is = DCSymCreate( df->com.ii, df->com.d );
        is->sclass = SYM_VAR;
        is->imx = df->com.imx;
        is->sym = var;
        is->state = DF_NOT;
        df->sr = SR_EXACT;
        df->com.cont = FALSE;
        cont = TRUE;
    }else{
        cont = TRUE;
    }
    return( cont );
}

static int ASymContLookup( dr_handle var, int index, void *_df ) {
/****************************************************************/
    blk_wlk_lookup   *df = _df;
    dr_handle        contain;
    int              cont;

    cont = TRUE;
    contain = DRGetContaining( var );
    if( contain != NULL ){
        contain = DRSkipTypeChain( contain ); /* PCH typedef link */
    }
    if( df->com.containing == contain ){
        cont = ASymLookup( var, index, df );
    }
    return( cont );
}

static int WalkOneBlock( blk_wlk      *df,
                         BLKLF         fn,
                         dr_handle     blk ){
    DRSetDebug( df->com.ii->dwarf->handle ); /* must do at each call into dwarf */
    DRWalkBlock( blk, df->com.what, fn, df );
    return( df->com.cont );
}

static int WalkScopedSymList( blk_wlk *df, BLKLF fn, address *addr ){
//*******************************************************************
// Walk inner to outer func scopes then containing class if present
// then module scope
//*******************************************************************
    imp_image_handle   *ii;
    scope_block         scope;
    dr_handle           cu_tag;
    dr_tag_type         sc;
    im_idx              imx;
    dr_handle           curr;
    int                 cont;

    ii = df->com.ii;
    cont = TRUE;
    if( DFAddrMod( ii, *addr, &imx ) != SR_NONE ) {
        if( DFAddrScope( ii, imx, *addr, &scope ) != SR_NONE ) {
            df->com.imx = imx;
            cu_tag = ii->mod_map[imx].cu_tag;
            for( ;; ){
                curr = scope.unique + cu_tag;
                cont = WalkOneBlock( df, fn, curr );
                if( !cont )break;
                if( DFScopeOuter( ii, imx, &scope, &scope ) == SR_NONE ){
                    cont = TRUE;
                    break;
                }
            }
            if( cont ){
                sc = DRGetTagType( curr );
                if( sc == DR_TAG_FUNCTION ){
                    imp_type_handle  it;

                    curr = GetContainingClass( curr );
                    if( curr != NULL ){
                        it.state = DF_NOT;
                        it.type = curr;
                        it.imx =  imx;
                        if( df->com.kind == WLK_WLK ){
                            df->wlk.wr = WalkTypeSymList( ii, &it,
                                 df->wlk.wk, df->wlk.is, df->com.d );
                            if( df->wlk.wr != WR_CONTINUE ){
                                cont = FALSE;
                            }
                        }else{
                            df->lookup.sr = SearchMbr( ii, &it,
                                          df->lookup.li, df->com.d );
                            if( df->lookup.sr == SR_EXACT ){
                                cont = FALSE;
                            }
                        }
                    }
                }
            }
        }
        if( cont ){
            cont = WalkModSymList( df, fn, imx );
        }
        if( cont && ii->mod_map[imx].dbg_pch != NULL ){
            imx = CuTag2ModIdx( ii, ii->mod_map[imx].dbg_pch );
            cont = WalkModSymList( df, fn, imx );
        }
    }
    return( cont );
}

static int WalkBlockSymList( blk_wlk  *df, BLKLF fn, scope_block *scope )
{
    imp_image_handle   *ii;
    dr_handle           cu_tag;
    im_idx              imx;
    dr_handle           blk;
    dr_tag_type         sc;
    int cont;

    ii = df->com.ii;
    if( DFAddrMod( ii, scope->start, &imx ) != SR_NONE ) {
        DRSetDebug( df->com.ii->dwarf->handle ); /* must do at each call into dwarf */
        df->com.imx = imx;
        cu_tag = ii->mod_map[imx].cu_tag;
        blk = scope->unique + cu_tag;
        sc = DRGetTagType( blk );
        if( sc == DR_TAG_CLASS ){
            imp_type_handle  it;

            it.state = DF_NOT;
            it.type = blk;
            it.imx =  imx;
            if( df->com.kind == WLK_WLK ){
                df->wlk.wr = WalkTypeSymList( ii, &it, df->wlk.wk,
                               df->wlk.is, df->com.d );
            }else{
                 df->lookup.sr = SearchMbr( ii, &it,
                                    df->lookup.li, df->com.d );
            }
        }else{
            cont = WalkOneBlock( df, fn, blk );
        }
    }else{
        cont = TRUE;
    }
    return( cont );
}

static int WalkModSymList( blk_wlk *df, BLKLF fn, im_idx imx )
{
    imp_image_handle *ii;
    dr_handle        cu_tag;
    int              cont;

    df->com.imx = imx;
    ii = df->com.ii;
    cu_tag = ii->mod_map[imx].cu_tag;
    if( df->com.what == DR_SRCH_ctypes &&
        ii->mod_map[imx].lang == DR_LANG_CPLUSPLUS ){
        df->com.what = DR_SRCH_cpptypes;
    }
    cont = WalkOneBlock( df, fn, cu_tag );
    return( cont );
}

static int WalkSymSymList( blk_wlk *df, BLKLF fn, imp_sym_handle *is )
{
    imp_image_handle *ii;
    im_idx           imx;
    int              cont;

    imx = is->imx;
    ii = df->com.ii;
    df->com.imx = imx;
    if( df->com.what == DR_SRCH_ctypes &&
        ii->mod_map[imx].lang == DR_LANG_CPLUSPLUS ){
        df->com.what = DR_SRCH_cpptypes;
    }
    cont = WalkOneBlock( df, fn, is->sym );
    return( cont );
}

static walk_result  WalkMyLDSyms( imp_image_handle *ii, im_idx imx, void *_df )
{
    blk_wlk_wlk *df = _df;

    df->com.imx = imx;
    WalkModSymList( df, &ASym, imx );
    return( df->wr );
}

static walk_result DFWalkSymList( imp_image_handle *ii,
                         symbol_source     ss,
                         void             *source,
                         IMP_SYM_WKR      *wk,
                         imp_sym_handle   *is,
                         void             *d )
{
    imp_mod_handle      im;
    walk_result         wr;
    blk_wlk_wlk         df;
    int                 cont;

    df.com.ii = ii;
    df.com.d = d;
    df.com.what = DR_SRCH_func_var;
    df.com.containing = 0;
    df.com.cont = TRUE;
    df.com.kind = WLK_WLK;
    df.wk = wk;
    df.is = is;
    df.wr = WR_CONTINUE;
    switch( ss ) {
    case SS_TYPE: /* special case */
        wr = WalkTypeSymList( ii,  (imp_type_handle *)source, wk, is, d );
        break;
    case SS_SCOPED:
        cont = WalkScopedSymList( &df, &ASym, (address *)source );
        wr = df.wr;
        break;
    case SS_SCOPESYM:
        is = (imp_sym_handle *)source;
        WalkSymSymList( &df, &ASym, is );
        if( cont ){
            df.com.containing = is->sym;
            WalkModSymList( &df, &ASymCont, is->imx );
        }
        wr = df.wr;
        break;
    case SS_BLOCK:
        WalkBlockSymList( &df, &ASym, (scope_block *)source );
        wr = df.wr;
        break;
    case SS_MODULE:
        im = *(imp_mod_handle *)source;
        if( im == (imp_mod_handle)NO_MOD ) {
            wr = DFWalkModList( ii, WalkMyLDSyms, &df );
        } else {
           WalkModSymList( &df, &AModSym, IM2IMX( im ) );
           wr = df.wr;
        }
        break;
    }
    return( wr );
}

walk_result DIPENTRY DIPImpWalkSymList( imp_image_handle *ii,
                                        symbol_source     ss,
                                        void             *source,
                                        IMP_SYM_WKR      *wk,
                                        imp_sym_handle   *is,
                                        void              *d )
{
    return( DFWalkSymList( 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( DFWalkSymList( ii, ss, source, wk, is, d ) );
}


#define SH_ESCAPE       '\xf0'
static void CollectSymHdl( byte *ep, imp_sym_handle *is )
{
    byte        *sp;
    byte        curr;
    static byte escapes[] = { SH_ESCAPE, '\0', '`' };

    ++ep;
    sp = (byte *)is;
    ++is;
    while( sp < (byte *)is ) {
        curr = *ep++;
        if( curr == SH_ESCAPE ) curr = escapes[ *ep++ - 1 ];
        *sp++ = curr;
    }
}


typedef struct {
    imp_image_handle   *ii;
    void               *d;
    int                 (*compare)(char const *, char const *);
    char               *name;
    dr_handle           sym;
}hash_look_data;

static int AHashItem( void *_find, dr_handle sym, char *name ) {
    hash_look_data *find = _find;
    imp_sym_handle *is;

    if( find->compare( name, find->name ) == 0 ){
        find->sym = sym;
        is = DCSymCreate( find->ii, find->d );
        is->imx = DwarfModIdx( find->ii, sym );
        is->sclass = SYM_VAR;
        is->sym = sym;
        is->state = DF_NOT;
    }
    return( TRUE );
}

typedef struct {
    char *p;
    int   len;
}strv;

static int StrVCopy( strv *dst, strv *src )
{
//Copy source until null char or source runs out
//to dest until it runs out, return total length of source
    int total;

    total = src->len;
    for(;;){
        if( src->len == 0 )break;
        if( *src->p == '\0' )break;
        if( dst->len > 0 ){
            *dst->p = *src->p;
            ++dst->p;
            --dst->len;
        }
        ++src->p;
        --src->len;
    }
    total -= src->len;
    return( total );
}

static int QualifiedName( char *buff, lookup_item  *li, int max )
{
    int total;
    strv curr;
    strv dst;
    strv tmp;

    curr.p = li->scope.start;
    curr.len = li->scope.len;
    dst.p = buff;
    dst.len = max;
    total = 0;
    while( curr.len > 0 ){
        total += StrVCopy( &dst, &curr );
        if( *curr.p == '\0' ){
            ++curr.p;
            --curr.len;
        }
        tmp.p = "::";
        tmp.len = 2;
        total += StrVCopy( &dst, &tmp );
    }
    curr.p = li->name.start;
    curr.len = li->name.len;
    total += StrVCopy( &dst, &curr );
    if( dst.len > 0 ){
        *dst.p = '\0';
    }
    total += 1;
    return( total );
}

static search_result HashSearchGbl( imp_image_handle *ii,
                                    lookup_item      *li, void *d )
{
    char                buff[256];
    int                 len;
    search_result       sr;
    hash_look_data      data;
    name_wlk            wlk;

    sr = SR_NONE;
    data.ii  = ii;
    data.compare = li->case_sensitive ? &strcmp : &stricmp;
    data.sym  = NULL;
    len = QualifiedName(  buff, li, sizeof( buff ) );
    if( len <= sizeof( buff ) ){
        data.name = buff;
    }else{
        data.name = DCAlloc( len+1 );
        len = QualifiedName(  data.name, li, len+1 );
    }
    data.d  = d;
    wlk.fn = AHashItem;
    wlk.name = data.name;
    wlk.d = &data;
    DRSetDebug( ii->dwarf->handle ); /* must do at each call into dwarf */
    FindHashWalk( ii->name_map, &wlk );
    if( data.sym != NULL ){
        sr = SR_EXACT;
    }
    if( data.name != buff ){
        DCFree( data.name );
    }
    return( sr );
}

extern search_result   DoLookupSym( imp_image_handle *ii,
                symbol_source ss, void *source, lookup_item *li,
                location_context *lc, void *d )
{
    imp_mod_handle      im;
    imp_sym_handle     *is;
    search_result       sr;
    char                *src;
    unsigned            len;
    blk_wlk_lookup      df;
    char                buff[256];
    int                 cont;

    if( *li->name.start == SH_ESCAPE ) {
        CollectSymHdl( li->name.start, DCSymCreate( ii, d ) );
        return( SR_EXACT );
    }
    if( li->type == ST_OPERATOR ) {
//TODO this operator
        src = li->name.start;
        len = li->name.len;
        return( SR_NONE );
    }
    if( ss ==  SS_TYPE ){
        if( li->mod != NO_MOD ){
            sr =  SR_NONE;
        }else{
            sr = SearchMbr( ii, (imp_type_handle *)source, li, d  );
        }
        return( sr );
    }
    df.com.ii = ii;
    df.com.d = d;
    df.com.what = Dip2DwarfSrch( li->type );
    df.com.containing = 0;
    df.com.cont = TRUE;
    df.com.kind = WLK_LOOKUP;
    df.comp = li->case_sensitive ? &memcmp : &memicmp;
    df.li = li;
    df.len =  li->name.len+1;
    if( df.len <= sizeof( buff ) ){
        df.buff = buff;
    }else{
        df.buff = DCAlloc( df.len );
    }
    df.sr = SR_NONE;
    switch( ss ) {
    case SS_SCOPED:
        if( li->scope.len == 0 ){
            cont = WalkScopedSymList( &df, &ASymLookup, (address *)source );
        }else{
            cont = TRUE;
        }
        sr = df.sr;
        if( cont ) {
            if( DR_SRCH_func_var == df.com.what ){
                sr = HashSearchGbl( ii, li, d );
           }
        }
        break;
    case SS_MODULE:
        im = *(imp_mod_handle *)source;
        if( im == (imp_mod_handle)NO_MOD ) {
            if( DR_SRCH_func_var == df.com.what ){
                sr = HashSearchGbl( ii, li, d );
            }
        } else {
           WalkModSymList( &df, &ASymLookup, IM2IMX( im ) );
           sr = df.sr;
        }
        break;
    case SS_SCOPESYM:
        is = (imp_sym_handle *)source;
        WalkSymSymList( &df, &ASymLookup, is );
        df.com.containing = is->sym;   //check for out of line defn
        WalkModSymList( &df, &ASymContLookup, is->imx );
        sr = df.sr;
        break;
    }
    if( df.buff != buff ){
        DCFree( df.buff );
    }
    return( sr );
}


extern search_result   DIPENTRY DIPImpLookupSym( imp_image_handle *ii,
                symbol_source ss, void *source, lookup_item *li, void *d )
{
    return( DoLookupSym( ii, ss, source, li, NULL, d ) );
}

extern search_result   DIPENTRY DIPImpLookupSymEx( imp_image_handle *ii,
                symbol_source ss, void *source, lookup_item *li,
                location_context *lc, void *d )
{
    return( DoLookupSym( ii, ss, source, li, lc, d ) );
}

int DIPENTRY DIPImpSymCmp( imp_image_handle *ii, imp_sym_handle *is1,
                                imp_sym_handle *is2 )
{
    /*
        Compare two sym handles and return 0 if they refer to the same
        information. If they refer to differnt things return either a
        positive or negative value to impose an 'order' on the information.
        The value should obey the following constraints.
        Given three handles H1, H2, H3:
                - if H1 < H2 then H1 is always < H2
                - if H1 < H2 and H2 < H3 then H1 is < H3
        The reason for the constraints is so that a client can sort a
        list of handles and binary search them.
    */
    long diff;

    ii = ii;
    diff = is1->sym - is2->sym;
    return( diff );
}

dip_status DIPENTRY DIPImpSymAddRef( imp_image_handle *ii, imp_sym_handle *is )
{
    ii=ii;
    is=is;
    return(DS_OK);
}

dip_status DIPENTRY DIPImpSymRelease( imp_image_handle *ii, imp_sym_handle *is )
{
    ii=ii;
    is=is;
    return(DS_OK);
}

dip_status DIPENTRY DIPImpSymFreeAll( imp_image_handle *ii )
{
    ii=ii;
    return(DS_OK);
}
